使用<privateimplementationdetails>和hasfieldrva

时间:2019-01-02 20:56:28

标签: c# .net windows

我正在尝试重写一个小型的旧应用程序,该源代码不再可用。

使用IDA分解了代码,我遇到了以下CIL,该CIL用于创建和初始化长度为16的字节数组。

ldc.i4.s 0x10
newarr   [mscorlib]System.Byte
dup
ldtoken  valuetype __StaticArrayInitTypeSize=16 <PrivateImplementationDetails>::'1FE209881344DB101FDBBF280BC13B2AA4C8CFCA'
call     void [mscorlib]System.Runtime.CompilerServices.RuntimeHelpers::InitializeArray(class [mscorlib]System.Array, valuetype [mscorlib]System.RuntimeFieldHandle)

我不了解初始化,即初始化数组的值。查找<PrivateImplementationDetails>::'1FE209881344DB101FDBBF280BC13B2AA4C8CFCA'会导致以下CIL:

.class private auto sealed ansi <PrivateImplementationDetails> extends [mscorlib]System.Object
                                        // DATA XREF: WindowsService.Program__DecryptFile+9↑o
                                        // WindowsService.Program__DecryptFileToFile+A↑o
{
  .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = (
   01 00 00 00) // ....
  .field assembly static initonly hasfieldrva valuetype __StaticArrayInitTypeSize=16 '1FE209881344DB101FDBBF280BC13B2AA4C8CFCA' // RVA = 00003E98
}

.class nested private explicit sealed ansi __StaticArrayInitTypeSize=16 extends [mscorlib]System.ValueType
{
    .pack 1
}

具有CIL的高级知识的任何人都可以告诉该数组初始化什么值吗?特别是hasfieldrva指的是什么?

1 个答案:

答案 0 :(得分:1)

FieldAttributes.HasFieldRVA状态的XML文档(重点是我的):

  

指定该字段具有相对虚拟地址(RVA)。 RVA是方法主体在当前图像中的位置,是相对于它所在的图像文件的开头的地址。

这似乎是一种通过将数组在其内存中布局中以特定偏移量插入可执行映像的方式,将原始类型的数组快速初始化为静态数组字段的技术。

RVA = 00003E98告诉您该偏移量是多少。 RuntimeHelpers::InitializeArray是一种internalcall方法,仅复制位。 严格的反汇编程序(例如IDA或ILDASM)不会告诉您这些值。

要获取值,您至少需要两个三个选项。

1。为工作使用更好的工具

IDA似乎更适合调试和本机可执行文件反汇编。它的IL输出类似于ILDASM的输出,它的输出与输出一样低。

ILSpy和类似工具将显示初始化值。您应该能够直接在反编译窗口中复制字段的声明和初始化。

看看在.NET 4.7.2中,System.Char的类型初始化器如何初始化categoryForLatin1字段。 IL视图几乎与您的示例相同。 C#视图与您在源代码中看到的视图非常接近-除了System.Char的{​​{3}}使用常量之外。反编译器无法知道每个值在源中使用了哪个常数,但是只要稍作研究和直觉,您就可以自己实现目标。

实际上,如果这是一个完全托管的程序集,那么这样的工具对于整个逆向工程来说将是更好的选择,因为它将为您提供C#输出。手动将IL转换为C#可能很有趣...直到不是那样。

2。在运行时检索字段

不运行程序本身,您可以询问它的值是什么。

创建一个新的控制台应用程序,并添加对可执行文件的引用。获取有问题的字段的FieldInfo对象,然后在其上调用GetValue(null)。然后迭代返回的数组并输出值,最好将其格式化,以便您可以简单地将其复制/粘贴到新项目中。

FieldInfo field = typeof(WindowsService.Program.DecryptFileToFile).GetField("<field name>", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
byte[] array = (byte[])field.GetValue(null);

foreach (byte value in array)
{
    Console.Writeline("0x{0:X2}", value);
}

这假设我正确地理解了类结构,并且DecryptFileToFile嵌套类型是public。如果不是,那么您需要做一些额外的反思工作。

3。直接读取可执行文件(奖励选项)

您可能可以查看文件本身中的偏移量,并查看这16个字节是什么。 IDA应该让您跳至该偏移量并查看那里的数据。我不知道IDA,但是对于任何调试器来说,这似乎是一个相当基本的工具。

坦率地说,我对这个选项并不完全有信心,但是如果我不提的话,我会感到很失落。如果另外两个选项对您不可用,并且产生了有意义的数据,那么我就不高兴了。

编辑:我尝试查看磁盘上文件的偏移量,但数据不存在。它必须引用加载到内存中的偏移量。

新3. ILDASM 确实为您提供了字节

也许IDA也可以。你只需要知道去哪里找。 .field指令的末尾有一个标签at I_xxxxxxxx。这是System.Char::categoryForLatin1

.field static assembly initonly valuetype
    '<PrivateImplementationDetails>'/'__StaticArrayInitTypeSize=256' B53A2C6DF21FC88B17AEFC40EB895B8D63210CDF
    at I_004E49CC

稍后,在文件中,您会看到一个.data指令,该指令带有定义原始字节的相同标签:

.data cil I_004E49CC = bytearray (
    0E 0E 0E 0E 0E 0E 0E 0E
    // and so on for another 248 bytes
    )