return bool(real rate of return= = x.real rate of return&& image = = x.image);

.net - How to programatically read native DLL imports in C#? - Stack Overflow
to customize your list.
Stack Overflow is a community of 4.7 million programmers, just like you, helping each other.
J it only takes a minute:
Join the Stack Overflow community to:
Ask programming questions
Answer and help your peers
Get recognized for your expertise
How can I programatically analyze a native DLL to read its imports?
[EDIT: my original question looked like the following, along with a huge chunk of defective code.
Please see answers below for more correct code.]
The C# code located at
is intended to print the imports of a native DLL.
I find that when I run the sample code with the original example's target, MSCOREE.DLL, it prints all the imports fine.
But when I use other dlls like GDI32.DLL or WSOCK32.DLL the imports do not get printed.
What's missing from this code that would let it print all the imports as, for example, DUMPBIN.EXE does?
7,21484283
There is one very big problem in the code (namely the definition of THUNK_DATA) and various other smaller problems mostly concerning end-of-table detection (using IsBadReadPtr instead of NULL checks, and also not adding base address as needed).
Here is a fixed version that produces the same output as dumpbin at least for wsock32:
using System.Runtime.InteropS
using System.S
namespace PETest2
[StructLayout(LayoutKind.Explicit)]
public unsafe struct IMAGE_IMPORT_BY_NAME
[FieldOffset(0)]
public ushort H
[FieldOffset(2)]
public fixed char Name[1];
[StructLayout(LayoutKind.Explicit)]
public struct IMAGE_IMPORT_DESCRIPTOR
#region union
/// &summary&
/// CSharp doesnt really support unions, but they can be emulated by a field offset 0
/// &/summary&
[FieldOffset(0)]
public uint C
// 0 for terminating null import descriptor
[FieldOffset(0)]
public uint OriginalFirstT
// RVA to original unbound IAT (PIMAGE_THUNK_DATA)
#endregion
[FieldOffset(4)]
public uint TimeDateS
[FieldOffset(8)]
public uint ForwarderC
[FieldOffset(12)]
public uint N
[FieldOffset(16)]
public uint FirstT
[StructLayout(LayoutKind.Explicit)]
public struct THUNK_DATA
[FieldOffset(0)]
public uint ForwarderS
[FieldOffset(0)]
public uint F
[FieldOffset(0)]
public uint O
[FieldOffset(0)]
public uint AddressOfD
// PIMAGE_IMPORT_BY_NAME
public unsafe class Interop
#region Public Constants
public static readonly ushort IMAGE_DIRECTORY_ENTRY_IMPORT = 1;
#endregion
#region Private Constants
#region CallingConvention CALLING_CONVENTION
/// &summary&
Specifies the calling convention.
/// &/summary&
/// &remarks&
Specifies &see cref="CallingConvention.Winapi" /& for Windows to
indicate that the default should be used.
/// &/remarks&
private const CallingConvention CALLING_CONVENTION = CallingConvention.W
#endregion CallingConvention CALLING_CONVENTION
#region IMPORT DLL FUNCTIONS
private const string KERNEL_DLL = "kernel32";
private const string DBGHELP_DLL = "Dbghelp";
#endregion
#endregion Private Constants
[DllImport(KERNEL_DLL, CallingConvention = CALLING_CONVENTION, EntryPoint = "GetModuleHandleA"), SuppressUnmanagedCodeSecurity]
public static extern void* GetModuleHandleA(/*IN*/ char* lpModuleName);
[DllImport(KERNEL_DLL, CallingConvention = CALLING_CONVENTION, EntryPoint = "GetModuleHandleW"), SuppressUnmanagedCodeSecurity]
public static extern void* GetModuleHandleW(/*IN*/ char* lpModuleName);
[DllImport(KERNEL_DLL, CallingConvention = CALLING_CONVENTION, EntryPoint = "IsBadReadPtr"), SuppressUnmanagedCodeSecurity]
public static extern bool IsBadReadPtr(void* lpBase, uint ucb);
[DllImport(DBGHELP_DLL, CallingConvention = CALLING_CONVENTION, EntryPoint = "ImageDirectoryEntryToData"), SuppressUnmanagedCodeSecurity]
public static extern void* ImageDirectoryEntryToData(void* Base, bool MappedAsImage, ushort DirectoryEntry, out uint Size);
static class Foo
// From winbase.h in the Win32 platform SDK.
const uint DONT_RESOLVE_DLL_REFERENCES = 0x;
const uint LOAD_IGNORE_CODE_AUTHZ_LEVEL = 0x;
[DllImport("kernel32.dll"), SuppressUnmanagedCodeSecurity]
static extern uint LoadLibraryEx(string fileName, uint notUsedMustBeZero, uint flags);
public static void Main()
//var path = @"c:\windows\system32\mscoree.dll";
//var path = @"c:\windows\system32\gdi32.dll";
var path = @"c:\windows\system32\wsock32.dll";
var hLib = LoadLibraryEx(path, 0,
DONT_RESOLVE_DLL_REFERENCES | LOAD_IGNORE_CODE_AUTHZ_LEVEL);
TestImports(hLib, true);
// using mscoree.dll as an example as it doesnt export any thing
// so nothing shows up if you use your own module.
// and the only none delayload in mscoree.dll is the Kernel32.dll
private static void TestImports(uint hLib, bool mappedAsImage)
//fixed (char* pszModule = "mscoree.dll")
//void* hMod = Interop.GetModuleHandleW(pszModule);
void* hMod = (void*)hL
uint size = 0;
uint BaseAddress = (uint)hM
if (hMod != null)
Console.WriteLine("Got handle");
IMAGE_IMPORT_DESCRIPTOR* pIID = (IMAGE_IMPORT_DESCRIPTOR*)Interop.ImageDirectoryEntryToData((void*)hMod, mappedAsImage, Interop.IMAGE_DIRECTORY_ENTRY_IMPORT, out size);
if (pIID != null)
Console.WriteLine("Got Image Import Descriptor");
while (pIID-&OriginalFirstThunk != 0)
char* szName = (char*)(BaseAddress + pIID-&Name);
string name = Marshal.PtrToStringAnsi((IntPtr)szName);
Console.WriteLine("pIID-&Name = {0} BaseAddress - {1}", name, (uint)BaseAddress);
THUNK_DATA* pThunkOrg = (THUNK_DATA*)(BaseAddress + pIID-&OriginalFirstThunk);
while (pThunkOrg-&AddressOfData != 0)
char* szImportN
if ((pThunkOrg-&Ordinal & 0x) & 0)
Ord = pThunkOrg-&Ordinal & 0
Console.WriteLine("imports ({0}).Ordinal{1} - Address: {2}", name, Ord, pThunkOrg-&Function);
IMAGE_IMPORT_BY_NAME* pIBN = (IMAGE_IMPORT_BY_NAME*)(BaseAddress + pThunkOrg-&AddressOfData);
if (!Interop.IsBadReadPtr((void*)pIBN, (uint)sizeof(IMAGE_IMPORT_BY_NAME)))
Ord = pIBN-&H
szImportName = (char*)pIBN-&N
string sImportName = Marshal.PtrToStringAnsi((IntPtr)szImportName); // yes i know i am a lazy ass
Console.WriteLine("imports ({0}).{1}@{2} - Address: {3}", name, sImportName, Ord, pThunkOrg-&Function);
Console.WriteLine("Bad ReadPtr Detected or EOF on Imports");
pThunkOrg++;
catch (AccessViolationException e)
Console.WriteLine("An Access violation occured\n" +
"this seems to suggest the end of the imports section\n");
Console.WriteLine(e);
Console.WriteLine("Press Any Key To Continue......");
Console.ReadKey();
35.3k32148
work on x64 you have change the data type of the RVA addresses (AddressOfFunctions, AddressOfNames and AddressOfNameOrdinals) in IMAGE_EXPORT_DIRECTORY. Those are always 32 bit long (UInt32). IntPtr is 32 bit on x86 and 64 bit on x64.
[StructLayout(LayoutKind.Sequential)]
public struct IMAGE_EXPORT_DIRECTORY
public UInt32 C
public UInt32 TimeDateS
public UInt16 MajorV
public UInt16 MinorV
public UInt32 N
public UInt32 B
public UInt32 NumberOfF
public UInt32 NumberOfN
public UInt32 AddressOfF
// RVA from base of image
public UInt32 AddressOfN
// RVA from base of image
public UInt32 AddressOfNameO
// RVA from base of image
22.7k851114
From the debugger you can see that this while loop is never entered (for gdi32.dll & wsock32.dll):
while (!Interop.IsBadReadPtr((void*)pIID-&OriginalFirstThunk, (uint)size))
It is strongly adviced not to use IsBadReadPtr since you cannot always rely on it's return value. see:
A different approach to handle the validaty of a pointer is by using structured exception handling. Try to access the memory address, handle any Access Violation Exceptions.
Wether this is good practice or not, is a different discussion.
might be usefull:
Building on Jester's corrections to the original sample, here is a class that reads both IMPORTs and EXPORTs.
I've been using it succesfully on 32-bit DLLs, don't know yet about 64-bit however.
using System.Collections.G
using System.Runtime.InteropS
using System.S
Inspirations:
* /dotnet/#AssemblyParser (Mike Woodring's "Parsing PE File Headers to Determine if a DLL or EXE is an Assembly")
* /questions/1563134/how-do-i-read-the-pe-header-of-a-module-loaded-in-memory ("How do I read the PE header of a module loaded in memory?")
* /questions/2975639/resolving-rvas-for-import-and-export-tables-within-a-pe-file ("Resolving RVA's for Import and Export tables within a PE file.")
* /blog/2006/04/i-love-it-when-a-plan-comes-together.html
* http://www.gamedev.net/community/forums/topic.asp?topic_id=409936
* /questions/4571088/how-to-programatically-read-native-dll-imports-in-c
namespace PE
public unsafe class PortableExecutableParser
public delegate void DLog(string fmt, params object[] args);
private readonly DLog _fnL
private void Log( string fmt, params object[] args )
if (_fnLog != null)
_fnLog(fmt, args);
private readonly List&string& _exports = new List&string&();
public IEnumerable&string& Exports { get { return _
private readonly List&Tuple&string, List&string&&& _imports = new List&Tuple&string, List&string&&&();
public IEnumerable&Tuple&string, List&string&&& Imports { get { return _ } }
public PortableExecutableParser( string path, DLog fnLog=null )
_fnLog = fnL
LOADED_IMAGE loadedI
if (MapAndLoad(path, null, out loadedImage, true, true))
LoadExports(loadedImage);
LoadImports(loadedImage);
private void LoadExports(LOADED_IMAGE loadedImage)
var hMod = (void*)loadedImage.MappedA
if (hMod != null)
Log("Got handle");
var pExportDir = (IMAGE_EXPORT_DIRECTORY*)ImageDirectoryEntryToData(
(void*)loadedImage.MappedAddress,
IMAGE_DIRECTORY_ENTRY_EXPORT,
out size);
if (pExportDir != null)
Log("Got Image Export Descriptor");
var pFuncNames = (uint*)RvaToVa(loadedImage, pExportDir-&AddressOfNames);
for (uint i = 0; i & pExportDir-&NumberOfN i++)
uint funcNameRva = pFuncNames[i];
if (funcNameRva != 0)
var funcName =
(char*)RvaToVa(loadedImage, funcNameRva);
var name = Marshal.PtrToStringAnsi((IntPtr)funcName);
funcName: {0}", name);
_exports.Add(name);
private static IntPtr RvaToVa( LOADED_IMAGE loadedImage, uint rva )
return ImageRvaToVa(loadedImage.FileHeader, loadedImage.MappedAddress, rva, IntPtr.Zero);
private static IntPtr RvaToVa(LOADED_IMAGE loadedImage, IntPtr rva)
return RvaToVa(loadedImage, (uint)(rva.ToInt32()) );
private void LoadImports(LOADED_IMAGE loadedImage)
var hMod = (void*)loadedImage.MappedA
if (hMod != null)
Console.WriteLine("Got handle");
var pImportDir =
(IMAGE_IMPORT_DESCRIPTOR*)
ImageDirectoryEntryToData(hMod, false,
IMAGE_DIRECTORY_ENTRY_IMPORT, out size);
if (pImportDir != null)
Log("Got Image Import Descriptor");
while (pImportDir-&OriginalFirstThunk != 0)
var szName = (char*) RvaToVa(loadedImage, pImportDir-&Name);
string name = Marshal.PtrToStringAnsi((IntPtr) szName);
var pr = new Tuple&string, List&string&&(name, new List&string&());
_imports.Add(pr);
var pThunkOrg = (THUNK_DATA*)RvaToVa(loadedImage, pImportDir-&OriginalFirstThunk);
while (pThunkOrg-&AddressOfData != IntPtr.Zero)
if ((pThunkOrg-&Ordinal & 0x) & 0)
ord = pThunkOrg-&Ordinal & 0
Log("imports ({0}).Ordinal{1} - Address: {2}", name, ord,
pThunkOrg-&Function);
var pImageByName =
(IMAGE_IMPORT_BY_NAME*) RvaToVa(loadedImage, pThunkOrg-&AddressOfData);
!IsBadReadPtr(pImageByName, (uint) sizeof (IMAGE_IMPORT_BY_NAME)))
ord = pImageByName-&H
var szImportName = pImageByName-&N
string sImportName = Marshal.PtrToStringAnsi((IntPtr) szImportName);
Log("imports ({0}).{1}@{2} - Address: {3}", name,
sImportName, ord, pThunkOrg-&Function);
pr.Item2.Add( sImportName );
Log("Bad ReadPtr Detected or EOF on Imports");
pThunkOrg++;
catch (AccessViolationException e)
Log("An Access violation occured\n" +
"this seems to suggest the end of the imports section\n");
Log(e.ToString());
pImportDir++;
// ReSharper disable InconsistentNaming
private const ushort IMAGE_DIRECTORY_ENTRY_IMPORT = 1;
private const ushort IMAGE_DIRECTORY_ENTRY_EXPORT = 0;
private const CallingConvention WINAPI = CallingConvention.W
private const string KERNEL_DLL = "kernel32";
private const string DBGHELP_DLL = "Dbghelp";
private const string IMAGEHLP_DLL = "ImageHlp";
// ReSharper restore InconsistentNaming
[DllImport(KERNEL_DLL, CallingConvention = WINAPI, EntryPoint = "GetModuleHandleA"), SuppressUnmanagedCodeSecurity]
public static extern void* GetModuleHandleA(/*IN*/ char* lpModuleName);
[DllImport(KERNEL_DLL, CallingConvention = WINAPI, EntryPoint = "GetModuleHandleW"), SuppressUnmanagedCodeSecurity]
public static extern void* GetModuleHandleW(/*IN*/ char* lpModuleName);
[DllImport(KERNEL_DLL, CallingConvention = WINAPI, EntryPoint = "IsBadReadPtr"), SuppressUnmanagedCodeSecurity]
public static extern bool IsBadReadPtr(void* lpBase, uint ucb);
[DllImport(DBGHELP_DLL, CallingConvention = WINAPI, EntryPoint = "ImageDirectoryEntryToData"), SuppressUnmanagedCodeSecurity]
public static extern void* ImageDirectoryEntryToData(void* pBase, bool mappedAsImage, ushort directoryEntry, out uint size);
[DllImport(DBGHELP_DLL, CallingConvention = WINAPI), SuppressUnmanagedCodeSecurity]
public static extern IntPtr ImageRvaToVa(
IntPtr pNtHeaders,
IntPtr pBase,
IntPtr pLastRvaSection);
[DllImport(DBGHELP_DLL, CallingConvention = CallingConvention.StdCall), SuppressUnmanagedCodeSecurity]
public static extern IntPtr ImageNtHeader(IntPtr pImageBase);
[DllImport(IMAGEHLP_DLL, CallingConvention = CallingConvention.Winapi), SuppressUnmanagedCodeSecurity]
public static extern bool MapAndLoad(string imageName, string dllPath, out LOADED_IMAGE loadedImage, bool dotDll, bool readOnly);
// ReSharper disable InconsistentNaming
[StructLayout(LayoutKind.Sequential)]
public struct LOADED_IMAGE
public IntPtr moduleN
public IntPtr hF
public IntPtr MappedA
public IntPtr FileH
public IntPtr lastRvaS
public UInt32 numbOfS
public IntPtr firstRvaS
public UInt32
public ushort systemI
public ushort dosI
public ushort readO
public IntPtr links_1;
// these two comprise the LIST_ENTRY
public IntPtr links_2;
public UInt32 sizeOfI
[StructLayout(LayoutKind.Explicit)]
public unsafe struct IMAGE_IMPORT_BY_NAME
[FieldOffset(0)]
public ushort H
[FieldOffset(2)]
public fixed char Name[1];
[StructLayout(LayoutKind.Explicit)]
public struct IMAGE_IMPORT_DESCRIPTOR
#region union
/// &summary&
/// CSharp doesnt really support unions, but they can be emulated by a field offset 0
/// &/summary&
[FieldOffset(0)]
public uint C
// 0 for terminating null import descriptor
[FieldOffset(0)]
public uint OriginalFirstT
// RVA to original unbound IAT (PIMAGE_THUNK_DATA)
#endregion
[FieldOffset(4)]
public uint TimeDateS
[FieldOffset(8)]
public uint ForwarderC
[FieldOffset(12)]
public uint N
[FieldOffset(16)]
public uint FirstT
[StructLayout(LayoutKind.Sequential)]
public struct IMAGE_EXPORT_DIRECTORY
public UInt32 C
public UInt32 TimeDateS
public UInt16 MajorV
public UInt16 MinorV
public UInt32 N
public UInt32 B
public UInt32 NumberOfF
public UInt32 NumberOfN
public IntPtr AddressOfF
// RVA from base of image
public IntPtr AddressOfN
// RVA from base of image
public IntPtr AddressOfNameO
// RVA from base of image
[StructLayout(LayoutKind.Explicit)]
public struct THUNK_DATA
[FieldOffset(0)]
public uint ForwarderS
[FieldOffset(0)]
public uint F
[FieldOffset(0)]
public uint O
[FieldOffset(0)]
public IntPtr AddressOfD
// PIMAGE_IMPORT_BY_NAME
// ReSharper restore InconsistentNaming
7,21484283
Expanding on
(and thanks to everyone who contributed code here)... That class, when merged with the x64 fixes, appears to run correctly if the .NET host project targets x86. It reads both 32 and 64 bit executables successfully.
However, two issues occur if the host project is set to target x64.
RvaToVA crashes on some files (e.g. the Adobe reader test case mentioned below), on the line
return RvaToVa(loadedImage, (uint)(rva.ToInt32());
With an overflow. Changing this to .ToInt64 resolves the overflow, but then
It appears to produce an incomplete list of imports when tested against Acrobat Reader 10 MUI baseline (acrord32.exe version 10.0.0.396). This is a 32 bit executable.
Dumpbin reports the following 9 imports for Shell32.dll
SHGetFolderPathW,
ShellExecuteExW,
CommandLineToArgvW,
ShellExecuteW,
SHCreateDirectoryExW,
SHGetFileInfoW,
SHGetPathFromIDListW,
FindExecutableW
SHBrowseForFolderW
However the code when run in x64 mode only finds 4 of these
SHGetFolderPathW,
ShellExecuteW,
SHGetFileInfoW,
FindExecutableW
And at this point pThunk->Ordinal returns 0, causing the loop to terminate
I haven't at this stage had the chance to do some debugging to try and figure out what's going on, although it's likely to be the size of something changing in x64. Meanwhile just be aware this appears to work OK as long as the host is targeting x86 (which is good enough for my needs). If I find the underlying reason, I'll let you folks know.
22.7k851114
Your Answer
Sign up or
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Post as a guest
By posting your answer, you agree to the
Not the answer you're looking for?
Browse other questions tagged
Stack Overflow works best with JavaScript enabled

我要回帖

更多关于 real image 的文章

 

随机推荐