API hooking

Share your advanced PureBasic knowledge/code with the community.
Inf0Byt3
PureBasic Fanatic
PureBasic Fanatic
Posts: 2236
Joined: Fri Dec 09, 2005 12:15 pm
Location: Elbonia

API hooking

Post by Inf0Byt3 »

Just a small process-wide API hooking example. This could be easily modified to support system-wide hooking :D. Many thanks to Rings for translating it.

Code: Select all

;Translated  from C to Pure by Siegfried Rings, 2006

;API Hooking example for PureBasic 4
;(c) Sigfried Rings and Inf0Byt3
;Version 0.1
;>------------------------------------------------------------

;License: Freeware but with some limits: By using this library you agree
;NOT use it for creating malware, viruses, spyware, worms or rootkits
;or any program of this kind. If you do this I will find you, I'll kick your sorry ass,
;and cut your arms off so you can't code such crap in the future ;) 
;Now get back to coding!
 
Global Dim Backup.b(5)

Procedure MyMessagebox(lp0.l,lp1.l,lp2.l,lp3.l)

 Debug "This one was hooked :D"

 ProcedureReturn

EndProcedure
 
Procedure Hook(Libname.s,FuncName.s,NewFunctionAddress)
 
dwAddr =GetProcAddress_(GetModuleHandle_(LibName), FuncName)
OriginalAdress=dwAddr
Result=ReadProcessMemory_(GetCurrentProcess_(), dwAddr, @Backup(0), 6, @readbytes) ;save old Bytes
 
 
 Dim a.b(6)
 a(0)=$e9
 a(5)=$C3
 
 dwCalc = NewFunctionAddress - dwAddr - 5;	//((to)-(from)-5)
 
 CopyMemory(@dwCalc,@a(1),4)
 
 Result = WriteProcessMemory_(GetCurrentProcess_(), dwAddr, @a(0), 6, @written);
 
EndProcedure
 
Procedure UnHook(Libname.s,FuncName.s)
 
dwAddr = GetProcAddress_(GetModuleHandle_(LibName), FuncName)
Result= WriteProcessMemory_(GetCurrentProcess_(), dwAddr, @Backup(0), 6, @written);

EndProcedure
 
;Beavis, the test! 
 
MessageRequester("Info","Yes No Hook",0)
 
Hook("user32.dll", "MessageBoxA", @MyMessageBox());
MessageRequester("Info","Yes No Hook",0)

UnHook("user32.dll", "MessageBoxA")
MessageRequester("Info","This wasn't hooked",0)
Last edited by Inf0Byt3 on Mon Aug 28, 2006 1:39 pm, edited 1 time in total.
None are more hopelessly enslaved than those who falsely believe they are free. (Goethe)
thefool
Always Here
Always Here
Posts: 5875
Joined: Sat Aug 30, 2003 5:58 pm
Location: Denmark

Post by thefool »

Very nice!
srod
PureBasic Expert
PureBasic Expert
Posts: 10589
Joined: Wed Oct 29, 2003 4:35 pm
Location: Beyond the pale...

Post by srod »

Interesting...

How would a system wide hook differ? Would you need to place the code in a dll?
I may look like a mule, but I'm not a complete ass.
thefool
Always Here
Always Here
Posts: 5875
Joined: Sat Aug 30, 2003 5:58 pm
Location: Denmark

Post by thefool »

Srod; for a system wide hook you need to inject the hook in every running process. You can do it using a dll that will hook the api in the process it gets injected to.
srod
PureBasic Expert
PureBasic Expert
Posts: 10589
Joined: Wed Oct 29, 2003 4:35 pm
Location: Beyond the pale...

Post by srod »

In which case, is it possible to inject into a process which you have no control over; e.g. an application which you did not write?

Just out of interest.
I may look like a mule, but I'm not a complete ass.
Inf0Byt3
PureBasic Fanatic
PureBasic Fanatic
Posts: 2236
Joined: Fri Dec 09, 2005 12:15 pm
Location: Elbonia

Post by Inf0Byt3 »

Yes, of course. I'll try to make an example.
None are more hopelessly enslaved than those who falsely believe they are free. (Goethe)
newbie
Enthusiast
Enthusiast
Posts: 296
Joined: Tue Jul 29, 2003 5:47 pm
Location: FRANCE
Contact:

Post by newbie »

Interesting piece of code, thanks for sharing ;)
But I do not understand at all this snippet :

Code: Select all

Dim a.b(6)
a(0)=$e9
a(5)=$C3
What are these values ? Where do they come from ?
Basically you backup the current real API address, and then you overwrite it with your custom procedure address, I don't see the need of these values.
- Registered PB user -

Using PB 4.00
Inf0Byt3
PureBasic Fanatic
PureBasic Fanatic
Posts: 2236
Joined: Fri Dec 09, 2005 12:15 pm
Location: Elbonia

Post by Inf0Byt3 »

Well, i guess that they are the fist 2 bytes from the process's import table... If you wipe them out, the hooking doesn't work anymore. I am not sure this is the right explanation, because Rings made this code... I think he knows better.
None are more hopelessly enslaved than those who falsely believe they are free. (Goethe)
Edwin Knoppert
Addict
Addict
Posts: 1073
Joined: Fri Apr 25, 2003 11:13 pm
Location: Netherlands
Contact:

