Frida prints the call stack of a function to facilitate tracing back the entire calling process of the function.

if (ObjC.available)
{
    try
    {
        //hook - ZYOperationView operationCopyLink
        var className = "ZYMediaDownloadHelper";
        var funcName = "+ downloadMediaUrl:isVideo:progress:finishBlock:";
        var hook = eval('ObjC.classes.' + className + '["' + funcName + '"]');
        
        Interceptor.attach(hook.implementation, {
            onEnter: function(args) {
                // args[0] is self
                // args[1] is selector (SEL "sendMessageWithText:")
                // args[2] holds the first function argument, an NSString

                var mainPath = ObjC.classes.NSBundle.mainBundle().executablePath().UTF8String();
                XLOG(mainPath)
                
                var slide = get_image_vm_slide(mainPath)
                
                XLOG(slide)
                
            }
        });
    }
    catch(err)
    {
        console.log("[!] Exception2: " + err.message);
    }
}
else
{
    console.log("[-] Objective-C Runtime is not available!");
}


if(ObjC.available){ //判断Object-C类方法是否已经加载进来
    console.log('\n[*] Starting Hooking');
    var _className = "JailbreakDetectionVC"; //类名
    var _methodName = "- isJailbroken"; //方法名
    var hooking = ObjC.classes[_className][_methodName]; //通过ObjC.classes返回当前注册类的映射表找到想要hook的类名、方法名
    console.log('className is: ' + _className + ' and methodName is: ' + _methodName);

    Interceptor.attach(hooking.implementation,{ //Interceptor.attach拦截函数 hooking.implementation即我们需要拦截的函数地址 是有一个
    //NativePointer参数
    //onEnter.function(args)被拦截函数调用之前回调 其中原始函数的参数使用args数组 有使用过Xposed则它有点类似于 XPosed 的 beforeHookedMethod
        onEnter: function(args) {
            //args[0]:self
            //args[1]:The selector
            //args[2]:方法的第一个参数开始
            //如下代码则是我们在函数调用之前 打印函数的调用堆栈 便于回溯函数的整个调用过程
            console.log(' hook success ')
            this._className = ObjC.Object(args[0]).toString();
            this._methodName = ObjC.selectorAsString(args[1]);
            console.log('Detected call to: ');
            console.log(' ' + this._className + ' --> ' + this._methodName);
            console.log('isJailbroken called from:\n' + Thread.backtrace(this.context,Backtracer.ACCURATE)
            .map(DebugSymbol.fromAddress).join('\n') + '\n');
            //print_arguments(args);
        },
        //onLeave.function(returnValue)被拦截函数调用之后回调 其中returnValue表示原始函数的返回值
        //有使用过Xposed则它有点类似于 Xposed 的 afterHookedMethod
        onLeave:function(returnValue){
            //如下代码则是我们在函数调用之后 打印函数的返回值及函数返回值类型
            console.log('Return value of: ');
            console.log(' ' + this._className + ' --> ' + this._methodName);
            var typeValue = Object.prototype.toString.call(returnValue);
            console.log("\t[-] Type of return value: " + typeValue);
            console.log("\t[-] Return Value: " + returnValue);
        }
    });
}

//如下代码则是我们在函数调用之后 打印函数的返回值及函数返回值类型
    var method = ObjC.Object(args[4]).toString();//NSString
    var typeValue = Object.prototype.toString.call(args[3]);
    var Name = ObjC.Object(args[2]).toString();
           // console.log("\t[-] Type of return value: " + typeValue);
            console.log("\t[-] _requestWithURLString method: " + method);

            console.log("\t[-] _requestWithURLString Name: " + Name);
