There are many posts on how to call an unmanaged DLL's function, by using "DllImport" or using LoadLibrary and GetProcAddress. There are almost no posts on how to list the available functions in a DLL, and none on how to do it using the .NET.
I started by using the code from this post:
http://www.gamedev.net/community/forums/topic.asp?topic_id=409936 by ReZimE
not much was left of the original code, but it gave me the idea I needed in order to approach the problem.
If MSDN jumps to your head, you probably didn't try to use it at all. The thing contains everything you need, ordered by structure. Looks OK, unless you're in a habit of solving a certain point. For those cases the best order is by orientation (aka keywords, categories, etc.) And thus Googling is the best method to use.
For the code I needed to define the structures to be used. PInvoke.NET did a good job on many of the structures. If you need them it's probably one of the best places, though I had to create a few missing structures; based on MSDN.
Now to the code:)
static void Main(string[] args)
{
string DllName = args[0];
unsafe
{
fixed (char* pszModule = DllName)
{
void* hMod = InterOp.GetModuleHandleW(pszModule);
if (hMod != null)
{
Console.WriteLine("Got handle"); uint BaseAddress = (uint)hMod;
// Verify DOS header
IMAGE_DOS_HEADER pDOSHeader = (IMAGE_DOS_HEADER)Marshal.PtrToStructure((IntPtr)hMod, typeof(IMAGE_DOS_HEADER));
if (pDOSHeader.e_magic != IMAGE_DOS_SIGNATURE) // "MZ"
{
Console.WriteLine("Error in DOS signature");
}
// NT Header
void* pNTHeader = InterOp.ImageNtHeader(hMod);
IMAGE_NT_HEADERS NTHeader = (IMAGE_NT_HEADERS)Marshal.PtrToStructure((IntPtr)pNTHeader, typeof(IMAGE_NT_HEADERS));
if (NTHeader.Signature != IMAGE_NT_SIGNATURE) // "PE"
{
Console.WriteLine("Error in NT signature");
}
// RVA of export table
uint lExportOffset = NTHeader.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
uint lExportSize = NTHeader.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size;
// Export table
IMAGE_EXPORT_DIRECTORY pExportDir = (IMAGE_EXPORT_DIRECTORY)Marshal.PtrToStructure((IntPtr)(BaseAddress + lExportOffset), typeof(IMAGE_EXPORT_DIRECTORY));
// Length of AddressOfNames array
int lNumberOfNames = (int)pExportDir.NumberOfNames;
Console.WriteLine("Found {0} names, size {1} at offset {2}", lNumberOfNames, lExportSize, lExportOffset);
for (int i = 0; i < lNumberOfNames; i++)
{
char* szName = (char*)(BaseAddress + Marshal.ReadInt32((IntPtr)(BaseAddress + pExportDir.AddressOfNames + 4 * i)));
string name = Marshal.PtrToStringAnsi((IntPtr)szName);
Console.WriteLine(name);
}
}
}
}
}
As you'll see; at least I did, because I forgot; it requires the "Allow unsafe code" flag in order to compile.
The constants used in the code are defined as
private static readonly ushort IMAGE_DIRECTORY_ENTRY_EXPORT = 0;
private static readonly ushort IMAGE_DOS_SIGNATURE = 0x5A4D;
private static readonly ushort IMAGE_NT_SIGNATURE = 0x4550;
private const string KERNEL_DLL = "kernel32";
private const string DBGHELP_DLL = "Dbghelp";
private const CallingConvention CALLING_CONVENTION = CallingConvention.Winapi;
I used 6 structures defined in the code, as far as I remember most of them are from the above links so I'll just list them here. In any case it's quite easy to create a new structure based on the definition in the MSDN. Just make sure to define it as "Explicit" instead of "Sequential" if there's a non-standard declaration.
The structures used in the code:
IMAGE_DOS_HEADER
IMAGE_NT_HEADERS
IMAGE_EXPORT_DIRECTORY
IMAGE_FILE_HEADER
IMAGE_OPTIONAL_HEADER32
IMAGE_DATA_DIRECTORY
The last thing is the "access class", I built it especially to access the external functions in the "unsafe" way.
private unsafe class InterOp
{
[DllImport(KERNEL_DLL, CallingConvention = CALLING_CONVENTION, EntryPoint = "GetModuleHandleW"), SuppressUnmanagedCodeSecurity]
public static extern void* GetModuleHandleW(/*IN*/ char* lpModuleName);
[DllImport(DBGHELP_DLL, CallingConvention = CALLING_CONVENTION, EntryPoint = "ImageNtHeader"), SuppressUnmanagedCodeSecurity]
public static extern void* ImageNtHeader(void* Base);
}
Thursday, October 22, 2009
Subscribe to:
Post Comments (Atom)
No comments:
Post a Comment