Files
luckyware/LuckywareCode/LuckywareStub/ExInfector/winpe.h
T
2026-08-27 11:23:03 -06:00

1180 lines
40 KiB
C

#ifndef _WINPE_H
#define _WINPE_H
#define WINPE_VERSION 370
#ifdef USECOMPAT
#include "commdef_v100.h"
#else
#include "commdef.h"
#endif // USECOMPAT
// define specific macro
#ifdef WINPE_API
#undef WINPE_API
#endif
#ifdef WINPE_API_DEF
#undef WINPE_API_DEF
#endif
#ifdef WINPE_API_EXPORT
#undef WINPE_API_EXPORT
#endif
#ifdef WINPE_API_INLINE
#undef WINPE_API_INLINE
#endif
#ifdef WINPE_STATIC
#define WINPE_API_DEF static
#else
#define WINPE_API_DEF extern
#endif // WINPE_STATIC
#ifdef WINPE_SHARED
#define WINPE_API_EXPORT EXPORT
#else
#define WINPE_API_EXPORT
#endif // WINPE_SHARED
#ifdef WINPE_NOINLINE
#define WINPE_API_INLINE
#else
#define WINPE_API_INLINE INLINE
#endif // WINPE_NOINLINE
#define WINPE_API WINPE_API_DEF WINPE_API_EXPORT WINPE_API_INLINE
// declear
#ifdef __cplusplus
extern "C" {
#endif // __cplusplus
#include <stdint.h>
#include <windows.h>
#include <winternl.h>
typedef struct _RELOCOFFSET
{
WORD offset : 12;
WORD type : 4;
}RELOCOFFSET,*PRELOCOFFSET;
typedef int bool_t;
typedef HMODULE (WINAPI *PFN_LoadLibraryA)(
LPCSTR lpLibFileName);
typedef FARPROC (WINAPI *PFN_GetProcAddress)(
HMODULE hModule, LPCSTR lpProcName);
typedef PFN_GetProcAddress PFN_GetProcRVA;
typedef LPVOID (WINAPI *PFN_VirtualAlloc)(
LPVOID lpAddress, SIZE_T dwSize,
DWORD flAllocationType, DWORD flProtect);
typedef BOOL (WINAPI *PFN_VirtualFree)(
LPVOID lpAddress, SIZE_T dwSize,
DWORD dwFreeType);
typedef BOOL (WINAPI *PFN_VirtualProtect)(
LPVOID lpAddress, SIZE_T dwSize,
DWORD flNewProtect, PDWORD lpflOldProtect);
typedef SIZE_T (WINAPI *PFN_VirtualQuery)(
LPCVOID lpAddress,
PMEMORY_BASIC_INFORMATION lpBuffer,
SIZE_T dwLength);
typedef BOOL (WINAPI *PFN_DllMain)(HINSTANCE hinstDLL,
DWORD fdwReason, LPVOID lpReserved );
#define WINPE_LDFLAG_MEMALLOC 0x1
#define WINPE_LDFLAG_MEMFIND 0x2
/**
* load the origin rawpe file in memory buffer by mem align
* mempe means the pe in memory alignment
* @param pmemsize mempe buffer size
* @return mempe buf
*/
WINPE_API
void* STDCALL winpe_memload_file(const char *path, size_t *pmemsize, bool_t same_align);
/**
* load the overlay data in a pe file
* @param pmemsize overlay size
* @return overlay buf
*/
WINPE_API
void* STDCALL winpe_overlayload_file(const char *path, size_t *poverlaysize);
/**
* similar to LoadlibrayA,
* will load the mempe in a valid imagebase
* @return hmodule base
*/
WINPE_API
void* STDCALL winpe_memLoadLibrary(void *mempe);
/**
* load the mempe in a valid imagebase, will call dll entry
* @param imagebase if 0, will load on mempe, else in imagebase
* @param flag WINPE_LDFLAG_MEMALLOC 0x1, will alloc memory to imagebase
* WINPE_LDFLAG_MEMFIND 0x2, will find a valid space,
* @return hmodule base
*/
WINPE_API
void* STDCALL winpe_memLoadLibraryEx(void *mempe, size_t imagebase, DWORD flag,
PFN_LoadLibraryA pfnLoadLibraryA, PFN_GetProcAddress pfnGetProcAddress);
/**
* similar to FreeLibrary, will call dll entry
* @return True on successful
*/
WINPE_API
BOOL STDCALL winpe_memFreeLibrary(void *mempe);
WINPE_API
BOOL STDCALL winpe_memFreeLibraryEx(void *mempe,
PFN_LoadLibraryA pfnLoadLibraryA, PFN_GetProcAddress pfnGetProcAddress);
/**
* similar to GetProcAddress
* @return function va
*/
WINPE_API
PROC STDCALL winpe_memGetProcAddress(void *mempe, const char *funcname);
/**
* use peb and ldr list, to obtain to find kernel32.dll address
* @return kernel32.dll va
*/
WINPE_API
void* winpe_findkernel32();
/**
* use peb and ldr list, similar as GetModuleHandleA
* @return ldr module address
*/
WINPE_API
void* STDCALL winpe_findmoduleaex(PPEB peb, const char *modulename);
WINPE_API
void* STDCALL winpe_findmodulea(const char *modulename)
{
return winpe_findmoduleaex(NULL, modulename);
}
/**
* @return LoadLibraryA func addr
*/
WINPE_API
PROC winpe_findloadlibrarya();
/**
* @return GetProcAddress func addr
*/
WINPE_API
PROC winpe_findgetprocaddress();
/**
* find a valid space address start from imagebase with imagesize
* @return va
*/
WINPE_API
void* STDCALL winpe_findspace(
size_t imagebase, size_t imagesize, size_t alignsize,
PFN_VirtualQuery pfnVirtualQuery);
/**
* @return the overlay offset
*/
WINPE_API
size_t STDCALL winpe_overlayoffset(const void *rawpe);
/**
* load the origin rawpe in memory buffer by mem align
* @return memsize
*/
WINPE_API
size_t STDCALL winpe_memload(const void *rawpe, size_t rawsize,
void *mempe, size_t memsize, bool_t same_align);
/**
* realoc the addrs for the mempe addr as image base
* origin image base usually at 0x00400000, 0x0000000180000000
* new image base mush be divided by 0x10000, if use loadlibrary
* @return reloc count
*/
WINPE_API
size_t STDCALL winpe_memreloc(void *mempe, size_t newimagebase);
/**
* load the iat for the mempe, use rvafunc for winpe_memfindexp
* @return iat count
*/
WINPE_API
size_t STDCALL winpe_membindiat(void *mempe,
PFN_LoadLibraryA pfnLoadLibraryA, PFN_GetProcAddress pfnGetProcAddress);
/**
* exec the tls callbacks for the mempe, before dll oep load
* @param reason for function PIMAGE_TLS_CALLBACK
* @return tls count
*/
WINPE_API
size_t STDCALL winpe_membindtls(void *mempe, DWORD reason);
/**
* find the iat addres, for call [iat]
* @return target iat va
*/
WINPE_API
void* STDCALL winpe_memfindiat(void *mempe, LPCSTR dllname, LPCSTR funcname);
/**
* find the exp addres, the same as GetProcAddress,
* without forward to other dll, such as NTDLL.RtlInitializeSListHead
* @return target exp va
*/
WINPE_API
void* STDCALL winpe_memfindexp(void *mempe, LPCSTR funcname);
WINPE_API
void* STDCALL winpe_memfindexpcrc32(void* mempe, uint32_t crc32);
/**
* forward the exp to the final expva
* @return the final exp va
*/
WINPE_API
void* STDCALL winpe_memforwardexp(void *mempe, size_t exprva,
PFN_LoadLibraryA pfnLoadLibraryA, PFN_GetProcAddress pfnGetProcAddress);
/**
* change the oep of the pe if newoeprva!=0
* @return the old oep rva
*/
WINPE_API
DWORD STDCALL winpe_oepval(void *mempe, DWORD newoeprva);
/**
* change the imagebase of the pe if newimagebase!=0
* @return the old imagebase va
*/
WINPE_API
size_t STDCALL winpe_imagebaseval(void *mempe, size_t newimagebase);
/**
* change the imagesize of the pe if newimagesize!=0
* @return the old imagesize
*/
WINPE_API
size_t STDCALL winpe_imagesizeval(void *pe, size_t newimagesize);
/**
* set off the aslr feature of an pe
*/
WINPE_API
void STDCALL winpe_noaslr(void *pe);
/**
* append a section header in a pe, sect rva will be ignored
* the mempe size must be enough for extend a section
* @return image size
*/
WINPE_API
size_t STDCALL winpe_appendsecth(void *mempe, PIMAGE_SECTION_HEADER psecth);
#ifdef __cplusplus
}
#endif // __cplusplus
// implement
#ifdef WINPE_IMPLEMENTATION
#if defined(__TINYC__)
#ifdef _WIN64
#pragma pack(8)
#else
#pragma pack(4)
#endif
#endif
#include <stdio.h>
#include <assert.h>
#include <windows.h>
#include <winternl.h>
void* STDCALL winpe_memload_file(const char* path, size_t* pmemsize, bool_t same_align)
{
if (!path) {
if (pmemsize) *pmemsize = 0;
return NULL; // Invalid path
}
// Open file with error checking
FILE* fp = fopen(path, "rb");
if (!fp) {
perror("fopen failed");
if (pmemsize) *pmemsize = 0;
return NULL; // File not found or inaccessible
}
// Get file size safely
if (fseek(fp, 0, SEEK_END) != 0) {
fclose(fp);
if (pmemsize) *pmemsize = 0;
return NULL; // Seek failed
}
long rawsize_long = ftell(fp);
if (rawsize_long <= 0 || rawsize_long > SIZE_MAX) {
fclose(fp);
if (pmemsize) *pmemsize = 0;
return NULL; // Invalid file size
}
size_t rawsize = (size_t)rawsize_long;
rewind(fp);
// Debug: Log the size before allocation
printf("Allocating %zu bytes for rawpe (path: %s)\n", rawsize, path);
// Alternative allocation with VirtualAlloc (Windows-specific workaround)
void* rawpe = NULL;
HMODULE hKernel32 = GetModuleHandleA("kernel32.dll");
if (hKernel32) {
FARPROC pVirtualAlloc = GetProcAddress(hKernel32, "VirtualAlloc");
if (pVirtualAlloc) {
rawpe = ((LPVOID(WINAPI*)(LPVOID, SIZE_T, DWORD, DWORD))pVirtualAlloc)(
NULL, rawsize, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
}
}
// Fallback to malloc if VirtualAlloc isn't available or fails
if (!rawpe) {
printf("GOING FOR MALLOC! \n");
rawpe = malloc(rawsize);
}
if (!rawpe) {
perror("Allocation failed for rawpe");
printf("Failed to allocate %zu bytes\n", rawsize);
fclose(fp);
if (pmemsize) *pmemsize = 0;
return NULL; // Memory allocation failed
}
// Debug: Confirm allocation succeeded
printf("Successfully allocated %zu bytes at %p\n", rawsize, rawpe);
// Read file into buffer
size_t bytes_read = fread(rawpe, 1, rawsize, fp);
fclose(fp);
if (bytes_read != rawsize) {
printf("Read failed: expected %zu, got %zu\n", rawsize, bytes_read);
if (hKernel32 && rawpe) {
FARPROC pVirtualFree = GetProcAddress(hKernel32, "VirtualFree");
if (pVirtualFree) {
((BOOL(WINAPI*)(LPVOID, SIZE_T, DWORD))pVirtualFree)(rawpe, 0, MEM_RELEASE);
}
}
else
{
free(rawpe);
}
if (pmemsize) *pmemsize = 0;
return NULL; // Incomplete read
}
// Calculate required memory size for aligned PE
void* mempe = NULL;
if (pmemsize) {
*pmemsize = winpe_memload(rawpe, rawsize, NULL, 0, FALSE);
if (*pmemsize == 0) {
printf("winpe_memload failed to calculate size\n");
if (hKernel32 && rawpe) {
FARPROC pVirtualFree = GetProcAddress(hKernel32, "VirtualFree");
if (pVirtualFree) {
((BOOL(WINAPI*)(LPVOID, SIZE_T, DWORD))pVirtualFree)(rawpe, 0, MEM_RELEASE);
}
}
else
{
free(rawpe);
}
return NULL;
}
mempe = malloc(*pmemsize);
if (!mempe) {
perror("malloc failed for mempe");
printf("Failed to allocate %zu bytes\n", *pmemsize);
if (hKernel32 && rawpe) {
FARPROC pVirtualFree = GetProcAddress(hKernel32, "VirtualFree");
if (pVirtualFree) {
((BOOL(WINAPI*)(LPVOID, SIZE_T, DWORD))pVirtualFree)(rawpe, 0, MEM_RELEASE);
}
}
else
{
free(rawpe);
}
*pmemsize = 0;
return NULL;
}
size_t loaded_size = winpe_memload(rawpe, rawsize, mempe, *pmemsize, same_align);
if (loaded_size == 0) {
printf("winpe_memload failed to load PE\n");
free(mempe);
if (hKernel32 && rawpe) {
FARPROC pVirtualFree = GetProcAddress(hKernel32, "VirtualFree");
if (pVirtualFree) {
((BOOL(WINAPI*)(LPVOID, SIZE_T, DWORD))pVirtualFree)(rawpe, 0, MEM_RELEASE);
}
}
else
{
free(rawpe);
}
*pmemsize = 0;
return NULL;
}
}
if (hKernel32 && rawpe) {
FARPROC pVirtualFree = GetProcAddress(hKernel32, "VirtualFree");
if (pVirtualFree) {
((BOOL(WINAPI*)(LPVOID, SIZE_T, DWORD))pVirtualFree)(rawpe, 0, MEM_RELEASE);
}
}
else
{
free(rawpe);
}
return mempe;
}
void* STDCALL winpe_memload_buffer(const void* rawpe, size_t rawsize, size_t* pmemsize, bool_t same_align)
{
void* mempe = NULL;
if (pmemsize)
{
*pmemsize = winpe_memload(rawpe, rawsize, NULL, 0, FALSE);
mempe = malloc(*pmemsize);
winpe_memload(rawpe, rawsize, mempe, *pmemsize, same_align);
}
return mempe;
}
void* STDCALL winpe_overlayload_file(const char *path, size_t *poverlaysize)
{
FILE *fp = fopen(path, "rb");
fseek(fp, 0, SEEK_END);
size_t rawsize = ftell(fp);
fseek(fp, 0, SEEK_SET);
void *rawpe = malloc(rawsize);
fread(rawpe, 1, rawsize, fp);
fclose(fp);
void *overlay = NULL;
size_t overlayoffset = winpe_overlayoffset(rawpe);
if(poverlaysize)
{
*poverlaysize = rawsize - overlayoffset;
if(*poverlaysize>0)
{
overlay = malloc(*poverlaysize);
memcpy(overlay, (uint8_t*)rawpe+overlayoffset, *poverlaysize);
}
}
free(rawpe);
return overlay;
}
void* STDCALL winpe_memLoadLibrary(void *mempe)
{
PFN_LoadLibraryA pfnLoadLibraryA = (PFN_LoadLibraryA)winpe_findloadlibrarya();
PFN_GetProcAddress pfnGetProcAddress = (PFN_GetProcAddress)winpe_findgetprocaddress();
return winpe_memLoadLibraryEx(mempe, 0,
WINPE_LDFLAG_MEMFIND | WINPE_LDFLAG_MEMALLOC,
pfnLoadLibraryA, pfnGetProcAddress);
}
void* STDCALL winpe_memLoadLibraryEx(void *mempe, size_t imagebase, DWORD flag,
PFN_LoadLibraryA pfnLoadLibraryA, PFN_GetProcAddress pfnGetProcAddress)
{
// bind windows api
char name_kernel32[] = { 'k', 'e', 'r', 'n', 'e', 'l', '3', '2', '.', 'd', 'l', 'l' , '\0'};
char name_VirtualQuery[] = {'V', 'i', 'r', 't', 'u', 'a', 'l', 'Q', 'u', 'e', 'r', 'y', '\0'};
char name_VirtualAlloc[] = {'V', 'i', 'r', 't', 'u', 'a', 'l', 'A', 'l', 'l', 'o', 'c', '\0'};
char name_VirtualProtect[] = {'V', 'i', 'r', 't', 'u', 'a', 'l', 'P', 'r', 'o', 't', 'e', 'c', 't', '\0'};
HMODULE hmod_kernel32 = pfnLoadLibraryA(name_kernel32);
PFN_VirtualQuery pfnVirtualQuery = (PFN_VirtualQuery)pfnGetProcAddress(hmod_kernel32, name_VirtualQuery);
PFN_VirtualAlloc pfnVirtualAlloc = (PFN_VirtualAlloc)pfnGetProcAddress(hmod_kernel32, name_VirtualAlloc);
PFN_VirtualProtect pfnVirtualProtect =(PFN_VirtualProtect)pfnGetProcAddress(hmod_kernel32, name_VirtualProtect);
#ifdef _DEBUG
assert(pfnVirtualQuery!=0 && pfnVirtualAlloc!=0 && pfnVirtualProtect!=0);
#endif
// find proper imagebase
size_t imagesize = winpe_imagesizeval(mempe, 0);
if(flag & WINPE_LDFLAG_MEMFIND)
{
imagebase = winpe_imagebaseval(mempe, 0);
imagebase = (size_t)winpe_findspace(imagebase, imagesize, 0x10000, pfnVirtualQuery);
}
if(flag & WINPE_LDFLAG_MEMALLOC) // find proper memory to reloc
{
imagebase = (size_t)pfnVirtualAlloc((void*)imagebase, imagesize,
MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
if(!imagebase) // try alloc in arbitary place
{
imagebase = (size_t)pfnVirtualAlloc(NULL, imagesize, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
if(!imagebase) return NULL;
}
else
{
imagebase = (size_t)pfnVirtualAlloc((void*)imagebase, imagesize, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
if(!imagebase) return NULL;
}
}
// copy to imagebase
if(!imagebase)
{
imagebase = (size_t)mempe;
}
else
{
DWORD oldprotect;
pfnVirtualProtect((void*)imagebase, imagesize, PAGE_EXECUTE_READWRITE, &oldprotect);
inl_memcpy((void*)imagebase, mempe, imagesize);
pfnVirtualProtect((void*)imagebase, imagesize, oldprotect, &oldprotect);
}
// initial memory module
if(!winpe_memreloc((void*)imagebase, imagebase)) return NULL;
if(!winpe_membindiat((void*)imagebase, pfnLoadLibraryA, pfnGetProcAddress)) return NULL;
winpe_membindtls(mempe, DLL_PROCESS_ATTACH);
PFN_DllMain pfnDllMain = (PFN_DllMain)(imagebase + winpe_oepval((void*)imagebase, 0));
pfnDllMain((HINSTANCE)imagebase, DLL_PROCESS_ATTACH, NULL);
return (void*)imagebase;
}
BOOL STDCALL winpe_memFreeLibrary(void *mempe)
{
PFN_LoadLibraryA pfnLoadLibraryA = (PFN_LoadLibraryA)winpe_findloadlibrarya();
PFN_GetProcAddress pfnGetProcAddress = (PFN_GetProcAddress)winpe_findgetprocaddress();
return winpe_memFreeLibraryEx(mempe, pfnLoadLibraryA, pfnGetProcAddress);
}
BOOL STDCALL winpe_memFreeLibraryEx(void *mempe,
PFN_LoadLibraryA pfnLoadLibraryA, PFN_GetProcAddress pfnGetProcAddress)
{
char name_kernel32[] = {'k', 'e', 'r', 'n', 'e', 'l', '3', '2', '\0'};
char name_VirtualFree[] = {'V', 'i', 'r', 't', 'u', 'a', 'l', 'F', 'r', 'e', 'e', '\0'};
HMODULE hmod_kernel32 = pfnLoadLibraryA(name_kernel32);
PFN_VirtualFree pfnVirtualFree = (PFN_VirtualFree)pfnGetProcAddress(hmod_kernel32, name_VirtualFree);
PFN_DllMain pfnDllMain = (PFN_DllMain)((uint8_t*)mempe + winpe_oepval(mempe, 0));
winpe_membindtls(mempe, DLL_PROCESS_DETACH);
pfnDllMain((HINSTANCE)mempe, DLL_PROCESS_DETACH, NULL);
return pfnVirtualFree(mempe, 0, MEM_FREE);
}
PROC STDCALL winpe_memGetProcAddress(void *mempe, const char *funcname)
{
// this function might failed if inline and -Os, -O3, if in dll function, use printf might help
void* expva = winpe_memfindexp(mempe, funcname);
size_t exprva = (size_t)expva - (size_t)mempe;
// printf("[winpe_memGetProcAddress] expva=%p\n", expva);
// use pfnLoadLibraryA, pfnGetProcAddress to avoid infinity loop
void *hmod_kernel32 = winpe_findkernel32();
char name_GetProcAddress[] = {'G', 'e', 't', 'P', 'r', 'o', 'c', 'A', 'd', 'd', 'r', 'e', 's', 's', '\0'};
char name_LoadLibraryA[] = {'L', 'o', 'a', 'd', 'L', 'i', 'b', 'r', 'a', 'r', 'y', 'A', '\0'};
char *name[2] = {name_LoadLibraryA, name_GetProcAddress};
void *func[2] = {NULL, NULL};
for(int i=0; i<2;i++)
{
func[i] = winpe_memfindexp(hmod_kernel32, name[i]);
}
PFN_LoadLibraryA pfnLoadLibraryA = (PFN_LoadLibraryA)func[0];
PFN_GetProcAddress pfnGetProcAddress = (PFN_GetProcAddress)func[1];
return (PROC)winpe_memforwardexp(mempe, exprva, pfnLoadLibraryA, pfnGetProcAddress);
}
// PE query functions
void* winpe_findkernel32()
{
// return (void*)LoadLibrary("kernel32.dll");
// TEB->PEB->Ldr->InMemoryOrderLoadList->curProgram->ntdll->kernel32
void *kerenl32 = NULL;
#ifdef WINPE_NOASM
char name_kernel32[] = { 'k', 'e', 'r', 'n', 'e', 'l', '3', '2', '.', 'd', 'l', 'l' , '\0' };
kerenl32 = winpe_findmodulea(name_kernel32);
#else
#if defined(__GNUC__)
// can not use -masm=intel, as there are some ATT in intrin-impl.h
#ifdef _WIN64
asm("mov %%gs:0x60, %%rax\n" // peb
"mov 0x18(%%rax), %%rax\n" // ldr
"mov 0x20(%%rax), %%rax\n" // InMemoryOrderLoadList, currentProgramEntry
"mov (%%rax), %%rax\n" // ntdllEntry, currentProgramEntry->->Flink
"mov (%%rax), %%rax\n" // kernel32Entry, ntdllEntry->Flink
"mov 0x30-0x10(%%rax), %%rax\n" // kernel32.DllBase
"mov %%rax, %0\n":"=m"(kerenl32));
#else
asm("mov %%fs:0x30, %%eax\n" // peb
"mov 0xc(%%eax), %%eax\n" // ldr
"mov 0x14(%%eax), %%eax\n" // InMemoryOrderLoadList, currentProgramEntry
"mov (%%eax), %%eax\n" // ntdllEntry, currentProgramEntry->->Flink
"mov (%%eax), %%eax\n" // kernel32Entry, ntdllEntry->Flink
"mov -0x8+0x18(%%eax), %%eax\n" // kernel32.DllBase
"mov %%eax, %0\n":"=m"(kerenl32));
#endif // _WIN64
#else
#ifdef _WIN64
__asm{
mov rax, gs:[60h]; peb
mov rax, [rax+18h]; ldr
mov rax, [rax+20h]; InMemoryOrderLoadList, currentProgramEntry
mov rax, [rax]; ntdllEntry, currentProgramEntry->->Flink
mov rax, [rax]; kernel32Entry, ntdllEntry->Flink
mov rax, [rax-10h+30h]; kernel32.DllBase
mov kerenl32, rax;
}
#else
__asm{
mov eax, fs:[30h]; peb
mov eax, [eax+0ch]; ldr
mov eax, [eax+14h]; InMemoryOrderLoadList, currentProgramEntry
mov eax, [eax]; ntdllEntry, currentProgramEntry->->Flink
mov eax, [eax]; kernel32Entry, ntdllEntry->Flink
mov eax, [eax - 8h +18h]; kernel32.DllBase
mov kerenl32, eax;
}
#endif // _WIN64
#endif // __GNUC__
#endif // WINPE_NOASM
return kerenl32;
}
void* STDCALL winpe_findmoduleaex(PPEB peb, const char *modulename)
{
typedef struct _LDR_ENTRY // has 3 kinds of pointer link list
{
LIST_ENTRY InLoadOrderLinks; // this has link pointer
LIST_ENTRY InMemoryOrderLinks; // order is program, ntdll, kernel32.dll
LIST_ENTRY InInitializationOrderLinks;//to next entry in same place
PVOID DllBase; // 0x18, 0x30
PVOID EntryPoint;
ULONG SizeOfImage;
UNICODE_STRING FullDllName;
UNICODE_STRING BaseDllName;
ULONG Flags;
USHORT LoadCount;
USHORT TlsIndex;
union
{
LIST_ENTRY HashLinks;
struct
{
PVOID SectionPointer;
ULONG CheckSum;
};
};
ULONG TimeDateStamp;
} LDR_ENTRY, *PLDR_ENTRY; // use this because of mingw bug
PLDR_ENTRY ldrentry = NULL;
PPEB_LDR_DATA ldr = NULL;
if(!peb)
{
PTEB teb = NtCurrentTeb();
#ifdef _WIN64
peb = *(PPEB*)((uint8_t*)teb + 0x60);
#else
peb = *(PPEB*)((uint8_t*)teb + 0x30);
#endif
}
#ifdef _WIN64
ldr = *(PPEB_LDR_DATA*)((uint8_t*)peb + 0x18);
#else
ldr = *(PPEB_LDR_DATA*)((uint8_t*)peb + 0xC);
#endif
// InMemoryOrderModuleList is the second entry
ldrentry = (PLDR_ENTRY)((size_t)ldr->InMemoryOrderModuleList.Flink - 2*sizeof(size_t));
if(!modulename)
{
return ldrentry->DllBase;
}
while(ldrentry->InMemoryOrderLinks.Flink != ldr->InMemoryOrderModuleList.Flink)
{
PUNICODE_STRING ustr = &ldrentry->FullDllName;
int i;
for(i=ustr->Length/2-1; i>0 && ustr->Buffer[i]!='\\';i--);
if(ustr->Buffer[i]=='\\') i++;
if(inl_stricmp2(modulename, ustr->Buffer + i)==0)
{
return ldrentry->DllBase;
}
ldrentry = (PLDR_ENTRY)((size_t)ldrentry->InMemoryOrderLinks.Flink - 2*sizeof(size_t));
}
return NULL;
}
PROC winpe_findloadlibrarya()
{
// -Os might make this function not current, such as strcpy(Flink, "LoadLibraryA");
void* hmod_kernel32 = winpe_findkernel32();
char name_LoadLibraryA[] = {'L', 'o', 'a', 'd', 'L', 'i', 'b', 'r', 'a', 'r', 'y', 'A', '\0'};
// suppose exp no forward, to avoid recursive
return (PROC)winpe_memfindexp(hmod_kernel32, name_LoadLibraryA);
}
PROC winpe_findgetprocaddress()
{
void* hmod_kernel32 = winpe_findkernel32();
char name_GetProcAddress[] = {'G', 'e', 't', 'P', 'r', 'o', 'c', 'A', 'd', 'd', 'r', 'e', 's', 's', '\0'};
return (PROC)winpe_memfindexp(hmod_kernel32, name_GetProcAddress);
}
void* STDCALL winpe_findspace(size_t imagebase,
size_t imagesize, size_t alignsize, PFN_VirtualQuery pfnVirtualQuery)
{
#define MAX_QUERY 0x1000
size_t addr = imagebase;
MEMORY_BASIC_INFORMATION minfo;
for (int i=0;i<MAX_QUERY;i++)
{
if(addr % alignsize) addr += alignsize - addr% alignsize;
pfnVirtualQuery((LPVOID)addr, &minfo, sizeof(MEMORY_BASIC_INFORMATION));
if(minfo.State==MEM_FREE && minfo.RegionSize >= imagesize) return (void*)addr;
addr += minfo.RegionSize;
}
return NULL;
}
// PE load, adjust functions
size_t STDCALL winpe_overlayoffset(const void *rawpe)
{
PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)rawpe;
PIMAGE_NT_HEADERS pNtHeader = (PIMAGE_NT_HEADERS)((uint8_t*)rawpe + pDosHeader->e_lfanew);
PIMAGE_FILE_HEADER pFileHeader = &pNtHeader->FileHeader;
PIMAGE_OPTIONAL_HEADER pOptHeader = &pNtHeader->OptionalHeader;
PIMAGE_DATA_DIRECTORY pDataDirectory = pOptHeader->DataDirectory;
PIMAGE_SECTION_HEADER pSectHeader = (PIMAGE_SECTION_HEADER)((uint8_t*)pOptHeader + pFileHeader->SizeOfOptionalHeader);
WORD sectNum = pFileHeader->NumberOfSections;
return pSectHeader[sectNum-1].PointerToRawData + pSectHeader[sectNum-1].SizeOfRawData;
}
size_t STDCALL winpe_memload(const void *rawpe, size_t rawsize,
void *mempe, size_t memsize, bool_t same_align)
{
// load rawpe to memalign
PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)rawpe;
PIMAGE_NT_HEADERS pNtHeader = (PIMAGE_NT_HEADERS)((uint8_t*)rawpe + pDosHeader->e_lfanew);
PIMAGE_FILE_HEADER pFileHeader = &pNtHeader->FileHeader;
PIMAGE_OPTIONAL_HEADER pOptHeader = &pNtHeader->OptionalHeader;
PIMAGE_SECTION_HEADER pSectHeader = (PIMAGE_SECTION_HEADER)((uint8_t*)pOptHeader + pFileHeader->SizeOfOptionalHeader);
WORD sectNum = pFileHeader->NumberOfSections;
size_t imagesize = pOptHeader->SizeOfImage;
if(!mempe) return imagesize;
else if(memsize!=0 && memsize<imagesize) return 0;
inl_memset(mempe, 0, imagesize);
inl_memcpy(mempe, rawpe, pOptHeader->SizeOfHeaders);
for(WORD i=0;i<sectNum;i++)
{
inl_memcpy((uint8_t*)mempe+pSectHeader[i].VirtualAddress,
(uint8_t*)rawpe+pSectHeader[i].PointerToRawData, pSectHeader[i].SizeOfRawData);
}
// adjust all to mem align
if(same_align)
{
pDosHeader = (PIMAGE_DOS_HEADER)mempe;
pNtHeader = (PIMAGE_NT_HEADERS)((uint8_t*)mempe + pDosHeader->e_lfanew);
pFileHeader = &pNtHeader->FileHeader;
pOptHeader = &pNtHeader->OptionalHeader;
pSectHeader = (PIMAGE_SECTION_HEADER)((uint8_t*)pOptHeader + pFileHeader->SizeOfOptionalHeader);
sectNum = pFileHeader->NumberOfSections;
pOptHeader->FileAlignment = pOptHeader->SectionAlignment;
for(WORD i=0;i<sectNum;i++)
{
pSectHeader[i].PointerToRawData = pSectHeader[i].VirtualAddress;
}
}
return imagesize;
}
size_t STDCALL winpe_memreloc(void *mempe, size_t newimagebase)
{
PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)mempe;
PIMAGE_NT_HEADERS pNtHeader = (PIMAGE_NT_HEADERS)((uint8_t*)mempe + pDosHeader->e_lfanew);
PIMAGE_FILE_HEADER pFileHeader = &pNtHeader->FileHeader;
PIMAGE_OPTIONAL_HEADER pOptHeader = &pNtHeader->OptionalHeader;
PIMAGE_DATA_DIRECTORY pDataDirectory = pOptHeader->DataDirectory;
PIMAGE_DATA_DIRECTORY pRelocEntry = &pDataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];
DWORD reloc_count = 0;
DWORD reloc_offset = 0;
int64_t shift = (int64_t)newimagebase - (int64_t)pOptHeader->ImageBase;
while (reloc_offset < pRelocEntry->Size)
{
PIMAGE_BASE_RELOCATION pBaseReloc = (PIMAGE_BASE_RELOCATION)
((uint8_t*)mempe + pRelocEntry->VirtualAddress + reloc_offset);
PRELOCOFFSET pRelocOffset = (PRELOCOFFSET)((uint8_t*)pBaseReloc + sizeof(IMAGE_BASE_RELOCATION));
DWORD item_num = (pBaseReloc->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) / sizeof(RELOCOFFSET);
for (size_t i = 0; i < item_num; i++)
{
if (!pRelocOffset[i].type && !pRelocOffset[i].offset) continue;
DWORD targetoffset = pBaseReloc->VirtualAddress + pRelocOffset[i].offset;
size_t *paddr = (size_t *)((uint8_t*)mempe + targetoffset);
size_t relocaddr = (size_t)((int64_t)*paddr + shift);
//printf("reloc 0x%08x->0x%08x\n", *paddr, relocaddr);
*paddr = relocaddr;
}
reloc_offset += sizeof(IMAGE_BASE_RELOCATION) + sizeof(RELOCOFFSET) * item_num;
reloc_count += item_num;
}
pOptHeader->ImageBase = newimagebase;
return reloc_count;
}
size_t STDCALL winpe_membindiat(void *mempe,
PFN_LoadLibraryA pfnLoadLibraryA, PFN_GetProcAddress pfnGetProcAddress)
{
PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)mempe;
PIMAGE_NT_HEADERS pNtHeader = (PIMAGE_NT_HEADERS)((uint8_t*)mempe + pDosHeader->e_lfanew);
PIMAGE_FILE_HEADER pFileHeader = &pNtHeader->FileHeader;
PIMAGE_OPTIONAL_HEADER pOptHeader = &pNtHeader->OptionalHeader;
PIMAGE_DATA_DIRECTORY pDataDirectory = pOptHeader->DataDirectory;
PIMAGE_DATA_DIRECTORY pImpEntry = &pDataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT];
PIMAGE_IMPORT_DESCRIPTOR pImpDescriptor = (PIMAGE_IMPORT_DESCRIPTOR)((uint8_t*)mempe + pImpEntry->VirtualAddress);
PIMAGE_THUNK_DATA pFtThunk = NULL;
PIMAGE_THUNK_DATA pOftThunk = NULL;
LPCSTR pDllName = NULL;
PIMAGE_IMPORT_BY_NAME pImpByName = NULL;
size_t funcva = 0;
char *funcname = NULL;
// origin GetProcAddress will crash at InitializeSListHead
if(!pfnLoadLibraryA) pfnLoadLibraryA = (PFN_LoadLibraryA)winpe_findloadlibrarya();
if(!pfnGetProcAddress) pfnGetProcAddress = (PFN_GetProcAddress)winpe_findgetprocaddress();
DWORD iat_count = 0;
for (; pImpDescriptor->Name; pImpDescriptor++)
{
pDllName = (LPCSTR)((uint8_t*)mempe + pImpDescriptor->Name);
pFtThunk = (PIMAGE_THUNK_DATA)((uint8_t*)mempe + pImpDescriptor->FirstThunk);
pOftThunk = (PIMAGE_THUNK_DATA)((uint8_t*)mempe + pImpDescriptor->OriginalFirstThunk);
size_t dllbase = (size_t)pfnLoadLibraryA(pDllName);
if(!dllbase) return 0;
for (int j=0; pFtThunk[j].u1.Function && pOftThunk[j].u1.Function; j++)
{
size_t _addr = (size_t)((uint8_t*)mempe + pOftThunk[j].u1.AddressOfData);
if(sizeof(size_t)>4) // x64
{
if(((uint64_t)_addr>>63) == 1)
{
funcname = (char *)(_addr & 0x000000000000ffff);
}
else
{
pImpByName=(PIMAGE_IMPORT_BY_NAME)_addr;
funcname = pImpByName->Name;
}
}
else
{
if(((size_t)pImpByName>>31) == 1)
{
funcname = (char *)(_addr & 0x0000ffff);
}
else
{
pImpByName=(PIMAGE_IMPORT_BY_NAME)_addr;
funcname = pImpByName->Name;
}
}
funcva = (size_t)pfnGetProcAddress((HMODULE)dllbase, funcname);
if(!funcva) continue;
pFtThunk[j].u1.Function = funcva;
#ifdef _DEBUG
assert(funcva == (size_t)GetProcAddress((HMODULE)dllbase, funcname));
#endif
iat_count++;
}
}
return iat_count;
}
size_t STDCALL winpe_membindtls(void *mempe, DWORD reason)
{
PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)mempe;
PIMAGE_NT_HEADERS pNtHeader = (PIMAGE_NT_HEADERS)((uint8_t*)mempe + pDosHeader->e_lfanew);
PIMAGE_FILE_HEADER pFileHeader = &pNtHeader->FileHeader;
PIMAGE_OPTIONAL_HEADER pOptHeader = &pNtHeader->OptionalHeader;
PIMAGE_DATA_DIRECTORY pDataDirectory = pOptHeader->DataDirectory;
PIMAGE_DATA_DIRECTORY pTlsDirectory = &pDataDirectory[IMAGE_DIRECTORY_ENTRY_TLS];
if(!pTlsDirectory->VirtualAddress) return 0;
size_t tls_count = 0;
PIMAGE_TLS_DIRECTORY pTlsEntry = (PIMAGE_TLS_DIRECTORY)((uint8_t*)mempe + pTlsDirectory->VirtualAddress);
PIMAGE_TLS_CALLBACK *tlscb= (PIMAGE_TLS_CALLBACK*)pTlsEntry->AddressOfCallBacks;
if(tlscb)
{
while(*tlscb)
{
(*tlscb)(mempe, reason, NULL);
tlscb++;
tls_count++;
}
}
return tls_count;
}
void* STDCALL winpe_memfindiat(void *mempe, LPCSTR dllname, LPCSTR funcname)
{
PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)mempe;
PIMAGE_NT_HEADERS pNtHeader = (PIMAGE_NT_HEADERS)((uint8_t*)mempe + pDosHeader->e_lfanew);
PIMAGE_FILE_HEADER pFileHeader = &pNtHeader->FileHeader;
PIMAGE_OPTIONAL_HEADER pOptHeader = &pNtHeader->OptionalHeader;
PIMAGE_DATA_DIRECTORY pDataDirectory = pOptHeader->DataDirectory;
PIMAGE_DATA_DIRECTORY pImpEntry = &pDataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT];
PIMAGE_IMPORT_DESCRIPTOR pImpDescriptor = (PIMAGE_IMPORT_DESCRIPTOR)((uint8_t*)mempe + pImpEntry->VirtualAddress);
PIMAGE_THUNK_DATA pFtThunk = NULL;
PIMAGE_THUNK_DATA pOftThunk = NULL;
LPCSTR pDllName = NULL;
PIMAGE_IMPORT_BY_NAME pImpByName = NULL;
for (; pImpDescriptor->Name; pImpDescriptor++)
{
pDllName = (LPCSTR)((uint8_t*)mempe + pImpDescriptor->Name);
if(dllname && inl_stricmp(pDllName, dllname)!=0) continue;
pFtThunk = (PIMAGE_THUNK_DATA)((uint8_t*)mempe + pImpDescriptor->FirstThunk);
pOftThunk = (PIMAGE_THUNK_DATA)((uint8_t*)mempe + pImpDescriptor->OriginalFirstThunk);
for (int j=0; pFtThunk[j].u1.Function && pOftThunk[j].u1.Function; j++)
{
pImpByName=(PIMAGE_IMPORT_BY_NAME)((uint8_t*)mempe + pOftThunk[j].u1.AddressOfData);
if((size_t)funcname < MAXWORD) // ordinary
{
WORD funcord = LOWORD(funcname);
if(pImpByName->Hint == funcord) return &pFtThunk[j];
}
else
{
if(inl_stricmp(pImpByName->Name, funcname)==0) return &pFtThunk[j];
}
}
}
return 0;
}
void* STDCALL winpe_memfindexp(void *mempe, LPCSTR funcname)
{
PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)mempe;
PIMAGE_NT_HEADERS pNtHeader = (PIMAGE_NT_HEADERS)((uint8_t*)mempe + pDosHeader->e_lfanew);
PIMAGE_FILE_HEADER pFileHeader = &pNtHeader->FileHeader;
PIMAGE_OPTIONAL_HEADER pOptHeader = &pNtHeader->OptionalHeader;
PIMAGE_DATA_DIRECTORY pDataDirectory = pOptHeader->DataDirectory;
PIMAGE_DATA_DIRECTORY pExpEntry = &pDataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT];
PIMAGE_EXPORT_DIRECTORY pExpDescriptor = (PIMAGE_EXPORT_DIRECTORY)((uint8_t*)mempe + pExpEntry->VirtualAddress);
WORD *ordrva = (WORD*)((uint8_t*)mempe + pExpDescriptor->AddressOfNameOrdinals);
DWORD *namerva = (DWORD*)((uint8_t*)mempe + pExpDescriptor->AddressOfNames);
DWORD *funcrva = (DWORD*)((uint8_t*)mempe + pExpDescriptor->AddressOfFunctions);
if((size_t)funcname <= MAXWORD) // find by ordnial
{
WORD ordbase = LOWORD(pExpDescriptor->Base) - 1;
WORD funcord = LOWORD(funcname);
return (void*)((uint8_t*)mempe + funcrva[ordrva[funcord-ordbase]]);
}
else
{
for(DWORD i=0;i<pExpDescriptor->NumberOfNames;i++)
{
LPCSTR curname = (LPCSTR)((uint8_t*)mempe+namerva[i]);
if(inl_stricmp(curname, funcname)==0)
{
return (void*)((uint8_t*)mempe + funcrva[ordrva[i]]);
}
}
}
return NULL;
}
void* STDCALL winpe_memfindexpcrc32(void* mempe, uint32_t crc32)
{
PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)mempe;
PIMAGE_NT_HEADERS pNtHeader = (PIMAGE_NT_HEADERS)((uint8_t*)mempe + pDosHeader->e_lfanew);
PIMAGE_FILE_HEADER pFileHeader = &pNtHeader->FileHeader;
PIMAGE_OPTIONAL_HEADER pOptHeader = &pNtHeader->OptionalHeader;
PIMAGE_DATA_DIRECTORY pDataDirectory = pOptHeader->DataDirectory;
PIMAGE_DATA_DIRECTORY pExpEntry = &pDataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT];
PIMAGE_EXPORT_DIRECTORY pExpDescriptor =(PIMAGE_EXPORT_DIRECTORY)((uint8_t*)mempe + pExpEntry->VirtualAddress);
WORD* ordrva = (WORD*)((uint8_t*)mempe + pExpDescriptor->AddressOfNameOrdinals);
DWORD* namerva = (DWORD*)((uint8_t*)mempe + pExpDescriptor->AddressOfNames);
DWORD* funcrva = (DWORD*)((uint8_t*)mempe + pExpDescriptor->AddressOfFunctions);
for (DWORD i = 0; i < pExpDescriptor->NumberOfNames; i++)
{
LPCSTR curname = (LPCSTR)((uint8_t*)mempe + namerva[i]);
if (crc32==inl_crc32(curname, inl_strlen(curname)))
{
return (void*)((uint8_t*)mempe + funcrva[ordrva[i]]);
}
}
return NULL;
}
void* STDCALL winpe_memforwardexp(void *mempe, size_t exprva,
PFN_LoadLibraryA pfnLoadLibraryA, PFN_GetProcAddress pfnGetProcAddress)
{
// this function might have infinite loop
// kerenl32.dll, GetProcessMitigationPolicy -> api-ms-win-core-processthreads-l1-1-1.dll -> kerenl32.dll, GetProcessMitigationPolicys
size_t dllbase = (size_t)mempe;
while (1)
{
PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)dllbase;
PIMAGE_NT_HEADERS pNtHeader = (PIMAGE_NT_HEADERS)((uint8_t*)dllbase + pDosHeader->e_lfanew);
PIMAGE_OPTIONAL_HEADER pOptHeader = &pNtHeader->OptionalHeader;
PIMAGE_DATA_DIRECTORY pDataDirectory = pOptHeader->DataDirectory;
PIMAGE_DATA_DIRECTORY pExpEntry = &pDataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT];
if(exprva >= pExpEntry->VirtualAddress && exprva < pExpEntry->VirtualAddress + pExpEntry->Size)
{
char namebuf[MAX_PATH];
char *dllname = (char*)(dllbase + exprva);
char *funcname = dllname;
//printf("[winpe_memforwardexp] dllname=%s funcname=%s\n", dllname, funcname);
int i=0, j=0;
while(dllname[i]!=0)
{
if(dllname[i]=='.')
{
namebuf[j] = dllname[i];
namebuf[++j] = 'd';
namebuf[++j] = 'l';
namebuf[++j] = 'l';
namebuf[++j] = '\0';
funcname = namebuf + j + 1;
}
else
{
namebuf[j] = dllname[i];
}
i++;
j++;
}
namebuf[j] = '\0';
dllname = namebuf;
dllbase = (size_t)pfnLoadLibraryA(dllname);
size_t expva = (size_t)pfnGetProcAddress((HMODULE)dllbase, funcname);
exprva = expva - dllbase;
}
else
{
return (void*)(dllbase + exprva);
}
}
return NULL;
}
// PE setting function
void STDCALL winpe_noaslr(void *pe)
{
PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)pe;
PIMAGE_NT_HEADERS pNtHeader = (PIMAGE_NT_HEADERS)((uint8_t*)pe + pDosHeader->e_lfanew);
PIMAGE_FILE_HEADER pFileHeader = &pNtHeader->FileHeader;
PIMAGE_OPTIONAL_HEADER pOptHeader = &pNtHeader->OptionalHeader;
#ifndef IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE
#define IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE 0x0040
#endif
pOptHeader->DllCharacteristics &= ~IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE;
}
DWORD STDCALL winpe_oepval(void *pe, DWORD newoeprva)
{
PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)pe;
PIMAGE_NT_HEADERS pNtHeader = (PIMAGE_NT_HEADERS)((uint8_t*)pe + pDosHeader->e_lfanew);
PIMAGE_FILE_HEADER pFileHeader = &pNtHeader->FileHeader;
PIMAGE_OPTIONAL_HEADER pOptHeader = &pNtHeader->OptionalHeader;
DWORD orgoep = pOptHeader->AddressOfEntryPoint;
if(newoeprva) pOptHeader->AddressOfEntryPoint = newoeprva;
return orgoep;
}
size_t STDCALL winpe_imagebaseval(void *pe, size_t newimagebase)
{
PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)pe;
PIMAGE_NT_HEADERS pNtHeader = (PIMAGE_NT_HEADERS)((uint8_t*)pe + pDosHeader->e_lfanew);
PIMAGE_FILE_HEADER pFileHeader = &pNtHeader->FileHeader;
PIMAGE_OPTIONAL_HEADER pOptHeader = &pNtHeader->OptionalHeader;
size_t imagebase = pOptHeader->ImageBase;
if(newimagebase) pOptHeader->ImageBase = newimagebase;
return imagebase;
}
size_t STDCALL winpe_imagesizeval(void *pe, size_t newimagesize)
{
PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)pe;
PIMAGE_NT_HEADERS pNtHeader = (PIMAGE_NT_HEADERS)((uint8_t*)pe + pDosHeader->e_lfanew);
PIMAGE_FILE_HEADER pFileHeader = &pNtHeader->FileHeader;
PIMAGE_OPTIONAL_HEADER pOptHeader = &pNtHeader->OptionalHeader;
size_t imagesize = pOptHeader->SizeOfImage;
if(newimagesize) pOptHeader->SizeOfImage = (DWORD)newimagesize;
return imagesize;
}
size_t STDCALL winpe_appendsecth(void *pe, PIMAGE_SECTION_HEADER psecth)
{
PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)pe;
PIMAGE_NT_HEADERS pNtHeader = (PIMAGE_NT_HEADERS)((uint8_t*)pe + pDosHeader->e_lfanew);
PIMAGE_FILE_HEADER pFileHeader = &pNtHeader->FileHeader;
PIMAGE_OPTIONAL_HEADER pOptHeader = &pNtHeader->OptionalHeader;
PIMAGE_SECTION_HEADER pSectHeader = (PIMAGE_SECTION_HEADER)((uint8_t*)pOptHeader + pFileHeader->SizeOfOptionalHeader);
WORD sectNum = pFileHeader->NumberOfSections;
PIMAGE_SECTION_HEADER pLastSectHeader = &pSectHeader[sectNum-1];
DWORD addr, align;
// check the space to append section
if(pFileHeader->SizeOfOptionalHeader + sizeof(IMAGE_SECTION_HEADER)> pSectHeader[0].PointerToRawData) return 0;
// fill rva addr
align = pOptHeader->SectionAlignment;
addr = pLastSectHeader->VirtualAddress + pLastSectHeader->Misc.VirtualSize;
if(addr % align) addr += align - addr%align;
psecth->VirtualAddress = addr;
// fill file offset
align = pOptHeader->FileAlignment;
addr = pLastSectHeader->PointerToRawData+ pLastSectHeader->SizeOfRawData;
if(addr % align) addr += align - addr%align;
psecth->PointerToRawData = addr;
// adjust the section and imagesize
pFileHeader->NumberOfSections++;
inl_memcpy(&pSectHeader[sectNum], psecth, sizeof(IMAGE_SECTION_HEADER));
align = pOptHeader->SectionAlignment;
addr = psecth->VirtualAddress + psecth->Misc.VirtualSize;
if(addr % align) addr += align - addr%align;
pOptHeader->SizeOfImage = addr;
return pOptHeader->SizeOfImage;
}
#endif // WINPE_IMPLEMENTATION
#endif // _WINPE_H