首页
社区
课程
招聘
[讨论]Frida脚本遍历dex里面的Class和method报错:Process terminated
发表于: 2020-7-31 16:30 7857

[讨论]Frida脚本遍历dex里面的Class和method报错:Process terminated

2020-7-31 16:30
7857

用的是使用Frida简单实现函数粒度脱壳FRIDA-DEXDump: 一吻便杀一个人,三秒便脱一个壳这两个脚本,简单修改了一下,用来实现遍历dex中的每个类的所有函数,但是只有少数app能正常运行,多数app运行一会儿就会自动结束进程,下面是用自己写的测试app执行脚本
使用的命令:

frida -R -l mysrc3.js cn.example.myapp

报错信息:

Process terminated

大佬们帮忙看一下是什么原因啊?非常感谢!
相关代码:

var enable_deep_search = false;
//var globalId = null;//计时器Id
var globalDexs = null;
var classArr = [];//从dex里面获取的类名
var dumpMethodName = [];//每个类里面的方法
var ArtMethod_invoke_replace = null;//保存ArtMethod_invoke
var DexBase = null;
var DexSize = null;
var globalStartTime = null;//记录每次的开始时间
var globalCurTime = null;//当前时间
var globalDexIndex = 0;
var globalPrvDexIndex = -1;
var globalClassIndex = 0;
var globalPrvClassIndex = -1;
var globalMethodIndex = 0;
const EXEC_TIME = 3000;//Exec 函数执行 3 秒后,开始下一次执行
var globalSumMethodCount = 0;//所有函数的总数
const PRINT_DEX_INDEX = true;
const PRINT_DEX_INFO = true;
const PRINT_CLASSARR_LEN = true;
const PRINT_OTHER_INFO = true;
var globalFinished = false;
var globalTimeoutId = null;
var globaCurClassName = null;
var globalStepClassNams = [];

globalTimeoutId = setTimeout(Exec2,0); 

function Exec2(){

    if (globalFinished && globalTimeoutId!=null) {
        clearTimeout(globalTimeoutId);
    } else {

        Exec();
        globalTimeoutId = setTimeout(Exec2,0); 
    }

}

function Exec() {

    globalStartTime = new Date().getTime();
    if (globalDexs != null) {

        outer:
        for (;globalDexIndex < globalDexs.length; globalDexIndex++) {

            if (PRINT_OTHER_INFO) {
                console.log("globalDexIndex:", globalDexIndex);    
            }

            //如果开始分析下一个 dex 就重新填充 classArr
            if (globalDexIndex != globalPrvDexIndex) {
                initClassArr(globalDexs[globalDexIndex].addr,globalDexs[globalDexIndex].size);
                globalPrvDexIndex = globalDexIndex;
                globalClassIndex = 0;
                globalPrvClassIndex = -1;
            }

            //遍历每个 dex 里面的 class
            for (;globalClassIndex < classArr.length;globalClassIndex++) {

                if (PRINT_OTHER_INFO) {
                    console.log("  globalClassIndex:", globalClassIndex, " name:", classArr[globalClassIndex]);    
                }

                //如果开始分析下一个 class 就重新填充 dumpMethodName
                if (globalClassIndex != globalPrvClassIndex) {
                    //InitdumpMethodName(classArr[globalClassIndex]);
                    globaCurClassName = classArr[globalClassIndex];
                    Java.perform(InitdumpMethodName);
                    globalPrvClassIndex = globalClassIndex;
                    globalMethodIndex = 0;
                }

                for (;globalMethodIndex < dumpMethodName.length; globalMethodIndex++) {
                    if (PRINT_OTHER_INFO) {
                        console.log("    globalMethodIndex:", globalMethodIndex, " name:",dumpMethodName[globalMethodIndex]);    
                    }
                    //PrintMethodName();
                    globalSumMethodCount++;
                    globalCurTime = new Date().getTime();

                    //如果运行超过3秒就结束
                    if ((globalCurTime - globalStartTime)>EXEC_TIME) {
                        console.log("Time reached, start another loop...");
                        globalMethodIndex++;
                        break outer;
                    }
                }

            }

        }

        if (globalDexIndex >= globalDexs.length) {
            console.log(globalSumMethodCount,"Method Exec Finished!");
            globalFinished = true;
        } 

    } else {
        globalDexs = scandex();
        if (globalDexs != null) {console.log("~~~~~~~  Dex Count: ", globalDexs.length, " ~~~~~~");}
    }

}

