当前位置:   article > 正文

APP动态分析-AndroidStudio调试+IDA 我来了_apk动态分析

apk动态分析

历史文章了,补发上来

0x00 前言

动态分析(dynamic analysis)是指在严格控制的环境(沙盒)中执行恶意软件,并使用系统检测实用工具记录其所有行为

静态分析(static analysis)通过浏览程序代码来理解程序的行为。

关于动静态分析,两者目的是相同的,无非是破解软件,分析软件行为,但是动态分析会比静态高效一点,

由于对静态分析比较熟悉,先说一下静态分析的思路

  1. 确认目的

        你是要破解APP,为了获取什么:

  • 绕过完整性检查;
  • 绕过调试检查;
  • 去广告;
  • 去内购;
  1. 获取信息

        运行APP,查看log、toast、运行信息等;

  1. 反编译获取smali和AndroidMainfest.xml
  2. 定位关键位置

        全局查找关键字符串和日志信息

  1. smali代码注入
  2. hook
  3. 用ida分析so文件

大部分加密函数,关键函数会放在so文件里,用ida分析so文件,可以帮助我们定位到关键函数,然后继续修改smali,从而达到我们破解的目的。

但是今天不讲静态分析。

0x01 调试前准备

以阿里Crackme为例,学习ida native分析。

 

1.反编译

用AndroidKiller对目标apk进行反编译;

2.添加debuggable属性

反编译成功后,为了后面的动态调试,需要我们做两件事;

1.在AndroidManifest.xml中添加android:debuggable=”true”

2.在入口处添加waitForDebugger代码进行等待调试

找到入口,添加一行代码:invoke-static {}, Landroid/os/Debug;->waitForDebugger()V

其实对应的Java代码就是:android.os.Debug.waitForDebugger();

保存,再点击编译,编译成功;AndroidKiller会自动对apk进行签名,这也是其方便之处;

再次反编译,可以看到java源码中增加了Debug.waitForDebugger();函数

 

0x02 用Android Studio对smali进行动态调试

1.插件安装

android studio安装smalidea-0.03插件,点击File->Settings->plugins->instal plugins from disk,选择下载的zip包就行,不要解压。安装完成后,AS提示重启生效,重启即可

2.导入工程

点击File->Open,选择文件目录即可

3.设置调试配置

Run->Edit configurations,点击+号,新建remote类型调试器,设置Name, 修改端口号,用DDMS查看应用占用端口,一般都是8700;

盗一张图

4.开始调试

因为我之前添加了waitForDebugger(),所以先下好断点,直接打开app,点击Debug(也就是绿色的那个小按钮),可以看到下图,(如果没有添加waitForDebugger(),可以用命令adbshell am start -D -n com.yaotong.crackme/.MainActivity来打开apk,从而进入调试模式)已经进入调试;

此时,DDMS那边,红色小蜘蛛也变成绿色了,代表已经进入调试了。

开始调试,使用F7单步调试,F8单步跳出进行操作;

至此,已经实现用Android Studio对smali进行动态调试,但是鉴于在实战中用Android Studio对smali进行动态调试的情况很少,原因是一般apk都不会像这些creakme这么小,当apk过大,一步步调试就显得过慢,所以出现用ida进行动态调试。

0x03 IDA调试Android native

1.IDA

2.IDA快捷方式

F5/Tab 翻译成C语言

y 还原JNI函数名

一般JNI函数方法名首先是一个指针加上一个数字,比如v3+676。然后将这个地址作为一个方法指针进行方法调用,并且第一个参数就是指针自己,比如(v3+676)(v3…)。这实际上就是我们在JNI里经常用到的JNIEnv方法。因为Ida并不会自动的对这些方法进行识别,所以当我们对so文件进行调试的时候经常会见到却搞不清楚这个函数究竟在干什么,因为这个函数实在是太抽象了。解决方法非常简单,只需要对JNIEnv指针做一个类型转换即可。

选中v3变量,按下y键;

将声明类型转换成JNIEnv*;

 

Shift+F12 打开so中所有的字符串内容窗口

Ctrl+S 在IDA View窗口时,是查看segment信息

Ctrl+S 在调试窗口,也就是Debug View时,可以快速定位到我们想要调试的so文件映射到内存

的地址

G 在IDA调试页面的时候,我们可以使用G键快速跳转到指定的内存位置

这里如果跳转到目的地址之后,发现是DCB数据的话,可以在使用 P 键,进行转化即可

F7 可以单步进入调试

F8 可以单步调试

 

3.调试前准备

a.在IDA中找到android_server

在IDA安装目录\dbgsrv\android_server

b.将android_server放到设备/data/local/tmp,并执行

用命令adb push

tip: 需要真机,模拟器不能运行,原因是结构不同,一个是arm,一个是x86

此时权限不足,不能执行,需要添加权限;

添加权限;

添加权限后;

执行./android_server;

此时ida仍然连接不上,因为还需要进行端口转发,

adb forward tcp:23946 tcp:23946

c.设置ida连接上设备

选择Debugger–>Attach–>Remote ARMLinux/Android debugger;

设置Hostname为127.0.0.1或者localhost,也就是本地;Port默认23946,不需要改;

