UnhookMe is an universal Windows API resolver & unhooker addressing problem of invoking unmonitored system calls from within of your Red Teams malware

Overview

UnhookMe - Dynamically unhooking imports resolver

In the era of intrusive AVs and EDRs that introduce hot-patches to the running processes for their enhanced optics requirements, modern adversaries must have a robust tool to slide through these watchguards. The propsed implementation of dynamic imports resolver that would be capable of unhooking used functions in-the-fly is yet another step towards strengthening adversary resilience efforts.

The solution I'm proposing here is to switch from using linker-resolved WinAPI imports, staying visibile in compiled executable's PE headers (Import Address Table specifically) to favor fully-dynamic approach insisting on resolving imports only in a dynamic fashion. Such dynamical resolver can be equipped with unhooking logic happening in the background, without any sort of guidance from the operator's side.

Showcase

Here's how UnhookMe example works:

  1. It presents us with the first MessageBoxW that is not subject for hooking
  2. Then we hook MessageBoxW prologue ourselves to make it always return 0 without displaying it's message
  3. Finally, we resolve MessageBoxW dynamically using the UnhookingImportResolver resolver, which will detect applied prologue patches and restore original bytes, effectively unhooking MessageBoxW functionality.

In the meantime of popping message boxes, these are the loglines printed to console's stdout:

