0
点赞
收藏
分享

微信扫一扫

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​​目录下,运行。

输出日志如下,很正常:

Android JNI 动态库逆向_数据

二、修改动态库

首先我们需要了解的是,无论是exe、so、dll、txt、doc,还是其他格式的文件,它们都只是文件,都是二进制数据,只是生成和解析方式不同

比如我们可以使用文本编辑器将​​txt​​​解析成我们能够理解的文本内容,也可以将我们输入的文本内容保存成​​txt​​​;我们可以使用Word将​​doc​​​解析成我们能够理解的内容,也可以将我们输入的内容保存成​​doc​​…

对于so文件,我们可以使用​IDA Pro​进行解析、修改。

1. IDA界面简介

​IDA Pro​​​在安装完成后,会分别有64位和32位的可执行文件。对于刚才生成的​​libreversetest.so​​这个动态库文件,使用64位的程序打开,打开后界面如下:

Android JNI 动态库逆向_java_02

2. 修改函数内容

修改常量字符串

在左边的函数表中,我们可以使用​​CTRL + F​​寻找我们需要查看的函数:

Android JNI 动态库逆向_数据_03

双击函数名,可查看其汇编指令,再按​​F5​​​,得到反汇编后的​​C​​代码:

Android JNI 动态库逆向_动态库_04

双击右边的​​content​​,即可跳转到其定义处:

Android JNI 动态库逆向_开发语言_05

这个时候我们可以使用​​IDA Pro​​​自带的编辑器修改其内容,也可以根据其偏移地址​​0x6E0​​使用其他二进制编辑器修改,或者自己写个代码修改文件的内容。

这里选择用​​IDA​​​自带的功能修改:点击​Edit->​Patch program​->​Change bytes...​

Android JNI 动态库逆向_数据_06

将其修改为61 - 67(也就是a-g):

Android JNI 动态库逆向_开发语言_07

确认后可以看到,这个字段的内容已经被我们成功修改了

Android JNI 动态库逆向_java_08

但是这个时候并没有保存数据至原动态库中,我们点击​​Edit​​​->​​Patch program​​​->​​Apply patches to input file..​​即可保存至原文件。

修改指令

双击另一个函数,看到以下源码:

Android JNI 动态库逆向_数据_09

这个动态库里的指令反汇编得到的代码和编写时的内容不是完全一致,但是不影响,表达的含义相同。

对于指令的修改,汇编视图会更友好,切换到汇编视图,内容如下:

Android JNI 动态库逆向_数据_10

我们知道,​​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​​,但是直接改数据是没问题的,修改指令为以下内容:

Android JNI 动态库逆向_java_11

Android JNI 动态库逆向_java_12

和刚才一样的操作,点击​​Apply patches to input file..​​保存修改至原文件。

对于​​x86_64​​​的动态库,我的设备点击​​Edit​​​->​​Patch program​​​->​​Assemble...​​​是没问题的,所以这里也对​​x86_64​​架构的动态库操作一遍:

原指令如下,我们将​​jl​​​修改为​​jge​​即可进入另一个逻辑分支:

原指令:

Android JNI 动态库逆向_动态库_13

修改后:

Android JNI 动态库逆向_android_14

Android JNI 动态库逆向_数据_15

Android JNI 动态库逆向_android_16

三、运行验证

刚才我们修改了一处常量字符串和一处判断指令,现在将修改好的​​arm64-v8a​​的动态库放进工程对应目录,运行,结果如下:

Android JNI 动态库逆向_java_17

大功告成,成功地修改动态库内容。

四、如何加固

程序本身就是相当于可阅读的东西,因此,无论如何加固,都只是增加攻破的难度,我们可以通过添加花指令、隐藏符号等方式来达到加固的作用,比如我们尝试用​​IDA Pro​​反汇编支付宝中的一个动态库:

Android JNI 动态库逆向_android_18

可以看到,打开后发现函数名都被修改成了这种让人看不下去的名字,大大增加逆向的难度。

作者:省油的灯

举报

相关推荐

0 条评论