小七先生ヽ 的博客 - Frida相关
type: channel
link: https://www.xiao7post.com/index.php/category/frida/
description: Frida相关知识、代码等
items: frida hook java
items: Frida Hook so
items: 某app zzReqSign 算法还原分析过程

frida hook java
type: item
date: 2023-04-17T21:16:00+08:00
description: 验证码服务平台 谷歌人机 ReCaptcha（v2/v3 通用版）, 直接返回 token ReCaptcha（v2/v3 企业版）, 直接返回 token ReCaptcha（steam）, 直接返回 token CloudFlare 盾通用版, 返回 cf_clearance、__cf_bm 、正确响应源码 html、验证流程使用的 tls 指纹 Incapsula 盾 reese84 通用版, 返回 reese84 cookie 或 solution 参数 Incapsula 盾 __utmvc 通用版, 服务器直接无感验证 或 __utmvc cookie Hcaptcha 通用版, 直接返回 generated_pass_UUID 直接返回 _abck tls 转发接口, 针对校验 ja3、http2 等指纹（akamai/cloudflare）的接口 更多支持后续敬请期待..... 注册连接：https://3ii.cc/V2J 新用户注册加群即送10000点余额 新用户注册加群即送10000点余额 新用户注册加群即送10000点余额Frida 启动attach 启动直接附加到指定包名的应用中frida -U com.kevin.android -l hook.js直接附加到当前应用中frida -UF -l hook.jsimport sys import time import frida def on_message(message,data): print("message",message) print("data",data) device = frida.get_usb_device() session = device.attach("com.kevin.demo1") with open("./demo1.js","r") as f: script = session.create_script(f.read()) script.on("message",on_message) script.load() sys.stdin.read()spawn 启动frida -U -f com.kevin.android -l demo1.js --no-pauseimport sys import time import frida def on_message(message,data): print("message",message) print("data",data) device = frida.get_usb_device() pid = device.spawn(["com.kevin.demo1"]) device.resume(pid) session = device.attach(pid) with open("./rpc_demo.js",'r') as f: script = session.create_script(f.read()) script.on("message",on_message) script.load() sys.stdin.read()frida-server 自定义端口frida server更改 frida server 默认端口: 27042 并开启远程连接adb shell su - cd /data/local/tmp # 输入 wifiadb 对应的 ip 和自定义端口 ./frida-server -l 192.168.0.1:6666 # 也可以使用默认端口启动 ./frida-server -l 192.168.0.1fridafrida 远程连接自定义端口# 连接指定 6666 端口 frida -H 192.168.0.1:6666 com.demo1.app -l demo1.js # 默认使用端口 27042 frida -H 192.168.0.1 -l demo1.jspython# -*- coding: UTF-8 -*- import frida, sys jsCode = """ console.log("test"); """ def message(message, data): if message['type'] == 'send': print(f"[*] {message['payload']}") else: print(message) # ./fs120800 -l "0.0.0.0:6666" # adb wifi 10.0.0.23 process = frida.get_device_manager().add_remote_device('127.0.0.1:6666').attach('…

Frida Hook so
type: item
date: 2023-04-17T13:00:00+08:00
description: 验证码服务平台 谷歌人机 ReCaptcha（v2/v3 通用版）, 直接返回 token ReCaptcha（v2/v3 企业版）, 直接返回 token ReCaptcha（steam）, 直接返回 token CloudFlare 盾通用版, 返回 cf_clearance、__cf_bm 、正确响应源码 html、验证流程使用的 tls 指纹 Incapsula 盾 reese84 通用版, 返回 reese84 cookie 或 solution 参数 Incapsula 盾 __utmvc 通用版, 服务器直接无感验证 或 __utmvc cookie Hcaptcha 通用版, 直接返回 generated_pass_UUID 直接返回 _abck tls 转发接口, 针对校验 ja3、http2 等指纹（akamai/cloudflare）的接口 更多支持后续敬请期待..... 注册连接：https://3ii.cc/V2J 新用户注册加群即送10000点余额 新用户注册加群即送10000点余额 新用户注册加群即送10000点余额IDA 判断 Thumb 指令集和 Arm 指令集IDA - Options - General - number of opcode bytes - 设置为 4此时查看 IDA VIew 中 opcode 的长度, 如果出现 2 个字节和 4 个字节的, 说明为 thumb 指令集如果都是 4 个字节的, 说明是 arm 指令集;在 Thumb 指令集下, inline hook 的偏移地址需要进行 +1 操作;获取所有 JNI 函数函数地址通过 hook ArtMethod 的 RegisterNative 函数, 可以监控所有的静态注册和动态注册的 JNI 函数的地址;frida14 仅在Android 8.1下测试成功，其他版本可能需要重新修改适配 原作者: Simp1er const STD_STRING_SIZE = 3 * Process.pointerSize; class StdString { constructor() { this.handle = Memory.alloc(STD_STRING_SIZE); } dispose() { const [data, isTiny] = this._getData(); if (!isTiny) { Java.api.$delete(data); } } disposeToString() { const result = this.toString(); this.dispose(); return result; } toString() { const [data] = this._getData(); return data.readUtf8String(); } _getData() { const str = this.handle; const isTiny = (str.readU8() & 1) === 0; const data = isTiny ? str.add(1) : str.add(2 * Process.pointerSize).readPointer(); return [data, isTiny]; } } function prettyMethod(method_id, withSignature) { const result = new StdString(); Java.api['art::ArtMethod::PrettyMethod'](result, method_id, withSignature ? 1 : 0); return result.disposeToString(); } function readStdString(str) { if ((str.readU8() & 1) === 1) { // size LSB (=1) indicates if it's a long string return str.add(2 * Process.pointerSize).readPointer().readUtf8String(); } return str.add(1).readUtf8String(); } function attach(addr) { Interceptor.attach(addr, { onEnter: function (args) { this.arg0 = args[0]; // this }, onLeave: function (retval) { var modulemap = new ModuleMap() mod…