[~] Resolved symbol kernel32.dll!CreateFileA
[~] Resolved symbol kernel32.dll!ReadProcessMemory
[~] Resolved symbol kernel32.dll!MapViewOfFile
[~] Resolved symbol kernel32.dll!VirtualProtectEx
[#] Found trampoline hook in symbol: MessageBoxW . Restored original bytes from file.
[~] Resolved symbol user32.dll!MessageBoxW

How to use it?

There are in total 5 C++ source code/header files that your solution need to include. However your main program file needs to include only two required headers, as detailed below.

  • resolver.h - header containing most of the UnhookingImportResolver implementation and handy macrodefinitions
  • resolver.cpp - source code with global options defined
  • usings.h - a one big and nasty header file containing tens of using type definitions for commonly used WinAPIs
  • PE.cpp - custom PE parser source code file
  • PE.h - custom PE parser header file

Required headers

Your program will require only two headers being included:

#include "usings.h"
#include "resolver.h"

Global options

There are couple of global options that can be changed affecting the way in which Resolver works or reports it's activity. These are defined in the very beginning of resolver.cpp file:

Resolver global options:

  • globalQuietOption - set to true if you don't want to have any sort of output
  • globalVerboseOption - set to true if you want to have detailed verbose output
  • globalAntiSplicingOption - unhook resolved functions if they're hooked.
  • globalLogFilePath - where to redirect output log lines. If empty, pick stdout.
bool globalQuietOption = false;
bool globalVerboseOption = true;
bool globalAntiSplicingOption = true;

wchar_t globalLogFilePath[MAX_PATH] = L"";

Custom API type specification

In order to use Resolver a function pointer type must be first declared with using statement of strict form:

    using fn_FunctionName = ReturnType WINAPI (
        ParamType1 paramName1,
        ...,
        ParamTypeN paramNameN,
    );

This repository comes with usings.h header file containing predefined using types for tens of popular Windows APIs.

The FunctionName will correspond to the WinAPI that we want to have ImportResolver resolve and that function pointer must be marked as having WINAPI call convention ( __stdcall on x86 and __fastcall on x64). The ReturnType must precede WINAPI type modifier.

Function resolution and usage

Having function pointer type defined like specified above, we will be able to use it in the following manner:

    RESOLVE(libraryName, FunctionName);
    ReturnType output = _FunctionName(param1, ..., paramN);

The macro RESOLVE takes care of instantiating ImportResolver templated object and adjust specifed library's name.

Resolver introduces several more Macrodefinitions offering easy to use in various circumstances constructor invocation:

#define RESOLVE(mod, func)                    RESOLVE_PARAMETERIZED(mod, func, ::globalVerboseOption, ::globalAntiSplicingOption)
#define RESOLVE_NO_UNHOOK(mod, func)          RESOLVE_PARAMETERIZED(mod, func, ::globalVerboseOption, false)

#define RESOLVE_VERBOSE_UNHOOK(mod, func)     RESOLVE_PARAMETERIZED(mod, func, true, true)
#define RESOLVE_VERBOSE_NOUNHOOK(mod, func)   RESOLVE_PARAMETERIZED(mod, func, true, false)
#define RESOLVE_NOVERBOSE_UNHOOK(mod, func)   RESOLVE_PARAMETERIZED(mod, func, false, true)
#define RESOLVE_NOVERBOSE_NOUNHOOK(mod, func) RESOLVE_PARAMETERIZED(mod, func, false, false)

Resolver's constructor:

    template<typename Ret, typename ...Args>
    ImportResolver<Ret WINAPI(Args...)>(
            std::string dllName,
            std::string funcName,
            bool _verbose = false,
            bool _unhook = false,
            bool *_wasItHooked = nullptr
        )

How does it work?

The underlaying resolver leverages custom PE headers parser, that processes every referenced DLL module to map their exports and verify that module's PE headers integrity as well as integrity of referenced function's stub bytes.

The idea is following:

  1. Firstly we issue LoadLibrary to load referenced by the user library (the one specified as first parameter for RESOLVE macro) if it could not be reached through GetModuleHandle.

  2. Then we process loaded/referenced library's PE headers, map its exports, retrieve array of exports addresses as well as compute these addresses ourselves for cross-verification.

  3. If address of a routine defined in DLL's Export Address Table doesn't correspond to what we would expect, the export is considered EAT hooked. The same goes if our Executable Import Address Table (IAT) entry for that function was altered and no longer points to the correct spot in DLL's code section - then the function is considered to be IAT hooked.

  4. Assuming no hooks were found so far, we fetch first N bytes of the function's prologue and compare them to what's in DLL's file stored in disk. If there is miscrepancy between bytes fetched from memory and from file - we consider function was inline patched (hot-patched).

  5. If the function was considered hooked - we return original export's address (the one we computed ourselves) and/or unhook the entry. If there were patch bytes in place, we'll restore them.

  6. Finally, in order to optimize resolver's performance impact - we cache all of the loaded modules imagebases and resolved functions addresses and return them from a cache (being std::map ) during subsequent hits.

Among the problems such dynamically-unhooking resolver faced are the issues with traversing forwarded APIs (a DLL may contain Export thunk saying that this function is not implemented in this module, but it is in another one) - which although this implementation has support for, sometimes it brokes its traversal logic.

Author

Mariusz Banach / mgeeky (@mariuszbit)

You might also like...
High performance build system for Windows, OSX and Linux. Supporting caching, network distribution and more.

FASTBuild FASTBuild is a build system for Windows, OSX and Linux, supporting distributed compilation and object caching. It is used by many game devel

Graphs the progress of block height in your Chia Full Node.
Graphs the progress of block height in your Chia Full Node.

Chia Height Graph Monitor for Chia Block Height Introduction The chiaheightgraph tool will graph Chia Block Height changes in a linux terminal. Use a

Generate a fictive and unique planet in ascii art with your gnupg fingerprint

GF2PA GPG Fingerprint 2 Planet Ascii Description Examples Usage Compilation Execution Other examples Description Generate a fictive and unique planet

Memgraph is a streaming graph application platform that helps you wrangle your streaming data, build sophisticated models that you can query in real-time, and develop graph applications.
Memgraph is a streaming graph application platform that helps you wrangle your streaming data, build sophisticated models that you can query in real-time, and develop graph applications.

Memgraph is a streaming graph application platform that helps you wrangle your streaming data, build sophisticated models that you can query in real-time, and develop graph applications.

A GREAT program to fuck your memory or swap

Let everyone enjoy the fun of fucking -- Chi_Tang FuckMemory This is a GREAT program to fuck your memory or Swap Installation Dependencies make g++ Li

Fully disables & removes Windows Defender

Fully disables & removes Windows Defender

Cross-platform STL-styled and STL-compatible library with implementing containers, ranges, iterators, type traits and other tools; actors system; type-safe config interface.

Yato A small repository where I'm gatherting useful snippets and abstractions for C++ development. Yato includes 3 main modules: multidimensional cont

Assembly HellGate implementation that directly calls Windows System Calls and displays the PPID of the explorer.exe process
Assembly HellGate implementation that directly calls Windows System Calls and displays the PPID of the explorer.exe process

Custom HellsGate Implementation Assembly HellGate implementation that directly calls Windows System Calls and displays the PPID of the explorer.exe pr

Celeborn is a Userland API Unhooker that I developed for learning Windows APIs and Syscall implementations

Celeborn is a Userland API Unhooker that I developed for learning Windows APIs and Syscall implementations. It mainly detects and patches hooking instructions in NTDLL.dll file. All PRs are welcome!

Violent Fungus is a command and control (C2) software suite, providing red teams post-exploitation persistence and other juicy stuff.

Violent Fungus is a command and control (C2) software suite, providing red teams post-exploitation persistence and other juicy stuff.

Dining philosophers problem is a problem created by Edsger Wybe Dijkstra in 1965 to explain the deadlock state of an operating system, which is traditionally commonly introduced in lectures on operating systems
Dining philosophers problem is a problem created by Edsger Wybe Dijkstra in 1965 to explain the deadlock state of an operating system, which is traditionally commonly introduced in lectures on operating systems

42-philosophers Dining philosophers problem is a problem created by Edsger Wybe Dijkstra in 1965 to explain the deadlock state of an operating system,

A recreation of the
A recreation of the "Nobelium" malware based on Microsofts Malware analysis - Part 1: PDF2Pwn

Nobelium PdfDownloadRunAesMalware A recreation of the "Nobelium" malware based on Microsofts Malware analysis - Part 1: PDF2Pwn 1. Download PDF file f

Mongoose Embedded Web Server Library - a multi-protocol embedded networking library with TCP/UDP, HTTP, WebSocket,  MQTT built-in protocols, async DNS resolver, and non-blocking API.
Mongoose Embedded Web Server Library - a multi-protocol embedded networking library with TCP/UDP, HTTP, WebSocket, MQTT built-in protocols, async DNS resolver, and non-blocking API.

Mongoose - Embedded Web Server / Embedded Networking Library Mongoose is a networking library for C/C++. It implements event-driven non-blocking APIs

A run-time API resolver for IL2CPP Unity.

IL2CPP Resolver A run-time API resolver for IL2CPP Unity. Quick Example #include "Main.hpp" void SomeFunction() { IL2CPP::Initialize(); // This n

Detours is a software package for monitoring and instrumenting API calls on Windows.

Detours is a software package for monitoring and instrumenting API calls on Windows. It is distributed in source code form.

raincoat is a shellcode injector that uses direct syscall invoking.

raincoat is a shellcode injector that uses direct syscall invoking. by liz @realhaxorleet & ellyysium @ellyysium opening the code may cause brain dama

Operating system project - implementing scheduling algorithms and some system calls for XV6 OS

About XV6 xv6 is a modern reimplementation of Sixth Edition Unix in ANSI C for multiprocessor x86 and RISC-V systems.

Operating system project - implementing scheduling algorithms and some system calls for XV6 OS

About XV6 xv6 is a modern reimplementation of Sixth Edition Unix in ANSI C for multiprocessor x86 and RISC-V systems. It was created for pedagogical p

Local OXID Resolver (LCLOR) : Research and Tooling

hazmat5 Local OXID Resolver (LCLOR) : Research and Tooling Welcome to a repository on my research into DCOM's Local OXID Resolution mechanisms, and RP

Comments
  • Simple question

    Simple question

    Hello @mgeeky hope ur doing good, Well I have a simple silly question, I am using syscalls, (exactly the following : NtAllocateVirtualMemory, NtWriteVirtualMemory, NtCreateThreadEx, NtOpenProcess), I want to know if this repo (btw it's amazing) can unhook these functions if they are getting hooked, I am asking this cz it syscalls that I am using and not some normal win api calls . So will it work in this situation ?

    Thanks for the code, & hope u reply soon :)

    opened by ORCA666 2
Owner
Mariusz B.
Sencha-inspired offensive security engineer, deeply in love with adversarial simulations.
Mariusz B.
An intrusive C++17 implementation of a Red-Black-Tree, a Weight Balanced Tree, a Dynamic Segment Tree and much more!

This is Ygg (short for Yggdrasil), a C++17 implementation of several intrusive data structures: several balanced binary search trees: a red-black Tree

Lukas Barth 97 Nov 22, 2022
A RBTree is a sorted associative collection that is implemented with a Red-Black Tree.

A RBTree is a sorted associative collection that is implemented with a Red-Black Tree.

Yusuke Endoh 5 Feb 9, 2022
Total 21 math problem solved by c language with 4 types of functional reference. Also added circular repeated linked list system of Data structure.

C-ProblemSolve Total 21 math problem solved by c language with 4 types of functional reference. Also added circular repeated linked list system of Dat

MH Miyazi 3 Aug 28, 2021
This is a beginner-friendly project aiming to build a problem-set on different data structures and algorithms in different programming languages.

DSAready Overview This is a beginner-friendly project that aims to create a problem-set for various Data Structures and Algorithms. Being a programmer

Riddhi Jain 13 Aug 17, 2022
Collection of all the LeetCode problem solutions using different programming languages.

LeetCode Solutions Collection of all the LeetCode problem solutions using different programming languages. To contribute, you can make a file for the

Jay Patel 34 Sep 2, 2022
Competitive Programming Problem Set

Competitive Programming Problem Set Please press ⭐ button if you like this repo ❤ . Your supports will encourage me a lot and help me put more my time

Tan Huynh 2 Jan 27, 2022
Problem solution of Quera's Problems with different programming language and approach.

Quera-Problem-Solution Problem solution of Quera's Problems with different programming language and approach. How to use Each folder is the category o

Mohammad YousefiPour 6 Oct 10, 2022
The problem consists in determining all shortest paths between pairs of nodes in a given graph.

All-Pairs-Shortest-Path-Problem-Parallel-Computing The problem consists in determining all shortest paths between pairs of nodes in a given graph. Exe

Ana Sofia N. 1 Dec 27, 2021
👨‍💻 Solution of everyday coding problem given in 30DaysofCode contest held on Hackerrank.

??‍??30DaysOfCode-PhoenixClub This repository gives you the solution of everyday problems given in 30DaysOfCode contest which is held on Hackerrank. N

Urveshkumar 8 Jan 30, 2022
Advanced keylogger written in C++ , works on all windows versions use it at your own risk !

About Keylogger Keyloggers or keystroke loggers are software programs or hardware devices that track the activities (keys pressed) of a keyboard. Key

anas 183 Nov 17, 2022