• RSS
  • Twitter
  • FaceBook

Security Forums

Log in

FAQ | Search | Usergroups | Profile | Register | RSS | Posting Guidelines | Recent Posts

Win9x/2k API hooking

Users browsing this topic:0 Security Fans, 0 Stealth Security Fans
Registered Security Fans: None
Goto page 1, 2, 3  Next
Post new topic   Reply to topic   Printer-friendly version    Networking/Security Forums Index -> Programming and More

View previous topic :: View next topic  
Author Message
capi
SF Senior Mod
SF Senior Mod


Joined: 21 Sep 2003
Posts: 16777097
Location: Portugal

Offline

PostPosted: Thu Jan 29, 2004 3:42 am    Post subject: Win9x/2k API hooking Reply with quote

(added a posteriori: This turned out to be a bit longer than it might have to, I guess I took the oportunity to try and teach a little something new to anyone who doesn't know this already, as well as ask my question)

Ok, as the topic suggests, I'm looking for suggestions on how to load a DLL's code segment into shared address space (i.e. > 7FFFFFFFh) in Win9x.

The reason I want to do this is I'm implementing some Win32 API hooking by means of patching the actual API itself in shared memory space - i.e. changing the first bytes of OpenProcess() or whatever to jump to a "hook" function that processes the arguments before optionally calling the real API through a trampoline that holds the original 5 bytes, - plus any aditional bytes needed to complete the original instructions (instructions vary in size on x86 architecture) - followed by a jump to the byte after the copied instructions on the real API.

Of course the kernel32.dll address space is write protected and VirtualProtect will refuse to change it, but that can be bypassed by calling the ring 0 VMM service _PageModifyPermissions from a VxD (or using kernel32's VxDCall from ring 3, which I plan to do on a later version to do away with the VxD). Calling _PageModifyPermissions is actually just what VirtualProtect does, after having verified the parameters and done a little math on them, of course.

The problem is getting the hook and trampoline functions on every process' page table. I've pretty much got it working - using SetWindowsHookEx with some do-nothing message hook allows me to load the DLL into most process' address space, while some messing around with the DLL image base (basically choosing a weird one so chances are it's unoccupied) made it possible to have it mapped to the same linear address on all of them. Also an aditional detail was having to make the DLL's code segment shared, so that it uses the same physical pages on all processes that link to it, instead of having a bunch of different copies - this is necessary since I create the trampolines on the fly, as stated above.

Ok, I said I pretty much had it working. The problem now is twofold:
  • a) the SetWindowsHookEx may not attach the DLL code to all processes. The function presumably attaches the DLL to a process when GetMessage() is about to return (haven't checked for sure yet but doesn't really matter as there's still problem b), meaning that processes that never call it or are still blocked inside it since before SetWindowsHookEx was called won't have the DLL ready if another thread makes a call to an altered API, thus resulting in the API jumping to a non-paged area.
  • b) regardless of a), there is another problem and it resides on new processes that launch after the hook is in place. Yes, the DLL will attach to them as well (presumably only right before it receives the first message, if it ever receives one), but before it attaches there's still plenty of time for the process to call one of the altered APIs - say CreateFile, OpenProcess or, why not, even Sleep comes in handy. This will result, as a), in an ugly page fault as the API jumps to an invalid address, leading to a general protection fault.

Now, the most obvious solution would be to have the DLL loaded on shared address space (above 7FFFFFFFh), where any process should be able to find it, regardless of if it's loaded or not - Win9x maps every page above 2Gb to the same physical page on all processes. How to accomplish this, though?

My first thought would be editing the DLL's PE header and changing the base address manually (I wouldn't need to do it manually if Borland's linker allowed image bases above 7FFFFFFFh, but it apparently doesn't like them). This is probably what I'll try next, but I was curious if anyone else had a suggestion on this, or perhaps another way of attaching the DLL that works better.

Another solution for attaching the DLL could have been using CreateToolhelp32Snapshot, then using CreateRemoteThread on each process in the list to load a piece of code that calls LoadLibrary, then making sure we hooked CreateProcess and do the same for every new process before we allow it to run. But this won't work, sadly CreateRemoteThread only exists in Windows NT. Also it would be kind of unwieldy and bring in problems of synchronization (new processes could be spawned after we took our snapshot and before we hooked CreateProcess).

