来写点安卓逆向题吧③:dynamicRegReverse

admin 2024年4月19日21:06:21评论8 views字数 2104阅读7分0秒阅读模式

本篇再深入一些,使用动态注册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}};

实际上的注册流程则是:

  1. Java处声明native函数,cpp处实现对应的函数

  2. 按照native函数的签名,在cpp处编写对应的JNINativeMethod数组(通常是这么写的,反正一定会写JNINativeMethod结构体)

  3. 书写JNI_Onload函数,使用数组注册native函数

3 混淆动态注册过程

最开始我想的是,能否直接混淆动态注册过程中记录两方函数之间关系的JNINativeMethod。

所以我们先来看看JNINativeMethod这个结构体的定义:

来写点安卓逆向题吧③:dynamicRegReverse

好吧,这个取名不是很具象。总而言之,name是函数在Java中对应的名字,signature则是对应的smali声明(输入输出),fnPtr则是指向cpp原函数的指针。

而众所周知(也许不是那么众所周知)结构体的声明在反汇编代码里是很容易识别的。比如我随便声明了一个JNINativeMethod的变量:

来写点安卓逆向题吧③:dynamicRegReverse

一大片连续偏移的指针就是结构体最明显的特征。

而且,最令人难以接受的事情是,这个特征是没法混淆的!!!由于本系列不探讨加壳或OLLVM这类的方法,所以笔者能倚靠的只有一双手- -。

如果结构体本身无法混淆,那么只能混淆结构体中存储的明文了。以下是几个我的思路。

3.1 混淆明文为函数

比如说,我们可以将结构体的值置为一个函数的返回值,最简单的例子如下:

来写点安卓逆向题吧③:dynamicRegReverse

相对应的上文中的反汇编代码,这次则会将mov ptr[a] offset string 变为call getJniName; mov ptr[a] eax:

来写点安卓逆向题吧③:dynamicRegReverse

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

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2024年4月19日21:06:21
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   来写点安卓逆向题吧③:dynamicRegReversehttps://cn-sec.com/archives/2671717.html

发表评论

匿名网友 填写信息