前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >使用IDA Pro进行静态分析

使用IDA Pro进行静态分析

作者头像
用户1631416
发布2019-05-05 15:00:56
3K0
发布2019-05-05 15:00:56
举报
文章被收录于专栏:玄魂工作室玄魂工作室

IDA Pro是目前功能最强大的静态反汇编分析工具,具备可交互、可编程、可扩展、多处理器支持等特点,是软件逆向分析必备的工具之一。

IDA Pro对Android的支持

IDA Pro是一款跨平台的商业软件,可以在Windows、Ubuntu、macOS系统上运行。IDA Pro每年都会有1~2次大规模的升级,升级的内容包括大量的Bug修正与新功能的添加。IDA Pro从6.1版本开始,提供了对Android的静态分析与动态调试的支持,包括Dalvik指令集的反汇编、原生库(ARM/Thumb代码)的反汇编、原生库(ARM/Thumb代码)的动态调试等。IDA Pro 6.95对Android的静态分析与动态调试的支持已经非常完善了。

分析DEX文件

以本章的实例Crackme0502为例,首先解压得到文件classes.dex,然后打开IDA Pro,将classes.dex拖到IDA Pro的主窗口中,此时会弹出加载新文件的对话框。IDA Pro解析得出,该文件属于Android DEX File。保持默认的选项设置,单击“OK”按钮,稍等片刻,IDA Pro就会完成对DEX文件的分析。

IDA Pro支持以结构化形式显示数据结构。单击“IDA View-A”选项卡,回到反汇编代码界面,然后单击菜单项“Jump”→“Jump to address”,或者按“G”键,将弹出地址跳转对话框。在其中输入“0”,让IDA Pro跳转到DEX文件的开头。可以看到,IDA Pro已经自动解释了结构体信息并加上了注释,如图5-3所示。

单击菜单项“Jump”→“Jump to segment”,或者按组合键“Ctrl+S”,将弹出段选择对话框。如图5-4所示,IDA Pro将DEX文件分成了11个段,每个段所对应的偏移量与DexHeader结构体相对应,最后两个段的偏移量可以通过计算得出。

DEX文件中所有方法的详细信息都可以在“Exports”选项卡中查看。方法的命名规则为“类名.方法名@方法声明”。

图5-3 IDA Pro自动解释了结构体信息并加上了注释

图5-4 IDA Pro将DEX文件分成了11个段

在“Exports”选项卡中任选一项,例如SimpleCursorAdapter.swapCursor@LL,然后双击跳转到相应的反汇编代码处,具体如下。

CODE:000D83C8 #Source file: SimpleCursorAdapter.java CODE:000D83C8 public android.database.Cursor android.support.v4.widget.SimpleCursorAdapter.swapCursor( CODE:000D83C8 android.database.Cursor c) #方法声明 CODE:000D83C8 this = v1 #this引用 CODE:000D83C8 c = v2 #第1个参数 CODE:000D83C8 .prologue_end CODE:000D83C8 .line 334 CODE:000D83C8 iget-object v0, this, SimpleCursorAdapter_mOriginalFrom CODE:000D83CC invoke-direct {this, c, v0}, <void SimpleCursorAdapter.findColumns(ref, ref) SimpleCursorAdapter_findColumns@VLL> CODE:000D83D2 .line 335 CODE:000D83D2 invoke-super {this, c}, <ref ResourceCursorAdapter.swapCursor(ref) imp. @ _def_ResourceCursorAdapter_swapCursor@LL> CODE:000D83D8 move-result-object v0 CODE:000D83DA CODE:000D83DA locret: CODE:000D83DA return-object v0 CODE:000D83DA Method End

IDA Pro的反汇编代码使用ref关键字来表示非Java标准类型的引用。方法第1行中invoke-super指令的前半部分如下。

invoke-super {this, C}, <ref ResourceCursorAdapter.swapCursor(ref)