Yet another solution I can think of is the IAT patching approach. This could be somewhat more elegant as there's no need to be using ring 0 code to smash into kernel memory, but has a few disadvantages. First, it will only work for processes that we manage to attach ourselves into (since we're not targeting the central point, the API itself). Second, it will only start to work after we've attached ourselves, so it suffers from a variation of problem b) above: although it won't generate a GPF, it will let the newly spawned process get away with calling whatever APIs it wants without us knowing until we have had the time to attach ourselves. This could be fixed by hooking CreateProcess and making sure we attach to the newly created process before allowing it to resume execution (although there are other APIs that spawn processes, we would have to hook them as well). Also, a process could use less standard methods to get the address of an API. GetProcAddress is an example, but this could be resolved simply by making sure we patch this API as well, then return false addresses to our own hook functions. What would be harder to cope with, however, would be hardcoded addresses (not very common, I know), or code that resolves the address by itself, without resorting to GetProcAddress (for example by reading into the system DLL's export table).

So for now the best approach I can see is what I've been doing so far. I'll keep working on it and report back with any relevant ideas, but would appreciate any suggestions or comments anyone may have to offer.

Edit: changed topic to reflect broader issue, as DLL isn't needed for Win9x.


Last edited by capi on Tue Feb 10, 2004 11:11 am; edited 3 times in total
Back to top
View user's profile Send private message
capi
SF Senior Mod
SF Senior Mod


Joined: 21 Sep 2003
Posts: 16777097
Location: Portugal

Offline

PostPosted: Tue Feb 10, 2004 10:41 am    Post subject: Reply with quote

Well, in the meantime I've come up with the solution for all the above problems and also managed to really simplify things in the process. The answer was so obvious, of course I had to overlook it... Rolling Eyes

Instead of dealing with a messy DLL and having to edit it's code segment on the fly, setting up a hook and et cetera to try and get it into most processes' address space (and even then, with problems, as I mentioned above), what I should have done from the start was to just put the hook and trampoline functions themselves into shared address space. Forget about no damn DLL. Just allocate a block of memory in shared ring 3 space, copy my hook functions there, then create the trampolines there as well! Solves everything: hook and trampoline functions are now readily available to all processes, from the moment I create them the APIs are hooked, no way of getting around it either. Geez, so simple it coulda bit me in the ass... Embarassed

Of course, there's the small problem, how do we go about allocating a range of memory in shared address space? Easily resolved, just a simple call from a VxD to the ring 0 VMM service _PageAllocate with the right parameters and presto! I was already having to mess with VxD's anyway to enable write permission on the system APIs so that I could change them (as described in previous post), didn't take more than a couple hundred bytes to add the AllocateSharedMem and FreeSharedMem services to my little custom VxD.

*** Start edit ***
Of course then there's the slightly more troublesome problem of having to move the hook function code around in memory, thereby possibly affecting absolute jumps/calls and obviously any IAT-dependant API calls made from within the hook functions. The solution I'll be using for now is just to rely on relative jumps, and as for API address resolving goes, I'll just store the addresses of any APIs I call from within the hook functions in a little shared memory buffer - something like:
Code:
TFuncAddies STRUCT
    lpfSleep          DWORD ?
    lpfOpenProcess    DWORD ?
    ...
TFuncAddies ENDS

Then it's just a matter of filling the shared buffer and patching the hook functions at run time before relocating them (sort of a private implementation of a IAT).
*** End edit ***

Heh, it doesn't seem like this topic attracted much attention anyways, but in case anyone was wondering, that's how I did it. Smile

P.S.: now to port this all to Win2000. As you know, Win2000's memory management is very different. The system memory range (above 2Gb, in this case), which is what we want to write to (that's where the system APIs are located) is set to Copy on Write, as opposed to Win9x, where it's just set to read only. This is both good and bad: good, because there's no need to be messing with device drivers to change page permissions, all we have to do is write to whatever address we want from each and every running process and that way all processes will have their own, private, altered copy of the system APIs. The snag is, again, how to attach ourselves unto all running processes... I will probably go with the DLL and SetWindowsHookEx() method for now, until I find something better in light of the problems described in my first post. Even though the problems aren't as severe in Win2000's case, since any process that calls a system API before we've attached ourselves to it won't crash or malfunction, it will simply use the original copy of the system APIs - but we don't want that, we want to hook all calls. Also, I still haven't looked into the guts of SetWindowsHookEx (guess it's time to fire up the debugger again Laughing), I'd like to figure out once and for all if it will attach my DLL to all processes without exception (just that it takes a long time for some, presumably only attaching the DLL when they return from a call to GetMessage() or PeekMessage()), or if some processes never get attached at all - for example, ones that never call GetMessage(), if my suspicion is right and that's when Windows injects my code, then for programs that never call it, I won't get injected. Either case, I'll probably have to come up with a better method than this for injecting code into all running processes - I do recall there being a registry setting one could create to have your DLL mapped into almost all processes' address space, but there's the "almost" again...

Any suggestions/comments welcome...
Back to top
View user's profile Send private message
PolyVector
Just Arrived
Just Arrived


Joined: 23 Sep 2004
Posts: 0


Offline

PostPosted: Thu Sep 23, 2004 10:13 am    Post subject: Reply with quote

@capi
I'm developing a theme library called FreeStyle... I've run into a major speedbump while skinning window scrollbars... The only way to fully skin them is to hook 3 - 4 API functions... This works Flawlessly in Win2k and above, however Win9x is obviously a little different... I've researched this and found that I need to call _PageModifyPermissions with VxDCall to unlock shared memory... For the life of me cannot get this to work at all... Did you ever get _PageModifyPermissions to work? I have the address of VxDCall but can't quite grasp the ASM needed to call _PageModifyPermissions with it... If you have any examples (or can point me in the right direction) I would really appriciate it...

I'm doing something like this, but it doesn't seem to work:
Code:
PUSHAD
PUSH 020060000h
PUSH 000000000h              ; ???
PUSH 000000001h              ; Page count...
PUSH MemoryAddy
PUSH 00001000Dh             ; _PageModifyPermissions
CALL VxDCall
POPAD
Back to top
View user's profile Send private message
capi
SF Senior Mod
SF Senior Mod


Joined: 21 Sep 2003
Posts: 16777097
Location: Portugal

Offline

PostPosted: Thu Sep 23, 2004 7:53 pm    Post subject: Reply with quote

Oh yes, here is the function prototype for _PageModifyPermissions:
Code:
ULONG _PageModifyPermissions(
   ULONG firstPage,
   ULONG numPages,
   ULONG andMask,
   ULONG orMask
);


Where:
  • firstPage is the number of the first page in the range - not it's address! In 32-bit Intel systems the page number will be baseAddress >> 12.
  • numPages is the number of pages (all of the pages in the range must be commited).
  • andMask is the AND mask which will be applied to the existing permissions (bits at 0 will clear their corresponding permission), and
  • orMask is the OR mask (bits at 1 will set their corresponding permission). To change kernel memory permissions you need to specify PC_STATIC here (defined below).


_PageModifyPermissions changes the EAX, ECX, EDX and EFLAGS registers. It returns the previous permissions of the first page, or -1 for error.

In particular:
  • to clear a given permission bit while leaving the others untouched, set the AND mask to ~<permission_you_want_to_clear>, and the OR mask to 0;
  • to set a given permission, without altering the others, set the AND mask to all 1's, and set the OR mask to the permission you want to enable;
  • to clear all permissions, set both masks to 0;
  • to set permissions to an absolute value, just pass 0 on the AND mask, and the value you want on the OR mask


Acceptable values:
Code:
PC_WRITEABLE    EQU    00020000H   ;duh
PC_USER         EQU    00040000H   ;access from ring 3
PC_STATIC       EQU    20000000H   ;you need this to change permissions of kernel memory
Back to top
View user's profile Send private message
PolyVector
Just Arrived
Just Arrived


Joined: 23 Sep 2004
Posts: 0


Offline

PostPosted: Thu Sep 23, 2004 11:45 pm    Post subject: Reply with quote

Wow, thanks capi!
I'm going to go try that out right now...This has to be the most helpful information I've found on the subject. Thanks Very Happy
Back to top
View user's profile Send private message
capi
SF Senior Mod
SF Senior Mod


Joined: 21 Sep 2003
Posts: 16777097
Location: Portugal

Offline

PostPosted: Thu Nov 04, 2004 10:48 pm    Post subject: Reply with quote

At another person's request, I will elaborate a bit on the explanations in this article, concerning the memory management involved in the hooking of Win98 APIs.

So, we want to hook Windows 98 system APIs. For this, there are two main paths. We can either patch the IAT of every process (which will require hooking on to every process and performing the deed); or we can patch the system DLLs in shared memory (which will require calling _PageModifyPermissions to do the editing). The former has the advantage of being doable from user level (ring 3), and less intrusive; the latter has greater assurance of not being bypassed (as we're tackling the issue at it's root, i.e. the API themselves), as well as the advantage of only having to patch things once.

Patching the IAT shouldn't raise too many new questions in itself, so let's focus instead on the system memory patch method.

Ok, so we want to patch system shared memory (2GB-3GB range, addresses 0x80000000 to 0xC0000000), which is where the APIs reside. This region of memory is read-only, and has a special protection bit that prevents it's protections from being altered in the conventional way (i.e. if we try to VirtualProtectEx() the write bit in, it will fail). What we need is to call the ring 0 VMM service _PageModifyPermissions directly, giving it the correct parameters.

Now, again, there are two ways of going about this. The first (and most fun Wink) way is just making our own VxD and have it act as a wrapper for the service. Teaching how to write a virtual device driver is really beyond the scope of this article, however, so instead I will focus on the other method, using VxDCall. One note first, though, to answer a question I was asked concerning whether and what exactly the CreateFile and DeviceIoControl APIs had to do with any of this: these APIs would be useful if we created a VxD that called _PageModifyPermissions, as they would allow us to communicate with the VxD. We would use CreateFile to get a handle to the virtual device driver, and DeviceIoControl to pass requests to the driver. Basically, our VxD would export a couple of control codes, each corresponding to an operation we want done (allocate N bytes of system memory, make address X writable, and so on), and we would use DeviceIoControl to request the operation from the VxD, feeding it the necessary parameters (number of bytes to allocate, address to change permissions of, whatever).

So, on to the VxDCall. This is actually an undocumented feature, thus why in some places you may find it's use being advised against. Whether this is a big concern or not really depends on the intended purpose of the application we're developping (i.e. self-replicating, self-hiding virus or nice and dandy commercial firewall/whatever). Nevertheless, considering that a) Windows 98 is basically not going to be changed much in the future, and b) none of what we're doing at ring 0 here is compatible with Windows NT/2000/XP anyway regardless of whether we use VxDCall or not, I'd say there isn't much of a problem with using it.

