Files
oldboy21-RflDllOb/ReflectiveDLL/dllmain.cpp
T
Vincenzo Santucci 558a1ff172 first commit bella
2023-12-21 20:18:31 +01:00

979 lines
29 KiB
C++

#include <Windows.h>
#include <winternl.h>
#define EXTERN_DLL_EXPORT extern "C" __declspec(dllexport)
typedef PVOID PACTIVATION_CONTEXT;
typedef struct _BASE_RELOCATION_ENTRY {
WORD Offset : 12;
WORD Type : 4;
} BASE_RELOCATION_ENTRY, * PBASE_RELOCATION_ENTRY;
typedef struct _API_SET_NAMESPACE {
ULONG Version;
ULONG Size;
ULONG Flags;
ULONG Count;
ULONG EntryOffset;
ULONG HashOffset;
ULONG HashFactor;
} API_SET_NAMESPACE, * PAPI_SET_NAMESPACE;
// https://www.nirsoft.net/kernel_struct/vista/PEB_LDR_DATA.html
typedef struct _PEBC_LDR_DATA {
ULONG Length;
ULONG Initialized;
PVOID SsHandle;
LIST_ENTRY InLoadOrderModuleList;
LIST_ENTRY InMemoryOrderModuleList;
LIST_ENTRY InInitializationOrderModuleList;
} PEBC_LDR_DATA, * PPEBC_LDR_DATA;
typedef struct _DLL_HEADER {
DWORD header;
CHAR key;
} DLL_HEADER, * PDLL_HEADER;
// https://www.nirsoft.net/kernel_struct/vista/LDR_DATA_TABLE_ENTRY.html
typedef struct _LDR_DATA_TABLE_ENTRYC {
LIST_ENTRY InLoadOrderLinks;
LIST_ENTRY InMemoryOrderLinks;
LIST_ENTRY InInitializationOrderLinks;
PVOID DllBase;
PVOID EntryPoint;
ULONG SizeOfImage;
UNICODE_STRING FullDllName;
UNICODE_STRING BaseDllName;
ULONG Flags;
WORD LoadCount;
WORD TlsIndex;
union {
LIST_ENTRY HashLinks;
struct {
PVOID SectionPointer;
ULONG CheckSum;
};
};
union {
ULONG TimeDateStamp;
PVOID LoadedImports;
};
PACTIVATION_CONTEXT EntryPointActivationContext;
PVOID PatchInformation;
LIST_ENTRY ForwarderLinks;
LIST_ENTRY ServiceTagLinks;
LIST_ENTRY StaticLinks;
} LDR_DATA_TABLE_ENTRYC, * PLDR_DATA_TABLE_ENTRYC;
typedef struct _PEBC
{
BOOLEAN InheritedAddressSpace;
BOOLEAN ReadImageFileExecOptions;
BOOLEAN BeingDebugged;
union
{
BOOLEAN BitField;
struct
{
BOOLEAN ImageUsesLargePages : 1;
BOOLEAN IsProtectedProcess : 1;
BOOLEAN IsImageDynamicallyRelocated : 1;
BOOLEAN SkipPatchingUser32Forwarders : 1;
BOOLEAN IsPackagedProcess : 1;
BOOLEAN IsAppContainer : 1;
BOOLEAN IsProtectedProcessLight : 1;
BOOLEAN IsLongPathAwareProcess : 1;
};
};
HANDLE Mutant;
PVOID ImageBaseAddress;
PPEB_LDR_DATA Ldr;
PRTL_USER_PROCESS_PARAMETERS ProcessParameters;
PVOID SubSystemData;
PVOID ProcessHeap;
PRTL_CRITICAL_SECTION FastPebLock;
PSLIST_HEADER AtlThunkSListPtr;
PVOID IFEOKey;
union
{
ULONG CrossProcessFlags;
struct
{
ULONG ProcessInJob : 1;
ULONG ProcessInitializing : 1;
ULONG ProcessUsingVEH : 1;
ULONG ProcessUsingVCH : 1;
ULONG ProcessUsingFTH : 1;
ULONG ProcessPreviouslyThrottled : 1;
ULONG ProcessCurrentlyThrottled : 1;
ULONG ProcessImagesHotPatched : 1; // REDSTONE5
ULONG ReservedBits0 : 24;
};
};
union
{
PVOID KernelCallbackTable;
PVOID UserSharedInfoPtr;
};
ULONG SystemReserved;
ULONG AtlThunkSListPtr32;
PAPI_SET_NAMESPACE ApiSetMap;
ULONG TlsExpansionCounter;
PVOID TlsBitmap;
ULONG TlsBitmapBits[2];
PVOID ReadOnlySharedMemoryBase;
PVOID SharedData;
PVOID* ReadOnlyStaticServerData;
PVOID AnsiCodePageData;
PVOID OemCodePageData;
PVOID UnicodeCaseTableData;
ULONG NumberOfProcessors;
ULONG NtGlobalFlag;
ULARGE_INTEGER CriticalSectionTimeout;
SIZE_T HeapSegmentReserve;
SIZE_T HeapSegmentCommit;
SIZE_T HeapDeCommitTotalFreeThreshold;
SIZE_T HeapDeCommitFreeBlockThreshold;
ULONG NumberOfHeaps;
ULONG MaximumNumberOfHeaps;
PVOID* ProcessHeaps;
PVOID GdiSharedHandleTable;
PVOID ProcessStarterHelper;
ULONG GdiDCAttributeList;
PRTL_CRITICAL_SECTION LoaderLock;
ULONG OSMajorVersion;
ULONG OSMinorVersion;
USHORT OSBuildNumber;
USHORT OSCSDVersion;
ULONG OSPlatformId;
ULONG ImageSubsystem;
ULONG ImageSubsystemMajorVersion;
ULONG ImageSubsystemMinorVersion;
KAFFINITY ActiveProcessAffinityMask;
ULONG GdiHandleBuffer[60];
PVOID PostProcessInitRoutine;
PVOID TlsExpansionBitmap;
ULONG TlsExpansionBitmapBits[32];
ULONG SessionId;
ULARGE_INTEGER AppCompatFlags;
ULARGE_INTEGER AppCompatFlagsUser;
PVOID pShimData;
PVOID AppCompatInfo;
UNICODE_STRING CSDVersion;
PVOID ActivationContextData;
PVOID ProcessAssemblyStorageMap;
PVOID SystemDefaultActivationContextData;
PVOID SystemAssemblyStorageMap;
SIZE_T MinimumStackCommit;
PVOID SparePointers[2];
PVOID PatchLoaderData;
PVOID ChpeV2ProcessInfo;
ULONG AppModelFeatureState;
ULONG SpareUlongs[2];
USHORT ActiveCodePage;
USHORT OemCodePage;
USHORT UseCaseMapping;
USHORT UnusedNlsField;
PVOID WerRegistrationData;
PVOID WerShipAssertPtr;
union
{
PVOID pContextData;
PVOID pUnused;
PVOID EcCodeBitMap;
};
PVOID pImageHeaderHash;
union
{
ULONG TracingFlags;
struct
{
ULONG HeapTracingEnabled : 1;
ULONG CritSecTracingEnabled : 1;
ULONG LibLoaderTracingEnabled : 1;
ULONG SpareTracingBits : 29;
};
};
ULONGLONG CsrServerReadOnlySharedMemoryBase;
PRTL_CRITICAL_SECTION TppWorkerpListLock;
LIST_ENTRY TppWorkerpList;
PVOID WaitOnAddressHashTable[128];
PVOID TelemetryCoverageHeader;
ULONG CloudFileFlags;
ULONG CloudFileDiagFlags;
CHAR PlaceholderCompatibilityMode;
CHAR PlaceholderCompatibilityModeReserved[7];
struct _LEAP_SECOND_DATA* LeapSecondData;
union
{
ULONG LeapSecondFlags;
struct
{
ULONG SixtySecondEnabled : 1;
ULONG Reserved : 31;
};
};
ULONG NtGlobalFlag2;
ULONGLONG ExtendedFeatureDisableMask;
} PEBC, * PPEBC;
/*---------FUNCTIONS PROTOTYPES--------------*/
FARPROC GPARO(IN HMODULE hModule, IN int ordinal);
/*----------------FUNCTION ALIASES----------------------*/
typedef HMODULE(WINAPI* fnLoadLibraryA)(
LPCSTR lpLibFileName
);
typedef HMODULE(WINAPI* fnLoadLibraryW)(
LPCWSTR lpLibFileName
);
typedef BOOL(WINAPI* fnVirtualProtect)(
LPVOID lpAddress,
SIZE_T dwSize,
DWORD flAllocationType,
PDWORD flProtect
);
typedef LPVOID(WINAPI* fnVirtualAlloc)(
LPVOID lpAddress,
SIZE_T dwSize,
DWORD flAllocationType,
DWORD flProtect
);
typedef BOOL(WINAPI* fnRtlAddFunctionTable)(
PRUNTIME_FUNCTION FunctionTable,
DWORD EntryCount,
DWORD64 BaseAddress
);
typedef BOOL(WINAPI* fnDllMain)(
HINSTANCE,
DWORD,
LPVOID
);
typedef NTSTATUS(NTAPI* fnNtFlushInstructionCache)(
HANDLE hProcess,
PVOID BaseAddress,
ULONG NumberOfBytesToFlush
);
typedef BOOL(WINAPI* fnVirtualFree)(
LPVOID lpAddress,
SIZE_T dwSize,
DWORD dwFreeType
);
typedef BOOL(WINAPI* fnCloseHandle)(
HANDLE hObject
);
/*----------------GENERIC FUNCTIONS--------------------*/
void* custom_malloc(size_t size, fnVirtualAlloc VA) {
void* allocated_memory = VA(NULL, size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
return allocated_memory;
}
void* custom_memcpy(void* pDestination, void* pSource, size_t sLength) {
PBYTE D = (PBYTE)pDestination;
PBYTE S = (PBYTE)pSource;
while (sLength--)
*D++ = *S++;
return pDestination;
}
void ToLowerCaseWIDE(WCHAR str[]) {
size_t i = 0;
while (str[i] != L'\0') {
if (str[i] >= L'A' && str[i] <= L'Z') {
str[i] = str[i] + 32; // Convert uppercase to lowercase
}
i++;
}
//return str;
}
bool ComprareStringASCII(CHAR str1[], CHAR str2[]) {
int i = 0;
while (str1[i] && str2[i]) {
if (str1[i] != str2[i]) {
return false; // Characters don't match, strings are different
}
i++;
}
// Check if both strings have reached the null terminator at the same time
return true;
}
bool CompareStringWIDE(WCHAR str1[], WCHAR str2[]) {
int i = 0;
while (str1[i] && str2[i]) {
if (str1[i] != str2[i]) {
return false; // Characters don't match, strings are different
}
i++;
}
return true;
}
int custom_stoi(char str[]) {
int result = 0;
int i = 0;
// Iterate through the string and convert characters to integers
while (str[i] != '\0') {
if (str[i] >= '0' && str[i] <= '9') {
result = result * 10 + (str[i] - '0');
}
i++;
}
return result;
}
//----------------GET MODULE HANDLE---------------------
HMODULE GMHR(IN WCHAR szModuleName[]) {
PPEBC pPeb = (PEBC*)(__readgsqword(0x60));
// geting Ldr
PPEBC_LDR_DATA pLdr = (PPEBC_LDR_DATA)(pPeb->Ldr);
// getting the first element in the linked list (contains information about the first module)
PLDR_DATA_TABLE_ENTRYC pDte = (PLDR_DATA_TABLE_ENTRYC)(pLdr->InMemoryOrderModuleList.Flink);
while (pDte) {
// if not null
if (pDte->FullDllName.Length != NULL) {
// check if both equal
ToLowerCaseWIDE(pDte->FullDllName.Buffer);
ToLowerCaseWIDE(szModuleName);
if (CompareStringWIDE(pDte->FullDllName.Buffer, szModuleName)) {
return (HMODULE)(pDte->InInitializationOrderLinks.Flink);
}
}
else {
break;
}
// next element in the linked list
pDte = *(PLDR_DATA_TABLE_ENTRYC*)(pDte);
}
return NULL;
}
/*----------------SUPPORT FUNCTIONS------------------------*/
void ParseForwarder(CHAR forwarder[], CHAR dll[], CHAR function[]) {
int i = 0;
while (forwarder[i]) {
if (forwarder[i] == '.') {
break;
}
i++;
}
for (int j = 0; j <= i; j++) {
dll[j] = forwarder[j];
}
dll[i + 1] = 'd';
dll[i + 2] = 'l';
dll[i + 3] = 'l';
dll[i + 4] = '\0';
i++;
int z = 0;
while (forwarder[i]) {
function[z] = forwarder[i];
i++;
z++;
}
function[z + 1] = '\0';
}
/*------------------GET PROC ADDRESS-------------------*/
FARPROC GPAR(IN HMODULE hModule, IN CHAR lpApiName[]) {
PBYTE pBase = (PBYTE)hModule;
PIMAGE_DOS_HEADER pImgDosHdr = (PIMAGE_DOS_HEADER)pBase;
if (pImgDosHdr->e_magic != IMAGE_DOS_SIGNATURE)
return NULL;
PIMAGE_NT_HEADERS pImgNtHdrs = (PIMAGE_NT_HEADERS)(pBase + pImgDosHdr->e_lfanew);
if (pImgNtHdrs->Signature != IMAGE_NT_SIGNATURE)
return NULL;
IMAGE_OPTIONAL_HEADER ImgOptHdr = pImgNtHdrs->OptionalHeader;
PIMAGE_EXPORT_DIRECTORY pImgExportDir = (PIMAGE_EXPORT_DIRECTORY)(pBase + ImgOptHdr.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);
PDWORD FunctionNameArray = (PDWORD)(pBase + pImgExportDir->AddressOfNames);
PDWORD FunctionAddressArray = (PDWORD)(pBase + pImgExportDir->AddressOfFunctions);
PWORD FunctionOrdinalArray = (PWORD)(pBase + pImgExportDir->AddressOfNameOrdinals);
//variables for forwarding
WCHAR kernel32[] = { L'K', L'e', L'r', L'n', L'e', L'l', L'3', L'2', L'.', L'd', L'l', L'l', L'\0' };
CHAR loadLibraryA[] = { 'L', 'o', 'a', 'd', 'L', 'i', 'b', 'r', 'a', 'r', 'y', 'A', '\0' };
fnLoadLibraryA LLA = NULL;
PBYTE functionAddress = NULL;
CHAR forwarder[260] = { 0 };
CHAR dll[260] = { 0 };
CHAR function[260] = { 0 };
// looping through all the exported functions
for (DWORD i = 0; i < pImgExportDir->NumberOfFunctions; i++) {
// getting the name of the function
CHAR* pFunctionName = (CHAR*)(pBase + FunctionNameArray[i]);
// searching for the function specified
if (ComprareStringASCII(lpApiName, pFunctionName)) {
functionAddress = (PBYTE)(pBase + FunctionAddressArray[FunctionOrdinalArray[i]]);
if (functionAddress >= (PBYTE)pImgExportDir && functionAddress < (PBYTE)(pImgExportDir + ImgOptHdr.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size)) {
//here i have to get a substring
ParseForwarder((CHAR*)functionAddress, dll, function);
if ((LLA = (fnLoadLibraryA)GPAR(GMHR(kernel32), loadLibraryA)) == NULL)
return NULL;
if (function[0] == '#') {
return GPARO(LLA(dll), custom_stoi(function));
}
else {
return GPAR(LLA(dll), function);
}
}
else {
return (FARPROC)(pBase + FunctionAddressArray[FunctionOrdinalArray[i]]);
}
}
}
return NULL;
}
FARPROC GPARO(IN HMODULE hModule, IN int ordinal) {
// we do this to avoid casting at each time we use 'hModule'
PBYTE pBase = (PBYTE)hModule;
// getting the dos header and doing a signature check
PIMAGE_DOS_HEADER pImgDosHdr = (PIMAGE_DOS_HEADER)pBase;
if (pImgDosHdr->e_magic != IMAGE_DOS_SIGNATURE)
return NULL;
// getting the nt headers and doing a signature check
PIMAGE_NT_HEADERS pImgNtHdrs = (PIMAGE_NT_HEADERS)(pBase + pImgDosHdr->e_lfanew);
if (pImgNtHdrs->Signature != IMAGE_NT_SIGNATURE)
return NULL;
// getting the optional header
IMAGE_OPTIONAL_HEADER ImgOptHdr = pImgNtHdrs->OptionalHeader;
// we can get the optional header like this as well
// PIMAGE_OPTIONAL_HEADER pImgOptHdr = (PIMAGE_OPTIONAL_HEADER)((ULONG_PTR)pImgNtHdrs + sizeof(DWORD) + sizeof(IMAGE_FILE_HEADER));
// getting the image export table
PIMAGE_EXPORT_DIRECTORY pImgExportDir = (PIMAGE_EXPORT_DIRECTORY)(pBase + ImgOptHdr.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);
//getting the base = first ordinal value in the export table (DWORD 4 bytes)
int base = (int)pImgExportDir->Base;
int NumberOfFunctions = (int)pImgExportDir->NumberOfFunctions;
//variables for forwarding
WCHAR kernel32[] = { L'K', L'e', L'r', L'n', L'e', L'l', L'3', L'2', L'.', L'd', L'l', L'l', L'\0' };
CHAR loadLibraryA[] = { 'L', 'o', 'a', 'd', 'L', 'i', 'b', 'r', 'a', 'r', 'y', 'A', '\0' };
fnLoadLibraryA LLA = NULL;
PBYTE functionAddress = NULL;
CHAR forwarder[260] = { 0 };
CHAR dll[260] = { 0 };
CHAR function[260] = { 0 };
//check if the ordinal falls into the range of ordinals of functions exported by the DLL
if (ordinal < base || ordinal >= base + NumberOfFunctions) {
return NULL;
}
// getting the function's names array pointer
PDWORD FunctionNameArray = (PDWORD)(pBase + pImgExportDir->AddressOfNames);
// getting the function's addresses array pointer
PDWORD FunctionAddressArray = (PDWORD)(pBase + pImgExportDir->AddressOfFunctions);
// getting the function's ordinal array pointer
PWORD FunctionOrdinalArray = (PWORD)(pBase + pImgExportDir->AddressOfNameOrdinals);
// as specified here https://learn.microsoft.com/en-us/windows/win32/debug/pe-format
// If the address specified is not within the export section (as defined by the address and length that are indicated
// in the optional header), the field is an export RVA, which is an actual address in code or data. Otherwise, the field is a forwarder RVA,
// // which names a symbol in another DLL.
functionAddress = (PBYTE)(pBase + FunctionAddressArray[ordinal]);
if (functionAddress >= (PBYTE)pImgExportDir && functionAddress < (PBYTE)(pImgExportDir + ImgOptHdr.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size)) {
//here i have to get a substring
ParseForwarder((CHAR*)functionAddress, dll, function);
if ((LLA = (fnLoadLibraryA)GPAR(GMHR(kernel32), loadLibraryA)) == NULL)
return NULL;
if (function[0] == '#') {
return GPARO(LLA(dll), custom_stoi(function));
}
else {
return GPAR(LLA(dll), function);
}
}
return (FARPROC)(pBase + FunctionAddressArray[ordinal]);
}
/*-------------------REFLECTIVE LOADER----------------------------*/
EXTERN_DLL_EXPORT bool ReflectiveFunction() {
/*--------------CREATE VARIABLES AND INITIALIZE FUNCTIONS--------------*/
//PE HEADERS VARS
PIMAGE_DOS_HEADER pImgDosHdr = NULL;
PIMAGE_NT_HEADERS pImgNtHdrs = NULL;
IMAGE_OPTIONAL_HEADER ImgOptHdr = {0};
IMAGE_FILE_HEADER ImgFileHdr = {0};
PIMAGE_SECTION_HEADER* peSections = NULL;
PIMAGE_IMPORT_DESCRIPTOR pImgImpDesc = NULL;
PIMAGE_THUNK_DATA64 pOriginalFirstThunk = NULL;
PIMAGE_THUNK_DATA64 pFirstThunk = NULL;
PIMAGE_IMPORT_BY_NAME pImgImportByName = NULL;
PIMAGE_BASE_RELOCATION pImgRelocation = NULL;
PBASE_RELOCATION_ENTRY pRelocEntry = NULL;
PIMAGE_RUNTIME_FUNCTION_ENTRY pImgRuntimeFunctionEntry = NULL;
PIMAGE_TLS_DIRECTORY pImgTlsDirectory = NULL;
PIMAGE_TLS_CALLBACK* arrayOfCallbacks = NULL;
//fix IAT vars
HMODULE dll = NULL;
FARPROC funcAddress = NULL;
int ordinal = 0;
//base relocation vars
ULONG_PTR delta = NULL;
int entriesCount;
//dll entry point
fnDllMain pDllMain = NULL;
//fix Memory Protection variables
DWORD dwOldProtection = 0x00;
DWORD dwProtection = 0x00;
//locate DLL in memory
PDLL_HEADER pDllHeader = NULL;
ULONG_PTR dllBaseAddress = NULL;
//new PE in memory
PBYTE pebase = NULL;
//function prototpyes
fnVirtualAlloc VA = NULL;
fnLoadLibraryA LLA = NULL;
fnVirtualProtect VP = NULL;
fnRtlAddFunctionTable RAFT = NULL;
fnNtFlushInstructionCache FIC = NULL;
//stack strings for PIC
WCHAR kernel32[] = { L'K', L'e', L'r', L'n', L'e', L'l', L'3', L'2', L'.', L'd', L'l', L'l', L'\0' };
WCHAR ntdll[] = { L'n', L't', L'd', L'l', L'l', L'.', L'd', L'l', L'l', L'\0' };
WCHAR user32[] = { L'U', L's', L'e', L'r', L'3', L'2', L'.', L'd', L'l', L'l', L'\0' };
CHAR virtualAlloc[] = { 'V', 'i', 'r', 't', 'u', 'a', 'l', 'A', 'l', 'l', 'o', 'c', '\0' };
CHAR virtualProtect[] = { 'V', 'i', 'r', 't', 'u', 'a', 'l', 'P', 'r', 'o', 't', 'e', 'c', 't', '\0' };
CHAR rtladdFunctionTable[] = { 'R', 't', 'l', 'A', 'd', 'd', 'F', 'u', 'n', 'c', 't', 'i', 'o', 'n', 'T', 'a', 'b', 'l', 'e', '\0' };
CHAR ntFlushInstructionCache[] = { 'N', 't', 'F', 'l', 'u', 's', 'h', 'I', 'n', 's', 't', 'r', 'u', 'c', 't', 'i', 'o', 'n', 'C', 'a', 'c', 'h', 'e', '\0' };
CHAR loadLibraryA[] = { 'L', 'o', 'a', 'd', 'L', 'i', 'b', 'r', 'a', 'r', 'y', 'A', '\0' };
if ((VA = (fnVirtualAlloc)GPAR(GMHR(kernel32), virtualAlloc)) == NULL)
return FALSE;
if ((LLA = (fnLoadLibraryA)GPAR(GMHR(kernel32), loadLibraryA)) == NULL)
return FALSE;
if (!(VP = (fnVirtualProtect)GPAR(GMHR(kernel32), virtualProtect)))
return FALSE;
if (!(RAFT = (fnRtlAddFunctionTable)GPAR(GMHR(kernel32), rtladdFunctionTable)))
return FALSE;
if (!(FIC = (fnNtFlushInstructionCache)GPAR(GMHR(ntdll), ntFlushInstructionCache)))
return FALSE;
/*--------------BRUTE FORCE DLL BASE ADDRESS--------------*/
dllBaseAddress = (ULONG_PTR)ReflectiveFunction;
while (TRUE)
{
pDllHeader = (PDLL_HEADER)dllBaseAddress;
//whatever i use as header, needs to be compared as reversed
//since little-endian
if (pDllHeader->header == 0x44434241) {
//the fifth byte is supposed to be the encryption key (unused so far but keeping track of ideas)
pImgDosHdr = (PIMAGE_DOS_HEADER)(dllBaseAddress + (5*sizeof(CHAR)));
if (pImgDosHdr->e_magic == IMAGE_DOS_SIGNATURE)
{
pImgNtHdrs = (PIMAGE_NT_HEADERS)(dllBaseAddress + pImgDosHdr->e_lfanew + (5 * sizeof(CHAR)));
if (pImgNtHdrs->Signature == IMAGE_NT_SIGNATURE) {
break;
}
}
}
dllBaseAddress--;
}
if (!dllBaseAddress)
return FALSE;
//fixing the baseAddress including the 5 bytes of header
dllBaseAddress = dllBaseAddress + (5 * sizeof(CHAR));
//setting some headers for new steps
PIMAGE_OPTIONAL_HEADER pImgOptHdr = (PIMAGE_OPTIONAL_HEADER)((ULONG_PTR)pImgNtHdrs + sizeof(DWORD) + sizeof(IMAGE_FILE_HEADER));
ImgFileHdr = pImgNtHdrs->FileHeader;
/*--------------COPY SECTIONS IN MEMORY---------------------------*/
//allocating memory for the PE in memory
if ((pebase = (PBYTE)VA(NULL, pImgOptHdr->SizeOfImage, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE)) == NULL)
return FALSE;
//allocate memory for an array of SECTION HEADERS
peSections = (PIMAGE_SECTION_HEADER*)custom_malloc((sizeof(PIMAGE_SECTION_HEADER) * ImgFileHdr.NumberOfSections), VA);
if (peSections == NULL)
return FALSE;
for (int i = 0; i < ImgFileHdr.NumberOfSections; i++) {
peSections[i] = (PIMAGE_SECTION_HEADER)(((PBYTE)pImgNtHdrs) + 4 + 20 + ImgFileHdr.SizeOfOptionalHeader + (i * IMAGE_SIZEOF_SECTION_HEADER));
}
for (int i = 0; i < ImgFileHdr.NumberOfSections; i++) {
custom_memcpy(
(PVOID)(pebase + peSections[i]->VirtualAddress),// Destination
(PVOID)(dllBaseAddress + peSections[i]->PointerToRawData),// Source
peSections[i]->SizeOfRawData// Size
);
}
/*--------------FIX IAT TABLE--------------*/
for (size_t i = 0; i < pImgOptHdr->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size; i += sizeof(IMAGE_IMPORT_DESCRIPTOR)) {
pImgImpDesc = (PIMAGE_IMPORT_DESCRIPTOR)(pebase + pImgOptHdr->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress + i);
if (pImgImpDesc->OriginalFirstThunk == NULL && pImgImpDesc->FirstThunk == NULL)
break;
dll = LLA((LPSTR)(pebase + pImgImpDesc->Name));
if (dll == NULL) {
return FALSE;
}
pOriginalFirstThunk = (PIMAGE_THUNK_DATA64)(pebase + pImgImpDesc->OriginalFirstThunk);
pFirstThunk = (PIMAGE_THUNK_DATA64)(pebase + pImgImpDesc->FirstThunk);
while (pOriginalFirstThunk->u1.Function != NULL && pFirstThunk->u1.Function != NULL) {
if (pOriginalFirstThunk->u1.Ordinal & 0x8000000000000000) {
ordinal = pOriginalFirstThunk->u1.Ordinal & 0xFFFF;
funcAddress = GPARO(dll, (int)ordinal);
if (funcAddress != nullptr)
pFirstThunk->u1.Function = (ULONGLONG)funcAddress;
}
else {
pImgImportByName = (PIMAGE_IMPORT_BY_NAME)(pebase + pOriginalFirstThunk->u1.AddressOfData);
funcAddress = GPAR(dll, pImgImportByName->Name);
if (funcAddress != nullptr)
pFirstThunk->u1.Function = (ULONGLONG)funcAddress;
}
pOriginalFirstThunk++;
pFirstThunk++;
}
}
/*--------------APPLY BASE RELOCATIONS--------------*/
delta = (ULONG_PTR)pebase - pImgOptHdr->ImageBase;
pImgRelocation = (PIMAGE_BASE_RELOCATION)(pebase + pImgOptHdr->DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress);
while (pImgRelocation->VirtualAddress) {
pRelocEntry = (PBASE_RELOCATION_ENTRY)(pImgRelocation + 1);
//removing headers size and dividing by entry size
entriesCount = (int)((pImgRelocation->SizeOfBlock - 8) / 2);
//loop through relocation entries
for (int i = 0; i < entriesCount; i++) {
switch (pRelocEntry->Type) {
case IMAGE_REL_BASED_DIR64://if it's equal to A meaning = 10
{//The base relocation applies the difference to the 64-bit field at offset.
//so i need to add the delta to the 64-bit value at that offset
ULONGLONG* toAdjust = (ULONGLONG*)(pebase + pImgRelocation->VirtualAddress + pRelocEntry->Offset);
*toAdjust += (ULONGLONG)delta;
break;
}
case IMAGE_REL_BASED_HIGHLOW:
//The base relocation applies all 32 bits of the difference to the 32-bit field at offset.
{
DWORD* toAdjust = (DWORD*)(pebase + pImgRelocation->VirtualAddress + pRelocEntry->Offset);
*toAdjust += (DWORD)delta;
}
break;
case IMAGE_REL_BASED_HIGH:
//The base relocation adds the high 16 bits of the difference to the 16-bit field at offset. The 16-bit field represents the high value of a 32-bit word.
{
WORD* toAdjust = (WORD*)(pebase + pImgRelocation->VirtualAddress + pRelocEntry->Offset);
*toAdjust += HIWORD(delta);
}
break;
case IMAGE_REL_BASED_LOW:
//The base relocation adds the low 16 bits of the difference to the 16-bit field at offset. The 16-bit field represents the low half of a 32-bit word.
{
WORD* toAdjust = (WORD*)(pebase + pImgRelocation->VirtualAddress + pRelocEntry->Offset);
*toAdjust += LOWORD(delta);
}
break;
case IMAGE_REL_BASED_ABSOLUTE:
//The base relocation is skipped. This type can be used to pad a block
break;
}
pRelocEntry++;
}
pImgRelocation = (PIMAGE_BASE_RELOCATION)(reinterpret_cast<DWORD_PTR>(pImgRelocation) + pImgRelocation->SizeOfBlock);
}
/*-------------ADJUST MEMORY PROTECTIONS BASING ON SECTIONS HEADERS*/
for (int i = 0; i < ImgFileHdr.NumberOfSections; i++) {
if (peSections[i]->Characteristics & IMAGE_SCN_MEM_WRITE) {//write
dwProtection = PAGE_WRITECOPY;
}
if (peSections[i]->Characteristics & IMAGE_SCN_MEM_READ) {//read
dwProtection = PAGE_READONLY;
}
if (peSections[i]->Characteristics & IMAGE_SCN_MEM_EXECUTE) {//exec
dwProtection = PAGE_EXECUTE;
}
if (peSections[i]->Characteristics & IMAGE_SCN_MEM_READ && peSections[i]->Characteristics & IMAGE_SCN_MEM_WRITE) { //readwrite
dwProtection = PAGE_READWRITE;
}
if (peSections[i]->Characteristics & IMAGE_SCN_MEM_EXECUTE && peSections[i]->Characteristics & IMAGE_SCN_MEM_WRITE) { //executewrite
dwProtection = PAGE_EXECUTE_WRITECOPY;
}
if (peSections[i]->Characteristics & IMAGE_SCN_MEM_EXECUTE && peSections[i]->Characteristics & IMAGE_SCN_MEM_READ) { //executeread
dwProtection = PAGE_EXECUTE_READ;
}
if (peSections[i]->Characteristics & IMAGE_SCN_MEM_EXECUTE && peSections[i]->Characteristics & IMAGE_SCN_MEM_READ && peSections[i]->Characteristics & IMAGE_SCN_MEM_WRITE) { //executereadwrite
dwProtection = PAGE_EXECUTE_READWRITE;
}
if (!VP((PVOID)(pebase + peSections[i]->VirtualAddress), peSections[i]->SizeOfRawData, dwProtection, &dwOldProtection)) {
return FALSE;
}
}
/*--------------REGISTER EXCEPTIONS HANDLERS--------------*/
if (pImgOptHdr->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXCEPTION].Size) {
pImgRuntimeFunctionEntry = (PIMAGE_RUNTIME_FUNCTION_ENTRY)(pebase + pImgOptHdr->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXCEPTION].VirtualAddress);
if (!RAFT(pImgRuntimeFunctionEntry, (pImgOptHdr->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXCEPTION].Size / sizeof(PIMAGE_RUNTIME_FUNCTION_ENTRY)), (DWORD64)pebase)) {
//do nothing, no worth to make it stop for this
}
}
/*--------------EXECUTE TLS CALLBACKS--------------*/
if (pImgOptHdr->DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].Size) {
//so what we do here is finding the address of these functions and executing them before
//hitting the entrypoint
pImgTlsDirectory = (PIMAGE_TLS_DIRECTORY)(pebase + pImgOptHdr->DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].VirtualAddress);
//pointer to pointer is array. remember uni days?
arrayOfCallbacks = (PIMAGE_TLS_CALLBACK*)(pImgTlsDirectory->AddressOfCallBacks);
int i = 0;
while (arrayOfCallbacks[i] != NULL) {
arrayOfCallbacks[i]((LPVOID)pebase, DLL_PROCESS_ATTACH, NULL);
}
}
/*--------------FLUSHING INSTRUCTION CACHE ALLA FEWER*/
FIC((HANDLE)-1, NULL, 0x00);
/*--------------EXECUTE ENTRY POINT--------------*/
pDllMain = (fnDllMain)(pebase + pImgNtHdrs->OptionalHeader.AddressOfEntryPoint);
return pDllMain((HMODULE)pebase, DLL_PROCESS_ATTACH, NULL);
}
VOID PayloadFunction() {
MessageBoxA(NULL, "Ciao Grande", "Ciao Grande from DllMain!", MB_OK | MB_ICONINFORMATION);
}
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
PayloadFunction();
break;
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}