-
-
[原创]CTF2018第五题分析(qwertyaa)
-
发表于:
2018-6-25 00:50
4122
-
[原创]CTF2018第五题分析(qwertyaa)
首先将apk用jadx打开,简单查看可知程序中主要加载了libexecute_table.so,并且调用其中注册的lkdakjudajndn来判断密钥是否成功。
另外Java层有一个判断函数,但由这个函数返回结果设置的Fail
提示似乎会被lkdakjudajndn的返回结果覆盖,并无实际用途。
顺带一提:Java层中几乎字符串都是用Base64加密的;解密函数调用时“偷偷”加载了libexecute_table.so。
利用 https://bbs.pediy.com/thread-216701.htm 上的程序,我伪造了一个JavaVM
来加载so,并趁机获得so加载基址和JNI_OnLoad函数地址(ida中直接显示的是错误的,应该是.init和.init_array中对JNI_OnLoad地址进行了修改所致)
我们找到正确JNI_OnLoad地址后在IDA中将其第一个参数的类型定义为JavaVM*
,找到其中GetEnv
的调用,将其第二个参数的类型定义为JNIEnv*
,顺路找到了调用RegisterNatives
的地址。(可能需要右键“Force call type”来显示全所有参数)
然后将上述程序调试运行,运行到RegisterNatives
处为止(注意由于这里FindClass
返回值为空,需要手工过掉一个跳转),成功得到lkdakjudajndn函数的注册地址为libexecute_table.so的基址+0xac98。
libexecute_table.so的基址+0xac98处的代码并不能直接F5,猜测可能是运行时需要动态修改所致。
直接将IDA挂载进正在运行的app,成功了。这说明该app并没用采用fork自身后ptrace自身这样变态的反调试。不过接下来一旦运行,似乎很快就会崩溃,所以我们放着程序不要运行。
按Ctrl+S在内存中找到位于libexecute_table.so的基址+0xac98的lkdakjudajndn函数,这里可以成功F5。
里面一些乱七八糟的函数其实是标准库中的字符串函数,利用标准库函数内的英文提示、部分函数的导出符号和对函数行为的简单分析(同时比对我自己用g++生成的程序的IDA反汇编结果),我们可以命名大部分函数,如下:
这里面有少量的花指令。
以
结尾的指令用于产生一个常量1。
而以
结尾的指令用于产生一个常量0。
还有一些产生了一个字符串,然后if(串非空)将串置空;
这样的花指令。
将根据输入的字符串从前往后看和根据返回值从后往前看两种方式相结合,阅读几遍程序,可发现程序做了如下操作:
1.第一位放到最后
--每位按表置换
2.高低位交换
3.四位一组异或
4.奇偶位交换
--每位按表置换
5.第一位放到最后
6.高四位内容(x>>4)替换为"A3Cw6Gb0OZWPU52s"[x>>4]产生A;低四位同理产生B(反序)
7.判断"3ww3 U5 3w OAWG 333 ww PZ56GGw0PO02OUW"(去掉空格)==A+B
这里比较容易遗漏的是两处“--每位按表置换”,代码类似于:
乍一看令人懵逼,其实: -0x6F38103E == 0x90C7EFC2 (DWORD下),而后者是so加载基址附近的一处内容。
这样,我们就可以把在0x90C7EFC2处的置换表直接从IDA中复制出来。
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)
最后于 2018-6-25 01:07
被qwertyaa编辑
,原因: 校对