迭代器变量的值不会改变?

时间:2014-08-25 22:57:33

标签: c# marshalling unmanaged

已解决 - >请看下面的答案

好的,这将是我的第一个问题,所以如果我对问题本身犯了一些错误,请指出,我会尝试修复它。

我正在尝试学习如何使托管和非托管代码进行互操作,因此作为一个学习项目,我尝试使用C#从内存中转储notepad.exe的IAT表。

所以,给出以下代码:

protected void DumpEntries_IAT()
{
    List<string> importedFunctions = new List<string>();
    int sizeOfEntry = Marshal.SizeOf(new PEHeaders.ImageImportDescriptor());
    long numberOfEntries = peHeaders.OptionalHeader64.IAT.Size/sizeOfEntry - 1; // Last entry is empty.
    Console.WriteLine("Number of IAT entries: {0}", numberOfEntries);
    Console.ReadKey(true);
    int bytesRead = 0;
    Console.WriteLine(peHeaders.OptionalHeader64.IAT.VirtualAddress.ToString("X"));
    for(int i = 0; i < numberOfEntries; i++)
    {
        byte[] buffer = new byte[sizeOfEntry];
        ReadProcessMemory64(processHandle.ToInt64(), process.MainModule.BaseAddress.ToInt64() + peHeaders.OptionalHeader64.IAT.VirtualAddress + i*sizeOfEntry, buffer, buffer.Length, ref bytesRead);
        PEHeaders.ImageImportDescriptor entry = new PEHeaders.ImageImportDescriptor();
        entry = UnmanagedInterop.FromBytes<PEHeaders.ImageImportDescriptor>(buffer);
        ReadProcessMemory64(processHandle.ToInt64(), process.MainModule.BaseAddress.ToInt64() + i*sizeOfEntry + entry.OriginalFirstThunk, buffer, buffer.Length, ref bytesRead);
        PEHeaders.ImageThunkData thunkData = new PEHeaders.ImageThunkData();
        buffer = new byte[Marshal.SizeOf(thunkData)];
        ReadProcessMemory64(processHandle.ToInt64(), process.MainModule.BaseAddress.ToInt64() + entry.OriginalFirstThunk, buffer, buffer.Length, ref bytesRead);
        thunkData = UnmanagedInterop.FromBytes<PEHeaders.ImageThunkData>(buffer);
        Console.WriteLine("Address of ImageImportByName is {0}", thunkData.AddressOfData.ToString("X"));
        Console.WriteLine("i= {0}", i);
        Console.ReadKey(true); // Since the value of i stays zero, it's effectively an infinite loop, so I had to add that to actually read the output.
    }
}

我得到以下结果:

Dumping IAT...
Number of IAT entries: 90
1D000
Address of ImageImportByName is 0
i= 0
Address of ImageImportByName is 100001
i= 0
Address of ImageImportByName is 100001
i= 0
Address of ImageImportByName is 100001
i= 0
Address of ImageImportByName is 100001
i= 0
Address of ImageImportByName is 100001
i= 0

从输出中可以看出,变量i似乎总是具有零值,即使它应该在每次迭代结束时增加。由于代码多次运行,循环本身似乎有点工作。

我试过四处寻找,但我并没有找到任何相关的东西,我无法弄清楚发生了什么。即使我尝试使用非托管代码和内存(同时涉及ReadProcessMemory和Marshal.PtrToStructure),i是一个本地托管变量,只应存在于for的范围内循环,它的值在其他任何地方的代码中都没有改变,而是由`i ++&#39;循环中的指令。

任何想法可能是导致这种行为的原因吗?

注意:我尝试在for声明之外创建一个迭代器变量,并在循环结束时使用指令i++i += 1进行更改,但它仍然保持为零。

1 个答案:

答案 0 :(得分:0)

好吧,事实证明我只是愚蠢。

我使用32位C示例为ReadProcessMemory设置DLLImport:

[DllImport("kernel32.dll", EntryPoint="ReadProcessMemory")]
protected static extern bool ReadProcessMemory64(Int64 hProcess, Int64 lpBaseAddress, byte[] lpBuffer, int dwSize, ref int lpNumberOfBytesRead);

正如您所看到的,我已将输入参数的某些的uint(32位)decalaration(如lpBaseAddress(因为我的系统是64位))更改为Int64以使其适合。 ..但忘了别人!

现在,我按此顺序声明变量:

int bytesRead = 0; // 32 bits of data...
for(int i = 0; // <-- Another 32 bit integer, *just right next* to bytesRead in the memory...

然后调用ReadProcessMemory:

ReadProcessMemory64(processHandle, memoryAddress, buffer, buffer.Length, ref bytesRead);

最后一个参数是关键。事实证明,64位RPM需要一个指向64位整数的指针,并且我向它传递了一个指向32位的指针。由于不受管理,它为该地址写了一个64位整数,没有任何错误。这意味着64位整数的一半会覆盖内存中readBytes旁边的下一个32位,这恰好是i变量。

ReadProcessMemory应该更像这样:

[DllImport("kernel32.dll", EntryPoint="ReadProcessMemory")]
protected static extern bool ReadProcessMemory64(Int64 hProcess, Int64 lpBaseAddress, byte[] lpBuffer, Int64 dwSize, ref Int64 lpNumberOfBytesRead);

readBytes当然应该是Int64。问题解决了。