function PrintMethodName() {
    console.log(dumpMethodName[globalMethodIndex]);
}

function verify_by_maps(dexptr, mapsptr) {
    var maps_offset = dexptr.add(0x34).readUInt();
    var maps_size = mapsptr.readUInt();
    for (var i = 0; i < maps_size; i++) {
        var item_type = mapsptr.add(4 + i * 0xC).readU16();
        if (item_type === 4096) {
            var map_offset = mapsptr.add(4 + i * 0xC + 8).readUInt();
            if (maps_offset === map_offset) {
                return true;
            }
        }
    }
    return false;
}

function verify(dexptr, range, enable_verify_maps) {

    if (range != null) {
        var range_end = range.base.add(range.size);
        // verify header_size
        if (dexptr.add(0x70) > range_end) {
            return false;
        }

        // verify file_size
        var dex_size = dexptr.add(0x20).readUInt();
        if (dexptr.add(dex_size) > range_end) {
            return false;
        }

        if (enable_verify_maps) {
            var maps_offset = dexptr.add(0x34).readUInt();
            if (maps_offset === 0) {
                return false
            }

            var maps_address = dexptr.add(maps_offset);
            if (maps_address > range_end) {
                return false
            }

            var maps_size = maps_address.readUInt();
            if (maps_size < 2 || maps_size > 50) {
                return false
            }
            var maps_end = maps_address.add(maps_size * 0xC + 4);
            if (maps_end < range.base || maps_end > range_end) {
                return false
            }
            return verify_by_maps(dexptr, maps_address)
        } else {
            return dexptr.add(0x3C).readUInt() === 0x70;
        }
    }


}

function dumpFile(name, base, size) {
    var file_path = "/sdcard/" + name + "_" + base + "_" + ptr(size) + ".dump";
    var file_handle = new File(file_path, "wb");
    if (file_handle && file_handle != null) {
        Memory.protect(ptr(base), size, 'rwx');
        var libso_buffer = ptr(base).readByteArray(size);
        file_handle.write(libso_buffer);
        file_handle.flush();
        file_handle.close();
        console.log("[dump]:", file_path);
    }
}

function scandex() {
    var result = [];
    Process.enumerateRanges('r--').forEach(function (range) {
        try {
            Memory.scanSync(range.base, range.size, "64 65 78 0a 30 ?? ?? 00").forEach(function (match) {

                if (range.file && range.file.path
                    && (// range.file.path.startsWith("/data/app/") ||
                        range.file.path.startsWith("/data/dalvik-cache/") ||
                        range.file.path.startsWith("/system/"))) {
                    return;
                }

                if (verify(match.address, range, false)) {
                    var dex_size = match.address.add(0x20).readUInt();
                    result.push({
                        "addr": match.address,
                        "size": dex_size
                    });
                }
            });

            if (enable_deep_search) {
                Memory.scanSync(range.base, range.size, "70 00 00 00").forEach(function (match) {
                    var dex_base = match.address.sub(0x3C);
                    if (dex_base < range.base) {
                        return
                    }
                    if (dex_base.readCString(4) != "dex\n" && verify(dex_base, range, true)) {
                        var dex_size = dex_base.add(0x20).readUInt();
                        result.push({
                            "addr": dex_base,
                            "size": dex_size
                        });
                    }
                })
            } else {
                if (range.base.readCString(4) != "dex\n" && verify(range.base, range, true)) {
                    var dex_size = range.base.add(0x20).readUInt();
                    result.push({
                        "addr": range.base,
                        "size": dex_size
                    });
                }
            }

        } catch (e) {
        }
    });

    return result;
}

