flat assembler
Message board for the users of flat assembler.

Index > Windows > Simple JMP Hook.

Goto page Previous  1, 2
Author
Thread Post new topic Reply to topic
typedef



Joined: 25 Jul 2010
Posts: 2909
Location: 0x77760000
typedef 17 Dec 2012, 04:43
That's a lot of APIs. I think M$ did this for security reasons.

And one thing I didn't know about Win7 is that Registry APIs are now in kernel32.dll (Probably proxies as the real ones exist also in ADVAPI32.DLL )
Post 17 Dec 2012, 04:43
View user's profile Send private message Reply with quote
Overflowz



Joined: 03 Sep 2010
Posts: 1046
Overflowz 17 Dec 2012, 11:38
I'm confused -.-
Post 17 Dec 2012, 11:38
View user's profile Send private message Reply with quote
f0dder



Joined: 19 Feb 2004
Posts: 3175
Location: Denmark
f0dder 17 Dec 2012, 13:32
yoshimitsu wrote:
you should probably just write a universal hook function which uses a length disassembler engine to securely save the instructions which need to get overwritten by the hook-jmp and save them to a different location and append a jmp back to the hooked function but behind the hook-jmp, creating a gate to call the original function without invoking the hook.
If you want to be on the safe side, you'll need to also add special handling for instructions with EIP-relative encoding.

typedef wrote:
And one thing I didn't know about Win7 is that Registry APIs are now in kernel32.dll (Probably proxies as the real ones exist also in ADVAPI32.DLL )
The API restructuring is explained in some Channel9 video - I think it's this one (not going to watch through the whole video to verify - even if it's not that video, there's other interesting material in it Razz). There's some pretty interesting technical kernel-level videos on the Channel9 site.

_________________
Image - carpe noctem
Post 17 Dec 2012, 13:32
View user's profile Send private message Visit poster's website Reply with quote
l_inc



Joined: 23 Oct 2009
Posts: 881
l_inc 17 Dec 2012, 13:46
yoshimitsu
Quote:
l_inc wrote:
First, you don't have to change page permissions with VirtualProtect. WriteProcessMemory is able to handle that for you.

msdn wrote:
lpBaseAddress [in]
A pointer to the base address in the specified process to which data is written. Before data transfer occurs, the system verifies that all data in the base address and memory of the specified size is accessible for write access, and if it is not accessible, the function fails.

That's good, you're reading the official documentation, but you should always be able to flexibly interpret it. Especially after you got a hint for that. If you look at the implementation of WriteProcessMemory, you'll see, that it first starts with modifying the permissions by means of ZwProtectVirtualMemory and only after that calls ZwWriteVirtualMemory. Thus in fact the function only fails, when it's unable to change the memory permissions (well, there are also other irrelevant in this context cases), but then calling VirtualProtect wouldn't help much either. And this behaviour holds at least since win2k.
f0dder
Quote:
If you want to be on the safe side, you'll need to also add special handling for instructions with EIP-relative encoding.

And also an AI-based code mutation engine, because the overwritten instructions can be referenced (e.g. as jump destination) by different code parts.
Post 17 Dec 2012, 13:46
View user's profile Send private message Reply with quote
yoshimitsu



Joined: 07 Jul 2011
Posts: 96
yoshimitsu 17 Dec 2012, 13:56
f0dder wrote:
yoshimitsu wrote:
you should probably just write a universal hook function which uses a length disassembler engine to securely save the instructions which need to get overwritten by the hook-jmp and save them to a different location and append a jmp back to the hooked function but behind the hook-jmp, creating a gate to call the original function without invoking the hook.
If you want to be on the safe side, you'll need to also add special handling for instructions with EIP-relative encoding.

Yeah, forgot to mention those. This is actually the reason I wrote the small disassembler engine I posted here in the first place.

typedef wrote:
And one thing I didn't know about Win7 is that Registry APIs are now in kernel32.dll (Probably proxies as the real ones exist also in ADVAPI32.DLL )

Just checked the imports and the exports: apparently, advapi32.dll contains proxies and the real functions do reside in kernel32.dll.

l_inc wrote:
That's good, you're reading the official documentation, but you should always be able to flexibly interpret it. Especially after you got a hint for that. If you look at the implementation of WriteProcessMemory, you'll see, that it first starts with modifying the permissions by means of ZwProtectVirtualMemory and only after that calls ZwWriteVirtualMemory. Thus in fact the function only fails, when it's unable to change the memory permissions (well, there are also other irrelevant in this context cases), but then calling VirtualProtect wouldn't help much either. And this behaviour holds at least since win2k.

