Kidimos's Studio.

Android逆向知识

Word count: 6.9kReading time: 25 min
2025/09/27
loading

Android包结构

Apk的组成结构

AndroidManifest.xml

  • Android应用的全局配置文件,包含了:包名、版本号、所需权限、注册服务等
Zip直接解压
  • 不是可读的文本,而是机器才认识的二进制数据,所以显示为乱码。
ApkTool解包
  • 解包后可读
  • 重点关注:
  1. package
  2. uses-permission
  3. activity
  4. service
  5. receiver
  6. provider
  7. application

res目录

  • 资源文件夹,它里面存放的所有文件都会被影射到R文件中,生成对应的资源ID,便于代码中通过ID直接访问。
  • 其中的资源文件包括了动画anim、图像drawable、布局layout、常量values、颜色值colors、尺寸值dimens、字符串strings、自定义样式styles等
Zip直接解压
  • res中的xml文件无法被直接阅读,只有res中存有的非XML资源可以被直接阅读(比如视频音频)
ApkTool解包
  • 可以正常阅读xml文件

classes.dex

  • 是Android系统运行于Dalvik Virtual Machine上的可执行文件,也是Android应用程序的核心所在。项目工程中的Java源码通过javac生成class文件,再通过dx工具转换为classes.dex。
  • 当方法数超过dex上限的时候,进行分dex操作,也就是划分为classes2.dex等等,Android5.0后dx自带支持,可以划分dx。
  • 现在一些热补丁有关的技术,主要便是对dex做各种处理。
Zip直接解压
  • 虚拟机执行的字节码,不是源码
  • 在AndroidStudip直接打开的时候,可以看见非常多的机器码函数
ApkTool解包
  • 使用apktool解包后,dex被转为Smali语言。

Smali

Zip直接解压
  • 直接使用Zip解压的话看不见Smali,因为Smali是ApkTool这个工具对classes.dex进行反汇编后产生的结果,是一种描述classes.dex内部指令的文本格式
ApkTool解包
  • 详见[[Smali语言]]

assets

用于保存需要保持原始文件的资源文件夹,开发过程中拖了什么到里面,打包完之后里面还是什么
一般是存放音频、网页(帮助网页之类的)、字体等文件。
可以有多级目录,而res只有两级

Zip直接解压
  • 存放的是原生文件,保存原始格式
  • Data里面的Managed文件夹里面存放的都是dll文件,此外,Managed文件夹外还有一些config、unity3d、json格式的文件(还有一些其他不太常见的格式)
ApkTool解包
  • 和assets的结构没什么差,但是部分文件已经可读

so库(lib目录)

  • 存放着应用需要的native库文件,比如一些底层实现的图片处理、音视频处理、数据加密的库以so库的形式在该文件夹中。
  • 该文件夹下有时会多一个层级,这是根据不同CPU型号而划分的,比如ARM、ARM-v7a、x86等
Zip直接解压
  • 针对特定CPU架构编译的原生机器码,比如在我们现在的测试的demo中,我们使用的就是armeabi-v7a架构的原生机器码
ApkTool解包
  • 与直接解压大概相同

aar(Android Archive)

  • 首先需要提到jar,jar是Java archive的缩写,所以其实aar就是一种类似于jar的打包格式。
  • jar包含了编译后的class文件以及一些包含元数据的文本文件,而aar比jar多了一些Android的特定文件,比如layout、drawable还有manifest文件,在Android中就是一个完整的Module。
使用方式
Android Studio导入

File->New->New Module,进入选择弹窗,选择导入jar或aar
系统自动在setting.gradle配置好aar
只需要在app的gradle配置依赖就可以了。

libs导入

libs建立新的文件夹aars,将要使用的aar文件放到aars文件夹中。
在app:build,gradle文件中加入代码
repositories {
flatDir {
dirs 'libs/aars'
}
}
在dependencies下加入依赖:
dependencies {
...

compile(name:'calculatelib-debug', ext:'aar')

}

META-INF文件夹

  • 该目录的主要作用是保证APK的完整性以及安全性

  • 主要分为三个文件

MANIFEST.MF
  • 保存了整个apk文件中所有文件的文件名+SHA-1后的base64哈希值。
  • 这也就意味着,这个MF文件代表着apk包的完整性。
CERT.RSA
  • 这个文件保存了公钥和加密方式的信息
