【Android逆向】静态分析+frida破解test2.apk
有了上一篇的基础
https://www.cnblogs.com/gradyblog/p/17152108.html
现在尝试静态分析的方式来处理
为什么还要多此一举,因为题眼告诉了我们是五位数字,所以可以爆破,不告诉这个题眼的话,就得分析
1. IDA 打开libroysue.so,查看JNI_OnLoad, 从method_table里找到Sign对应的函数
.data:00080000 ; ===========================================================================
.data:00080000
.data:00080000 ; Segment type: Pure data
.data:00080000 AREA .data, DATA
.data:00080000 ; ORG 0x80000
.data:00080000 ; JNINativeMethod method_table[1]
.data:00080000 1C 55 07 00 21 55 07 00 25 71+_ZL12method_table JNINativeMethod <aSign, aLjavaLangStrin_1, _Z4fuckP7_JNIEnvP7_jclassP8_jstring+1>
.data:00080000 03 00 ; DATA XREF: JNI_OnLoad+EA↑o
.data:00080000 ; JNI_OnLoad+EC↑o
.data:00080000 ; .text:off_376D0↑o
.data:00080000 ; _Unwind_VRS_Interpret+1B2↑o
.data:00080000 ; _Unwind_VRS_Interpret:def_68226↑o
.data:00080000 ; .text:off_68354↑o
.data:00080000 ; fuck(_JNIEnv *,_jclass *,_jstring *) ...
从这里可以看出,底层是这个 fuck函数与之对应,看一下它,整理后
jstring __fastcall fuck(JNIEnv *env, jclass jcls, jstring str_)
{
jstring v4; // [sp+14h] [bp-BCh]
_jmethodID *methodID; // [sp+18h] [bp-B8h]
jstring v6; // [sp+30h] [bp-A0h]
int i; // [sp+38h] [bp-98h]
jbyte *ByteArrayElements; // [sp+3Ch] [bp-94h]
_jbyteArray *array; // [sp+40h] [bp-90h]
jobject j_str_bytes; // [sp+44h] [bp-8Ch]
_jmethodID *v11; // [sp+48h] [bp-88h]
_jclass *v12; // [sp+4Ch] [bp-84h]
_jmethodID *digest_method_id; // [sp+50h] [bp-80h]
_jobject *md_instance; // [sp+54h] [bp-7Ch]
_jclass *Class; // [sp+5Ch] [bp-74h]
_jobject *j_str; // [sp+60h] [bp-70h]
_jfieldID *fieldID; // [sp+68h] [bp-68h]
_jclass *clazz; // [sp+6Ch] [bp-64h]
unsigned __int8 *src; // [sp+74h] [bp-5Ch]
char *v23; // [sp+9Ch] [bp-34h]
_WORD v24[4]; // [sp+A3h] [bp-2Dh] BYREF
if ( !str_ )
return 0;
src = (unsigned __int8 *)_JNIEnv::GetStringUTFChars(env, str_, 0);
clazz = _JNIEnv::FindClass(env, "android/os/Build");
fieldID = _JNIEnv::GetStaticFieldID(env, clazz, "FINGERPRINT", "Ljava/lang/String;");
_JNIEnv::GetStaticObjectField(env, clazz, fieldID);
strcat((char *)src, "REAL");
j_str = (_jobject *)j_o0OoOOOO(env, src);
_android_log_print(4, "roysuejni", "before entering aes => %s", (const char *)src);
Class = _JNIEnv::FindClass(env, "java/security/MessageDigest");
methodID = _JNIEnv::GetStaticMethodID(env, Class, "getInstance", "(Ljava/lang/String;)Ljava/security/MessageDigest;");
v4 = j_o0OoOOOO(env, "MD5");
md_instance = _JNIEnv::CallStaticObjectMethod(env, Class, methodID, v4);
digest_method_id = _JNIEnv::GetMethodID(env, Class, "digest", "([B)[B");
v12 = _JNIEnv::FindClass(env, "java/lang/String");
v11 = _JNIEnv::GetMethodID(env, v12, "getBytes", "()[B");
j_str_bytes = _JNIEnv::CallObjectMethod(env, j_str, v11);
array = (_jbyteArray *)_JNIEnv::CallObjectMethod(env, md_instance, digest_method_id, j_str_bytes);
ByteArrayElements = _JNIEnv::GetByteArrayElements(env, array, 0);
for ( i = 0; i <= 15; ++i )
sprintf((char *)&v24[i], "%02x", (unsigned __int8)ByteArrayElements[i]);
v23 = (char *)j_ll11l1l1ll(src);
strcat(v23, (const char *)v24);
v6 = j_o0OoOOOO(env, (const unsigned __int8 *)v23);
_android_log_print(4, "roysuejni", "result is => %s ", v23);
_JNIEnv::ReleaseStringUTFChars(env, str_, src);
free(v23);
return v6;
}
静态分析可知,大概逻辑如下
1. 给输入拼接个 REAL,比如输入 1111 变成 1111REAL
2. 然后执行给MD5,得到MD5的值(32位)
3. 将拼接后的输入由j_ll11l1l1ll处理一下,得到返回值
4. 将返回值和md5进行拼接,返回
2. 点进去看看j_ll11l1l1ll在干什么
unsigned __int8 *__fastcall ll11l1l1ll(const unsigned __int8 *input)
{
unsigned __int8 *v2; // [sp+8h] [bp-30h]
uint8_t *output; // [sp+Ch] [bp-2Ch]
size_t byte_count; // [sp+10h] [bp-28h]
uint8_t *iv; // [sp+18h] [bp-20h]
uint8_t *key; // [sp+1Ch] [bp-1Ch]
char *v8; // [sp+2Ch] [bp-Ch]
key = (uint8_t *)ll11lll1l1();
iv = (uint8_t *)ll11l1l1l1();
v8 = (char *)ll11l1l11l(input);
byte_count = strlen(v8);
output = (uint8_t *)malloc(byte_count);
j_qpppqp(output, (uint8_t *)v8, byte_count, key, iv);
v2 = j_bbddbbdbb(output, byte_count);
free(v8);
free(output);
free(key);
free(iv);
return v2;
}
看到 key iv ,八成就是AES加密了,再看看是哪种模式的加密,点进j_qpppqp看看
void __fastcall qpppqp(uint8_t *output, uint8_t *input, uint32_t length, const uint8_t *key, const uint8_t *iv)
{
__int64 v5; // d17
unsigned __int8 v6; // [sp+Bh] [bp-2Dh]
uint32_t i; // [sp+Ch] [bp-2Ch]
v6 = length & 0xF;
if ( key )
{
Key = key;
KeyExpansion();
}
if ( iv )
Iv = (uint8_t *)iv;
for ( i = 0; i < length; i += 16 )
{
v5 = *((_QWORD *)input + 1);
*(_QWORD *)output = *(_QWORD *)input;
*((_QWORD *)output + 1) = v5;
XorWithIv(output);
state = (state_t *)output;
Cipher();
Iv = output; // 这里加密后的数据变下一次IV,是典型的CBC模式
input += 16;
output += 16;
}
if ( v6 )
{
qmemcpy(output, input, v6);
memset(&output[v6], 0, 16 - v6);
XorWithIv(output);
state = (state_t *)output;
Cipher();
}
}
由代码特征可知: 这里加密后的数据变下一次IV,是典型的CBC模式
那么只要拿到key 和iv 试一下就可确认算法是不是预测正确
frida代码
function print_dump(arg, size) {
console.log(hexdump(arg, {
offset: 0,
length: size,
header: true,
ansi: true
}))
}
function main() {
Java.perform(function () {
var lib_hanlder = Process.findModuleByName("libroysue.so");
console.log("lib_handler: " + lib_hanlder)
if (lib_hanlder) {
var addr_ll11l1l1ll = lib_hanlder.base.add(0x0003C9E4 + 0x1)
Interceptor.attach(addr_ll11l1l1ll,{
onEnter: function(args) {
console.log(" === hook before")
var arg = args[0]
print_dump(arg, 128)
},
onLeave:function(retVal) {
console.log(" === hook after: " + retVal)
print_dump(retVal, 128)
}
})
var addr_qpppqp = lib_hanlder.base.add(0x0003B868 + 0x1)
var output
Interceptor.attach(addr_qpppqp,{
onEnter: function(args) {
output = args[0]
console.log(" === hook qpppqp before: " + output)
console.log(" === hook qpppqp before KEY: ")
var arg = args[3]
print_dump(arg, 128)
console.log(" === hook qpppqp before IV: ")
var arg = args[4]
print_dump(arg, 128)
},
onLeave:function(retVal) {
console.log(" === hook qpppqp after==>: " + output)
print_dump(output, 128)
}
})
}
})
}
setTimeout(main, 3000)
输出日志
0 1 2 3 4 5 6 7 8 9 A B C D E F 0123456789ABCDEF
dbf3a038 31 31 31 31 52 45 41 4c 00 84 f1 db 10 33 f0 db 1111REAL.....3..
dbf3a048 00 f2 58 d9 00 00 00 00 58 a0 f3 db 00 00 00 00 ..X.....X.......
dbf3a058 bc 6e c1 c6 44 00 00 00 48 ac 20 c7 58 ab 20 c7 .n..D...H. .X. .
dbf3a068 00 00 00 00 00 00 96 42 00 ad 20 c7 00 00 00 00 .......B.. .....
dbf3a078 00 00 00 00 00 00 00 00 18 e2 11 d6 00 00 00 00 ................
dbf3a088 64 e2 11 d6 00 00 00 00 d0 f0 9b e4 00 00 00 00 d...............
dbf3a098 00 20 bb c6 00 00 00 00 80 27 f2 db 00 00 00 00 . .......'......
dbf3a0a8 00 00 00 00 00 00 00 00 00 29 f2 db 00 00 00 00 .........)......
=== hook qpppqp before: 0xcd33c9d0
=== hook qpppqp before KEY:
0 1 2 3 4 5 6 7 8 9 A B C D E F 0123456789ABCDEF
e42d0350 67 6f 6f 64 6c 2d 61 65 73 2d 6b 65 79 31 32 34 goodl-aes-key124
e42d0360 00 52 34 cd 88 52 34 cd 67 6f 6f 64 6c 2d 61 65 .R4..R4.goodl-ae
e42d0370 73 2d 69 76 31 32 33 35 00 d8 07 dc 88 d8 07 dc s-iv1235........
e42d0380 31 31 31 31 52 45 41 4c 08 08 08 08 08 08 08 08 1111REAL........
e42d0390 00 00 00 00 c7 c3 00 00 80 03 2d e4 9b 87 77 11 ..........-...w.
e42d03a0 00 00 00 00 bd 04 1b e7 1e 00 00 00 c8 c3 00 00 ................
e42d03b0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
e42d03c0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
=== hook qpppqp before IV:
0 1 2 3 4 5 6 7 8 9 A B C D E F 0123456789ABCDEF
e42d0368 67 6f 6f 64 6c 2d 61 65 73 2d 69 76 31 32 33 35 goodl-aes-iv1235
e42d0378 00 d8 07 dc 88 d8 07 dc 31 31 31 31 52 45 41 4c ........1111REAL
e42d0388 08 08 08 08 08 08 08 08 00 00 00 00 c7 c3 00 00 ................
e42d0398 80 03 2d e4 9b 87 77 11 00 00 00 00 bd 04 1b e7 ..-...w.........
e42d03a8 1e 00 00 00 c8 c3 00 00 00 00 00 00 00 00 00 00 ................
e42d03b8 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
e42d03c8 00 00 00 00 00 00 00 00 e8 04 2d e4 01 05 1b e7 ..........-.....
e42d03d8 00 10 24 e5 68 e7 60 da 80 28 e1 e5 b0 9f 4f d6 ..$.h.`..(....O.
=== hook qpppqp after==>: 0xcd33c9d0
0 1 2 3 4 5 6 7 8 9 A B C D E F 0123456789ABCDEF
cd33c9d0 72 cb e2 0c 9e 28 ec 25 e0 0f e3 bf 7a 37 c1 8e r....(.%....z7..
cd33c9e0 2c 60 f6 e4 00 00 00 00 13 00 00 00 00 00 00 00 ,`..............
cd33c9f0 44 0b e1 e5 00 00 00 00 40 51 9a e4 00 00 00 00 D.......@Q......
cd33ca00 2c 60 f6 e4 00 00 00 00 13 00 00 00 01 20 00 00 ,`........... ..
cd33ca10 a4 f4 38 c6 80 fc 97 c6 00 b8 2d c6 00 40 f0 db ..8.......-..@..
cd33ca20 a4 f4 2c c6 f0 fb 97 c6 50 ec 33 c6 00 40 f0 db ..,.....P.3..@..
cd33ca30 3e 00 00 00 44 00 00 00 4b 00 00 00 53 00 00 00 >...D...K...S...
cd33ca40 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
=== hook after: 0xda60e740
0 1 2 3 4 5 6 7 8 9 A B C D E F 0123456789ABCDEF
da60e740 37 32 63 62 65 32 30 63 39 65 32 38 65 63 32 35 72cbe20c9e28ec25
da60e750 65 30 30 66 65 33 62 66 37 61 33 37 63 31 38 65 e00fe3bf7a37c18e
da60e760 00 66 34 65 33 62 30 65 38 61 33 32 35 63 66 37 .f4e3b0e8a325cf7
da60e770 63 65 66 32 38 39 61 62 31 66 35 36 32 64 66 65 cef289ab1f562dfe
da60e780 00 20 00 00 03 00 00 00 00 00 00 00 00 00 00 00 . ..............
da60e790 00 00 80 3f 00 00 00 00 00 00 00 00 00 00 00 00 ...?............
da60e7a0 00 00 80 3f 00 00 00 00 00 00 00 00 00 00 00 00 ...?............
da60e7b0 00 00 80 3f 10 00 00 00 00 d0 86 e4 68 ad 04 00 ...?........h...
那么可以得出
key: goodl-aes-key124
iv: goodl-aes-iv1235
加密后的数据为: 72cbe20c9e28ec25e00fe3bf7a37c18e4f4e3b0e8a325cf7cef289ab1f562dfe
去掉32位的md5,aes加密部分为72cbe20c9e28ec25e00fe3bf7a37c18e
4. 打开在线AES解密,得出结果确实是1111REAL
5. 取出apk中的校验字符串4143cb60bf8083ac94c57418a9a7ff5a14a63feade6b46d9d0af3182ccbdf7af,去掉后面的32个字符得到4143cb60bf8083ac94c57418a9a7ff5a,解密得到45678REAL
6. 得到flag为45678,手机验证,通过
【Android逆向】静态分析+frida破解test2.apk的更多相关文章
- Android逆向之旅---破解"穿靴子的猫"游戏的收费功能
一.游戏收费分析 游戏收费非常正常的,可是玩游戏最恶心的就是你还没玩就要充值,非常恼火,事实上我不怎么玩游戏,主要是给小孩子们弄,比方如今好多小屁孩们喜欢玩水果忍者这个游戏.可是这个游戏在没有開始玩的 ...
- Android简单应用程序破解——runtime.apk
对于<Debugging Android Application>一文中最后附上的练习,我采用了另一种静态方法绕开原有的逻辑去破解.主要的过程如下: 利用apktool将练习的runtim ...
- Android逆向之旅---静态分析技术来破解Apk
一.前言 从这篇文章开始我们开始我们的破解之路,之前的几篇文章中我们是如何讲解怎么加固我们的Apk,防止被别人破解,那么现在我们要开始破解我们的Apk,针对于之前的加密方式采用相对应的破解技术,And ...
- Android逆向之旅---动态方式破解apk进阶篇(IDA调试so源码)
Android逆向之旅---动态方式破解apk进阶篇(IDA调试so源码) 来源 https://blog.csdn.net/jiangwei0910410003/article/details/51 ...
- Android逆向破解表单注册程序
Android逆向破解表单注册程序 Android开发 ADT: android studio(as) 程序界面如下,注册码为6位随机数字,注册成功时弹出通知注册成功,注册失败时弹出通知注册失败. 布 ...
- Android逆向破解表单登录程序
Android逆向破解表单登录程序 Android开发 ADT: android studio(as) 程序界面如下,登录成功时弹出通知登录成功,登录失败时弹出通知登录失败. 布局代码 <?xm ...
- Android逆向之静态分析
想必打过CTF的小伙伴多多少少都触过Android逆向,所以斗哥将给大家整一期关于Android逆向的静态分析与动态分析.本期先带来Android逆向的静态分析,包括逆向工具使用.文件说明.例题解析等 ...
- Android 逆向实战篇(加密数据包破解)
1. 实战背景由于工作需要,要爬取某款App的数据,App的具体名称此处不便透露,避免他们发现并修改加密逻辑我就得重新破解了. 爬取这款App时发现,抓包抓到的数据是加密过的,如图1所示(原数据较长, ...
- Android逆向分析(2) APK的打包与安装背后的故事
前言 上一次我们反编译了手Q,并遇到了Apktool反编译直接crash的问题,虽然笔者很想在这次解决这个问题,但在解决途中,发现该保护依赖于很多知识,所以本次先插入一下,正所谓知其然知其所以然,授之 ...
- Android逆向分析(2) APK的打包与安装
http://blog.zhaiyifan.cn/2016/02/13/android-reverse-2/ 2/18日增加对aidl和java编译的描述. 前言 上一次我们反编译了手Q,并遇到了Ap ...
随机推荐
- [转帖]Web技术(四):TLS 握手过程与性能优化(TLS 1.2与TLS 1.3对比)
https://blog.csdn.net/m0_37621078/article/details/106126033?ops_request_misc=%257B%2522request%255Fi ...
- [转帖]tidb-系统内核调优及对比
一.背景 验证系统调优对性能的影响,用sysbench做了一些简单的测试,具体调整方法可见官方文档 二.特殊说明 1.透明大页查看 # 查看透明大页是否开启,[]在always处表示开启,[]在nev ...
- [转帖]使用 TiUP cluster 在单机上安装TiDB
https://zhuanlan.zhihu.com/p/369414808 TiUP 是 TiDB 4.0 版本引入的集群运维工具,TiUP cluster 是 TiUP 提供的使用 Golan ...
- [转帖]Linux—编写shell脚本操作数据库执行sql
Linux-编写shell脚本操作数据库执行sql Hughman关注IP属地: 北京 0.0762020.03.20 09:02:13字数 295阅读 1,036 修改数据库数据 在升级应用时, ...
- [转帖]必看!PostgreSQL参数优化
https://zhuanlan.zhihu.com/p/333201734 前不久,一个朋友所在的公司,业务人员整天都喊慢. 朋友是搞开发的,不是很懂DB,他说他们应用的其实没什么问题,但是就是每天 ...
- [转帖]ldconfig命令
https://linux265.com/course/linux-command-ldconfig.html ldconfig命令的作用主要是在默认搜寻目录/lib和/usr/lib以及动态库配置文 ...
- [转帖]springboot中使用skywalking实现日志追踪
文章目录 SkyWalking分布式追踪系统 介绍 主要架构 环境 引入依赖 配置Log4j2 下载编译好的8.7.0版本包 使用探针实现日志追踪 启动脚本 启动Java服务 访问服务 使用UI 切换 ...
- [转帖]一个故事看懂CPU的SIMD技术
https://www.cnblogs.com/xuanyuan/p/16048303.html 好久不见,我叫阿Q,是CPU一号车间的员工.我所在的CPU有8个车间,也就是8个核心,咱们每个核心都可 ...
- 银河麒麟安装nmon以及rpc.rstatd的方法
背景说明 随着公司业务的发展,需要在ARM环境上面进行性能测试. 为了进行ARM环境的验证,需要一些组件进行资料收集. 比较好的方式是使用nmon或者是rstatd进行性能参数收集. 为了方便部署,想 ...
- node中的fs模块和http模块的学习
读取文件 fs 模块 第1个参数就是要读取的文件路径 第2个参数是一个回调函数(error,data)=>{} error 如果读取失败,error 就是错误对象 如果读取成功,error 就是 ...