skip to content
secrary[dot]com

Bypass User-Mode Hooks

/

Introduction

User-mode hooks are unreliable and can be bypassed in various ways. While tools like makin can bypass hooks by loading ntdll from the %temp% directory, this approach is noisy due to DLL loading. Let’s explore a stealthier method - reimplementing ntdll functions.

The Approach

To achieve better stealth, we’ll:

  1. Work with undocumented functions
  2. Reimplement low-level functions directly
  3. Use Windows-specific implementation details

Note: This implementation targets Windows Version 1709 x64

Function Analysis

NtCreateFile Implementation

Using IDA or similar disassemblers, we can analyze the original implementation:

NtCreateFile implementation

NtClose Implementation

NtClose implementation

Implementation

Assembly

.code
NtClose PROC
mov r10, rcx;
mov eax, 15;
syscall;
ret;
NtClose ENDP
NtCreateFile PROC
mov r10, rcx;
mov eax, 85;
syscall;
ret;
NtCreateFile ENDP
END

Main Code

int main() {
RtlInitUnicodeStringEx* initUnicode = (RtlInitUnicodeStringEx*)GetProcAddress(GetModuleHandle(L"ntdll"), "RtlInitUnicodeStringEx");
UNICODE_STRING un;
initUnicode(&un, L"\\??\\C:\\file.txt");
HANDLE hFile;
OBJECT_ATTRIBUTES objA{};
objA.Length = sizeof(OBJECT_ATTRIBUTES);
objA.ObjectName = &un;
_IO_STATUS_BLOCK IoStatusBlock{};
auto status = NtCreateFile(&hFile, GENERIC_ALL, &objA, &IoStatusBlock, 0, 0, 0, CREATE_NEW, 0, 0, 0);
NtClose(hFile);
}

Improving Stability

Pro Tip: For better stability, extract the index number from ntdll at runtime:

ntdll runtime extraction

Resources

Demonstration

Below is a demonstration of the hook bypassing in action:

Hook bypass demonstration

View full-size