.NET Reactor 4.0 - Metadata 手工修复记

来源:互联网 发布:js统计人数 编辑:程序博客网 时间:2024/05/29 15:13

.NET Reactor 4.0 (Beta) 相对于以前的版本有很大的提升,就连最常用的 "Suppress ILDASM" 都升级成 "Suppress Decompilation / Anti ILDASM"。本文就是用这个功能做案例,来锻炼自己对元数据表结构的认知。

1. 加密

找个目标程序集,用 4.0 加密,注意不要选择其他选项,仅选中 "Quick Settings" 中的 "Anti ILDASM" 即可。因为本文的目的是手工修复元数据表,而不是为了完成一个破解过程。

当我们用 .NET Reflector 或者 Mono Cecil 打开这个加密的程序都会发现出错,可见还是具有一定的防护能力的。接下来,我们就依照 .NET Reflector 给出的错误信息开始手工修复过程。

2. 修复

先准备好相应的工具软件,包括 CFF Explorer VII、ILDASM (修改版)、计算器 (16进制计算),以及一个随手记录信息的记事本。

(1) NumberOfRvaAndSizes

uploads/200906/13_144752_1.png



这个错误通常是 Optional Header 中的 NumberOfRvaAndSizes 被修改造成的,其实际值应该是 0x00000010 (16)。修改保存,刷新 Reflector,继续下一个错误信息。

(2) NumberOfStreams

uploads/200906/13_144758_2.png



这也是一个比较常见的手段,通过造成错误的 MetaData Streams 来达到干扰目的。

uploads/200906/13_144804_3.png



多了一个冒牌的 #GUlD 和 #Blop。没关系,将后面正确的 Offset 和 Size 值拷贝到山寨货的位置,同时在 Hex Editor 中跳转到到相应的 Offset 位置,修正这两个冒牌货的名字。

uploads/200906/13_144810_4.png



当然,别忘了在 MetaData Header 中将 NumberOfStreams 从 0007 改成 0005。保存后在 CFF Explorer VII 中重新打开目标文件。再次浏览 MetaData Streams 时,#Strings、#GUID、#US 和 #Blob 数据都恢复正常。

(3) Multiple Assembly Definitions

刷新 Reflector 继续下一个错误信息。

uploads/200906/13_144825_5.png



晕~~~~ 这个太变态了,居然包含多个程序集。这显然是动了 #~ Stream 了。

uploads/200906/13_144831_6.png



在 Tables 中我们果然看到了多出的这个破坏分子。怎么办呢?先复习一下 Metadata 结构知识。#~ 中前 24 bytes 存储了 Metadata Header 信息。从 0x00000018 (Offset 24) 开始存储的是 Rows 信息,也就是你在 Tables 中看到的各种类型统计数字。Rows 的长度是 4 * n。

uploads/200906/13_155101_11.png



我们数数看,一共 15 种类型,也就是说长度是 60 (0x3c),偏移位置应该是 0x00000018 ~ 0x00000053。Assembly 的索引序号是 11 (从0开始),偏移位置就是 0x00000018 + 11 * 4 = 0x00000044。在 CFF Explorer VII 中的 #~ 右侧 16 进制编辑器中将 Row 值 从 02 改成 01。

uploads/200906/13_144837_7.png



注意,事情并没有结束。在 Rows 之后,也就是 0x00000054 开始存储的是各种具体类型细节信息的 Tables,我们修改了 Row 值,也就意味着 Tables 连续读取的 Index 和 Offset 也会发生变化,因此我们需要将后续数据前移 4 byte,覆盖被剔除的那个伪造 Assembly 数据。

首先得获取伪造 Assembly 详细信息的偏移量。由于这次的偏移量计算涉及到不同具体类型信息的长度,因此我们借助 ILDASM 来获得相应数据。用 ILDASM 打开目标文件,在 View -> MetaInfo 菜单中选中 Raw:Header,Schema,Rows 和 Raw:Heaps 两项。然后 Ctrl + M 查看元数据信息。

