已解决 - >请看下面的答案
好的,这将是我的第一个问题,所以如果我对问题本身犯了一些错误,请指出,我会尝试修复它。
我正在尝试学习如何使托管和非托管代码进行互操作,因此作为一个学习项目,我尝试使用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
进行更改,但它仍然保持为零。
答案 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
。问题解决了。