安卓逆向实战:极简APP

引言

今天我们来逆向一个简单的安卓 APP。

appbasic1

appbasic1 地址:https://appbasic1.scrape.center/

appbasic1 说明:

极简 App 案例,只有一个按钮和回调提示框,逻辑在 Java 层实现,适合做 Hook 分析。

一个很简单的 APP,只有一个按钮和很简单的逻辑,先安装看下效果,adb 命令将 APP 传过去。

image-20250209200121651

安装看看,也可以直接使用 adb Install 命令来安装,效果是一样的。

01

点击按钮,弹窗显示一个数字 3,现在我们来逆向看看它的逻辑。

首先需要安装 jadx-gui 工具,因为我是 MacOS 系统,安装方法是使用 brew 命令:brew Install jadx-gui

image-20250209201126305

打开 jadx-gui,正常来说打开后是这样的界面。然后打开 appbasic1 对应的 apk 文件。

image-20250209201259991在左侧的源代码中打开反编译后的源代码,可以看到一大堆类路径,这些一般都是安卓系统的类库,我们要如何找到我们想要找的类呢?一般情况下,默认的程序入口都是 MainActivity 类,我们直接搜索。

image-20250209201437418

image-20250209201552547

双击 MainActivity 类,整个 MainActivity 类的源代码都可以看到了。

从代码中可以看到,只有三个方法,一个是 onCreate 方法,初始化用的,一个 onClickTest 回调方法,是在点击 Test 按钮的时候调用的方法。还有一个就是在点击按钮的时候调用的方法,叫 getMessage,它输入两个整形值,返回一个字符串。

整体的逻辑就是在点击 Test 按钮的时候,调用 getMessage 方法,传入 12 两个整形值,返回它们的和的字符串,也就是 3

appbasic2

appbasic2 地址:https://appbasic2.scrape.center/

appbasic2 说明:

极简 App 案例,只有一个按钮和回调提示框,逻辑在 Native 层实现,适合做逆向和 Hook 分析。

和上面的 APP 一样,只有一个按钮和调用提示框,但是实际的逻辑在 Native 层实现的,Native 层就是我们所说的 so 层,也就是使用 C++ 或者 Go 或者其他语言开发的 Linux 系统的动态链接库文件,类似于 Windows 上面的 dll 文件,可以被 Java 程序所调用,一般用来实现性能敏感的逻辑或者比较核心的功能,方便混淆,不易被人逆向出来。

先反编译看看 Java 层的函数调用逻辑:

image-20250209210131931

发现和刚才的 APP 差不多,唯一不同的就是 getMessage 函数被放到了 Native 层去实现,并且通过静态块加载了一个名字叫 nativeso 文件,只是没有 so 后缀。

APP 就不截图了,我们直接解压 apk 文件。

image-20250209202401948

查看 lib 文件夹,一般 so 文件都会放到这里面,lib 中的四个子文件夹对应的是不同的平台,例如 arm 平台就使用 arm 开头的文件夹中的 so 文件,我们这里随意选择一个就好。

使用 ida 打开,直接将 so 文件拖到 ida 图标上。

image-20250209204904387

默认会识别出来对应的 CPU 架构,一般情况下直接点 OK 就行。

image-20250209205025997

查看左侧的函数列表,可以发现有一个 Java 开头的函数,说明 so 中有一个导出给 Java 使用的函数,它的函数名是有含义的,一般是 Java 关键字加上全限定类名加上对应的函数名。

打开以后,我们按 F5 使用 ida 强大的反编译功能查看汇编对应的 C 语言代码。

image-20250209205248360

发现是一个很简单的 C 语言函数,不过函数看起来怪怪的,a1 变量不知道是在做什么。这个时候,把光标放在 a1 变量上面,按键盘上面的 y 键。

image-20250209205422472

会弹出来一个窗口,下拉选择第二个 JNIEnv* 类型,so 导出给 Java 的函数签名第一个参数都是 JNIEnv 类型的,ida 不能自动识别,我们要手动转换一下。

JNIEnv* 是一个指向 JNI 环境的指针,通过这个指针可以调用 JNI 提供的各种方法和功能。在 Java 层我们看到 getMessage 方法只有两个入参,但是 so 层有四个,除了第一个 JNIEnv 的指针外,还有一个 a2 是做什么的呢?其实它是一个执行调用方的类或者实例的变量,方便从 so 中调用 Java 类对应的方法。

image-20250209205537152

点击确定后,我们看到,现在的代码正常了许多,首先声明了一个 s 数组,然后将 a3a4 变量的值相加,并且格式化成字符串写入 s 数组中,最后通过 a1 变量调用 NewStringUFT 函数创建一个字符串返回。

总结

到这里其实整个逻辑就清除了,其实两个 APP 都是实现了一个加法函数,只是一个在 Java 层实现,另一个在 so 层实现,整体的逻辑也比较简单,方便我们来练习使用相关反编译工具。

本文章首发于个人博客 LLLibra146’s blog

本文作者:LLLibra146

更多文章请关注公众号 (LLLibra146):LLLibra146

版权声明:本博客所有文章除特别声明外,均采用 © BY-NC-ND 许可协议。非商用转载请注明出处!严禁商业转载!

本文链接
https://blog.d77.xyz/archives/f45924e7.html