前面的ref是swapCursor() 方法的返回类型,后面括号中的ref是参数类型,后半部分的代码是由IDA Pro智能地识别出来的。IDA Pro能够智能识别Android SDK的API函数,并使用imp关键字将其标识出来。例如,第1行中的invoke-super指令的后半部分如下。

imp. @ _def_ResourceCursorAdapter_swapCursor@LL

imp表明该方法为Android SDK中的API,@ 后面的部分为API的声明,类名与方法名之间用下画线分隔。

IDA Pro能识别隐式传递过来的this引用。在smali语法中使用p0寄存器传递this指针。在此处,由于this取代了p0,后面的寄存器命名值都要依次减1。

IDA Pro能识别代码中的循环、switch分支与try/catch结构,并能将它们以类似高级语言的结构形式显示出来,这对分析大型程序时了解代码的结构有很大的帮助。具体的代码反汇编效果,读者可以打开本章的SwitchCase与TryCatch实例的classes.dex文件自行查看。

定位关键代码

使用IDA Pro定位关键代码的方法在整体上与定位smali关键代码相差不大。定位关键代码的方法有如下三种。

  • 第一种方法是搜索特征字符串。按组合键“Ctrl+S”,打开段选择对话框,双击STRINGS段,跳转到字符串段,然后单击菜单项“Search”→“text”,或者按组合键“Alt+T”,打开文本搜索对话框,在“String”旁边的文本框中输入要搜索的字符串,单击“OK”按钮,稍等片刻就会定位搜索结果。不过,IDA Pro不支持对中文字符串的显示与搜索。如果字符串中的中文字符显示为乱码,需要编写相关的字符串处理插件。这项工作就交给读者去完成吧。
  • 第二种方法是搜索关键API。按组合键“Ctrl+S”,打开段选择对话框,双击第1个CODE段,跳转到数据起始段,然后单击菜单项“Search”→“text”,或者按组合键“Alt+T”,打开文本搜索对话框,在“String”旁边的文本框中输入要搜索的API的名称,单击“OK”按钮,稍等片刻就会定位搜索结果。如果API多次被调用,可以按组合键“Ctrl+T”来搜索下一项。
  • 第三种方法是通过方法名来判断方法的功能。这种方法比较笨拙,因为对混淆过的代码,定位其关键代码是比较困难的。例如,我们知道Crackme0502程序的主Activity类为MainActivity,在“Exports”选项卡中输入“Main”,代码会自动定位以“Main”开头的行(由此可以粗略判断每个方法的作用)。

下面我们来尝试破解Crackme0502。首先,安装并运行APK程序。程序运行后,会出现两个按钮,单击“获取注解”按钮会以Toast方式弹出三条信息。在文本框中输入任意字符串,单击“检测注册码”按钮,程序会弹出注册码错误的提示信息。在这里,我们以按钮事件响应为突破口来查找关键代码。通过搜索字符串“Main”,可以发现两个名为“OnClick()”的方法。那么,具体是哪一个呢?我们分别进去看看。前者调用了MainActivity.access$000() 方法,在IDA Pro的反汇编界面双击MainActivity_access,可以看到它其实调用了MainActivity的getAnnotations() 方法。看到这里我们应该能够明白,MainActivity$1.onClick() 方法是前面按钮的事件响应代码。接下来,查看MainActivity$2.onClick() 方法。双击代码行,来到相应的反汇编代码处,按“空格”键切换到IDA Pro的流程视图,代码的“分水岭”就是if-eqz v2, loc_AAC64处。如图5-5所示,在第一个方框下面,左边的箭头表示条件不满足时程序执行的路线,右边的箭头表示条件满足时程序执行的路线。

使用我们自己编写的字符串处理插件后,IDA Pro已经能够正确显示中文字符串了。从字符串信息中可以看出,直接修改if-eqz指令即可将程序破解。将光标定位到指令if-eqz v2, loc_AAC64所在的行,然后单击IDA Pro主界面的“Hex View-A”选项卡,可以看到这条指令所在的文件偏移为0xAAC46,相应的字节码为“38 02 0F 00”。通过前面的学习我们知道,只需将if-eqz指令的Opcode值38改成if-nez的Opcode值39即可。