Alright, so what's VxDCall, then? First of all, it's an API, exported by KERNEL32.DLL. It's exported by ordinal (not by name), you can reach it at ordinal 1 (GetModuleHandle() to get a handle for KERNEL32.DLL, then GetProcAddress() with lpProcName set to 1 to get the function address). Ok, and what can VxDCall do for us? A world of good, actually Wink. What VxDCall does, is allow us to call a VxD service from ring 3, simple as that. Comes in handy, eh? Armed with this knowledge, we can now just call _PageModifyPermissions directly from our code (passing it the correct parameters), and change the permissions ourselves. So how do we use VxDCall? Ok, it only takes one parameter, and that is a DWORD (32-bit UINT for you C people) specifying which service of which VxD to call. The high-order word specifies the device ID (the VxD), the low-order word specifies the service. Parameters required by the actual VxD service must be placed in the stack before calling VxDCall. The return value is that of the actual service being called.

An example, for calling _PageModifyPermissions:
Code:
push [permor]   ; OR mask for permissions
push [permand]   ; AND mask for permissions
push [npages]   ; number of pages
push [page]   ; linear address of first page
push 1000Dh   ; (0001h = VMM.VxD << 16) | 000Dh = _PageModifyPermissions
call dword ptr [p_VxDCall]

For C coders, this would equate to:
Code:
p_VxDCall(0x1000D, page, npages, permand, permor);

