精华内容
下载资源
问答
  • 这是作者的系列网络安全自学教程,主要是关于网安工具和实践操作的...这一篇文章将详细讲解IDA Pro反汇编工具的基础用法,并简单讲解一个EXE逆向工程解密实战方法。希望对入门的博友有帮助,大神请飘过,谢谢各位看官!

    这是作者的系列网络安全自学教程,主要是关于网安工具和实践操作的在线笔记,特分享出来与博友共勉,希望您们喜欢,一起进步。上一篇文章分享了实验吧CFT实战的题目,涉及WEB渗透和隐写术常见题型,包括“这是什么”、“天网管理系统”、“忘记密码”、“false”、“天下武功唯快不破”和“隐写术之水果、小苹果”;这一篇文章将详细讲解IDA Pro反汇编工具的基础用法,并简单讲解一个EXE逆向工程解密实战方法。希望对入门的博友有帮助,大神请飘过,谢谢各位看官!

    下载地址:https://github.com/eastmountyxz/NetworkSecuritySelf-study
    百度网盘:https://pan.baidu.com/s/1dsunH8EmOB_tlHYXXguOeA 提取码:izeb

    PS:作为初学者,深知网络安全这块要学习的知识太多,希望自己能始终保持满腔热血,科研结合实际慢慢前行。

    展开全文
  • 系统安全系列作者将深入研究恶意样本分析、逆向分析、攻防实战和Windows漏洞利用等,通过在线笔记和实践操作...这篇文章将详细讲解IDA Pro反汇编工具的基础用法,并简单讲解一个EXE逆向工程解密实战方法,希望您喜欢。

    您可能之前看到过我写的类似文章,为什么还要重复撰写呢?只是想更好地帮助初学者了解病毒逆向分析和系统安全,更加成体系且不破坏之前的系列。因此,我重新开设了这个专栏,准备系统整理和深入学习系统安全、逆向分析和恶意代码检测,“系统安全”系列文章会更加聚焦,更加系统,更加深入,也是作者的慢慢成长史。换专业确实挺难的,逆向分析也是块硬骨头,但我也试试,看看自己未来四年究竟能将它学到什么程度,漫漫长征路,偏向虎山行。享受过程,一起加油~

    系统安全系列作者将深入研究恶意样本分析、逆向分析、攻防实战和Windows漏洞利用等,通过在线笔记和实践操作的形式分享与博友们学习,希望能与您一起进步。前文作者普及了逆向分析基础知识,告诉大家如何学好逆向分析,并给出吕布传游戏逆向案例。这篇文章将详细讲解IDA Pro反汇编工具的基础用法,并简单讲解一个EXE逆向工程解密实战方法,希望您喜欢。

    话不多说,让我们开始新的征程吧!您的点赞、评论、收藏将是对我最大的支持,感恩安全路上一路前行,如果有写得不好的地方,可以联系我修改。基础性文章,希望对您有所帮助,作者的目的是与安全人共同进步,加油~

    作者的github资源:

    前文分析:


    声明:本人坚决反对利用教学方法进行犯罪的行为,一切犯罪行为必将受到严惩,绿色网络需要我们共同维护,更推荐大家了解它们背后的原理,更好地进行防护。(参考文献见后)


    一.IDA Pro工具简介及初识

    1.IDA Pro简介

    IDA Pro(Interactive Disassembler Professional)简称“IDA”,是Hex-Rays公司出品的一款交互式反汇编工具,是目前最棒的一个静态反编译软件,为众多0day世界的成员和ShellCode安全分析人士不可缺少的利器。IDA Pro具有强大的功能,但操作较为复杂,需要储备很多知识,同时,它具有交互式、可编程、可扩展、多处理器等特点,可以通过Windows或Linux、MacOS平台来分析程序, 被公认为最好的逆向工程利器之一。

    IDA Pro已经成为分析敌意代码的标准并让其自身迅速成为攻击研究领域的重要工具。它支持数十种CPU指令集其中包括Intel x86、x64、MIPS、PowerPC、ARM、Z80、68000、c8051等等。

    在这里插入图片描述


    2.IDA Pro新建工程

    IDA Pro是点击下一步傻瓜式安装,安装成功会后会显示两个运行程序“IDA Pro(32bit)”和“IDA Pro(64bit)”,分别对应32位和64位程序的分析。IDA支持常见的PE格式,DOS、UNIX、Mac、Java、.NET等平台的文件格式。

    下面讲解首次打开IDA Pro的流程。

    第一步:打开IDA Pro32软件

    双击exe文件弹出如下图所示的“Support message”界面,点击OK按钮。

    在这里插入图片描述

    第二步:新建一个文件

    IDA包括三种加载文件的方式,其中“New”是新建打开一个标准文件的对话框,“GO”是运行打开一个空白工作,用户将要分析的文件拖入分析,“Previous”是选择最近一次使用过的文件。

    在这里插入图片描述

    第三步:选择一个exe文件载入,它将是我们要进行分析的程序

    作者通过C语言写了一段代码,并在本地生成一个“test01.exe”文件,它就是接下来分析的可执行文件。

    #include<stdio.h>
    int main()
    {
    	printf("Hello World!!!\n");
    	return 0;
    } 
    

    选择要导入的文件。

    在这里插入图片描述

    第四步:装载PE文件
    在“Load a new file”窗口中选择装载PE文件,包括text(代码块)、data(数据块)、rsrc(资源块)、idata(输入表)和edata(输出表)等,也可以载入二进制文件。

    在这里插入图片描述

    IDA反汇编包括两个阶段,首先将程序的代码和数据分开,分别标记函数并分析参数调用、跳转、指令关系等;接着如果IDA能识别文件的编译类型,就装载对应的编译器特征文件,给各函数赋名。同时,IDA会创建一个数据库,其组件分别保存在“.id0”、“.id1”、“.nam”和“.til”的文件里。

    接着弹出确认窗口,可以选择“Don’t show this message again”选项。

    在这里插入图片描述

    第五步:在“Check for Hex-Rays product updates”中点击“OK”
    在接下来弹出的Hex-Rays信息框再点击OK后,会要求设置更新选项,这里直接点击OK,默认即可。

    在这里插入图片描述

    第六步:显示运行结果
    此时,运行结果如下图所示,接着可以开始我们的逆向分析。

    在这里插入图片描述

    IDA View显示如下图所示:

    在这里插入图片描述

    Hex View十六进制显示如下图所示:

    在这里插入图片描述

    下图可以看到代码中的“hello world!!!\n”。

    在这里插入图片描述

    第七步:查看源代码
    按下F5能够查看对应的源代码。

    在这里插入图片描述

    第八步:关闭IDA Pro并保存数据库文件
    保存IDB数据库文件至本地,它记录了用IDA Pro对该程序分析中的工作状态,包括反汇编分析、区段扫描、用户自定义结构、用户自定义名称、注释等信息。点击右上角的关闭按钮,弹出IDA Pro保存数据库窗口(Save Database),使用默认选项,直接点击OK即可以保存生成数据库(.idb)文件。

    在这里插入图片描述

    下次载入时,可以直接加载数据库文件,获取之前分析的状态。

    在这里插入图片描述


    二.IDA Pro工具基本用法

    IDA Pro工具打开的主界面如下图所示:

    在这里插入图片描述

    IDA View窗口

    该窗口显示如下图所示:

    在这里插入图片描述

    它是通过点击“View”中“Open subviews”->“Disaassembly”调出来的。

    在这里插入图片描述

    IDA View包括两种浏览模式,一种是Text View,一种是Graph View,右键能够相互跳转。

    在这里插入图片描述

    在这里插入图片描述

    如下图所示,变换成另一种模式。

    IDA View主要包括三个区域:

    • 地址区: PE文件加载到内存后的虚地址为准,镜像地址+偏移地址,如0x00401000
    • OpCode操作区: 该部分默认因此,需要Options->General->设置Number of opcode bytes为8显示出来,它是16进制数
    • 反编译代码区: IDA主功能区域,能高亮显示,双击函数或变量名能跳转对应的地址。

    在这里插入图片描述

    在这里插入图片描述


    Hex View窗口

    显示16进制,默认为只读状态,可以用快捷键F2对数据区域(绿色字符区域)在只读和编辑两种状态切换。

    在这里插入图片描述

    Strings窗口

    IDA的View有几个按钮对定位代码很重要,如下图所示:

    在这里插入图片描述

    • Open exports window 打开导出窗口
    • Open import window 打开导入窗口
    • Open names window 函数和参数的命名列表
    • Open functions window 程序调用的所有函数窗口
    • Open strings window 打开字符串显示窗口

    这里作者点击Strings显示程序中所有字符串,该窗口有助于你通过程序的运行输出逆向找出对应的代码片断,如下图的字符串及对应的Address。

    在这里插入图片描述

    双击String跳转IAD View页面,如下图所示的地址,单击会高亮。

    在这里插入图片描述

    其他窗口:

    • 导出/入窗口:导出窗口列出文件的入口点,导入窗口列出由被分析的二进制文件导入的所有函数
    • 函数窗口:函数名称,区域,起始位置,长度,描述函数的标记
    • 结构体窗口:分析数据结构,双击数据结构名称展开,查看详细布局
    • 枚举窗口:enums可列举,定义枚举类型
    • 段窗口 segmentation:段的简单列表

    文件类型

    IDA会创建一个数据库,名为IDB文件,它由四个文件组成。

    • id0:二叉树形式的数据库
    • id1:程序字节标识
    • nam:Named窗口的索引信息
    • til:给定数据库的本地类型定义的相关信息

    在这里插入图片描述


    三.IDA Pro逆向工程实战

    1.代码加密

    前面第一篇 博客 讲解音乐文件通常采用异或加密,接下来作者通过C语言简单编写了一段加密代码,如下所示:

    #include<stdio.h>
    #include<string.h>
    
    int main()
    {
    	int i;
    	int len;
    	char key[20];
    	char res[20];
    	char *num = "eastmount";     //密钥 
    	char *right = "123456789";   //正确值 
    	
    	//请输入正确的密码
    	printf("please input the key:");
    	scanf("%s", &key);
    	
    	//判断
    	len = strlen(key);
    	if(len<6 || len>10) {
    		printf("Error, The length of the key is 6~10\n");
    	} 
    	else {
    		//加密
    		for(i=0; i<len; i++) {
    			res[i] = (key[i]^num[i]); //异或加密 
    		}	 
    		//printf("%s\n", res);
    		if(strcmp(res, right)==0) {
    			printf("You are right, Success.\n");
    		} else {
    			printf("Error, please input the right key.\n");
    		}
    	}
    	
    	return 0;
    }
    

    输入长度不在6-10之间反馈错误“Error, The length of the key is 6~10”,输入错误反馈“Error, please input the right key.”,正确的key才显示正确信息“You are right, Success.”。

    在这里插入图片描述

    在这里插入图片描述

    接下来我们通过IDA Pro工具解密这个EXE文件,尝试获取Key值。


    2.逆向解密

    第一步:按照第一部分步骤向IDA Pro中导入文件
    显示的调用程序如下图所示。
    在这里插入图片描述

    在这里插入图片描述

    树形图把条件分支清晰地显示出来了,左下角有IDA视图的缩略图。在上面点击可以快速定位到视图的指定位置,并且各个部分都有详细的代码信息 ,比如定义的两个变量及偏移位置。

    在这里插入图片描述

    第二步:查看字符串显示窗口
    IDA Pro工具中菜单栏的View有几个按钮对定位代码很重要,如下图所示:

    • Open exports window 打开导出窗口
    • Open import window 打开导入窗口
    • Open names window 函数和参数的命名列表
    • Open functions window 程序调用的所有函数窗口
    • Open strings window 打开字符串显示窗口

    在这里插入图片描述

    这里作者点击Strings显示程序中所有字符串,该窗口有助于你通过程序的运行输出逆向找出对应的代码片断,如下图的字符串及对应的Address。

    在这里插入图片描述

    双击String跳转到如下图所示的地址,单击会高亮。

    在这里插入图片描述

    第三步:查看源代码
    在如下图所示界面中按下F5键可以显示源代码。

    在这里插入图片描述

    显示的源代码如下所示:

    int __cdecl main(int argc, const char **argv, const char **envp)
    {
      char Str1[32]; // [esp+38h] [ebp-50h]
      char Str[40]; // [esp+58h] [ebp-30h]
      int v6; // [esp+80h] [ebp-8h]
      int i; // [esp+84h] [ebp-4h]
    
      __main();
      printf("please input the key:");
      scanf("%s", Str);
      v6 = strlen(Str);
      if ( v6 > 5 && v6 <= 10 )
      {
        for ( i = 0; i < v6; ++i )
          Str1[i] = gcc2_compiled_[i] ^ Str[i];
        if ( !strcmp(Str1, "123456789") )
          printf("You are right, Success.\n");
        else
          printf("Error, please input the right key.\n");
      }
      else
      {
        printf("Error, The length of the key is 6~10\n");
      }
      return 0;
    }
    

    注意,该部分代码与之前写的C语言代码略有不同,比如之前判断长度 if(len<6 || len>10) 提示错误,而这里是 if ( v6 > 5 && v6 <= 10 ) 正确执行,else显示错误。

    在这里插入图片描述

    这段代码的基本逻辑是输入字符串Str,然后循环与gcc2_compiled_变量异或加密,输出为Str1变量,当加密后的Str1变量值为“123456789”则解密成功,否则失败。
    那么,gcc2_compiled_变量的值是多少呢?

    第四步:定位核心代码
    接着选中gcc2_compiled_变量,当它变高亮双击之后会跳转到对应的页面。

    在这里插入图片描述

    原来如此,它的密钥是“eastmount”,加密结果是“123456789”。

    在这里插入图片描述

    第五步:逆向解密
    最后撰写解密代码,实现逆向解密,“eastmount” 异或输入代码Str,并且值等于123456789,则可以成功显示。

    #include<stdio.h>
    #include<string.h>
    
    int main()
    {
    	int i;
    	int len;
    	char res[9];
    	char *num = "eastmount";     //密钥 
    	char *right = "123456789";   //正确值 
    	
    	
    	//判断 TS@@XYBVM
    	len = strlen(num);
    	for(i=0; i<len; i++) {
    		res[i] = (right[i]^num[i]); //异或加密
    	}
    	res[i] = 0;
    	printf("The right key is: %s\n", res);
    	return 0;
    }
    

    解密结果如下图所示:

    在这里插入图片描述

    注意,IDA Pro本地 创建的文件如下图所示。

    在这里插入图片描述


    四.总结

    写到这里,这篇基础性文章就叙述完毕,安全要学习的知识真的很多,涉及面很广,包括汇编、网络、操作系统、加密解密、C/C++、Python等。希望自己能慢慢进步,科研与实践并重,也希望读者喜欢这系列总结笔记。不喜勿喷,与你同行~

    三年前你在敦煌日出前写下“璋娜”,而今天我写了封情书作为礼物,三张薄纸,道不出无数思恋。武汉美,武大更美,但我知道此行的目的,是来求知,来充电的,吾家有女初成长,早日学成团聚才是我的归属。深夜写的博客,记录今天IDA Pro学习心得,一起加油。

    今天刚好CSDN粉丝破十万,真心感谢大家这些年来的陪伴和支持,感恩认识您,也希望未来能继续分享更高质量的文章,帮助更多人入门和解决为题,寓教于乐,共勉!

    在这里插入图片描述

    2020年8月18新开的“娜璋AI安全之家”,主要围绕Python大数据分析、网络空间安全、人工智能、Web渗透及攻防技术进行讲解,同时分享论文的算法实现。娜璋之家会更加系统,并重构作者的所有文章,从零讲解Python和安全,写了近十年文章,真心想把自己所学所感所做分享出来,还请各位多多指教,真诚邀请您的关注!谢谢。

    在这里插入图片描述

    (By:Eastmount 2020-12-17 星期四 晚上10点写于武汉 https://blog.csdn.net/Eastmoun)


    展开全文
  • Android逆向基础笔记—初识逆向

    千次阅读 2016-08-24 14:47:38
    初识 APK、Dalvik字节码以及Smali 1. apk是什么? apk实质上是一个zip压缩包,将apk后缀修改为zip,解压之后可以看到其内部结构: 2. apk 的组成 assets: 资源目录1 assets 和 res 都是资源目录但有所区别: ...

    (本笔记来源于吾爱以及吾爱坛友,加上本人自己的整理)

    一.初识 APK、Dalvik字节码以及Smali

    1. apk是什么?
    apk实质上是一个zip压缩包,将apk后缀修改为zip,解压之后可以看到其内部结构:


    2. apk 的组成

    assets: 资源目录1

    assets 和 res 都是资源目录但有所区别:
    res 目录下的资源文件在编译时会自动生成索引文件(R.java),在Java代码中用R.xxx.yyy来引用;

    而asset
    目录下的资源文件不需要生成索引,在Java 代码中需要用AssetManager来访问;
    一般来说,除了音频和视频资源(需要放在raw或asset下),使用Java开发的Android工程使用到的资源文件都
    会放在res下;

    使用C++游戏引擎(或使用 Lua Unity3D等)的资源文件均需要放在 assets 下。
    lib: so 库存放位置,一般由NDK编译得到,常见于使用游戏引擎或 JNI native调用的工程中
    META-INF: 存放工程一些属性文件,例如 Manifest.MF
    res: 资源目录2

    AndroidManifest.xml: Android工程的基础配置属性文件
    classes.dex: Java代码编译得到的 Dalvik VM 能直接执行的文件
    resources.arsc: 对res 目录下的资源的一个索引文件,保存了原工程中 strings.xml等文件内

    apktool.yml - 重新打包必须文件
    lib - native 动态库 so
    META-INF -签名   


    3. Dalvik字节码(重点来了)

    Dalvik 是 google 专门为 Android 操作系统设计的一个虚拟机,经过深度优化。虽然 Android 上的程序是使用java 来开发的,但是 Dalvik 和标准的 java 虚拟机 JVM 还是两回事。

    Dalvik VM 是基于寄存器的,而 JVM 是基于栈的;

    Dalvik有专属的文件执行格式 dex (dalvik executable),而 JVM 则执行的是 java 字节码。

    Dalvik VM 比 JVM 速度更快,占用空间更少。
    通过 Dalvik 的字节码我们不能直接看到原来的逻辑代码,这时需要借助如 Apktool 或 dex2jar+jd-gui 工具来帮助查看。但是,我们最终修改 APK 需要操作的文件是 .smali 文件,而不是导出来的 Java 文件重新编译。

    4. Smali(破解的重点。好吧还是重点

    1)Smali,Baksmali 分别是指安卓系统里的 Java 虚拟机(Dalvik)所使用的一种 dex 格式文件的汇编器,反汇编器。其语法是一种宽松式的 Jasmin/dedexer 语法,而且它实现了 .dex 格式所有功能(注解,调试信息,线路信息等)
    当我们对 APK 文件进行反编译后,便会生成此类文件。在Davlik字节码中,寄存器都是32位的,能够支持任何类型,64位类(Long/Double)用2个寄存器表示;Dalvik字节码有两种类型:原始类型;引用类型(包括对象和数组)

    2)原始类型:
    B---byte
    C---char
    D---double
    F---float
    I---int
    J---long
    S---short
    V---void
    Z---boolean
    [XXX---array
    Lxxx/yyy---object
    这里解析下最后两项,数组的表示方式是:在基本类型前加上前中括号“[”,例如 int 数组和 float 数组分别表示为:[I、[F;

    对象的表示则以 L 作为开头,格式是 LpackageName/objectName;(注意必须有个分号跟在最后),例如 String 对象在 smali 中为:Ljava/lang/String;,

    其中 java/lang 对应 java.lang包,String 就是定义在该包中的一个对象。

    内部类又如何在 smali 中:LpackageName/objectName$subObjectName;也就是在内部类前加“$”符号。

    3)方法的定义
    Func-Name (Para-Type1Para-Type2Para-Type3...)Return-Type注意参数与参数之间没有任何分隔符,举例如下:
    A ()V   这就是void A()。
    B (II)Z  这个则是boolean B(int, int)。
    C (Z[I[ILjava/lang/String;J)Ljava/lang/String;    这是String C (boolean, int[], int[], String, long) 。

    4)Smali基本语法

    .field private isFlag:z  定义变量
    .method  方法
    .parameter  方法参数
    .prologue  方法开始
    .line 123  此方法位于第123行
    invoke-super  调用父函数
    const/high16 v0, 0x7fo3  把0x7fo3赋值给v0
    invoke-direct  调用函数
    return-void  函数返回void
    .end method  函数结束
    new-instance  创建实例
    iput-object  对象赋值
    iget-object  调用对象
    invoke-static  调用静态函数

    5)条件跳转分支

    "if-eq vA, vB, :cond_**" 如果vA等于vB则跳转到:cond_**
    "if-ne vA, vB, :cond_**" 如果vA不等于vB则跳转到:cond_**
    "if-lt vA, vB, :cond_**" 如果vA小于vB则跳转到:cond_**
    "if-ge vA, vB, :cond_**" 如果vA大于等于vB则跳转到:cond_**
    "if-gt vA, vB, :cond_**" 如果vA大于vB则跳转到:cond_**
    "if-le vA, vB, :cond_**" 如果vA小于等于vB则跳转到:cond_**
    "if-eqz vA, :cond_**" 如果vA等于0则跳转到:cond_**
    "if-nez vA, :cond_**" 如果vA不等于0则跳转到:cond_**
    "if-ltz vA, :cond_**" 如果vA小于0则跳转到:cond_**
    "if-gez vA, :cond_**" 如果vA大于等于0则跳转到:cond_**
    "if-gtz vA, :cond_**" 如果vA大于0则跳转到:cond_**
    "if-lez vA, :cond_**" 如果vA小于等于0则跳转到:cond_**

    二.Smali 文件

    1. Smali中的包信息

    .class public Lcom/aaaaa; (它是com.aaaaa这个package下的一个类)
    .super Lcom/bbbbb; (继承自com.bbbbb这个类)
    .source "ccccc.java" (一个由ccccc.java编译得到的smali文件)

    2. Smali中的声明

    # annotations
    .annotation system Ldalvik/annotation/MemberClasses;
    value = {
    Lcom/aaa$qqq;,
    Lcom/aaa$www;
    }.
    end annotation
    //这个声明是内部类的声明:aaa这个类它有两个成员内部类——qqq和www,内部类将在后面小节中会有提及。

    3.关于寄存器

    寄存器是什么意思呢?在 smali 里的所有操作都必须经过寄存器来进行:本地寄存器用 v 开头,数字结尾的符号来表示,如v0、v1、v2、...

    参数寄存器则使用 p 开头,数字结尾的符号来表示,如p0、p1、p2、...

    特别注意的是,p0 不一定是函数中的第一个参数,在非 static 函数中,p0 代指“this”,p1 表示函数的第一个参数,p2 代表函数中的第二个参数。

    而在 static 函数中 p0 才对应第一个参数(因为 Java 的 static 方法中没有 this 方法。

    4. 寄存器简单实例分析

    const/4 v0, 0x1
    iput-boolean v0, p0, Lcom/aaa;->IsRegistered:Z

    我们来分析一下上面的两句 smali 代码,首先它使用了 v0 本地寄存器,并把值 0x1 存到 v0 中,然后第二句用 iput-boolean 这个指令把 v0 中的值存放到 com.aaa.IsRegistered 这个成员变量中。
    即相当于:this.IsRegistered= true;(上面说过,在非static函数中p0代表的是“this”,在这里就是
    com.aaa 实例)。

    5. Smali中的成员变量

    成员变量格式是:.field public/private [static] [final] varName:<类型>。
    对于不同的成员变量也有不同的指令。
    一般来说,获取的指令有:iget、sget、iget-boolean、sget-boolean、iget-object、sget-object等。
    操作的指令有:iput、sput、iput-boolean、sput-boolean、iput-object、sput-object等。
    没有“-object”后缀的表示操作的成员变量对象是基本数据类型,带“-object”表示操作的成员变量是对象类
    型,特别地,boolean 类型则使用带“-boolean”的指令操作。

    6. Smali成员变量指令简析

    1) 简析一
    sget-object v0, Lcom/aaa;->ID:Ljava/lang/String;
    sget-object就是用来获取变量值并保存到紧接着的参数的寄存器中,本例中,它获取ID这个String类型的成员变量并放到v0这个寄器中。
    注意:前面需要该变量所属的类的类型,后面需要加一个冒号和该成员变量的类型,中间是“->”表示所属关系。

    2) 简析二
    iget-object v0, p0, Lcom/aaa;->view:Lcom/aaa/view;
    可以看到iget-object指令比sget-object多了一个参数,就是该变量所在类的实例,在这里就是p0即“this”。
    获取array的话我们用aget和aget-object,指令使用和上述一致

    3) 简析三

    put指令的使用和get指令是统一的)
    const/4 v3, 0x0
    sput-object v3, Lcom/aaa;->timer:Lcom/aaa/timer;
    相当于:this.timer= null;
    注意,这里因为是赋值object 所以是null

    4) 简析四
    .local v0, args:Landroid/os/Message;
    const/4 v1, 0x12
    iput v1, v0, Landroid/os/Message;->what:I
    相当于:args.what = 18;(args 是 Message 的实例)

    三.Smali函数分析

    1. Smali中函数的调用
    1)smali中的函数和成员变量一样也分为两种类型,分别为direct和virtual之分。

    direct method和virtualmethod的区别:简单来说,direct method 就是 private 函数,其余的 public 和 protected 函数都属于 virtual method。所以在调用函数时,有invoke-direct,invoke-virtual,另外还有invoke-static、invoke-super以及invokeinterface等几种不同的指令。当然其实还有invoke-XXX/range 指令的,这是参数多于4个的时候调用的指令。

    2)invoke-static:

    用于调用static函数,例如:invoke-static {}, Lcom/aaa;->CheckSignature()Z
    这里注意到 invoke-static 后面有一对大括号“{}”,其实是调用该方法的实例+参数列表,由于这个方法既不需参数也是static的,所以{}内为空

    再看一个:const-string v0, "NDKLIB"
    invoke-static {v0}, Ljava/lang/System;->loadLibrary(Ljava/lang/String;)V
    这个是调用 static void System.loadLibrary(String) 来加载 NDK 编译的 so 库用的方法,同样也是这里 v0 就是参数"NDKLIB"了。
    3)invoke-super:

    调用父类方法用的指令,一般用于调用onCreate、onDestroy等方法。
    4)invoke-direct:

    调用private函数:invoke-direct {p0}, Landroid/app/TabActivity;->()V
    这里init()就是定义在TabActivity中的一个private函数
    5)invoke-virtual:

    用于调用 protected 或 public 函数,同样注意修改smali时不要错用 invoke-direct或 invoke-static:

    sget-object v0, Lcom/dddd;->bbb:Lcom/ccc;
    invoke-virtual {v0, v1}, Lcom/ccc;->Messages(Ljava/lang/Object;)V
    v0是bbb:Lcom/ccc
    v1是传递给Messages方法的Ljava/lang/Object参数。
    6)invoke-xxxxx/range:

    当方法的参数多于5个时(含5个),不能直接使用以上的指令,而是在后面加上“/range”,range表示范围,使用方法也有所不同:
    invoke-direct/range {v0 .. v5}, Lcmb/pb/ui/PBContainerActivity;->h(ILjava/lang/CharSequence;Ljava/lang/String;Landroid/content/需要传递v0到v5一共6个参数,这时候大括号内的参数采用省略形式,且需要连续。
    2. Smali中函数返回结果操作
    在Java代码中调用函数和返回函数结果可以用一条语句完成,而在Smali里则需要分开来完成,在使用上述指令后,如果调用的函数返回非void,那么还需要用到move-result(返回基本数据类型)和move-result-object(返回对象)指令:
    const-string v0, "Eric"
    invoke-static {v0}, Lcmb/pbi;->t(Ljava/lang/String;)Ljava/lang/String;
    move-result-object v2
    v2保存的就是调用t方法返回的String字符串。
    3. Smali中函数实体分析--if函数分析
    .method private ifRegistered()Z
    .locals 2 //在这个函数中本地寄存器的个数
    .prologue
    const/4 v0, 0x1 // v0赋值为1
    .local v0, tempFlag:Z
    if-eqz v0, :cond0 // 判断v0是否等于0,等于0则跳到cond0执行
    const/4 v1, 0x1 // 符合条件分支
    :goto_0 //标签
    return v1 //返回v1的值
    :cond_0 //标签
    const/4 v1, 0x0 // cond_0分支
    goto :goto0 //跳到goto0执行 即返回v1的值 这里可以改成return v1 也是一样的
    .end method

    展开全文
  • 所以步入Android逆向工程的第一步就是了解Smali语法,所以有了本篇文章。 2.Smali语法 数据类型 对比于Java,smali也有相应的数据类型 类型关键字 对应Java中的类型 V void,只能用于返回类型 Z boolean B byte S ...

    1.什么是Smali?

    官方解释:

    Smali是指安卓系统里的Java虚拟copy机(Dalvik)所使用的一种.dex格式文件的汇编器,反汇编器。其语法是一种宽松式的Jasmin/dedexer语法,而且它实现了.dex格式所有功能(注解,调试信息,线路信息等zhidao)。

    其实说白了smali使用一种语言,是Dalvik的反编译语言。

    那么问题又来了,什么是Dalvik?
    Dalvik是Google公司自己设计用于Android平台的虚拟机。它支持.dex(即“Dalvik Executable”)格式的Java应用程序的运行。.dex格式是专为Dalvik设计的一种压缩格式,适合内存和处理器速度有限的系统。Dalvik虚拟机是基于寄存器架构的虚拟机。

    不同于java虚拟机JVM编译后生成的class文件,Android虚拟机Dalvik在执行在重新整合打包后生成的dex文件,dex文件反编译之后就是smali代码。

    所以步入Android逆向工程的第一步就是了解Smali语法,所以有了本篇文章。

    2.Smali语法

    数据类型

    对比于Java,smali也有相应的数据类型

    类型关键字 对应Java中的类型
    V void,只能用于返回类型
    Z boolean
    B byte
    S short
    C char
    I int
    J long (64 bits)
    F float
    D double (64 bits)
    [XXX array
    Lxxx/yyy object

    对象

       smali语法             java语法
    Ljava/lang/String     java.lang.String
    

    方法

    Lpackage/name/ObjectName;->MethodName(III)Z
    

    第一部分Lpackage/name/ObjectName;用于声明具体的类型,以便JVM寻找

    第二部分MethodName(III)Z,其中MethodName为具体的方法名,()中的字符,表示了参数数量和类型,即3个int型参数,Z为返回值的类型,即返回Boolean类型

    寄存器

    在Smali中,如果需要存储变量,必须先声明足够数量的寄存器,1个寄存器可以存储32位长度的类型,比如Int,而两个寄存器可以存储64位长度类型的数据,比如Long或Double。

    声明可使用的寄存器数量的方式为:.registers N,N代表需要的寄存器的总个数

    例子:

    .method private test(I)V
        .registers 1  # 声明总共需要使用1个寄存器
    
        const-string v0, "MRyan"  # 将v0寄存器赋值为字符串常量"MRyan
    
        return-void #返回空
    .end method #方法结束
    

    如何确定需要使用的寄存器的个数?
    就小学数学加法呗
    非static方法,需要占用一个寄存器以保存this指针,那么这类方法的寄存器个数,最低就为1,其余按照数据类型叠加

    例如下面一个Java代码

     Void M1(int a1, float a2, Double a3);
    

    对应的Smali代码如下:

    method LMyObject;->M1(IFD)V
    

    寄存器的对应情况如下:

    寄存器名称	对应的引用         寄存器个数
    p0	          this                 1
    p1	       int型的a1参数            1
    p2, p3	       float型的a2参数          2
    p4,p5	       Double型的a3参数         2
    

    1+1+2+2=6,所以就需要6个寄存器

    3.Dalvik指令集(此处转载)

    寄存参数使用p寄存器,形如p0,p1,用.param定义,且从p1开始计数,因为p0为非静态方法自动创建的寄存器,存储着this,也就是该方法所属类的实例本身

    寄存方法中的内部变量使用v寄存器,形如v0,v1,用.locals在方法开头表示所需的内部变量数,在声明变量时用.local …声明。值得一提的是方法中的内部类也属于方法的内部变量。

    1.移位操作:

    一般的指令格式为:[op]-type/[位宽,默认4位] [目标寄存器],源寄存器,比如:move v1,v2,move-wide/from16 v1,v2

     指令	                      说明
    move v1,v2	               将v2中的值移入到v1寄存器中(4位,支持int型)
    move/from16 v1,v2	       将16位的v2寄存器中的值移入到8位的v1寄存器中
    move/16 v1,v2	       将16位的v2寄存器中的值移入到16位的v1寄存器中
    move-wide v1,v2            将寄存器对(一组,用于支持双字型)v2中的值移入到v1寄存器对中 
                              (4位,猜测支持float、double型)
    move-wide/from16 v1,v2	将16位的v2寄存器对(一组)中的值移入到8位的v1寄存器中
    move-wide/16 v1,v2	        将16位的v2寄存器对(一组)中的值移入到16位的v1寄存器中
    move-object v1,v2	        将v2中的对象指针移入到v1寄存器中
    move-object/from16 v1,v2	将16位的v2寄存器中的对象指针移入到v1(8位)寄存器中
    move-object/16 v1,v2	将16位的v2寄存器中的对象指针移入到v1(16位)寄存器中
    move-result v1	        将这个指令的上一条指令计算结果,移入到v1寄存器中(需要配合invoke-static、invoke-virtual等指令使用)
    move-result-object v1	将上条计算结果的对象指针移入v1寄存器
    move-result-wide v1	        将上条计算结果(双字)的对象指针移入v1寄存器
    move-exception v1	        将异常移入v1寄存器,用于捕获try-catch语句中的异常
    

    在invoke-virtual {v0, p0~pn}…中,v0存有该方法所属的类,p0至pn表示该方法需要的传参,…表示v0所存类与该方法的联系

    返回操作:

    指令	             说明
    return-void	         返回void,即直接返回
    return v1	         返回v1寄存器中的值
    return-object v1	返回v1寄存器中的对象指针
    return-wide v1	返回双字型结果给v1寄存器
    

    常量操作:

    用于声明常量,比如字符串常量(仅声明,String a = “abc”这种语句包含声明和赋值)

    指令	说明
    const(/4、/16、/hight16) v1 xxx	      将常量xxx赋值给v1寄存器,/后的类型,需要根 
                                              据xxx的长度选择
    const-wide(/16、/32、/hight16) v1 xxx	将双字型常量xxx赋值给v1寄存器,/后的类 
                                              型,需要根据xxx的长度选择
    const-string(/jumbo) v1 “aaa”	       将字符串常量”aaa”赋给v1寄存器,过长时需要 
                                                加上jumbo
    const-class v1 La/b/TargetClass	       将Class常量a.b.TargetClass赋值给v1,等价 
                                                于a.b.TargetClass.class
    

    调用操作:

    用于调用方法,基本格式:invoke-kind {vC, vD, vE, vF, vG}, meth@BBBB,其中,BBBB代表方法引用(参见上面介绍的方法定义及调用),vC~G为需要的参数,根据顺序一一对应

       指令	              说明
    invoke-virtual	  用于调用一般的,非private、非static、非final、非构造函数的方法,它的第一个参数往往会传p0,  也就是this指针
    invoke-super	用于调用父类中的方法,其他和invoke-virtual保持一致
    invoke-direct	用于调用private修饰的方法,或者构造方法
    invoke-static	用于调用静态方法,比如一些工具类
    invoke-interface	用于调用interface中的方法
    

    判断操作:

    指令	               说明
    if-eq v1,v2	           判断两个寄存器中的值是否相等
    if-ne v1,v2	           判断两个寄存器中的值是否不相等
    if-lt v1,v2	           判断v1寄存器中的值是否小于v2寄存器中的值(lt == less than)
    if-ge v1,v2	           判断v1寄存器中的值是否大于或等于v2寄存器中的值(ge == great 	           	           	           
                            than or equals)
    if-gt v1,v2	           判断v1寄存器中的值是否大于v2寄存器中的值(gt == great than)
    if-le v1,v2	           判断v1寄存器中的值是否小于或等于v2寄存器中的值(le == less than 
                            or equals)
    

    属性操作:

    属性操作的分为:取值(get)和赋值(put)

    目标类型分为:数组(array)、实例(instance)和静态(static)三种,对应的缩写前缀就是a、i、s

    长度类型分为:默认(什么都不写)、wide(宽,64位)、object(对象)、boolean、byte、char、short(后面几种就不解释了,和Java一致)

    指令格式:[指令名] [源寄存器], [目标字段所在对象寄存器], [字段指针],示例代码如下,操作是为int型的类成员变量mIntA赋值为100:

    const/16 v0, 0x64
    
    iput v0, p0, Lcom/coderyuan/smali/MainActivity;->mIntA:I
    
    
    指令	                       说明
    iget	               取值,用于操作int这种的值类型
    iget-wide	               取值,用于操作wide型字段
    iget-object	               取值,用于操作对象引用
    iget-boolean	       取值,用于操作布尔类型
    iget-byte		       取值,用于操作字节类型
    iget-char	               取值,用于操作字符类型
    iget-short	               取值,用于操作short类型
    iput	               赋值,用于操作int这种的值类型
    iput-wide	               赋值,用于操作wide型字段
    iput-object	               赋值,用于操作对象引用
    iput-boolean	       赋值,用于操作布尔类型
    iput-byte	               赋值,用于操作字节类型
    iput-char	               赋值,用于操作字符类型
    iput-short	               赋值,用于操作short类型
    

    其中注意一个Smali文件对应的是一个Java.class文件。

    热热身!例子!

    在Idea插件中安装java2smali可以将java编译成smali文件,我们可以对比来学习。

    ###例子1:简单的赋值操作
    java代码:简单的赋值操作

    /**
     * @description:简单例子1赋值分析
     * @Author MRyan
     * @Date 2020/4/19 11:53
     * @Version 1.0
     */
    public class text {
        public static void main(String[] args) {
            int a = 15;
            int b = 4;
            b = a;
            System.out.println(b);
        }
    }
    

    smali代码:

    #静态函数main 参数String数组,函数返回值Void
    .method public static main([Ljava/lang/String;)V
        #定义4个寄存器
        .registers 4
        #第一个 寄存器 相当于this
        .param p0, "args"
    
        .prologue
        .line 11
        #第二个寄存器 16字节的 声名常量15并赋值给寄存器v0  
        const/16 v0, 0xf
    
        .line 13
        #定义 int型的a变量指向寄存器v0  a=15的意思
        .local v0, "a":I
        #将V0寄存器的数值移动到v1寄存器中
        move v1, v0
    
        .line 14
        #定义 int型的b变量指向寄存器v1 现在b=15
        .local v1, "b":I
    
        #sget是对静态字段读操作
        sget-object v2, Ljava/lang/System;->out:Ljava/io/PrintStream;
    
        #调用方法
        invoke-virtual {v2, v1}, Ljava/io/PrintStream;->println(I)V
    
        .line 15
        #返回空
        return-void
    .end method
    

    ###例子2:简单的条件分支分析
    java代码:简单的条件分支分析

    /**
     * @description:简单的条件分支
     * @Author MRyan
     * @Date 2020/3/28 11:53
     * @Version 1.0
     */
    public class text {
        public static void main(String[] args) {
            boolean istrue=false;
            if(istrue){
                System.out.println("true");
            }else{
                System.out.println("false");
            }
        }
    }
    

    Smali代码:

    .method public static main([Ljava/lang/String;)V
        #定义4个寄存器
        .registers 4
        .param p0, "args"    # [Ljava/lang/String;
    
        .prologue
        .line 11
        #声名常量0并赋值给v0寄存器 也就是false
        const/4 v0, 0x0
    
        .line 12
        #本地寄存器v0 名称istrue 数据类型boolean
        .local v0, "istrue":Z
        #如果寄存器中数值等于0 则跳转到cond_b
        if-eqz v0, :cond_b
    
        .line 13
        #符合条件分支执行
        sget-object v1, Ljava/lang/System;->out:Ljava/io/PrintStream;
    
        const-string v2, "true"
        #输出true
        invoke-virtual {v1, v2}, Ljava/io/PrintStream;->println(Ljava/lang/String;)V
    
    
        .line 17
        #跳转goto_a 结束
        :goto_a
        return-void
    
        .line 15
        #如果寄存器中数值等于0
        :cond_b
        sget-object v1, Ljava/lang/System;->out:Ljava/io/PrintStream;
    
        const-string v2, "false"
         #输出false
        invoke-virtual {v1, v2}, Ljava/io/PrintStream;->println(Ljava/lang/String;)V
    
        goto :goto_a
    .end method
    

    ###例子3: 复杂的条件分支

    /**
     * @description:复杂的条件分支
     * @Author MRyan
     * @Date 2020/3/28 12:05
     * @Version 1.0
     */
    public class text {
        public static void main(String[] args) {
            int a = 0;
            if (a == 1) {
                System.out.println("1");
            } else if (a == 2) {
                System.out.println("2");
            } else if (a == 0) {
                System.out.println("0");
            }
        }
    }
    

    Smali代码:

    .method public static main([Ljava/lang/String;)V
        #定义四个寄存器
        .registers 4
        .param p0, "args"    # [Ljava/lang/String;
    
        .prologue
        .line 11
        #声名常量0并赋值给v0寄存器 数值为0
        const/4 v0, 0x0
    
        .line 12
        #本地寄存器v0 为int类型 名称为a
        .local v0, "a":I
        #声名常量1赋值给寄存器v1 数值为1
        const/4 v1, 0x1
    
        #如果v0,v1不相等(也就是a不等于1)就跳转cond_c
        if-ne v0, v1, :cond_c
    
        .line 13
        #其他分支 v0和v1相等 (也就是a等于1)
        sget-object v1, Ljava/lang/System;->out:Ljava/io/PrintStream;
        #常量1赋值给寄存器v2
        const-string v2, "1"
        #输出1
        invoke-virtual {v1, v2}, Ljava/io/PrintStream;->println(Ljava/lang/String;)V
    
        .line 19
        #结束
        :cond_b
        :goto_b
        return-void
    
        .line 14
        #如果v0,v1不相等(也就是a不等于1)
        :cond_c
       #声明变量2赋值给寄存器v1
        const/4 v1, 0x2
        #如果寄存器v0数值不等于寄存器v1数值 也就是(a不等于2) 跳转 cond_17
        if-ne v0, v1, :cond_17
    
        .line 15
        #其他分支 如果寄存器v0数值等于寄存器v1数值 也就是(a等于2)
        sget-object v1, Ljava/lang/System;->out:Ljava/io/PrintStream;
    
        const-string v2, "2"
        #输出2
        invoke-virtual {v1, v2}, Ljava/io/PrintStream;->println(Ljava/lang/String;)V
        #返回
        goto :goto_b
    
        .line 16
        :cond_17
        #如果寄存器v0中的值不等于0 (也就是a不等于0) 执行 cond_b
        if-nez v0, :cond_b
    
        .line 17
        #如果寄存器v0中的值等于0 (也就是a等于0)
        sget-object v1, Ljava/lang/System;->out:Ljava/io/PrintStream;
    
        const-string v2, "0"
        #输出0
        invoke-virtual {v1, v2}, Ljava/io/PrintStream;->println(Ljava/lang/String;)V
        #结束
        goto :goto_b
    .end method
    

    在这里插入图片描述

    展开全文
  • 标题:初识逆向工程之植物大战僵尸游戏数据修改 目录 标题:初识逆向工程之植物大战僵尸游戏数据修改 前言 一、工具准备 二、操作内容 1.修改《植物大战僵尸》的存档文件,跳到指定关卡5-1 2.修改《植物大战...
  • 课程名称:《第二行代码》逆向天地玄门 课程简介:用OD和CE进行逆向反汇编分析,最终用 VB6.0来操作分析出来的...5、《第二行代码》-逆向工程,用CE找人物坐标,初步认https://www.bilibili.com/video/BV1Nh411H7Hj/ ...
  •  说白点:spring Boot 并不是对spring的增强,而是提供了一种快速使用spring的方式(其实你在构建spring Boot 项目时,你会发现它其实就是有一个父工程) 2.spring Boot 的特性? 使用 Spring 项目引导页面可以在几...
  • Android逆向工程——初识Handler机制 安卓逆向学习交流群692903341 此次教程的目的:找APP付费项目地址,实施有效爆破。 本次教程的知识点:初步认识Handler机制,或者说,建立对Handler机制的一个认识概念。线程...
  • 逆向工程:游戏安全入门教程 杨闯(rkvir)天融信阿尔法实验室安全研究员。...
  • 逆向工程中可以用到后两个:后编译时编织和加载时编织。 1.安装AspectJ 下载地址: http://www.eclipse.org/aspectj/downloads.php 选择里面的1.9版本下载,下载完成之后是个jar包 安装命令 1 java -jar aspectj-...
  • 这是逆向工程里的一个大块,我在这里几句话是一定说不清楚的,如果大家想深入了解,可以去学习一下。我这里简单说一下,hook,中文就是钩子的意思,简单理解为勾住一切事物,来实现我们想要的功能。 外挂中的体现:...
  • 首先说一下javaagent是...在逆向中javaagent可以完成对类的拦截和增强。看一个例子在Eclipse新建如下MyAgent结构的项目MyAgent.java文件内容packagecom.vvvtimes.demo.agent; importjava.lang.instrument.Instru...
  • 前言 从今年年前开始,由于个人...IDA(Interactive Disassembler Professional)是一款交互式静态反汇编工具,它是可编程的,可扩展的,多处理器的,能够交叉Windows或Linux WinCE MacOS平台主机来分析程序的逆向工程
  • iOS逆向技术视频教程

    2018-11-05 21:57:12
    初识逆向工程 课时02.iOS系统安全机制 课时03.认识越狱设备 课时04.越狱环境配置 课时05.第一章文档总结 课时06.App结构与构建过程 课时07.寻找控件背后的代码 课时08.数据存储 课时09.类与方法 课时10....
  • 网易云IOS逆向与安全

    2019-07-26 16:41:01
    初识逆向工程.avi 课时02.iOS系统安全机制.avi 课时03.认识越狱设备.avi 课时04.越狱环境配置.avi 课时06.App结构与构建过程.avi 课时07.寻找控件背后的代码.avi 课时08.数据存储.avi 课时09.类与方法.avi 课时10....
  • 文章目录1:人人开源搭建后台管理系统2:逆向工程搭建 1:人人开源搭建后台管理系统 前面我们创建好了各个微服务,以及微服务中对应的数据库和开发环境的搭建,接下来我们就要使用人人开源来搭建后台管理系统 按照...
  • starUML初识

    2017-08-30 21:32:54
    StarUML是一种生成类图和其他类型的统一建模语言(UML)图表...SU也可以做JAVA逆向工程,以产生相应的UML图表。 在本教程中,我们将使用SU设计一个pizza饼。执行下列步骤,可以创建如下面所示的UML图。SU可以生成反映类
  • 初识CSDN

    2020-11-03 17:08:48
    初识CSDN对CSDN的认识本文章的意义个人介绍计算机电气工程及其自动化日语如何使用CSDN使用频度发布内容计算机电气工程及其自动化日语总结 对CSDN的认识 许久之前就已经对这个平台有些许的了解,也经常使用这个平台...
  • 初识CTF

    2019-09-13 09:55:31
    初识CTF赛事介绍竞赛模式CTF常见题型赛事级别及练习平台 赛事介绍 CTF(Capture The Flag)夺旗锦标赛,网络安全人员之间进行技术竞技一种比赛 CTF起源于1996年DEFCON全球黑客大会,以代替之前黑客们通过互相发起...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 484
精华内容 193
关键字:

初识逆向工程