请注意,本文编写于 1495 天前,最后修改于 1481 天前,其中某些信息可能已经过时。
前言
本文仅供学习探讨之用,如果侵犯您的权益请联系我删除。
上文
距离上一篇文章已经过了半年了,最近也是刚好在学逆向相关的内容,就拿以前的工程来练手。
静态分析
还是接着上文,寻找hkey计算方式
可以看到,生成hkey
的过程中调用了Native
函数encode
,这个函数在libnative-lib.so
里
解压出so文件,拖进IDA,可以看到伪代码,可以看到一共有5个参数,但是在Java代码中是3个参数,前2个参数是不需要的。
尝试直接Hook,但是只能得到看不懂的结果,应该都是字符串地址。
我们换个思路,从return
开始分析
int __fastcall encode(int a1, int a2, int a3, int a4, int a5)
{
const char *v5; // r10
int v6; // r4
int v7; // r6
int v8; // r8
const char *v9; // r11
int v10; // r0
bool v11; // zf
size_t v12; // r5
char *v13; // r5
char *v14; // r0
size_t v15; // r0
char *v16; // r0
int v17; // r5
int result; // r0
int v19; // [sp+0h] [bp-30h]
int *v20; // [sp+4h] [bp-2Ch]
int v21; // [sp+8h] [bp-28h]
int v22; // [sp+Ch] [bp-24h]
v19 = a4;
v6 = a1; // v6 是第一个参数
v7 = a4;
if ( j_check_signature(a1) == 1 ) // 看名字应该是验证签名的方法
{
v8 = 0;
v9 = (const char *)(*(int (__fastcall **)(int, int, _DWORD))(*(_DWORD *)v6 + 676))(v6, v7, 0);
v10 = (*(int (__fastcall **)(int, int, _DWORD))(*(_DWORD *)v6 + 676))(v6, a5, 0);
v11 = v9 == 0;
if ( v9 )
{
v5 = (const char *)v10;
v11 = v10 == 0;
}
if ( !v11 )
{
v21 = a5;
v12 = strlen(v9);
v20 = &v19;
v13 = (char *)&v19 - ((strlen(v5) + v12 + 21) & 0xFFFFFFF8);
v14 = strcpy(v13, v9);
v15 = strlen(v14);
_aeabi_memcpy(&v13[v15], "/bfhdkud_time=", 15);
v16 = strcat(v13, v5);
v17 = j_MDString(v16); // v16 被赋值
(*(void (__fastcall **)(int, int, const char *))(*(_DWORD *)v6 + 680))(v6, v7, v9);
(*(void (__fastcall **)(int, int, const char *))(*(_DWORD *)v6 + 680))(v6, v21, v5);
v8 = j_charToJstring(v6, v17); // v8 被赋值,值与v6,v17有关
}
if ( _stack_chk_guard == v22 )
return v8; // 返回值是 v8
} //正常逻辑应该走不到这里
result = _stack_chk_guard - v22;
if ( _stack_chk_guard == v22 )
result = j_j_charToJstring(v6, UNSIGNATURE[0]);
return result;
}
不难看出,返回值跟j_charToJstring
和j_MDString
有关,j_
大概是一个修饰符,真实函数应该是charToJstring
和MDString
找到目标,接下来上Hook。
动态分析
接下来使用 Frida 进行分析,Frida 安装与使用可以参考:
Python 加载器
保存为run.py
import sys
import frida
process_name = 'com.max.xiaoheihe'
# 发送信息回调函数
def on_message(message, data):
if message['type'] == 'send':
print(f"[*] {message['payload']}")
else:
print(message)
if __name__ == '__main__':
try:
device = frida.get_usb_device()
except:
device = frida.get_remote_device()
if not device:
print("* 连接到Frida Server失败")
else:
process = device.attach(process_name)
# 加载JS脚本
js = open('hook.js', encoding='utf-8').read()
script = process.create_script(js)
script.on('message', on_message)
script.load()
# 读取返回输入
input()
script.unload()
Hook代码
保存为hook.js
console.log("脚本载入成功");
Java.perform(function () {
var charToJstringAddr = Module.findExportByName("libnative-lib.so", "charToJstring");
console.log(charToJstringAddr);
if (charToJstringAddr != null) {
Interceptor.attach(charToJstringAddr, {
onEnter: function (args) {
var arg0 = args[0];
var arg1 = args[1];
console.log('charToJstring - Enter');
console.log(arg0, Memory.readCString(arg0));
console.log(arg1, Memory.readCString(arg1));
},
onLeave: function (retval) {
//retval函数返回值
console.log('charToJstring - Leave');
console.log(retval.toString());
console.log('======');
}
});
}
var MDStringAddr = Module.findExportByName("libnative-lib.so", "MDString");
console.log(MDStringAddr);
if (MDStringAddr != null) {
Interceptor.attach(MDStringAddr, {
onEnter: function (args) {
var arg0 = args[0];
var arg1 = args[1];
console.log('MDString - Enter');
console.log(arg0, Memory.readCString(arg0));
console.log(arg1, Memory.readCString(arg1));
},
onLeave: function (retval) {
console.log('MDString - Leave');
console.log(retval.toString());
console.log('======');
}
});
}
})
不难看出,MDString
的输入是特定的拼接字符串,MDString
的输出是charToJstring
的输入,而且是一个32位哈希值,推测是MD5
试了一下,果真是MD5
所以encode
的逻辑是把url
的路径部分,拼上/bfhdkud_time=
,再加上秒级时间戳,然后返回整个字符串的MD5哈希
Python 实现
稍微整理了一下Java代码:
String path = get_url_path(str);
String time = (System.currentTimeMillis() / 1000) + "";
if (path.endsWith("/")) {
path = path.substring(0, i.length() - 1); //去除path结尾的"/"
}
String hkey = get_MD5(NDKTools.encode(HeyBoxApplication.f(), path, time).replaceAll("a", "app").replaceAll("0", "app")).substring(0, 10);
接下来换成Python实现
import time
import hashlib
from urllib.parse import urlparse
def gen_hkey(url: str,t:int) -> str:
def url_to_path(url: str) -> str:
path = urlparse(url).path
if path and path[-1] == '/':
path = path[:-1]
return(path)
def get_md5(data: str):
md5 = hashlib.md5()
md5.update(data.encode('utf-8'))
result = md5.hexdigest()
return(result)
h = f'{url_to_path(url)}/bfhdkud_time={t}'
h = get_md5(h)
h = h.replace('a', 'app')
h = h.replace('0', 'app')
h = get_md5(h)
h = h[:10]
return(h)
t=time.time()
h=gen_hkey('https://api.xiaoheihe.cn/bbs/app/feeds/news',t)
print('time: ',t)
print('hkey: ',h)
后续
本文链接:https://blog.chrxw.com/archives/2020/08/05/1347.html
转载请保留本文链接,谢谢
1 条评论
niu