Android JNI动态库逆向
技术咨询/指导服务
经常在一些地方看到类似于这样的介绍:一些重要的字段不要放在Java代码中,需要放在native。 但是事实上,并没有绝对的安全,即使是将数据放在native,我们也可以使用IDA等工具进行查看,对于未加密的常量字段数据,我们可以在.rodata
数据段直接看到数据内容,即使是通过插入花指令等方式使数据看着没那么容易理解,有经验的逆向者也可以通过代码阅读、调试动态库等方式了解原数据内容。
一、编译一个动态库
先写一个动态库,CMakeLists.txt
内容如下:
cmake_minimum_required(VERSION 3.6)
add_library(reversetest
SHARED
reverse.cpp)
find_library(
log-lib
log)
target_link_libraries(reversetest ${log-lib})
reverse.cpp
中的代码内容如下:
#include <jni.h>
#include <android/log.h>
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,"reservetest" ,__VA_ARGS__)
extern "C" JNIEXPORT void
JNICALL
Java_com_wsy_jnidemo_test_ReverseTest_reverseData(
JNIEnv
*env,
jclass) {
const char *content = "content";
LOGI("content is: %s", content);
}
extern "C" JNIEXPORT void
JNICALL
Java_com_wsy_jnidemo_test_ReverseTest_reverseJudge(
JNIEnv
*env,
jclass,
jint count
) {
if (count > 1000) {
LOGI("count is %d, count > 1000", count);
} else {
LOGI("count is %d, count <= 1000", count);
}
}
Java
调用:
public class ReverseTest {
static {
System.loadLibrary("reversetest");
}
public static native void reverseData();
public static native void reverseJudge(int count);
}
private void doReverseTest() {
ReverseTest.reverseData();
ReverseTest.reverseJudge(10000);
}
点击externalNativeBuildRelease
,将生成的动态库复制到jniLibs
目录下,运行。
输出日志如下,很正常:
二、修改动态库
首先我们需要了解的是,无论是exe、so、dll、txt、doc,还是其他格式的文件,它们都只是文件,都是二进制数据,只是生成和解析方式不同。
比如我们可以使用文本编辑器将txt
解析成我们能够理解的文本内容,也可以将我们输入的文本内容保存成txt
;我们可以使用Word将doc
解析成我们能够理解的内容,也可以将我们输入的内容保存成doc
…
对于so
文件,我们可以使用IDA Pro
进行解析、修改。
1. IDA界面简介
IDA Pro
在安装完成后,会分别有64位和32位的可执行文件。对于刚才生成的libreversetest.so
这个动态库文件,使用64位的程序打开,打开后界面如下:
2. 修改函数内容
修改常量字符串
在左边的函数表中,我们可以使用CTRL + F
寻找我们需要查看的函数:
双击函数名,可查看其汇编指令,再按F5
,得到反汇编后的C
代码:
双击右边的content
,即可跳转到其定义处:
这个时候我们可以使用IDA Pro
自带的编辑器修改其内容,也可以根据其偏移地址0x6E0
使用其他二进制编辑器修改,或者自己写个代码修改文件的内容。
这里选择用IDA
自带的功能修改:点击Edit
->Patch program
->Change bytes...
将其修改为61 - 67(也就是a-g):
确认后可以看到,这个字段的内容已经被我们成功修改了
但是这个时候并没有保存数据至原动态库中,我们点击Edit
->Patch program
->Apply patches to input file..
即可保存至原文件。
修改指令
双击另一个函数,看到以下源码:
这个动态库里的指令反汇编得到的代码和编写时的内容不是完全一致,但是不影响,表达的含义相同。
对于指令的修改,汇编视图会更友好,切换到汇编视图,内容如下:
我们知道,LT
代表less than
,GT
代表greater than
,GE
代表greater or equals
,只要我们将LT
修改为GE
即可进入判断的另一个分支:
选中这行指令,点击Edit
->Patch program
->Assemble...
,对于arm架构的动态库,我的电脑会报Sorry, this processor module doesn't support the assembler
,但是直接改数据是没问题的,修改指令为以下内容:
和刚才一样的操作,点击Apply patches to input file..
保存修改至原文件。
对于x86_64
的动态库,我的设备点击Edit
->Patch program
->Assemble...
是没问题的,所以这里也对x86_64
架构的动态库操作一遍:
原指令如下,我们将jl
修改为jge
即可进入另一个逻辑分支:
原指令:
修改后:
三、运行验证
刚才我们修改了一处常量字符串和一处判断指令,现在将修改好的arm64-v8a
的动态库放进工程对应目录,运行,结果如下:
四、如何加固
程序本身就是相当于可阅读的东西,因此,无论如何加固,都只是增加攻破的难度,我们可以通过添加花指令、隐藏符号等方式来达到加固的作用,比如我们尝试用IDA Pro
反汇编支付宝中的一个动态库:
作者:省油的灯
原文链接: https://juejin.cn/post/6943521608858337293
推荐阅读:
Android NDK CMake指定so输出路径以及生成多个so的案例与总结
最全Android及资源混淆方法汇总(无需加固节约成本并将APP上架Google Play成功的最佳方案)
星球优惠活动、感兴趣的可以加入体验