阿里2014移动安全挑战赛第二题调试笔记

Posted 夏侯爷の星辰大海

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了阿里2014移动安全挑战赛第二题调试笔记相关的知识,希望对你有一定的参考价值。

 

0x00前言

  最近在学习安卓安全,看到52破解上面有分析2014年阿里安全挑战赛的第二个crackme的文章。勾起了我的回忆,那是我第一次参加安全比赛,在安卓安全也没有做多深入的学习。第一题比较简单,直接在logcat里面就可以看到输出的信息,只要将数字和文字的关系对应关系搞明白就可以解出来。第二题我就遇到困难了,虽然临时学会了怎么用ida调试so,但只要ida附加到进程上去,程序就退出了,屡试不爽。心里也有往反调试那边想,但是功力不足没有能把反调试干掉,最后止步于这一题。现在又看到基于这道题的调试技巧文章,所以就拿起来练练手,练习练习动态调试。

 

0x01静态分析

应用程序打开的主界面是

把程序拖到jeb中,可以看到主程序的代码比较简单,就是取得输入的信息,然后调用native的securityCheck方法做比较,根据返回的结果展示不同的内容。没有提供有用的信息。

解压程序,将libcrackme.so拖到ida中,找到Java_com_yaotong_crackme_MainActivity_securityCheck函数直接f5,代码没有做混淆,条理也非常清晰,对比v6和v5的值。

其中v5是用户的输入,看起来比较别扭,参考蒸米《安卓动态调试七种武器之孔雀翎 – Ida Pro》的内容:一个指针加上一个数字,比如v3+676。然后将这个地址作为一个方法指针进行方法调用,并且第一个参数就是指针自己,比如(v3+676)(v3…)。这实际上就是我们在JNI里经常用到的JNIEnv方法。因为Ida并不会自动的对这些方法进行识别,所以当我们对so文件进行调试的时候经常会见到却搞不清楚这个函数究竟在干什么,因为这个函数实在是太抽象了。解决方法非常简单,只需要对JNIEnv指针做一个类型转换即可。比如说上面提到v3指针,我们选中后按一下”y”键,然后将类型声明为”JNIEnv*”。

可以看到off_628C的内容为

看到字符串为wojiushidaan,将该字符串输入,并没有通过校验,可见程序在运行的时候对比较的字符串做了修改,这就要求我们动态去调试这个程序了。

 

0x02动态调试

到ida安装目录.\\IDA 6.8\\dbgsrv\\下面将android_server拷贝到安卓设备中

adb push android_server /data/local/tmp/

修改文件的权限

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

以9000作为调试端口启动,修改默认端口是因为有些反调试会读取/proc/net/tcp下的信息,默认端口容易躺枪

adb shell /data/local/tmp/android_server -p9000

另开一个窗口,在这个窗口里面做端口转发

adb forward tcp:9000 tcp:9000

修改Debugger-Run-RemoteArmLinux/Android debugger中的配置去调试,点击ok

就可以看到所有运行的程序,基本我们启动的需要调试的应用的pid号都比较大,可以按pid排序方便找到调试的程序。

载入的过程较长,其中库的载入有弹框确认,直接略过,在modules框中找到函数,在函数头下断点

F9运行,程序直接退出,ida输出如下

几次尝试都是这个结果,所以肯定有反调试。

 

0x03反调试

我们用以下命令以调试模式启动一个应用

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

其中主activity可以在logcat里面看到,或者反编译manifest文件也可以看到

程序启动停在等待调试器的状态

修改Debugger-debugger options的配置,让程序在载入lib的时候断下来,这样我们才可以调试JNI_Onload函数,还有某些可能会把反调试放在.init_array,该函数的加载比JNI_Onload还要早。

然后再附加进程,然后f9运行程序,可以看到程序还是停在等待调试器的状态

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

让程序恢复运行,这时程序会在linker停下来,在JNI_Oload函数上下断点,然后f9运行程序,f8逐条运行,运行到这条函数的时候就会退出,f7跟进去调试

是一个创建线程的库函数,如果在反汇编代码中可以看到具体的地址指令是 BLX R7,R7的值就是pthread_create函数的地址,如果是做比赛可以直接nop  BLX R7,然后去试试有没有过掉反调试。

点击dword_9BC882B4函数也可以看到函数已经被定位到了pthread_create

而在静态中只有符号信息,没有做相应的映射