The first parameter (0x1000D) is the only one that VxDCall actually uses, the others are passed on to the VxD service being called (_PageModifyPermissions in this case).

Basically, for C use, you would have:
Code:
DWORD (*p_VxDCall)(DWORD service, ...);


As for the service codes, these are not the same as the ones specified in the 98 DDK, which are meant to be used by other VxDs (i.e. for calling services already from ring 0). VxDCall codes basically have to be obtained by some reverse engineering, a few useful ones (exported from VMM.VXD):

Code:
#define _PageReserve            0x00010000
#define _PageCommit             0x00010001
#define _PageDecommit           0x00010002
#define _PageFree               0x0001000A
#define _PageModifyPermissions  0x0001000D
#define _PageQuery              0x0001000E


Finally, perhaps an example of how to calculate the parameters for _PageModifyPermissions would be in order. Let's say we want to set write permissions for a memory range of 10000 bytes starting on linear address 0xBFF00000. As this is in the system shared memory region, we will need to use the PC_STATIC flag in the permissions (otherwise it won't let us change anything).

As per the _PageModifyPermissions prototype (can be seen on my other post above), we will need to pass it the following parameters: page, npages, permand and permor.

So, to calculate base, which is the page number of the first page in the range: all we need to do is take the base address (0xBFF00000 in this case), and shift it right by 12 bits: 0xBFF00000 >> 12 == 0xBFF00. That will be our first parameter, base.

For npages, we can use the following expression:
Code:
((base_address & 0xFFF) + num_bytes + 0xFFF) >> 12


For permand, since we don't want to clear any permissions (in this case), we will set it all to 1's, so we'll use 0xFFFFFFFF.

