这是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期)