- 博客(182)
- 资源 (7)
- 收藏
- 关注
原创 使用 Frida 增强 FART:实现更强大的 Android 脱壳能力
主动调用时 dump 得到的 dex (*_dex_file.dex)和此时 dex 中的所有类列表,以及该 dex 中所有函数的 CodeItem( bin 文件)Execute 脱壳点得到的 dex (*_dex_file_execute.dex)和 dex 中的所有类列表( txt 文件)枚举出所有 ClassLoader 后,再结合 FART 的 api 就可以实现动态加载 dex 的脱壳。增强 FART 的脱壳能力:解决对抗 FART 的壳、动态加载的 dex 的 dump 和修复;
2025-05-28 23:32:37
764
原创 FART 自动化脱壳框架一些 bug 修复记录
FART 中通过 mkdir 函数在 sdcard 上创建 dump 文件存放目录,但是这样必须 app 拥有存储卡读写权限。在 Android 编译构建阶段的 dex2oatd 工具执行时 调用了 art_method.cc 中的方法,导致出现下面的日志。解决方案:把 dump 路径改为:/sdcard/Android/data/<packageName>/fart。下面时一个 frida 脚本,调用系统 的 mkdir 函数创建目录。成功时:返回一个非负整数(即 >= 0),它是打开的文件描述符。
2025-05-28 00:10:19
653
原创 移植 FART 到 Android 10 实现自动化脱壳
~~~~~~~^说明:Android 6.0 中有 mirror::AbstractMethod;Android 10 中已经移除或合并进 Executable / Method 等类型。修复方式:使用 mirror::Executable(它是 ART 中 java.lang.reflect.Method 和 Constructor 的基类)代替。= nullptr);
2025-05-24 00:33:00
1084
原创 FART 主动调用组件设计和源码分析
/ DEX 字节码必须按照 4 字节对齐private:// 方法使用的虚拟寄存器数量(包括本地变量和参数)// 方法的入参占用的寄存器数量// 方法调用其他方法时所需的最大出参寄存器数量(即调用其他方法时的参数空间)// try-catch 块的数量。如果不为 0,则在 insns_ 后紧跟 try_item 和 catch_handler。// 调试信息在 DEX 文件中的偏移,指向 debug_info 结构// 包括局部变量名、源码行号映射等。
2025-05-19 23:50:19
791
原创 FART 自动化脱壳框架简介与脱壳点的选择
ART 环境下基于主动调用的自动化脱壳方案,可以解决函数抽取壳。基于 art 下的类加载机制,实现函数抽取壳FART 的作用就是所有这些被抽空的函数的还原和修复,把加固的 dex 整体 dump 下来。
2025-05-19 23:43:51
1005
原创 如何让 Google 收录 Github Pages 个人博客
SEO(Search Engine Optimization,搜索引擎优化)信息是指你在网页中设置的一些帮助搜索引擎理解、索引和展示你网站内容的内容和元数据(meta data),让你的网站更容易被搜索引擎(如 Google、Bing)收录和排到靠前的位置。将此文件放在你的 GitHub Pages 仓库下的根目录下,git push 重新构建网站。点击 “尝试使用 Google Search Console”,输入网址,点击继续。description:页面简介,可能显示在搜索结果摘要中。
2025-05-16 19:04:05
1059
原创 在 Hugo 博客中集成评论系统 Waline 与 浏览量统计
5、点击顶部的 Settings - Environment Variables 进入环境变量配置页,并配置三个环境变量 LEAN_ID, LEAN_KEY 和 LEAN_MASTER_KEY。此时请点击 Visit ,即可跳转到部署好的网站地址,此地址即为你的服务端地址。在你的 Hugo 主题中添加 Waline 的前端代码,一般是在 themes\m10c\layouts_default\single.html。的 init() 函数初始化,并传入必要的 el 与 serverURL 选项。
2025-05-15 15:47:45
740
原创 基于 art 下的类加载机制,实现函数抽取壳
函数抽取壳其实就是基于 art 下的类加载机制,只有 ArtMethod 初始化完成后,java 函数才能被调用,所以通过劫持 ClassLinker::LoadMethod 函数对 ArtMethod 中的 CodeItem 打补丁的方式实现脱壳。
2025-05-14 16:23:15
688
原创 Android PLT hook 与 Inline hook
Android Native 函数 Hook 技术是一种在应用运行时拦截或替换系统或自身函数行为的手段,常见实现包括 PLT Hook、Inline Hook。PLT Hook 和 Inline Hook 是两种不同层次和机制的函数 Hook 技术,常用于逆向工程、安全分析、壳保护或热修复等场景。
2025-05-11 22:39:26
747
原创 adb 实用命令汇总
通过 stat 命令查看更加详细的文件信息,包括访问时间、修改时间、文件类型和 inode 号等。查找 /data 路径下所有包含 com.cyrus.example 的文件或目录。通过 adb shell 进入命令行通过 ls -alh 查看当前路径下所有文件。此时屏幕左下角会显示 – INSERT --,表示你现在可以开始输入内容。head 用于查看文本文件的前几行内容,默认是前 10 行。按下 Esc 键即可退出插入模式,回到普通模式。如果文件不存在,vim 会创建一个新的。
2025-05-10 20:37:24
1245
原创 关于 dex2oat 以及 vdex、cdex、dex 格式转换
为了提高性能,Android 会将 .dex 文件进一步编译为 .oat 文件(或 .odex/.vdex 文件),以便设备可以直接执行本地代码而不是解释执行 .dex 字节码。在 Android 9(Pie)中,APP 的 .cdex 文件 是由 dex2oat 优化生成的,通常以 odex, vdex 或直接优化后的 .art 文件形式存在。输入:一个或多个 .dex 文件(通常来自 APK 中的 classes.dex)。.oat / .odex:包含从 dex 编译来的 优化后的中间表示代码。
2025-05-05 23:47:04
831
原创 ART 下 Dex 加载流程源码分析 和 通用脱壳点
进入 dex2oat.cc 的 main(),在 dex2oat::ReturnCode Setup() 方法中 将 dex 注册到 VerificationResults 时候可以拿到 dex_file 对象,这里也是一个很好的脱壳点。重新执行 frida 脚本 dump dex,从输出可以看到 dump 下来的 dex 魔数都是 dex 039 / dex 035 (标准 Dex 文件的魔数)不是 cdex001,可以直接用 jadx 去反编译了。
2025-05-04 22:38:16
842
原创 使用 Dex2C 加壳保护 Android APK 代码
因为 jarsigner 只能生成老的 v1 签名,apksigner 支持 v1/v2/v3/v4 新版签名,才能确保 APK 在 Android 7.0 及以上系统正常、安全安装。首先在 app 代码合适的位置,如 Application 的静态代码块或 onCreate 等,添加加载 so 库代码,并重新生成 apk。project-source.zip 是个 jni 工程,里面包含我们编译出来的 C 代码,解压出来后可以直接使用 ndk 编译。
2025-04-27 22:48:45
939
原创 Android APP 热修复原理
从日志可以看到 PathClassLoader 的 DexPathList 中 目前有两个 Element:plugin-debug.apk 和 base.apk,而且 plugin-debug.apk 前面所以会优先找到 plugin 中的 PluginClass。PluginClass.getString:通过 Class.forName 加载 com.cyrus.example.plugin.PluginClass 类 创建对象并调用 getString方法,并显示结果。
2025-04-25 19:54:25
830
原创 Android 加壳应用运行流程 与 生命周期类处理方案
因为 系统在启动组件(如 Activity、Service)时,是通过 AMS → ActivityThread → Instrumentation 最终调用 Class.forName(组件类名) 来加载组件类的,而这个过程默认使用的是系统的 ClassLoader(通常是 PathClassLoader),而不是我们自定义的 DexClassLoader。替换系统组件类加载器为我们的 DexClassLoader,同时设置 DexClassLoader 的 parent 为系统组件类加载器。
2025-04-25 02:29:13
980
原创 详解 Android APP 启动流程
当 Zygote fork 出新进程后,这个进程(即你的 App)会启动并运行 ActivityThread.main(),随后 系统会通过 Binder 调用 ApplicationThread.bindApplication(),然后由主线程调用 handleBindApplication()。ActivityThread 是 Android 应用进程的 主线程(UI 线程)管理类,它是系统在启动你的 App 时,创建和调度 Application 和 Activity 的关键组件。
2025-04-24 03:56:57
609
原创 Android 下的 ClassLoader 与 双亲委派机制
getClassNameList 方法需要一个参数 mCookie,mCookie 是一个 native 层的句柄(handle)或指针,它指向底层的 ART 或 Dalvik 虚拟机中加载的 DEX 文件对象,是 DexFile 对象的唯一标识。Android 中的类加载器的作用就是将 .dex、.jar 或 .apk 中的类文件(字节码)加载到内存中,转化为 Android 虚拟机 可用的 Class<?常用于插件化、热修复以及 dex 加壳。它提供了在类加载过程中对类的访问控制和安全检查的能力。
2025-04-21 02:41:58
770
原创 Android NDK 编译 so 文件 抹除导出符号 反逆向
Android 的 ART 虚拟机会用 dlsym() 查找你导出的 JNI 方法(如Java_com_example_native_NativeUtils_secretMethod),所以这些你不能隐藏,否则会导致运行时崩溃。但除了必须导出的 JNI 函数外,其余 C/C++ 函数符号不导出其实也完全没影响,编译器/链接器内部可以调用,运行时照样可以正常执行。此时 .so 中不需要导出 Java_com_example_xxx 符号,IDA 也就看不到!
2025-04-15 12:47:26
1390
原创 Frida 调用 kill 命令挂起&恢复 Android 线程
kill 是 Linux 系统中用来向进程发送信号的命令,最常用于终止进程。在底层,kill() 实际上会触发系统调用(比如 Linux 的 syscall kill),让内核发送信号给指定的进程。实现一个 suspendOtherThread 函数,挂起除了 excludeList 中指定名字的所有线程。kill 在 C 语言中是定义在 <signal.h> 中的一个标准函数,它本质上是一个系统调用的封装函数。这个目录中每一个子目录的名字就是该 App 的一个线程的 TID(Thread ID)。
2025-04-09 18:23:33
1008
原创 Frida Stalker Trace 指令跟踪&寄存器变化监控
putCallout 会在你指定的位置插入一个“钩子”,在那一刻调用你指定的 JS 函数,提供当前上下文(CPU 寄存器状态)。在 Stalker.follow 的 transform 回调函数中 处理目标线程执行的每一条汇编指令。你无法在那时访问寄存器、调用栈等。iterator 是一个 指令迭代器对象,它让你能够 逐条处理目标线程将要执行的原始机器指令。指令级跟踪:Stalker 可精确到指令级别,对应用的原生代码进行实时监控。对比当前和上一次的寄存器值,返回发生变化的寄存器(不包括 pc 寄存器)。
2025-04-07 19:41:47
916
原创 Frida Hook Android Native 函数
android_dlopen_ext 是 Android 特有的 dlopen 扩展版本,允许开发者在加载共享库时使用额外的选项,比如 指定库的加载路径 或 共享库的保护标志。dlopen 函数 在 linker 模块,是 Android 系统上的动态库加载函数,用于在运行时加载共享库(.so 文件)。在 Android 系统中,这些函数的原型通常可以在 Bionic(Android 的 C 库)中找到。argTypes:一个数组,指定函数的参数类型,如 [“pointer”, “int”]。
2025-04-03 04:02:05
645
原创 Frida Hook Native:jobjectArray 参数解析
通过 env.js 中定义的 stringFromJni 函数可以直接获取到字符串对象的值。通过 getObjectClassName 可以获取到对象的类名进而判断该元素的类型。常用的 JNI 函数在 frida 的 env.js 中都已经定义好了。通过下面代码获取 JNIEnv 引用,就可以调用相关的 JNI 函数。hook native 函数并打印 jobjectArray 传参。打印 jobjectArray 的元素类型和值。
2025-04-02 18:08:39
224
原创 Unidbg Trace 反 OLLVM 控制流平坦化(fla)
在 callJniMethodObject 方法之前添加如下代码,trace 指令执行和内存读写,并把 trace log 输出到文件。得到 trace log,包含指令流、寄存器变化、内存读写信息。F5 反汇编代码如下,很明显通过 fla 隐藏了真实的执行流。通过 unidbg 加载 so 并执行 so 中目标函数。把 so 放到 resource 目录下。根据真实的执行指令流去还原算法执行过程。目标方法反汇编视图如下。
2025-03-30 23:38:33
335
原创 使用 Frida Stalker 反 OLLVM 算法还原
Stalker.follow() 使用 onCallSummary 时,不会实时回调,而是在合适的时间点返回已汇总的调用信息。通过 onRecive 解析可以知道 调用的是 libaes.so 偏移 0x25f60 的函数。使用 CyberChef 的 AES CBC 算法加密得到结果和 app 的是一样的。因此,你会在目标函数执行完毕后,看到 onCallSummary 输出的调用信息。用 IDA 打开 libaes.so 并调整到对应的地址,可以找到调用的函数。
2025-03-30 04:39:06
934
原创 Android 中实现一个自定义的 AES 算法
在 LibTomCrypt 中,AES 算法的 S-Box(替代盒)是通过查找表(lookup table)实现的,而 AES 的表(如 S-Box)主要是存在于 src/cipher/aes/aes_tab.c 文件中。算法支持丰富:包括对称加密(AES、DES 等)、非对称加密(RSA、ECC 等)、哈希算法(SHA-256、MD5 等)理论上,你可以通过修改 LibTomCrypt 中的 S-Box 或其他查找表,来实现你自己的 AES 变体。
2025-03-29 04:59:51
942
原创 Android 自定义变形 HMAC 算法
HMAC(Hash-based Message Authentication Code)是一种基于哈希函数的消息认证码,用于验证数据的完整性和真实性。比如,哈希函数是 SHA256 则返回的字符串就是 32 字节(256位),通常由长度为 64 的 十六进制字符串 表示。比如,哈希函数是 MD5 则返回的字符串就是 16 字节(128位),通常由长度为 32 的 十六进制字符串 表示。HMAC-MD5 总共调用了 2 次 MD5:一次计算 InnerHash,一次计算最终的 HMAC。
2025-03-26 22:23:59
644
原创 OLLVM 增加 C&C++ 字符串加密功能
当我们如果没有对字符串进行加密,使用 IDA 反汇编一下 so 可以看到 C++ 代码中的字符串就直接暴露了。编译完成后,通过 IDA 打开 so 可以看到字符串常量 “cyrus” 已经被替换成 &unk_6DE20。processConstantStringUse() 找到所有使用加密字符串的地方,替换为解密后的变量。只要在定义的地方把字符串加密,引用时候再解密就可以实现字符串的自动加解密了。为字符串变量创建一个初始化函数,用于在运行时执行解密操作。通过生成 ir 文件可以看到字符串的定义都是 @“?
2025-03-25 20:24:13
1104
原创 Android 自定义变形 SHA1 算法
SHA1Update 用于处理输入数据。SHA1Init 是 SHA1 算法中的一个初始化函数,用于初始化 SHA1 的上下文 (SHA1_CTX),设置初始状态和计数器,为后续的哈希计算做好准备。在 SHA1 算法中,R0、R1、R2、R3、R4 是 SHA1 的五个主要轮次(Rounds),每个轮次包含 20 次操作,总共 80 次迭代。这些轮次的核心是基于位运算的消息调度和非线性函数的应用,用于将输入数据混淆并生成最终的哈希值。R4 (Round 4):最终的轮次,进一步强化数据的不可逆性。
2025-03-25 02:57:05
917
原创 Android 自定义变形 MD5 算法
在 MD5 中,FF、GG、HH 和 II 是四个核心的轮函数(Round Functions),它们负责对数据块进行不同形式的混淆和非线性操作。每一轮都包含 16 次操作,共 64 次。MD5是一种哈希函数,用于将任意长度的数据映射为一个固定长度的哈希值。在 cpp 中实现 native 方法,调用 MD5_Init、MD5_Update、MD5_Final 完成 MD5 的计算并返回结果。固定长度输出:将任意长度的数据转换为 128 位(16 字节) 的哈希值,通常以 32 位十六进制 字符串表示。
2025-03-22 01:53:56
1138
原创 使用 Unicorn 还原变异 CRC32 算法
把 LDR X8, [X19] 和 BLR X8 nop 掉,再替换成自定义的 hook 函数 get_string_utf_chars,在函数中实现自定义的 GetStringUTFChars。app 中实现一个 CRC32 算法变形,具体实现在 so 中 modifiedCRC32 函数,现在要通过 unicorn 和 IDA Pro 逆向还原 so 中的算法。直接 nop 掉就好。把 X8 存入 X29(即 FP,帧指针)的 var_8 位置,通常是局部变量或栈空间的一部分。
2025-03-18 20:39:14
806
原创 基于 Unicorn 实现一个轻量级的 ARM64 模拟器
get_string_utf_chars() 模拟了 GetStringUTFChars(),在指定内存地址写入 UTF-8 编码的字符串,并返回指针地址。代码 Hook:在 _setup_hooks() 中设置 UC_HOOK_CODE 钩子,每次执行到一条指令时触发 hook_code()。寄存器设置:提供了 set_x0()、set_x1() 和 set_x2() 等方法,用于直接设置寄存器值。内存映射:在 _setup_memory() 中分配 10MB 的代码区和 1MB 的栈区。
2025-03-18 18:34:34
378
原创 安卓实现魔改版 CRC32 算法
CRC32 Table 是通过 init_crc32_table 方法中 位移 和 异或 常量 0xedb88320 运算得来的。实现 native 方法并调用 crc32 方法进行加密并返回 hex 字符串。我们可以通过修改常量值,实现自定义 Table,比如改成 0xd76aa478。计算 CRC 时额外 XOR 0xA5A5A5A5 进一步扰动结果。创建 crc32.cpp,使用 C++ 实现标准 CRC32 算法。修改常量 0xedb88320 改为 0x82F63B78。
2025-03-13 23:43:44
687
原创 安卓逆向魔改版 Base64 算法还原
通过引用查找发现 xmmword_54C30、qword_54C40 是在 sub_23F30 方法中初始化的,sub_23F30 方法在 init_array 时被调用。customEncode 是一个 Function1<byte[], String> 类型的 函数接口,表示它是一个接受 byte[] 并返回 String 的函数。_QWORD 和 _OWORD都是 IDA Pro 反编译器使用的类型,它们不是标准的 C/C++ 关键字,而是 IDA 用于表示不同大小的数据类型。
2025-03-12 21:26:03
1792
原创 安卓实现魔改版 Base64 算法
C++ 实现 customBase64Encode 和 customBase64Decode(使用自定义 Base64 码表)。使用 XOR 值对标准 Base64 码表进行偏移,生成新的 Base64 码表。实现 native 函数并调用 C++ 中 Base64 编码和解码函数。码表基于 输入长度变化,用 异或(XOR)运算 生成新字符映射。创建 base64.cpp 实现 Base64 编码和解码。Kotlin 层中声明 native 编码和解码函数。C++ 中实现 native 编码和解码函数。
2025-03-12 21:07:16
423
原创 常用加解密算法介绍
HMAC(基于哈希的消息认证码)使用一个密钥(Key)和一个哈希函数(Hash Function),将输入消息进行加密计算,生成一个固定长度的认证码(MAC)。它提供了一系列 加密、解密、编码、解码、数据转换、压缩、哈希、取证分析 等功能,适用于安全研究、数据处理和取证分析等场景。OpenSSL 是一个开源加密库,支持 SSL/TLS 协议,实现 RSA、AES、SM2、SM4 等算法,提供加密、证书管理、哈希计算等功能,广泛用于网络安全、身份认证和数据保护。
2025-03-07 00:32:27
814
原创 unidbg 实现 JNI 与 Java 交互
再实现一个 native 方法 sign 接受一个字符串 content,将 java 层 UnidbgActivity 中 静态变量 a + content + 非静态变量 b 拼接,再调用 java 层的 base64 方法传入拼接后的字符串得到加密串作为返回值。更简单的方案,直接把反编译后的 java 类复制过来,做一下简单的修改,去掉不需要的代码,只留下目标方法相关的代码(注意:类路径一定要保持一致!对于对象中的字段,我们可以重写 getObjectField 方法类似的处理,处理逻辑也类似。
2025-03-03 10:37:50
1174
原创 unidbg 加载 so 并调用 so 中函数
unidbg 是一个基于 Java 的 Android 动态分析框架,专注于模拟 Android 应用中的 native 代码。以下是它的主要功能:支持对so的加载;支持对JNI接口函数的模拟调用;支持常见syscalls的模拟调用;支持ARM32和ARM64。支持Android以及iOS基于HookZz实现的inline hookxHook实现的hookiOS fishhook,substrate、whale hook等支持gdb、IDA远程调试等高级功能。…Unidgb 项目地址:https://git
2025-02-27 13:42:04
1336
原创 使用 AndroidNativeEmu 调用 JNI 函数
native_method 装饰器用于在 AndroidNativeEmu 中将 Python 函数标记为模拟的 JNI 原生方法,允许函数在模拟器中执行并与 Android 的原生方法交互。对应 JNI 接口的模拟实现在 src/androidemu/java/jni_env.py,通过 write_function_table 方法模拟实现 JNI 函数表。so 加载过程中,对 so 中导入符号的 Hook,具体代码在:src/androidemu/native/hooks.py。
2025-02-23 18:13:41
512
原创 使用 Unicorn 如何进行栈读写 和 Patch
struct.pack 是 Python 标准库 struct 模块中的一个函数,它用于将 Python 的基本数据类型(如 int、float、long)打包为字节流,以便在二进制文件、网络传输或内存操作(如 Unicorn 仿真器的 mem_write)中使用。在 Unicorn 中,可以通过 mem_write 方法直接修改指定地址的指令数据。例如,要将某个位置的指令替换为 NOP。<f:表示小端(<)的 4 字节浮点数(float)value:要转换的 Python 值。
2025-02-23 18:03:45
567
原创 Unicorn Hook 详解:指令、代码块、内存、系统调用等
UC_HOOK_BLOCK用于 Hook 代码块(Basic Block)执行,在 Unicorn 模拟执行时,每进入一个新的 Basic Block,都会触发 Hook 回调。默认情况下,UC_HOOK_MEM_READ 和 UC_HOOK_MEM_WRITE 会监听所有内存地址的读写。但是,你可以指定特定的内存范围来限制 Hook 的触发范围。第二次执行时崩溃,因为 SVC 指令触发了系统调用,而 Hook 已移除,没有模拟返回值,导致 CPU 异常 (UC_ERR_EXCEPTION)。
2025-02-10 00:23:31
723
空空如也
TA创建的收藏夹 TA关注的收藏夹
TA关注的人