Finally, for permor, we will set the permission bit(s) we want to set. In this case, that will be PC_WRITEABLE and PC_STATIC (this latter is required for system memory), both defined in my previous post.

And well, I believe that should take care of the questions I was posed, happy coding everyone! For further information I suggest readers search the Web for matters such as Windows 9x driver development or virus coding (yes, there is much to be learned from blackhat virii making sites, especially for undocumented stuff).
Back to top
View user's profile Send private message
russiandevil
Just Arrived
Just Arrived


Joined: 04 Nov 2004
Posts: 0


Offline

PostPosted: Fri Nov 05, 2004 2:53 am    Post subject: Reply with quote

hi capi,

thanks for posting the clarifications to my questions. I have some more questions that arose as a result of me trying out some of the suggestions:

-----------------------------------------------------------------
HMODULE hMod = GetModuleHandle("Kernel32.dll");

if (hMod != NULL)
{
pf_VxDCall pVxDCall = (pf_VxDCall)GetProcAddress(hMod, MAKEINTRESOURCE(1));
}
-------------------------------------------------------------------

the above snipped of the code seems to fail in GetProcAddress, with GetLastError reporting 50 (The request is not supported. ERROR_NOT_SUPPORTED). This to me suggests that I should do the manual walk-through the PE header, and locate the EXPORTS section of Kernel32.dll, and do my work...

(a little bit later I found a google group post which mentions that:

However, at some point during the Windows 95 beta, Microsoft added code to "GetProcAddress" to see if it's being called with the ordinal form of the function. If so, and if the HMODULE passed to "GetProcAddress" is that of KERNEL32.DLL, "GetProcAddress" fails the call. In the debugging version of KERNEL32.DLL, the code emits a trace diagnostic: "GetProcAddress: kernel32 by id not supported."

)

second question is regarding the 'Patching the IAT shouldn't raise too many new questions in itself' comment... unless I'm mistaken, if I'm doing IAT patching on Windows 98 machine and am trying to intercept the API routine from a system dll (such as user32.dll and gdi32.dll), at some point in time I still have to modify the shared address space above the 2GB... so once again I'll be needing to 1) use _PageModifyPermissions and 2) load my interception routines into the shared address space..... The reason I say this is that Jeffrey Richter's sample in 'Programming Applications for Microsoft Windows' uses WriteProcessMemory routine to patch up the IAT of the modules that are currently loaded into the address space of a target process... and on 9x, WriteProcessMemory will fail if that address is above a certain region (as we are all aware by now..)

regards,
Greg
Back to top
View user's profile Send private message Send e-mail
capi
SF Senior Mod
SF Senior Mod


Joined: 21 Sep 2003
Posts: 16777097
Location: Portugal

Offline

PostPosted: Fri Nov 05, 2004 3:26 am    Post subject: Reply with quote

russiandevil wrote:
the above snipped of the code seems to fail in GetProcAddress, with GetLastError reporting 50 (The request is not supported. ERROR_NOT_SUPPORTED). This to me suggests that I should do the manual walk-through the PE header, and locate the EXPORTS section of Kernel32.dll, and do my work...

Whoops, you are correct indeed. I've not worked with Windows 98 at a low level in a while, and did not have a 98 box to test the GetProcAddress thing at the time of writing this. Seems Windows 98's kernel32.dll does not play nice Wink. You'll have to get the address manually as you noted. It is there, just have to work a bit more to get at it.

Quote:
if I'm doing IAT patching on Windows 98 machine and am trying to intercept the API routine from a system dll (such as user32.dll and gdi32.dll), at some point in time I still have to modify the shared address space above the 2GB...

Actually, this is where the IAT method is different than the other one. If you patch the the process' IAT, you won't have to patch the APIs at all - you don't need to change the system shared memory. What you do is change the relevant IAT entries to point to your own intercept functions (which you will insert inside the process' private address space). That way, when the target process tries to call, say, MessageBoxA, it will actually end up calling your FakeMessageBoxA, which is located inside the process' own private address space.

Obviously, if you want your intercept functions to call the true APIs at some point, you will have to obtain the actual addresses at runtime through some means (for example using GetProcAddress), then hardcode it on the fly into the code you will inject before actually injecting it. Nothing too hard though, just a matter of overwritting at the corresponding offsets before injecting.
Back to top
View user's profile Send private message
russiandevil
Just Arrived
Just Arrived


Joined: 04 Nov 2004
Posts: 0


Offline

PostPosted: Fri Nov 05, 2004 4:11 am    Post subject: Reply with quote

