C# 遍历DLL导出函数
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); // e_lfanew 248
- 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));
- // 63 63 72 75 6E 2E 63 6F 6D
- 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;
- // #include "stdafx.h"
- // #include <ImageHlp.h>
- // #include <Windows.h>
- // #pragma comment(lib, "ImageHlp.lib")
- static partial class Win32Native
- {
- [DllImport("dbghelp", SetLastError = true)] // PIMAGE_SECTION_HEADER LastRvaSection
- 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; // Magic number
- public ushort e_cblp; // Bytes on last page of file
- public ushort e_cp; // Pages in file
- public ushort e_crlc; // Relocations
- public ushort e_cparhdr; // Size of header in paragraphs
- public ushort e_minalloc; // Minimum extra paragraphs needed
- public ushort e_maxalloc; // Maximum extra paragraphs needed
- public ushort e_ss; // Initial (relative) SS value
- public ushort e_sp; // Initial SP value
- public ushort e_csum; // Checksum
- public ushort e_ip; // Initial IP value
- public ushort e_cs; // Initial (relative) CS value
- public ushort e_lfarlc; // File address of relocation table
- public ushort e_ovno; // Overlay number
- [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
- public ushort[] e_res1; // Reserved words
- public ushort e_oemid; // OEM identifier (for e_oeminfo)
- public ushort e_oeminfo; // OEM information; e_oemid specific
- [MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)]
- public ushort[] e_res2; // Reserved words
- public int e_lfanew; // File address of new exe header
- 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;
- // PE32 contains this additional field
- [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; // RVA from base of image
- public uint AddressOfNames; // RVA from base of image
- public uint AddressOfNameOrdinals; // RVA from base of image
- }
- [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); }
- }
- }
C# 遍历DLL导出函数的更多相关文章
- DLL导出函数和类的定义区别 __declspec(dllexport)
DLL导出函数和类的定义区别 __declspec(dllexport) 是有区别的, 请看 : //定义头文件的使用方,是导出还是导入 #if defined(_DLL_API) #ifndef D ...
- AFX_MANAGE_STATE(AfxGetStaticModuleState())DLL导出函数包含MFC资源
AFX_MANAGE_STATE(AfxGetStaticModuleState()) 先看一个例子: .创建一个动态链接到MFC DLL的规则DLL,其内部包含一个对话框资源.指定该对话框ID如下: ...
- dll 导出函数名的那些事
dll 导出函数名的那些事 关键字: VC++ DLL 导出函数 经常使用VC6的Dependency或者是Depends工具查看DLL导出函数的名字,会发现有DLL导出函数的名字有时大不相同,导 ...
- dll导出函数的两种方式的比较
最初的网页链接已经挂了, 在此贴一个中间的转载链接 https://blog.csdn.net/zhazhiqiang/article/details/51577523 一 概要 vs中导出 dll的 ...
- 动态链接库DLL导出函数并导入使用
动态链接库DLL导出函数并导入使用 本文完全参考自<vs2008制作dll笔记,回带值样例>. 首先制作DLL文件,在vs2010中新建Win32控制台项目,选择DLL选项,简历头文件,源 ...
- Dll 导出函数那些破事
经常使用VC6的Dependency查看DLL导出函数的名字,会发现有DLL导出函数的名字有时大不相同,导致不同的原因大多是和编译DLL时候指定DLL导出函数的界定符有关系. VC++支持两种语言:即 ...
- 使用dumpbin命令查看dll导出函数及重定向输出到文件【轉】
查看dll导出函数,一般使用Viewdll等第三方工具. VS开发环境中,可以查看32位和64位的dll.具体使用方法如下: 1. 进入VS开发环境,然后Tools -> Visual stud ...
- 使用dumpbin命令查看dll导出函数及重定向输出到文件(VS自带)
以前查看dll导出函数,一般使用Viewdll等第三方工具.但由于Viewdll采用dephi编写,因此仅能查看32位的dll.其实微软已经帮我们提供一个查看dll导出函数的命令,嵌在VS开发环境中, ...
- DLL导出函数
使用DEF文件从DLL导出 模块定义(.def)文件时包含一个或多个描述DLL各种属性的Module语句的文本文件.如果不使用_declspec(dllexport)关键字导出DLL的函数,则DLL需 ...
随机推荐
- 利用Apache Ant编译Hadoop2.6.0-eclipse-plugin
环境要求:系统不重要,重要的是要有Ant环境,这里不做赘述,自行百度配置去. 1)在github上下载Hadoop-eclipse-plugin-master的zip包,下载地址. 2)在Hadoop ...
- c# 中定时器的用法
来源于:http://blog.sina.com.cn/s/blog_62c501440100fog1.html System.Threading.Timer 是一个非常常用的定时器类,关于这个类的使 ...
- 天气预报数据API
http://www.weather.com.cn/data/cityinfo/101010100.html//过期: http://api.36wu.com/Weather/GetMoreWeath ...
- 【09_242】Valid Anagram
Valid Anagram My Submissions Question Total Accepted: 43694 Total Submissions: 111615 Difficulty: Ea ...
- [Leetcode][JAVA] Best Time to Buy and Sell Stock I, II, III
Best Time to Buy and Sell Stock Say you have an array for which the ith element is the price of a gi ...
- Log4j 配置数据库连接池(将日志信息保存到数据库)
org.apache.log4j.jdbc.JDBCAppender 是利用传统的 JDBC 连接方法,这种方式连接数据库效率低下,为了解决这个问题,现在自定义一个 Log4j 的 Appender, ...
- 数据库知识整理<一>
关系型数据库知识整理: 一,关系型数据库管理系统简介: 1.1使用数据库的原因: 降低存储数据的冗余度 提高数据的一致性 可以建立数据库所遵循的标准 储存数据可以共享 便于维护数据的完整性 能够实现数 ...
- haskell debug
最近在学习haskell这门神奇的语言,但是由于print不方便,程序出错的时候都不知道是怎么回事.网上搜了一把发现有这么一个好东西 import Debug.Trace funct :: Integ ...
- 使用Process类重定向输出与错误时遇到的问题 (转)
程序中要调用外部程序cmd.exe执行一些命令行,并取得屏幕输出,使用了Process类,基本代码如下: Process process = new Process(); process.StartI ...
- [Xamarin] 用Service 來製作一個Notification的時鐘 (转帖)
這篇利用來製作一個會出現在Notification的時鐘,來敘述一下 Service,在你製作的App被關閉時,可以透過Service繼續運行你想處理的部分,當然Service 也有其生命周期 接下來 ...