CERT.SF
  • 这个文件和MANIFEST.MF的结构一样,只是其编码会被私钥加密
  • 如果apk包被修改了,而篡改者没有私钥生成CERT.SF,则无法完成校验
签名(Signature)
  • 部分内容与上面重复,因为上面的内容是后面补上的。
Zip直接解压
  • 似乎存放在META_INF文件夹里面?.RSA文件是签名文件?不管是不是,在Zip解压中,.RSA文件是二进制数据无法阅读
  • 一些关于META-INF的知识
    • MANIFEST.MF:清单文件,记录了APK中除了META-INF目录外其他所有文件的路径,以及每个文件内容的SHA-256哈希值(数字指纹,确保包内的每个文件都没有被篡改)
    • SF文件:不关心原始文件,只关注MANIFEST.MF,包含了MANIFEST本身的哈希值,还包含了文件中每一项的哈希值,确保清单文件本身没有被伪造或者修改。
    • RSA:数字签名,是整个验证链的信任起点。包含了开发者的数字证书(开发者的公钥)以及加密后的签名(通过开发者的私钥对SF文件对哈希值进行加密后产生的数据),保证SF文件不被篡改,并且只有拥有私钥的开发者才能生成这个签名。
    • 额外元数据
  • 验证过程:
    • 读取RSA,取出开发者的公钥
    • 使用公钥解密RSA中的签名,得到SF文件的原始哈希值A。系统自己计算一遍SF文件的哈希值,如果不相等,说明被修改过,验证失败。
    • SF验证通过后,系统逐一比对SF和MF中的哈希值,确保清单可信。
    • 最后,计算每一个实际文件的哈希值,和MF清单中的哈希值进行对比,如果有不一致,说明被篡改,安装失败。
签名流程?或许正确?
  • 准备签名密钥库(一次性工作)
    • keytool -genkeypair -v -keystore [你的密钥库文件名].keystore -alias [你的别名] -keyalg RSA -keysize 2048 -validity 10000
    • 需要记住密钥库的密码和别名
  • 执行签名
    • ./apksigner sign --ks [密钥库文件名].keystore --ks-key-alias [你的别名] [需要签名的APK路径]
    • 使用的工具apksigner来自Android Studio内部,路径为:
      ~/Library/Android/sdk/36.0.0/build-tools/apksigner
  • 验证签名(可选)
    • ./apksigner verify [已签名的APK路径]
      PS:别的说法:VSCode里面自己生成的.app.idsig是v4签名方案,可以在app install的时候直接查找这个文件来签名
ApkTool解包
  • RSA无法直接阅读,但是MF和SF可以

resources.arsc

  • 所有文件中结构最复杂的
  • 记录了资源文件、资源文件位置
  • resource相关的索引表

可以选择package,resource.arsc包含多个package的资源
有个Resource Types的列表,可以看到不同的type,比如anim、drawable等。
右边显示了type里有多少个resource,以及对应的ID、Name和default(其实就是资源的路径?)

  • 通过这个,我们可以完成通过id+对应的configuration获取对应资源的操作
  • 后面的资源混淆的原理,就是修改这里各个维度的值,并且修改对应res里面的文件夹以及文件名实现的
分析方式

可以直接使用Android Studio中的Analyze apk分析apk

混淆(Obfuscation)

架构

ARM架构

arm64-v8a

  • 64位处理,必须支持(谷歌要求)

armeabi-v7a

  • 支持32位,支持FPU(硬件浮点运算)以及NEON支持(高级单指令多数据流技术,可以并行处理大量数据)

armeabi

  • 32位,早期架构,已被淘汰

x86

x86_64

  • 64位intel,当前模拟器必备(?),因为大部分电脑是x86_64架构

x86

  • 32位桌面架构

Android逆向工具

需要掌握的工具

  • 要求:可以熟练使用命令完成逆向

一些有趣的网站
吾爱破解
蓝色星原解密
Android App逆向入门

Analyze APK

Android Studio自带

