Hello,

since under 9x systems CreateRemoteThread is not available I was wondering how API hooking can be accomplished. I have a sample application that *should* work on 9x boxes (not having a 9x system I really can't verify it) that seems to overwrite the first 5 bytes of an API to hook with a jump to a function exported by a user coded DLL.
From the little documentation and from the source code it seems that placing a jmp at the API head is all that is needed to hook that API system-wide. What I can't understand is why this should accomplish a system-wide hook. Doesn't each running process have an own copy of system DLL in memory???? I mean, I can't see why modifying a copy in memory of a system DLL running inside a single process memory space should have any impact on the "copies" of the same system DLL running in other processes' memory space.


yaa
Posted on 2004-02-02 08:23:16 by yaa
No, in fact under win9x a process does NOT have it's own copy of, say kernel32.dll, user32.dll, etc. Hence, patching the kernel runtime will insert systemwide api-hooks.

Fake
Posted on 2004-02-02 15:53:40 by Fake51
Win9x is a horrible hack.

Rather than mapping views of DLLs individuall in each process, the win9x memory space is split in the "process space" and the "shared space". 16bit windows programs, DLLs, and the kernel is located in the "shared space", which is mapped into all processes - that's why it's so easy to wreak havok (and do shared DLL hooking) on win9x.

I can't remember if it does Copy-On-Write for the shared space, though... I think it does, so you'll probably have to turn that off first. Shouldn't really be that bad, considering the amount of ring0 hacks there has been for 9x (and notice that those r0 hacks usually won't work if you test them under vmware or similar).
Posted on 2004-02-02 16:46:23 by f0dder
see y0da
Posted on 2004-02-02 18:57:06 by comrade
There is no Copy-On-Write in Windows 9x.
Posted on 2004-02-03 06:06:50 by Opcode
Posted on 2004-02-03 06:10:01 by Opcode
Hrm, no COW on 9x at all? While you may not be able to specify COW yourself for your own pages, I can hardly believe there's no COW at all, as this would that page sharing between multiple instances of the same executable cannot be done...
Posted on 2004-02-03 06:52:21 by f0dder
There is copy on write, but it is not used with system DLLs. If you want to patch user DLLs, you better do it in Ring0. It could be quite tricky.
Posted on 2004-02-03 12:30:58 by Sephiroth3
What about injection on 9x .... having no CreateRemoteThread are hooks the only other possibility???

yaa
Posted on 2004-02-03 12:34:53 by yaa
acording to msdn CreateRemoteThread is available in windows 9x unless there is some other reason why it can't be used.
Posted on 2004-02-03 14:35:49 by ENF
CreateRemoteThread:

Client: Included in Windows XP, Windows 2000 Professional, and Windows NT Workstation.
Server: Included in Windows Server 2003, Windows 2000 Server, and Windows NT Server.


... but see elicz' work perhaps.
Posted on 2004-02-03 14:40:23 by f0dder
Yes, Elicz does have CreateRemoteThread alternative for 9x, including virtualallocex
Posted on 2004-02-03 15:41:26 by comrade
For 9x systems global api hooking is easy, here are steps
1. copy your code to shared region, be carefull not to use any fixed offsets
2. unprotect memory page where is the entrypoint of API you want to hook
3. save first 5 bytes of API proc somewhere, and replace them by "jmp my_shared_code"
4. after your code does the job, execute first 5 bytes (or more depending what instructions were there, and would 5 bytes were ending in middle of instruction or not), and then jump to original code
For example you can check out yoda's example.
And you can do all this without ring0 messing
Posted on 2004-02-03 17:15:58 by Mikky

And you can do all this without ring0 messing

But you'd have to do a VxdCall0 to unprotect the pages, right?
Posted on 2004-02-03 17:25:11 by f0dder
Since we're on the subject of hacks anyway: there's a good old 9x hack that allows you to write to the shared memory of system dll's without doing any ring0 hacks. So actually you don't have to unprotect the pages. However, the hack is a hack and shouldn't be used - the hack is different depending on versions of the kernel32.dll, which is reason enough to leave it alone.

Fake
Posted on 2004-02-04 03:40:29 by Fake51
I'm always learning. But I want to know if win9x REALLY have COW mechanism, because I NEVER found this information in any
book that I'd read. If is not used in system DLLs, where it is used????
Posted on 2004-02-04 05:19:38 by Opcode
Well, if it doesn't have (some for of) COW, it would be impossible to share code/data pages between processes. If you want to investigate this, create an app that shows the physical addresses used by a bunch of it's code pages - you'll probably need ring0 for this, but then this is win9x so that's not too troublesome. Fire up a bunch of instances of the app, and it should (hopefully) show the same physical addresses for the same code pages, if they haven't been modified.
Posted on 2004-02-04 07:24:08 by f0dder
Yep, Windows 9X does copy on write on modules loaded at a low address (<0x80000000). It just can't do it for modules loaded at a high address, since it doesn't change these pages when switching processes.
Posted on 2004-02-04 11:58:01 by Sephiroth3
And all DLLs are loaded above 0x80000000, right? Because of the whole ugly shared/global deal...
Posted on 2004-02-04 12:23:17 by f0dder
And all DLLs are loaded above 0x80000000, right?



Using ListDLLs V2.23 - DLL lister for Win9x/NT created by Mark Russinovich
at http://www.sysinternals.com
I got this in Windows 98 (sample)




C:\WINDOWS\EXPLORER.EXE pid: FFFF7AC3
Base Size Version Path
0x015e0000 0x22000 C:\ARQUIVOS DE PROGRAMAS\BRAZIP\SZSHELL.DLL
0x01280000 0x29000 C:\ARQUIVOS DE PROGRAMAS\WINRAR\RAREXT.DLL
0x015a0000 0x31000 2.01.0000.0000 C:\ARQUIVOS DE PROGRAMAS\WINACE\ARCEXT.DLL
0x023e0000 0xdb000 2.02.0000.0000 C:\ARQUIVOS DE PROGRAMAS\WINACE\ACE.DLL
0x22680000 0x14000 5.04.0007.3800 C:\ARQUIVOS DE PROGRAMAS\ICQ\ICQSHEXT.DLL



Look at Base Column, there are base < 0x80000000.
Then, NOT ALL DLLs are loaded above 0x80000000 address.
Posted on 2004-02-04 13:22:07 by Opcode