之前看过吾爱破解论坛一个关于Android'逆向动态调试的经验总结帖,那个帖子写的很好,对Android的脱壳和破解很有帮助,之前我们老师在上课的时候也讲过集中调试的方法,但是现在不太实用。对吾爱破解论坛的该贴,我也是看了很多遍,自己也查了不少资料,但是自己动手的时候总觉比较繁琐,并且很多细节的地方没有注意到,按照那个帖子尝试了几遍但是却出现了错误(后面会提到),今天周末重新拾起来试了试,终于把遇到的问题给解决了,顺便做个记录以免忘记了,其中的一些细节我也不是太明白,忘知道的人给指出。

第一步、给meke.exe工具添加系统环境变量


对Android的动态调试,要在cmd控制台手动输入命令,比较繁琐,下面我就偷懒用个简单一点的方法。为了能偷懒,我们需要将AndroidNDK提供的make.exe工具位于安装目录C:\AndroidDevlopment\android-ndk-r9d-windows-x86_64\android-ndk-r9d\prebuilt\windows-x86_64\bin下(具体的路径由自己安装目录决定),在进行Android动态调试之前,需要将该路径添加到系统或临时的PATH环境变量中,具体的操作如下:

将该路径添加到系统环境PATH变量中:

第二步、准备android_server文件和编写Android动态调试需要的mk文件


android_server文件是由IDA 6.6提供,具体的文件路径是在IDA的安装路径的IDA 6.6\dbgsrv目录下,这里直接拷贝过来使用(只有IDA6.1以上版本才支持Android的动态调试)。具体的mk文件我已经写好了,可以直接拷贝代码保存为.mk后缀文件使用,至于makefile文件的编写我也不知道。

cmd控制台1使用的listen.mk文件的编写:

#说明(控制台1)
#使用Android-NDK提供的make.exe程序,需将该程序的路径 xx\android-ndk-r9d-windows-x86_64\android-ndk-r9d\prebuilt\windows-x86_64\bin添加到环境变量
#记得要先开启Android模拟器或者将开发的手机连接到电脑
#这里android_server的版本是IDA 6.6的
#使用命令(控制台1) make -f listen.mk
#文件名称
MODALE_NAME=crackme.apk #安装程序到手机
listen:
adb push $(MODALE_NAME) /data/local/tmp
adb shell chmod 755 /data/local/tmp/$(MODALE_NAME) adb push android_server /data/local/tmp
adb shell chmod 755 /data/local/tmp/android_server #调试模式启动程序
#此时,手机界面会出现Waiting For Debugger页面
#格式 adb shell am start -D -n 包名/.类名
adb shell am start -D -n com.yaotong.crackme/.MainActivity #端口转发
adb forward tcp:23946 tcp:23946 #启动android_server
#adb shell su
adb shell /data/local/tmp/android_server


cmd控制台2使用的conn.mk文件的编写


#接下来 IDA附加,设置调试的选项(控制台2)
#静态找到目标函数对应所在模块的偏移地址,Ctrl+S找到对应模块的基地址,两个地址相加得到最终地址
#G跳转至地址,然后下断,F9运行
#其中port=8700是从ddms中看到的
#IDA中,F9运行程序,此时是runing状态
conn:
jdb -connect com.sun.jdi.SocketAttach:hostname=127.0.0.1,port=8700

简要的说一下.mk文件中的命令的作用:

#使用命令(控制台1)
make -f listen.mk

//注释 make -f listen.mk 说明是listen.mk文件在控制台使用的命令格式

#文件名称

MODALE_NAME=crackme.apk

//crackme.apk是我们要动态调试的目标apk应用程序

adb push $(MODALE_NAME) /data/local/tmp

//使用adb程序将要调试的目标apk应用程序拷贝Android系统的文件/data/local/tmp目录下

adb shell chmod 755 /data/local/tmp/$(MODALE_NAME)

//adb shell命令的意思是进入到Android系统中

//上面这条命令的作用是修改/data/local/tmp目录下的目标apk应用程序的文件权限为755

adb push android_server /data/local/tmp

//使用adb程序将android_server程序文件拷贝Android系统的文件/data/local/tmp目录下

adb shell chmod 755 /data/local/tmp/android_server

//修改Android系统目录/data/local/tmp下的android_server程序文件的权限为755

#格式 adb shell am start -D -n 包名/.类名 或者 adb shell am start -D -n 包名/包名.类名

adb shell am start -D -n com.yaotong.crackme/.MainActivity

//使用adb shell am start -D -n 包名/.类名 命令以-D调试模式启动apk应用程序,apk应用程序调试模式启动以后,会停止在Waiting For Debugger界面上。am start命令的具体的使用参考网址:http://developer.android.com/tools/help/adb.html#IntentSpec

