apriorit / mhook Goto Github PK
View Code? Open in Web Editor NEWThis project forked from martona/mhook
A Windows API hooking library
License: MIT License
This project forked from martona/mhook
A Windows API hooking library
License: MIT License
The original function before hook at one address is like this
I am hooking at one specific memory address as shown in the image below
The hooked function successfully hooking function gets called, but while trying call back hooking function (System/Original function) it crashes. I tried to hook at different location address it works. The different address location where I successfully hooked and successfully called hooking function (System/Original function), as shown in the below images.
Before hook.
After hook.
The code for hooked function and calling the hook function is as follows.
Your help is much appreciated. Please help me if I am making any mistake.
On Win10 hooking VirtualAlloc gives the following error message/ warning: [0x7FFEF0CADFE0] ANOMALY: meaningless REX prefix used
The function after the skiped jumps:
https://pastebin.com/RRaQ8JG0
This doesn't happen on Win7 (I'd have to get back to you with the dissasemble on that if you need it). The hook works but I am not sure if I can simply ignore that or I have to "fix" that in some way in the library. Can you tell me why this is bad? http://wiki.osdev.org/X86-64_Instruction_Encoding#REX_prefix This site lists it as a legacy opcode. Can you clarify this please?
I want to hook CreateCaret and DestroyCaret functions from user32.dll. Hooking CreateCaret works ok, but DestroyCaret - no.
#include <Windows.h>
typedef BOOL(WINAPI *CreateCaretFuncPtr)(
_In_ HWND hWnd,
_In_opt_ HBITMAP hBitmap,
_In_ int nWidth,
_In_ int nHeight);
typedef BOOL(WINAPI *DestroyCaretFuncPtr)(VOID);
static CreateCaretFuncPtr CreateCaretOrigFuncPtr = NULL;
static DestroyCaretFuncPtr DestroyCaretOrigFuncPtr = NULL;
static BOOL WINAPI MyCreateCaret(
_In_ HWND hWnd,
_In_opt_ HBITMAP hBitmap,
_In_ int nWidth,
_In_ int nHeight)
{
return CreateCaretOrigFuncPtr(hWnd, hBitmap, nWidth, nHeight);
}
static BOOL WINAPI MyDestroyCaret(VOID)
{
return DestroyCaretOrigFuncPtr();
}
In main function I have:
HMODULE user32ModuleHandle = GetModuleHandle(L"User32");
CreateCaretOrigFuncPtr = (CreateCaretFuncPtr)GetProcAddress(user32ModuleHandle, "CreateCaret");
DestroyCaretOrigFuncPtr = (DestroyCaretFuncPtr)GetProcAddress(user32ModuleHandle, "DestroyCaret");
// will be true
bool createHookSetOk = Mhook_SetHook((PVOID*)&CreateCaretOrigFuncPtr, MyCreateCaret);
// will be false
bool destroyHookSetOk = Mhook_SetHook((PVOID*)&DestroyCaretOrigFuncPtr, MyDestroyCaret);
I studied a bit how mhook works under the hood and I see that the first call to DisassembleAndSkip in Mhook_SetHookEx returns instruction length of 5 bytes for CreateCaret, but 2 bytes for DestroyCaret. ollydbg shows that CreateCaret starts with MOV EAX,1032
(5 bytes long) while DestroyCaret is
759B38C7 6A 06 PUSH 6
759B38C9 E8 1F28FFFF CALL USER32.759A60ED
759B38CE C3 RETN
First instruction for DestroyCaret is PUSH which takes 2 bytes. So DisassembleAndSkip returns 2 bytes and we go to else block where a check for IsJumpPresentInFirstFiveBytes takes place. IsJumpPresentInFirstFiveBytes returns false because it checks only for conditional jumps (ITYPE_BRANCHCC). So trampoline is not created.
Could please anyone comment on this situation? Is this a known behavior?
In IsJumpPresentInFirstFiveBytes I tried to add a check for ITYPE_CALL and return true for that and after that I see that my hook is working (gets called). Is there any drawback of such modification?
OS is Windows 7. Application type is x86.
Windows on Arm64 is a new and growing ecosystem. Could we add support for ARM64 architecture as well?
Hello Team,
Just an FYI in order to get this to compile in mingw on Windows I had to make the following changes to mhook.c:
Line 262:
NTSTATUS(NTAPI PZwQuerySystemInformation)(
SYSTEM_INFORMATION_CLASS SystemInformationClass,
PVOID SystemInformation,
ULONG SystemInformationLength,
PULONG ReturnLength
);
#define STATUS_INFO_LENGTH_MISMATCH ((NTSTATUS)0xC0000004L)
//remove this.... static PZwQuerySystemInformation fnZwQuerySystemInformation = NULL;
//put this instead
static decltype(PZwQuerySystemInformation) *fnZwQuerySystemInformation=NULL;
Line 762:
fnZwQuerySystemInformation = (decltype(PZwQuerySystemInformation))((void)GetProcAddress(GetModuleHandle("ntdll.dll"), "ZwQuerySystemInformation"));
The error I was getting:
c:\mhook-master>g++ mhook-lib\mhook.c disasm-lib\disasm.c disasm-lib\disasm_x86.c disasm-lib\cpu.c T:/hookdll/main.cpp -o t:/hookdll/mhooktest.dll -D_WIN32_WINNT=0x0502 -w -Wfatal-errors -fpermissive -shared
mhook-lib\mhook.c:261:25: error: typedef 'PZwQuerySystemInformation' is initialized (use 'decltype' instead)
261 | typedef NTSTATUS(NTAPI* PZwQuerySystemInformation)(
c:\mhook-master>g++ mhook-lib\mhook.c disasm-lib\disasm.c disasm-lib\disasm_x86.c disasm-lib\cpu.c T:/hookdll/main.cpp -o t:/hookdll/mhooktest.dll -w -Wfatal-errors -fpermissive -shared
mhook-lib\mhook.c: In function 'BOOL CreateProcessSnapshot(void**)':
mhook-lib\mhook.c:762:115: error: cannot convert 'const wchar_t*' to 'LPCSTR' {aka 'const char*'}
762 | fnZwQuerySystemInformation = (decltype(PZwQuerySystemInformation))((void)GetProcAddress(GetModuleHandle(L"ntdll.dll")....
Compiler info:
c:\mhook-master>g++ --version
g++ (Rev10, Built by MSYS2 project) 11.2.0
Copyright (C) 2021 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
Hope this helps
Best Regards,
-Avery T
Lines 1004 to 1013 in 2238938
In this, and the following two cases, the break can (and does in my tests) cause the hook installation to fail. I have personally removed them on my end and it works well. But what's the reasoning for breaking here?
Below function in mhook.c
static BOOL GetCurrentProcessSnapshot(PVOID* snapshot, PSYSTEM_PROCESS_INFORMATION* procInfo)
{
// get a view of the threads in the system
if (!CreateProcessSnapshot(snapshot))
{
ODPRINTF((L"mhooks: can't get process snapshot!"));
return FALSE;
}
DWORD pid = GetCurrentProcessId();
*procInfo = FindProcess(*snapshot, pid);
return TRUE;
}
In case of FindProcess return NULL but this function is still return TRUE.
Solution:
...
return NULL != *procInfo
Hiya, I used mhook(2.4) today, and it worked fine but the dll I created kept getting unloaded.
Now I found your project and I'm trying to figure out how to get started with it, the getting started is pretty small and I cant understand, if I use it with AppInit hooking method and I dont get how is it suppose to load the dll hooks if there is no dll entrypoint in your example test.
Can I have an explanation? do you guys have an irc/discord channel by any chance?
Hello,
I just found this article on the web.
https://www.linux.com/training-tutorials/splice-hooking-unix-systems/
Seems that splice hooking supports the ARM architecture.
Would me mind sharing how to support ARM in the Mhook library?
I have a Kylin OS running on ARM64 CPU, which has ftrace disabled, so I cannot use the ftrace hooking method described on Apriorit website. Thanks!
I came across some article: https://www.apriorit.com/dev-blog/160-apihooks
Why does it need to be a dll? Can't it just be called on a simple exe file?
Hi, This is a nice hook library, but also there's so many "junk" information in code.
Such as,
Line 86 in 43c4949
after build in Release, there's so many log out there, not pretty, Why not use NDEBUG Micro to disable in release?
And also, assert function.
Hi,
I build a sample (AppInitHook) and added global hooks for CopyFileA/W. Also I created simple application that call CopyFileA/W. Dll installs those hooks but the hooks aren't called when I run the application which call CopyFileA/W.
I didn't found special limitations for Kernel32.dll. Are there some limitations?
#include "mhook/mhook-lib/mhook.h"
#include <fstream>
typedef BOOL(WINAPI* _CopyFileA)(LPCSTR lpExistingFileName, LPCSTR lpNewFileName, BOOL bFailIfExists);
typedef BOOL(WINAPI* _CopyFileW)(LPCWSTR lpExistingFileName, LPCWSTR lpNewFileName, BOOL bFailIfExists);
typedef BOOL(WINAPI* _CopyFileExA)(LPCSTR lpExistingFileName, LPCSTR lpNewFileName, LPPROGRESS_ROUTINE lpProgressRoutine, LPVOID lpData, LPBOOL pbCancel, DWORD dwCopyFlags);
//////////////////////////////////////////////////////////////////////////
// Defines and typedefs
#define STATUS_SUCCESS ((NTSTATUS)0x00000000L)
typedef struct _MY_SYSTEM_PROCESS_INFORMATION
{
ULONG NextEntryOffset;
ULONG NumberOfThreads;
LARGE_INTEGER Reserved[3];
LARGE_INTEGER CreateTime;
LARGE_INTEGER UserTime;
LARGE_INTEGER KernelTime;
UNICODE_STRING ImageName;
ULONG BasePriority;
HANDLE ProcessId;
HANDLE InheritedFromProcessId;
} MY_SYSTEM_PROCESS_INFORMATION, *PMY_SYSTEM_PROCESS_INFORMATION;
typedef NTSTATUS (WINAPI *PNT_QUERY_SYSTEM_INFORMATION)(
__in SYSTEM_INFORMATION_CLASS SystemInformationClass,
__inout PVOID SystemInformation,
__in ULONG SystemInformationLength,
__out_opt PULONG ReturnLength
);
//////////////////////////////////////////////////////////////////////////
// Original function
PNT_QUERY_SYSTEM_INFORMATION OriginalNtQuerySystemInformation =
(PNT_QUERY_SYSTEM_INFORMATION)::GetProcAddress(::GetModuleHandle(L"ntdll"), "NtQuerySystemInformation");
_CopyFileA origCPAHandlerPtr = (_CopyFileA)::GetProcAddress(::GetModuleHandle(L"Kernel32"), "CopyFileA");
_CopyFileW origCPWHandlerPtr = (_CopyFileW)::GetProcAddress(::GetModuleHandle(L"Kernel32"), "CopyFileW");
_CopyFileExA origCopyFileExAPtr = (_CopyFileExA)::GetProcAddress(::GetModuleHandle(L"Kernel32"), "CopyFileExA");
//////////////////////////////////////////////////////////////////////////
// Hooked function
BOOL WINAPI HookCopyFileExA(
LPCSTR lpExistingFileName,
LPCSTR lpNewFileName,
LPPROGRESS_ROUTINE lpProgressRoutine,
LPVOID lpData,
LPBOOL pbCancel,
DWORD dwCopyFlags
)
{
std::ofstream("c:/tmp/test.txt", std::ios::app) << "CopyFileA" << std::endl;
if (origCopyFileExAPtr == nullptr)
return FALSE;
return origCopyFileExAPtr(lpExistingFileName, lpNewFileName, lpProgressRoutine, lpData, pbCancel, dwCopyFlags);
}
BOOL WINAPI HookCopyFileA(LPCSTR lpExistingFileName, LPCSTR lpNewFileName, BOOL bFailIfExists)
{
// CallHandler::logCall("CopyFileA", lpExistingFileName, lpNewFileName);
std::ofstream("c:/tmp/test.txt", std::ios::app) << "CopyFileA" << std::endl;
if (origCPAHandlerPtr == nullptr)
return FALSE;
return origCPAHandlerPtr(lpExistingFileName, lpNewFileName, bFailIfExists);
}
BOOL WINAPI HookCopyFileW(LPCWSTR lpExistingFileName, LPCWSTR lpNewFileName, BOOL bFailIfExists)
{
//getHandlers().getOriginFunctionPtr(L"Kernel32.dll", "CopyFileW");
// CallHandler::logCall("CopyFileW", lpExistingFileName, lpNewFileName);
std::ofstream("c:/tmp/test.txt", std::ios::app) << "CopyFileW" << std::endl;
if (origCPWHandlerPtr == nullptr)
return FALSE;
return origCPWHandlerPtr(lpExistingFileName, lpNewFileName, bFailIfExists);
}
NTSTATUS WINAPI HookedNtQuerySystemInformation(
__in SYSTEM_INFORMATION_CLASS SystemInformationClass,
__inout PVOID SystemInformation,
__in ULONG SystemInformationLength,
__out_opt PULONG ReturnLength
)
{
std::ofstream("c:/tmp/test.txt", std::ios::app) << "NtQuerySystemInformation" << std::endl;
NTSTATUS status = OriginalNtQuerySystemInformation(SystemInformationClass,
SystemInformation,
SystemInformationLength,
ReturnLength);
if (SystemProcessInformation == SystemInformationClass && STATUS_SUCCESS == status)
{
//
// Loop through the list of processes
//
PMY_SYSTEM_PROCESS_INFORMATION pCurrent = NULL;
PMY_SYSTEM_PROCESS_INFORMATION pNext = (PMY_SYSTEM_PROCESS_INFORMATION)SystemInformation;
do
{
pCurrent = pNext;
pNext = (PMY_SYSTEM_PROCESS_INFORMATION)((PUCHAR)pCurrent + pCurrent->NextEntryOffset);
if (!wcsncmp(pNext->ImageName.Buffer, L"Calculator.exe", pNext->ImageName.Length))
{
if (0 == pNext->NextEntryOffset)
{
pCurrent->NextEntryOffset = 0;
}
else
{
pCurrent->NextEntryOffset += pNext->NextEntryOffset;
}
pNext = pCurrent;
}
}
while(pCurrent->NextEntryOffset != 0);
}
return status;
}
//////////////////////////////////////////////////////////////////////////
// Entry point
BOOL WINAPI DllMain(
__in HINSTANCE hInstance,
__in DWORD Reason,
__in LPVOID Reserved
)
{
std::ofstream("c:/tmp/test.txt", std::ios::app) << "DllMain" << std::endl;
switch (Reason)
{
case DLL_PROCESS_ATTACH:
std::ofstream("c:/tmp/test.txt", std::ios::app) << "DLL_PROCESS_ATTACH " << Mhook_SetHook((PVOID*)&origCPAHandlerPtr, HookCopyFileA) << std::endl;
std::ofstream("c:/tmp/test.txt", std::ios::app) << "DLL_PROCESS_ATTACH " << Mhook_SetHook((PVOID*)&origCPWHandlerPtr, HookCopyFileW) << std::endl;
// Mhook_SetHook((PVOID*)&OriginalNtQuerySystemInformation, HookedNtQuerySystemInformation);
std::ofstream("c:/tmp/test.txt", std::ios::app) << "DLL_PROCESS_ATTACH " << Mhook_SetHook((PVOID*)&origCopyFileExAPtr, HookCopyFileExA) << std::endl;
break;
case DLL_PROCESS_DETACH:
std::ofstream("c:/tmp/test.txt", std::ios::app) << "DLL_PROCESS_DETACH" << std::endl;
// Mhook_Unhook((PVOID*)&OriginalNtQuerySystemInformation);
Mhook_Unhook((PVOID*)&origCPAHandlerPtr);
Mhook_Unhook((PVOID*)&origCPWHandlerPtr);
Mhook_Unhook((PVOID*)&origCopyFileExAPtr);
break;
default:
std::ofstream("c:/tmp/test.txt", std::ios::app) << "def: " << Reason << std::endl;
}
return TRUE;
}
And simple app:
#include <iostream>
#include <Windows.h>
int main()
{
CopyFileA("c:/tmp/1.txt", "c:/tmp/2.txt", FALSE);
CopyFileW(L"c:/tmp/1.txt", L"c:/tmp/2.txt", FALSE);
std::cout << "Hello World!\n";
}
AppVeyor offers a free windows-based CI for open-source projects. Let's use it.
Have you come across Microsoft's vcpkg? It would be great, to be able, to install mhook through it. https://github.com/Microsoft/vcpkg.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.