C#如何去遍歷一個由C++或E語言編寫的本地DLL導出函數呢 不過在這里我建議對PE一無所知的人
你或許應先補補這方面的知識,我不知道為什么PE方面的 應用在C#中怎么這么少,我查閱過相關
C#的知識大概只見一個人寫過關于PE的應用 還只是從PE信息中判斷執行文件是X86還是X64方式
編譯,難道C#程序員真的很差 真的只能會點asp.net / MVC?想想看雪論壇那些玩inline-asm /
inline-hook的牛牛 真是感到有很大差距 不過不論什么語言 在我看來其實都差不多 重點在于人是否
有心。雖然我不敢保證C#可以嵌入動態匯編(auto-asm)但是我可以保證C#可以做inline-hook雖然會
的人比較少,不過也還好,至少C#程序員不會是一群渣渣。不過我在寫下述代碼時,可是累得緊 寫
結構體部分有些麻煩 而且C#與C++有些不同 當然也可以動態偏移地址搞定不過那個有些麻煩了,你
想推敲地址可不是那么好玩的事情,可能你自己推敲半天結果發現你推敲錯了,那種方法用在結構體
層次較少的情況下的確可以提升逼格 反正別人看不懂就好嘛? 呵呵。下面的代碼需要在X86的環境下
使用主要在于該代碼中使用的PE信息全是32位的結構體而非64位的PE信息結構體 所以需要X86環境
不過不論是X86還是X64方法都是相等的,只是兩者的結構體與對稱不太一樣而已。

