mcpField
R
reversing-xamarin-maui

reversing-xamarin-maui

github.com/trilwu安全17748 次安装12 周前更新
代码仓库

关于 reversing-xamarin-maui

用于逆向分析 Xamarin 或 .NET MAUI 构建的 Android 和 iOS 应用的技能。它介绍如何识别并提取打包的 .NET 程序集、检查还原出的 C#,以及在分析应用行为时使用支持 Mono 的运行时钩子。

主要功能

  1. 01识别 Xamarin 打包格式世代
  2. 02提取 AssemblyStore 与 XALZ 程序集
  3. 03将 DLL 反编译为可读 C#
  4. 04使用 Frida Hook Mono 方法
  5. 05检查应用中的密钥与逻辑
  6. 06修补并重新打包程序集

适用场景

  1. 01分析 Xamarin APK 或 IPA
  2. 02查找应用程序集中的嵌入凭据
  3. 03在运行时观察托管方法
  4. 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 + .manifestAssemblyStore使用 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

评论

支持 Markdown