观前提示:
本文章仅供学习交流,切勿用于非法通途,如有侵犯贵司请及时联系删除
样本包名:Y24uaHNhLmFwcCAxLjMuMTI=
本文没有对混淆的代码和检测函数做下一步定位和验证
0x1 定位反调试所在的so
hook dlopen
函数
function hook_dlopen() {
Interceptor.attach(Module.findExportByName(null, "android_dlopen_ext"),
{
onEnter: function (args) {
var pathptr = args[0];
if (pathptr !== undefined && pathptr != null) {
LogPrint("android_dlopen_ext_addr onEnter "+ ptr(args[0]).readCString())
}
}
}
);
}
so都是是顺序加载,从命令行中当加载libxloader.so
之后,进程就崩溃了,可以猜测反调试点在libxloader.so
中
0x2 寻找检测函数所在位置
先hook JNI_OnLoad
function hook_dlopen(){
var android_dlopen_ext_addr = Module.findExportByName(null, "android_dlopen_ext")
Interceptor.attach(android_dlopen_ext_addr, {
onEnter: function(args){
LogPrint("android_dlopen_ext_addr onEnter "+ ptr(args[0]).readCString())
var so_name = ptr(args[0]).readCString()
if ( so_name.indexOf('libxloader.so')> -1){
this.hook = true;
}
}, onLeave:function(retval){
if (this.hook) {
var jniOnload = Module.findExportByName("libxloader.so", "JNI_OnLoad");
LogPrint("jniOnload " +jniOnload)
Interceptor.attach(jniOnload, {
onEnter: function (args) {
LogPrint("Enter libxloader JNI OnLoad");
},
onLeave: function (retval) {
LogPrint("After libxloader JNI OnLoad");
}
});
}
}
})
}
发现执行还没有进入JNI_OnLoad
进程就被kill
,检测函数比JNI_OnLoad
更早执行。
so中init函数执行顺序
.init_proc -> .init_array -> JNI_OnLoad
ida 打开so发现寻找.inti_array没有可疑函数,继续寻找.init_proc
,发现有大量代码,不过都是被混淆过的。hook open
和 pthread_create
函数看看
hook_pthread
function hook_pthread(){
var pthread_create_addr = null;
var symbols = Process.findModuleByName("libc.so").enumerateSymbols();
for(var i = 0;i<symbols.length;i++){
var symbol = symbols[i].name;
if(symbol.indexOf("pthread_create")>=0){
pthread_create_addr = symbols[i].address;
}
}
LogPrint("pthread_create_addr,"+pthread_create_addr);
Interceptor.attach(pthread_create_addr,{
onEnter:function(args){
var libxloader_addr = Process.findModuleByName("libxloader.so");
if (libxloader_addr){
LogPrint("pthread_create_addr args[0],args[1],args[2],args[3]:"+args[0]+" "+args[1]+" "+args[2]+" "+args[3]);
LogPrint("libxloader "+libxloader_addr.base) // 0x633d4 0x5f5d8 0x7963c
LogPrint('CCCryptorCreate called from:n' +
Thread.backtrace(this.context, Backtracer.ACCURATE)
.map(DebugSymbol.fromAddress).join('n') + 'n');
}
},onLeave:function(retval){
LogPrint("retval is:"+retval)
}
})
}
hook open
function libc_open(){
var libcmodule = Process.getModuleByName("libc.so");
var openaddr = libcmodule.getExportByName("open");
openaddr_target = Interceptor.attach(openaddr, {
onEnter: function (args) {
var filepath = ptr(args[0]).readCString();
LogPrint("open:" + filepath);
}, onLeave: function (retval) {
}
});
}
发现还没有创建线程,有读取maps文件,一般检测maps
也会检测status
文件,将正常maps
和status
都copy过来放到/sdcard/
目录下,将libc_open
函数改造下
function libc_open(){
const openPtr = Module.getExportByName('libc.so', 'open');
const open = new NativeFunction(openPtr, 'int', ['pointer', 'int']);
var readPtr = Module.findExportByName("libc.so", "read");
var read = new NativeFunction(readPtr, 'int', ['int', 'pointer', "int"]);
var fakePath = "/sdcard/2937_maps";
var fakePath3 = "/sdcard/2937_status";
openaddr_replace_target = openPtr;
Interceptor.replace(openPtr, new NativeCallback(function (pathnameptr, flag) {
var pathname = Memory.readUtf8String(pathnameptr);
LogPrint("open:"+pathname)
if (pathname.indexOf("maps") >= 0 || pathname.indexOf("status") >= 0) {
var temp = pathname.indexOf("maps") >= 0 ? 1 : 2;
switch (temp) {
case 1:
var filename = Memory.allocUtf8String(fakePath);
return open(filename, flag);
break;
case 2:
var filename = Memory.allocUtf8String(fakePath3);
return open(filename, flag);
break;
}
}
var fd = open(pathnameptr, flag);
// Thread.sleep(1)
return fd;
}, 'int', ['pointer', 'int']));
}
运行后app进程居然崩溃了...
猜测是不是 hook 的某个函数导致的,在JNI_OnLoad
函数执行前将所有hook的函数都释放掉,app居然正常启动了,在巧合下过掉了frida的检测.
function hook_dlopen(){
var android_dlopen_ext_addr = Module.findExportByName(null, "android_dlopen_ext")
Interceptor.attach(android_dlopen_ext_addr, {
onEnter: function(args){
LogPrint("android_dlopen_ext_addr onEnter "+ ptr(args[0]).readCString())
var so_name = ptr(args[0]).readCString()
if ( so_name.indexOf('libxloader.so')> -1){
this.hook = true;
}
}, onLeave:function(retval){
if (this.hook) {
var jniOnload = Module.findExportByName("libxloader.so", "JNI_OnLoad");
LogPrint("jniOnload " +jniOnload)
Interceptor.attach(jniOnload, {
onEnter: function (args) {
LogPrint("Enter libxloader JNI OnLoad");
if (openaddr_replace_target){
Interceptor.revert(openaddr_replace_target);
LogPrint("openaddr_replace_target Hook reverted.");
}
Interceptor.detachAll();
LogPrint("pthread_create Hook reverted.");
},
onLeave: function (retval) {
LogPrint("After libxloader JNI OnLoad");
}
});
}
}
})
}
在hook_pthread
中发现0x633d4
中有maps
和status
的检测逻辑,可以分析分析
0x3 案例总结
1.使用魔改的frida
2.hook dlopen
函数寻找关键so
3.寻找关键函数在so中的位置
4.hook pthread_create
函数是否能发现可以函数
5.hook open
函数是否打开了maps status 等文件
6.hook strstr
strcmp
等字符串操作函数,能发现一些可以字符串明文,验证推测
7.是否需要释放hook的函数
原文始发于微信公众号(逆向与采集):android|frida检测的通用处理逻辑
- 左青龙
- 微信扫一扫
- 右白虎
- 微信扫一扫
评论