Hot Patching hook (32bits)

Share your advanced PureBasic knowledge/code with the community.
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 »

Excuse me, but this super subject give to me an idea :idea:

Believe you it's possible to modify the behaviour of the OLE32.dll, with this great code ????
ImageThe happiness is a road...
Not a destination
Opcode
Enthusiast
Enthusiast
Posts: 137
Joined: Thu Jul 18, 2013 4:58 am

Re: Hot Patching hook (32bits)

Post by Opcode »

Updated, as today even syscalls are hot-patchable.

Code: Select all

; Hot Patch Hooking

; --------------------------------------------------
;   Place Hook
;   $E9, $xx, $xx, $xx, $xx, $EB, $F9
; --------------------------------------------------

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

; --------------------------------------------------
;   Remove Hook
;   $CC, $CC, $CC, $CC, $CC, $8B, $FF
; --------------------------------------------------

Procedure RemoveHook(TargetFuncAddress.l)
  
  Protected.l Protection
  
  VirtualProtect_(TargetFuncAddress - 5, 7, #PAGE_EXECUTE_READWRITE, @Protection)
  
  PokeB(TargetFuncAddress - 5, $CC)
  PokeB(TargetFuncAddress - 4, $CC)
  PokeB(TargetFuncAddress - 3, $CC)
  PokeB(TargetFuncAddress - 2, $CC)
  PokeB(TargetFuncAddress - 1, $CC)
  PokeB(TargetFuncAddress + 0, $8B)
  PokeB(TargetFuncAddress + 1, $FF)
  
  VirtualProtect_(TargetFuncAddress - 5, 7, Protection, @Protection)
  
EndProcedure

; --------------------------------------------------
;   Check If Function Is Hot Patchable
; --------------------------------------------------

Procedure.b IsHotPatchable(TargetFuncAddress.l)
  
  Protected.q EntryPoint = PeekQ(TargetFuncAddress - 5)
  
  If FindString(Hex(EntryPoint), "FF8BCCCCCCCCCC", 3)
    ProcedureReturn #True
  EndIf
  
  ProcedureReturn #False
  
EndProcedure
Example:

Code: Select all

XIncludeFile "HotPatch.pbi"

Prototype.l ProtoMessageBox(hWnd.l, *lpText, *lpCaption, uType.l = 0)

Global CocoaMessageBox.ProtoMessageBox

; Hooked MessageBoxW
Procedure MsgBoxProxy(hWnd.l, *lpText, *lpCaption, uType.l = 0)
  
  Debug "MessageBoxW => " + "Title: " + PeekS(*lpCaption) + " Body: " + PeekS(*lpText)
  CocoaMessageBox(hWnd, *lpText, *lpCaption, uType)
  
EndProcedure

; Main
If OpenLibrary(0, "User32.dll")
  
  Address.l = GetFunction(0, "MessageBoxW")
  
  If IsHotPatchable(Address)
    CocoaMessageBox = Address + 2
    HotPatchHook(Address, @MsgBoxProxy())
    
    CallFunction(0, "MessageBoxW", 0, @"Body", @"Title", 0)
    CallFunction(0, "MessageBoxW", 0, @"bbbb", @"aaaa", 0)
    CallFunction(0, "MessageBoxW", 0, @"2222", @"1111", 0)
    
    RemoveHook(Address)
    CallFunction(0, "MessageBoxW", 0, @"dddd", @"cccc", 0)
  EndIf
EndIf
BarryG
Addict
Addict
Posts: 3292
Joined: Thu Apr 18, 2019 8:17 am

Re: Hot Patching hook (32bits)

Post by BarryG »

SFSxOI wrote: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?
Maybe it could stop false positives with virus-checkers? I will have to check this out.
User avatar
Mijikai
Addict
Addict
Posts: 1360
Joined: Sun Sep 11, 2016 2:17 pm

Re: Hot Patching hook (32bits)

Post by Mijikai »

BarryG wrote:
SFSxOI wrote: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?
Maybe it could stop false positives with virus-checkers? I will have to check this out.
This is often used to update a running program or to add in some logging functionality (statistics).
Hooks are also often used in the game modding scene or program automation.

With some minor changes the method shown here can be used to hook code without the need of pre existing 'spaces'.

Hooking itself will more likely increase false positives as it is also used in malware.
User avatar
chi
Addict
Addict
Posts: 1028
Joined: Sat May 05, 2007 5:31 pm
Location: Linz, Austria

Re: Hot Patching hook (32bits)

Post by chi »

@Opcode: IsHotPatchable() always returns 0 on my rig with Win7 x64 PB5.71(x86+x64) and WinXP x86 (VM) PB5.70(x86). Any ideas why?
Et cetera is my worst enemy
Opcode
Enthusiast
Enthusiast
Posts: 137
Joined: Thu Jul 18, 2013 4:58 am

Re: Hot Patching hook (32bits)

Post by Opcode »

BarryG wrote:
SFSxOI wrote: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?
Maybe it could stop false positives with virus-checkers? I will have to check this out.
From my personal experience, the best way to reduce false positives with PB compiled binary is to make sure you include version info (some antivirus scanners will flag it simply because it lacks version info) and then packing the binary with UPX (scrambles and masks signatures that antivirus scanners have flag otherwise). If I do neither, I'll get like 13/69 on VirusTotal. If I do both, depending on the code base I'm comping I can even achieve 0/69. I've noticed even just version info strings themselves can upset virus scanners. So you have to be creative and do a little trial and error.
chi wrote:@Opcode: IsHotPatchable() always returns 0 on my rig with Win7 x64 PB5.71(x86+x64) and WinXP x86 (VM) PB5.70(x86). Any ideas why?
I changed NOP to INT3 since on Windows 10 Pro x64 it wouldn't work (what's read on my machine shows "FF8BCCCCCCCCCC" instead of "FF8B9090909090").