PE格式,是微軟Win32環境可移植執行文件如(exe / sys / dll / vxd / vdm)等都是標準的文件格式
PE格式衍生于VAX / VMS上的COFF文件格式,Portable是指對于不同的Windows版本和不同的
CPU類型上PE文件的格式是一樣的,或許CPU不一指令與二進制編碼不一,但是文件中各種東
西的布局是一至的。
PE文件中第一個字節是MS-DOS信息頭即IMAGE_DOS_HEADER與IMAGE_NT_HEADER中包
含許多PE裝載器用到。
- [STAThread]
- unsafe static void Main()
- {
- IntPtr hFileBase = Win32Native._lopen(@"C:/Windows/System32/ATL.dll", Win32Native.OF_SHARE_COMPAT);
- IntPtr hFileMapping = Win32Native.CreateFileMapping(hFileBase, Win32Native.NULL, Win32Native.PAGE_READONLY, 0, 0, null);
- IntPtr PSDos32pe = Win32Native.MapViewOfFile(hFileMapping, Win32Native.FILE_MAP_READ, 0, 0, Win32Native.NULL);
- IMAGE_DOS_HEADER sDos32pe = (IMAGE_DOS_HEADER)Marshal.PtrToStructure(psDos32pe, typeof(IMAGE_DOS_HEADER));
- IntPtr psNt32pe = (IntPtr)(sDos32pe.e_lfanew + (long)psDos32pe);
- IMAGE_NT_HEADERS sNt32pe = (IMAGE_NT_HEADERS)Marshal.PtrToStructure(psNt32pe, typeof(IMAGE_NT_HEADERS));
-
- IntPtr psExportDirectory = Win32Native.ImageRvaToVa(psNt32pe, psDos32pe, sNt32pe.OptionalHeader.ExportTable.VirtualAddress, Win32Native.NULL);
- IMAGE_EXPORT_DIRECTORY sExportDirectory = (IMAGE_EXPORT_DIRECTORY)Marshal.PtrToStructure(psExportDirectory, typeof(IMAGE_EXPORT_DIRECTORY));
- IntPtr ppExportOfNames = Win32Native.ImageRvaToVa(psNt32pe, psDos32pe, sExportDirectory.AddressOfNames, Win32Native.NULL);
- for (uint i = 0, nNoOfExports = sExportDirectory.NumberOfNames; i < nNoOfExports; i++)
- {
- IntPtr pstrExportOfName = Win32Native.ImageRvaToVa(psNt32pe, psDos32pe, (uint)Marshal.ReadInt32(ppExportOfNames, (int)(i * 4)), Win32Native.NULL);
- Console.WriteLine(Marshal.PtrToStringAnsi(pstrExportOfName));
- }
- Win32Native.UnmapViewOfFile(psDos32pe);
- Win32Native.CloseHandle(hFileMapping);
- Win32Native._lclose(hFileBase);
- Console.ReadKey(false);
- }
包含 入口點 Entry Point
文件偏移地址 File Offset
虛擬地址 Virtual Address(VA)
基地址 Image Base
相對虛擬地址 Relative Virual Address(RVA)
公式:RVA (相對虛擬地址) = VA(虛擬地址) - Image Base (基地址)
文件偏移地址和虛擬地址轉換
在X86系統中,每個內存頁的大小是4KB
文件偏移地址 File Offset = RVA(相對虛擬地址) - ΔK
文件偏移地址 File Offset = VA(虛擬地址) - Image Base (基地址) - ΔK
詳細解釋內容請參考百度百科,反正你想真正理解還需要自己去研究PE文件
IMAGE_NT_HEADERS在MS-DOS信息頭后面它是標準的Win32執行文件信息頭,其中包含了
導入的函數表,導出函數表,資源信息表、CLR運行時頭,IAT、TLS表、包括調試信息 等等
我們現在要做的就是獲取在DLL中導出的函數名,而DLL是屬于標準Win32執行文件中的一種
那么我們則必須要獲取到IMAGE_NT_HEADERS結構,實際上需要定位NT結構是很簡單的,
因為在規定中NT信息頭在DOS信息頭后面,即IMAGE_DOS_HEADER.e_lfanew + IMAGE_DOS_HEADER
所以你會看到我在代碼中有這樣一句話IntPtr psNt32pe = (IntPtr)(sDos32pe.e_lfanew + (long)psDos32pe);
IMAGE_OPTIONAL_HEADER可選映像頭是一個可選結構,但是IMAGE_FILE_HEADER結構不滿足PE文件
需求定義的屬性,因此這些屬性在OPTIONAL結構中定義,因此FILE+OPTIONAL兩個結構聯合起來 才是一
個完整的PE文件結構,在其中包含了很多重要的信息字段 如 AddressOfEntryPoint、DataDirectory、Subsystem
不過提到DataDirectory我想說一下,在C#中不好定義所以在代碼中該字段換了另一種方式定義,DataDirectory
默認是有16個IMAGE_DATA_DIRECTORY的尺寸,所以在代碼中你可以看到有很多該類型的定義。它們則是表
示DataDirectory中信息IMAGE_DIRECTORY_ENTRY_EXPORT導出表 我們現在只需要獲取它的信息,在這里
我們需要用到ImageRvaToVa(相對虛擬地址到虛擬地址)有人是這樣理解的, 物理地址到虛擬地址 不過原來我在
理解時這個地方也是小小糾結了一番,不過后來則釋然了。ImageRvaToVa(NT_H, DOS_H, RVA, RvaSection);
IMAGE_DATA_DIRECTORY中包含兩個字段,一個VirtualAddress(RVA)另一個為Size(尺寸)獲取到結構體中的
RVA但是這個地址我們不管怎么轉換都沒法使用,對的因為提供給我的地址根本沒法用 那么我們則需要把RVA
轉換為VA利用上面提到函數,只有默默的感謝微軟一番 呵呵,當轉換后會得到IMAGE_EXPORT_DIRECTORY
在這里我需要提示一下大家,不是每個DataDirectory包含的RVA對應的結構都是EXPORT每個都有自己獨立的
解釋結構,不要搞混了 不然肯定會飛高的。
我們需要IMAGE_EXPORT_DIRECTORY中NumberOfNames(函數名總數)與AddressOfNames(函數名地址)
兩個字段中的內容,不過AddressOfNames中包含的是相對虛擬地址RVA,所以我們需要做一次轉換,會返回有
效char**的指針前提你提供的數據有效否則返回NULL,由于C#中你懂的char占兩個字節,即char=wchar_t那么
我們查看指針中的數據肯定會有問題DLL導出函數名全部是Ascii編碼,所以為了方便在C#專用干脆IntPtr方便通過
Marshal進行轉換最后只是進行一個資源釋放的操作好了基本就是這個樣子剩下的還需要大家自己去理解多說無益
- using System;
- using System.Runtime.InteropServices;
-
- static partial class Win32Native
- {
- [DllImport("dbghelp", SetLastError = true)]
- public static extern IntPtr ImageRvaToVa(IntPtr NtHeaders, IntPtr Base, uint Rva, int LastRvaSection);
-
- [DllImport("kernel32", SetLastError = true)]
- public static extern IntPtr _lopen(string lpPathName, int iReadWrite);
-
- [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
- public static extern IntPtr CreateFileMapping(IntPtr hFile, int lpFileMappingAttributes, int flProtect, uint dwMaximumSizeHigh, uint dwMaximumSizeLow, string lpName);
-
- [DllImport("kernel32.dll", SetLastError = true)]
- public static extern IntPtr MapViewOfFile(IntPtr hFileMappingObject, int dwDesiredaccess, uint dwFileOffsetHigh, uint dwFileOffsetLow, int dwNumberOfBytesToMap);
-
- [DllImport("kernel32.dll", SetLastError = true)]
- public static extern int UnmapViewOfFile(IntPtr hMapFile);
-
- [DllImport("kernel32.dll", SetLastError = true)]
- public static extern int _lclose(IntPtr hFile);
-
- [DllImport("kernel32.dll", SetLastError = true)]
- public static extern int CloseHandle(IntPtr hObject);
- }
-
- static partial class Win32Native
- {
- public const int NULL = 0;
- public const int OF_SHARE_COMPAT = 0;
- public const int PAGE_READONLY = 2;
- public const int FILE_MAP_READ = 4;
- public const int IMAGE_DIRECTORY_ENTRY_EXPORT = 0;
- }
-
- [StructLayout(LayoutKind.Sequential)]
- public struct IMAGE_DOS_HEADER
- {
- [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
- public char[] e_magic;
- public ushort e_cblp;
- public ushort e_cp;
- public ushort e_crlc;
- public ushort e_cparhdr;
- public ushort e_minalloc;
- public ushort e_maxalloc;
- public ushort e_ss;
- public ushort e_sp;
- public ushort e_csum;
- public ushort e_ip;
- public ushort e_cs;
- public ushort e_lfarlc;
- public ushort e_ovno;
- [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
- public ushort[] e_res1;
- public ushort e_oemid;
- public ushort e_oeminfo;
- [MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)]
- public ushort[] e_res2;
- public int e_lfanew;
-
- private string _e_magic
- {
- get { return new string(e_magic); }
- }
-
- public bool isValid
- {
- get { return _e_magic == "MZ"; }
- }
- }
-
- [StructLayout(LayoutKind.Explicit)]
- public struct IMAGE_OPTIONAL_HEADERS
- {
- [FieldOffset(0)]
- public MagicType Magic;
-
- [FieldOffset(2)]
- public byte MajorLinkerVersion;
-
- [FieldOffset(3)]
- public byte MinorLinkerVersion;
-
- [FieldOffset(4)]
- public uint SizeOfCode;
-
- [FieldOffset(8)]
- public uint SizeOfInitializedData;
-
- [FieldOffset(12)]
- public uint SizeOfUninitializedData;
-
- [FieldOffset(16)]
- public uint AddressOfEntryPoint;
-
- [FieldOffset(20)]
- public uint BaSEOfCode;
-
-
- [FieldOffset(24)]
- public uint BaseOfData;
-
- [FieldOffset(28)]
- public uint ImageBase;
-
- [FieldOffset(32)]
- public uint SectionAlignment;
-
- [FieldOffset(36)]
- public uint FileAlignment;
-
- [FieldOffset(40)]
- public ushort MajorOperatingSystemVersion;
-
- [FieldOffset(42)]
- public ushort MinorOperatingSystemVersion;
-
- [FieldOffset(44)]
- public ushort MajorImageVersion;
-
- [FieldOffset(46)]
- public ushort MinorImageVersion;
-
- [FieldOffset(48)]
- public ushort MajorSubsystemVersion;
-
- [FieldOffset(50)]
- public ushort MinorSubsystemVersion;
-
- [FieldOffset(52)]
- public uint Win32VersionValue;
-
- [FieldOffset(56)]
- public uint SizeOfImage;
-
- [FieldOffset(60)]
- public uint SizeOfHeaders;
-
- [FieldOffset(64)]
- public uint CheckSum;
-
- [FieldOffset(68)]
- public SubSystemType Subsystem;
-
- [FieldOffset(70)]
- public DllCharacteristicsType DllCharacteristics;
-
- [FieldOffset(72)]
- public uint SizeOfStackReserve;
-
- [FieldOffset(76)]
- public uint SizeOfStackCommit;
-
- [FieldOffset(80)]
- public uint SizeOfHeapReserve;
-
- [FieldOffset(84)]
- public uint SizeOfHeapCommit;
-
- [FieldOffset(88)]
- public uint LoaderFlags;
-
- [FieldOffset(92)]
- public uint NumberOfRvaAndSizes;
-
- [FieldOffset(96)]
- public IMAGE_DATA_DIRECTORY ExportTable;
-
- [FieldOffset(104)]
- public IMAGE_DATA_DIRECTORY ImportTable;
-
- [FieldOffset(112)]
- public IMAGE_DATA_DIRECTORY ResourceTable;
-
- [FieldOffset(120)]
- public IMAGE_DATA_DIRECTORY ExceptionTable;
-
- [FieldOffset(128)]
- public IMAGE_DATA_DIRECTORY CertificateTable;
-
- [FieldOffset(136)]
- public IMAGE_DATA_DIRECTORY BaseRelocationTable;
-
- [FieldOffset(144)]
- public IMAGE_DATA_DIRECTORY Debug;
-
- [FieldOffset(152)]
- public IMAGE_DATA_DIRECTORY Architecture;
-
- [FieldOffset(160)]
- public IMAGE_DATA_DIRECTORY GlobalPtr;
-
- [FieldOffset(168)]
- public IMAGE_DATA_DIRECTORY TLSTable;
-
- [FieldOffset(176)]
- public IMAGE_DATA_DIRECTORY LoadConfigTable;
-
- [FieldOffset(184)]
- public IMAGE_DATA_DIRECTORY BoundImport;
-
- [FieldOffset(192)]
- public IMAGE_DATA_DIRECTORY IAT;
-
- [FieldOffset(200)]
- public IMAGE_DATA_DIRECTORY DelayImportDescriptor;
-
- [FieldOffset(208)]
- public IMAGE_DATA_DIRECTORY CLRRuntimeHeader;
-
- [FieldOffset(216)]
- public IMAGE_DATA_DIRECTORY Reserved;
- }
-
- [StructLayout(LayoutKind.Sequential)]
- public struct IMAGE_FILE_HEADER
- {
- public ushort Machine;
- public ushort NumberOfSections;
- public uint TimeDateStamp;
- public uint PointerToSymbolTable;
- public uint NumberOfSymbols;
- public ushort SizeOfOptionalHeader;
- public ushort Characteristics;
- }
-
- public enum MachineType : ushort
- {
- Native = 0,
- I386 = 0x014c,
- Itanium = 0x0200,
- x64 = 0x8664
- }
- public enum MagicType : ushort
- {
- IMAGE_NT_OPTIONAL_HDR32_MAGIC = 0x10b,
- IMAGE_NT_OPTIONAL_HDR64_MAGIC = 0x20b
- }
- public enum SubSystemType : ushort
- {
- IMAGE_SUBSYSTEM_UNKNOWN = 0,
- IMAGE_SUBSYSTEM_NATIVE = 1,
- IMAGE_SUBSYSTEM_WINDOWS_GUI = 2,
- IMAGE_SUBSYSTEM_WINDOWS_CUI = 3,
- IMAGE_SUBSYSTEM_POSIX_CUI = 7,
- IMAGE_SUBSYSTEM_WINDOWS_CE_GUI = 9,
- IMAGE_SUBSYSTEM_EFI_application = 10,
- IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER = 11,
- IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER = 12,
- IMAGE_SUBSYSTEM_EFI_ROM = 13,
- IMAGE_SUBSYSTEM_XBOX = 14
-
- }
- public enum DllCharacteristicsType : ushort
- {
- RES_0 = 0x0001,
- RES_1 = 0x0002,
- RES_2 = 0x0004,
- RES_3 = 0x0008,
- IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE = 0x0040,
- IMAGE_DLL_CHARACTERISTICS_FORCE_INTEGRITY = 0x0080,
- IMAGE_DLL_CHARACTERISTICS_NX_COMPAT = 0x0100,
- IMAGE_DLLCHARACTERISTICS_NO_ISOLATION = 0x0200,
- IMAGE_DLLCHARACTERISTICS_NO_SEH = 0x0400,
- IMAGE_DLLCHARACTERISTICS_NO_BIND = 0x0800,
- RES_4 = 0x1000,
- IMAGE_DLLCHARACTERISTICS_WDM_DRIVER = 0x2000,
- IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE = 0x8000
- }
-
- [StructLayout(LayoutKind.Sequential)]
- public struct IMAGE_DATA_DIRECTORY
- {
- public uint VirtualAddress;
- public uint Size;
- }
-
- [StructLayout(LayoutKind.Sequential)]
- public struct IMAGE_EXPORT_DIRECTORY
- {
- public uint Characteristics;
- public uint TimeDateStamp;
- public ushort MajorVersion;
- public ushort MinorVersion;
- public uint Name;
- public uint Base;
- public uint NumberOfFunctions;
- public uint NumberOfNames;
- public uint AddressOfFunctions;
- public uint AddressOfNames;
- public uint AddressOfNameOrdinals;
- }
-
- [StructLayout(LayoutKind.Explicit)]
- public struct IMAGE_NT_HEADERS
- {
- [FieldOffset(0)]
- [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
- public char[] Signature;
-
- [FieldOffset(4)]
- public IMAGE_FILE_HEADER FileHeader;
-
- [FieldOffset(24)]
- public IMAGE_OPTIONAL_HEADERS OptionalHeader;
-
- private string _Signature
- {
- get { return new string(Signature); }
- }
-
- public bool isValid
- {
- get { return _Signature == "PE/0/0" && (OptionalHeader.Magic == MagicType.IMAGE_NT_OPTIONAL_HDR32_MAGIC || OptionalHeader.Magic == MagicType.IMAGE_NT_OPTIONAL_HDR64_MAGIC); }
- }
- }