首页
论坛
课程
招聘
[原创]基于inlinehook免重打包实现持久化NativeHook
2020-9-4 21:44 5299

[原创]基于inlinehook免重打包实现持久化NativeHook

2020-9-4 21:44
5299

两个主角函数:

目的:

通过这两个函数,以及inlinehook我们可以实现root下不修改smali,不重打包完成持久化native hook

实现原理(arm32):

众所周知,System.loadLibrary()可以根据名称加载/data/app/com.xxx/lib/arm/目录下的so,而inlinehook也是通过加载so来动态修改原来的汇编代码,正常使用的话我们考虑修改smali代码加上一句System.loadLibrary()来实现自定义so的加载,但是我们不正常!所以我们想着能不能不修改smali完成加载
我们使用inlinehook编译一个so并把名称改为他原来的so的名称,把他原来的so改个名字,由我们编译的so来加载,嗯 。。。这就是本文的大概原理

需要处理的问题:

(这里涉及了两个so,统一一下名称便于后文描述,原app的so称为 '原so' ,我们用inlinehook生成的so称为 '新so' )

 

1.替换以后我们需要知道由系统调用的dlopen获得的 新so 的handle

 

2.替换以后原本的函数不管是静态注册还是动态注册的必然在新so里面是找不到的

解决办法:

1.最开始想尝试使用frida去实践一下想法

  • ①hook android_dlopen_ext
  • ②第一个参数路径包含 新so,记录handle
  • ③第一个参数路径包含 原so,拦截dlsym()替换第一个参数为上handle

发现死活不行,想到可能是连续调用导致frida性能问题(欢迎大佬给我普及一下为什么),后面改用Module.findExportByName()返回的pointer直接去替换dlsym返回值,这就行了(没读过frida源码,但是这里看参数和结果似乎frida的这个api就是调用的dlsym返回)
然后后面又想着用inlinehook去实现
但是系统连新so都还没加载进去,谈何hook,emmm
最后想着我在调用一次dlopen加载新so不就行了么……

 

2.我们需要稍微了解一下他为什么调用不起来
调用细节看图
其实注意的就是刚才说的dlopen返回的handle,dlsym传递的两个参数,第一个就是dlopen返回的handle,第二个是我们需要调用的函数符号
这个时候使用inlinehook去hook一下这两个函数,在手动加载 原so 后,触发一下原so的Jni_onload(),再启动inlinehook当dlsym第一个参数是 新so 的dlopen handle时就替换为 原so 的handle

举例

我们这里就用最右(cn.xiaochuangkeji.tieba)来举例
替换以前

操作步骤
  • 把原来的libmarsxlog.so改名为libmarsxlogcp.so,
  • 然后编译出so,修改名称为libmarsxlog.so,并移动到该目录下
  • 启动查看日志

inlinehook替换函数前8字节(2条arm指令或者4条thumb指令)为跳转,而frida hook在这里是enter时候的参数自然是原来的,所以看起来是用了错误的handle加载function还不崩掉
替换以后

 

这里这个手机没有开全局调试 只有将就用frida hook看一下打印日志

1
2
3
4
5
6
7
8
9
10
11
12
13
function hookLog() {
    var isFirst = true
    Interceptor.attach(Module.findExportByName("liblog.so","__android_log_print"), {
        onEnter: function (args) {
            if(isFirst) {
                console.log("\n")
                isFirst = false
            }
            if(args[1].readCString().indexOf("ZZZ")!=-1)
                console.log(args[1].readCString()+"\t"+args[2].readCString()+"\t"+args[3]+"\t"+args[4]+"\t"+args[5])
        }
    });
}

这里__android_log_print是变长参数为了能展示全部参数,只好多填几个参数,各自眼神忽略把
替换参数

 

至于这里为什么dlopen头文件定义的两个参数,在这里为什么是三个参数,就是第二个参数才是路径,看汇编F5,同理dlsym
dlopen参数

 

