Page 1 of 1

Darky - PureBasic API Hooking Library

Posted: Wed Aug 18, 2010 3:29 am
by Darky
detour_lib.pbi

Code: Select all

Structure Hook_Data
  OriBytes.b[6]
  NewBytes.b[6]
  ProcAddr.l
EndStructure

#CURRENT_LIB_VERSION = "1.0"
#CURRENT_LIB_NAME = "Darky - PureBasic API Hooking Library"

Global Dim Hooks.Hook_Data(0)
Global bFirstTime.b = #True

Procedure.i Setup_Hook(Libname.s, FuncName.s, RedFunAddr.l)
If bFirstTime = #False
  ReDim Hooks(ArraySize(Hooks()) + 1)
EndIf
bFirstTime = #False
  
dwAddr = GetProcAddress_(GetModuleHandle_(LibName), FuncName) ;Get the Function Memory Address
OriginalAdress = dwAddr
Hooks(ArraySize(Hooks()))\ProcAddr = dwAddr ;This for Fast Unhooking

If OriginalAdress > 0
  ;Save the old api Bytes
  If ReadProcessMemory_(-1, dwAddr, @Hooks(ArraySize(Hooks()))\OriBytes[0], 6, 0)
    
    Dim a.b(6)
    a(0)=$e9 ;JMP
    a(5)=$C3 ;RET
    
    dwCalc = RedFunAddr - dwAddr - 5; 

    CopyMemory(@dwCalc, @a(1), 4)
    
    ;Save the New Bytes
    CopyMemory(@a(0), @Hooks(ArraySize(Hooks()))\NewBytes[0], 6)
    ;Get ready for new hook
    
    If WriteProcessMemory_(-1, dwAddr, @a(0), 6, 0)
      ProcedureReturn ArraySize(Hooks())
    EndIf
  EndIf
EndIf
   
ProcedureReturn - 1 ;Bad didn't work
EndProcedure

Procedure.b Fast_ReHook(hookIndex.i)
  ProcedureReturn WriteProcessMemory_(-1, Hooks(hookIndex)\ProcAddr, @Hooks(hookIndex)\NewBytes[0], 6, 0)
EndProcedure

Procedure.b ReHook(hookIndex.i, LibName.s, FuncName.s)
  dwAddr = GetProcAddress_(GetModuleHandle_(LibName), FuncName) ;Get the Memory Address
  ProcedureReturn WriteProcessMemory_(-1, dwAddr, @Hooks(hookIndex)\NewBytes[0], 6, 0)
EndProcedure

Procedure.b Fast_UnHook(hookIndex.i)
  ProcedureReturn WriteProcessMemory_(-1, Hooks(hookIndex)\ProcAddr, @Hooks(hookIndex)\OriBytes[0], 6, 0)
EndProcedure

Procedure.b UnHook(hookIndex.i, LibName.s, FuncName.s)
  dwAddr = GetProcAddress_(GetModuleHandle_(LibName), FuncName) ;Get the Memory Address
  ProcedureReturn WriteProcessMemory_(-1, dwAddr, @Hooks(hookIndex)\OriBytes[0], 6, 0) ;Restore Old Bytes
EndProcedure 
Example:

Code: Select all

Procedure.l RedMsgboxA(hWnd.i, lpText.s, lpCaption.s, uType.i)
  Fast_UnHook(0)
  MessageBox_(0, "Hooked" ,"me", 0)
  Fast_ReHook(0)
  ProcedureReturn 1
EndProcedure

Debug Setup_Hook("User32.dll", "MessageBoxA", @RedMsgboxA())
MessageBox_(0, "123", "456", 0) 
Note: Setup_Hook returns the current hook index.

Re: Darky - PureBasic API Hooking Library

Posted: Wed Aug 18, 2010 12:58 pm
by Rescator
Same issues as the other hook post.

This only works for the Ascii calls, not the Unicode "W" calls.

Secondly this only works within the current process, starting a second process while the first is running and the second behaves just like normal, no hooking shown.

Thirdly, it's a good thing it doesn't work on other processes etc. Because in the example you forgot to restore the original.
Not only that but the unhook routines, seem odd, for some reason they re-read the proc address instead of simply using the ProcAddr in the array.
And there really should be a unhook all that one could call at the end of the program.


Then again, since this only works in the current process it's just simpler to use a macro anyway. *laughs*

The way hooks are easily done is making a dll, putting that dll in the program folder. Obviously that dll need to replace/pass through ALL functions of the original dll.
The other way is a Loader (or injector).
A third would be a Trainer but not really intended for this kind of hooking.

The proper way to do this is a Debugger hook, and it must be running as admin and it must have write to process privileges etc. (I'm sure some of the folks around here knows how to properly do this stuff?)

But I wouldn't be surprised if your code works as intended on Win 9x though.

Re: Darky - PureBasic API Hooking Library

Posted: Wed Aug 18, 2010 9:46 pm
by Darky
This only works for the Ascii calls, not the Unicode "W" calls.
Unicode calls work fine for me.
Thirdly, it's a good thing it doesn't work on other processes etc. Because in the example you forgot to restore the original.
I do restore the original bytes by using the Fast_UnHook or the UnHook Procedure:
Procedure.l RedMsgboxA(hWnd.i, lpText.s, lpCaption.s, uType.i)
Fast_UnHook(0)
MessageBox_(0, "Hooked" ,"me", 0)
Fast_ReHook(0)
ProcedureReturn 1
EndProcedure
Then again, since this only works in the current process it's just simpler to use a macro anyway. *laughs*
The way hooks are easily done is making a dll, putting that dll in the program folder. Obviously that dll need to replace/pass through ALL functions of the original dll.
This code is to be used inside an dll not out.
But I wouldn't be surprised if your code works as intended on Win 9x though.
Working at 100% on Windows Xp/Vista/7 - 32bit.

Re: Darky - PureBasic API Hooking Library

Posted: Wed Aug 18, 2010 9:57 pm
by Thorium
Darky wrote: Working at 100% on Windows Xp/Vista/7 - 32bit.
It doesnt work at 100%.
Same problem than the other inline hook example: It misses a disassembler to verify code integrity. It will lead to crashes if used on functions that start with instructions that dont align to the 5 or 6 byte border. Which is very uncommen in WinAPI, only a few functions like DbgBreakPoint are that way. But it's actualy common in none WinAPI DLLs.

Re: Darky - PureBasic API Hooking Library

Posted: Thu Aug 26, 2010 7:22 pm
by registrymechanic22
Darky wrote:
does not work on Win_64 :(
what to do to fix this?

Re: Darky - PureBasic API Hooking Library

Posted: Thu Aug 26, 2010 9:03 pm
by Thorium
registrymechanic22 wrote:
Darky wrote:
does not work on Win_64 :(
what to do to fix this?
Use integer as addresses. I am not sure if the assembler instructions have to be changed, since jmp is relativ it should also work on x64.

Re: Darky - PureBasic API Hooking Library

Posted: Fri Aug 27, 2010 9:00 am
by DarkDragon
Rescator wrote:Then again, since this only works in the current process it's just simpler to use a macro anyway. *laughs*
This doesn't work in all cases. Just look at the old v2synth libraries. There you had to hook a directshow audio routine behind the lib to render the v2 music to a file. This can't be done with PB macros. :wink: