本篇再深入一些,使用动态注册native函数,顺便分析一下使用动态注册的so文件。
1 基础目标
写一个动态注册的Native APP。由于Java这边该讲的都在系列②里讲了,本篇就专注讲一下动态注册cpp的内容,由于不涉及到具体的实现细节,应该会比较短。
2 动态注册流程及特点说明
无论是逆向还是编写NativeAPP,我们首先要记住这一点:动态注册的dll一定会有一个导出函数JNI_Onload,同时所有动态注册的函数都将在这个函数中被注册。
这是动态注册native函数的最大弱点,也是我们出题时做手脚(或者你要说,加固)最方便的地方。
一个单刀直入的JNI_Onload注册过程会长这样:
JNIEXPORT int JNI_OnLoad(JavaVM *vm , void *r){
static const char* className = "indi/augusttheodor/reverse3/MainActivity"; //获取native函数所在的类
JNIEnv *env = nullptr;
int registerResult = vm->GetEnv( (void **) &env, JNI_VERSION_1_6 ); //获取env
jclass jc = env->FindClass(className);
env->RegisterNatives(jc, methods, sizeof(methods) / sizeof(JNINativeMethod));
return JNI_VERSION_1_6;
}
其中methods为一个结构体JNINativeMethod数组,比如:
const JNINativeMethod methods[]={
{"stringFromJNI", "(Ljava/lang/String;)Ljava/lang/String;",(void *)stringDynamic}
};
实际上的注册流程则是:
-
Java处声明native函数,cpp处实现对应的函数
-
按照native函数的签名,在cpp处编写对应的JNINativeMethod数组(通常是这么写的,反正一定会写JNINativeMethod结构体)
-
书写JNI_Onload函数,使用数组注册native函数
3 混淆动态注册过程
最开始我想的是,能否直接混淆动态注册过程中记录两方函数之间关系的JNINativeMethod。
所以我们先来看看JNINativeMethod这个结构体的定义:
好吧,这个取名不是很具象。总而言之,name是函数在Java中对应的名字,signature则是对应的smali声明(输入输出),fnPtr则是指向cpp原函数的指针。
而众所周知(也许不是那么众所周知)结构体的声明在反汇编代码里是很容易识别的。比如我随便声明了一个JNINativeMethod的变量:
这一大片连续偏移的指针就是结构体最明显的特征。
而且,最令人难以接受的事情是,这个特征是没法混淆的!!!由于本系列不探讨加壳或OLLVM这类的方法,所以笔者能倚靠的只有一双手- -。
如果结构体本身无法混淆,那么只能混淆结构体中存储的明文了。以下是几个我的思路。
3.1 混淆明文为函数
比如说,我们可以将结构体的值置为一个函数的返回值,最简单的例子如下:
相对应的上文中的反汇编代码,这次则会将mov ptr[a] offset string 变为call getJniName; mov ptr[a] eax:
3.2 使用密文结构体,然后封装解密和注册
从之前的JNI_Onload来看,最后注册native函数并用到JNINativeMethod的语句只有一句:
env->RegisterNatives(jc, methods, sizeof(methods) / sizeof(JNINativeMethod));
那不如直接封装走起?
void fakeRegisterNatives(clazz jc,JNINativeMethod* method,JNIEnv env,int size){
/*解密过程 do something with fake name*/
env.RegisterNatives(jc,method,size);
}
然后在外部使用fakeRegisterNatives代替RegisterNatives。
我的病应该是好了,不过正所谓伤筋动骨一百天,何况我第一天都坐上轮椅了,想好全估计得要上一段时间。这次住院给我最深的两个感触:1.止痛药真的非常非常有用,在医院那两天是我这周过的最无痛的两天;2.赚钱真的非常非常没用,我住院平均一天就要烧一千块,更不用说隔壁的重症患者,所以平常还是想吃点啥就吃点啥吧。
还有一个比较重要的消息。按照客户要求,我之后会给他们培训下安卓CTF(我会在培训结束后把材料修改为文章发出)。目前我倾向于选择网络上公开靶场中的题目用作教学,只是不知道哪些题目难度合适:是否有无native层的题目用于入门?有无较难的题目作为核心?如果读者心中有题目推荐,请不吝赐教在后台告知于我,万分感谢。
原文始发于微信公众号(重生之成为赛博女保安):来写点安卓逆向题吧③:dynamicRegReverse
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论