新人求助,Mac平台,Swift 语言一款软件的frida hook
目前我在练习的这软件,接口请求时,客户端会生成一个 JWT (HS256),我希望通过动态分析。找到生成 JWT 的 Secret目前用 hopper 已经找到了我要抓数据包(请求参数中 JWT 生成)的位置。如下图
根据查阅资料,看到 sub_10103a838 可以使用 0x0103a838 这个内存地址调试,在 frida 使用以下函数,确实可以调试,但是 onEnter 进来之后,这个 swift 对象没有办法正常打印。也就无从得知 jwt 的 secret 。
/**
* 根据module名字和目标方法的偏移地址获得方法的绝对地址
*/
function get_func_addr(module, offset) {
// 根据名字获取module地址
var base_addr = Module.findBaseAddress(module);
console.log("base_addr: " + base_addr);
console.log(hexdump(ptr(base_addr), {
length: 16,
header: true,
ansi: true
}));
var func_addr = base_addr.add(offset);
var return_addr;
if (Process.arch == 'arm')
return_addr = func_addr.add(1);//如果是32位地址+1
else
return_addr = func_addr;
console.log('func_addr: ' + return_addr);
console.log(hexdump(ptr(return_addr), {
length: 16,
header: true,
ansi: true
}));
Interceptor.attach(ptr(return_addr), {
// 接受可变参数
onEnter: hook,
onLeave: function (retval) {
send("====onLeave=====");
send("retval: " + retval);
}
});
return return_addr;
}
console.log("[+] script started...")
if (ObjC.available) {
if (Process.isDebuggerAttached() === true) {
console.log("[+] Debugger attached, in addition to Frida.");
}
var a = Process.arch.toString()
get_func_addr("Raycast", "0x0103a838");
console.log("[+] Device chip: " + a);
} else {
console.log("[+] Objective-C Runtime not available!");
}
console.log("[+] ...script completed")
function hook(args) {
console.log("=================Hooked=================")
// String is parsed by value
let ptr1 = args;
let ptr2 = args;
console.log(ptr1)
console.log(ptr2)
let ptr1hex = '0x' + ptr1.toString(16);
let ptr2hex = '0x' + ptr2.toString(16);
let ptr1value = BigInt(ptr1hex);
let ptr2value = BigInt(ptr2hex);
let smallObject = ptr2value & 0xFFn; // the last byte
// first, try parse smallstring
if (isSmallString(smallObject)) {
let smallStr = new SDSwiftSmallString(ptr1hex, ptr2hex);
console.log(`${smallStr.desc()}`)
return
}
// Large String
let largeStr = new SDSwiftLargeString(ptr1value, ptr2value);
console.log(`${largeStr.desc()}`)
}
function isSmallString(value) {
let smth = (value >> 4n) & 0xFn;
return (smth & 2n) > 0n;
}
class SDSwiftSmallString {
strValue;
count;
isHex;
constructor(h1, h2) {
// max small string length is 15 bytes
let h1Array = hexStrToUIntArray(h1).reverse();
let h2Array = hexStrToUIntArray(h2).reverse();
function isValidChar(element, index, array) {
return (element > 0);
}
let dataArr = h1Array.concat(h2Array).slice(0, 15);
let data = dataArr.filter(isValidChar);
let str = String.fromCharCode.apply(null, data);
if (isPrintableString(str)) {
this.strValue = str;
this.count = str.length;
this.isHex = false;
} else {
this.strValue = uintArrayToHexStr(dataArr)
this.count = dataArr.length;
this.isHex = true;
}
}
desc() {
let hexTip = this.isHex ? "hex" : "str";
return `<Swift.String(Small), count=${this.count}, ${hexTip}='${this.strValue}'>`;
}
}
class SDSwiftLargeString {
// https://github.com/TannerJin/Swift-MemoryLayout/blob/master/SwiftCore/String.swift
_countAndFlagsBits;
_object;
isASCII;
isNFC;
isNativelyStored;
isTailAllocated;
count;
strValue;
constructor(inCountAndFlag, inObject) {
this._countAndFlagsBits = inCountAndFlag;
this._object = inObject;
// 1. parse _countAndFlagsBits
let abcd = inCountAndFlag >> 48n >> 12n & 0xFn; // 16bits, 2bytes
this.isASCII = (abcd & 0x8n) > 0n;
this.isNFC = (abcd & 0x4n) > 0n;
this.isNativelyStored = (abcd & 0x2n) > 0n;
this.isTailAllocated = (abcd & 0x1n) > 0n;
this.count = inCountAndFlag & 0xFFFFFFFFFFFFn ; // 48bits,6bytes
// 2. parse _object
let objectFlag = inObject >> 56n & 0xFFn;
let strAddress = '0x' + (inObject & 0xFFFFFFFFFFFFFFn).toString(16); // low 56 bits
let strPtr = new NativePointer(strAddress);
let cstrPtr = strPtr.add(32);
this.strValue = cstrPtr.readCString() ?? "";
}
desc() {
return `<Swift.String(Large), count=${this.count}, str='${this.strValue}'>`;
}
}
function isPrintableChar(val) {
//
//0-90x30-0x39
//A-Z0x41-0x5a
//a-z97-122
//0x5f 0x24 0x20
let isNumber = (val >= 0x30 && val <= 0x39);
let isUpper = (val >= 0x41 && val <= 0x5a);
let isLower = (val >= 0x61 && val <= 0x7a);
let isSpecial = (val == 0x5f) || (val == 0x24) || (val == 0x20);
return isNumber || isUpper || isLower || isSpecial;
}
function isPrintableString(str) {
for(var i = 0; i < str.length; i++) {
let val = str.charCodeAt(i);
if (!isPrintableChar(val)) {
return false;
}
}
return true;
}
function hexString(str) {
var ret = "0x";
for(var i = 0; i < str.length; i++) {
let val = str.charCodeAt(i);
var valstr = val.toString(16);
if (valstr.length == 1) {
valstr = '0' + valstr;
}
ret = ret + valstr;
}
return ret;
}
function readUCharHexString(ptr, maxlen) {
var idx = 0;
var hexStr = "";
while (true) {
let val = ptr.add(idx).readU8()
if (val == 0) {
break;
}
var valstr = val.toString(16);
if (valstr.length == 1) {
valstr = '0' + valstr;
}
hexStr += valstr;
idx++;
if (idx >= maxlen) {
break;
}
}
if (hexStr.length > 0) {
hexStr = "0x" + hexStr;
}
return hexStr;
}
function swapInt16(val) {
return ((val & 0xff) << 8) | ((val >> 8) & 0xff);
}
function swapInt32(val) {
return (
((val & 0xff) << 24) |
((val & 0xff00) << 8) |
((val & 0xff0000) >> 8) |
((val >> 24) & 0xff)
);
}
function hexStrToUIntArray(inputStr) {
var str = inputStr
if (str.startsWith('0x')) {
str = str.substr(2);
}
var hex = str.toString();
var result = [];
for (var n = 0; n < hex.length; n += 2) {
result.push(parseInt(hex.substr(n, 2), 16));
}
return result;
}
function uintArrayToHexStr(array) {
var str = "";
for (var n = 0; n < array.length; n += 1) {
let val = array;
var valstr = array.toString(16);
if (valstr.length == 1) {
valstr = '0' + valstr;
}
str += valstr;
}
if (str.length > 0) {
str = "0x" + str;
}
return str;
}
使用 ipsw swift-dump 可以看到这样一个结构体,看起来 JWT 可能在这里。但是不知道如何使用 frida 获取这个结构体的实例。
struct Environment {
let VERSION: Swift.Int;
let RAYCAST_API_TOKEN: Swift.String;
let RAYCAST_STORE_CLIENT_ID: Swift.String;
let RAYCAST_STORE_CLIENT_SECRET: Swift.String;
let RAYCAST_STORE_JWT_SECRET: Swift.String;
let SENTRY_DSN: Swift.String;
let SEGMENT_WRITE_KEY: Swift.String;
let RAYCAST_IMAGE_PROXY_KEY: Swift.String;
let RAYCAST_IMAGE_PROXY_SALT: Swift.String;
let AMPLITUDE_API_KEY: Swift.String;
let AERODATABOX_API_KEY: Swift.String;
let STRIPE_API_PRODUCT_ID_STAGING: Swift.String;
let STRIPE_API_PRODUCT_ID_BETTER_AI_UPGRADE_STAGING: Swift.String;
let STRIPE_API_KEY_STAGING: Swift.String;
let STRIPE_API_PRODUCT_ID_PRODUCTION: Swift.String;
let STRIPE_API_PRODUCT_ID_BETTER_AI_UPGRADE_PRODUCTION: Swift.String;
let STRIPE_API_KEY_PRODUCTION: Swift.String;
let STRIPE_API_PRODUCT_ID_DEVELOPMENT: Swift.String;
let STRIPE_API_PRODUCT_ID_BETTER_AI_UPGRADE_DEVELOPMENT: Swift.String;
let STRIPE_API_KEY_DEVELOPMENT: Swift.String;
let OPENAI_API_KEY: Swift.String;
let OPENAI_ORGANIZATION: Swift.String;
let POSTHOG_API_KEY: Swift.String;
}
请大佬们指点。{:301_995:} 在 web 项目中,通常 jwt token 是server 端生成并返回的;
之后返回给 client ;
之后client 与 server 的通信都是携带 token 信息 Vvvvvoid 发表于 2024-6-1 21:57
在 web 项目中,通常 jwt token 是server 端生成并返回的;
之后返回给 client ;
之后client 与 server...
这个软件客户端也会生成,hs256,服务端生成的是rsa,我已经找到服务端的生成验签所需要的公钥了。
页:
[1]