版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Vblegend_2013/article/details/82530486
很早的时候用VB6.0写过一次,今天找出来做成C# 的
完整源码下载地址
https://download.csdn.net/download/vblegend_2013/10653851
从内存加载DLL 步骤
1.加载DLLByte数组并校验数据有效性,通过校验 DOSHEADER、NTHEADER、SECTION_HEADER 三个位置实现验证
2.计算Dll加载到内存后所需要的空间,
3.申请内存,并设置为可读可写可执行
4.拷贝DLL中 步骤1中提到的三个段头,和所有区段数据到内存
5.重定位 IMAGE_DIRECTORY_ENTRY_BASERELOC 区段的重定位表
6.填充IMAGE_DIRECTORY_ENTRY_IMPORT 导入表里所有导入函数
7.调用Dll的DllMain函数通知DLL加载(加壳的DLL会在DllMain里进行壳的初始化)
使用方法
使用委托的方式调用API函数 下面例子演示了调用zlib.dLL里的compress函数
using System;
using System.IO;
namespace InvokeDll
{
class Program
{
public delegate Int32 CompressHandle(ref Byte dest,ref Int32 len, Byte [] source,Int32 sourcelen);
static void Main(string[] args)
{
Byte[] source = new byte[10000];
Byte[] dest = new byte[10000];
Int32 len = source.Length;
Byte[] dllBin = File.ReadAllBytes("zlib1.dll");
using (var dll = new DllLoader())
{
if (dll.LoadLibrary(dllBin))
{
var Compress = dll.GetProcDelegate<CompressHandle>("compress");
if (Compress != null)
{
var result = Compress.Invoke(ref dest[0], ref len, source, len);
Console.WriteLine(result);
}
}
}
}
}
}
需要使用到的WindowsAPI
using System;
using System.Runtime.InteropServices;
namespace InvokeDll.Win32
{
public enum IMAGE_DIRECTORY_ENTRY
{
IMAGE_DIRECTORY_ENTRY_EXPORT = 0,// ' Export Directory
IMAGE_DIRECTORY_ENTRY_IMPORT = 1,// ' Import Directory
IMAGE_DIRECTORY_ENTRY_RESOURCE = 2,// ' Resource Directory
IMAGE_DIRECTORY_ENTRY_EXCEPTION = 3,// ' Exception Directory
IMAGE_DIRECTORY_ENTRY_SECURITY = 4,// ' Security Directory
IMAGE_DIRECTORY_ENTRY_BASERELOC = 5,// ' Base Relocation Table
IMAGE_DIRECTORY_ENTRY_DEBUG = 6,// ' Debug Directory
IMAGE_DIRECTORY_ENTRY_ARCHITECTURE = 7,// ' Architecture Specific Data
IMAGE_DIRECTORY_ENTRY_GLOBALPTR = 8,// ' RVA of GP
IMAGE_DIRECTORY_ENTRY_TLS = 9,// ' TLS Directory
IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG = 10,// ' Load Configuration Directory
IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT = 11,// ' Bound Import Directory in headers
IMAGE_DIRECTORY_ENTRY_IAT = 12,// ;// ' Import Address Table
IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT = 13,// ' Delay Load Import Descriptors
IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR = 14// ' COM Runtime descriptor
}
public class API
{
public const Int32 MEM_COMMIT = 0x1000;
public const Int32 MEM_RESERVE = 0x2000;
public const Int32 MEM_RELEASE = 0x8000;
public const Int32 IMAGE_NT_SIGNATURE = 0x4550;
public const Int32 IMAGE_FILE_DLL = 0x2000;
public const Int32 PAGE_EXECUTE_READWRITE = 0x40;
public const Int32 IMAGE_REL_BASED_HIGHLOW = 3;
public const Int32 DLL_PROCESS_ATTACH = 1;
public const Int32 DLL_THREAD_ATTACH = 2;
public const Int32 DLL_THREAD_DETACH = 3;
public const Int32 DLL_PROCESS_DETACH = 0;
[DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)]
public static extern IntPtr VirtualAllocEx(Int32 hProcess, Int32 lpAddress, Int32 dwSize, Int32 flAllocationType, Int32 flProtect);
[DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)]
public static extern bool VirtualFreeEx(Int32 hProcess, IntPtr lpAddress, int dwSize, Int32 dwFreeType);
[DllImport("kernel32.dll")]
public static extern IntPtr GetModuleHandle(string lpModuleName);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern IntPtr LoadLibrary(string lpFileName);
[DllImport("kernel32", CharSet = CharSet.Ansi, ExactSpelling = true, SetLastError = true)]
public static extern IntPtr GetProcAddress(IntPtr hModule, string procName);
[DllImport("kernel32", CharSet = CharSet.Ansi, ExactSpelling = true, SetLastError = true)]
public static extern IntPtr GetProcAddress(IntPtr hModule, Int32 procName);
[DllImport("kernel32.dll")]
public static extern void CopyMemory(IntPtr Destination, IntPtr Source, int Length);
}
public unsafe struct IMAGE_FILE_HEADER
{
public Int16 Machine { get; set; }
public Int16 NumberOfSections { get; set; }
public Int32 TimeDateStamp { get; set; }
public Int32 PointerToSymbolTable { get; set; }
public Int32 NumberOfSymbols { get; set; }
public Int16 SizeOfOptionalHeader { get; set; }
public Int16 Characteristics { get; set; }
}
public unsafe struct IMAGE_DATA_DIRECTORY
{
public Int32 VirtualAddress { get; set; }
public Int32 Size { get; set; }
}
public unsafe struct IMAGE_MISC
{
public Int32 PhysicalAddress { get; set; }
public Int32 VirtualSize { get; set; }
}
public unsafe struct IMAGE_IMPORT_DESCRIPTOR
{
public Int32 OriginalFirstThunk { get; set; }
public Int32 TimeDateStamp { get; set; }
public Int32 ForwarderChain { get; set; }
public Int32 Name { get; set; }
public Int32 FirstThunk { get; set; }
}
public unsafe struct IMAGE_IMPORT_BY_NAME
{
public Int16 Hint { get; set; }
public fixed Byte Name_[260];
}
public unsafe struct IMAGE_EXPORT_DIRECTORY
{
public Int32 Characteristics { get; set; }
public Int32 TimeDateStamp { get; set; }
public Int16 MajorVersion { get; set; }
public Int16 MinorVersion { get; set; }
public Int32 pName { get; set; }
public Int32 Base { get; set; }
public Int32 NumberOfFunctions { get; set; }
public Int32 NumberOfNames { get; set; }
public Int32 AddressOfFunctions { get; set; }
public Int32 AddressOfNames { get; set; }
public Int32 AddressOfNameOrdinals { get; set; }
}
public unsafe struct IMAGE_DOS_HEADER
{
public Int16 e_magic { get; set; }
public Int16 e_cblp { get; set; }
public Int16 e_cp { get; set; }
public Int16 e_crlc { get; set; }
public Int16 e_cparhdr { get; set; }
public Int16 e_minalloc { get; set; }
public Int16 e_maxalloc { get; set; }
public Int16 e_ss { get; set; }
public Int16 e_sp { get; set; }
public Int16 e_csum { get; set; }
public Int16 e_ip { get; set; }
public Int16 e_cs { get; set; }
public Int16 e_lfarlc { get; set; }
public Int16 e_ovno { get; set; }
public fixed Int16 e_res[4];
public Int16 e_oemid { get; set; }
public Int16 e_oeminfo { get; set; }
public fixed Int16 e_res2[10];
public Int16 e_lfanew { get; set; }
}
public unsafe struct IMAGE_OPTIONAL_HEADER32
{
public Int16 Magic { get; set; }
public Byte MajorLinkerVersion { get; set; }
public Byte MinorLinkerVersion { get; set; }
public Int32 SizeOfCode { get; set; }
public Int32 SizeOfInitializedData { get; set; }
public Int32 SizeOfUninitializedData { get; set; }
public Int32 AddressOfEntryPoint { get; set; }
public Int32 BaseOfCode { get; set; }
public Int32 BaseOfData { get; set; }
public Int32 ImageBase { get; set; }
public Int32 SectionAlignment { get; set; }
public Int32 FileAlignment { get; set; }
public Int16 MajorOperatingSystemVersion { get; set; }
public Int16 MinorOperatingSystemVersion { get; set; }
public Int16 MajorImageVersion { get; set; }
public Int16 MinorImageVersion { get; set; }
public Int16 MajorSubsystemVersion { get; set; }
public Int16 MinorSubsystemVersion { get; set; }
public Int32 Win32VersionValue { get; set; }
public Int32 SizeOfImage { get; set; }
public Int32 SizeOfHeaders { get; set; }
public Int32 CheckSum { get; set; }
public Int16 Subsystem { get; set; }
public Int16 DllCharacteristics { get; set; }
public Int32 SizeOfStackReserve { get; set; }
public Int32 SizeOfStackCommit { get; set; }
public Int32 SizeOfHeapReserve { get; set; }
public Int32 SizeOfHeapCommit { get; set; }
public Int32 LoaderFlags { get; set; }
public Int32 NumberOfRvaAndSizes { get; set; }
public fixed Int32 DataDirectory[32];
/// <summary>
/// 获取数据目录
/// </summary>
/// <param name="index"></param>
/// <returns></returns>
public IMAGE_DATA_DIRECTORY GetDirectory(IMAGE_DIRECTORY_ENTRY index)
{
fixed (int* p = DataDirectory)
{
IMAGE_DATA_DIRECTORY* DATA = (IMAGE_DATA_DIRECTORY*)p;
DATA += (Int32)index;
return *DATA;
}
}
}
public unsafe struct IMAGE_NT_HEADERS
{
public Int32 Signature { get; set; }
public IMAGE_FILE_HEADER FileHeader { get; set; }
public IMAGE_OPTIONAL_HEADER32 OptionalHeader { get; set; }
}
//Public Const IMAGE_SIZEOF_SHORT_NAME As Long = 8&
public unsafe struct IMAGE_SECTION_HEADER
{
public fixed Byte Name_[8];
public Int32 Misc { get; set; }
public Int32 VirtualAddress { get; set; }
public Int32 SizeOfRawData { get; set; }
public Int32 PointerToRawData { get; set; }
public Int32 PointerToRelocations { get; set; }
public Int32 PointerToLinenumbers { get; set; }
public Int16 NumberOfRelocations { get; set; }
public Int16 NumberOfLinenumbers { get; set; }
public Int32 Characteristics { get; set; }
}
public unsafe struct IMAGE_BASE_RELOCATION
{
public Int32 VirtualAddress { get; set; }
public Int32 SizeOfBlock { get; set; }
}
}
DllLoader 类
using System;
using System.IO;
using System.Runtime.InteropServices;
using InvokeDll.Win32;
namespace InvokeDll
{
/// <summary>
/// DllMain函数委托
/// </summary>
/// <param name="hModule"></param>
/// <param name="ul_reason_for_call"></param>
/// <param name="lpReserved"></param>
/// <returns></returns>
public delegate Boolean DllMainHandle(IntPtr hModule, UInt32 ul_reason_for_call, IntPtr lpReserved);
/// <summary>
/// 动态链接库内存加载器
/// </summary>
public class DllLoader : IDisposable
{
/// <summary>
/// 从Byte数组加载Dll
/// </summary>
/// <param name="data"></param>
/// <returns></returns>
public Boolean LoadLibrary(Byte[] data)
{
IntPtr buffer = IntPtr.Zero;
try
{
buffer = Marshal.AllocHGlobal(data.Length);
Marshal.Copy(data, 0, buffer, data.Length);
return LoadDll(buffer, data.Length);
}
catch (Exception ex)
{
if (hModule != IntPtr.Zero)
{
API.VirtualFreeEx(-1, hModule, hModuleSize, API.MEM_RELEASE);
hModule = IntPtr.Zero;
}
throw ex;
}
finally
{
Marshal.FreeHGlobal(buffer);
}
}
/// <summary>
/// 加载dLL
/// </summary>
/// <param name="localPtr"></param>
/// <param name="DataLength"></param>
/// <returns></returns>
private unsafe Boolean LoadDll(IntPtr localPtr, Int32 DataLength)
{
IMAGE_DOS_HEADER* dosHeader = (IMAGE_DOS_HEADER*)localPtr;
IMAGE_NT_HEADERS* peHeader = (IMAGE_NT_HEADERS*)(localPtr + dosHeader->e_lfanew);
IMAGE_SECTION_HEADER* sectionHeader = (IMAGE_SECTION_HEADER*)(localPtr + dosHeader->e_lfanew + sizeof(IMAGE_NT_HEADERS));
if (dosHeader->e_magic != 0x5A4D)
{
throw new Exception("DOS file format error");
}
if (DataLength < dosHeader->e_lfanew + sizeof(IMAGE_DOS_HEADER))
{
throw new Exception("DOS file header data error");
}
if (peHeader->Signature != API.IMAGE_NT_SIGNATURE)
{
throw new Exception("windows file Signature error");
}
if ((peHeader->FileHeader.Characteristics & API.IMAGE_FILE_DLL) != API.IMAGE_FILE_DLL)
{
throw new Exception("Dll Not dynamic library");
}
for (int i = 0; i < peHeader->FileHeader.NumberOfSections; i++)
{
if (sectionHeader->PointerToRawData + sectionHeader->SizeOfRawData > DataLength)
{
throw new Exception("Section data error");
}
}
//计算空间
hModuleSize = CalcTotalImageSize(dosHeader, peHeader, sectionHeader);
if (hModuleSize <= 0 || hModuleSize > DataLength * 10)
{
throw new Exception("unknown error");
}
hModule = API.VirtualAllocEx(-1, peHeader->OptionalHeader.ImageBase, hModuleSize, API.MEM_COMMIT | API.MEM_RESERVE, API.PAGE_EXECUTE_READWRITE);
if (hModule == IntPtr.Zero)
{
hModule = API.VirtualAllocEx(-1, 0, hModuleSize, API.MEM_COMMIT | API.MEM_RESERVE, API.PAGE_EXECUTE_READWRITE);
}
if (hModule == IntPtr.Zero)
{
throw new Exception("run out of memory?");
}
CopyDllDatas(localPtr, dosHeader, peHeader, sectionHeader);
dosHeader = (IMAGE_DOS_HEADER*)hModule;
peHeader = (IMAGE_NT_HEADERS*)(hModule + dosHeader->e_lfanew);
sectionHeader = (IMAGE_SECTION_HEADER*)(hModule + dosHeader->e_lfanew + sizeof(IMAGE_NT_HEADERS));
//重定位
var DataDictory = peHeader->OptionalHeader.GetDirectory(IMAGE_DIRECTORY_ENTRY.IMAGE_DIRECTORY_ENTRY_BASERELOC);
if (DataDictory.VirtualAddress > 0 && DataDictory.Size > 0)
{
ReLocation(peHeader);
}
FillImportTable(peHeader);
DllMain = (DllMainHandle)Marshal.GetDelegateForFunctionPointer(hModule + peHeader->OptionalHeader.AddressOfEntryPoint, typeof(DllMainHandle));
return DllMain.Invoke(hModule, API.DLL_PROCESS_ATTACH, IntPtr.Zero);
}
/// <summary>
/// 填充导入表
/// </summary>
/// <param name="peHeader"></param>
private unsafe void FillImportTable(IMAGE_NT_HEADERS* peHeader)
{
var Offset = peHeader->OptionalHeader.GetDirectory(IMAGE_DIRECTORY_ENTRY.IMAGE_DIRECTORY_ENTRY_IMPORT).VirtualAddress;
if (Offset == 0)
{
return;
}
IMAGE_IMPORT_DESCRIPTOR* Import = (IMAGE_IMPORT_DESCRIPTOR*)(hModule + Offset);
while (Import->FirstThunk > 0)
{
Int32* pRealIAT = (Int32*)(hModule + Import->FirstThunk);
Int32* pOriginalIAT =
(Int32*)(hModule + (Import->OriginalFirstThunk > 0
? Import->OriginalFirstThunk
: Import->FirstThunk));
var DllName = Marshal.PtrToStringAnsi(hModule + Import->Name);
var hDll = API.GetModuleHandle(DllName);
if (hDll == IntPtr.Zero)
{
hDll = API.LoadLibrary(DllName);
}
if (hDll == IntPtr.Zero)
{
throw new Exception(String.Format("load library({0}) fail", DllName));
}
while (*pOriginalIAT > 0)
{
IntPtr lpfunc = IntPtr.Zero;
if (*pOriginalIAT < 0)
{
var funid = *pOriginalIAT | 0x80000000;
lpfunc = API.GetProcAddress(hDll, (Int32)funid);
}
else
{
var funname = Marshal.PtrToStringAnsi(hModule + *pOriginalIAT + 2);
lpfunc = API.GetProcAddress(hDll, funname);
}
if (lpfunc != IntPtr.Zero)
{
*pRealIAT = (Int32)lpfunc;
}
pRealIAT++;
pOriginalIAT++;
}
Import++;
}
}
/// <summary>
/// 获取API函数委托
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="procname"></param>
/// <returns></returns>
public T GetProcDelegate<T>(String procname) where T : Delegate
{
var addr = GetProcAddress(procname);
if (addr == IntPtr.Zero)
{
return default(T);
}
return (T)Marshal.GetDelegateForFunctionPointer(addr, typeof(T));
}
/// <summary>
/// 获取API函数地址
/// </summary>
/// <param name="procName"></param>
/// <returns></returns>
public unsafe IntPtr GetProcAddress(String procName)
{
if (hModule == IntPtr.Zero)
{
return IntPtr.Zero;
}
IMAGE_DOS_HEADER* dosHeader = (IMAGE_DOS_HEADER*)hModule;
IMAGE_NT_HEADERS* peHeader = (IMAGE_NT_HEADERS*)(hModule + dosHeader->e_lfanew);
var Export = peHeader->OptionalHeader.GetDirectory(IMAGE_DIRECTORY_ENTRY.IMAGE_DIRECTORY_ENTRY_EXPORT);
if (Export.VirtualAddress == 0 || Export.Size == 0)
{
return IntPtr.Zero;
}
IMAGE_EXPORT_DIRECTORY* lpExport = (IMAGE_EXPORT_DIRECTORY*)(hModule + Export.VirtualAddress);
Int16* ordinals = (Int16*)(hModule + lpExport->AddressOfNameOrdinals);
Int32* lpName = (Int32*)(hModule + lpExport->AddressOfNames);
for (int i = 0; i < lpExport->NumberOfNames; i++)
{
var DllName = Marshal.PtrToStringAnsi(hModule + *lpName);
if (DllName == procName)
{
if (*ordinals > 0 && *ordinals <= lpExport->NumberOfFunctions)
{
Int32* funcoffset = (Int32*)(hModule + lpExport->AddressOfFunctions + *ordinals * 4);
return new IntPtr((Int32)hModule + *funcoffset);
}
}
lpName++;
ordinals++;
}
return IntPtr.Zero;
}
/// <summary>
/// 重定位表的处理
/// </summary>
/// <param name="peHeader"></param>
private unsafe void ReLocation(IMAGE_NT_HEADERS* peHeader)
{
Int32 delta = (Int32)hModule - peHeader->OptionalHeader.ImageBase;
if (delta == 0)
{
//是不是不需要重定位了
//return;
}
var adr = hModule + peHeader->OptionalHeader.GetDirectory(IMAGE_DIRECTORY_ENTRY.IMAGE_DIRECTORY_ENTRY_BASERELOC).VirtualAddress;
IMAGE_BASE_RELOCATION* relocation = (IMAGE_BASE_RELOCATION*)adr;
while (relocation->VirtualAddress > 0 && relocation->SizeOfBlock > 0)
{
var pLocData = adr + sizeof(IMAGE_BASE_RELOCATION);
var NumberOfReloc = (relocation->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) / 2;
for (int i = 0; i < NumberOfReloc; i++)
{
Int16* LONG = (Int16*)pLocData + i * 2;
if ((*LONG & 0xFFFF) / 4096 == API.IMAGE_REL_BASED_HIGHLOW)
{
var v = relocation->VirtualAddress + (*LONG & 0xFFF);
Int32* lpPoint = (Int32*)(hModule + relocation->VirtualAddress + (*LONG & 0xFFF));
*lpPoint += delta;
}
}
adr = adr + relocation->SizeOfBlock;
relocation = (IMAGE_BASE_RELOCATION*)(adr);
}
}
/// <summary>
/// 拷贝区段数据到内存
/// </summary>
/// <param name="dosHeader"></param>
/// <param name="peHeader"></param>
/// <param name="sectionHeader"></param>
private unsafe void CopyDllDatas(IntPtr localPtr, IMAGE_DOS_HEADER* dosHeader, IMAGE_NT_HEADERS* peHeader, IMAGE_SECTION_HEADER* sectionHeader)
{
var HeaderSize = peHeader->OptionalHeader.SizeOfHeaders;
var SectionSize = peHeader->FileHeader.NumberOfSections * sizeof(IMAGE_SECTION_HEADER);
var MoveSize = HeaderSize + SectionSize;
API.CopyMemory(hModule, localPtr, MoveSize);
for (int i = 0; i < peHeader->FileHeader.NumberOfSections; i++)
{
if (sectionHeader[i].VirtualAddress > 0 && sectionHeader[i].SizeOfRawData > 0)
{
var lpSection = hModule + sectionHeader[i].VirtualAddress;
API.CopyMemory(lpSection, localPtr + sectionHeader[i].PointerToRawData, sectionHeader[i].SizeOfRawData);
}
}
}
/// <summary>
/// 计算要申请的内存空间大小
/// </summary>
/// <param name="dosHeader"></param>
/// <param name="peHeader"></param>
/// <param name="sectionHeader"></param>
/// <returns></returns>
private unsafe Int32 CalcTotalImageSize(IMAGE_DOS_HEADER* dosHeader, IMAGE_NT_HEADERS* peHeader, IMAGE_SECTION_HEADER* sectionHeader)
{
var nAlign = peHeader->OptionalHeader.SectionAlignment;
var Size = GetAlignedSize(peHeader->OptionalHeader.SizeOfHeaders, nAlign);
for (int i = 0; i < peHeader->FileHeader.NumberOfSections; i++)
{
var CodeSize = sectionHeader[i].Misc;
var LoadSize = sectionHeader[i].SizeOfRawData;
var MaxSize = LoadSize > CodeSize ? LoadSize : CodeSize;
var SectionSize = GetAlignedSize(sectionHeader[i].VirtualAddress + MaxSize, nAlign);
if (Size < SectionSize)
{
Size = SectionSize;
}
}
return Size + 1;
}
/// <summary>
/// 对齐
/// </summary>
/// <param name="origin"></param>
/// <param name="Alignment"></param>
/// <returns></returns>
private Int32 GetAlignedSize(Int32 origin, Int32 Alignment)
{
return (origin + Alignment - 1) / Alignment * Alignment;
}
/// <summary>
/// 释放DLL
/// </summary>
/// <returns></returns>
public Boolean FreeLibrary()
{
if (hModule != IntPtr.Zero)
{
//调用 DllMain 通知卸载DLL
var dll = DllMain.Invoke(hModule, API.DLL_PROCESS_DETACH, IntPtr.Zero);
if (dll)
{
//释放内存空间
API.VirtualFreeEx(-1, hModule, hModuleSize, API.MEM_RELEASE);
hModule = IntPtr.Zero;
return true;
}
else
{
return false;
}
}
return true;
}
/// <summary>
/// 销毁 清理
/// </summary>
public void Dispose()
{
FreeLibrary();
}
/// <summary>
/// 模块大小
/// </summary>
private Int32 hModuleSize { get; set; }
/// <summary>
/// 模块句柄
/// </summary>
public IntPtr hModule { get; private set; }
/// <summary>
/// DllMain 函数委托,用于通知DLL 模块加载卸载等
/// </summary>
public DllMainHandle DllMain { get; private set; }
}
}