hello Smile

Let's take notepad.exe application as a simple example. If I am to open it up in depends.exe (on Windows 98 machine) and look at the list of list of parent import functions for the currently selected module (and traverse my way down through the first-level of dependencies: SHELL32.DLL, KERNEL32.DLL, USER32.DLL, GDI32.DLL, COMDLG32.DLL and ADVAPI32.DLL), I won't see TextOutA routine being mentioned. If you, however, expand all the subtrees on the left hand panel, you'll find that TextOutA appears below notepad.exe->COMDLG32.DLL->GDI32.DLL.

I've put in some logging in the current (old-school) implementation (the ProcHook library from 1993 that I mentioned in the message earlier), and have detected that under certain circumstances the notepad.exe process does invoke TextOutA API routine.

This to me suggests that it does so indirectly, through one of the function calls in (see chain I mentioned above) COMDLG32.DLL. Taking this further, it then seems insufficient to simply patch up the IAT of the module that we're targetting... instead (and I'm pretty sure that's what Jeff Richter's code is doing), we need to obtain the list of modules currently loaded in target process' address space and apply the patching to the IATs of all these modules.

Please let me know if I'm way off my tree...
Back to top
View user's profile Send private message Send e-mail
capi
SF Senior Mod
SF Senior Mod


Joined: 21 Sep 2003
Posts: 16777097
Location: Portugal

Offline

PostPosted: Fri Nov 05, 2004 4:22 am    Post subject: Reply with quote

Ah, I see what you mean now, you are correct.

What I've been talking about regarding the process' IAT has been speaking on the generic case, intercepting calls made by the actual .exe program code.

For what you plan to do, simply patching the IAT would not suffice as the API is being called indirectly. As you noted, you would have to go down the list of loaded modules and patch all the IATs, wherever you find a reference to the API you want to intercept. Which of course will mean having to patch shared memory, effectively removing the simplicity we wanted to gain by going for the IAT method.

This is yet another reason why dealing with the problem at the root (that is, patching the API itself) is more practical and thorough. As I noted earlier, this way you only have to patch once, and you know everything will be going through your trampoline (discounting of course separate private copies of the DLLs, that's one advantage the IAT patching method would have over this one).
Back to top
View user's profile Send private message
russiandevil
Just Arrived
Just Arrived


Joined: 04 Nov 2004
Posts: 0


Offline

PostPosted: Fri Nov 05, 2004 4:54 am    Post subject: Reply with quote

hello again Smile

the main reason I didn't want to patch the API itself is because in my particular instance I only care about the API routines originating from a particular (known to me) process... and I didn't want to involve all the other currently-running (and soon-to-be-running) processes.

I'm still thinking of spending a bit of time figuring out how ProcHook manages to achieve the desired result (you can find the source code it in the self-extracting archive found at http://www.gaby.de/ftp/pub/win3x/archive/softlib/prochook.exe), because I don't see any references to virtual device driver calls at all in whatever code I've seen... is it just possible that the code compiled using VS 1.52 is allowed to do all kinds of crazy things to shared address space on 9x machine? guess time and investigation will show. looks like it does use some API calls that were around back in the Windows 3.11 days... that MSDN search fails to locate Smile

but I guess my general goal is to have a single library that works on all flavours of Windows (95+) and doesn't use a really low-level stuff (so that people maintaining it aren't scratching their heads like I am often doing now)

Smile
Back to top
View user's profile Send private message Send e-mail
capi
SF Senior Mod
SF Senior Mod


Joined: 21 Sep 2003
Posts: 16777097
Location: Portugal

Offline

PostPosted: Fri Nov 05, 2004 9:30 pm    Post subject: Reply with quote

russiandevil wrote:
the main reason I didn't want to patch the API itself is because in my particular instance I only care about the API routines originating from a particular (known to me) process... and I didn't want to involve all the other currently-running (and soon-to-be-running) processes.