adb forward tcp:23946 tcp:23946

//adb端口转发

adb shell /data/local/tmp/android_server

//启动拷贝到Android系统中android_server程序,等待IDA6.6程序的连接

#使用命令(控制台2) make -f conn.mk

//注释 make -f conn.mk 说明是conn.mk文件在控制台使用的命令格式

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

//jdb调试器的使用,具体命令行含义不知道,貌似Linux下该命令还不是这样的

OK,需要的文件已经准备齐全了,Android逆向动态调试的脚步又就进了一步。

第三步、打开Eclipse应用程序和为要调试的目标apk应用程序添加android:exported="true"选项,生成符合调试的apk程序


在Android逆向动态调试的时候,必须要打开Eclipse程序,并且还要运行Android的模拟器DDMS以方便使用adb程序和jdb程序,有钱的土豪可以使用真机调试。

在进行Android动态调试的动手之前,我们还需要做一件事情,为要调试的目标apk程序android:exported="true"以及修改listen.mk文件。前面看别人的写的帖子和博客也可能是人品问题!在Android动态调试的时候am
start -D命令不能以调试模式启动要调试的目标apk应用程序,也可能是人品爆发,今天百度查资料解决了,解决的方案就是为启动Activity添加android:exported="true"选项,加了这个选项之后执行am start -D命令,被调试的目标Apk程序能够出现Waiting For Debugger界面并停在那儿。那么现在的问题就是如何添加android:exported="true"选项,很简单。我们使用Android逆向工程利器AndroidKiller工具,这个工具的使用很久简单。我这里要动态调试的目标程序为crackme.apk应用程序,接下来打开AndroidKiller程序,直接拖拽crackeme.apk程序到AndroidKiller程序的界面内进行crackeme.apk应用程序的逆向反汇编,在解压的工程选项中找到crackme.apk的配置文件AndroidManifest.xml打开,如下图依次找到crackme.apk文件的包名、主活动的Activity以及正确的在活动中添加android:exported="true"选项:

在对要动态调试的目标apk程序crackeme.apk文件进行解包逆向修改添加android:exported="true"选项以后,千万不能忘记对修改后的目标程序的工程进行再次打包、签名处理生成新的crakeme.apk程序以备后面调试的时候使用,新生成的crakeme.apk程序在Android
Killer的安装目录的C:\AndroidDevlopment\AndroidKiller\projects\crackme\Bin路径下(具体的路径由Android Killer的安装目录决定)。现在轻松多了,要动态调试的目标应用程序crackme.apk文件有了。

对了,对应着要调试的目标apk应用程序的名称以及它的主启动Activity相应的修改
listen.mk文件中的变量 MODALE_NAME=crackme.apk以及 命令adb shell am start -D -ncom.yaotong.crackme/.MainActivity。

第四步、开启一个cmd控制台以调试模式启动目标apk程序


将第三步中修改后重新打包生成的C:\AndroidDevlopment\AndroidKiller\projects\crackme\Bin路径下的crackme.apk文件以及android_server、listen.mk文件、conn.mk文件拷贝到同一目录下,然后开启一个cmd控制台cd命令进入到该目录,执行命令 make
-f listen.mk 如下图:

其实在这里的时候要注意一下,如果在第三步中没有为要调试的目标apk应用程序添加android:exported="true" 选项,在执行adb
shell am start -D -n com.yaotong.crackme/.MainActivity命令的时候会出现如下的错误,但是如果为要调试的目标apk应用程序添加android:exported="true" 选项以后,执行该命令不会出现下面的错误提示,具体的原因我也不知道,之前在尝试Android动态调试的时候也是卡在了这里,可能是Android'应用程序的权限问题吧,在注册Android内容提供者的时候也需要导出,可能道理一样,也可以参考一下这篇文章http://chenxuebinbj.blog.163.com/blog/static/42869151201302235215832/。对于此种错误的情况,我在看雪论坛上也遇到过了。

:我真的很无语,当我写完这篇笔记想将该错误重现的时候,无语的事情出现了,我没有android:exported="true" 选项再次执行adb
shell am start -D -n com.yaotong.crackme/.MainActivity命令的时候,竟然没有报找不到com.yaotong.crackme/.MainActivity类的错误。我还连续试了几次,之前遇到的这个am start -D命令的错误提示都没有出现,真无语。更正一下,看来添加android:exported="true" 选项不是必须的。

此时Android'模拟中被动态调试的目标crackme.apk程序的运行状态如下,停止在了Waiting For Debugger界面:

启动一个IDA主程序,点击菜单 Debugger->Attach->Remote ArmLinux/Android debugger,打开调试程序对话框,在hostname一栏输入localhost,点击ok,然后在IDA弹出的窗口中,选择自己要附加的进程com.yaotong.crackme后点击OK即可,如下图:

