【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 ...
随机推荐
- [转帖]grafana 连接 influxdb 1.x 和 2.x
文章目录 一.安装 influxdb Ⅰ.docker 安装 二.常用操作 Ⅰ.influxdb 1.x版本添加用户认证 Ⅱ.influxdb 2.x 使用命令行 Ⅲ.CLI 配置token Ⅴ.CL ...
- 周末拾遗 xsos 的学习与使用
周末拾遗 xsos 的学习与使用 摘要 周末陪儿子上跆拳道课. 自己一个人傻乎乎的开着笔记本想着学习点东西. 上午看到了一个sosreport的工具. 本来想学习一下. 发现xsos 应该是更好的一个 ...
- [转帖]Elasticsearch-索引性能调优
1:设置合理的索引分片数和副本数 索引分片数建议设置为集群节点的整数倍,初始数据导入时副本数设置为 0,生产环境副本数建议设置为 1(设置 1 个副本,集群任意 1 个节点宕机数据不会丢失:设置更多副 ...
- Nginx 系列 | (转)Nginx 上传文件:client_max_body_size 、client_body_buffer_size
原文:http://php-note.com/article/detail/488 client_max_body_size client_max_body_size 默认 1M,表示 客户端请求服务 ...
- WinSCP和xftp 从Windows 上传到linux服务器时出现中文乱码的解决方案
1. 日常工作中有需求从Windows的办公机器将文件上传到linux服务器上面进行使用 中文经常出现乱码, 需要处理一下. 这里面主要用到了两个工具 WinSCP还有xftp 两个的原理都是一样的 ...
- AppCan 打包无限次下载解决方案
1.下载AppCan 官网上打包好的文件apk文件 2.将apk文件放在指定的服务器文件内,谇文件发布到IIS,一般都会用已发布发的网站上面随便一个目录就可以了. 3.MIME类型中填写apk的MIM ...
- ABP无法使用异步操作,但要调用异步方法
使用 AsyncHelper.RunSync(() => _studentRepository.FirstOrDefaultAsync(x => x.Code == studentCode ...
- 剪粘板增强小工具(可多次Ctrl+V)
前言 windows的剪贴板中存储是的最新一次的复制结果,比如先复制A,再复制B,C,在按下粘贴键时粘贴的是最后一次的结果C,在工作时有时候会遇到需要多次复制粘贴的情景,我就在思考有没有一款工具可以保 ...
- 人工智能的新篇章:深入了解大型语言模型(LLM)的应用与前景
人工智能的新篇章:深入了解大型语言模型(LLM)的应用与前景 LLM(Large Language Model)技术是一种基于深度学习的自然语言处理技术,旨在训练能够处理和生成自然语言文本的大型模型. ...
- 从嘉手札<2024-1-17>
昨天我以为 人生是一场体验 是一辆不会回头的列车 我们遇到了风景 感悟了风景 放下了风景 构成了自己 今天我以为 静水流深.光而不耀 可多思必多疑 思维是一种极为复杂的东西 我曾经觉得知行合一是对自我 ...