NT(dll) Unhooker
July 15, 2025 · View on GitHub
A Windows security tool demonstrating a method to detect and remove inline hooks and IAT (Import Address Table) hooks from NTDLL.dll. This tool is particularly useful for security researchers, penetration testers, and malware analysts who need to restore the integrity of system DLLs that may have been hooked by security solutions or malicious software.
Features
- Inline Hook Detection: Identifies and removes inline hooks in NTDLL.dll functions
- IAT Hook Detection: Detects and cleans Import Address Table hooks
- Clean NTDLL Restoration: Downloads and uses a clean version of NTDLL for comparison
- Critical Function Protection: Safely skips critical functions to prevent system instability
How It Works
The tool works by:
- Loading NTDLL: Dynamically loads NTDLL.dll using Windows API functions
- PE Analysis: Parses the PE headers to extract function information
- Clean Comparison: Downloads a clean version of NTDLL for comparison
- Hook Detection: Compares the current NTDLL with the clean version to identify hooks
- Unhooking: Restores original function code by overwriting hooked functions
- IAT Cleaning: Removes any IAT hooks that redirect function calls
Prerequisites
- Rust toolchain (latest stable version)
- Windows development environment
Installation
As a Binary Tool
# For development
cargo build
# For release (recommended)
cargo build --release
# For static linking
cargo rustc --release --bin nt_unhooker -- -C target-feature=+crt-static
As a Library
Add to your Cargo.toml:
[dependencies]
nt_unhooker = { path = "path/to/nt_unhooker" }
Or from a git repository:
[dependencies]
nt_unhooker = { git = "https://github.com/yourusername/nt_unhooker" }
Example Output
When the tool runs successfully, you'll see output similar to this (truncated):
String length: 18, Maximum length: 20
Buffer contents: [110, 116, 100, 108, 108, 46, 100, 108, 108, 0]
Attempting download from: https://msdl.microsoft.com/download/symbols/ntdll.dll/67CA8829217000/ntdll.dll
Successfully downloaded clean NTDLL: 2187376 bytes
Starting unhooking process...
Getting NTDLL handle...
NTDLL handle obtained: 0x7ffb28710000
Checking current hook status:
[Inline Hooks]
NtMapViewOfSection: 4C 8B D1 E9 C6 E8 08 00 F6 04 25 08 03 FE 7F 01 [HOOKED]
NtProtectVirtualMemory: 4C 8B D1 E9 BF E3 08 00 F6 04 25 08 03 FE 7F 01 [HOOKED]
NtWriteVirtualMemory: 4C 8B D1 E9 7D E6 08 00 F6 04 25 08 03 FE 7F 01 [HOOKED]
NtAllocateVirtualMemory: 4C 8B D1 E9 C0 EA 08 00 F6 04 25 08 03 FE 7F 01 [HOOKED]
[IAT Hooks]
NtCreateFile: 4C 8B D1 B8 55 00 00 00 F6 04 25 08 03 FE 7F 01 [CLEAN]
Unhooking operations:
Starting inline hook removal...
Processing sections...
Processing section: .text
Found .text section at RVA: 0x1000, Raw offset: 0x1000, Size: 0x12e000
Writing clean section at 0x7ffb28711000 with size 0x12e000
Successfully wrote 1236992 bytes
✓ Inline hooks removed
Starting IAT hook removal...
✓ IAT hooks removed
Verifying final state:
[Inline Hooks]
NtMapViewOfSection: 4C 8B D1 B8 28 00 00 00 F6 04 25 08 03 FE 7F 01 [CLEAN]
NtProtectVirtualMemory: 4C 8B D1 B8 50 00 00 00 F6 04 25 08 03 FE 7F 01 [CLEAN]
NtWriteVirtualMemory: 4C 8B D1 B8 3A 00 00 00 F6 04 25 08 03 FE 7F 01 [CLEAN]
NtAllocateVirtualMemory: 4C 8B D1 B8 18 00 00 00 F6 04 25 08 03 FE 7F 01 [CLEAN]
[IAT Hooks]
NtCreateFile: 4C 8B D1 B8 55 00 00 00 F6 04 25 08 03 FE 7F 01 [CLEAN]
Successfully completed all unhooking operations
Successfully unhooked all hooks
This example shows the tool successfully detecting and removing inline hooks from several critical NTDLL functions while leaving clean functions untouched.
Using as a Library
Basic Usage
use nt_unhooker::{NtUnhooker, check_and_unhook};
fn main() {
// Simple unhooking
if NtUnhooker::unhook() {
println!("Successfully unhooked NTDLL");
}
// Or use the direct function
if check_and_unhook() {
println!("Successfully unhooked NTDLL");
}
}
Advanced Usage
use nt_unhooker::{get_ntdll_symbol_info, get_clean_ntdll, check_hooks, check_iat_hooks, unhook_ntdll};
fn main() {
// Get NTDLL symbol information
if let Some(info) = get_ntdll_symbol_info() {
println!("NTDLL timestamp: {:#x}", info.timestamp);
println!("NTDLL size: {:#x}", info.size);
}
// Download clean NTDLL for comparison
if let Some(clean_dll) = get_clean_ntdll() {
println!("Downloaded clean NTDLL: {} bytes", clean_dll.len());
// Get current NTDLL handle (you'd need to implement this)
// let ntdll_handle = get_ntdll_handle();
// Check for hooks without unhooking
// check_hooks(&clean_dll, ntdll_handle);
// check_iat_hooks(&clean_dll, ntdll_handle);
// Direct unhooking without checks (if you already have the handles)
// unsafe { unhook_ntdll(&clean_dll, ntdll_handle); }
}
}
Available Functions
check_and_unhook()- Full unhooking processget_ntdll_symbol_info()- Get NTDLL metadataget_clean_ntdll()- Download clean NTDLLcheck_hooks()- Check for inline hookscheck_iat_hooks()- Check for IAT hooksunhook_iat()- Remove IAT hooks onlyunhook_ntdll()- Remove inline hooks only (requires clean_dll and ntdll handle)get_clean_function_address()- Get function address from clean DLL
Struct API
use nt_unhooker::NtUnhooker;
// All functions are available as static methods
NtUnhooker::unhook();
NtUnhooker::unhook_direct(clean_dll, ntdll_handle); // Direct unhooking without checks
NtUnhooker::get_symbol_info();
NtUnhooker::download_clean_ntdll();