ApkTool

  • apktool本质上就是一个.jar文件,需要JRE才能运行。
  • 命令行使用方法:
    • 基本命令格式:java -jar apktool.jar d your_app.apk
    • 因为我们电脑上直接使用homebrew下载,所以不需要那么多的命令,直接使用apktool代替java -jar apktool.jar
    • d代表的是decode,也就是解码,帮助解码apk
      • -o:指定解码后的输出目录名
      • -f:强制删除已经存在的输出目录
      • -s:不反汇编smali文件夹
      • -r:不解码资源文件
      • -p:指定框架文件所在的目录(通常推荐使用if命令进行全局安装)
    • b代表的是build,也就是构造,帮助从解码文件构造成apk
      • -o:指定输出的APK文件路径和名称
      • -f:构建的时候跳过文件变更检测,强制构建所有文件
      • -a:手动置顶aapt或者aapt2工具的路径
    • apktool if framework-res.apk
      • 当解码非原生Android应用的时候,如果需要引用厂商自己添加的公共资源,就需要提取所需框架文件。
      • -t:为安装的框架文件打上一个标签
      • empty-framework-dir:清空已经安装的所有框架文件
      • h:显示帮助信息
      • v:显示版本号

nm

安装方式

LLVM自带

使用方式:

nm xxxxx.so

  • 列出文件中的符号表

jadx-gui

作用
  • 直接将文件拖入jadx,可以直接阅读源码
下载方式:
  • brew install jadx
使用方式
  • 终端直接输入jadx-gui,打开对应的解包或者apk
  • 前面的是jadx的GUI使用方式,我们可以不使用这个方式启动软件,而是直接使用jadx来对apk文件进行解码。
  • 常见格式:
    • -r:不解码resources
    • -s:不解码sources
    • -d:指定输出文件夹

IDA

启动台启动IDA

PS:如果没有办法启动,试试将输入法切换到英文

使用方法

  • 拖拽.so文件到ida中
  • 寻找入口点 (Functions Window)
    • 在 IDA 的左侧或通过 Shift+F3 打开 “Functions Window”(函数窗口)。这里列出了 IDA 在 .so 文件中识别出的所有函数。
    • 寻找那些名字看起来很可疑或有意义的函数,特别是以 Java_ 开头的函数。这些是 JNI(Java Native Interface)函数,是 Java 代码调用 C/C++ 代码的桥梁。例如,Java_com_example_app_MainActivity_decryptString 这个函数,显然就是 MainActivity 中用于解密字符串的原生方法。
  • 【最关键的一步】反编译成 C 伪代码 (F5)
    • 在函数列表中双击一个您感兴趣的函数,IDA 的主视图会跳转到该函数的汇编代码。
    • 现在,按下键盘上的 F5 键。
    • 奇迹发生了! IDA 内置的 Hex-Rays Decompiler 会将当前函数的、复杂的 ARM 汇编代码,瞬间反编译成可读性非常高的 C 语言风格的伪代码
  • 以上操作由gemini生成,因为我还没试过
    https://bbs.kanxue.com/thread-266021.htm

AndroidKiller

使用的版本为AndroidKiller4J,因为Mac平台限制

启动方式

进入下载中,直接进入文件夹运行./startup.sh
不知道为什么打不开apk?所以还是放弃这个

PS:完全没有用,之后寻找别的使用方法。

VSCode

下载了插件APKLab,似乎可以直接集成apktool和jadx?

一些常用命令:
  1. rebuild:右键apktool.yml,直接重建apk
  2. command + shift + p:>APKLab :有多个指令,可以选择jadx或者apktool解析apk包,APKLab中集成了这几种工具。
IDA教程

IDA从入门到理解

Android打包流程

资源

  • Android打包流程的第一步,是处理资源文件

处理资源文件

aapt

AndroidManifest.xml、res文件夹以及resource.arsc文件的生成都与其有关

  • aapt解析项目代码中的AndroidManifest.xml,收集项目中res文件夹的资源文件以及xml,对其做压缩和编译的处理。
  • 在这过程中,分配了资源ID以及生成了R.java以及arsc文件

  • 如果项目引入了Android support包,又或许依赖于其他第三方aar库,那么构建前会将aar解压并与本地资源合并。本地资源包括:assets目录、res目录以及Androidmainfest.xml。
  • 当第三方依赖中的assets或者res文件与本地文件有冲突的时候,会优先选用本地文件。但是res/value略有不同,此目录下的strings、color、styles等xml文件会被整合到一个叫做values等文件中去,会其他第三方依赖中的values进行内容上的合并,不会直接舍弃。
    • 理解:对于assets或者res这种资源型的文件,一般来说本地优先,舍弃第三方库的资源,但是如果是values,会将值进行合并(可以理解,因为这几个文件基本上在每个Android Module中都存在,并且这种键值对方式存储的资源文件确实适合这么合并存储)
  • Androidmanifest.xml的合并相比来说则要复杂一些,除了第三方依赖中的manifest,项目还可以在不同目录下分别拥有manifest文件。构建过程中,会根据manifest中元素、属性及赋值来生成一个manifest文件,并应用于后续的打包过程。gradle为不同的manifest赋予了不同的优先级,其顺序如下:
    • buildType 设置  >  productFlavor 设置  >  src/main  >  dependency&library
    • 后续还有一些具体的规则和错误,可以在文档或者网上查看(实在不想看这个了)

