Page 1 of 2

API hooking

Posted: Thu Jul 13, 2006 12:29 am
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)

Posted: Thu Jul 13, 2006 11:46 am
by thefool
Very nice!

Posted: Thu Jul 13, 2006 12:17 pm
by srod
Interesting...

How would a system wide hook differ? Would you need to place the code in a dll?

Posted: Thu Jul 13, 2006 1:04 pm
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.

Posted: Thu Jul 13, 2006 1:14 pm
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.

Posted: Thu Jul 13, 2006 5:06 pm
by Inf0Byt3
Yes, of course. I'll try to make an example.

Posted: Sat Aug 26, 2006 9:57 am
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.

Posted: Sat Aug 26, 2006 10:02 am
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.

Posted: Sat Aug 26, 2006 10:26 am
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)

Posted: Mon Aug 28, 2006 8:36 am
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 ?

Posted: Mon Aug 28, 2006 10:34 am
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?

Posted: Mon Aug 28, 2006 10:51 am
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.

Posted: Mon Aug 28, 2006 1:26 pm
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...

Posted: Mon Aug 28, 2006 1:41 pm
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?

Posted: Mon Aug 28, 2006 1:52 pm
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 :-) .