function HookArtInvoke() {
        var libart = Process.findModuleByName("libart.so");
        var symbols = libart.enumerateSymbols();
        var symbol_name = null;
        var addr_ArtMethod_invoke = null;
        for(var index=0; index < symbols.length; index++) {
            var symbol = symbols[index];
            var symbol_name = symbol.name;
            if (symbol_name.indexOf("_ZN3art9ArtMethod6InvokeEPNS_6ThreadEPjjPNS_6JValueEPKc") >= 0 ) {
                addr_ArtMethod_invoke = symbol.address;
                console.log("addr_ArtMethod_invoke:",addr_ArtMethod_invoke);
                var addr_ArtMethod_invoke_replace = addr_ArtMethod_invoke;
                ArtMethod_invoke_replace = new NativeFunction(
                    addr_ArtMethod_invoke_replace, 'void', ['pointer', 'pointer', 'pointer', 'uint32', 'pointer','pointer']
                ); 
                //console.log(ArtMethod_invoke_replace);
                Interceptor.attach(addr_ArtMethod_invoke, {
                    onEnter: function (args) {
                    try {
                        //console.log("DexBase is :",DexBase);
                        //console.log(222);

                        return;


                    } catch (error) {
                        console.log(error);
                    }

                    }, onLeave: function (retval) {

                    }
                });

            }
        }
}


