修改Artmethod源码来trace被dexvmp保护的apk
2021-04-29 18:59:00 Author: mp.weixin.qq.com(查看原文) 阅读量:149 收藏

本文为看雪论坛优秀文章
看雪论坛作者ID:laifuling

前 言

样例来源于3W班10月份第1题,考察java核心代码被保护起来,如何通过修改aosp源码,快速逆向分析方法,破解flag。

思 路

apk核心的Java层代码被转换为Native,jadx反编译工具,无法正常的静态分析。我们可以跟老师学习的技能,从aosp源码修改入手,结合frida,破解apk

解 题

一、静态分析apk

核心onCreate方法,被vmp保护了,变为native方法。这里无需对vmp函数还原,可以修改aosp对函数调用进行探测,从而达到分析目的。

二、VMP LOG分析

修改aosp源码,监控InvokeWithArgArray。刷入修改后的rom,手机运行app,结合frida hook strstr函数,获取具体代码call日志。
重要信息如下:
======summerycalled: java.lang.String com.kanxue.test.MainActivity.stringFromJNI(java.lang.String)called: byte[] java.lang.String.getBytes(java.lang.String)called: void javax.crypto.spec.SecretKeySpec.<init>(byte[], java.lang.String)called: javax.crypto.Cipher javax.crypto.Cipher.getInstance(java.lang.String)called: void javax.crypto.Cipher.init(int, java.security.Key)called: byte[] javax.crypto.Cipher.doFinal(byte[])called: byte[] android.util.Base64.encode(byte[], int)called: java.lang.String java.lang.StringFactory.newStringFromBytes(byte[])called: java.lang.String java.lang.String.replace(java.lang.CharSequence, java.lang.CharSequence)called: boolean java.lang.String.equals(java.lang.Object)
从而得到具体的流程,将其分为2个阶段:
1> 输入input -->srtingFromJNI(libnative-lib.so)2> Cipher加密分析

三、Frida hook分析具体函数

根据log日志,选择如下函数,进行frida hook监测:
1> java.lang.String com.kanxue.test.MainActivity.stringFromJNI(java.lang.String)2> javax.crypto.Cipher.getInstance(java.lang.String)3> void javax.crypto.Cipher.init(int, java.security.Key)4> byte[] javax.crypto.Cipher.doFinal(byte[])5> byte[] android.util.Base64.encode(byte[], int)
app输入input:1111
frida监测到核心日志
MainActivity.stringFromJNI::  1111  rst: ptx4WA== Cipher.getInstance :: AES/ECB/PKCS5Padding Cipher.init :: 1Cipher.init :: [48,49,50,51,52,53,54,55,56,57,97,98,99,100,101,102] Cipher.doFinal input:: ptx4WA== Base64.encode:: int--> 0Base64.encode rstStr:: bauiEdMM9zdcklxoLHXU9g==
这里应该就是对输入的flag进行处理,总结流程:
<1>input --> stringFromJNI (1111 --> ptx4WA==)
<2> AES_ECB_PKCS5Padding (key: 0123456789abcdef) --> Base64
那么梳理一下,就是输入flag进行上述处理,得出的结果,与真实的flag进行比较。
这里需要找到真实的flag,可以rom log后面,有调用:
called: boolean java.lang.String.equals(java.lang.Object)
可以用frida hook该函数,获取真实的flag:
String.equals:: arg1: +OcSHGzedhKYu34wz2DqbONkdYp9OGzQ+KkX552G6S0=
可以就按照上述过程,反过来逆向出真实的flag。
正确的密码:+OcSHGzedhKYu34wz2DqbONkdYp9OGzQ+KkX552G6S0=加密流程:stringFromJni -->AES/ECB/PKCS5Padding(已知key) --> base64算法故而解除密码:base64算法 --> AES/ECB/PKCS5Padding(已知key) --> stringFromJni

四、AES/ECB/PKCS5Padding算法