对加壳的app可以使用这种方式来hook关键点
OpenCommon / OpenMemory
C实现,替换原so就能在启动时hook从而dumpdex,这种基于inlinehook的操作不像xp框架,frida之类的容易被反调试,这种操作基本上没有什么反调试,比较香

 

附源码 inlinehook
)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
#include <stdio.h>
#include <jni.h>
 
#include "../inlineHook/include/inlineHook.h"
#include <android/log.h>
 
#include <unistd.h>
#include <stdlib.h>
#include <dlfcn.h>
 
#define LOG_TAG "ZZZ"
#define LOGD(fmt, args...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG,fmt, ##args)
#define LOGE(fmt, args...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG,fmt, ##args)
 
//需要Hook的函数地址
unsigned int func_dlopen = NULL;
unsigned int func_dlsym = NULL;
 
//新so handle
void *p0;
//原so handle
void *p1;
int *env;
 
static unsigned long find_module_by_name(char *soName) {
    char filename[32];
    char cmdline[256];
    sprintf(filename, "/proc/%d/maps", getpid());
    LOGD("filename = %s", filename);
    FILE *fp = fopen(filename, "r");
    unsigned long revalue = 0;
    if (fp) {
        while (fgets(cmdline, 256, fp)) //逐行读取
        {
            if (strstr(cmdline, soName) && strstr(cmdline, "r-xp"))//筛选
            {
                LOGD("cmdline = %s", cmdline);
                char *str = strstr(cmdline, "-");
                if (str) {
                    *str = '\0';
                    char num[32];
                    sprintf(num, "0x%s", cmdline);
                    revalue = strtoul(num, NULL, 0);
                    LOGD("revalue = %lu", revalue);
                    return revalue;
                }
            }
            memset(cmdline, 0, 256); //清零
        }
        fclose(fp);
    }
    return 0L;
}
 
//原函数指针
void* (*old_func_dlopen)(const char* filename, int flags, const void* caller_addr,void* s) = NULL;
void* (*old_fun_dlsym)(void* /*handle*/, const char* /*symbol*/) = NULL;
 
void* new_func_dlopen(const char *filename, int flags, const void *caller_addr, void *s) {
    void* p = old_func_dlopen(filename,flags,caller_addr,s);
    LOGD("%p = __loader_dlopen('%s','%d','%p')",p,filename,flags,caller_addr);
    return p;
}
 
void* new_func_dlsym(void *handle, const char *symbol){
    if(handle == p0 && strstr(symbol,"JNI_OnLoad") == NULL){
        handle = p1;
        LOGD("change handle from %p to %p",p0,p1);
    }
    void* ret = old_fun_dlsym(handle,symbol);
    LOGD("%p = __loader_dlsym('%p','%s')",ret,handle,symbol);
    return ret;
}
 
