沉淀两天,发发技术。主要是心情不好,懒得整活。
本篇深入一些些,到达native层(不过还是很简单)。
1 基础目标
本次书写目标是一个静态注册的Native APP。
2 native APP的搭建过程及基本配置
新建一个Project,模版选择Native C++:
一路向下,C++配置选择默认即可:
构建完后的Project结构如图所示,比起一般的APP只在src/main下多了一个cpp文件夹:
里面的native-lib.cpp就是我们编写native方法的地方,旁边的CMakeLists.txt就是用来配置此app文件的。
我们简单说一下默认配置里的两个:
project指示了编译后的so文件文件名,为lib[project].so(因为下面这个add_library用了这个projectname作为名字,很绕)。add_library设置了这个so文件会包含哪些cpp文件,便于在使用cpp文件过多的情况下管理。
3 讲讲native函数语法与约定
这个内容我在同系列“渗透测试从0开始”的“关于Native方法”里会小提一下(截止写下这段字的时间,我还没在公众号发布这篇,所以我会在这里也讲一讲,这也是方便不想看合集内其他文章的读者)。
首先,在Java中我们会引入so文件,然后声明要导出的函数(类似cpp中头文件的声明):
// 这里读取so文件,libname就是对应cmake文件里记录的project name
static { System.loadLibrary("reverse2"); }
public native String helloDog(String a,int b,int[] c); //这里声明要调用的方法
这里的导出方法名不是乱取的,在静态注册的情况下,需要与cpp文件中的对应函数名匹配。我们假设这个函数在包indi.augusttheodor.A下,则对应的cpp函数头为:
extern "C" JNIEXPORT jstring JNICALL
Java_indi_augusttheodor_A_helloDog
(
JNIEnv* env,
jobject, /* this */
jstring a, jint b, jintArray c
);
如果是动态注册呢,cpp的函数名就不需要遵循这种规则,对于CTF题目,自然是动态注册更有难度了。但是本篇我们不深入到动态注册中,就先不讲了。
4 码代码
由于上一节中已经讲了基础的Android Java代码书写,这一节中我们不再赘述。
依照我们上述所言,静态注册的native函数仍然是易于找到的,只是比上一节中的纯Java要稍微多一点步骤而已(指要打开IDA,哈哈),并且native函数仍然可被frida或unidbg直接调用。
如果需要在题目中增加难度,最简单的方式就是将flag藏在函数中间,避免挑战者使用钩子走捷径。比如:
extern "C" JNIEXPORT jstring JNICALL
Java_indi_augusttheodor_A_helloDog
(
JNIEnv* env, #JNIEnv 指针
jobject, /* this */ #作为成员函数被导入,自然会传入this
){
//在函数中算出flag
return env.newString("Hello~");
}
或者,可以在主函数中写一个复杂的跳转,而真正的flag由依照一定顺序调用分支函数得出。
extern "C" JNIEXPORT void JNICALL
Java_indi_augusttheodor_A_helloDog
(
JNIEnv* env, #JNIEnv 指针
jobject, /* this */ #作为成员函数被导入,自然会传入this
jstring a
){
for(int i=0;i<1;i++){
a=func_b(func_a(a));
}
func_c(a);
return;
}
写完之后不需要别的操作,照常build运行即可。
原文始发于微信公众号(重生之成为赛博女保安):来写点安卓逆向题吧②:babyNativeReverse
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论