某app zzReqSign 算法还原分析过程
type: item
date: 2023-03-29T17:10:00+08:00
description: 验证码服务平台 谷歌人机 ReCaptcha（v2/v3 通用版）, 直接返回 token ReCaptcha（v2/v3 企业版）, 直接返回 token ReCaptcha（steam）, 直接返回 token CloudFlare 盾通用版, 返回 cf_clearance、__cf_bm 、正确响应源码 html、验证流程使用的 tls 指纹 Incapsula 盾 reese84 通用版, 返回 reese84 cookie 或 solution 参数 Incapsula 盾 __utmvc 通用版, 服务器直接无感验证 或 __utmvc cookie Hcaptcha 通用版, 直接返回 generated_pass_UUID 直接返回 _abck tls 转发接口, 针对校验 ja3、http2 等指纹（akamai/cloudflare）的接口 更多支持后续敬请期待..... 注册连接：https://3ii.cc/V2J 新用户注册加群即送10000点余额 新用户注册加群即送10000点余额 新用户注册加群即送10000点余额工欲善其事必先利其器工具：真机or模拟器 Fiddler 或任意一款抓包工具 VSCode frida 老规矩 先抓包其中 zzReqSign 便是我们需要还原的算法 我们查课发现没有加固 直接丢进jadx进行反编译搜索定位 我们来到如下位置发现是个 native 方法 那么加密在so层 上面 System.loadLibrary("signLib"); 就是加载so的指令 其中 signLib就是so名字解压apk 去lib目录寻找是否有这个文件拖入IDA 导出函数 搜索 getSign定位如下位置：代码如下：int __fastcall Java_com_zhuanzhuan_sign_SignUtil_getSign(JNIEnv_ *a1, int a2, int a3, int a4) { const char *app_sign_sha1; // r0 struct _jobject *v9; // r8 signed int v10; // r5 int DevID; // r0 struct _jobject *v12; // r8 int v13; // r9 jbyte *v14; // r6 jsize v15; // r10 _BYTE *v16; // r8 signed int i; // r11 jbyte v18; // r4 int v19; // r1 JNIEnv_ *v20; // r4 int v21; // r9 int MD5; // r10 int v24; // [sp+8h] [bp-30h] struct _jobject *v25; // [sp+Ch] [bp-2Ch] struct _jobject *v26; // [sp+10h] [bp-28h] JNIEnv_ *v27; // [sp+14h] [bp-24h] jbyte *v28; // [sp+18h] [bp-20h] if ( !a3 ) return 0; app_sign_sha1 = get_app_sign_sha1(a1, a4); if ( !app_sign_sha1 ) return 0; if ( strcmp(app_sign_sha1, app_sing_str) ) return 0; v9 = toBytes(a1, a3); v10 = a1->functions->GetArrayLength(a1, v9); v28 = a1->functions->GetByteArrayElements(a1, v9, 0); DevID = getDevID(a1, a2); if ( !DevID ) return 0; v26 = v9; v24 = DevID; v12 = toBytes(a1, DevID); v13 = 0; v14 = a1->functions->GetByteArrayElements(a1, v12, 0); v27 = a1; v25 = v12; v15 = a1->functions->GetArrayLength(a1, v12); v16 = malloc(v10); for ( i = 0; i < v10; ++i ) { v18 = v28[v13 % v10]; v19 = (v13 + 1) % v15; v13 += 2; v16[i] = v14[v19] ^ v18; } v20 = v27; v21 = v27->functions->NewByteArray(&v27->…