分享一个简短的内存加载DLL EXE C++源码
实现类似功能的代码很多,但是我这份没有参考到别人的代码,纯粹是看微软文档撸出来的。这个需求是源于我的一个比较复杂的x86_64 shellcode,需要实现的功能很多,依赖也很多。因此用传统的方法弄的shellcode很不方便。于是我想着直接用dll/exe当作shellcode,写一个简短的linker控制在0x1000字节以内,将linker直接填在PE头处,调用时直接call头部的linker实现dll/exe的self link并执行。需求已经测试通过,完整项目不能发出来,但是可以跟大家分享验证阶段的测试代码。主要原理:
SDK_GetProcAddress 解析kernel32拿到LoadLibraryA和GetProcAddress供linker使用。如果不是裸的代码,这里不需要。
SDK_LoadLibrary 解析dos头和nt头,并将section展开到内存。
RelocImage进行image base重定向
LinkDLL加载和连接依赖的dll
这里并没有处理TLS和32位的支持。这个有机会再说吧。
以下代码用mingw-w64编译,可加载运行vs和mingw-w64编译出来的pe。
#include <windows.h>
#include <stdio.h>
#include <string.h>
#include "winapi.h"
#ifndef MIN
#define MIN(a, b) ((a) > (b) ? (b) : (a))
#endif
#define RVA(a) ((PVOID)((ULONG_PTR)hExecutable + (a)))
#define K32RVA(a) ((PVOID)((ULONG_PTR)hKernel32 + (a)))
#define API pContext->
typedef struct {
union {
#ifdef _WIN64
struct {
DWORD64Unused1:63;
DWORD64OrdinalIfSet:1;
} Flag;
DWORD64 Long;
#else
struct {
DWORDUnused1:31;
DWORDOrdinalIfSet:1;
} Flag;
DWORD Long;
#endif
WORD OrdinalNumber;
DWORD NameAddress;
} u;
} IMPORT_LOOKUP_DESC, *PIMPORT_LOOKUP_DESC;
typedef struct {
LoadLibraryA_t LoadLibraryA;
GetProcAddress_t GetProcAddress;
GetModuleHandleA_t GetModuleHandleA;
} LINK_CONTEXT, *PLINK_CONTEXT;
typedef struct {
DWORD Page;
DWORD BlockSize;
struct {
WORD Offset:12;
WORD Type:4;
} TypeOffset;
} BASE_RELOCATION_BLOCK, *PBASE_RELOCATION_BLOCK;
HMODULE hExecutable = NULL;
int SDK_strcmp(const char *s1, const char *s2)
{
while(*s1 && *s2) {
if (*s1 != *s2)
return -1;
s1 ++;
s2 ++;
}
return *s2 - *s1;
}
PVOID SDK_GetProcAddress(HMODULE hKernel32, const char *FuncName)
{
PIMAGE_DOS_HEADER pDos = (PIMAGE_DOS_HEADER)hKernel32;
PIMAGE_NT_HEADERS pNt = (PIMAGE_NT_HEADERS)((char *)pDos + pDos->e_lfanew);
PIMAGE_EXPORT_DIRECTORY EDT = (PIMAGE_EXPORT_DIRECTORY)K32RVA(pNt->OptionalHeader.DataDirectory.VirtualAddress);
// printf("DLL Name: %s\n", K32RVA(EDT->Name));
// printf("Number Of Functions: %d\n", EDT->NumberOfFunctions);
// printf("Number Of Names: %d\n", EDT->NumberOfNames);
PDWORD ExportAddressTable = (PDWORD)MOD_RVA(EDT->AddressOfFunctions);
PDWORD ExportNamePointerTable = (PDWORD)MOD_RVA(EDT->AddressOfNames);
PWORD ExportOrdinalTable= (PWORD)MOD_RVA(EDT->AddressOfNameOrdinals);
for(size_t i = 0; i < EDT->NumberOfNames; i++)
{
PCHAR name = (PCHAR)MOD_RVA(ExportNamePointerTable);
if (SDK_strcmp(name, FuncName) == 0) {
WORD Ordinal = ExportOrdinalTable;
return (PVOID)MOD_RVA(ExportAddressTable);
}
}
return NULL;
}
void LinkDLL(PLINK_CONTEXT pContext, PIMAGE_IMPORT_DESCRIPTOR IDT)
{
const char* DLLName = (const char*)RVA(IDT->Name);
HMODULE hDLL = API GetModuleHandleA(DLLName);
if (!hDLL) {
hDLL = API LoadLibraryA(DLLName);
}
if (!hDLL) {
return -1;
}
printf("** %s **\n", DLLName);
PIMPORT_LOOKUP_DESC ILD = (PIMPORT_LOOKUP_DESC)RVA(IDT->OriginalFirstThunk);
PULONG_PTR IAT = (PULONG_PTR)RVA(IDT->FirstThunk);
while (ILD->u.Long) {
if (!ILD->u.Flag.OrdinalIfSet) {
*IAT = (ULONG_PTR) API GetProcAddress(hDLL, (PCSTR)RVA(ILD->u.NameAddress+2));
printf("%s %p\n", RVA(ILD->u.NameAddress+2), *IAT);
} else {
*IAT = (ULONG_PTR) API GetProcAddress(hDLL, (PCSTR)MAKEINTRESOURCE(ILD->u.OrdinalNumber));
printf("%d %p\n", RVA(ILD->u.OrdinalNumber), *IAT);
}
IAT ++;
ILD ++;
}
}
void RelocImage(PBASE_RELOCATION_BLOCK BRB, ptrdiff_t Difference)
{
printf("Difference: %ld\n", Difference);
for(size_t i = 0; i < (BRB->BlockSize - 8)/2; i++)
{
WORD Offset = BRB->TypeOffset.Offset;
printf("0x%.4x\t%d ", Offset, BRB->TypeOffset.Type);
switch(BRB->TypeOffset.Type) {
case IMAGE_REL_BASED_ABSOLUTE:break; // The base relocation is skipped
case IMAGE_REL_BASED_HIGHLOW: // TODO Not test yet
*(DWORD*)RVA(BRB->Page + Offset) += Difference;
break;
case IMAGE_REL_BASED_DIR64:
printf("DIR64 %lx => ", *(ptrdiff_t*)RVA(BRB->Page + Offset));
*(ptrdiff_t*)RVA(BRB->Page + Offset) += Difference;
printf("%lx", *(ptrdiff_t*)RVA(BRB->Page + Offset));
break;
default:
fprintf(stderr, "Not support this relocation type yet.");
abort();
break;
}
putchar('\n');
}
}
#define LLRVA(a) ((PVOID)((char*)Image + (a)))
HMODULE SDK_LoadLibrary(PCSTR LibraryName)
{
IMAGE_DOS_HEADER DosHdr;
IMAGE_NT_HEADERS NtHdr;
HMODULE hModule = NULL;
FILE *libfp = fopen(LibraryName, "rb");
if (!libfp)
goto CLEAN;
fread(&DosHdr, sizeof(IMAGE_DOS_HEADER), 1, libfp);
fseek(libfp, DosHdr.e_lfanew, SEEK_SET);
fread(&NtHdr, sizeof(IMAGE_NT_HEADERS), 1, libfp);
PVOID Image = VirtualAlloc(NULL, NtHdr.OptionalHeader.SizeOfImage, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
if (!Image)
goto CLEAN;
fseek(libfp, 0, SEEK_SET);
fread(Image, NtHdr.OptionalHeader.SizeOfHeaders, 1, libfp);
PIMAGE_NT_HEADERS pNt = (PIMAGE_NT_HEADERS)((char *)Image + DosHdr.e_lfanew);
PIMAGE_SECTION_HEADER Sections = IMAGE_FIRST_SECTION(pNt);
for(size_t i = 0; i < pNt->FileHeader.NumberOfSections; i++)
{
fseek(libfp, Sections.PointerToRawData, SEEK_SET);
fread(LLRVA(Sections.VirtualAddress), Sections.SizeOfRawData, 1, libfp);
printf("%s\n", Sections.Name);
}
hModule = (HMODULE)Image;
CLEAN:
if (libfp)
fclose(libfp);
return hModule;
}
void SDK_FreeLibrary(HMODULE hModule)
{
VirtualFree(hModule, 0, MEM_RELEASE);
}
int main(int argc, const char *argv[])
{
LINK_CONTEXT Context;
if (argc != 2) {
fprintf(stderr, "Missing dll\n");
return -1;
}
HMODULE hKernel32 = GetModuleHandleA("kernel32.dll");
Context.LoadLibraryA = (LoadLibraryA_t)SDK_GetProcAddress(hKernel32, "LoadLibraryA");
Context.GetProcAddress = (GetProcAddress_t)SDK_GetProcAddress(hKernel32, "GetProcAddress");
Context.GetModuleHandleA = (GetModuleHandleA_t)SDK_GetProcAddress(hKernel32, "GetModuleHandleA");
printf("LoadLibraryA\t\t%p\n", Context.LoadLibraryA);
printf("GetProcAddress\t\t%p\n", Context.GetProcAddress);
printf("GetModuleHandleA\t%p\n", Context.GetModuleHandleA);
hExecutable = SDK_LoadLibrary(argv);
if (hExecutable == NULL) {
fprintf(stderr, "Can not load dll\n");
exit(-1);
}
PIMAGE_DOS_HEADER pDos = (PIMAGE_DOS_HEADER)hExecutable;
PIMAGE_NT_HEADERS pNt = (PIMAGE_NT_HEADERS)((char *)pDos + pDos->e_lfanew);
if ((PVOID)hExecutable != (PVOID)pNt->OptionalHeader.ImageBase)
{
printf("Image Base: %p\n", pNt->OptionalHeader.ImageBase);
printf("Loaded Base: %p\n", hExecutable);
ptrdiff_t Difference = (ptrdiff_t)hExecutable - (ptrdiff_t)pNt->OptionalHeader.ImageBase;
PBASE_RELOCATION_BLOCK BRB = (PBASE_RELOCATION_BLOCK)RVA(pNt->OptionalHeader.DataDirectory.VirtualAddress);
while (BRB->BlockSize) {
RelocImage(BRB, Difference);
BRB = (PBASE_RELOCATION_BLOCK)((char*)BRB + BRB->BlockSize);
}
}
PIMAGE_IMPORT_DESCRIPTOR IDT = (PIMAGE_IMPORT_DESCRIPTOR)RVA(pNt->OptionalHeader.DataDirectory.VirtualAddress);
while (IDT->Name != 0) {
LinkDLL(&Context, IDT);
IDT ++;
}
((void(*)(HMODULE,DWORD,PVOID))RVA(pNt->OptionalHeader.AddressOfEntryPoint))(hExecutable, DLL_PROCESS_ATTACH, NULL);
SDK_FreeLibrary(hExecutable);
return 0;
}
页:
[1]