代码

得到R.java文件后,与项目代码一起编译得到class文件,然后打包为jar包。这个过程中,还会有混淆代码这一步骤。
之后,再通过dx工具,将生成的jar包与第三方的jar包一起编译为dex文件,包括了分dex

签名

  • 按步骤生成MANIFEST.MF,CERT.RSA,CERT.SF并放入META-INF文件夹即可。*

业内有关技术小结

apk加固

  • 加固工具拿出原始的classes.dex文件,并使用加密算法将其变成一堆无法直接读取的二进制数据。
  • 加固工具生成一个新的classes.dex文件,也就是壳DEX,这个壳本身也是一段可执行的代码,但是功能非常单一,就是一个解锁程序。
  • 壳DEX与加密后的原始DEX放回apk中,生成一个新的、加固后的APK

快速多渠道包

减少多渠道打包的时间:

  • 其实需要攻破的是META-INF的完整性检验机制
  • 两种方案
    • META-INF下添加空文件不会破坏签名(文件名为渠道号)
      • 原理:Android 的 V1 签名方案在校验时,会严格检查 MANIFEST.MF 文件里列出的每一个文件的指纹是否正确。但是,它对于 META-INF 目录里多出来的、未被列出的文件,会选择忽略。
      • 实现步骤
      1. 先正常打一个完整的、已签名的“基础包”。这个过程很慢,但我们只需要做一次。
      2. 需要“华为”渠道包?复制一份基础包,然后用 ZIP 工具在它的 META-INF/ 目录下创建一个名为 huawei 的空文件。
      3. 需要“小米”渠道包?再复制一份基础包,在 META-INF/ 目录下创建一个名为 xiaomi 的空文件。
    • apk文件末尾写入信息(本质利用了ZIP文件可以添加comment数据结构的特点)
      • 原理:APK 文件本质上是一个 ZIP 压缩包。标准的 ZIP 格式规范允许在文件的末尾附加一段“注释”信息(Comment)。Android 的 V1 签名校验只会检查 ZIP 包里包含的那些文件条目,完全不会去校验这个末尾的“注释”区域
      • 实现步骤
      1. 同样,先打一个完整的、已签名的“基础包”
      2. 需要“华为”渠道包?复制一份基础包,然后用程序打开这个 APK 文件,在文件末尾的 ZIP 注释区写入 huawei
      3. 需要“小米”渠道包?再复制一份,在注释区写入 xiaomi
      • 为什么快:这同样是一个纯粹的文件 I/O 操作,不触及任何已被签名的文件内容,速度飞快。
      • App 如何读取渠道号:App 运行时,可以像读取普通文件一样打开自己的 APK,然后从文件末尾读取 ZIP 注释,从而拿到渠道号。
      • 可靠性:这个方法比方案一更可靠,因为它利用的是 ZIP 文件格式的标准特性。美团等公司开源的著名多渠道打包工具 Walle 就是基于这个原理并针对 V2 签名方案进行了优化
  • 这两种方案都不会导致MF文件的改变,就不需要再次打包。
  • “快速”的关键在于,将 N 次“编译 + 签名”的重度操作,转变成了 1 次“编译 + 签名” 和 N 次“轻度文件 I/O” 操作。

资源混淆

资源混淆通过混淆资源路径名以及资源文件名,减少安装包的体积,并且提高破解难度
res/drawable/icon -> r/s/a
入手点皆为:resource.arsc

  1. 修改刚刚提及的aapt,使得在生成resource.arsc的过程中,就修改掉项目中资源的名称,实现了资源的混淆。
  2. 打出apk包之后,读入已经生成的resource.arsc文件,进行混淆、改写,同时修改掉res文件夹下的资源名称,完成混淆。最后再重新打包得到混淆后新apk文件。