jint JNICALL
JNI_OnLoad(JavaVM *vm, void *reserved) {
 
    LOGE("------------------- JNI_OnLoad -------------------");
 
    if (vm->GetEnv( (void**)&env, JNI_VERSION_1_6) == JNI_OK) {
        LOGD("GetEnv OK");
    }
 
    char *lib_name = const_cast<char *>("linker");
    unsigned int base = find_module_by_name(lib_name);
    LOGD("Find %s at 0x%x ", lib_name,base);
 
    //计算需要Hook的函数地址偏移 (baseAddress + offset + thumb ? 1 : 0)
    //这里的地址是pull出linker导出函数里面找的,不同系统版本不一样
    //这里使用的是Neux 6P 安卓9
    func_dlopen = base + 0x75A4+1;
    func_dlsym = base + 0x76F0+1;
 
    LOGE("------------------- InlineHook -------------------");
 
    //注册Hook信息
    registerInlineHook((uint32_t) func_dlopen, (uint32_t) new_func_dlopen, (uint32_t **) &old_func_dlopen)==ELE7EN_OK ?
    LOGD("Success Hook func_dlopen at 0x%x",func_dlopen):LOGE("Fail Hook func_dlopen at 0x%x",func_dlopen);
 
    registerInlineHook((uint32_t) func_dlsym, (uint32_t) new_func_dlsym, (uint32_t **) &old_fun_dlsym)==ELE7EN_OK ?
    LOGD("Success Hook func_dlsym at 0x%x",func_dlsym):LOGE("Fail Hook func_dlsym at 0x%x",func_dlsym);
 
    inlineHookAll();
 
    //新so
    p0 = dlopen("/data/data/cn.xiaochuankeji.tieba/lib/libmarsxlog.so", 0);
    LOGD("dlopen libmarsxlog.so handle = 0x%p",p0);
    //原so
    p1 = dlopen("/data/data/cn.xiaochuankeji.tieba/lib/libmarsxlogcp.so", 0);
    LOGD("dlopen libmarsxlogcp.so handle =  0x%p",p1);
 
    //拿到原so的JNI_OnLoad()地址
    void *p2 = dlsym(p1, "JNI_OnLoad");
    LOGD("called dlsym JNI_OnLoad 0x%p",p2);
    //手动调用原so的JNI_OnLoad()
    p2(vm,reserved);
    LOGE("-------------------  Function  -------------------");
 
    return JNI_VERSION_1_6;
}
总结
  • 这里既然可以通过dlsym让他调函数得到改变,所以这个可以当作一个hook思路?只要能修改dlsym就可以控制导出函数的调用
  • 这么看来基于PLT的hook似乎也能做点事情了

    hook思路?

  • 关于dlopen以及dlsym函数地址的获取,目前这里是用的基地址加偏移,或者是采用写一个函数只用于调用dlopen,这样再去hook这个函数拿到一个类似于dlopen的代理地址,算是比较通用

    代理这两个函数

  • 还有一个最通用的方法
    用typedef重定义一个dlopen,重新声明一个函数指针,并将这个函数指针指向dlopen并强转为重定义的dlopen

1
2
3
4
5
typedef int (*dlopen_tp)(const char* __filename, int __flag);
dlopen_tp my_dlopen = (dlopen_tp)dlopen;
 
func_dlopen = base + 0x2F00+1;
LOGD("DLOPEN = %p   -----   %p ",my_dlopen,func_dlopen);

my_dlopen = func_dlopen


[看雪官方]《安卓高级研修班》线下班,网课(12月)班开始同步招生!!

最后于 2020-10-8 10:18 被唱过阡陌编辑 ,原因: 更新 纠正错误
收藏
点赞3
打赏
分享
最新回复 (23)
雪    币: 116
活跃值: 活跃值 (369)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
唱过阡陌 活跃值 2020-9-6 10:20
2
0
typedef int (*dlopen_tp)(const char* __filename, int __flag);
dlopen_tp my_dlopen = (dlopen_tp)dlopen;

    func_dlopen = base + 0x2F00+1;
    func_dlsym = base + 0x2FB8+1;

    LOGD("DLOPEN = %p   ?   %p  %p",my_dlopen,func_dlopen,func_dlsym);

解决了上面的问题  这样会得到一个和dlopen地址(my_dlopen)
雪    币: 804
活跃值: 活跃值 (318)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
lhxdiao 活跃值 2020-9-7 00:39
3
0
以前做了一个一键生成so、dll劫持源码的小工具,对这种可以说非常有用。
缺点就是 有的so自带JNI_OnLoad时 一键链接Java层所有的native函数,这个部分支持依然有点问题,需要用hook去直接hook register native,然后一个一个 链接到自己的函数上,偷懒没做。
雪    币: 5664
活跃值: 活跃值 (1911)
能力值: ( LV7,RANK:108 )
在线值:
发帖
回帖
粉丝
neilwu 活跃值 2020-9-7 10:59
4
0
感谢分享 之前用inject感觉也挺方便的 
雪    币: 6424
活跃值: 活跃值 (230)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
tDasm 活跃值 2020-9-7 15:35
5
0
“我们使用inlinehook编译一个so并把名称改为他原来的so的名称,把他原来的so改个名字,由我们编译的so来加载.”
不重新打包,你怎么替换/data/app/com.xxx/lib/目录下的so?难道在root下使用copy来替换?
雪    币: 86
活跃值: 活跃值 (42)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
Lcing 活跃值 2020-9-7 15:50
6
0
都root了还用inlineHook实乃不明智之举。
雪    币: 116
活跃值: 活跃值 (369)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
唱过阡陌 活跃值 2020-9-7 16:11
7
0
tDasm “我们使用inlinehook编译一个so并把名称改为他原来的so的名称,把他原来的so改个名字,由我们编译的so来加载.” 不重新打包,你怎么替换/data/app/com.xxx/lib/目录下 ...

