首页
社区
课程
招聘
[原创]2015年AliCrackMe中第二道题的分析
发表于: 2019-8-13 01:46 6162

[原创]2015年AliCrackMe中第二道题的分析

2019-8-13 01:46
6162

       这道题涉及了动态调试so、反调试、基本的ARM汇编等等。以下是逆向得到注册码的过程。

       app装入模拟器后可以看出,界面依然是逆向获得注册码的类型。

       那就找找看校验验证码的地方在哪里吧。将app用解压软件打开,拿出其中的classes.dex文件,拖出静态分析工具JEB中直接分析,得到的JAVA代码如下:

       由上面的代码可以看出,app启动后就加载了动态库crackme, 从从这库中导出了本地函数securityCheck,然后流程才到app的入口onCreate函数中。入口函数的代码也不复杂,只是设定了“输入密码”这个按钮的点击监听函数,然后在监听函数中校验验证码,根据校验的结果显示不同的界面。

       现在的问题是校验验证码的代码不在dex文件,而在某个库中。再次打开apk文件查看lib目录,发现只有一个动态库:libcrackme.so。同样,将其拖出,然后拖拽进IDA分析(这里使用的IDA是32位7.0版本)。

       首先在左边Function name窗口找到securityCheck在库中对应的函数名Java_com_yaotong_crack

me_MainActivity_securityCheck(名字这么长是由so中导出导出函数的命名规则所致)后双击它,然后在右边显示ARM汇编的窗口中就可以用IDA的F5反汇编功把ARM汇编转成C代码,结果如下:

       根据so库中有关java导出函数的参数的约定,第一个参数的类型必然是结构体指针JNIEnv*,第二个参数的类型一定是jobject。而导出函数具有3个参数,那么第三个必然是Java代码中本地函数唯一的参数String。不过JNI中没有String类的定义,而是jstring。这也是JNI的规则。

       使用IDA对相关类型重新命名后,可读性就好了许多:


       3到8行是相关定义,10和11两个赋值在这里对结果没有影响;12行到21行是两个对全局变量的判断语句,不影响后面的功能;22行是打印函数,仍然没有影响到后面检验验证码的过程。真正的代码从23行才开始,前面就暂且当是花指令处理了。

        看来事情并没有那么简单。

       所以现在的关键就是把偏移off_628C处的字符串从UTF格式转回它原来的格式;或者也可以动态调试让app自己说出来。

       动态调试就和模拟器无关了。由于市面上的模拟器多是用x86来模拟arm,总会有这样那样的问题,用真机调试是最为稳妥的。

       此次用来调试的安卓机器是Android6.0的Nexus5,是已经root过的。将手机连接到笔记本上,打开手机的调试选项,Nexus5就能成功连接上了。

       然后就是安装apk,需要用adb工具提供的选项来安装,如果成功的话如下图所示:

        由于apk启动后的内存并不在本机的内存中,而是在手机上,所以不能想exe一样直接用OllyDbg调试exe一样调试,需要借助几个工具:32位的IDA以及android_server(在IDA安装目录下的dbgsrv目录)。

       在本机上打开IDA,android_server则需要推送到真机上运行:


        仅是这样IDA还无法连接到它,android_server只是监听在手机的23946端口上而已,还不了解是那种协议,只能看看了。

        android_server拖进IDA,左边函数列表窗口选中main(可执行程序默认入口)并跳转过去,为了节省时间点击函数名用F5功能把代码解析C代码。可以发现在248行出现了一个可疑的j_accept函数:


        

        果然是accept函数,毫无疑问是tcp协议的服务器。为了让IDA能调试,必须要用adb把本机的23946端口转发到手机的23946端口上:


        若要测试端口是否被成功监听了,可以使用命令查看:


        下一步,让app加载到内存中,以被调试的方式启动。Win32下的调试是让调试器以调试的方式打开,Android下也一样,不过使用的是adb工具:


        此时被调试的手机就会黑屏,然后弹出一个标题为“Waitting For Debugger”。接下来只需要让调试器附加到这个app上去。启动IDA,然后在菜单栏找到Debugger,打开选中Attach项,再点击它的子菜单中的Remote ARMLinux\Android Debugger,就会弹出一个对话框:

         对话框的设置按上图的设定即可,点击OK,就有新的对话框用来选择被调试的进程:


        按照app的包名不难找到目标进程。双击它,IDA会卡住几秒,然后换成了类似OD的调试界面:

        现在是断点怎么停在securityCheck函数的问题。这个函数由库libcrackme.so导出,用快捷键CTRL+S查看,libcrackme.so其实还没有加载进来。

       其实不难理解,手机还在等待调试器,而被调试app的内存由调试器加载。

       这里就要用到jdb工具了:



[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

收藏
免费 3
支持
分享
最新回复 (7)
雪    币: 212
活跃值: (405)
能力值: ( LV3,RANK:38 )
在线值:
发帖
回帖
粉丝
2
一个CrackMe 检测模拟器,没那么复杂吧……会不会是其他原因导致的的啊。期待你的进一步探索
2019-8-13 09:34
0
雪    币: 144
活跃值: (38)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
很详细,适合初学者分析
2019-8-13 13:56
0
雪    币: 263
活跃值: (444)
能力值: ( LV4,RANK:40 )
在线值:
发帖
回帖
粉丝
4
function hookcall() {
    send("Running Script");
    var securityCheck = undefined;
    //枚举导出表函数
    exports = Module.enumerateExportsSync("libcrackme.so");
    for(i=0; i<exports.length; i++){
        if(exports[i].name == "Java_com_yaotong_crackme_MainActivity_securityCheck"){
            //获取导出表函数地址
            securityCheck = exports[i].address;
            send("securityCheck is at " + securityCheck);
            break;
        }
    }

    Interceptor.attach(securityCheck,{
        onEnter:
            function(args){
                send("key is: " + Memory.readUtf8String(Memory.readPointer(securityCheck.sub(0x11a8).add(0x628c))));
            }
        });
    send("Hooks installed.");
}
最后于 2019-8-23 12:51 被fzyspark编辑 ,原因:
2019-8-23 12:49
1
雪    币: 396
活跃值: (54)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
5
fzyspark function&nbsp;hookcall()&nbsp;{&nbsp;&nbsp;&nbsp;&nbsp;send("Running&am ...
原来用Hook还简单方便很多
2019-8-26 00:56
0
雪    币: 396
活跃值: (54)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
6
zylyy 很详细,适合初学者分析
谢谢
2019-8-26 00:56
0
雪    币: 396
活跃值: (54)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
7
capser 一个CrackMe 检测模拟器,没那么复杂吧……会不会是其他原因导致的的啊。期待你的进一步探索
你说的对,patch掉检测模拟器的代码之后,样本apk即使是安装在模拟器上也可以用一样的验证码拿到flag了。
2019-8-26 00:59
0
雪    币: 365
活跃值: (559)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
8
 
最后于 2020-4-1 22:06 被wx_A.R编辑 ,原因:
2020-3-29 22:06
0
游客
登录 | 注册 方可回帖
返回
//