加菲猫 发表于 2016-1-6 15:41

使用 IDA 进行简单的脱壳

本帖最后由 加菲猫 于 2016-1-6 17:33 编辑

写在前面:

0. 主要针对 http://blog.csdn.net/pengyan0812/article/details/46275317 这篇文章进行二次加工,因此算作“Android 分享”,感谢原作者的分享

1. 在实验过程中,原作个别步骤存在问题,因此按照自己的实验过程重新记录实验步骤

2. 文章以实践为主,很少涉及理论知识

3. 由于图片较多,上传过于混乱,因此你可以下载图文排版异常精美的 PDF 版及其对应的 apk 文件

4. 贴后答疑,如果你在实验的过程中存在问题可以留言(不要咨询我特别高深的问题,因为这篇文章都是我瞎编了,我也不会,哈哈哈)

5. 感谢所有乐于分享的人们

6. 附件内容超过 1M,请前往:http://pan.baidu.com/s/1nuyxc9N 密码:d29f

0x00 摘要Apk脱壳方法有两种:
(1)使用脱壳神器ZjDroid进行脱壳(现在此方法不是很好使,因为很多应用都同步更新自己的防御机制,个人觉得熟练脱壳还是得使用 IDA 进行操练)。

(2)使用 IDA Pro 在 dvmDexFileOpenPartial 这个函数下断点进行脱壳。(大杀技)加壳能防止源代码被偷窥,但是这只能防止静态分析,无法防止动态调试。不管怎么加壳保护,原始的classes.dex在App运行时都要加载到内存中。所以如果在App加载classes.dex处下个断点,然后再把classes.dex对应内存中的内容抠出来还原成原始的classes.dex文件,就能达到脱壳的目的了。
0x01 实验(1)以第1届Alictf的EvilApk300(如图0所示)为例,简单介绍一下使用IDA Pro 进行脱壳的步骤


[*]step 1:将手机连接电脑
adb install C:\Users\Bravelee\Desktop\jscrack.apk

-------启动服务,开启监听-------
adb shell
su root
chmod 777 /data/local/tmp/android_server
/data/local/tmp/android_server

------------端口转发------------
再次打开一个终端窗口:
adb forward tcp:23946 tcp:23946

-----------root 模式下启动该 app----------
因为加壳了,所以只能查看 manifest.xml 文件才能获取 apk 对应的包名
adb shell
su root
am start -D -n com.ali.tg.testapp/com.ali.tg.testapp.MainActivity

如果成功,手机上 app 会弹出 “Waiting For Debugger”

[*]step 2:操作 IDA
依次点击”Debbuger -> Attach -> Remote ARMLinux/Android debugger”启动IDA Pro中的Android Debbuger
然后在弹出的对话框中点击”Debug options”按钮,将“Suspend on process entry point”,“Suspend on thread start/exit”,“Suspend on library load/unload”这几个选项勾选上,再将Hostname配置为localhost,端口:23946



注意:Ctrl + F 方便查找

[*]step 3:继续 IDA
脱壳的时候重点关注:dvmDexFileOpenPartial 函数(在该函数处下断点)

依次点击“Debugger -> Debugger windows -> Module list”,找到so文件列表
在Module list中找到libdvm.so这个文件(注意:Ctrl + F 方便查找)
双击libdvm.so,在弹出的函数列表中找到dvmDexFileOpenPartial函数,然后双击该函数就看到dvmDexFileOpenPartial函数的具体实现
在dvmDexFileOpenPartial函数处下断点(F2 下断点)

[*]step 4:使用jdb命令动态调试Apk
点击 ida 左上角的绿色运行按钮(F9)blob:http%3A//115.29.201.173/46f80edb-fc81-43d1-973d-de05b990eaa8
打开 DDMS 工具(android-sdk\sdk\tools\ddms.bat)

使用jdb命令进行调试时,一般选择8700端口,因为8700是默认的调试端口;打开终端窗口,输入:

jdb -connect com.sun.jdi.SocketAttach:hostname=localhost,port=8700

此时 IDA 会弹出 ”Add map…” 窗口(点击 cancel 按钮即可):
此时进程就执行到了dvmDexOpenPartial函数断点处,dvmDexOpenPartial 函数的定义:
/*
* Create a DexFile structure for a "partial" DEX.This is one that is in
* the process of being optimized.The optimization header isn't finished
* and we won't have any of the auxillary data tables, so we have to do
* the initialization slightly differently.
*
* Returns nonzero on error.
*/
int dvmDexFileOpenPartial(const void* addr, int len, DvmDex** ppDvmDex)
{
    DvmDex* pDvmDex;
    DexFile* pDexFile;
    int parseFlags = kDexParseDefault;
    int result = -1;

    /* -- file is incomplete, new checksum has not yet been calculated
    if (gDvm.verifyDexChecksum)
      parseFlags |= kDexParseVerifyChecksum;
    */

    pDexFile = dexFileParse((u1*)addr, len, parseFlags);
    if (pDexFile == NULL) {
      ALOGE("DEX parse failed");
      goto bail;
    }
    pDvmDex = allocateAuxStructures(pDexFile);
    if (pDvmDex == NULL) {
      dexFileFree(pDexFile);
      goto bail;
    }

    pDvmDex->isMappedReadOnly = false;
    *ppDvmDex = pDvmDex;
    result = 0;

bail:
    return result;
}