Post by Edwin Knoppert »

If anyone is that clever, make me a way to reposition the file offset used by LoadLibrary() to obtain the dll from an exe or memory.
I'm aware of the loadfrommem code on this forum but i whould like to know if a simple modification to the LoadLibrary() process could work as well.

Meaning, embed a dll in an exe, know the fileoffset in the exe to the dll and instruct the LL() stuff to read it from there, not from the 1st byte (exe)
User avatar
Rings
Moderator
Moderator
Posts: 1435
Joined: Sat Apr 26, 2003 1:11 am

Post by Rings »

newbie wrote:But I do not understand at all this snippet :

Code: Select all

Dim a.b(6)
a(0)=$e9
a(5)=$C3
What are these values ? Where do they come from ?
Basically you backup the current real API address, and then you overwrite it with your custom procedure address, I don't see the need of these values.
Inf0Byt3 wrote:Well, i guess that they are the fist 2 bytes from the process's import table... If you wipe them out, the hooking doesn't work anymore. I am not sure this is the right explanation, because Rings made this code... I think he knows better.
ok,
if a process calls the api-Procedure (for example MessageBoxEx@16 (same as Messagerequester(....) ), the first 5 Bytes in the Api-Procedure
are Codes to save some registers.
You can test severals Apis, and you get the same results:

Code: Select all

Api.s="MessageBoxA"
Lib.s="user32.dll"
l=LoadLibrary_(@Lib.s)
addr=GetProcAddress_(l,@Api)
If addr
 Debug "found at : " + Hex(addr)
 Debug "-----------------"
 Debug "Get first bytes now:"
 Debug ""
 Pointer =addr
 While p<5
  Pointer=  DisASMCommand(Pointer)
  p=Pointer-addr
  Debug GetDisASMString()    
 
 Wend
 Debug p
 FreeLibrary_(l)
EndIf

The trick to redirect is now to replace those 5 Bytes with a JMP- condition.
Regular, all JMP-Condition with FAR-Pointers have 6 Bytes.
Only the relative JMP-Condition has 5 Bytes.
The First Opcode for this relative JMP is then the magic $E9.
(see INTEL-x86 Books or just google for 'E9 and JMP'
the $C3 is only for saveness, its a Exception-Call. so if any error occurs,
your own exceptionhandler (maybe OnError) will be called.
This byte is not needed IMHO.

The Rest (not in the snippet described) is to make a Trampoline function, which then can also call the original function.....

@Edwin, Yes, way and idea seems not bad. Try OllyDebug and follow LoadLibraryA() and GetProcAddr(). (you will end in the kernel i guess)

Enough hacking for a monday then......all right ?
SPAMINATOR NR.1
DarkDragon
Addict
Addict
Posts: 2344
Joined: Mon Jun 02, 2003 9:16 am
Location: Germany
Contact:

Post by DarkDragon »

I have just one problem: Why isn't the function hooked? I mean: why can't I control the calls myself like in the remoteAPI lib? Why does the Messagerequester appear even if I hooked it?
bye,
Daniel
User avatar
Rings
Moderator
Moderator
Posts: 1435
Joined: Sat Apr 26, 2003 1:11 am

Post by Rings »

DarkDragon wrote:I have just one problem: Why isn't the function hooked? I mean: why can't I control the calls myself like in the remoteAPI lib? Why does the Messagerequester appear even if I hooked it?
what was wrong with that example ?
it works here as it should do.
SPAMINATOR NR.1
DarkDragon
Addict
Addict
Posts: 2344
Joined: Mon Jun 02, 2003 9:16 am
Location: Germany
Contact:

Post by DarkDragon »

Rings wrote:
DarkDragon wrote:I have just one problem: Why isn't the function hooked? I mean: why can't I control the calls myself like in the remoteAPI lib? Why does the Messagerequester appear even if I hooked it?
what was wrong with that example ?
it works here as it should do.
Ohh I see :lol: . I thought I have seen 3 MessageBoxes(The one which was hooked, too), but it were only 2. Sorry. I need new glasses...
bye,
Daniel
Inf0Byt3
PureBasic Fanatic
PureBasic Fanatic
Posts: 2236
Joined: Fri Dec 09, 2005 12:15 pm
Location: Elbonia

Post by Inf0Byt3 »

It really would be cool to make a system wide hook through a driver :? . I must download the DDK and try it. BTW, to start a driver I must start it like a normal service right?
None are more hopelessly enslaved than those who falsely believe they are free. (Goethe)
DarkDragon
Addict
Addict
Posts: 2344
Joined: Mon Jun 02, 2003 9:16 am
Location: Germany
Contact:

Post by DarkDragon »

Inf0Byt3 wrote:It really would be cool to make a system wide hook through a driver :? . I must download the DDK and try it. BTW, to start a driver I must start it like a normal service right?
Not the DDK, use assembler, like purefan did. Make a rootkit and call it pure-rootkit which replaces a system dll with someones own through only one PB command :-) .
bye,
Daniel
Post Reply