===========================================================Metadata section: 0x424a5342, version: 1.1, extra: 0, version len: 12, version: v2.0.50727           flags: 0x00, streams: 5Stream 0: name: #~, size 1040Stream 1: name: #Strings, size 1448Stream 2: name: #GUID, size 32Stream 3: name: #US, size 216Stream 4: name: #Blob, size 444Metadata header: 2.0, heaps: 0x00, rid: 0x01, valid: 0x000003092000d557, sorted: 0x0000000000000000Strings: 1448(0x5a8), Blobs: 444(0x1bc), Guids: 32(0x20), User strings: 216(0xd8)=================================================...32(0x20): Assembly             cRecs:    2(0x2), cbRec: 22(0x16), cbTable:    44(0x2c)  col  0:  HashAlgId    oCol: 0, cbCol:4, ULONG    col  1:  MajorVersion oCol: 4, cbCol:2, USHORT   col  2:  MinorVersion oCol: 6, cbCol:2, USHORT   col  3:  BuildNumber  oCol: 8, cbCol:2, USHORT   col  4:  RevisionNumber oCol: a, cbCol:2, USHORT   col  5:  Flags        oCol: c, cbCol:4, ULONG    col  6:  PublicKey    oCol:10, cbCol:2, blob     col  7:  Name         oCol:12, cbCol:2, string   col  8:  Locale       oCol:14, cbCol:2, string -------------------------------------------------   1 == 0:00008004, 1:0001, 2:0000, 3:0000, 4:0000, 5:00000000, 6:blob#0, 7:string#1, 8:string#0   2 == 0:00008004, 1:0001, 2:0000, 3:0000, 4:0000, 5:00000000, 6:blob#0, 7:string#6, 8:string#0...


嗯,很好,有个 04 80 00 00 的标记,我们找到这个位置就行了。继续在编辑器中工作,找到第二个标记位置(0x000003AE),往后数出 22(0x16) 个字节(0x000003AE ~ 0x000003C3),这就是我们要覆盖的数据。选择 0x000003C4 开始的数据,以 Unicode 方式拷贝,并 Write 到 0x000003AE 处。

拷贝

uploads/200906/13_144842_8.png



写入

uploads/200906/13_144848_9.png



保存修改 (注意关掉 ILDASM,否则无法保存)。刷新 Reflector,可以看到该错误被修复。

(4) Multiple Module Definitions

这个错和上面的如出一辙,修复手段也一样。

uploads/200906/13_144854_10.png



先修改 Rows 值,Module 是第一项,偏移位置就是 0x00000018,将其修改为 01 即可 (先别保存,否则 ILDASM 无法打开)。

... 0(0): Module               cRecs:    2(0x2), cbRec: 10(0xa), cbTable:    20(0x14)  col  0:  Generation   oCol: 0, cbCol:2, USHORT   col  1:  Name         oCol: 2, cbCol:2, string   col  2:  Mvid         oCol: 4, cbCol:2, GUID     col  3:  EncId        oCol: 6, cbCol:2, GUID     col  4:  EncBaseId    oCol: 8, cbCol:2, GUID   -------------------------------------------------   1 == 0:0000, 1:string#2b, 2:guid#1, 3:guid#0, 4:guid#0   2 == 0:0000, 1:string#0, 2:guid#2, 3:guid#0, 4:guid#0...


记录长度为 10(0xa),那么第二条记录的偏移位置就是 0x00000054 + 0xa = 0x0000005E。数出 10 bytes (0x0000005E ~ 0x00000067),将其后的数据按照前面的手法前移覆盖(顺便说一下 CFF Exploer VII 的编辑器不太好用,可能需要多次拷贝覆盖,千万记住上次覆盖的结束位置,避免出错)。

保存修改。再次用 Reflector 刷新程序集时,我们已经可以看到其原始面目了,表明我们的修复工作顺利完成。

------- 分割线 --------------

最简单的修复手法是 ILDasm + ILAsm,不过本文的目的是为了复习元数据的相关知识,因此手工修复可以加强对相关知识的了解。同时该文章也表明很多看上去貌似高深的技术,其根本还是对基础知识的掌握,当然少不了耐心和细心。

附件是修复前的原始加密文件,大家可以据此练习本文操作过程。而有关 Metadata 结构定义可以到 ECMA C# and Common Language Infrastructure Standards 下载 MS Partition II。

点击下载原始加密文件 (重新加密的,和上面演示的数据有出入)

原创粉丝点击