热补丁

通过native hook的方式,替换class中的方法实现完成热补丁
classloader加载新dex覆盖原有class完成替换的方案

其他

使用 Annotation 自动生成代码,buck exopackage 提高打包速度

Android的模拟器问题

需要在Android Studio上运行一个Unity开发的APK,但是里面用到的so库是armeabi v7a,折腾了一顿发现,我这个版本的Android Studio上没有办法创建armeabi v7a架构的虚拟机,创建后启动虚拟机会直接报错。

设备

工作电脑是2018年的Intel芯片Mac pro,总的来说配置很低,intel芯片在现在的Mac系统上也挺难用。

报错原因

没有定位准确的原因,以下是一些可能的问题参考:

  • Intel Mac是x86架构,armeabi-v7a是ARM架构,在x86硬件上直接运行ARM系统需要指令集转换,所以我们无法直接在x86架构的Intel Mac电脑上安装并且运行需要ARM指令集的项目。
  • 性能问题
  • 系统镜像不兼容,某些系统镜像可能不完全支持对ARM库的翻译功能。
  • 环境配置

个人觉得应该是第一种原因,Intel Mac没法直接创建ARM架构的虚拟机。

解决方法

放弃使用x86_64架构的虚拟机,转而使用x86架构的虚拟机。

在x86架构的虚拟机上,可以直接运行armeabi-v7a架构的项目,原因是x86内置有libhoudini翻译器,可以在32位环境中将arm指令翻译为x86指令,从而让.so库在x86 cpu上运行。
x86_64无法成功运行,可能是因为64位到32位到翻译不够直接和稳定,或者说64位缺少了从32位ARM翻译到64位x86_64的翻译器。

Hook

概览

  • Hook是一种允许你拦截和修改系统或者应用程序中函数调用、消息或者时间的技术。
  • 在Android逆向的语境中,Hook的本质就是改变应用原有的执行流程,将其引导到我们自己编写的代码逻辑中。可以通过这种技术实现以下的目的:
    • 动态分析
    • 逻辑修改
    • 安全绕过
  • Hook技术分为两大类:
    • Java Hook(Dalvik/ART)
      • 针对的是Java或者Kotlin编写的代码,运行在Android运行时。
      • 原理:通过修改虚拟机内部的数据结构来改变方法的执行入口,或者利用Java的反射机制。
    • Native Hook(ELF)
      • 针对C/C++编写的so库文件
      • 直接修改内存中加载的ELF文件的机器码或者相关数据表

反射Hook

本质其实是Java提供的运行时能力,也就是Java反射,允许程序在运行时检查和操作类、方法、字段等。
需要解释的是,我们通常利用Java反射来实现一些类似Hook的目的,但是它本身并不是一种替换函数实现的Hook。

技术原理

Java反射的核心是java.lang.reflect包下面的一系列API。通过这些API可以实现。

  • 在运行时候获取任意一个类的对象。
  • 通过class对象,获取该类的所有方法、构造函数以及字段。
  • 即使方法是私有的或者受保护的,也可以通过setAccessible来解除访问限制。
  • 通过invoke来调用方法,通过Field.get()、Field.set()来读写字段值。

逆向应用

  • 调用私有/隐藏的API
  • 修改对象状态
  • 替换回调实现:如果一个功能室通过设置监听器或者回调来实现的,我们可以通过反射来找到存储该监听器实例的字段,然后将其替换为我们自己实现的监听器实例,这等同于Hook

要实现真正的方法替换,通常需要结合Xposed等框架?
需要注意的是,反射操作的性能远远低于直接调用

MSHook(Cydia Substrate)

MSHook是Cydia Substrate框架提供的一个核心函数,用于在Native层实现inline Hook。