Oh, I see, I thought you were trying to hook the APIs system-wide. Well, in that case, your best bet would probably be going the IAT route. Will take a bit of work, though, but seeing as though it's a specific target your research will be facilitated. You'll need to traverse down the loaded DLLs and patch any relevant IAT entries - this may be a problem if said DLLs are loaded in shared space, as patching them there will obviously affect all processes (not to mention you'll need ring 0 to change the permissions to write to them). However, you should be ok - in Win9x, apart from USER32.DLL, GDI32.DLL and KERNEL32.DLL, everything else is mapped on the private space of the process (in particular COMDLG32.DLL, SHELL32.DLL and so on). This has the added benefit of removing the need for ring 0 code at all in your case Smile

If this were for a NT based OS (i.e. 2000 and so on) it would all be easier, as the system DLLs are mapped copy-on-write to each process. It would be the best of both worlds for you, all you'd need to do is directly patch the APIs from within the target process' context. As it would be copy-on-write, there would be no problems with permissions or ring levels, and you would have the added benefit that it would only affect the target process.

But for Win9x you're stuck, as the APIs are in system shared space, and don't have the copy-on-write set, you can't change them without affecting every process (not to mention the change would have to be from ring 0). You'll have to intercept them at ever point of call instead.

Naturally, this will mean either patching the process' code itself (i.e. finding all calls to the API and changing them to call your function), or patching the IATs. Between the two, naturally the IATs will be less work as they are centralized. The only potential problem is if the process uses GetProcAddress to obtain the address of the APIs you want to intercept, since obviously that will bypass the patched IATs. You need to make sure that doesn't happen, or if it does, you'll have to intercept GetProcAddress as well (from the IATs) and filter the return values according to the requested function.
Back to top
View user's profile Send private message
russiandevil
Just Arrived
Just Arrived


Joined: 04 Nov 2004
Posts: 0


Offline

PostPosted: Sun Nov 07, 2004 8:27 am    Post subject: Reply with quote

Well the routines I'm intercepting are all in User32.dll and Gdi32.dll Smile

Have lost the number of times I have crashed explorer.exe on my VMWare image of Windows 98, while testing the program so far. Actually, one of the crashes was in HOOK.DLL, which is one of VMWare's own libraries... so I'm wondering if VMWare itself is doing some sort of hooking... I guess ideally I'd have a stand-alone non-virtual 9x box to test things on but 'Revert to Snapshot' is just such a useful button!

I'm guessing its worth mentioning on the subject of VxDCall that it returns the -1 on failure or previous page permissions in case of success, and its probably a good idea (correct me if I'm wrong) to restore the permissions, right after we're done modifying the shared address space.

I guess I'm now up to the point where I need to somehow load my interceptor DLL into 2GB+ address space on a 9x machine. Looks like CreateFileMapping and MapViewOfFile will come in handy (I'm trying to keep VxDCall usage to a minimum... then again, I'm still not quite clear as to how to routines are copied from one location to another ... most of the examples are in assembly Smile)

Oh well more MSDN-ining for me coming up. thanks for your comments/feedback capi, I'll keep you updated on how things go Smile
Back to top
View user's profile Send private message Send e-mail
capi
SF Senior Mod
SF Senior Mod


Joined: 21 Sep 2003
Posts: 16777097
Location: Portugal

Offline

PostPosted: Sun Nov 07, 2004 8:49 am    Post subject: Reply with quote

russiandevil wrote:
Well the routines I'm intercepting are all in User32.dll and Gdi32.dll Smile

Yes, but are they being called from those DLLs? Because what I was going for was that if you went the IAT patching way, you could keep totally in ring 3, and deal only in process private space. Unless the APIs you want to intercept are being called from user32.dll, kernel32.dll or gdi32.dll, everywhere else is on private process space. That means if, say, foobar.dll calls CreateProcess, you can just patch foobar.dll's IAT in memory inside the target process' private space.

Quote:
Have lost the number of times I have crashed explorer.exe on my VMWare image of Windows 98, while testing the program so far. Actually, one of the crashes was in HOOK.DLL, which is one of VMWare's own libraries... so I'm wondering if VMWare itself is doing some sort of hooking... I guess ideally I'd have a stand-alone non-virtual 9x box to test things on but 'Revert to Snapshot' is just such a useful button!

May be a good idea indeed. If you're dealing with low level stuff you'll want to remove as many variables from the equation as you can. At least try to see if VMWare isn't being the cause of some of those crashes.

Quote:
I'm guessing its worth mentioning on the subject of VxDCall that it returns the -1 on failure or previous page permissions in case of success, and its probably a good idea (correct me if I'm wrong) to restore the permissions, right after we're done modifying the shared address space.

That's actually what _PageModifyPermissions returns (VxDCall just returns whatever the called function returned). Indeed it's a good idea to put things back after you've changed them, always better to clean up after ourselves Wink.

Still, as long as the APIs you're intercepting aren't being called from the three shared system libraries (user32, kernel32 and gdi32), you could just work inside the process' private space, by traversing down the IATs of all loaded modules except user32, kernel32 and gdi32, and patching the relevant entries. Would be some work, but would at least spare you the ring 0 stuff.

