关于 reversing-xamarin-maui
用于逆向分析 Xamarin 或 .NET MAUI 构建的 Android 和 iOS 应用的技能。它介绍如何识别并提取打包的 .NET 程序集、检查还原出的 C#,以及在分析应用行为时使用支持 Mono 的运行时钩子。
主要功能
- 01识别 Xamarin 打包格式世代
- 02提取 AssemblyStore 与 XALZ 程序集
- 03将 DLL 反编译为可读 C#
- 04使用 Frida Hook Mono 方法
- 05检查应用中的密钥与逻辑
- 06修补并重新打包程序集
适用场景
- 01分析 Xamarin APK 或 IPA
- 02查找应用程序集中的嵌入凭据
- 03在运行时观察托管方法
- 04修改并重建应用包
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ trilwu/ secskills --skill reversing-xamarin-maui安装后在 Claude Code 中输入/reversing-xamarin-maui确认已加载。
详细介绍
逆向 Xamarin 和 .NET MAUI 应用
Xamarin 应用会在 Android 包中隐藏一个完整的 .NET 应用。提取并解压程序集后,你就能得到接近源代码质量的 C#,因此这是回报率最高的逆向工作之一——但前提是你能处理容器格式;这种格式曾两度变更,简单解压无法奏效。
适用情况
- APK 包含
lib/*/libmonodroid.so、libmonosgen-2.0.so或libxamarin-app.so - APK 包含
assemblies/assemblies.blob或assemblies/*.dll jadx只显示mono.MonoPackageManager和 Xamarin 引导类- IPA 包含
.dll文件或Frameworks/Mono*布局 - 目标应用被描述为 Xamarin、Xamarin.Forms 或 .NET MAUI
不适用情况
- Unity(
global-metadata.dat、libil2cpp.so)——使用reversing-unity-il2cpp; Unity 同样基于 .NET,但采用完全不同的打包方式 - Flutter 或 React Native——使用
reversing-flutter-apps或reversing-react-native-apps - TLS 拦截问题——使用
bypassing-mobile-pinning - 更广泛的评估——使用
testing-mobile-applications
识别打包代际
该产品生命周期内使用过三种格式,提取方式各不相同。
unzip -l target.apk | rg 'assemblies|libmonodroid|libxamarin|libmonosgen'
| 看到的内容 | 代际 | 提取方式 |
|---|---|---|
assemblies/*.dll,可读的 PE 标头(MZ) | 经典、未压缩 | 解压并直接反编译 |
assemblies/*.dll,以 XALZ 开头 | 经典、LZ4 压缩 | 先解压 XALZ 封装 |
assemblies/assemblies.blob + .manifest | AssemblyStore | 使用 pyxamstore 解包 |
lib/*/libxamarin-app.so,没有 assemblies/ | .NET 6+ / MAUI,程序集位于 ELF 中 | 从共享库中提取 |
| 找不到任何托管程序集 | NativeAOT | 不属于 .NET 逆向——使用 analyzing-binaries |
# Which one is it? Check the first four bytes of an assembly
unzip -p target.apk 'assemblies/Mono.Android.dll' 2>/dev/null | xxd | head -1
# 4d5a... → MZ, a plain .NET PE, decompile now
# 58414c5a → "XALZ", LZ4-compressed, decompress first
提取
# AssemblyStore (assemblies.blob)
pyxamstore unpack -d ./out target.apk
# produces the individual .dll files under ./out
# XALZ-compressed individual DLLs
# The header is: magic "XALZ" | descriptor index | uncompressed size | LZ4 block
python3 -c "
import lz4.block, struct, sys
d = open(sys.argv[1],'rb').read()
assert d[:4] == b'XALZ'
size = struct.unpack('<I', d[8:12])[0]
open(sys.argv[2],'wb').write(lz4.block.decompress(d[12:], uncompressed_size=size))
" Mono.Android.dll Mono.Android.decompressed.dll
# MAUI / .NET 6+ assemblies embedded in libxamarin-app.so
# They are stored as sections; carve by MZ header or use pyxamstore's newer modes
unzip -j target.apk 'lib/arm64-v8a/*' -d libs && binwalk -Me libs/libxamarin-app.so
拿到普通的 .dll 文件后,后续就是常规的 .NET 工作:
ilspycmd ./out/YourApp.dll -o ./decompiled # or dnSpy / dnSpyEx / dotPeek
rg -n 'https?://|ApiKey|ConnectionString|Bearer|password' ./decompiled | head -40
从应用自身的程序集开始,不要先看框架程序集。它通常以产品命名;Mono.Android.dll、System.* 和 Xamarin.* 都是标准程序集,会浪费你的时间。
运行时挂钩
Frida 的 Java 桥接无法看到 Mono 方法——应用逻辑不在 JVM 中。你需要使用能够识别 Mono 的插桩方式。
# Enumerate the Mono runtime and its loaded assemblies
frida -U -f com.target.app -l frida-mono-api.js
# Fridax targets Xamarin specifically; also useful:
# mono_get_root_domain, mono_assembly_foreach, mono_class_get_methods,
# mono_compile_method → resolve a managed method to a native address, then
# Interceptor.attach at that address
实用做法是:先反编译,找到目标类和方法的确切位置,然后通过 Mono API 解析并挂钩。盲目挂钩 Mono 远不如直接阅读你已还原的 C#。
Xamarin 中的证书验证位于托管代码中,因此通用的 Android Pinning 绕过方法完全无法覆盖它:
// The two hook targets, both in the managed layer
ServicePointManager.ServerCertificateValidationCallback
HttpClientHandler.ServerCertificateCustomValidationCallback
通过 Mono 挂钩强制让这些方法返回 true,或修补程序集后重新打包。周边诊断请参阅 bypassing-mobile-pinning。
发现所在之处
Xamarin 应用中的风险往往集中在以下位置,反编译后很容易发现:
- C# 中硬编码的机密。 开发者以为编译后的程序集不可读;API 密钥、连接字符串和存储凭据都以纯 IL 形式随应用发布。
- 客户端中包含完整的后端逻辑。 移动应用与服务器端项目共用代码是 Xamarin 的惯例,因此客户端往往包含权威业务规则——有时还包括服务器自身的模型和验证逻辑,能准确告诉你如何构造恶意请求。
- 自定义
ServerCertificateValidationCallback返回true。 这种情况常见于最终发布的开发构建。 - 不安全的本地存储。
Xamarin.Essentials.SecureStorage通常没问题;Preferences和直接写入原始文件则不安全。 - 嵌入式 SQLite,其中存有凭据或完整的离线数据集。
修补和重新打包
# Edit IL directly in dnSpy, save the assembly, then rebuild the container
pyxamstore pack -d ./out # rebuild assemblies.blob
apktool b target -o patched.apk && apksigner sign --ks debug.keystore patched.apk
重新打包必须精确复现原始容器格式——加载器需要 XALZ 时却提供未压缩的 DLL,或 Blob 大小不正确,都会导致应用启动时发生难以诊断的原生崩溃。如果只需观察,优先使用运行时挂钩。
应当避免的错误判断
- “jadx 什么都没找到,所以它经过了混淆。” dex 中什么都没有。应用位于
assemblies/中。 - “解压后得到了 DLL,但 dnSpy 拒绝打开。” 它们经过 XALZ 压缩。检查前四个字节。
- “Frida 的 Java 钩子不起作用。” 这些方法是 Mono 方法,不是 JVM 方法。请使用 Mono API。
- “它编译成了 DLL,所以密钥是安全的。” IL 可以反编译成可读的 C#。应将每个程序集常量都视为公开信息。
- “绕过固定验证已运行,但流量仍然失败。” Xamarin 在托管代码中进行验证;Java 层的绕过从未触及它。
- “程序集有数百个。” 大多数都是标准框架程序集。读取以产品命名的那个。
参考资料
testing-mobile-applications— 更广泛的评估和平台存储bypassing-mobile-pinning— 诊断此处的拦截故障reversing-unity-il2cpp— 另一种基于 .NET 的移动框架analyzing-binaries— 不含托管程序集的 NativeAOT 构建- pyxamstore、dnSpy/dnSpyEx、ILSpy、Fridax、frida-mono-api