此时,要动态调试的目标apk应用程序的进程被IDA6.6程序附加成功以后的状态如下图:

下面我们为目标apk应用程序的动态调试进行IDA6.6的一些调试设置,点击该IDA菜单项Debugger->Debugger Opitions 在弹出的Debugger setup窗口的Events中选择 suspend on thread start/exit 以及 suspend
on library load/unload,再点击OK退出。通过此操作可以设置程序在创建新线程和加载so时自动中断。具体操作见下图:

OK,IDA6.6的设置完成,然后按IDA快捷键F9。注意此时,cmd控制台不要关闭保持状态,IDA6.6程序不要关闭保持状态,Eclipse程序和Android模拟器也不能关闭继续保持状态,在后面的动态调试中还会用到。

第五步、再开启一个cmd控制台,在目标apk应用程序的so库的JNI_OnLoad函数处下断点


根据第四步中com.yaotong.crackme进程调试端口8612/8700修改conn.mk文件中的jdb命令为jdb
-connect com.sun.jdi.SocketAttach:hostname=127.0.0.1,port=8700,如下图:

再开启一个cmd控制台,cd命令进入到conn.mk所在的目录,执行make
-f conn.mk 命令,如下图:

连接成功后,在第三步的IDA6.6程序中按F9后Android模拟上的“waiting
for debugger"提示会自动消失,这个时候应该已经断在新线程,或者加载so处,具体的状态如下图。不过有一点不太明白,在我的调试运行过程中IDA6.6出现了如下的提示,不知道是否出错,请指导的大神帮忙指点一下。

IDA6.6下方的提示如下图,对于上图中的这个对话框我没有理会,直接一路确定迷迷糊糊的这个Add
map对话框就被我给无视了。

现在就可以在IDA6.6中按下快捷键CTRL+S来查看要调试的so是否已经加载了,如果没有就F9,直到加载了为止;如果已经有了,就记下该so的start内存基地址,然后直接用压缩软件解压crackme.apk文件,得到crackme.apk文件要加载的so库,并且再另开一个IDA6.6静态分析该.so库,找到JNI_Onload函数的内存相对虚拟地址(RVA)JNI_Onload_Offset,那么该JNI_OnLoad函数在内存中的真实地址为so.start+
JNI_OnLoad_Offset(so库的内存加载基址+JNI_Onload函数的内存相对虚拟地址)。

注意:在快捷键CTRL+S跳出的窗口中有几个个同名的so库,我们应当选择class类型为CODE即代码段的内存加载基址so.Start也就是权限为RX的这个,RX一般是代码段,RW一般是数据段。这里的so.Start=AA238000.

通过另开的IDA6.6静态分析目标apk应用程序的so库文件得到libcrackme.so文件中JNI_Onload函数的内存相对虚拟地址为00001B9C即JNI_OnLoad_Offset=00001B9C,因此JNI_Onload函数在内存中真实地址为so.start+
JNI_OnLoad_Offset=AA238000+00001B9C=AA239B9C.得到真实地址后,在附加目标进程的IDA6.6中按下快捷键G跳转到地址AA239B9C,然后按下快捷键F2就完成在JNI_OnLoad函数入口处下断点了。

OK,在JNI_Onload函数处下断点成功,下面就可以进行SO文件的动态调试F7、F8单步或者直接F9运行JNI_Onload函数断点处。

在apk应用程序的JNI_Onload函数进行下断点,对于从arm汇编的角度来产看apk程序的本地方法做了什么操作还是很有效果的,但是这种方法也不是经常有效的。在Android的JNI编程也可以不使用JNI_Onload函数进行Android的JNI编程。

Mark一下

有时间关注一下这位作者的使用IDA调试Android程序的思路:http://bbs.csdn.net/topics/390338991

参考网址

http://www.cnblogs.com/wanyuanchun/p/3760825.html?utm_source=tuicool

http://www.52pojie.cn/forum.php?mod=viewthread&tid=293648

2015/4/12 2:08