ah, ok. Didn't look into the implementation as I thought with accessible the current access rights are meant.


Last edited by yoshimitsu on 17 Dec 2012, 15:56; edited 2 times in total
Post 17 Dec 2012, 13:56
View user's profile Send private message Reply with quote
f0dder



Joined: 19 Feb 2004
Posts: 3175
Location: Denmark
f0dder 17 Dec 2012, 14:19
l_inc wrote:
f0dder wrote:
If you want to be on the safe side, you'll need to also add special handling for instructions with EIP-relative encoding.

And also an AI-based code mutation engine, because the overwritten instructions can be referenced (e.g. as jump destination) by different code parts.
Yeah, that's if you want to be extremely safe - I doubt this will happen for entrypoint hooking of normal API code though Smile

_________________
Image - carpe noctem
Post 17 Dec 2012, 14:19
View user's profile Send private message Visit poster's website Reply with quote
l_inc



Joined: 23 Oct 2009
Posts: 881
l_inc 17 Dec 2012, 14:53
f0dder
Well... GetTickCount64 looks on my Vista like this:
Code:
CPU Disasm
Address   Hex dump              Command                                  Comments
76825E3F  /$ /EB 00             JMP SHORT 76825E41                       ; kernel32.GetTickCount64(guessed void)
76825E41  |> \8B0D 2403FE7F     /MOV ECX,DWORD PTR DS:[7FFE0324]
76825E47  |.  8B15 2003FE7F     |MOV EDX,DWORD PTR DS:[7FFE0320]
76825E4D  |.  A1 2803FE7F       |MOV EAX,DWORD PTR DS:[7FFE0328]
76825E52  |.  3BC8              |CMP ECX,EAX
76825E54  |.  75 34             |JNE SHORT 76825E8A
76825E56  |.  A1 0400FE7F       |MOV EAX,DWORD PTR DS:[7FFE0004]
76825E5B  |.  F7E2              |MUL EDX
76825E5D  |.  0FACD0 18         |SHRD EAX,EDX,18
76825E61  |.  56                |PUSH ESI
76825E62  |.  57                |PUSH EDI
76825E63  |.  C1EA 18           |SHR EDX,18
76825E66  |.  8BF0              |MOV ESI,EAX
76825E68  |.  A1 0400FE7F       |MOV EAX,DWORD PTR DS:[7FFE0004]
76825E6D  |.  8BFA              |MOV EDI,EDX
76825E6F  |.  F7E1              |MUL ECX
76825E71  |.  6A 00             |PUSH 0                                  ; /Arg4 = 0
76825E73  |.  68 00010000       |PUSH 100                                ; |Arg3 = 100
76825E78  |.  52                |PUSH EDX                                ; |Arg2
76825E79  |.  50                |PUSH EAX                                ; |Arg1
76825E7A  |.  E8 C9E60300       |CALL __allmul                           ; \ntdll._allmul
76825E7F  |.  03F0              |ADD ESI,EAX
76825E81  |.  13FA              |ADC EDI,EDX
76825E83  |.  8BD7              |MOV EDX,EDI
76825E85  |.  5F                |POP EDI
76825E86  |.  8BC6              |MOV EAX,ESI
76825E88  |.  5E                |POP ESI
76825E89  |.  C3                |RETN
76825E8A  |>  F390              |PAUSE
76825E8C  \.^ EB B3             \JMP SHORT 76825E41
    

You may notice, that the address 76825E41 is referenced from two places: 76825E3F and 76825E8C. Thus you'll have a problem if you carelessly overwrite the beginning of the function with a 5-bytes jump (btw., it's hotpatchable). Besides there are also cases, when the beginning of a function is referenced by a relocation, which would be relevant for offline patching.
Post 17 Dec 2012, 14:53
View user's profile Send private message Reply with quote
f0dder



Joined: 19 Feb 2004
Posts: 3175
Location: Denmark
f0dder 17 Dec 2012, 15:16
l_inc wrote:
Well... GetTickCount64 looks on my Vista like this:
Thanks for showing that snippet! - hadn't expected code like that for an API function. Annoying Smile