在Debug option勾选这三项,方便调试;

点击上面的ok后,会出现下图的进程列表,如果android_server没有以root权限运行,是看不到这么多进程的,所以要以root权限运行,然后找到需要调试的进程,可以试用Search功能进行搜索进程。

4.正式调试

以2016阿里的Crackme为例进行调试。

目的:获取密码,或者绕过输入密码的界面;

思路:找到输入密码按钮的关键函数,看是否能找到密码;先静态分析,查看源码,若是调用了so,需要到native层进行静态分析,然后动态调试,对关键函数进行下断点,理清函数执行流程,寻找突破。

0x00 寻找入口

这里我使用AndroidKiller打开apk,找到入口为 com.yaotong.crackme.MainActivity

查看并分析源码;发现securityCheck()放在native层调用,这时候我们需要到native层分析。

0x01 寻找native函数的相对地址

将libcrackme.so拖到ida中分析,找到securityCheck()函数的位置;一般是完整的包名加函数名,如:Java_com_yaotong_crackme_MainActivity_securityCheck

发现native函数的相对地址:11A8

0x02 定位关键函数的绝对地址

此时另外打开一个ida,按之前的方式,关联调试应用,选择对应的调试进程;

用ctrl+s找到对应so,也就是libcrackme.so的基地址为:5BA11000

而绝对地址=基地址+相对地址=5BA11000+11A8=5BA121A8;使用G键,直接跳转到这个地址;

选择第一个小蓝点,下个断点,然后F9运行程序;

然后就挂掉了;

这种情况一般就是做了反调试。

0x03 反调试技术

先简单说下调试原理,IDA是将android_server在root环境下注入到被调试的进程中,用到的技术是Linux的ptrace,而Android的进程如果被另一个进程ptrace之后,会在相应进程的 status文件中(文件目录/proc/[pid]/status)的一个字段(TracerPid)中标注是被哪个进程ptrace。这里就是反调试的关键。

没有被调试的正常情况,如下:

应用被29443进程号的应用ptrace;

查看29443的pid是谁;

也就是我们之前启动的ida带的android_server了。

常见的反调试技术:

  1. 直接调用ptrace(PTRACE_TRACEME, 0, 0, 0);
  2. 判断TracerPid的值,如果!=0,直接退出程序;
  3. 系统23946端口的占用情况,当端口被占用时,直接退出程序;
  4. 判断android_server的进程信息;

0x04 添加debuggable属性,重打包

因为AndroidKiller集成大部分功能,所以还是用AndroidKiller来完成这部分。

发现不行。。。

好吧,原因是我debuggable放错地方了。。。 T.T

好了,再来一次;

还是不行,想哭

0x05 反调试对抗

此时发现正常的调试手段是进不去的,因为此应用的反调试方式是使用了上面的第二种方式,而且还是在底层写了一个检测的循环,原理便是在程序运行过程中,循环检测进程中的TracerPid标识来确定程序是否被调试。只要一运行程序,就退出了调试界面,说明这个循环检测程序执行的时机非常早,已知最早的两个时机是:一个是.init_array,一个是JNI_OnLoad。

那么正常方式进不去,有什么办法是能够在.init_array加载之前就能够进入debug?这是就想到waitForDebugger()函数了,只要把waitForDebugger()放在.init_array加载之前就可以了,但是这里不想又重打包,可以换个方式,用am命令,以调试的方式启动应用。

adb shell am start -D -n com.yaotong.crackme/.MainActivity -D,用debug方式启动

 

步骤按理应该是如下:

第一步:运行:adb shell am start -D -n com.yaotong.crackme/.MainActivity

出现Debugger的等待状态

第二步:启动IDA 进行目标进程的Attach操作

第三步:运行:jdb -connect com.sun.jdi.SocketAttach:hostname=127.0.0.1,port=8700

第四步:设置Debugger Option选项

第五步:点击IDA运行按钮,或者F9快捷键,运行;jdb成功的attach住了,debug消失,正常运行

但是我在第三步的时候jdb连接不上,没办法,看来动态是不行了,只能静态去找反调试的位置了。

  

参考:http://www.wjdiankong.cn/android%E9%80%86%E5%90%91%E4%B9%8B%E6%97%85-%E5%8A%A8%E6%80%81%E6%96%B9%E5%BC%8F%E7%A0%B4%E8%A7%A3apk%E5%89%8D%E5%A5%8F%E7%AF%87eclipse%E5%8A%A8%E6%80%81%E8%B0%83%E8%AF%95smail%E6%BA%90%E7%A0%81/

参考:http://www.wjdiankong.cn/android%e9%80%86%e5%90%91%e4%b9%8b%e6%97%85-%e5%8a%a8%e6%80%81%e6%96%b9%e5%bc%8f%e7%a0%b4%e8%a7%a3apk%e8%bf%9b%e9%98%b6%e7%af%87ida%e8%b0%83%e8%af%95so%e6%ba%90%e7%a0%81/

参考:http://www.52pojie.cn/thread-554068-1-1.html

参考:https://www.52pojie.cn/thread-559205-1-1.html

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/从前慢现在也慢/article/detail/478028
推荐阅读
  

闽ICP备14008679号