很早的时候用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);
}
}
}
}
}
}
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; }
}
}