技术原理:inline Hook

  • inline Hook是最直接、最强大的Hook方式之一。
  • 核心思想:直接在内存中修改目标函数的开头几字节的机器指令,替换为一个跳转指令,使其跳转到我们自己编写的函数。
  • 流程:
    • 定位函数:首先找到目标函数在内存中的起始地址。
    • 指令修改:- 将目标函数头部的若干字节的机器码替换为一个无条件跳转指令(如 ARM64 架构下的 BBR 指令),该指令指向我们的新函数(Hook 函数)。
    • 保存原指令:被覆盖掉的原始指令会保存在一个叫做Trampoline的可执行内存区域中。
    • 执行流程:
      • 当程序调用原函数的时候,实际上会执行我们插入的跳转指令,进入我们的Hook函数。
      • 在Hook函数中,我们可以读取/修改参数、执行我们自己的逻辑
      • 如果需要调用原始函数的功能,可以通过执行之前保存的Trampoline来实现。Trampoline会执行被覆盖的原始指令,然后跳转回原始函数中未被修改的部分继续执行。
      • 原始函数执行完毕后,控制权返回到我们的Hook函数,我们可以在此时读取/修改返回值。(这部分应该有实践更好理解)
      • 最后Hook函数返回,完成了整个调用过程。

Cydia Substrate API

  • 简化了inline Hook的流程,提供了简单的API,比如:
    • MSHookFunction
    • void MSHookFunction(void *symbol, void *hook, void **old);
    • symbol是指向原始函数的指针
    • hook是指向我们自己编写的新函数地址的指针。
    • old用于保存Trampoline地址的指针,以便我们在新函数中可以调用原始函数。

优缺点

  • 优点:
    • 通用性强:几乎可以Hook任何Native函数,无论是库的导出函数还是内部的静态函数
    • 功能强大:可以完全控制函数的执行,包括参数、返回值和执行时机
  • 缺点:
    • 实现复杂
    • 平台依赖性:指令集差异
    • 易于被检测,很多安全保护方案会检验函数头部的完整性,一旦被修改,就会判定为被攻击。

And64Hook

And64是一个开源的、专门为Android ARM64架构设计的Native Hook库。

技术原理

主要是实现了两种主流的Native Hook技术

inline Hook

与MSHook的原理相同,直接修改了函数头部的指令。
对AARch64指令集优化。

PLT/GOT Hook

背景知识:

  • 为了实现动态链接以及代码共享,当一个.so文件(模块A)调用另一个.so(模块B)文件中的函数的时候,不是直接跳转到绝对地址,而是通过一个中间层来实现。
    • PLT:过程链接表,模块A对代码实际调用的是PLT中的一个条目。
    • GOT:全局偏移表,PLT条目根据GOT表中的地址进行跳转,GOT中存放着外部函数的真实地址。这个地址在程序第一次调用该函数的时候由动态链接器来填充。
  • Hook原理:不去修改目标函数的代码,而是从GOT表中存储的该函数的地址下手。将原本指向原始函数的地址,替换为我们自己编写的Hook函数的地址。
  • 执行流程:
    • 当模块A调用目标函数的时候,跳转到PLT
    • PLT根据GOT去寻找函数地址。
    • 此时,它获取到的是我们已经修改过的Hook函数的地址。
    • 程序跳转到我们的Hook函数从而实现拦截。

如何从应用层调用到Natvie层?

本质上是Java去调用C/C++

JNI调用流程概述

  • Java层
    • 编写一个Java类,在其中使用native关键字声明一个或多个方法。这些方法没有方法体。
    • 在合适的时机(通常是静态代码块中),使用System.loadLibrary("库名")来加载编译好的C/C++动态链接库。
  • Native层
    • 使用C/C++编写代码,实现Java层实现的native方法。这个C/C++函数的命名必须遵循JNI的特定规则。
    • 将C/C++代码编译成动态链接库。
  • 打包和运行
    • 将编译好的.so文件打包到APK的lib目录下。
    • 当Java代码调用native方法时,ART虚拟机就会通过JNI规范,在已经加载的.so库中寻找到对应的C/C++函数并执行它。

实战步骤:

  • 确保安装NDK
  • 在Java层声明Native方法
    • 使用static代码加载so库
    • 使用native关键字声明一个本地方法
  • 在C/C++层实现Native方法
    • AS通常会在app/src/main/cpp目录下面自动生成一个文件(名字对应so库名字)
    • JNIEnv* env JNI环境的指针,通过它可以调用所有JNI函数
    • jclass 调用该静态方法的java类
    • jstring 从Java层传过来的String对象
  • 配置CMake构建脚本
    • app/src/main/cpp/CMakeLists.txt
    • add_library( native-lib SHARED native-lib.cpp)
  • 在应用层调用
    • 使用之前声明的类和方法调用

需要注意的点:

  • 需要安装NDK?已经安装完毕了,在Tools->SDK Manager->SDK Tools里面有NDK和CMake

