C # traverse the DLL export function,
C # How to traverse a local DLL export function written in C ++ or E language? But here I suggest people who do not know anything about PE.
You may need to supplement this knowledge first. I don't know why there are so few PE applications in C #.
C # I only know that one person has written an application about PE and only checks whether the execution file is X86 or X64 from the PE information.
Compile. Is C # Really bad for programmers? Can I just click Asp. Net/MVC? Think about playing inline-asm/in the snow forum/
Inline-hook cool really felt a big gap, but no matter what language, in my opinion, it is almost important to know whether people
Have a heart. Although I cannot guarantee that C # can be embedded into auto-asm, I can ensure that C # can be embedded into inline-hook.
A small number of people, but it is also good, at least C # programmers will not be a group of scum. However, when I write the following code
The structure part is a little troublesome, and C # is somewhat different from C ++. Of course, you can also use dynamic offset addresses to handle it. But that is a little troublesome. You
It's not that fun to think about the address. Maybe you think about it for half a day and you find that you're wrong. That method is used in struct.
In the case of few levels, it can indeed be upgraded to a higher level. Can someone else not understand it? Haha. The following code must be in an X86 Environment
The main reason is that the PE information used in this code is a 32-bit structure rather than a 64-bit PE information structure. Therefore, the X86 environment is required.
However, both X86 and X64 methods are equal, but the structure and symmetry of the two are not the same.
PE format, which is a portable execution file in Microsoft Win32 environment, such as (exe/sys/dll/vxd/vdm ).
The PE format is derived from the COFF file format on VAX/VMS. Portable refers to different Windows versions and different
The format of PE files on the CPU type is the same. The CPU and binary encoding may be different,
The layout of the West is one to one.
In the PE file, the first byte is the MS-DOS information header, that is, the package of IMAGE_DOS_HEADER and IMAGE_NT_HEADER
It is used by many PE loaders.
[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)
Base Address: Image Base
Relative virtual Address Relative Virual Address (RVA)
Formula: RVA (relative virtual address) = VA (Virtual Address)-Image Base (Base address)
File offset address and virtual address conversion
In X86 systems, the size of each memory page is 4 kb.
File Offset = RVA (relative virtual address)-△k
File Offset = VA (Virtual Address)-Image Base (Base address)-△k
For details, refer to Baidu encyclopedia. If you want to understand it, you need to study the PE file by yourself.
IMAGE_NT_HEADERS is the standard Win32 execution File Information header after the MS-DOS information header, which contains
Imported function table, exported function table, resource information table, CLR runtime header, IAT, TLS table, including debugging information, etc.
What we need to do now is to get the function name exported in the DLL, And the DLL is a type
Therefore, we must obtain the IMAGE_NT_HEADERS structure. In fact, it is very easy to locate the NT structure,
In the regulations, the NT header is behind the DOS header, that is, IMAGE_DOS_HEADER.e_lfanew + IMAGE_DOS_HEADER
So you will see that I have such a sentence in the Code: IntPtr psNt32pe = (IntPtr) (sDos32pe. e_lfanew + (long) psDos32pe );
The optional IMAGE_OPTIONAL_HEADER image header is an optional structure, but the IMAGE_FILE_HEADER structure does not meet the PE file requirements.
Therefore, these attributes are defined in the OPTIONAL structure. Therefore, the combination of FILE and OPTIONAL is the same.
Contains many important information fields, such as AddressOfEntryPoint, DataDirectory, and Subsystem.
But when it comes to DataDirectory, I would like to mention that it is not well defined in C #, so this field is defined in the Code in another way, DataDirectory
The default size is 16 IMAGE_DATA_DIRECTORY, so you can see many definitions of this type in the code. They are tables.
The information in DataDirectory is IMAGE_DIRECTORY_ENTRY_EXPORT. to export a table, we only need to obtain its information. Here
We need to use ImageRvaToVa (relative to virtual address). Someone understands this. physical address to virtual address, but I used
When I understood it, it was a little bit difficult, but it was relieved later. ImageRvaToVa (NT_H, DOS_H, RVA, RvaSection );
IMAGE_DATA_DIRECTORY contains two fields, one VirtualAddress (RVA) and the other is Size (Size ).
RVA, but we can't use this address no matter how it is converted. Right, because the address provided to me cannot be used at all, we need
To convert to VA using the functions mentioned above, only thanks to Microsoft. After conversion, you will get IMAGE_EXPORT_DIRECTORY
Here, I want to remind you that not every RVA structure in DataDirectory is EXPORT and each has its own
Explain the structure, don't confuse it, or it will definitely fly high.
We need NumberOfNames (total number of function names) and AddressOfNames (function name address) in IMAGE_EXPORT_DIRECTORY)
But AddressOfNames contains a relatively virtual address RVA. Therefore, we need to perform a conversion to return
If the pointer to the char ** is valid, otherwise NULL is returned. Because char in C # occupies two bytes, that is, char = wchar_t.
We can check the data in the pointer. The DLL export function names are all Ascii encoded, so in order to facilitate the use of the C # dedicated IntPtr
The final operation of Marshal is just a resource release operation. Well, it's basically like this. The rest still need to be understood by yourself.
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); } } }
Copyright Disclaimer: This article is an original article by the blogger and cannot be reproduced without the permission of the blogger.