所以可以知道unk_9BC836A4就是该线程创建完成之后执行的函数,在该函数下断点,f9执行,断在了该函数

F5之后比原来的汇编代码还别扭

可以看到有一个明显的循环体,其中主要的函数调用是BL unk_9BC8330C,可以直接nop这个函数调用,然后去试试反调试是不是已经过掉了,不过现在不是做比赛,我想继续跟进去看看他是怎么做的。

不过里面的代码确实是难看懂,反正是调试,不如就动态跟着一步一步调一下,发现里面读取了/proc/pid/status的tracepid字段,然后做了字符串的比较,最后执行到了

可以看到R2寄存器指向了libc.so下的kill函数,这就是反调试的最后一步,当发现被调试时杀死进程,来实现自毁的目的,在流程图里面也可以看到这个一个单独的分支,之后就没有代码了。

所以我们把BGE loc_9BC59600这个函数nop掉,让这个分支的代码不执行。libcrackme.so加载的基地址为0x9BC58000,修改原文件的地址为0x9BC595D80-x9BC58000=0x15D8

然后重打包运行,ida附加上去没有退出,说明我们的反反调试成功了,在securityCheck函数上下断点,然后f8单步调试

此时R2指向了保存的密码

输入aiyou,bucuoo,答案正确

 

0x04其他思路

思路一:

在我们输入密码进行比较的时候,logcat有输出信息

所以我们可以使用这条打印信息来把密码打印出来

这是原来的代码布局

选择的patch方法是直接把这个log函数往下移,因为在0x12A4地址处正好有我们需要的打印的数据地址赋值给了R2寄存器,因此将代码段从0x1284到0x129C的地方都用NOP改写,在0x12AC的地方调用log函数,同时为了不影响R1的值,把0x12A0处的R1改成R3: 9BC7F1A8,同时由之前的动态调试我们也确认了此时R2指向的是密码,所以具体的patch方案如下:

  ①0x1284-0x129c:NOP (0000A0E1)

  ②0x12A8:MOV R0,#4 (0400A0E3)

  ③0x12AC:BL  __android_log_print (88FFFFEB)这里的88是由一开始在0x1284的92FFFFEB得出的,两个地址相差40个字节,ARM指令4字节对齐,即最低两位是00,所以地址右移两位,应除以4,对应就为:0x92-10=0x88。

  ④0x12A40-0x12A84:NOP (0000A0E1)

patch之后的代码布局

重新打包运行,随便输入密码,打印出来的log如下

思路二:

静态时密码的偏移量是0x4450

所以我们attach上进程后不运行,直接在libcrackme.so的基地址加上0x4450得到的地址为

0x9BC30000+0x4450=0x9BC34450

G直接跳转到那个位置,然后就看到了答案,请允许我做一个悲伤的表情,为什么当初没有想到。

 

0x05小结

  除了读取/proc/pid/status下面的tracepid方法外,现在反调试还采用了读取/proc/net/tcp下面的tcp信息,对常见的调试器的调试端口进行检测。还有函数的运行时间,读取进入函数和出来函数的系统时间,然后做差和预定值作比较,来判定是否处于调试状态。
  现在的反调试还是在大粒度上面做的,采用nop线程开启和nop整个函数调用都可以过掉整个反调试,是不是可以采用线程之间互相配合的方式,主线程依赖于子线程的运行,如果子线程不运行,那么主线程也退出,细化一点就是把反调试函数和正常功能函数混合到一起,比如采用生产者消费者模型来建立主从线程的关系,这样过掉反函数的难度就更大一些了。

 

参考:

ARM中跳转指令BL/BLX偏移值计算规则

[Android 原创] 【练习】IDA调试Android native(Crackme)

Android逆向之旅—动态方式破解apk进阶篇(IDA调试so源码)

安卓APP动态调试-IDA实用攻略

安卓动态调试七种武器之长生剑 - Smali Instrumentation

以上是关于阿里2014移动安全挑战赛第二题调试笔记的主要内容,如果未能解决你的问题,请参考以下文章

阿里云移动研发平台EMAS,是如何连续5年安全护航双11的?

2021.5.26,阿里巴巴实习笔试,第二题

Leetcode代码练习

计蒜客-第五场初赛-第二题 UCloud 的安全秘钥(简单)

比例简化(NOIP2014 普及组第二题)

2014年百度之星资格赛第二题Disk Schedule