adb push xxx.so /data/app/com.xxx/lib/arm/

最后于 2020-9-7 16:15 被唱过阡陌编辑 ,原因:
雪    币: 6424
活跃值: 活跃值 (230)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
tDasm 活跃值 2020-9-7 16:31
8
0
唱过阡陌 tDasm “我们使用inlinehook编译一个so并把名称改为他原来的so的名称,把他原来的so改个名字,由我们编译的so来加载.” 不重新打包,你怎么替换 ...
root下使用copy来替换,猜对了
雪    币: 1
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
云天逵 活跃值 2020-9-8 10:17
9
0
牛皮牛皮
雪    币: 7
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
Himeko 活跃值 2020-9-18 16:33
10
0
dlopen地址自动获取其实有更高明的手段,比如vapp里用的那玩意
或者我之前写的方式www.52pojie.cn/thread-1226153-1-1.html
雪    币: 7
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
Himeko 活跃值 2020-9-18 16:35
11
0
知道windos有dll代理,也想了想应该linux的也能代理吧,但是确实没想到原来替换个handle就可以用了
雪    币:
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
wx_havenow 活跃值 2020-9-18 21:14
12
0
这边试了下,没成功,有两个疑问:
1、"手动加载 原so 后,触发一下原so的Jni_onload()",这个没太明白
程序启动,应该是runtime 先dloepn libmarsxlog.so,在进入JNI_OnLoad函数,此时在JNI_OnLoad函数中dlopen libmarsxlogcp.so,只是获取了libmarsxlogcp.so的handle
System.loadLibrary(libName)
->JavaVMExt.loadNativieLibrary:
     ->dlopen
     ->JNI_OnLoad
2、下面的代码仅仅打印下吗
 //手动调用原so的JNI_OnLoad()
    void *p2 = dlsym(p1, "JNI_OnLoad");
    LOGD("called dlsym JNI_OnLoad 0x%p",p2);
雪    币: 116
活跃值: 活跃值 (369)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
唱过阡陌 活跃值 2020-9-19 08:46
13
0
wx_havenow 这边试了下,没成功,有两个疑问: 1、"手动加载 原so 后,触发一下原so的Jni_onload()",这个没太明白 程序启动,应该是runtime 先dloepn libm ...

第一个问题:

