恰饭
简介
抓包
过程
hook下请求头的okhttp的 addHeader
Java.perform(function () {
var Builder = Java.use('okhttp3.Request$Builder');
Builder.addHeader.overload('java.lang.String', 'java.lang.String').implementation = function (key, value) {
if (key != null && key === 'zzReqSign') {
console.log(Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Throwable").$new()))
console.log('Header added: ' + key + ': ' + value);
}
var original = this.addHeader(key, value);
return original;
};
});
frida检测并且app没闪退
应该是开线程检测的,hook下dlopen以及pthread_create
functionhook_dlopen() {
Interceptor.attach(Module.findExportByName(null, "android_dlopen_ext"),
{
onEnter: function (args) {
var pathptr = args[0];
if (pathptr !== undefined && pathptr != null) {
var path = ptr(pathptr).readCString();
console.log("enter: " + path);
}
},
onLeave: function (retval) {
console.log("leave ");
}
}
);
}
hook_dlopen()
跟贝壳和某书的监测点相似,都是libmsaoaidsec.so开三个线程检测
hook下JNI_OnLoad发现在其执行之前,脚本如下
function hook_dlopen(soName = '') {
Interceptor.attach(Module.findExportByName(null, "android_dlopen_ext"),
{
onEnter: function (args) {
var pathptr = args[0];
if (pathptr !== undefined && pathptr != null) {
var path = ptr(pathptr).readCString();
if (path.indexOf(soName) >= 0) {
this.is_can_hook = true;
}
}
},
onLeave: function (retval) {
if (this.is_can_hook) {
hook_JNI_OnLoad(soName)
}
}
}
);
}
function hook_JNI_OnLoad(soName) {
let module = Process.findModuleByName(soName)
let jniOnloadAddr = module.findExportByName(soName, "JNI_OnLoad");
Interceptor.attach(jniOnloadAddr, {
onEnter(args) {
console.log("call JNI_OnLoad")
}
})
}
setImmediate(hook_dlopen, "libmsaoaidsec.so")
加载so->链接so-初始化(init_proc)-数组初始化(init_array)-jni_onLoad
监测点还在前面,根据hook到的偏移量找到位置:
几次交叉引用查找到了init_proc
在这里选择一个较早执行的外部函数hook
function hook_dlopen(soName = '') {
Interceptor.attach(Module.findExportByName(null, "android_dlopen_ext"),
{
onEnter: function (args) {
var pathptr = args[0];
if (pathptr !== undefined && pathptr != null) {
var path = ptr(pathptr).readCString();
if (path.indexOf(soName) >= 0) {
locate_init()
}
}
}
}
);
}
functionlocate_init() {
let secmodule = null
Interceptor.attach(Module.findExportByName(null, "__system_property_get"),
{
onEnter: function (args) {
secmodule = Process.findModuleByName("libmsaoaidsec.so")
var name = args[0];
if (name !== undefined && name != null) {
name = ptr(name).readCString();
if (name.indexOf("ro.build.version.sdk") >= 0) {
hook_pthread_create()
}
}
}
}
);
}
let i = 0;
functionhook_pthread_create() {
if (i >= 2) {
console.log("成功过检测")
return
}
let baseAddress = Process.findModuleByName("libmsaoaidsec.so").base;
console.log("libmsaoaidsec.so --- " + baseAddress);
Interceptor.replace(Module.findExportByName("libc.so", "pthread_create"), new NativeCallback(function (attr, start_routine, arg1, arg2) {
let func_addr = arg1.sub(baseAddress);
if (func_addr.equals(ptr(0x1c544)) || func_addr.equals(ptr(0x1b8d4) ) || func_addr.equals(ptr(0x26e5c) )) {
i++
console.log(func_addr, i)
return 0
}
let pthread_create = new NativeFunction(Module.findExportByName("libc.so", "pthread_create"), 'int', ['pointer', 'pointer', 'pointer', 'pointer']);
return pthread_create(attr, start_routine, arg1, arg2);
}, 'int', ['pointer', 'pointer', 'pointer', 'pointer']));
}
setImmediate(hook_dlopen, "libmsaoaidsec.so")
现在hook Builder.addHeader 就可以了
Header added: zzReqSign: e6ece0fc26af7c1c8f9561617b62090c java.lang.Throwable at okhttp3.Request$Builder.addHeader(Native Method) at com.wuba.zhuanzhuan.framework.network.interceptor.SignInterceptor.intercept(SignInterceptor.java:48) at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:10) at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:1) at com.wuba.zhuanzhuan.framework.network.interceptor.PPURefreshInterceptor.intercept(PPURefreshInterceptor.java:2) at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:10) at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:1)
到getSign native
静态
先改下环境指针
上Ai 先理下思路
第一部分:验证签名
if ( !a3 )
return 0LL;
v6 = (const char *)get_app_sign_sha1(a1, a4);
if ( !v6 )
return 0LL;
if ( strcmp(v6, app_sing_str) )
return 0LL;
第二部分:明文转字节数组
v9 = (*a1)->FindClass(a1, "java/lang/String");
v10 = (*a1)->NewStringUTF(a1, "utf-8");
v11 = (*a1)->GetMethodID(a1, v9, "getBytes", "(Ljava/lang/String;)[B");
v12 = (void *)_JNIEnv::CallObjectMethod(a1, mingwen, v11, v10);
第三部分:JNI掉java获取设备ID 然后转字节数组
第四部分:异或运算
理一下
v14: 明文字节数组 = mingwen
v18: 明文字节数组长度 = menwen_len
v23: 设备id字节数组 = device
v24: 设备id字节数组长度 = device_len
if ( (int)menwen_len >= 1 )
{
v27 = 0LL;
v28 = 0;
do
{
v29 = mingwen[(unsigned int)(v28 - v28 / (int)menwen_len * menwen_len)];
v30 = device[v28 + 1 - (v28 + 1) / device_len * device_len];
v25[v27++] = v30 ^ v29;
v28 += 2; // 步进2
}
while ( menwen_len != v27 );
}
AI转一下
def xor_mix(mingwen: bytes, device: bytes) -> bytes:
mingwen_len = len(mingwen)
device_len = len(device)
result = bytearray(mingwen_len) # 预分配结果数组
for i in range(mingwen_len):
# 明文字节索引: i % mingwen_len
mingwen_idx = i % mingwen_len
# 设备ID字节索引: (i + 1) % device_len
device_idx = (i + 1) % device_len
# 异或操作
result[i] = device[device_idx] ^ mingwen[mingwen_idx]
return bytes(result)
最后就是拼接个字符串实现md5
// 创建一个新的字节数组,长度 = 异或结果长度(v18) + 9(盐值长度)
v31 = (*a1)->NewByteArray(a1, (unsigned int)(v18 + 9));
// 异或结果v26写入新数组的前半部分
(*a1)->SetByteArrayRegion(a1, v31, 0LL, v18, v26);
// 固定字符串"smiletozz"写入新数组的后半部分(
(*a1)->SetByteArrayRegion(a1, v31, v18, 9LL, "smiletozz");
v32 = getMD5(a1, v31);
原文始发于微信公众号(爬虫逆向小林哥):【安卓逆向】某二手平台反调试请求头分析
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论