dvmDexFileOpenPartial 函数的原型如下所示:
int dvmDexFileOpenPartial(const void* addr, int len, DvmDex** ppDvmDex)
其中 addr表示Dex文件在内存中的起始地址,
len 表示Dex文件的大小,
ppDvmDex是一个指向DvmDex类型的二级指针,具体表示什么,我也不知道脱壳只用到 addr 和 len 这两个参数,所以需要获取 R0 和 R1 寄存器的值(ARM的传递参数机制规定 R0 保存着函数从左至右的第一个参数,R1 保存着函数从左至右的第二个参数),可以查看到寄存器列表中的内容如图所示:

[*]step 5:在 IDA 中编写idc脚本dump内存还原dex文件
选择 File -> Script command…

blob:http%3A//115.29.201.173/b98aa35f-a179-419e-8882-69bee6256afd



稍等片刻,即可以把 dump 出来的 dex 文件保存在 C 盘根目录
IDC脚本:
auto fp, dex_addr,end_addr;
    fp = fopen("C:\\dump.dex","wb");
    end_addr = r0 + r1;
    for (dex_addr = r0; dex_addr < end_addr; dex_addr ++)
      fputc(Byte(dex_addr),fp);



[*]step 6:使用 JEB 分析dump 出来的 dex 文件[此处内容请参考原文]

本文脱壳核心思想:在 dvmDexFileOpenPartial 函数处下断点,然后动态调试 Apk,待App 运行到断点处后,写一个 idc 脚本将 dex 文件所对应的内存 dump 出来,然后还原成 dex 文件就完成脱壳操作了,最后再分析反编译 dex 所得到的 smali 文件。


[*]参考文献
听鬼哥说ZJDROID脱壳的简单使用:http://blog.csdn.net/guiguzi1110/article/details/38727753
安卓逆向学习笔记(9)- 使用IDA Pro进行简单的脱壳 :http://blog.csdn.net/pengyan0812/article/details/46275317
Android应用方法隐藏及反调试技术浅析:http://www.kuqin.com/shuoit/20151012/348473.html




加菲猫 发表于 2016-1-11 17:42

myoldid 发表于 2016-1-8 13:07
我在输入 jdb -connect com.sun.jdi.SocketAttach:hostname=localhost,port=8700 后,报致命错误,无法附加 ...

不好意思,回复略晚,adb forward tcp:23946 jdwp:5586--->   adb forward tcp:23946 tcp:23946

欢迎一起交流学习

mmpo789 发表于 2016-3-14 02:48

加菲猫 发表于 2016-1-11 17:42
不好意思,回复略晚,adb forward tcp:23946 jdwp:5586--->   adb forward tcp:23946 tcp:23946

...

我输入 jdb -connect com.sun.jdi.SocketAttach:hostname=localhost,port=8700 后,报致命错误,无法附加到目标 VM不知道你说的这是什么意思:adb forward tcp:23946 jdwp:5586--->   adb forward tcp:23946 tcp:23946

加菲猫 发表于 2016-1-6 15:43

我去。。。。粘贴过来排版如此混乱。。。。 请大家下载精美的 pdf 版吧,谢谢,另外咨询一下版主,论坛支持 Markdown 排版格式吗?谢谢

aikuimail 发表于 2016-1-6 15:54

用代码标记呀楼主,你的图片挂了吧

Ericky 发表于 2016-1-6 16:17

赞一个!

Hmily 发表于 2016-1-6 16:30

加菲猫 发表于 2016-1-6 15:43
我去。。。。粘贴过来排版如此混乱。。。。 请大家下载精美的 pdf 版吧,谢谢,另外咨询一下版主,论坛支持 ...

抱歉,论坛不支持Markdown 排版,文章还得编辑下,现在图片是盗链无法显示,最好上传到本地。

smcree 发表于 2016-1-6 16:33

的确,图片都挂了 ,估计是图片比较多,没上传成功。

加菲猫 发表于 2016-1-6 17:39

Hmily 发表于 2016-1-6 16:30
抱歉,论坛不支持Markdown 排版,文章还得编辑下,现在图片是盗链无法显示,最好上传到本地。

终于排版好了{:1_908:}:loveliness:

Hmily 发表于 2016-1-6 18:23

加菲猫 发表于 2016-1-6 17:39
终于排版好了

太辛苦了,还有2个图片没有上传,还是在那转转的。

yyj85391 发表于 2016-1-6 21:24

好教程啊,堪称手把手叫

myoldid 发表于 2016-1-7 08:48

难得一见的详细教程,中午试试。多谢楼主分享
页: [1] 2 3 4
查看完整版本: 使用 IDA 进行简单的脱壳