You could try going back to using NOP.

Code: Select all

If FindString(Hex(EntryPoint), "FF8B9090909090", 3)
If that's the case you'll need to update the unhook function as well.

Code: Select all

  PokeB(TargetFuncAddress - 5, $90)
  PokeB(TargetFuncAddress - 4, $90)
  PokeB(TargetFuncAddress - 3, $90)
  PokeB(TargetFuncAddress - 2, $90)
  PokeB(TargetFuncAddress - 1, $90)
  PokeB(TargetFuncAddress + 0, $8B)
  PokeB(TargetFuncAddress + 1, $FF)
User avatar
chi
Addict
Addict
Posts: 1028
Joined: Sat May 05, 2007 5:31 pm
Location: Linz, Austria

Re: Hot Patching hook (32bits)

Post by chi »

@Opcode: Thanks, with "FF8B9090909090" I got it working on PB x86, but on PB x64 Hex(EntryPoint) returns "EC83489090909090". I think it's because the user32.dll doesn't load from "C:\Windows\System32\user32.dll" but from "C:\Windows\winsxs\amd64_microsoft-windows-user32_31bf3856ad364e35_6.1.7601.24524_none_2bdcf8519d2214ea\user32.dll" instead. Seems like MS patched the HotPatching feature?! The dll now contains "90 90 90 90 90 90 90 90 90 48 83 EC" instead of "90 90 90 90 90 8B FF"...
Et cetera is my worst enemy
Opcode
Enthusiast
Enthusiast
Posts: 137
Joined: Thu Jul 18, 2013 4:58 am

Re: Hot Patching hook (32bits)

Post by Opcode »

chi wrote:@Opcode: Thanks, with "FF8B9090909090" I got it working on PB x86, but on PB x64 Hex(EntryPoint) returns "EC83489090909090". I think it's because the user32.dll doesn't load from "C:\Windows\System32\user32.dll" but from "C:\Windows\winsxs\amd64_microsoft-windows-user32_31bf3856ad364e35_6.1.7601.24524_none_2bdcf8519d2214ea\user32.dll" instead. Seems like MS patched the HotPatching feature?! The dll now contains "90 90 90 90 90 90 90 90 90 48 83 EC" instead of "90 90 90 90 90 8B FF"...
It seems there's a lot of variance between builds of Windows in regards to if they use NOP or INT3. I will stick to the inline method of hooking (using a trampoline) as it still works flawlessly.

I posted updated code in this topic if you're interested: viewtopic.php?p=543517#p543517
User avatar
chi
Addict
Addict
Posts: 1028
Joined: Sat May 05, 2007 5:31 pm
Location: Linz, Austria

Re: Hot Patching hook (32bits)

Post by chi »

Opcode wrote:
chi wrote:@Opcode: Thanks, with "FF8B9090909090" I got it working on PB x86, but on PB x64 Hex(EntryPoint) returns "EC83489090909090". I think it's because the user32.dll doesn't load from "C:\Windows\System32\user32.dll" but from "C:\Windows\winsxs\amd64_microsoft-windows-user32_31bf3856ad364e35_6.1.7601.24524_none_2bdcf8519d2214ea\user32.dll" instead. Seems like MS patched the HotPatching feature?! The dll now contains "90 90 90 90 90 90 90 90 90 48 83 EC" instead of "90 90 90 90 90 8B FF"...
It seems there's a lot of variance between builds of Windows in regards to if they use NOP or INT3. I will stick to the inline method of hooking (using a trampoline) as it still works flawlessly.

I posted updated code in this topic if you're interested: viewtopic.php?p=543517#p543517
Thanks, going to check it out...

I was using Peyman's API_HookEngine Module for some time, but eventually switched to MinHook because it's much more reliable and has some unique features.
Et cetera is my worst enemy
User avatar
Mijikai
Addict
Addict
Posts: 1360
Joined: Sun Sep 11, 2016 2:17 pm

Re: Hot Patching hook (32bits)

Post by Mijikai »

chi wrote:@Opcode: Thanks, with "FF8B9090909090" I got it working on PB x86, but on PB x64 Hex(EntryPoint) returns "EC83489090909090". I think it's because the user32.dll doesn't load from "C:\Windows\System32\user32.dll" but from "C:\Windows\winsxs\amd64_microsoft-windows-user32_31bf3856ad364e35_6.1.7601.24524_none_2bdcf8519d2214ea\user32.dll" instead. Seems like MS patched the HotPatching feature?! The dll now contains "90 90 90 90 90 90 90 90 90 48 83 EC" instead of "90 90 90 90 90 8B FF"...
The easiest solution for a multiplatfom scenario is to hook the IAT instead of the function itself.
Post Reply