Android动态调试so库JNI_Onload函数-----基于IDA实现的更多相关文章

  1. IDA远程调试so库JNI_Onload函数

    JNI_OnLoad函数大概功能就是在程序加载so的时候,会执行JNI_OnLoad函数,做一系列的准备工作.很多时候,程序猿们会将一些重要信息放在此函数中,而不是通过某种事件来重复触发.包括说将反调 ...

  2. android在JNI_OnLoad入口函数下断点动态调试so库

    一般来说,很多APK的校验代码,都会在程序运行的时候自动加载一些动态so库,然后执行这些库中的校验代码.所以为了能够通过程序的校验,我们必须在执行这些函数之前下断点——理想的方法就是在JNI_OnLo ...

  3. android动态调试samli代码(转)

    转载自看雪http://bbs.pediy.com/showthread.php?t=189610,非常感谢原作者分享! 跟踪apk一般的做法是在反编译的smali代码中插入log输出,然后重新编译运 ...

  4. 通过模拟器和ida搭建Android动态调试环境的问题

    这几天在学Android的native层逆向.在按照教程用ida搭建动态调试环境时,第一步是把android_server 放到手机里执行,但是在手机里可以,在genymotion模拟器上就提示 no ...

  5. Android动态方式破解apk终极篇(加固apk破解方式)

    一.前言 今天总算迎来了破解系列的最后一篇文章了,之前的两篇文章分别为: 第一篇:如何使用Eclipse动态调试smali源码 第二篇:如何使用IDA动态调试SO文件 现在要说的就是最后一篇了,如何应 ...

  6. 开启Android Apk调试与备份选项的Xposed模块的编写

    本文博客地址:https://blog.csdn.net/QQ1084283172/article/details/80963610 在进行Android应用程序逆向分析的时候,经常需要进行Andro ...

  7. IDA动态调试技术及Dump内存

    IDA动态调试技术及Dump内存 来源 https://blog.csdn.net/u010019468/article/details/78491815 最近研究SO文件调试和dump内存时,为了完 ...

  8. JEB动态调试解密数据包加密字段

    0x00 场景 在测试某个app的时候,抓取数据包,发现某些参数存在被加密的情况,或者有签名校验的情况,这个时候如果我们想直接去篡改数据包的内容往往是做不到的,那就来看看抓取的某个app登录数据包,如 ...

  9. Android动态方式破解apk进阶篇(IDA调试so源码)

    一.前言 今天我们继续来看破解apk的相关知识,在前一篇:Eclipse动态调试smali源码破解apk 我们今天主要来看如何使用IDA来调试Android中的native源码,因为现在一些app,为 ...

随机推荐

  1. new String("abc"),到底在不在常量池中存储"abc"?

    String str = new String("Hello World"); 问之:这行代码到底有没有在字符串常量池中创建"Hello World"字符串呢? ...

  2. HDOJ-2181(深搜记录路径)

    哈密顿绕行世界问题 HDOJ-2181 1.本题是典型的搜索记录路径的问题 2.主要使用的方法是dfs深搜,在输入的时候对vector进行排序,这样才能按照字典序输出. 3.为了记录路径,我使用的是两 ...

  3. POJ-3281(最大流+EK算法)

    Dining POJ-3281 这道题目其实也是网络流中求解最大流的一道模板题. 只要建模出来以后直接套用模板就行了.这里的建模还需要考虑题目的要求:一种食物只能给一只牛. 所以这里可以将牛拆成两个点 ...

  4. 在Fedora中安装PostgreSQL并配置密码和开启远程登陆

    在Fedora中安装PostgreSQL并配置密码 首先先放出官方的文档教程 :https://fedoraproject.org/wiki/PostgreSQL 我写的内容其实也八九不离十,站在一个 ...

  5. FreeBSD 的xfce 终端动态标题不显示问题解决了:

    tcsh配置,home目录创建.tcshrc, 写入以下配置 alias h history 25 alias j jobs -l alias la ls -aF alias lf ls -FA al ...

  6. 一起来学习LiteOS中断模块的源代码

    摘要:本文带领大家一起剖析了LiteOS中断模块的源代码. 本文我们来一起学习下LiteOS中断模块的源代码,文中所涉及的源代码,均可以在LiteOS开源站点https://gitee.com/Lit ...

  7. Mysql被黑客攻击了?一定要注意一点,不要关闭mysql服务

    因为mysql没有关闭的情况,可以从缓存里面获取到数据,如果关闭了只能从文件里面去获取数据了,会大大加大恢复难度

  8. 第七届蓝桥杯省赛JavaB组——第十题压缩变换

    题目: 压缩变换小明最近在研究压缩算法.他知道,压缩的时候如果能够使得数值很小,就能通过熵编码得到较高的压缩比.然而,要使数值很小是一个挑战.最近,小明需要压缩一些正整数的序列,这些序列的特点是,后面 ...

  9. RocketMQ的安装配置:配置jdk环境,配置RocketMQ环境,配置集群环境,配置rocketmq-console

    RocketMQ的安装配置 演示虚拟机环境:Centos64-1 (D:\linuxMore\centos6_64) root / itcast : 固定IP 192.168.52.128 一,配置J ...

  10. MarkDown-简单学习

    标题 注意:首部添加1-6个"#"号来设置标题大小: 字体 1:粗体 (注意:首尾同时添加2个"*"号来设置) 2:斜体 (注意:首尾同时添加1个"* ...