I wrote an anti-jaclib hook before. I don't remember if I shared it or not but I remember writing it.. There was lots of features but the one you seem to be interested in is the MouseHook and KeyboardHook flag removal.. Below should be enough to get you started on writing your own.
How it works? We get the game to load our code/plugin/dll (use whatever method you want). Then in DLLMain we HIDE ourselves from detection so if the game tries to detect that our module is loaded/injected, it won't. Then we hook the SetWindowsHookEx function. If the game tries to hook the mouse, return our custom hooks instead and keep a pointer to the original function (Trampoline).
In our trampoline function, we remove the Injection Flags and call the original hook function (don't break the chain). Voila. We are undetected and our mouse and keyboard is undetected. All without the need of a driver.
C++ Code:
#include <windows.h>#include <winternl.h>#include <TlHelp32.h>#include <chrono>#include <thread> typedef struct _LDR_MODULE
{ LIST_ENTRY InLoadOrderModuleList
; LIST_ENTRY InMemoryOrderModuleList
; LIST_ENTRY InInitializationOrderModuleList
; PVOID BaseAddress
; PVOID EntryPoint
; ULONG SizeOfImage
; UNICODE_STRING FullDllName
; UNICODE_STRING BaseDllName
; ULONG Flags
; SHORT LoadCount
; SHORT TlsIndex
; LIST_ENTRY HashTableEntry
; ULONG TimeDateStamp
;} LDR_MODULE
, *PLDR_MODULE
;typedef struct _ProcessModuleInfo
{ std
::uint32_t Size
; std
::uint32_t Initialized
; HANDLE SsHandle
; LIST_ENTRY LoadOrder
; LIST_ENTRY InitOrder
; LIST_ENTRY MemoryOrder
;} ProcessModuleInfo
, *pProcessModuleInfo
;void* DetourFunction
(BYTE
*src
, const BYTE
*dst
, const int len
);typedef HHOOK
(__stdcall
*SetWindowsHookEx_t
)(int idHook
, HOOKPROC lpfn
, HINSTANCE hMod
, DWORD dwThreadId
);SetWindowsHookEx_t o_SetWindowsHookEx
;HOOKPROC oMouseHookedProc
= NULL
;LDR_MODULE
* GetModuleIterator
() //I use assembly here but you can remove it and use GetPEB() from WinAPI.{ #ifndef _USE_GET_PEB_ void* result
= NULL
; #ifdef INTEL_SYNTAX /**-masm=intel**/ asm
(".intel_syntax noprefix\n"); #else asm
(".att_syntax noprefix\n"); #endif // INTEL_SYNTAX #ifndef INTEL_SYNTAX asm
volatile ( "movl %%FS:0x18, %%eax\n" "movl 0x30(%%eax), %%eax\n" "movl 0x0C(%%eax), %0\n" : "=r" (result
) :: "eax" ); #else asm
volatile ( "mov eax, DWORD PTR [FS:0x18]\n\t" "mov eax, DWORD PTR [eax + 0x30]\n\t" "mov %0, DWORD PTR [eax + 0x0C]\n" : "=r" (result
) :: "eax" ); #endif // INTEL_SYNTAX return reinterpret_cast
<ProcessModuleInfo
*>(result
)->LoadOrder.
Flink; #else reinterpret_cast
<ProcessModuleInfo
*>(GetPEB
())->LoadOrder.
Flink; #endif}void LinkLocalProcessModule
(LDR_MODULE
* module
){ auto AddLink
= [&](LIST_ENTRY
* Link
) { Link
->Flink
->Blink
= Link
; Link
->Blink
->Flink
= Link
; }; AddLink
(&module
->InLoadOrderModuleList
); AddLink
(&module
->InMemoryOrderModuleList
); AddLink
(&module
->InInitializationOrderModuleList
); AddLink
(&module
->HashTableEntry
);}void UnlinkLocalProcessModule
(LDR_MODULE
* module
){ auto RemoveLink
= [](LIST_ENTRY
* Link
) { Link
->Blink
->Flink
= Link
->Flink
; Link
->Flink
->Blink
= Link
->Blink
; }; RemoveLink
(&module
->InLoadOrderModuleList
); RemoveLink
(&module
->InMemoryOrderModuleList
); RemoveLink
(&module
->InInitializationOrderModuleList
); RemoveLink
(&module
->HashTableEntry
);}void HideSelf
(HMODULE self
, LDR_MODULE
** old
){ LDR_MODULE
* module
= GetModuleIterator
(); while (module
->BaseAddress
) { if (module
->BaseAddress
== self
) { *old
= module
; UnlinkLocalProcessModule
(module
); } module
= reinterpret_cast
<LDR_MODULE
*>(module
->InLoadOrderModuleList.
Flink); }}LRESULT __stdcall mHookedProc
(int Code
, WPARAM wParam
, LPARAM lParam
){ if (Code
== HC_ACTION
) { MSLLHOOKSTRUCT
* Info
= reinterpret_cast
<MSLLHOOKSTRUCT
*>(lParam
); Info
->flags
&= ~LLMHF_INJECTED
; //remove the injected flag. Info
->flags
&= ~LLMHF_LOWER_IL_INJECTED
; //remove the injected flag. } return oMouseHookedProc
(Code
, wParam
, lParam
);}HHOOK __stdcall HOOKED_SetWindowsHookEx
(int idHook
, HOOKPROC lpfn
, HINSTANCE hMod
, DWORD dwThreadId
){ if (idHook
== WH_MOUSE_LL
) { oMouseHookedProc
= (HOOKPROC
)DetourFunction
((unsigned char*)lpfn
, (unsigned char*)&mHookedProc
, 6); } return o_SetWindowsHookEx
(idHook
, oMouseHookedProc
, hMod
, dwThreadId
);}void* DetourFunction
(BYTE
*src
, const BYTE
*dst
, const int len
){ BYTE
*jmp
= (BYTE
*)malloc(len
+5); DWORD dwBack
; VirtualProtect
(src
, len
, PAGE_EXECUTE_READWRITE
, &dwBack
); memcpy(jmp
, src
, len
); jmp
+= len
; jmp
[0] = 0xE9; //Assembly JMP instruction. *(DWORD
*)(jmp
+1) = (DWORD
)(src
+len
- jmp
) - 5; src
[0] = 0xE9; *(DWORD
*)(src
+1) = (DWORD
)(dst
- src
) - 5; for (int i
=5; i
<len
; i
++) src
[i
]=0x90; //Assembly NOP instruction. VirtualProtect
(src
, len
, dwBack
, &dwBack
); return (jmp
-len
);}void InitialiseHooks
(){ while(!GetModuleHandle
("User32.dll")) //hook user32's SetWindowsHookEx function.. { std
::this_thread::sleep_for(std
::chrono::milliseconds(100)); } o_SetWindowsHookEx
= (SetWindowsHookEx_t
) GetProcAddress
(GetModuleHandle
("User32.dll"), "SetWindowsHookExA"); o_SetWindowsHookEx
= (SetWindowsHookEx_t
) DetourFunction
((unsigned char*)o_SetWindowsHookEx
, (unsigned char*)&HOOKED_SetWindowsHookEx
, 5);}static LDR_MODULE
* me
= NULL
;DWORD __stdcall DllMain
(HINSTANCE hInst
, DWORD nReason
, LPVOID Reserved
){ switch(nReason
) { case DLL_PROCESS_ATTACH
: { DisableThreadLibraryCalls
(hInst
); HideSelf
(hInst
, &me
); std
::thread([&] {InitialiseHooks
();}).
detach(); } break; case DLL_PROCESS_DETACH
: { LinkLocalProcessModule
(me
); } break; } return TRUE
;}