android 脱壳

fdex2

原理:1. 通过loadClass得到一个Class对象。2. 通过 getDex得到Dex对象。3.通过getBytes得到

  • frida版本构造原理:BaseDexClassLoader.findClass=>DexPathList.findClass=>DexFile.loadClassBinaryName=>DexFile.defineClass.最终会得到mCookie,而mCookie则指向Dex的首地址,即DexFile的指针。只要遍历mCookie即可。

var savepath = "/sdcard"

function savedexfile(dexfileptr){
    try{
        var dexfilebegin = ptr(dexfileptr).add(Process.pointerSize*1).readPointer();
        var dexfilesize = ptr(dexfileptr).add(Process.pointerSize*2).readU32();
        var dex = new File(savepath+"_"+dexfilesize+".dex","a");
        if(dex!=null){
            var content = ptr(dexfilebegin).readByteArray(dexfilesize);
            dex.write(content);
            dex.flush();
            dex.close();
            console.warn('[dump]dex'+savepath+"_"+dexfilesize+".dex")
   
        }
    }
    catch(e){

    }
}

function dump(){
    Java.perform(function(){
        var DexFileClass = Java.use('dalvik.system.DexFile')
        Java.choose('dalvik.system.DexFile',{
            onMatch:function(dexfile){
                var mCookie = dexfile.mCookie.value;
                var classlist = DexFileClass.getClassNameList(mCookie);
                classlist.forEach(function(classname){
                    console.log(dexfile.mFileName.value+"->"+classname)
                })
                console.log(mCookie.$className)
                var Array = Java.use('java.lang.reflect.Array');
                var size = Array.getLength(mCookie);
                var i=0;
                for(i=0;i<size;i++){
                    console.log(i+'->'+Array.getLength(mCookie,i))
                    var longvalue = Array.getLong(mCookie,i);
                    var dexfileptr = ptr(longvalue + "")
                    savedexfile(dexfileptr)

                }
            },
            onComplete:function(){ 
                console.warn('search DexFile over!')
            }
        })
    })
}
vmp的识别

vmp主要分2种形式,一种是数字壳,脱完壳之后对onCreate函数进行native化。另一种是onCreate函数中加载的是对各种相同签名的函数地址进行绑定。图中的A.V也是native函数,所以我们只能进行so层的逆向
对于这种vmp,我们可以hook RegisterNative函数对jni注册的函数进行查看。


1
2

当编译源码时,如果之前已经刷过源码,则只需要重新刷入system.img和system_other.img即可。下面的代码是通过frida来hook得到RegisterNative以及知道method_idx来得到索引。

var addrGetMethodNameByArtMethod = null;
var funcGetMethodNameByArtMethod = null;
var ArtMethodPrettyMethodaddr=null;

function readStdString(str) {
    const isTiny = (str.readU8() & 1) == 0;
    if (isTiny) {
        return str.add(1).readUtf8String();
    }
    return str.add(2 * Process.pointerSize).readPointer().readUtf8String();
}

//arm32
function callprettymethod(artmethodptr) {
    ArtMethodPrettyMethodaddr = Module.findExportByName("libart.so", "_ZN3art9ArtMethod12PrettyMethodEb");
    var ArtMethodPrettyMethodfunc = new NativeFunction(ArtMethodPrettyMethodaddr, "pointer", ["pointer", "pointer", "pointer"]);
    var strptr = Memory.alloc(64);
    var ArtMethodName = null;
    if (strptr != null) {
        ArtMethodPrettyMethodfunc(ptr(strptr), ptr(artmethodptr), ptr(1));
        ArtMethodName = readStdString(strptr);
        return ArtMethodName;
    }
    return null;

}


function hooklibart() {
    console.log("go into hooklibart," + "Process.arch:" + Process.arch);
    var module_libext = null;
    if (Process.arch === "arm64") {
        module_libext = Module.load("/data/app/fart64.so");
    } else if (Process.arch === "arm") {
        module_libext = Module.load("/data/app/fart.so");
    }
    if (module_libext != null) {
        addrGetMethodNameByArtMethod = module_libext.findExportByName("getMethodNameByArtMethod");
        funcGetMethodNameByArtMethod = new NativeFunction(addrGetMethodNameByArtMethod, "pointer", ["pointer", "pointer"]);

    }
    ArtMethodPrettyMethodaddr = Module.findExportByName("libart.so", "_ZN3art9ArtMethod12PrettyMethodEb");
    var libartmodule = Process.getModuleByName("libart.so");
    var symbols = libartmodule.enumerateExports();
    symbols.forEach(function (symbol) {
        var symbolname = symbol.name;
        if (symbolname != null) {
            if (symbolname == '_ZN3art9ArtMethod14RegisterNativeEPKvb') {
                console.log(symbol.name + "---" + symbol.address);
                Interceptor.attach(symbol.address, {
                    onEnter: function (args) {
                        this.artmethod = args[0];
                        //method1
                        //var methodname = callprettymethod(ptr(this.artmethod));
                        //method2
                        var methodnameptr = funcGetMethodNameByArtMethod(ptr(ArtMethodPrettyMethodaddr), ptr(this.artmethod));
                        var methodname = ptr(methodnameptr).readCString();
                        var address = args[1];
                        this.dex_method_index_ = ptr(this.artmethod).add(12).readU32();
                        console.log("go into _ZN3art9ArtMethod14RegisterNativeEPKvb---" + "artmethodptr:" + ptr(this.artmethod) + "---methodidx:" + this.dex_method_index_ + "--addr:" + address + "----name:" + methodname);
                    }, onLeave: function (retval) {

                    }
                })
            }

        }

    });
}

function main() {
    hooklibart();
}

setImmediate(main);

分析vmp的办法

jni trace
pip install jnitrace==3.0.3 指定安装的jnitrace为3.0.3
高级用法可以查看官网,比如正则匹配去trace

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容