如何从PE模块的导出表中读取名称?

时间:2009-10-14 01:37:23

标签: c# .net memory pinvoke pe-exports

我已成功读取另一个进程加载到内存中的非托管模块的PE头。我现在要做的是读取该模块的导出名称。基本上,这是我到目前为止(我已经省略了大部分的PE解析代码,因为我已经知道它有效):

扩展

public static IntPtr Increment(this IntPtr ptr, int amount)
{
    return new IntPtr(ptr.ToInt64() + amount);
}

public static T ToStruct<T>(this byte[] data)
{
    GCHandle handle = GCHandle.Alloc(data, GCHandleType.Pinned);
    T result = (T)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(T));
    handle.Free();
    return result;
}

public static byte[] ReadBytes(this Process process, IntPtr baseAddress, int size)
{
    int bytesRead;
    byte[] bytes = new byte[size];
    Native.ReadProcessMemory(process.Handle, baseAddress, bytes, size, out bytesRead);
    return bytes;
}

public static T ReadStruct<T>(this Process process, IntPtr baseAddress)
{
    byte[] bytes = ReadBytes(process, baseAddress, Marshal.SizeOf(typeof(T)));
    return bytes.ToStruct<T>();
}

public static string ReadString(this Process process, IntPtr baseAddress, int size)
{
    byte[] bytes = ReadBytes(process, baseAddress, size);
    return Encoding.ASCII.GetString(bytes);
}

GetExports()

Native.IMAGE_DATA_DIRECTORY dataDirectory =
    NtHeaders.OptionalHeader.DataDirectory[Native.IMAGE_DIRECTORY_ENTRY_EXPORT];

if (dataDirectory.VirtualAddress > 0 && dataDirectory.Size > 0)
{
    Native.IMAGE_EXPORT_DIRECTORY exportDirectory =
        _process.ReadStruct<Native.IMAGE_EXPORT_DIRECTORY>(
            _baseAddress.Increment((int)dataDirectory.VirtualAddress));

    IntPtr namesAddress = _baseAddress.Increment((int)exportDirectory.AddressOfNames);
    IntPtr nameOrdinalsAddress = _baseAddress.Increment((int)exportDirectory.AddressOfNameOrdinals);
    IntPtr functionsAddress = _baseAddress.Increment((int)exportDirectory.AddressOfFunctions);

    for (int i = 0; i < exportDirectory.NumberOfFunctions; i++)
    {
        Console.WriteLine(_process.ReadString(namesAddress.Increment(i * 4), 64));
    }
}

当我运行它时,我得到的只是双重问号的模式,然后是完全随机的字符。我知道正确读取标头,因为签名是正确的。问题在于我在迭代函数列表的方式。

1 个答案:

答案 0 :(得分:1)

this link处的代码似乎暗示名称和序数形成一对匹配的数组,计数到NumberOfNames,并且函数是分开的。所以你的循环可能迭代次数错误,但这并不能解释你从一开始就看到坏字符串的原因。

对于只打印名称,我已经成功完成了如下所示的循环。我认为调用ImageRvaToVa可能是您获取正确字符串所需的内容?但是我不知道该函数是否会起作用,除非您通过调用MapAndLoad实际加载了图像 - 这就是文档所要求的,并且映射似乎在我使用的一些快速实验中不起作用{ {1}}而不是。

这是pInvoke声明:

LoadLibrary

这是我的主循环:

    [DllImport("DbgHelp.dll", CallingConvention = CallingConvention.StdCall), SuppressUnmanagedCodeSecurity]
    public static extern IntPtr ImageRvaToVa(
        IntPtr NtHeaders,
        IntPtr Base,
        uint Rva,
        IntPtr LastRvaSection);