之前看过吾爱破解论坛一个关于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. (三)MySQL锁机制 + 事务

    转: (三)MySQL锁机制 + 事务 表锁(偏读) 偏向MyISAM存储引擎.开销小,加锁快,无死锁,锁定粒度大,发生锁冲突的概率最高,并发最低. 查看当前数据库中表的上锁情况,0表示未上锁. sh ...

  2. 京东 Vue3 组件库闪亮登场

    京东零售开源项目 NutUI 是一套京东风格的轻量级移动端 Vue 组件库,是开发和服务于移动 Web 界面的企业级产品.经过长时间的开发与打磨,NutUI 3.0 终于要和大家见面了!3.0 版本在 ...

  3. 微信小程序左滑删除

    <view class="touch-item {{item.isTouchMove ? 'touch-move-active' : ''}}" data-index=&qu ...

  4. HDOJ-3416(最大流+最短路+ISAP算法+向前星dijikstra算法+如何判断一条边是否在最短路中)

    Marriage Match IV HDOJ-3416 这题的题意就是要找两点之间最短路的路径个数,而且边不能重复. 最大流和最短路的结合.首先正向和反向建图,再跑两遍dijikstra.到这里就求出 ...

  5. POJ-1087(最大流+EK算法)

    A Plug for UNIX POJ-1087 这一题也是最大流的应用,但是题目有点绕. 题目的意思就是有插座和插头,只不过这里使用设备取代了插头.只有插座和设备进行匹配了. 题目要注意的是那个适配 ...

  6. POJ-2502(Dijikstra应用+最短路)

    Subway POJ-2502 这里除了直接相连的地铁站,其他图上所有的点都要连线,这里是走路的速度. 记住最后的结果需要四舍五入,否则出错. #include<iostream> #in ...

  7. Java-Socket通信 知识点记录

    目录 一.Socket基本案例 二.消息通信 2.1 双向通信 2.2 告知发送结束 2.2.1 通过Socket关闭 2.2.2 通过Socket关闭输出流的方式 2.2.3 通过约定符号 2.2. ...

  8. mysql查询缓存简单使用

    MySQL是一个关系型数据库管理系统,由瑞典MySQL AB 公司开发,属于 Oracle 旗下产品.MySQL 是最流行的关系型数据库管理系统之一,在 WEB 应用方面,MySQL是最好的 RDBM ...

  9. SQL SERVER跨数据库服务,联表进行查询

    SELECT * FROM 数据库A..表A a, 数据库B..表B b WHERE a.field=b.field

  10. vue-cli脚手架安装及注意事项

    1.下载nodejs 链接:https://nodejs.org/en/直接下载电脑对应的版本即可. 13.5网上说不大稳定(一个表示①推荐用户版本,②最新版本) 2.安装nodejs 建议在D或者E ...