2

別のプロセスによってメモリにロードされたアンマネージ モジュールから 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));
    }
}

これを実行すると、二重の疑問符のパターンと完全にランダムな文字だけが得られます。署名が正しいため、ヘッダーが正しく読み取られていることがわかります。問題は、関数リストを繰り返し処理する方法にあります。

4

1 に答える 1

2

このリンクのコードは、名前と序数が対応する配列のペアを形成し、NumberOfNames までカウントされ、関数が分離されていることを示唆しているようです。そのため、ループの反復回数が間違っている可能性がありますが、最初から悪い文字列が表示される理由は説明できません。

名前を印刷するだけで、以下に示すようなループで成功しています。ImageRvaToVaへの呼び出しは、正しい文字列を取得するために必要なものだと思いますか? ただし、呼び出して実際に画像を読み込んでいない限り、その関数が機能するかどうかはわかりませんMapAndLoad-それがドキュメントの要求であり、代わりに使用したいくつかの簡単な実験ではマッピングが機能しないようでしたLoadLibrary.

pInvoke 宣言は次のとおりです。

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

ここに私のメインループがあります:

               LOADED_IMAGE loadedImage = ...; // populated with MapAndLoad
               IMAGE_EXPORT_DIRECTORY* pIID = ...; // populated with ImageDirectoryEntryToData

                uint* pFuncNames = (uint*)
                    ImageRvaToVa(
                        loadedImage.FileHeader,
                        loadedImage.MappedAddress, 
                        pIID->AddressOfNames, 
                        IntPtr.Zero);

                for (uint i = 0; i < pIID->NumberOfNames; i++ )
                {
                    uint funcNameRVA = pFuncNames[i];
                    if (funcNameRVA != 0)
                    {
                        char* funcName =
                                (char*) (ImageRvaToVa(loadedImage.FileHeader,
                                   loadedImage.MappedAddress, 
                                   funcNameRVA, 
                                   IntPtr.Zero));
                        var name = Marshal.PtrToStringAnsi((IntPtr) funcName);
                        Console.WriteLine("   funcName: {0}", name);
                    }
                }
于 2010-12-31T22:08:00.623 に答える