【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 ...
随机推荐
- [转帖]Kafka 核心技术与实战学习笔记(八)kafka集群参数配置(下)
一.Topic级别参数 Topic的优先级: 如果同时设置Topic级别参数和全局Broker参数,那么Topic级别优先 消息保存方面: retention.ms:规定Topic消息保存时长.默认是 ...
- 【转帖】一文解析ethtool 命令的使用
命令简介 ethtool命令用于查询和控制网络设备驱动程序和硬件设置,尤其是有线以太网设备,devname网卡的名称.网卡就像是交换机的一个端口,正常使用我们只是配置网卡IP地址等信息,网卡的速率.双 ...
- [转帖]ARMv8架构概述、相关技术文档以及ARMv8处理器简介
ARMv8架构 文章目录 ARMv8架构 参考文档 ARMv8架构的概述 从32位到64位的变化The changes from 32 bits to 64 bits 1,Larger registe ...
- [转帖] shell管道咋堵住了
https://www.cnblogs.com/codelogs/p/16060378.html 背景# 起因是这样的,我们想开发一个小脚本,当cpu使用率过高时,使用jstack将java的线程栈保 ...
- 【JS 逆向百例】百度翻译接口参数逆向
逆向目标 目标:百度翻译接口参数 主页:https://fanyi.youdao.com/ 接口:https://fanyi.baidu.com/v2transapi 逆向参数: Form Data: ...
- 基于.Net Core3.1 MVC + EF Core的项目(一)框架的初步搭建
项目暂时分为六大块,结构如图所示 代码地址是 https://github.com/hudean/VacantCloud- 里面有许多没有完成,不过一些大致的内容都写的差不多了,权限认证依赖注入 ...
- 5.10 Windows驱动开发:摘除InlineHook内核钩子
在笔者上一篇文章<内核层InlineHook挂钩函数>中介绍了通过替换函数头部代码的方式实现Hook挂钩,对于ARK工具来说实现扫描与摘除InlineHook钩子也是最基本的功能,此类功能 ...
- 4.9 C++ Boost 命令行解析库
命令行解析库是一种用于简化处理命令行参数的工具,它可以帮助开发者更方便地解析命令行参数并提供适当的帮助信息.C++语言中,常用的命令行解析库有许多,通过本文的学习,读者可以了解不同的命令行解析库和它们 ...
- 守护进程(Python)
#__author__:Kelvin #date:2020/5/10 11:37 import time from multiprocessing import Process def son1(): ...
- 多进程实现socket通信(Python)
服务器端: #__author__:Kelvin #date:2020/5/9 11:35 import socket from multiprocessing import Process def ...