//if(method == "GET")
{
  //[NSThread callStackSymbols];
 console.log(' processJsonObject callStackSymbols statr')
 var NSTharr = ObjC.classes.NSThread.callStackSymbols();
 //NSString *tempString = [mutableArray componentsJoinedByString:@","];--分隔符 将array数组转换为string字符串
console.log('processJsonObject call to: \n'+NSTharr.componentsJoinedByString_('\n'));
console.log(' processJsonObject callStackSymbols  ===end ')

{
  //[NSThread callStackSymbols];
 console.log(' processJsonObject callStackSymbols statr')
 var NSTharr = ObjC.classes.NSThread.callStackSymbols();
 //NSString *tempString = [mutableArray componentsJoinedByString:@","];--分隔符 将array数组转换为string字符串
console.log('processJsonObject call to: \n'+NSTharr.componentsJoinedByString_('\n'));
console.log(' processJsonObject callStackSymbols  ===end ')

//===========
// xia0 log
function XLOG(log) {
    console.log("[*] " + log)
}

function XLibLOG(log) {
    console.log(log)
}

// format string with width
function format(str,width){ 
    str = str + ""
    var len = str.length;
    
    if(len > width){
        return str
    }
    
    for(var i = 0; i < width-len; i++){
        str += " "
    }
    return str; 
}

function get_image_vm_slide(modulePath){
    // intptr_t   _dyld_get_image_vmaddr_slide(uint32_t image_index)
    var _dyld_get_image_vmaddr_slide = new NativeFunction(
        Module.findExportByName(null, '_dyld_get_image_vmaddr_slide'),
        'pointer',
        ['uint32']
    );
    // const char*  _dyld_get_image_name(uint32_t image_index) 
    var _dyld_get_image_name = new NativeFunction(
        Module.findExportByName(null, '_dyld_get_image_name'),
        'pointer',
        ['uint32']
    );
    // uint32_t  _dyld_image_count(void)
    var _dyld_image_count = new NativeFunction(
        Module.findExportByName(null, '_dyld_image_count'),
        'uint32',
        []
    );

    var image_count = _dyld_image_count();

    for (var i = 0; i < image_count; i++) {
        var image_name_ptr = _dyld_get_image_name(i)
        var image_silde_ptr = _dyld_get_image_vmaddr_slide(i)
        var image_name = Memory.readUtf8String(image_name_ptr)

        if (image_name == modulePath) {
            //XLOG(Memory.readUtf8String(image_name_ptr) + " slide:"+image_silde_ptr)
            return image_silde_ptr;
        }
        //XLOG(Memory.readUtf8String(image_name_ptr) + "slide:"+image_silde_ptr)
    }

    return 0;
}

function get_all_objc_class(modulePath){

    // const char * objc_copyClassNamesForImage(const char *image, unsigned int *outCount)
    var objc_copyClassNamesForImage = new NativeFunction(
        Module.findExportByName(null, 'objc_copyClassNamesForImage'),
        'pointer',
        ['pointer', 'pointer']
    );
    // free
    var free = new NativeFunction(Module.findExportByName(null, 'free'), 'void', ['pointer']);
    
    // if given modulePath nil, default is mainBundle
    if(!modulePath){
        var path = ObjC.classes.NSBundle.mainBundle().executablePath().UTF8String();
    }else{
        var path = modulePath;
    }

    // create args
    var pPath = Memory.allocUtf8String(path);
    var p = Memory.alloc(Process.pointerSize);
    Memory.writeUInt(p, 0);

    var pClasses = objc_copyClassNamesForImage(pPath, p);
    var count = Memory.readUInt(p);
    var classes = new Array(count);

    for (var i = 0; i < count; i++) {
        var pClassName = Memory.readPointer(pClasses.add(i * Process.pointerSize));
        classes[i] = Memory.readUtf8String(pClassName);
    }

    free(pClasses);
    
    // XLOG(classes)
    return classes;
}
    

function get_all_class_method(classname){
    var objc_getClass = new NativeFunction(
        Module.findExportByName(null, 'objc_getClass'),
        'pointer',
        ['pointer']
    );
    var class_copyMethodList = new NativeFunction(
        Module.findExportByName(null, 'class_copyMethodList'),
        'pointer',
        ['pointer', 'pointer']
    );

    var objc_getMetaClass = new NativeFunction(
        Module.findExportByName(null, 'objc_getMetaClass'),
        'pointer',
        ['pointer']
    );
    
    var method_getName = new NativeFunction(
        Module.findExportByName(null, 'method_getName'),
        'pointer',
        ['pointer']
    );
    
    var free = new NativeFunction(Module.findExportByName(null, 'free'), 'void', ['pointer']);
    
    // get objclass and metaclass
    var name = Memory.allocUtf8String(classname);
    var objClass = objc_getClass(name)
    var metaClass = objc_getMetaClass(name)
    
    // get obj class all methods
    var size_ptr = Memory.alloc(Process.pointerSize);
    Memory.writeUInt(size_ptr, 0);
    var pObjMethods = class_copyMethodList(objClass, size_ptr);
    var count = Memory.readUInt(size_ptr);
    
    var allMethods = new Array();
    
    var allObjMethods = new Array();
    
    // get obj class all methods name and IMP
    for (var i = 0; i < count; i++) {
        var curObjMethod = new Array();
        
        var pObjMethodSEL = method_getName(pObjMethods.add(i * Process.pointerSize))
        var pObjMethodName = Memory.readCString(Memory.readPointer(pObjMethodSEL))
        var objMethodIMP = Memory.readPointer(pObjMethodSEL.add(2*Process.pointerSize))
        // XLOG("-["+classname+ " " + pObjMethodName+"]" + ":" + objMethodIMP)
        curObjMethod.push(pObjMethodName)
        curObjMethod.push(objMethodIMP)
        allObjMethods.push(curObjMethod)
    }
    
    var allMetaMethods = new Array();
    
    // get meta class all methods name and IMP
    var pMetaMethods = class_copyMethodList(metaClass, size_ptr);
    var count = Memory.readUInt(size_ptr);
    for (var i = 0; i < count; i++) {
        var curMetaMethod = new Array();
        
        var pMetaMethodSEL = method_getName(pMetaMethods.add(i * Process.pointerSize))
        var pMetaMethodName = Memory.readCString(Memory.readPointer(pMetaMethodSEL))
        var metaMethodIMP = Memory.readPointer(pMetaMethodSEL.add(2*Process.pointerSize))
        //XLOG("+["+classname+ " " + pMetaMethodName+"]" + ":" + metaMethodIMP)
        curMetaMethod.push(pMetaMethodName)
        curMetaMethod.push(metaMethodIMP)
        allMetaMethods.push(curMetaMethod)
    }
    
    allMethods.push(allObjMethods)
    allMethods.push(allMetaMethods)
    
    free(pObjMethods);
    free(pMetaMethods);
    
    return allMethods;
}
    
function get_info_form_address(address){
    
    // int dladdr(const void *, Dl_info *);
    
    //typedef struct dl_info {
    //        const char      *dli_fname;     /* Pathname of shared object */
    //        void            *dli_fbase;     /* Base address of shared object */
    //        const char      *dli_sname;     /* Name of nearest symbol */
    //        void            *dli_saddr;     /* Address of nearest symbol */
    //} Dl_info;
    
    var dladdr = new NativeFunction(
        Module.findExportByName(null, 'dladdr'),
        'int',
        ['pointer','pointer']
    );
    
    var dl_info = Memory.alloc(Process.pointerSize*4);

    dladdr(ptr(address),dl_info)

    var dli_fname = Memory.readCString(Memory.readPointer(dl_info))
    var dli_fbase = Memory.readPointer(dl_info.add(Process.pointerSize))
    var dli_sname = Memory.readCString(Memory.readPointer(dl_info.add(Process.pointerSize*2)))
    var dli_saddr = Memory.readPointer(dl_info.add(Process.pointerSize*3))
    
    //XLOG("dli_fname:"+dli_fname)
    //XLOG("dli_fbase:"+dli_fbase)
    //XLOG("dli_sname:"+dli_sname)
    //XLOG("dli_saddr:"+dli_saddr)
    
    var addrInfo = new Array();
    
    addrInfo.push(dli_fname);
    addrInfo.push(dli_fbase);
    addrInfo.push(dli_sname);
    addrInfo.push(dli_saddr);
    
    //XLOG(addrInfo)
    return addrInfo;
}


function find_symbol_from_address(modulePath,addr){
    var frameAddr = addr
    
    var theDis = 0xffffffffffffffff;
    var tmpDis = 0;
    var theClass = "None"
    var theMethodName = "None"
    var theMethodType = "-"
    var theMethodIMP = 0
    
    var allClassInfo = {}

    var allClass = get_all_objc_class(modulePath);
    
    for(var i = 0, len = allClass.length; i < len; i++){
        var mInfo = get_all_class_method(allClass[i]);
        var curClassName = allClass[i]
        
        var objms = mInfo[0];
        for(var j = 0, olen = objms.length; j < olen; j++){
            var mname = objms[j][0]
            var mIMP = objms[j][1]
            if(frameAddr >= mIMP){
                var tmpDis = frameAddr-mIMP
                if(tmpDis < theDis){
                    theDis = tmpDis
                    theClass = curClassName
                    theMethodName = mname
                    theMethodIMP = mIMP
                    theMethodType = "-"
                }
            }
        }

        var metams = mInfo[1];
        for(var k = 0, mlen = metams.length; k < mlen; k++){
            var mname = metams[k][0]
            var mIMP = metams[k][1]
            if(frameAddr >= mIMP){
                var tmpDis = frameAddr-mIMP
                if(tmpDis < theDis){
                    theDis = tmpDis
                    theClass = curClassName
                    theMethodName = mname
                    theMethodIMP = mIMP
                    theMethodType = "+"
                }
            }
        }
    }

    var symbol = theMethodType+"["+theClass+" "+theMethodName+"]"

    if(symbol.indexOf(".cxx")!=-1){
        symbol = "maybe C function?"
    }
    
    // if distance > 3000, maybe a c function
    if(theDis > 3000){
        symbol = "maybe C function? symbol:" + symbol
    }
    
    return symbol;
}


//================================
var onlyMainModule=this.context;
 function getExeFileName(modulePath){
        modulePath += ""
        return modulePath.split("/").pop()
    }

var mainPath = ObjC.classes.NSBundle.mainBundle().executablePath().UTF8String();
    var mainModuleName = getExeFileName(mainPath)

    var backtrace = Thread.backtrace(this.context, Backtracer.ACCURATE).map(DebugSymbol.fromAddress)


 for (var i = 0;i < backtrace.length;i ++)
    {
        var curStackFrame = backtrace[i] + ''
        var curSym = curStackFrame.split("!")[1]
        var curAddr = curStackFrame.split("!")[0].split(" ")[0]
        var curModuleName = curStackFrame.split("!")[0].split(" ")[1]
var info = get_info_form_address(curAddr);
        // skip frida call stack
        if(!info[0]){
          console.log(' processJsonObject get_info_form_address  ===nli ');
            continue;
        }


           var dl_symbol = info[2]+""
        var curModulePath = info[0]+""
        
        var fileAddr = curAddr-get_image_vm_slide(curModulePath);

        if (onlyMainModule) {
            if (curModulePath == mainPath) {
                var symbol = find_symbol_from_address(curModulePath,curAddr);
            }else{
                var symbol = info[2];
            }
        }else{
            if((!info[2] || dl_symbol.indexOf("redacted")!=-1) && curModulePath.indexOf("libdyld.dylib") == -1){
                var symbol = find_symbol_from_address(curModulePath,curAddr);
            }else{
                var symbol = info[2];
            }
        }

        XLOG(format(i, 4)+format(getExeFileName(info[0]), 20)+"mem:"+format(ptr(curAddr),13)+"file:"+format(ptr(fileAddr),13)+format(symbol,80))

}



  return;
}
var nsDictArg = new ObjC.Object(args[3]); // NSDictionary

    //https://blog.csdn.net/dieyu4807/article/details/102296246 参照
    // convert nsDictArg to JSON
    var err = ptr(ObjC.classes.NSError.alloc())
    //NSData *jsonData = [NSJSONSerialization dataWithJSONObject:objct options:0 error:&error];
    var json = ObjC.classes.NSJSONSerialization.dataWithJSONObject_options_error_(nsDictArg , 0, err);
        // let jsonStr = json.bytes().readUtf8String(json.length());
        //-var jsonBinary = json.bytes().readByteArray(json.length());

        //jsonString = [[NSString alloc]initWithData:jsonData encoding:NSUTF8StringEncoding];
        var nsting = ObjC.classes.NSString.alloc();
 var jsonBinary = nsting.initWithData_encoding_(json , 0);

        // Send JSON data back to Frida 

console.log("\t[-] _requestWithURLString params: " + jsonBinary);

          //如下代码则是我们在函数调用之前 打印函数的调用堆栈 便于回溯函数的整个调用过程
            console.log(' hook success ')
            this._className = ObjC.Object(args[0]).toString();
            this._methodName = ObjC.selectorAsString(args[1]);
            console.log('Detected call to: ');
            console.log(' ' + this._className + ' --> ' + this._methodName);
            console.log('isJailbroken called from:\n' + Thread.backtrace(this.context,Backtracer.ACCURATE)
            .map(DebugSymbol.fromAddress).join('\n') + '\n');
//[NSThread callStackSymbols];
 console.log(' hook callStackSymbols statr')
 var NSTharr = ObjC.classes.NSThread.callStackSymbols();

console.log(' hook callStackSymbols  ===end ')

Guess you like

Origin blog.csdn.net/qq_21051503/article/details/133172445