If you do want to go shared and place your routines in shared space, you could just use a ring 0 solution to allocate shared memory above the 2GB barrier. Use _PageReserve and _PageCommit with VxDCall to allocate the shared memory, then just copy the data along from ring 3 like you would copy any block of memory. You can also just use _PageAllocate and do the allocation in one shot (I don't have the specifics for that service right now, though, I'm on a Linux box Wink).
Back to top
View user's profile Send private message
russiandevil
Just Arrived
Just Arrived


Joined: 04 Nov 2004
Posts: 0


Offline

PostPosted: Sun Nov 07, 2004 9:02 am    Post subject: Reply with quote

Yes, but are they being called from those DLLs?

-> yep, otherwise in depends.exe these routines would have been listed in the import table of my target process (for all my experimental purposes so far it has been notepad.exe) Smile

Use _PageReserve and _PageCommit with VxDCall to allocate the shared memory, then just copy the data along from ring 3 like you would copy any block of memory

-> yep, I noticed you mentioned these routines earlier on in this thread, I'm just not too comprehensive of the the whole 'copying of address space of DLL to some new location' concept. i.e. do I need to get the base address of my interceptor DLL in memory, and copy everything starting from that address and ending god-knows-where to this newly alloc-ed block... Shocked.

I don't like asking for other people to write code for me so just ignore my rantings, I gotta google it on my own heheh Laughing
Back to top
View user's profile Send private message Send e-mail
capi
SF Senior Mod
SF Senior Mod


Joined: 21 Sep 2003
Posts: 16777097
Location: Portugal

Offline

PostPosted: Sun Nov 07, 2004 6:22 pm    Post subject: Reply with quote

russiandevil wrote:
-> yep, otherwise in depends.exe these routines would have been listed in the import table of my target process (for all my experimental purposes so far it has been notepad.exe) Smile

Yes, they are being called indirectly by other DLLs, but what I meant was, have you checked if the DLLs where they are being called from are mapped in shared space or not? Because most DLLs, excluding some few system ones, are mapped to the process' private space. Meaning, if the DLLs that call the APIs (not the DLLs where the APIs are, the DLLs that call them) are not in system shared space, you could edit the IAT perfectly from within ring 3 just like any other memory range..

Quote:
-> yep, I noticed you mentioned these routines earlier on in this thread, I'm just not too comprehensive of the the whole 'copying of address space of DLL to some new location' concept. i.e. do I need to get the base address of my interceptor DLL in memory, and copy everything starting from that address and ending god-knows-where to this newly alloc-ed block... Shocked.

Oh but you don't have to deal with DLLs at all... If you allocate system shared memory, all you have to do is manually copy your function code to the region of shared memory. You don't need your code to even be in a DLL, you just need to copy it to the shared space. Obviously, this means your code needs to fully relocatable (i.e. no static references, no calling APIs via IATs, etc). So this isn't just "code as normal, then copy the code over", it takes some careful thought. But nothing too hard.

Basically, you can't use global or static variables inside those functions, and you can't call any APIs directly. What you do to call APIs from there is place the addresses of the APIs (obtained with GetProcAddress) in a region of the shared space. Your injected code will then read from that region, and take the pointers from there. This means you will obviously have to patch your own code at runtime before placing it in the shared memory region, thus why this is easier to do in assembly (and why most examples are in assembly). I'd suggest doing something like your typical buffer overflow exploit. Compile your function code separately - remember, no calling APIs directly, all through function pointers or hardcoded addresses which will be fixed by your injector code before injecting. Disassemble it, identify the places you need to patch inline (i.e. where you're calling APIs). Take the assembled code as hex into your C injector program, in some char array. Better to make it nice and put the assembler mnemonics as comments next to each line, to make it easier to maintain the whole thing. Then, in your injector code, you will use GetProcAddress to obtain the addresses of whatever APIs your "code to inject" requires, fill in the blanks within the code as necessary (patch it inline with the required addresses from GetProcAddress, or place it in a struct filled with function pointers which will be accessed by the injected code), then use VxDCall to allocate system shared memory and copy the whole thing over. If you did use a struct filled with function pointers (i.e. your own personal implementation of a IAT, basically), be sure to copy the struct along as well to shared space, and patch the injected code with the address of where it went.

And well, these are just some pointers, as you said, I'm sure you'll be quite capable of making it on your own Smile
Back to top
View user's profile Send private message
Display posts from previous:   

Post new topic   Reply to topic   Printer-friendly version    Networking/Security Forums Index -> Programming and More All times are GMT + 2 Hours
Goto page 1, 2, 3  Next
Page 1 of 3


 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum

Community Area

Log in | Register