function initClassArr(base, size){
    if (PRINT_DEX_INDEX) {
        console.log("****** Dex: ", globalDexIndex, " ******");
    }

    classArr = [];

    if (PRINT_DEX_INFO) {
        console.log(" base:",base,"\tsize:",size.toString(16));
    }

    DexBase = base;
    DexSize = size;
    //dump_dex("init.dex");
    // console.log("DexBase:",hexdump(base));
    var string_ids_size = DexBase.add(0x38).readU32();
    var string_ids_off = DexBase.add(0x3c).readU32();

    if (PRINT_DEX_INFO) {
        console.log(" uint string_ids_size:",string_ids_size); //.toString(16)
        console.log(" uint string_ids_off:",string_ids_off);
    }

    var type_ids_size = ptr(DexBase).add(0x40).readU32();
    var type_ids_off = ptr(DexBase).add(0x44).readU32();

    if (PRINT_DEX_INFO) {
        console.log(" uint type_ids_size:",type_ids_size);
        console.log(" uint type_ids_off:",type_ids_off);
    }

    var class_idx = ptr(DexBase).add(0x60).readU32();
    var class_defs_off = ptr(DexBase).add(0x64).readU32();
    if (PRINT_DEX_INFO) {
        console.log(" uint class_idx:",class_idx);
        console.log(" uint class_defs_off:",class_defs_off);
    }

    // var offsetStrEnd = DexBase.add(type_ids_off);
    // 有些str会超出
    // console.log("offsetStrEnd:",offsetStrEnd);
    for(var i=0; i<class_idx; i++){
        var offsetClass = DexBase.add(class_defs_off+i*0x20);
        // console.log("offsetClass:",offsetClass);
        var type_idx = offsetClass.readU32();
        // console.log("type_idx:",type_idx);
        var descriptor_idx = DexBase.add(type_ids_off+type_idx*0x4).readU32();
        // console.log("descriptor_idx:",descriptor_idx);
        var offsetStr = DexBase.add(string_ids_off + descriptor_idx*4).readU32();
        // console.log("offsetStr:",offsetStr);
        if(offsetStr > size){
            console.log("offsetStr > size:",offsetStr,">",size);
            break;
        }
        var addrStr =  DexBase.add(offsetStr);
        // console.log("addrStr:", hexdump(addrStr));
        // console.log("addrStr.readU32:",);
        var classNameLen =  addrStr.readU8();
        if(classNameLen > 0x7f){
            //这里类名都没超过0x7F
            console.log("ClassName Len > 0x7f:",addrStr);
            var lebdtl = DecodeUnsignedLeb128(addrStr);
            addrStr = addrStr.add(lebdtl[1]);
        }else{
            addrStr = addrStr.add(1);
        }
        // console.log("addrStr:",addrStr);
        // 读utf16有错误
        // var str = addrStr.readUtf16String();
        var str = addrStr.readUtf8String();
        // console.log(i,":", str);
        // console.log(hexdump(addrStr));
        // break;
        str = str.replace(/L([^;]+);/,"$1").replace(/\//g,'.');
        //console.log(i,":",str);
        classArr.push(str);
    }
    if (PRINT_CLASSARR_LEN) {
        console.log("------classArr.length:",classArr.length,"------");
    }    
}

function hook_java(){
    console.log("--------------------Start Invoke:",new Date().getTime());

    for(var i=0; i<classArr.length; i++ ){
        //console.log("class:",classArr[i]);
        loadClassAndInvoke(classArr[i]);
    }    
    console.log("--------------------End Invoke:",new Date().getTime());
}


function InitdumpMethodName() {
    try {
        var className = globaCurClassName;
        if (className in globalStepClassNams) {
            console.log("Step class :", className);
        }
        var classResult = Java.use(className).class;
        if(!classResult) return;

        var methodArr = classResult.getDeclaredConstructors();
        methodArr = methodArr.concat(classResult.getDeclaredMethods());

        dumpMethodName = [];
        for(var i=0;i<methodArr.length;i++){
            var  methodName = methodArr[i].toString();
            dumpMethodName.push(methodName);
        } 
        if (PRINT_OTHER_INFO) {
            console.log("    Method Count:",methodArr.length);
        }
    } catch (error) { 
        console.log("InitdumpMethodName error:[",className,"]",error);
    }
}

function loadClassAndInvokeEx() {
    Java.perform(function(){
        try {
            var classResult = Java.use(className).class;
            if(!classResult) return;

            var methodArr = classResult.getDeclaredConstructors();
            methodArr = methodArr.concat(classResult.getDeclaredMethods());

            dumpMethodName = [];

            for(var i=0;i<methodArr.length;i++){
                var  methodName = methodArr[i].toString();

                //如果已经存进去了就跳过
                if(methodName in dumpMethodName){
                    continue;
                }
                // console.log("methodName:",methodName);
                // c++层调用
                if(ArtMethod_invoke_replace){
                    //每次都会报错,但是我还没找到更方便的
                    try{
                        dumpMethodName.push(methodName);
                        // console.log("getArtMethod:", hexdump(ptr(methodArr[i].getArtMethod())));

                        //console.log("invoking Class " + " :" + classArr[globalClassCount] + " ~" 
                          //  + globalFunCount + ":" + methodName);

                        //ArtMethod_invoke_replace(ptr(methodArr[i].getArtMethod()), ptr(0), ptr(0), 6, invokeSize, invokeStr);
                        console.log("invok finished!");
                    } catch(error){
                        console.log("invok Error!");
                        // console.log("ArtMethod_invoke error:[",className,"]",error);
                    }
                }
            }
        } catch (error) { 
            console.log("loadClassAndInvoke error:[",className,"]",error);
        }
    });
}

[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

最后于 2020-8-1 17:13 被从未沦陷编辑 ,原因:
上传的附件:
收藏
免费 0
支持
分享
最新回复 (4)
雪    币: 10837
活跃值: (4462)
能力值: ( LV12,RANK:404 )
在线值:
发帖
回帖
粉丝
2
scandex这个方法比较耗时吧?优化下?
https://github.com/frida/frida/issues/113
https://github.com/frida/frida/issues/752
2020-7-31 17:29
1
雪    币: 1777
活跃值: (995)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
堂前燕 scandex这个方法比较耗时吧?优化下? https://github.com/frida/frida/issues/113 https://github.com/frida/frida/iss ...

谢谢大佬,我重新修改了一下,现在不会报

Failed to load script: timeout was reached

这个错误了,但是大多数app,运行这个脚本一会儿就会进程终止,只有少数的运行完脚本进程不会自动退出

2020-8-1 16:25
1
雪    币: 1777
活跃值: (995)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
2020-8-3 09:26
0
雪    币:
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
5
2020-12-2 11:38
0
游客
登录 | 注册 方可回帖
返回
//