Hot Patching hook (32bits)

Share your advanced PureBasic knowledge/code with the community.
xorc1zt
Enthusiast
Enthusiast
Posts: 276
Joined: Sat Jul 09, 2011 7:57 am

Hot Patching hook (32bits)

Post by xorc1zt »

Since Windows XP, Most of the windows APIs are compiled with the hotpatch command who make inline hook more proper (no more trampolines).

Code: Select all

; hot patching hook
; xorc1zt

Procedure HotPatchHook(TargetFuncAddress.l, ProxyFuncAddress.l)
  ;E9 XX XX XX XX EB F9 
  Protection.w
  JumpOffset.l = ( ProxyFuncAddress - ( TargetFuncAddress-5 ) )-5
  VirtualProtect_(TargetFuncAddress-5, 7, #PAGE_EXECUTE_READWRITE, @Protection)
  PokeA( TargetFuncAddress-5, $E9 ) ;Far Jump
  PokeL( TargetFuncAddress-4, JumpOffset )
  PokeA( TargetFuncAddress,   $EB ) ;Short Jump
  PokeA( TargetFuncAddress+1, $F9 ) ; -5
  VirtualProtect_(TargetFuncAddress-5, 7, Protection, @Protection )
EndProcedure

Procedure RemoveHook(TargetFuncAddress.l)
  ;90 90 90 90 90 8B FF
  Protection.w
  VirtualProtect_(TargetFuncAddress-5, 7, #PAGE_EXECUTE_READWRITE, @Protection)
  PokeA( TargetFuncAddress-5, $90 )
  PokeA( TargetFuncAddress-4, $90 )
  PokeA( TargetFuncAddress-3, $90 )
  PokeA( TargetFuncAddress-2, $90 )
  PokeA( TargetFuncAddress-1, $90 )
  PokeA( TargetFuncAddress,   $8B )
  PokeA( TargetFuncAddress+1, $FF )
  VirtualProtect_(TargetFuncAddress-5, 7, Protection, @Protection )
EndProcedure
Example: hooking MessageBoxA

Code: Select all

Prototype.l ProtoMessageBox(Window.l, Body$, Title$, Flags.l = 0)
Global CocoaMessageBox.ProtoMessageBox

Procedure MsgBoxProxy(Window.l, Body$, Title$, Flags.l = 0)
  Debug "MessageBoxA: "+Str(Window)+", "+Body$+", "+Title$+", "+Str(Flags)
  CocoaMessageBox(Window, Body$, Title$, Flags)
EndProcedure

OpenLibrary(0, "User32.dll")
address.l = GetFunction(0, "MessageBoxA")
CocoaMessageBox = address+2
HotPatchHook(address,@MsgBoxProxy())
CallFunction(0,"MessageBoxA", 0, @"Body", @"Title", 0)
CallFunction(0,"MessageBoxA", 0, @"aaaa", @"bbbb", 0)
CallFunction(0,"MessageBoxA", 0, @"1111", @"2222", 0)
RemoveHook(address)
CallFunction(0,"MessageBoxA", 0, @"cccc", @"dddd", 0)
edit : use this to check if a function is hot patchable or not

Code: Select all

Procedure.b IsHotPatchable(TargetFuncAddress.l)
  op.q = PeekQ(TargetFuncAddress-5)
  If FindString(Hex(op), "FF8B9090909090", 3)
    ProcedureReturn #True
  EndIf
  ProcedureReturn #False
EndProcedure
User avatar
luis
Addict
Addict
Posts: 3876
Joined: Wed Aug 31, 2005 11:09 pm
Location: Italy

Re: Hot Patching hook (32bits)

Post by luis »

Weird in a nice way thanks !

So this can be useful to replace all the calls to a specific Windows api with your code ?

Didn't know about this thing. :)

I suppose this works only for the patching process, right ?
"Have you tried turning it off and on again ?"
A little PureBasic review
xorc1zt
Enthusiast
Enthusiast
Posts: 276
Joined: Sat Jul 09, 2011 7:57 am

Re: Hot Patching hook (32bits)

Post by xorc1zt »

luis wrote:I suppose this works only for the patching process, right ?
Yes, system wide hook must be done at kernel level with a driver
SFSxOI
Addict
Addict
Posts: 2970
Joined: Sat Dec 31, 2005 5:24 pm
Location: Where ya would never look.....

Re: Hot Patching hook (32bits)

Post by SFSxOI »

It is nice in a weird sort of way, but I don't know about a replacement for a call to the API. I mean, if you still need to declair a prototype of some sort and still call the API then why not just call the API in the first place instead of adding additional code that in the end does the same thing?

But... it is interesting. Thanks for the tip. :)
The advantage of a 64 bit operating system over a 32 bit operating system comes down to only being twice the headache.
xorc1zt
Enthusiast
Enthusiast
Posts: 276
Joined: Sat Jul 09, 2011 7:57 am

Re: Hot Patching hook (32bits)

Post by xorc1zt »

with api hooking you can do what you want into every process where you inject your code.

example with ShellAboutW (many apps use this function for the about box)

Code: Select all

; Proxy DLL
; xorc1zt

Prototype.l ProtoShellAbout(hWnd.l, szApp.s, szOtherStuff.s, hIcon.l)
Global oShellAbout.ProtoShellAbout
Global ShellAboutAddress.l


Procedure ShellAboutProxy(hWnd.l, szApp.s, szOtherStuff.s, hIcon.l)
  szApp = "**** xorc1zt ****"
  szOtherStuff = "Hello from proxy.dll"
  oShellAbout(hWnd, szApp, szOtherStuff, hIcon)
EndProcedure

Procedure HotPatchHook(TargetFuncAddress.l, ProxyFuncAddress.l)
  ;E9 XX XX XX XX EB F9
  Protection.w
  JumpOffset.l = ( ProxyFuncAddress - ( TargetFuncAddress-5 ) )-5
  VirtualProtect_(TargetFuncAddress-5, 7, #PAGE_EXECUTE_READWRITE, @Protection)
  PokeA( TargetFuncAddress-5, $E9 ) ;Far Jump
  PokeL( TargetFuncAddress-4, JumpOffset )
  PokeA( TargetFuncAddress,   $EB ) ;Short Jump
  PokeA( TargetFuncAddress+1, $F9 ) ; -5
  VirtualProtect_(TargetFuncAddress-5, 7, Protection, @Protection )
EndProcedure

Procedure RemoveHook(TargetFuncAddress.l)
  ;90 90 90 90 90 8B FF
  Protection.w
  VirtualProtect_(TargetFuncAddress-5, 7, #PAGE_EXECUTE_READWRITE, @Protection)
  PokeA( TargetFuncAddress-5, $90 )
  PokeA( TargetFuncAddress-4, $90 )
  PokeA( TargetFuncAddress-3, $90 )
  PokeA( TargetFuncAddress-2, $90 )
  PokeA( TargetFuncAddress-1, $90 )
  PokeA( TargetFuncAddress,   $8B )
  PokeA( TargetFuncAddress+1, $FF )
  VirtualProtect_(TargetFuncAddress-5, 7, Protection, @Protection )
EndProcedure


ProcedureDLL AttachProcess(Instance)
  OpenLibrary(0, "Shell32.dll")
  
  CompilerIf #PB_Compiler_Unicode
    ShellAboutAddress = GetFunction(0, "ShellAboutW")
    oShellAbout = ShellAboutAddress+2
    HotPatchHook(ShellAboutAddress,@ShellAboutProxy())
  CompilerElse
    ShellAboutAddress = GetFunction(0, "ShellAboutA")
    oShellAbout = ShellAboutAddress+2
    HotPatchHook(ShellAboutAddress,@ShellAboutProxy())
  CompilerEndIf
EndProcedure
  
ProcedureDLL DetachProcess(Instance)
  RemoveHook(ShellAboutAddress)
EndProcedure
  
ProcedureDLL AttachThread(Instance) 
EndProcedure
  
ProcedureDLL DetachThread(Instance)
EndProcedure
this dll hook ShellAboutW (or ShellAboutA if ASCII mode)

Code: Select all

ShellAboutAddress = GetFunction(0, "ShellAboutW")
oShellAbout = ShellAboutAddress+2
HotPatchHook(ShellAboutAddress,@ShellAboutProxy())
Now, Every time the process call ShellAboutW, the call will be detoured to my function (ShellAboutProxy) who modify the arguments szApp and szOtherStuff

Code: Select all

Procedure ShellAboutProxy(hWnd.l, szApp.s, szOtherStuff.s, hIcon.l)
  szApp = "**** xorc1zt ****"
  szOtherStuff = "Hello from proxy.dll"
  oShellAbout(hWnd, szApp, szOtherStuff, hIcon)
EndProcedure
Try to inject this dll into notepad.exe and go to "?" then "About Notepad".
User avatar
Kwai chang caine
Always Here
Always Here
Posts: 5342
Joined: Sun Nov 05, 2006 11:42 pm
Location: Lyon - France

Re: Hot Patching hook (32bits)

Post by Kwai chang caine »

That's look great, but i have not understand how use it :oops:

1/ I create a DLL with the first code
2/ I name it Inject.dll

So after where i put the DLL ???
How i call her ???

Can you give to me more explanation, please :cry:
ImageThe happiness is a road...
Not a destination
User avatar
luis
Addict
Addict
Posts: 3876
Joined: Wed Aug 31, 2005 11:09 pm
Location: Italy

Re: Hot Patching hook (32bits)

Post by luis »

@Kwaï chang caïne

I suppose the easier way should be using a DLL injector.

http://warpzone.se/uniject.php

I never used it, it's the first I found, I suppose it should work.

Anyway search for "dll injection" and you will find a lot of info.
"Have you tried turning it off and on again ?"
A little PureBasic review
User avatar
Kwai chang caine
Always Here
Always Here
Posts: 5342
Joined: Sun Nov 05, 2006 11:42 pm
Location: Lyon - France

Re: Hot Patching hook (32bits)

Post by Kwai chang caine »

Ok thanks LUIS 8)
ImageThe happiness is a road...
Not a destination
SFSxOI
Addict
Addict
Posts: 2970
Joined: Sat Dec 31, 2005 5:24 pm
Location: Where ya would never look.....

Re: Hot Patching hook (32bits)

Post by SFSxOI »

luis wrote:@Kwaï chang caïne

I suppose the easier way should be using a DLL injector.

http://warpzone.se/uniject.php

I never used it, it's the first I found, I suppose it should work.

Anyway search for "dll injection" and you will find a lot of info.
If you just wanted a .dll injector, here is one i've used for a long time for general .dll injection (and in a few games for testing :) )

Code: Select all

DisableDebugger

Prototype.i PFNCreateToolhelp32Snapshot(dwFlags.i, th32ProcessID.i) ;
Prototype.b PFNProcess32First(hSnapshot.i, *lppe.PROCESSENTRY32) ;
Prototype.b PFNProcess32Next(hSnapshot.i, *lppe.PROCESSENTRY32) ;

Procedure GetPidByName(p_name$) 
    Protected hDLL.i, process_name$ 
    Protected PEntry.PROCESSENTRY32, hTool32.i 
    Protected pCreateToolhelp32Snapshot.PFNCreateToolhelp32Snapshot 
    Protected pProcess32First.PFNProcess32First 
    Protected pProcess32Next.PFNProcess32Next 
    Protected pid.i 
    
    hDLL = OpenLibrary(#PB_Any,"kernel32.dll") 
    
    If hDLL 
        pCreateToolhelp32Snapshot = GetFunction(hDLL,"CreateToolhelp32Snapshot") 
        pProcess32First = GetFunction(hDLL,"Process32First") 
        pProcess32Next = GetFunction(hDLL,"Process32Next") 
    Else 
        ProcedureReturn 0 
    EndIf 
    
    PEntry\dwSize = SizeOf(PROCESSENTRY32) 
    hTool32 = pCreateToolhelp32Snapshot(#TH32CS_SNAPPROCESS, 0) 
    pProcess32First(hTool32, @PEntry) 
    process_name$ = Space(#MAX_PATH) 
    CopyMemory(@PEntry\szExeFile,@process_name$,#MAX_PATH) 
    
    If  UCase(process_name$) = UCase(p_name$) 
        ProcedureReturn PEntry\th32ProcessID 
    EndIf 
    
    While pProcess32Next(hTool32, @PEntry) > 0 
        process_name$ = Space(#MAX_PATH) 
        CopyMemory(@PEntry\szExeFile,@process_name$,#MAX_PATH) 
        
        If  UCase(process_name$) = UCase(p_name$) 
            ProcedureReturn PEntry\th32ProcessID 
        EndIf 
    
    Wend 
    
    CloseLibrary(hDLL) 
    
    ProcedureReturn 0 
EndProcedure

Procedure InjectLibA(dwProcessId.i, pszLibFile$) 
  hProcess.i 
  hThread.i 
  lzLibFileRemote.i 
  lSize.i 
  endSize.i 
  lsThreadRtn.i 
  
  hProcess = OpenProcess_(#PROCESS_QUERY_INFORMATION | #PROCESS_CREATE_THREAD | #PROCESS_VM_OPERATION | #PROCESS_VM_WRITE, 0, dwProcessId) 
  
  If hProcess = 0 : Goto ErrHandle : EndIf 
  lSize = 1 + Len(pszLibFile$) 
  endSize = lSize 
  
  lzLibFileRemote = VirtualAllocEx_(hProcess, #Null, endSize, #MEM_COMMIT, #PAGE_READWRITE) 
  
  If lzLibFileRemote = 0 : Goto ErrHandle : EndIf 
  
  If (WriteProcessMemory_(hProcess, lzLibFileRemote, pszLibFile$, endSize, #Null) = 0) : Goto ErrHandle : EndIf 
  
  OpenLibrary(0, "Kernel32.dll") : lsThreadRtn = GetFunction(0, "LoadLibraryA") : CloseLibrary(0) 
  
  If lsThreadRtn = 0 : Goto ErrHandle : EndIf 
  
  hThread = CreateRemoteThread_(hProcess, #Null, #Null, lsThreadRtn, lzLibFileRemote, #Null, #Null) 
  
  If (hThread = 0) : Goto ErrHandle : EndIf 
  
  WaitForSingleObject_(hThread, #INFINITE) 
  
  If lzLibFileRemote<>0 
    VirtualFreeEx_(hProcess, lzLibFileRemote, 0, #MEM_RELEASE) 
    MessageRequester("Inject Status", "Injection Suceeded", 0)
    Else
    VirtualFreeEx_(hProcess, lzLibFileRemote, 0, #MEM_RELEASE) 
    MessageRequester("Inject Status", "Injection Failed !!!", 0)
  EndIf 
  End 
  
  ErrHandle: 
      CloseHandle_(hThread) 
      CloseHandle_(hProcess)
      MessageRequester("Inject Status", "Injection Failed !!!", 0) 
EndProcedure

dll_dir$ = GetCurrentDirectory() + "mydll.dll" ; dll is in dir with injector
Input_proc$ = "target_exe.exe"
val_pid.i = GetPidByName(Input_proc$)
Delay(10)
File_dll$ = dll_dir$
Delay(10)
InjectLibA(val_pid, dll_dir$)
The above code is from somewhere in the forum, can't remember who originated it or if it was a collective sum of methods and ideas from possibly here > http://www.purebasic.fr/english/viewtop ... 12&t=16676 - but if this code belongs to you please let me know so that I can credit it properly, and until then the credit goes to the original poster.
Last edited by SFSxOI on Fri Sep 02, 2011 10:19 pm, edited 2 times in total.
The advantage of a 64 bit operating system over a 32 bit operating system comes down to only being twice the headache.
SFSxOI
Addict
Addict
Posts: 2970
Joined: Sat Dec 31, 2005 5:24 pm
Location: Where ya would never look.....

Re: Hot Patching hook (32bits)

Post by SFSxOI »

I can see its use for other things, already got some ideas in mind so this is a nice addition to the arsenel of useful tricks and tips.

Does leaving this "detour" return what ever you used it on to its original 'before hook' state. Like the MS Detours use was able to do?
The advantage of a 64 bit operating system over a 32 bit operating system comes down to only being twice the headache.
xorc1zt
Enthusiast
Enthusiast
Posts: 276
Joined: Sat Jul 09, 2011 7:57 am

Re: Hot Patching hook (32bits)

Post by xorc1zt »

another example is to hook CreateProcessW for a antivirus or prevent user to launch forbidden softwares.

speudo code

Code: Select all

Procedure MyCreateProcessW( lpApplicationName.s, ...)
	If FindString(lpApplicationName, "notepad.exe", 1)
		MessageRequester("Denied!", "You are not allowed to use notepad", #PB_MessageRequester_Ok)
		ProcedureReturn
	EndIf
	oCreateProcessW( lpApplicationName, ...	)
EndProcedure
SFSxOI wrote:I can see its use for other things, already got some ideas in mind so this is a nice addition to the arsenel of useful tricks and tips.

Does leaving this "detour" return what ever you used it on to its original 'before hook' state. Like the MS Detours use was able to do?
do you mean using ProcedureReturn originalfunc(...) ?

Like this

Code: Select all

Procedure MsgBoxProxy(Window.l, Body$, Title$, Flags.l = 0)
  ; stuff
  ProcedureReturn CocoaMessageBox(Window, Body$, Title$, Flags) ; return value of the original MessageBoxA
EndProcedure
SFSxOI
Addict
Addict
Posts: 2970
Joined: Sat Dec 31, 2005 5:24 pm
Location: Where ya would never look.....

Re: Hot Patching hook (32bits)

Post by SFSxOI »

@xorc1zt

Never mind, got it figured out now. My thoughts were confusing this with something else similar we use at work. Thanks for posting :)
The advantage of a 64 bit operating system over a 32 bit operating system comes down to only being twice the headache.
User avatar
Kwai chang caine
Always Here
Always Here
Posts: 5342
Joined: Sun Nov 05, 2006 11:42 pm
Location: Lyon - France

Re: Hot Patching hook (32bits)

Post by Kwai chang caine »

Thanks a lot SFSxOI 8)
Just another question.
It's surely more careful to make a copy of the DLL before, no ?? :D
In the case of it's impossible to return back :(
ImageThe happiness is a road...
Not a destination
SFSxOI
Addict
Addict
Posts: 2970
Joined: Sat Dec 31, 2005 5:24 pm
Location: Where ya would never look.....

Re: Hot Patching hook (32bits)

Post by SFSxOI »

Kwaï chang caïne wrote:Thanks a lot SFSxOI 8)
Just another question.
It's surely more careful to make a copy of the DLL before, no ?? :D
In the case of it's impossible to return back :(
It doesn't actually change the physical process file its self, it only does it in memory. The physical file is still intact in its original form and unchanged. Your injecting a .dll into a process in memory, and the code in the .dll you inject changes what ever is in memory of the process that your .dll was designed to affect. So there is nothing to worry about returning back to, when the process ends so does the injected .dll effect on the process and the original file of the process is unchanged.

It is possible to create a .dll to inject that does make changes to the physical process file, but unless you intentionally create or use such an injected .dll then there is nothing to worry about.
The advantage of a 64 bit operating system over a 32 bit operating system comes down to only being twice the headache.
User avatar
Kwai chang caine
Always Here
Always Here
Posts: 5342
Joined: Sun Nov 05, 2006 11:42 pm
Location: Lyon - France

Re: Hot Patching hook (32bits)

Post by Kwai chang caine »

Thanks a lot SFSxOI for your good explanation 8)

This subject is really interesting, but like sometime KCC play with the fire, and try code without understand :oops:
Image
In fact, KCC want always playing with the big, but sometime he thinks a little bit before :mrgreen:

Cool !!!! , only in memory, this story of DLL injecting it's really very GREAT :shock:

Thanks again at xorc1zt and you, and have a good day 8)
ImageThe happiness is a road...
Not a destination
Post Reply