首页
社区
课程
招聘
[原创]Frida和Xposed打印init_array的字符串解密函数
发表于: 2020-11-16 15:02 7205

[原创]Frida和Xposed打印init_array的字符串解密函数

2020-11-16 15:02
7205

这是2W班8月份的练习题第一题。题目要求是
ollvm针对加密字符串的解密都是在位于init_array节当中的函数。请编写Xposed插件,完成对测试apk中位于init_array节中的函数的hook,并获取对应的解密后的字符串。

这题还是需要查看源码,主要是so文件加载,这方面的文章网上还是蛮多的。根据源码可以找到系统是什么时候调用,接下来就是hook验证流程了。

有壳,frida脚本整体dump即可

查看Shell函数,静态注册的

这里就是取off_1B004的5个长度进行比较

先手动计算一下 ^= 0xFCu 得到 [99,104,101,99,107] = check

验证正确,开始写xposed

由于ollvm字符串混淆的函数名开头都是.datadiv_decode,所以可以先hook以这个函数开头的数据

这里虽然hook了,但是并没有打印日志,应该是hook之前就运行了。看看loadLibrary

java层中loadLibrary最终调用了nativeLoad

进入art可以找到do_dlopen,网上也有比较多关于do_dlopen的文章

我们要hook的init_array就在dlopen的时候通过do_dlopen->call_constructors->call_array->call_function就已经运行了。这个流程走完后,loadLibrary才算作结束,所以我们再hook init_array中的函数的时候已经不会再次运行了。

接下来尝试hook linker 中的call_xxx相关函数

使用xposed dlopen linker并没有取到模块,由于并不熟悉xposed,所以这里首先使用frida验证猜想,环境是pixel 8.0

使用frida hook linker模块的几个call_xx函数都正常,这里过滤下call_function的typename为function就是init_array中的函数,可以在它运行前hook它

可以看到0xcbf0b1b9就是.datadiv_decode9080531325931451386字符串解密函数,接下来打印对比

这里输出结果和加密函数datadiv_decode9080531325931451386对应上了,流程是走通了,然后就是在xposed中实现

Xposed环境是n5 6.0

Xposed使用dlopen和dlsym无法获取非导出函数call_constructors。所以这里ida打开so文件,获取函数偏移自己计算,这里是thumb模式,所以需要+1,这里也可以找枚举符号表的代码,就偷个懒写死了

结果hook没反应,这时候frida和xposed一起使用,看看差别是什么

可以看出地址不一样,这时候查看dlopen源码发现是重新加载了linker模块,所以导致不一样。而frida是直接查找现有模块的地址。xposed也可以根据maps文件来查找。不主动加载看看能不能hook到。

由于linker每次加载地址并没有变化,所以这里先写死看看能不能Hook住

思路是行的通,这边new_call_constructors 有hook到,但是可能参数问题,导致程序崩溃

之后尝试hook call_fucntion正常运行,先不管call_constructors

接下来就是查看maps文件找出linker和libnative-lib.so的地址,然后打印出函数运行前后加密字符串的变化

这里需要注意xposed加载hook的so文件时机不能在libnative-lib.so之后,我这边最开始就加载了

就是网上抄抄代码处理maps和打印, 对c++开发方面了解很浅

打印的结果

将结果放到010中查看

和frida实现的效果一样

 
public boolean check(String content) {
    if (Shell(content)) {
        return true;
    }
    return false;
}
 
public native boolean Shell(Object obj);
public boolean check(String content) {
    if (Shell(content)) {
        return true;
    }
    return false;
}
 
public native boolean Shell(Object obj);
bool __fastcall sub_87C4(const char *a1)
{
  s = (char *)a1;
  v2 = (unsigned __int8 *)off_1B004;
 
    if ( strlen(s) < 6 )
      v4 = (unsigned __int8)*s == *v2
        && (unsigned __int8)s[1] == v2[1]
        && (unsigned __int8)s[2] == v2[2]
        && (unsigned __int8)s[3] == v2[3]
        && (unsigned __int8)s[4] == v2[4];
...
bool __fastcall sub_87C4(const char *a1)
{
  s = (char *)a1;
  v2 = (unsigned __int8 *)off_1B004;
 
    if ( strlen(s) < 6 )
      v4 = (unsigned __int8)*s == *v2
        && (unsigned __int8)s[1] == v2[1]
        && (unsigned __int8)s[2] == v2[2]
        && (unsigned __int8)s[3] == v2[3]
        && (unsigned __int8)s[4] == v2[4];
...
.data:0001B004 off_1B004       DCD byte_1B008          ; DATA XREF: sub_876C+16o
.data:0001B004                                         ; sub_876C+18r ...
.data:0001B008 ; _BYTE byte_1B008[8]
.data:0001B008 byte_1B008      DCB 0x9F, 0x94, 0x99, 0x9F, 0x97, 0xFC, 0, 0
.data:0001B004 off_1B004       DCD byte_1B008          ; DATA XREF: sub_876C+16o
.data:0001B004                                         ; sub_876C+18r ...
.data:0001B008 ; _BYTE byte_1B008[8]
.data:0001B008 byte_1B008      DCB 0x9F, 0x94, 0x99, 0x9F, 0x97, 0xFC, 0, 0
 
//hook .datadiv_decode9080531325931451386
void *(*old_datadiv_decode)() = nullptr;
void *new_datadiv_decode() {
    __android_log_print(4, "hookso", "new_datadiv_decode onEnter");
    void *result = old_datadiv_decode();
    __android_log_print(4, "hookso", "new_datadiv_decode onLeave");
    return result;
}
 
void starthookInitArray() {
    void *libchandle = dlopen("libnative-lib.so", RTLD_NOW);
    __android_log_print(4, "hookso", "libchandle->0x%x",libchandle);
    void *datadiv_decode_addr = dlsym(libchandle, ".datadiv_decode9080531325931451386");
    __android_log_print(4, "hookso", "datadiv_decode_addr->0x%x",datadiv_decode_addr);
    if (registerInlineHook((uint32_t) datadiv_decode_addr, (uint32_t) new_datadiv_decode,
                           (uint32_t **) &old_datadiv_decode) !=
        ELE7EN_OK) {
        return;
    }
    if (inlineHook((uint32_t) datadiv_decode_addr) == ELE7EN_OK) {
        __android_log_print(4, "hookso", "hook native-lib.so->datadiv_decode9080531325931451386 success!");
        //return -1;
    }
}
//hook .datadiv_decode9080531325931451386
void *(*old_datadiv_decode)() = nullptr;
void *new_datadiv_decode() {
    __android_log_print(4, "hookso", "new_datadiv_decode onEnter");
    void *result = old_datadiv_decode();
    __android_log_print(4, "hookso", "new_datadiv_decode onLeave");
    return result;
}
 
void starthookInitArray() {
    void *libchandle = dlopen("libnative-lib.so", RTLD_NOW);
    __android_log_print(4, "hookso", "libchandle->0x%x",libchandle);
    void *datadiv_decode_addr = dlsym(libchandle, ".datadiv_decode9080531325931451386");
    __android_log_print(4, "hookso", "datadiv_decode_addr->0x%x",datadiv_decode_addr);
    if (registerInlineHook((uint32_t) datadiv_decode_addr, (uint32_t) new_datadiv_decode,
                           (uint32_t **) &old_datadiv_decode) !=
        ELE7EN_OK) {
        return;
    }
    if (inlineHook((uint32_t) datadiv_decode_addr) == ELE7EN_OK) {
        __android_log_print(4, "hookso", "hook native-lib.so->datadiv_decode9080531325931451386 success!");
        //return -1;
    }
}
 
 
 
 
 
Interceptor.attach(addr_call_function_args, {
    onEnter : function(args){
        var typename = args[0].readCString();
        var soname = args[2].readCString();
        if(typename == "function" && soname.indexOf("libnative-lib.so") > -1){
            //这里是init_array
            var funcaddr = args[1];
            console.log("addr_call_function_args onEnter->",funcaddr);
            Interceptor.attach(funcaddr, {
                onEnter : function(args){
                    console.log("call ", funcaddr," onEnter->");
                },
                onLeave: function(retval){
                    console.log("call ", funcaddr," onLeave->");
                }
            });
        }
    },
    onLeave: function(retval){
        // console.log("addr_call_function_args onLeave->");
    }
});
Interceptor.attach(addr_call_function_args, {
    onEnter : function(args){
        var typename = args[0].readCString();
        var soname = args[2].readCString();
        if(typename == "function" && soname.indexOf("libnative-lib.so") > -1){
            //这里是init_array
            var funcaddr = args[1];
            console.log("addr_call_function_args onEnter->",funcaddr);
            Interceptor.attach(funcaddr, {
                onEnter : function(args){
                    console.log("call ", funcaddr," onEnter->");
                },
                onLeave: function(retval){
                    console.log("call ", funcaddr," onLeave->");
                }
            });
        }
    },
    onLeave: function(retval){
        // console.log("addr_call_function_args onLeave->");
    }
});
android_dlopen_ext: /data/app/com.kanxue.hookinit_array-ePb0iNQ5c_WaWNJ8D3IHsw==/lib/arm/libnative-lib.so
addr_call_function_args onEnter-> 0xcbf0b1b9
call  0xcbf0b1b9  onEnter->     //.datadiv_decode9080531325931451386
call  0xcbf0b1b9  onLeave->
addr_call_function_args onEnter-> 0xcbf0a76d
call  0xcbf0a76d  onEnter->     //sub_876C
call  0xcbf0a76d  onLeave->
libnative-> [object Object]
libnative-> 0xcbf02000
datadiv_decode_addr-> 0xcbf0b1b9
android_dlopen_ext: /data/app/com.kanxue.hookinit_array-ePb0iNQ5c_WaWNJ8D3IHsw==/lib/arm/libnative-lib.so
addr_call_function_args onEnter-> 0xcbf0b1b9
call  0xcbf0b1b9  onEnter->     //.datadiv_decode9080531325931451386
call  0xcbf0b1b9  onLeave->
addr_call_function_args onEnter-> 0xcbf0a76d
call  0xcbf0a76d  onEnter->     //sub_876C
call  0xcbf0a76d  onLeave->
libnative-> [object Object]
libnative-> 0xcbf02000
datadiv_decode_addr-> 0xcbf0b1b9
Interceptor.attach(addr_call_function_args, {
    onEnter : function(args){
        var typename = args[0].readCString();
        var soname = args[2].readCString();
        if(typename == "function" && soname.indexOf("libnative-lib.so") > -1){
            //这里是init_array
            var funcaddr = args[1];
            console.log("addr_call_function_args onEnter->",funcaddr);
            console.log("before function->", g_start_byte.readByteArray(g_byte_len));
            this.printafter = true;
        }
    },
    onLeave: function(retval){
        console.log("after function->", g_start_byte.readByteArray(g_byte_len));
        var bs =  g_start_byte.readByteArray(g_byte_len);
        var start = -1;
        var preu8 = 0;
        for(var i=0; i<g_byte_len; i++){
            var valu8 =  g_start_byte.add(i).readU8();
            if(valu8 == 0){
                if(preu8 != 0){
                    console.log("so addr[0x"+(g_start_byte.add(start+1) - g_libnative.base).toString(16)+"]->",g_start_byte.add(start+1).readCString());
                }
                start = i;
            }
            preu8 = valu8;
        }
    }
});
 
Interceptor.attach(func_call_constructors, {
    onEnter : function(args){
        var soname = args[0].readCString();
        if( soname.indexOf("libnative-lib.so") > -1){
            //这时候就能通过findModuleByName查找到我们需要的so
            var libnative = Process.findModuleByName("libnative-lib.so");
            g_libnative = libnative;
            g_start_byte = g_libnative.base.add(0x1B008);
            g_byte_len =  0x1B0C0 - 0x1B008;
            console.log("func_call_constructors onEnter->",soname,g_libnative.base );
        }
    },
    onLeave: function(retval){
        // console.log("func_call_constructors onLeave->");
    }
});
Interceptor.attach(addr_call_function_args, {
    onEnter : function(args){
        var typename = args[0].readCString();
        var soname = args[2].readCString();
        if(typename == "function" && soname.indexOf("libnative-lib.so") > -1){
            //这里是init_array
            var funcaddr = args[1];
            console.log("addr_call_function_args onEnter->",funcaddr);
            console.log("before function->", g_start_byte.readByteArray(g_byte_len));
            this.printafter = true;
        }
    },
    onLeave: function(retval){
        console.log("after function->", g_start_byte.readByteArray(g_byte_len));
        var bs =  g_start_byte.readByteArray(g_byte_len);
        var start = -1;
        var preu8 = 0;
        for(var i=0; i<g_byte_len; i++){
            var valu8 =  g_start_byte.add(i).readU8();
            if(valu8 == 0){
                if(preu8 != 0){
                    console.log("so addr[0x"+(g_start_byte.add(start+1) - g_libnative.base).toString(16)+"]->",g_start_byte.add(start+1).readCString());
                }
                start = i;
            }
            preu8 = valu8;
        }
    }
});
 
Interceptor.attach(func_call_constructors, {

[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)

上传的附件:
收藏
免费 3
支持
分享
最新回复 (4)
雪    币: 754
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
2
addr_call_function_args 这个究竟是一个什么东西呢?不像是内置函数,感觉是一个自定义函数,但没有放出内容来
2023-2-28 18:32
0
雪    币: 116
活跃值: (1012)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
_thouger addr_call_function_args 这个究竟是一个什么东西呢?不像是内置函数,感觉是一个自定义函数,但没有放出内容来
看样子应该是linker中的一个函数
2023-2-28 20:42
0
雪    币: 754
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
4
万里星河 看样子应该是linker中的一个函数
我后面去安卓源码那里找了一下,是so调用链里面用到一个call_function函数,安卓8里有,10没有了,然后addr_call_function_args 这个变量应该是找到这个函数的相对地址了
2023-3-2 15:03
0
雪    币: 197
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
5
学习
2023-3-2 21:44
0
游客
登录 | 注册 方可回帖
返回
//