LoadNativeLibrary调用了android_dlopen_ext()和dlsym(),并由dlsym()调用了JNI_Onload(),所以我们手动dlopen打开一个so得手动去调用dlsym(),来触发他的JNI_Onload(),具体可以参见另一篇文章:(https://www.jianshu.com/p/5252b62aa9d2



第二个问题:

void *p2 = dlsym(p1, "JNI_OnLoad"); //就是上述我们说的要手动调用他的JNI_Onload()

LOGD("called dlsym JNI_OnLoad 0x%p",p2); //这里只是打印看一下调用情况

补充:

至于试了没有成功,可能不是这个问题,举例说的话,这种方式调用不是什么情况下都能成功的,比如Unity游戏中libil2cpp.so,具体也没研究(欢迎大佬来补充),但是众所周知这个so哪怕是改了一个字节他都会报错的,so里面做了其他处理吧,一般情况替换工具so是没问题的,建议动态用frida先跑通了在尝试inlinehook


雪    币:
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
wx_havenow 活跃值 2020-9-19 22:46
14
0
感觉这个方法确实不是什么情况下都能成功,我这边失败的原因暂时没找到。
我看了下打印的日志,我这边的app,老so的部分jni方法确实是有被dlsym,老so的jni方法为什么会被dlsym,而且只是部分被dlsym,具体的原因还有待验证,有可能是反射机制,java层调用的时候才会去dlsym

作者说的  “所以我们手动dlopen打开一个so得手动去调用dlsym(),来触发他的JNI_Onload()”,个人觉得是有问题的:
libdl.cpp --->dlsym() //加载jni_onload() 
对于这个一个流程的个人觉得应该是在libdl.cpp中先dlysm了jni_onload在去调用jni_onload

本身dlsym仅仅是获取jni_onload这个这个函数的handle
如果要调用,应该是  p2(vm,  reserved);
雪    币:
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
wx_havenow 活跃值 2020-9-19 22:54
15
0
这边搜索了下代码 JavaVMExt::LoadNativeLibrary,楼主写的 “所以我们手动dlopen打开一个so得手动去调用dlsym(),来触发他的JNI_Onload()” 应该是有问题的

JavaVMExt::LoadNativeLibrary
{
void* sym;  
 sym = library->FindSymbol("JNI_OnLoad", nullptr);  
  if (sym == nullptr) {  
    VLOG(jni) << "[No JNI_OnLoad found in \"" << path << "\"]";  
    was_successful = true;  
  } else {  
    // Call JNI_OnLoad.  We have to override the current class  
    // loader, which will always be "null" since the stuff at the  
    // top of the stack is around Runtime.loadLibrary().  (See  
    // the comments in the JNI FindClass function.)  
    ScopedLocalRef<jobject> old_class_loader(env, env->NewLocalRef(self->GetClassLoaderOverride()));  
    self->SetClassLoaderOverride(class_loader);  
   
    VLOG(jni) << "[Calling JNI_OnLoad in \"" << path << "\"]";  
    typedef int (*JNI_OnLoadFn)(JavaVM*, void*);  
    JNI_OnLoadFn jni_on_load = reinterpret_cast<JNI_OnLoadFn>(sym);  
    int version = (*jni_on_load)(this, nullptr);  
}

注意关键点:
sym = library->FindSymbol("JNI_OnLoad", nullptr);  //这里应该是dlsym JNI_OnLoad函数
    JNI_OnLoadFn jni_on_load = reinterpret_cast<JNI_OnLoadFn>(sym);  
    int version = (*jni_on_load)(this, nullptr);  //这里是根据函数地址做函数调用,这个调用就会进入so的JNI_OnLoad

雪    币:
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
wx_havenow 活跃值 2020-9-19 23:07
16
0

猜测失败的原因:
老的so里面函数dlsym应该是都会成功的,但是调用可以会有问题
vm是唯一的,但是env是线程相关的,如果JNI_OnLoad函数里面用到了env,可能会出问题

最后于 2020-9-20 21:38 被wx_havenow编辑 ,原因:
雪    币: 116
活跃值: 活跃值 (369)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
唱过阡陌 活跃值 2020-9-20 20:39
17
0
wx_havenow 猜测失败的原因:1、老的so里面部分函数dlsym失败;不确定用registerNative注册的函数和直接用Java_com_xxxx映射的函数 dlsym有没有区别2、vm是唯一的,但是env是线 ...
大佬指出的是,我刚才重新看了一下源码,文章这里确实是写错了 ,压根就没有调用jni_onload   /xk
是在调用FindSymbol()拿到JNI_Onload地址之后,做了一次函数的调用
```
JNI_OnLoadFn jni_on_load = reinterpret_cast<JNI_OnLoadFn>(sym);
int version = (*jni_on_load)(this, nullptr);
```
实际操作中不管是动态注册还是静态注册的函数dlsym只会调用一次
这里的this,都是一个同一个javaVM,但是函数里用到的env确实可能拿到不一样的env导致出问题
要真是线程相关的问题还不好处理

可以附一下报错嘛,大家一起找问题
雪    币: 116
活跃值: 活跃值 (369)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
唱过阡陌 活跃值 2020-9-20 20:48
18
0
还有一个小问题,在自己写的小demo里面,java层的点击事件触发一个静态注册的native函数,hook dlsym的时候发现其实注册函数只是被调用了一次,即使后面再点击按钮不会再出发dlsym获取函数地址,可能是某种缓存机制?就是说要想hook到注册函数的调用时机得早,在他调用之后你再去改返回值其实也就不生效了,反正他也不会调用了 
雪    币:
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
wx_havenow 活跃值 2020-9-20 21:47
19
0
我这边确认过了:
java端调用System.loadLibrary()后,
1、dlopen so
2、dlsym so中的JNI_OnLoad函数,并且调用JNI_OnLoad函数
3、如果JNI_OnLoad函数中有registerNatives,对本地方法进行注册,这里是不会调用dlsym的,因为是将函数指针保存起来了
4、如果有Java_com.xxxx_fun的jni函数,在调用jni函数时,vm会dlysm jni函数,获取到jni函数地址,在调用jni函数,只会dlsym一次,
因为获取到jni函数的地址后会存起来,就不用在dlsym了

你做hook,肯定是要在so load结束,才能hook成功
比如你的System.loadLibrary不是在static块里面,用一个按钮去触发,app启动了,hook jni函数肯定是失败的
雪    币:
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
wx_havenow 活跃值 2020-9-20 22:19
20
0
13030-13057/? E/inlinehook: new_func_dlsym from 0x7a45cdaf, glSamplerParameteriv
13030-13057/? D/inlinehook: 0x0 = __loader_dlsym('0x7a45cdaf','glSamplerParameteriv')
13030-13057/? E/inlinehook: new_func_dlsym from 0xc68f21d3, glSamplerParameteriv
13030-13057/? D/inlinehook: 0xe5ce11a0 = __loader_dlsym('0xc68f21d3','glSamplerParameteriv')
13030-13077/? I/Process: Sending signal. PID: 13030 SIG: 9
1635-3586/? D/ActivityManager: report kill process: killerPid is:13030, killedPid is:13030

只能可看到 Sending signal. PID: 13030 SIG: 9
雪    币: 1356
活跃值: 活跃值 (162)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
Amun 活跃值 2020-9-21 11:32
21
0

还是 lief 比较香

`pip install lief`

#!/usr/bin/env python3    
# Description    
# -----------    
# Hook the 'cos' function from the standard math library (libm)    
import lief    
libm = lief.parse("/usr/lib/libm.so.6")    
hook = lief.parse("hook")    
cos_symbol  = libm.get_symbol("cos")    
hook_symbol = hook.get_symbol("hook")    
code_segment = hook.segment_from_virtual_address(hook_symbol.value)    
segment_added = libm.add(code_segment)    
print("Hook inserted at VA: 0x{:06x}".format(segment_added.virtual_address))    
# Offset of the function 'hook' within the CODE segment    
hook_offset = hook_symbol.value - code_segment.virtual_address    
new_addr    = segment_added.virtual_address + hook_offset    
print(f"Change {cos_symbol.name}!{cos_symbol.value:x} -> {cos_symbol.name}!{new_addr:x}")    
cos_symbol.value = new_addr    
libm.write("libm.so.6")


雪    币: 2196
活跃值: 活跃值 (112)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
VNRKDOEA 活跃值 2020-9-21 12:06
22
0
tql
雪    币: 8
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
huangbof 活跃值 2天前
23
0
这个根本不必要这样搞啊,直接hook system.loadlibrary,然后先注入自己的inlinehook,再加载原有lib就可以了
雪    币: 116
活跃值: 活跃值 (369)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
唱过阡陌 活跃值 1天前
24
0
huangbof 这个根本不必要这样搞啊,直接hook system.loadlibrary,然后先注入自己的inlinehook,再加载原有lib就可以了
1.这篇文章是在不修改smali代码的情况下完成的,当你遇到指令抽取的时候可以绕过修改smali
2.发文就是想给大家分享思路,大家各抒己见就行,但是既然看到这篇文章,如果觉得思路有意思,咋不妨就去谈论一下这种思路的可行性,可能遇到的问题,听大佬的发言一起完善它,这才能有进步嘛
游客
登录 | 注册 方可回帖
返回