8种机械键盘轴体对比
本人程序员,要买一个写代码的键盘,请问红轴和茶轴怎么选?
记一种直接进入jni-onload 和native方法的实现
巧入jni_onload
通常我们在调试Android的so的时候为了能进入jni_onload 需要am start 启动app,然后使用ida附加,在jdb附加。整个过程显得非常的麻烦。有些加固so 在init_array中设置了反调试,这个过程就变得更加的艰难。这个时候就可以利用自己写个 loader的办法加载这个so,直接加载jni_onload。在Android上,利用xposed 就可以实现就可以实现这个功能。
分析Android加载so的方法,看到就只有2种方式:System.loader 和 System.loadLibrary,我们hook他,让他先加载我们的so_loader。
注意:不能直接hook System.class中的load 和loadLibaray,看xposed作者说的使用Runtime.class。
可以看到 我们让目标so加载我们自己的hook.so,做到李代桃僵,让app人为自己加载的就是原始的so。接下来我们看看hook.so的实现:
被hook的app进程会先加载我们的hook.so,执行jni_onload方法。在jni_onload中我们利用dlopen 打开了原始的so。利用dlsym找到原始so的jni_onload。编译运行测试,我么可以发现app已经能正常运行,测试成功。有了这样的工具,我们可以跨过init_array中的反调试,避免每次am start 、jdb 转发的麻烦过程。快速的进去调试so的jni_onload。
快速进入native方法。
现在是个app都会利用RegisterNatives动态注册一大堆函数。之前可以通过替换env结构体中的RegisterNative 函数,具体参考TomaksKing的文章。但是发现registernatives 最后调用的还是dvmUseJniBridge。
我们hook这个地方就能拿到一个method结构体,和一个动态注册函数的地址。我们拿到method结构体就能得到方法的name。Method结构如下所示:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19struct Method {
ClassObject* clazz;
u4 accessFlags;
u2 methodIndex;
u2 registersSize;
u2 outsSize;
u2 insSize;
const char* name;
DexProto prototype;
const char* shorty;
const u2* insns;
int jniArgInfo;
DalvikBridgeFunc nativeFunc;
bool fastJni;
bool noRef;
bool shouldTrace;
const RegisterMap* registerMap;
bool inProfile;
}
hook 代码如下图所示:
hook的结果如图,可以看到注册的方法和对应的地址等信息:
这个时候如果我们过滤出想要调试的native方法只需要在注册的时候 休眠几秒。我们趁机附加调试并且在真实的Oncreate地方断点,这样继续执行后就会在断点地方断下来了。
如图所示:
先在sleep 结束地方断点,保证注册的是我们需要调试的函数。这个时候r6寄存器就是注册的函数地址。我们跳转过去断点,执行后就成功到达断点位置。
进入断点位置后:
总结
结合xposed 和inlinehook 可以简化我们调试过程,过掉一些初级的反调试。
利用动态注册的特性可以hook到注册函数,得到注册地址。