<1> 将aes_ecb_pks5padding的key,转换为base64字符串或者hex:
[48,49,50,51,52,53,54,55,56,57,97,98,99,100,101,102]tohex: 30313233343536373839616263646566toBase64: MDEyMzQ1Njc4OWFiY2RlZg==toUTF8: 0123456789abcdef
<2> base64正确flag进行aes_ecb算法加密:
Input(base64):: +OcSHGzedhKYu34wz2DqbONkdYp9OGzQ+KkX552G6S0=
得到结果:8YEoDpO3wRFihWIGSzZ0/Q==

五、stringFromJNI分析

需要分析出stringFromJNI对input做了哪些处理,获取完整的流程,后面就可以根据流程反推出正确的flag。

用ida64打开zlibnative-lib.so,没有任何混淆,代码可读性好。
__int64 __fastcall Java_com_kanxue_test_MainActivity_stringFromJNI(__int64 a1, __int64 a2, __int64 a3){  __int64 v3; // ST48_8  __int64 v4; // x0  __int64 v5; // ST28_8  __int64 v6; // x0  __int64 v7; // ST20_8  __int64 v8; // ST08_8  __int64 v9; // ST18_8   v3 = a1;  v4 = sub_15EC(a1, a3, 0LL);  v5 = v4;  v6 = strlen(v4);  v7 = malloc(v6);  strcpy(v7, v5);  sub_1440(&unk_3008, v7); //关键函数  v8 = strlen(v5);  v9 = sub_8AC(v7, v8);  //标准的base64算法  sub_1440(&unk_3008, v7);  return sub_163C(v3, v9);}
这里可以用frida hook sub_1440和sub_8AC,进一步验证:
输入:1111
frida hook关键日志:
1> sub_1440(&unk_3008, v7); //关键函数核心日志:sub_1440 onEnter==========sub_1440 arg0:: 0 1 2 3 4 5 6 7 8 9 A B C D E F 0123456789ABCDEF7edacf6008 72 63 34 74 65 73 74 00 00 00 00 00 00 00 00 00 rc4test.........sub_1440 arg1:: 1111sub_1440 onLeave==========sub_1440 ret:: 0x7feced9600sub_1440 this.arg1:: 0 1 2 3 4 5 6 7 8 9 A B C D E F 0123456789ABCDEF7ee6fff600 a6 dc 78 582> sub_8AC(v7, v8);核心日志:sub_8AC arg0:: 0 1 2 3 4 5 6 7 8 9 A B C D E F 0123456789ABCDEF7ee6fff450 a6 dc 78 58sub_8AC arg1:: 0x4sub_8AC onLeave==========sub_8AC ret:: ptx4WA==
验证是否是标准的base64算法:
FromHex:a6dc7858
ToBase64:ptx4WA==
 
stringFromJNI核心算法:sub_1440 -> sub_12C4

发现sub_12C4应该是一个RC4算法,且key为:rc4test

在线cyberchef网站验证:
测试样例:1111 ---> a6dc7858
stringFromJNI算法:
rc4(key:rc4test) ---> base64
 
那么得到真实的flag:
获取的真实的FLAG:
flag{kanxue6666}

本文附件可点击左下方阅读原文自行下载!

看雪ID:laifuling

https://bbs.pediy.com/user-home-814746.htm

  *本文由看雪论坛 laifuling 原创,转载请注明来自看雪社区。

《安卓高级研修班》2021年6月班开始招生!

# 往期推荐

公众号ID:ikanxue
官方微博:看雪安全
商务合作:[email protected]

球分享

球点赞

球在看

点击“阅读原文”,了解更多!


文章来源: http://mp.weixin.qq.com/s?__biz=MjM5NTc2MDYxMw==&mid=2458384125&idx=1&sn=40440d73c792e7a3c8238e9f2e2035fa&chksm=b180c67786f74f61facf555743858e6abd8d93daadde8b04f2a42da8cdb7e21f405789d0f91c#rd
如有侵权请联系:admin#unsafe.sh