i know some people are interested in these topics, but its hard to find places where i feel comfortable posting items like these. as in the wrong hands could be used to exploit other applications. but anyway people have been asking me and have asked from time to time about checking the imports section of there applications dll's for changes. and i thought i would contribute to the forum by posting an example of doing this with in c# so that it might help some one next time they want to do some thing similar.
any comments on this are welcome infact i encourage it.
these files are fairly bug free.
Examples only.
(if you want to try this code you will have to compile with unsafe code enabled)
(EDIT Updated Program.cs) - posted wrong version originaly
File Name = "Interop.cs"
using System;
using System.Runtime.InteropServices;
using System.Reflection;
using System.Security;
namespace PEHeaderTest
{
[StructLayout(LayoutKind.Explicit)]
public unsafe struct IMAGE_IMPORT_BY_NAME
{
[FieldOffset(0)]
public ushort Hint;
[FieldOffset(2)]
public fixed char Name[1];
}
[StructLayout(LayoutKind.Explicit)]
public struct IMAGE_IMPORT_DESCRIPTOR
{
#region union
[FieldOffset(0)]
public uint Characteristics;
[FieldOffset(0)]
public uint OriginalFirstThunk;
#endregion
[FieldOffset(4)]
public uint TimeDateStamp;
[FieldOffset(8)]
public uint ForwarderChain;
[FieldOffset(12)]
public uint Name;
[FieldOffset(16)]
public uint FirstThunk;
}
[StructLayout(LayoutKind.Explicit)]
public struct THUNK_DATA
{
[FieldOffset(0)]
public uint ForwarderString;
[FieldOffset(4)]
public uint Function;
[FieldOffset(8)]
public uint Ordinal;
[FieldOffset(12)]
public uint AddressOfData;
}
public unsafe class Interop
{
#region Public Constants
public static readonly ushort IMAGE_DIRECTORY_ENTRY_IMPORT = 1;
#endregion
#region Private Constants
#region CallingConvention CALLING_CONVENTION
private const CallingConvention CALLING_CONVENTION = CallingConvention.Winapi;
#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( char* lpModuleName);
[DllImport(KERNEL_DLL, CallingConvention = CALLING_CONVENTION, EntryPoint = "GetModuleHandleW"), SuppressUnmanagedCodeSecurity]
public static extern void* GetModuleHandleW( 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 );
}
}
File Name = "Program.cs"
using System;
using System.Text;
using System.Runtime.InteropServices;
namespace PEHeaderTest
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("This is just a sample app to demonstrate reading");
Console.WriteLine("the imports section of a native module in c#");
Console.WriteLine("as i have had lots of people saying you cant do this");
Console.WriteLine("in the language");
unsafe
{
fixed (char* pszModule = "mscoree.dll")
{
void* hMod = Interop.GetModuleHandleW(pszModule);
uint size = 0;
uint BaseAddress = (uint)hMod;
if (hMod != null)
{
Console.WriteLine("Got handle");
IMAGE_IMPORT_DESCRIPTOR* pIID = (IMAGE_IMPORT_DESCRIPTOR*)Interop.ImageDirectoryEntryToData((void*)hMod, true,Interop.IMAGE_DIRECTORY_ENTRY_IMPORT, out size);
if (pIID != null)
{
Console.WriteLine("Got Image Import Descriptor");
while (!Interop.IsBadReadPtr((void*)pIID->OriginalFirstThunk,(uint)size))
{
try
{
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 (!Interop.IsBadReadPtr((void*)pThunkOrg->AddressOfData,4U))
{
char* szImportName;
uint Ord;
if ((pThunkOrg->Ordinal & 0x80000000) > 0)
{
Ord = pThunkOrg->Ordinal & 0xffff;
Console.WriteLine("imports ({0}).Ordinal{1} - Address: {2}", name, Ord, pThunkOrg->Function);
}
else
{
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->Hint;
szImportName = (char*)pIBN->Name;
string sImportName = Marshal.PtrToStringAnsi((IntPtr)szImportName);
Console.WriteLine("imports ({0}).{1}@{2} - Address: {3}", name, sImportName, Ord,pThunkOrg->Function);
}
else
{
Console.WriteLine("Bad ReadPtr Detected or EOF on Imports");
break;
}
}
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);
}
pIID++;
}
}
}
}
}
Console.WriteLine("Press Any Key To Continue......");
Console.ReadKey();
}
}
}
[Edited by - RenZimE on August 16, 2006 10:39:40 PM]