C#如何去遍歷一個由C++或E語言編寫的本地DLL導出函數呢 不過在這裏我建議對PE一無所知的人 程序員
你或許應先補補這方面的知識,我不知道爲何PE方面的 應用在C#中怎麼這麼少,我查閱過相關web
C#的知識大概只見一我的寫過關於PE的應用 還只是從PE信息中判斷執行文件是X86仍是X64方式app
編譯,難道C#程序員真的不好 真的只能會點Asp.Net / MVC?想一想看雪論壇那些玩inline-asm / ide
inline-hook的牛牛 真是感到有很大差距 不過不論什麼語言 在我看來其實都差很少 重點在於人是否函數
有心。雖然我不敢保證C#能夠嵌入動態彙編(auto-asm)可是我能夠保證C#能夠作inline-hook雖然會oop
的人比較少,不過也還好,至少C#程序員不會是一羣渣渣。不過我在寫下述代碼時,但是累得緊 寫佈局
結構體部分有些麻煩 並且C#與C++有些不一樣 固然也能夠動態偏移地址搞定不過那個有些麻煩了,你ui
想推敲地址可不是那麼好玩的事情,可能你本身推敲半天結果發現你推敲錯了,那種方法用在結構體this
層次較少的狀況下的確能夠提高逼格 反正別人看不懂就好嘛? 呵呵。下面的代碼須要在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); }
- }
- }