对于逆向来说:

  • 切入点:分析APK的时候,如果看到出现了native关键字或者loadLibrary,可能说明App的核心逻辑在Native层的.so库。
  • 定位实现:反编译后,在lib文件下找到不同架构的so文件
  • 静态分析:使用IDA或者其他工具打开so文件,直接搜索遵循JNI命名规则的函数。
  • 动态调试:Hook
CATALOG
  1. 1. Android包结构
    1. 1.1. Apk的组成结构
      1. 1.1.1. AndroidManifest.xml
        1. 1.1.1.1. Zip直接解压
        2. 1.1.1.2. ApkTool解包
      2. 1.1.2. res目录
        1. 1.1.2.1. Zip直接解压
        2. 1.1.2.2. ApkTool解包
      3. 1.1.3. classes.dex
        1. 1.1.3.1. Zip直接解压
        2. 1.1.3.2. ApkTool解包
      4. 1.1.4. Smali
        1. 1.1.4.1. Zip直接解压
        2. 1.1.4.2. ApkTool解包
      5. 1.1.5. assets
        1. 1.1.5.1. Zip直接解压
        2. 1.1.5.2. ApkTool解包
      6. 1.1.6. so库(lib目录)
        1. 1.1.6.1. Zip直接解压
        2. 1.1.6.2. ApkTool解包
      7. 1.1.7. aar(Android Archive)
        1. 1.1.7.1. 使用方式
          1. 1.1.7.1.1. Android Studio导入
          2. 1.1.7.1.2. libs导入
      8. 1.1.8. META-INF文件夹
        1. 1.1.8.1. MANIFEST.MF
        2. 1.1.8.2. CERT.RSA
        3. 1.1.8.3. CERT.SF
        4. 1.1.8.4. 签名(Signature)
          1. 1.1.8.4.1. Zip直接解压
          2. 1.1.8.4.2. 签名流程?或许正确?
        5. 1.1.8.5. ApkTool解包
      9. 1.1.9. resources.arsc
        1. 1.1.9.1. 分析方式
      10. 1.1.10. 混淆(Obfuscation)
  2. 2. 架构
    1. 2.1. ARM架构
      1. 2.1.1. arm64-v8a
      2. 2.1.2. armeabi-v7a
      3. 2.1.3. armeabi
    2. 2.2. x86
      1. 2.2.1. x86_64
      2. 2.2.2. x86
  3. 3. Android逆向工具
    1. 3.1. 需要掌握的工具
      1. 3.1.1. Analyze APK
      2. 3.1.2. ApkTool
      3. 3.1.3. nm
        1. 3.1.3.1. 安装方式
        2. 3.1.3.2. 使用方式:
      4. 3.1.4. jadx-gui
        1. 3.1.4.1. 作用
        2. 3.1.4.2. 下载方式:
        3. 3.1.4.3. 使用方式
      5. 3.1.5. IDA
        1. 3.1.5.1. 启动台启动IDA
      6. 3.1.6. AndroidKiller
        1. 3.1.6.1. 启动方式
      7. 3.1.7. VSCode
        1. 3.1.7.1. 一些常用命令:
        2. 3.1.7.2. IDA教程
  4. 4. Android打包流程
    1. 4.1. 资源
      1. 4.1.1. 处理资源文件
        1. 4.1.1.1. aapt
    2. 4.2. 代码
    3. 4.3. 签名
  5. 5. 业内有关技术小结
    1. 5.1. apk加固
    2. 5.2. 快速多渠道包
    3. 5.3. 资源混淆
    4. 5.4. 热补丁
    5. 5.5. 其他
  6. 6. Android的模拟器问题
    1. 6.1. 设备
    2. 6.2. 报错原因
    3. 6.3. 解决方法
  7. 7. Hook
    1. 7.1. 概览
    2. 7.2. 反射Hook
      1. 7.2.1. 技术原理
      2. 7.2.2. 逆向应用
    3. 7.3. MSHook(Cydia Substrate)
      1. 7.3.1. 技术原理:inline Hook
      2. 7.3.2. Cydia Substrate API
      3. 7.3.3. 优缺点
    4. 7.4. And64Hook
      1. 7.4.1. 技术原理
        1. 7.4.1.1. inline Hook
        2. 7.4.1.2. PLT/GOT Hook
    5. 7.5. 如何从应用层调用到Natvie层?