wraithdu Posted January 6, 2009 Posted January 6, 2009 (edited) IMPORTANT: For those who don't have them, please download and install the Microsoft VC++ 2008 SP1 RedistributableIf you don't have these runtimes, the example will crash.This little project of mine got influnce from many places. First was monoceres' example of hooking a local API call by modifying the IAT. Next was Ward's MemoryDll UDF, which formed a basis for my method. Lastly was a CodeProject article here -http://www.codeproject.com/KB/system/mini_hook_engine.aspxwhich describes a hook engine, and from which I took the idea for the hook bridge, which allows a hooking function to call the real function without resetting the hook (makes this process thread-safe). I'm also using Distorm64 for the disassembly. The compiled distorm64 DLL is included and used via Ward's MemoryDll UDF.What this archive contains -Source for the testapp, example app, and DLLThe compiled DLL that is injected into the testapp to hook the MessageBoxW functionUDF source files include _WinApiHook (main UDF), and support files _Distorm, _Distorm_src (the DLL), _MemoryDll (from Ward)In order to do remote hooking, a DLL must* be used. This method uses RtlCreateUserThread() to cause the remote process to call LoadLibraryA to load the remote DLL. Similarly, it can be made to call FreeLibrary, or any function in your injected DLL. This method can be used to retrieve a remote process's commandline, for example.I hope the included sample DLL can show the functions needed and how to use them. 2 functions are requred for each API - 1 to do the actual hooking, and 1 to retrieve the Bridge address. This function must be called manually before setting the hook to provide the remote process with the address of the Bridge. Well, the 2nd function and manual call are only required if you want your hooking function to be able to call the original function.Comments welcome!* I said must above, but that's not 100% true. There is a way to do it without an external DLL using WriteProcessMemory, but it sill requires the binary data of compiled code, and the code must adhere to specific guidelines -(among others, HERE under "Additional caveats")- code must not use C/C++ runtimes- code must not call other functions, unless they are also injected (those functions must adhere to the same guidelines)This makes it pretty hard to do anything useful.Update 1: 2009/01/06- fixed small error in example- added note about installing the VC++ 2008 SP1 RedistributableUpdate 2: 2009/01/22- fixed error in _HookApi_Get() trying to FreeLibrary the wrong address- added function to find the base address of a module in a process (incorporated in main functions)- _InjectDll and _FreeRemoteDll now search the remote process for the base address of kernel32.dll, instead of assuming the base address is constant in all processes- removed compiled apps from archive to reduce its size- _HookApi_Get creates hook backup by reading remote process memory, instead of assuming local code is identicalUpdate 3: 2009/09/25- fixed virtual memory release errors: previously used _MemVirtualFree() with the $MEM_DECOMMIT flag instead of the correct $MEM_RELEASE flag- changed inject/free functions to use RtlCreateUserThread() (original CreateRemoteThread option is still there, only commented out)- minor changes to _MemoryDll UDF: now it allocates memory using _MemVirtualAlloc() with the $PAGE_EXECUTE_READWRITE flag to avoid any possible problems with DEPUpdate 4: 2009/09/28- added _GetPrivilege_SEDEBUG.au3 to zip fileUpdate 5: 2009/10/04- updated injection functions to work on XP: it will use CreateRemoteThread() on XP and RtlCreateUserThread() on Vista+Update 6: 2009/10/06- new option in _InjectDll() and _FreeRemoteDll() to skip remotely locating the base address of 'kernel32.dll' - THIS IS DANGEROUS, USE AT YOUR OWN RISK!!!- switched to use the CreateToolhelp32 API to enumerate remote modules (the PSAPI version is still included)- much better error detection and return values in all UDFsUpdate 7: 2009/10/06- workaround for AutoIt < 3.3.1.0 bug_WinApiHook.zip Edited October 6, 2009 by wraithdu
JRSmile Posted January 6, 2009 Posted January 6, 2009 (edited) This little project of mine got influnce from many places. First was monoceres' example of hooking a local API call by modifying the IAT. Next was Ward's MemoryDll UDF, which formed a basis for my method. Lastly was a CodeProject article here -http://www.codeproject.com/KB/system/mini_hook_engine.aspxwhich describes a hook engine, and from which I took the idea for the hook bridge, which allows a hooking function to call the real function without resetting the hook (makes this process thread-safe). I'm also using Distorm64 for the disassembly. The compiled distorm64 DLL is included and used via Ward's MemoryDll UDF.What this archive contains -A compiled testapp (the app that will be hooked)A compiled example app which will show both local and remote hookingA compiled DLL that is injected into the testapp to hook the MessageBoxW functionSource for the testapp, example app, and DLLUDF source files include _WinApiHook (main UDF), and support files _Distorm, _Distorm_src (the DLL), _MemoryDll (from Ward)In order to do remote hooking, a DLL must* be used. This method uses CreateRemoteThread to cause the remote process to call LoadLibraryA to load the remote DLL. Similarly, it can be made to call FreeLibrary, or any function in your injected DLL. This method can be used to retrieve a remote process's commandline, for example.I hope the included sample DLL can show the functions needed and how to use them. 2 functions are requred for each API - 1 to do the actual hooking, and 1 to retrieve the Bridge address. This function must be called manually before setting the hook to provide the remote process with the address of the Bridge. Well, the 2nd function and manual call are only required if you want your hooking function to be able to call the original function.Comments welcome!* I said must above, but that's not 100% true. There is a way to do it without an external DLL using WriteProcessMemory, but it sill requires the binary data of compiled code, and the code must adhere to specific guidelines -(among others, HERE under "Additional caveats")- code must not use C/C++ runtimes- code must not call other functions, unless they are also injected (those functions must adhere to the same guidelines)This makes it pretty hard to do anything useful.the hooked msgboxw crashed the testap before the 10 seconds ran out.. im using vista.ps: tested with adminrights without and with compatibility mode. everytime crash befor i could press the button.pss: but anyway a nice and worthful try. keep on the good work. Edited January 6, 2009 by JRSmile $a=StringSplit("547275737420796F757220546563686E6F6C75737421","") For $b=1 To UBound($a)+(-1*-1*-1)step(2^4/8);&$b+=1*2/40*µ&Asc(4) Assign("c",Eval("c")&Chr(Dec($a[$b]&$a[$b+1])));''Chr("a")&"HI" Next ;time_U&r34d,ths,U-may=get$the&c.l.u.e;b3st-regards,JRSmile; MsgBox(0x000000,"",Eval("c"));PiEs:d0nt+*b3.s4d.4ft3r.1st-try:-)
wraithdu Posted January 6, 2009 Author Posted January 6, 2009 (edited) That's very odd. I'm also on Vista SP1 32-bit, and it works fine here, both in compiled form and from Scite. How are you running the test? You should extract the 2 compiled EXEs and the DLL to the same directory, and run ApiHookExample.exe. Also works well on an XP box I just tested. Edited January 6, 2009 by wraithdu
yehia Posted January 6, 2009 Posted January 6, 2009 crashes here too win xp sp2 My Scripts:IE New UDFsElastic images moving under mouse (with a happy valentine's example)_FileRemoveLine
wraithdu Posted January 6, 2009 Author Posted January 6, 2009 Are you running the compiled EXE as described above, or recompiling, or what? I can't seem to reproduce these crashes on Vista or XP.
wraithdu Posted January 6, 2009 Author Posted January 6, 2009 (edited) Ok, so I did get it to crash on an XP system I have at home. Unfortunately I have no idea why it would crash on some systems and not others. Any ideas would be welcome. I've tested on 1 Vista sys (OK), 2 XP SP3 system (1 OK, 1 crash). Edited January 6, 2009 by wraithdu
wraithdu Posted January 7, 2009 Author Posted January 7, 2009 (edited) Ok, duh, I figured it out. I did find one error in the example, but it wasn't necessarily related to the crash. For those who had problems with the test crashing, please download the VC++ 2008 SP1 Redistributable and install the runtimes. The msgdll.dll was failing to load on systems without the runtimes and crashing the testapp. See first post for an updated archive and download link for the runtimes. Edited January 7, 2009 by wraithdu
wraithdu Posted January 7, 2009 Author Posted January 7, 2009 Eh, 722 downloads??? That's gotta be a board error...there's not even that many views!
trancexx Posted January 7, 2009 Posted January 7, 2009 Eh, 722 downloads??? That's gotta be a board error...there's not even that many views!Maybe the view counter is wrong. Ahhaaa!I know that I have downloaded. That's 1.Nothing crashed for me (XP SP3) ♡♡♡ . eMyvnE
JRSmile Posted January 7, 2009 Posted January 7, 2009 Eh, 722 downloads??? That's gotta be a board error...there's not even that many views!i downloaded 5 times: laptop, iphone,rootserver,work pc,svn-server... maybe others did the same? $a=StringSplit("547275737420796F757220546563686E6F6C75737421","") For $b=1 To UBound($a)+(-1*-1*-1)step(2^4/8);&$b+=1*2/40*µ&Asc(4) Assign("c",Eval("c")&Chr(Dec($a[$b]&$a[$b+1])));''Chr("a")&"HI" Next ;time_U&r34d,ths,U-may=get$the&c.l.u.e;b3st-regards,JRSmile; MsgBox(0x000000,"",Eval("c"));PiEs:d0nt+*b3.s4d.4ft3r.1st-try:-)
wraithdu Posted January 7, 2009 Author Posted January 7, 2009 LOL, holy crap! You do that for everyone's stuff, or is it just that good? HA!
JRSmile Posted January 8, 2009 Posted January 8, 2009 this is my normal procedure if i find interresting code for further development: download, categorize (function name includes dlls used etc..) upload to svn, backup on nas and a zipped working example on all of my machines. sorry to dissapoint you :-) $a=StringSplit("547275737420796F757220546563686E6F6C75737421","") For $b=1 To UBound($a)+(-1*-1*-1)step(2^4/8);&$b+=1*2/40*µ&Asc(4) Assign("c",Eval("c")&Chr(Dec($a[$b]&$a[$b+1])));''Chr("a")&"HI" Next ;time_U&r34d,ths,U-may=get$the&c.l.u.e;b3st-regards,JRSmile; MsgBox(0x000000,"",Eval("c"));PiEs:d0nt+*b3.s4d.4ft3r.1st-try:-)
arcker Posted January 9, 2009 Posted January 9, 2009 (edited) that's the thing i tried to do when monoceres did his script for local api hook, but i never managed to do it, and whe i see the complexity of all, i understand why do you think you can make a hook for the function SHFileOperation used in shell32.dll with the process explorer.exe ? i'm trying to edit your code to make it woek but it's a little bit hard with the dll's part. awesome job anyway that open lot of possibilities for monitoring. Edited January 9, 2009 by arcker -- Arck System _ Soon -- Ideas make everything "La critique est facile, l'art est difficile" Projects :[list] [*]Au3Service : Run your exe as service V3 / Updated 29/07/2013Â Get it Here [/list]
wraithdu Posted January 9, 2009 Author Posted January 9, 2009 Where exactly are you having trouble, injecting the DLL, hooking the API, or coding the DLL to do what you want? What do you want the hook to do? Also, are you hooking the Ansi or Unicode version of the function, or both? FYI, the script already gets the SE_DEBUG privilege if it can, so you should be OK to open explorer. Be careful though, if ya mess up, you're taking explorer down with you The basic DLL layout would be something like - // main.h #ifndef __MAIN_H__ #define __MAIN_H__ #include <windows.h> /* To use this exported function of dll, include this header * in your project. */ #ifdef BUILD_DLL #define DLL_EXPORT __declspec(dllexport) WINAPI #else #define DLL_EXPORT __declspec(dllimport) WINAPI #endif #ifdef __cplusplus extern "C" { #endif int DLL_EXPORT MySHFileOpW(LPSHFILEOPSTRUCT lpFileOp); int DLL_EXPORT GetSHFileOpW(void *p); #ifdef __cplusplus } #endif #endif // __MAIN_H__ expandcollapse popup// main.cpp #include "main.h" int (WINAPI *pMySHFileOpW) (LPSHFILEOPSTRUCT); // pointer to the bridge // SHFileOpW hook function int DLL_EXPORT MySHFileOpW(LPSHFILEOPSTRUCT lpFileOp) { if (pMySHFileOpW == NULL) return 1; // do something // call the original SHFileOpW function through the Bridge return pMySHFileOpW(lpFileOp); } // obtain the address to the Bridge int DLL_EXPORT GetSHFileOpW(void *p) { // this function must be called before setting the hook to provide the hooking function with the bridge address pMySHFileOpW = (int (WINAPI *)(LPSHFILEOPSTRUCT)) p; return 0; } BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) { switch (fdwReason) { case DLL_PROCESS_ATTACH: pMySHFileOpW = NULL; case DLL_PROCESS_DETACH: case DLL_THREAD_ATTACH: case DLL_THREAD_DETACH: break; } return TRUE; // succesful }
arcker Posted January 9, 2009 Posted January 9, 2009 thx for the answer ! i've a problem coding the dll, that's all ... for now i want to hook, for now, just if the Api is called. After i will try to get the pointer information and launch my own "copyfile", lile supercopier does. i'm using VC++ 2005 thx again -- Arck System _ Soon -- Ideas make everything "La critique est facile, l'art est difficile" Projects :[list] [*]Au3Service : Run your exe as service V3 / Updated 29/07/2013Â Get it Here [/list]
arcker Posted January 9, 2009 Posted January 9, 2009 mmm the autoit code returns a bad parameter ( error 87 ) when using openprocess with explorer.exe.... don't know why. -- Arck System _ Soon -- Ideas make everything "La critique est facile, l'art est difficile" Projects :[list] [*]Au3Service : Run your exe as service V3 / Updated 29/07/2013Â Get it Here [/list]
wraithdu Posted January 9, 2009 Author Posted January 9, 2009 This doesn't work for you and return a handle to explorer.exe? #include <_WinApiHook.au3> $pid = ProcessExists("explorer.exe") ConsoleWrite("pid: " & $pid & @CRLF) $hProc = _GetProcHandle($pid) ConsoleWrite("hProc: " & $hProc & @CRLF) If $hProc Then _WinAPI_CloseHandle($hProc)
arcker Posted January 10, 2009 Posted January 10, 2009 (edited) yes this code works at home . ( not tested at work ) Now i try to run the test but it crashes explorer.exe. :/ ( so if there is just one explorer.exe, it crash the desktop but fortunately windows manage to restore him ) here is what i have : expandcollapse popup#NoTrayIcon #AutoIt3Wrapper_Change2CUI=y #include <_WinApiHook.au3> #include <_MemoryDll.au3> Local $MyMsgBox = DllCallbackRegister("_MyCopyFile", "none", "ptr") Local $pMyMsgBox = DllCallbackGetPtr($MyMsgBox) Local $targetmodule = "shell32.dll" Local $targetfunction = "SHFileOperationW" $DISTORM_DEBUG = True ;; remote hook test ;MsgBox(0 + 64, "Info", "Press OK. You then have 10 seconds to test the Message button.") ;$pid = Run("explorer.exe") ;ProcessWait($pid) ;Sleep(500) ;test by using existing process $pid = ProcessExists("explorer.exe") ConsoleWrite("pid: " & $pid & @CRLF) ; for remote processes, the Bridge element will be NULL ; the BridgePtr will be a pointer in the remote process to the memory allocated $MyHook = _HookApi_Get($targetmodule, $targetfunction, $pid) ConsoleWrite("-------------" & @CRLF) ConsoleWrite("HookAddress: " & DllStructGetData($MyHook, "HookAddress") & @CRLF) ConsoleWrite("HookBak: " & DllStructGetData($MyHook, "HookBak") & @CRLF) ConsoleWrite("Bridge: " & DllStructGetData($MyHook, "Bridge") & @CRLF) ConsoleWrite("BridgePtr: " & DllStructGetData($MyHook, "BridgePtr") & @CRLF) ConsoleWrite("Status after get: " & DllStructGetData($MyHook, "Status") & @CRLF) ConsoleWrite("Process: " & DllStructGetData($MyHook, "Process") & @CRLF) ; verify bridge $hProcess = _GetProcHandle($pid) $s = DllStructCreate("byte[64]") DllCall("kernel32.dll", "int", "ReadProcessMemory", "ptr", $hProcess, "ptr", DllStructGetData($MyHook, "BridgePtr"), "ptr", DllStructGetPtr($s), "uint", 64, "uint*", 0) ConsoleWrite("-------------------" & @CRLF) ConsoleWrite("remote bridge: " & DllStructGetData($s, 1) & @CRLF) ; inject dll $hModule = _InjectDll(@ScriptDir & "\mine.dll", $pid) ;; set hook ; call the remote function to set the bridge address ; if you know the offset, then add it to $hModule ; if not, load the dll locally to get hMod and use GetProcAddress to get the funcaddres ; then the offset = funcaddress - hMod ; get the bridge setting function offset $hMod = _WinAPI_LoadLibrary("mine.dll") $fnAddress = _GetProcAddress($hMod, "_GetSHFileOp@4") $offset = $fnAddress - $hMod ; set the bridge $ret = DllCall("kernel32.dll", "ptr", "CreateRemoteThread", "ptr", $hProcess, "ptr", 0, "uint", 0, "ptr", $hModule + $offset, "ptr", DllStructGetData($MyHook, "BridgePtr"), "dword", 0, "ptr", 0) _WinAPI_WaitForSingleObject($ret[0]) _WinAPI_CloseHandle($ret[0]) ; get hook function offset $fnAddress = _GetProcAddress($hMod, "_MySHFileOp@16") $offset = $fnAddress - $hMod ; free the locally loaded library _WinAPI_FreeLibrary($hMod) _HookApi_Set($MyHook, $hModule + $offset) $s = 0 $s = DllStructCreate("byte[10]") DllCall("kernel32.dll", "int", "ReadProcessMemory", "ptr", $hProcess, "ptr", DllStructGetData($MyHook, "HookAddress"), "ptr", DllStructGetPtr($s), "uint", 10, "uint*", 0) ConsoleWrite("remote hook: " & DllStructGetData($s, 1) & @CRLF) _WinAPI_CloseHandle($hProcess) ; test out the hooked function Sleep(10000) MsgBox(0 + 64, "Info", "Time is up. Please close any testapp message boxes, or it may crash.") ; unset the hook _HookApi_UnSet($MyHook) ; optionally free the injected library ; if the remote hooked message box is open when we do this, the remote app will crash ; leaving the injected library loaded will prevent the crash, and won't do any harm _FreeRemoteDll($hModule, $pid) MsgBox(0 + 64, "Unhooked", "MessageBoxW is now unhooked, and the dll has been unloaded.") DllCallbackFree($MyMsgBox) Func _MyCopyFile($LpFileOp) MemoryFuncCall("int", DllStructGetData($MyHook, "BridgePtr"), "hwnd", 0, _ "wstr", "This is the hook intercepting the MessageBoxW call, then calling the bridge to the real function." & @CRLF & _ "Here's what we got:" & @CRLF & @CRLF & _ "wstr", "Hooked Message Box", _ "uint", 48) EndFunc thx for your great support ! Edited January 10, 2009 by arcker -- Arck System _ Soon -- Ideas make everything "La critique est facile, l'art est difficile" Projects :[list] [*]Au3Service : Run your exe as service V3 / Updated 29/07/2013Â Get it Here [/list]
wraithdu Posted January 10, 2009 Author Posted January 10, 2009 I don't have time right now, but I'll look at it soon.
wraithdu Posted January 10, 2009 Author Posted January 10, 2009 (edited) Could you post the source for your DLL, and if you can figure it out, at what step exactly Explorer is crashing. From the name of your function, something doesn't look right. Both the SHFileOp hook function and the _Get function should only have 1 parameter, and so should be named at @4. Post the source and I'll look at it. Vista or XP? Edited January 10, 2009 by wraithdu
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now