吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 751|回复: 2
收起左侧

[求助] 新人求助,Mac平台,Swift 语言一款软件的frida hook

[复制链接]
keniu007 发表于 2024-6-1 18:07
50吾爱币
目前我在练习的这软件,接口请求时,客户端会生成一个 JWT (HS256),我希望通过动态分析。找到生成 JWT 的 Secret

目前用 hopper 已经找到了我要抓数据包(请求参数中 JWT 生成)的位置。如下图

raycastcode.jpg


根据查阅资料,看到 sub_10103a838 可以使用 0x0103a838 这个内存地址调试,在 frIDA 使用以下函数,确实可以调试,但是 onEnter 进来之后,这个 swift 对象没有办法正常打印。也就无从得知 jwt 的 secret 。

[JavaScript] 纯文本查看 复制代码
/**
	* 根据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[0];
    let ptr2 = args[1];

	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) {
    // [A-Za-z0-9_$ ]
    //0-9  0x30-0x39
    //A-Z  0x41-0x5a
    //a-z  97-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[n];
        var valstr = array[n].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 获取这个结构体的实例。

[Objective-C] 纯文本查看 复制代码
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:}

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

Vvvvvoid 发表于 2024-6-1 21:57
在 web 项目中,通常 jwt token 是server 端生成并返回的;
之后返回给 client ;
之后client 与 server 的通信都是携带 token 信息

免费评分

参与人数 1吾爱币 +1 热心值 +1 收起 理由
keniu007 + 1 + 1 热心回复!

查看全部评分

 楼主| keniu007 发表于 2024-6-1 22:26
Vvvvvoid 发表于 2024-6-1 21:57
在 web 项目中,通常 jwt token 是server 端生成并返回的;
之后返回给 client ;
之后client 与 server  ...

这个软件客户端也会生成,hs256,服务端生成的是rsa,我已经找到服务端的生成验签所需要的公钥了。
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-11-21 19:13

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表