说干就干。首先,使用010 Editor打开classes.dex文件,将偏移0xAAC46处的值中的“38”改为“39”。然后,运行DexFixer.1sc脚本,修复DEX的校验和,保存并退出。最后,将修改后的classes.dex文件导入APK文件,对APK重新签名后进行安装。测试发现,程序已经被破解了。

为了让读者了解一种常见的Android程序的保护手段,这里更换一下破解思路。通过前面的分析可以发现,MainActivity$SNChecker.isRegistered() 方法实际上返回了一个Boolean值,通过判断它的返回值可以确定注册码是否正确。现在的问题是:如果该程序是一个大型Android软件,调用注册码判断的地方可能不止一处,该如何处理?在这种情况下通常有两种解决方法:第一种方法是使用IDA Pro的交叉引用功能找到所有的方法被调用的地方,然后修改所有的判断结果;第二种方法是直接给isRegistered() 方法“动手术”,让它的返回结果永远为真。显然,第二种方法更加干脆,而且一劳永逸。

下面我们尝试使用第二种方法进行破解。按“空格”键切换到反汇编视图,发现直接修改方法的第2条指令为“return v9”即可完成破解(对应的机器码为“0F 09”)。重新修复DEX文件头的散列值并进行签名。安装程序,测试发现程序启动后就立即退出了,因此我们要先考虑程序的修改是否正确。使用IDA Pro重新导入修改后的classes.dex文件,发现修改的地方没有错,看来程序采取了某种保护措施。回想一下前面提到的两种退出程序的方法—— Context的finish()方法与android.os.Process的killProcess() 方法。首先按组合键“Ctrl+S”并双击CODE,回到代码段,接着按组合键“Alt+T”,搜索“finish”与“killProcess”,最后在MyApp类的onCreate() 方法中找到相应的调用。查看相应的反汇编代码,发现这段代码使用了Java的反射机制,手工调用了isRegistered() 方法来检查字符串“11111”是否为合法注册码。如果是合法字符串或者调用isRegistered() 方法失败,都说明程序被修改了,将调用killProcess() 方法来“杀死”进程。理解了保护手段,解决方法就很简单了:直接将两处killProcess() 的调用NOP掉(修改相应的指令为0)即可。

图5-5 程序执行的路线

本文节选自《Android软件安全权威指南》一书,丰生强 著,电子工业出版社出版。

丰生强,网名"非虫”,独立软件安全研究员,资深安全专家,ISC2016安全训练营独立讲师,有丰富的软件安全实战经验。自2008年起,在知名安全杂志《黑客防线》上发表多篇技术文章,从此踏上软件安全研究道路,常年混迹于国内各大软件安全论坛,著有畅销安全图书《Android软件安全与逆向分析》与《macOS软件安全与逆向分析》。

《Android软件安全权威指南》从平台搭建和语言基础开始,循序渐进地讲解了Android平台上的软件安全技术,提供了对Windows、Linux、macOS三个平台的支持,涉及与Android软件安全相关的环境搭建、文件格式、静态分析、动态调试、Hook与注入、软件保护技术、软件壳等主题,涵盖OAT、ELF等新的文件格式。

将Java与Native层的软件安全技术分开讲解,加入了与软件壳相关的章节,内容安排细致、合理。

每一章都以实例讲解的方式来展开内容,实践性较强。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-03-26,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 玄魂工作室 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • IDA Pro对Android的支持
  • 分析DEX文件
  • 定位关键代码
相关产品与服务
智能识别
腾讯云智能识别(Intelligent Identification,II)基于腾讯各实验室最新研究成果,为您提供视频内容的全方位识别,支持识别视频内的人物、语音、文字以及帧标签,对视频进行多维度结构化分析。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档