So, the safest is probably to start out by seeing if the function can be hotpatched (including, perhaps, support for hooking already-hotpatched functions - that can probably be handled robustly?), reverting to doing "fingers-crossed-LDE-and-a-little-extra" patching if the function hasn't been prepared for hotpatch?

Doing full code trace for API hooking isn't feasible, IMHO.

_________________
Image - carpe noctem
Post 17 Dec 2012, 15:16
View user's profile Send private message Visit poster's website Reply with quote
yoshimitsu



Joined: 07 Jul 2011
Posts: 96
yoshimitsu 17 Dec 2012, 15:56
Interesting snippet, l_inc.
Hotpatching GetTickCount64 doesn't provide its full convenience, though, as the first two bytes are not dummy code and thus have to be saved (and further its offset needs to be adjusted and you likely have to transform it to a jmp rel32).
But as you already explained in this example it'd be way more convenient than using a 5-byte hook.
Post 17 Dec 2012, 15:56
View user's profile Send private message Reply with quote
yoshimitsu



Joined: 07 Jul 2011
Posts: 96
yoshimitsu 31 Dec 2012, 02:46
l_inc wrote:
yoshimitsu
Quote:
l_inc wrote:
First, you don't have to change page permissions with VirtualProtect. WriteProcessMemory is able to handle that for you.

msdn wrote:
lpBaseAddress [in]
A pointer to the base address in the specified process to which data is written. Before data transfer occurs, the system verifies that all data in the base address and memory of the specified size is accessible for write access, and if it is not accessible, the function fails.

That's good, you're reading the official documentation, but you should always be able to flexibly interpret it. Especially after you got a hint for that. If you look at the implementation of WriteProcessMemory, you'll see, that it first starts with modifying the permissions by means of ZwProtectVirtualMemory and only after that calls ZwWriteVirtualMemory. Thus in fact the function only fails, when it's unable to change the memory permissions (well, there are also other irrelevant in this context cases), but then calling VirtualProtect wouldn't help much either. And this behaviour holds at least since win2k.

Was just using WriteProcessMemory and recalled what you wrote, so I stepped through the function to see what's going on:
It calls ZwProtectVirtualMemory and modifies the rights to PAGE_EXECUTE_READWRITE, indeed, but directly after that it checks whether the old protection value specified PAGE_NOACCESS or PAGE_READONLY. And if so, it changes them back to the original value and aborts.
If not, it continues, even if there were no write-rights.
So it's not always sufficient to call WriteProcessMemory only.
Post 31 Dec 2012, 02:46
View user's profile Send private message Reply with quote
l_inc



Joined: 23 Oct 2009
Posts: 881
l_inc 31 Dec 2012, 03:16
yoshimitsu
Quote:
And if so, it changes them back to the original value and aborts.

You're right. But this does not fit into the scope of applicability limited by the following statement:
l_inc wrote:
there are also other irrelevant in this context cases

Smile
The patched memory is executable and therefore PAGE_NOACCESS and PAGE_READONLY are not really relevant in this context.
Post 31 Dec 2012, 03:16
View user's profile Send private message Reply with quote
revolution
When all else fails, read the source


Joined: 24 Aug 2004
Posts: 20451
Location: In your JS exploiting you and your system
revolution 31 Dec 2012, 04:24
yoshimitsu wrote:
... I stepped through the function to see what's going on:
It calls ZwProtectVirtualMemory and modifies the rights to PAGE_EXECUTE_READWRITE, indeed, but directly after that it checks whether the old protection value specified PAGE_NOACCESS or PAGE_READONLY. And if so, it changes them back to the original value and aborts.
If not, it continues, even if there were no write-rights.
So it's not always sufficient to call WriteProcessMemory only.
Well at the very least you saw one version of the OS have this behaviour. But there is no guarantee that other versions of the OS will do the same things. Writing your application to rely on such behaviour may cause problems on future or past versions of Windows. This is why we have official documentation, so that we have a known outcome when we properly follow what the documentation says.
Post 31 Dec 2012, 04:24
View user's profile Send private message Visit poster's website Reply with quote
Display posts from previous:
Post new topic Reply to topic

Jump to:  
Goto page Previous  1, 2

< Last Thread | Next Thread >
Forum Rules:
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
You cannot attach files in this forum
You can download files in this forum


Copyright © 1999-2025, Tomasz Grysztar. Also on GitHub, YouTube.

Website powered by rwasa.