Problems hooking GetFileInformationByHandle on win7 64bits

Sep 26, 2010 at 10:40 AM

Hi,

I'm looking for suggestions, I'm trying to hook GetFileInformationByHandle

kernel32!GetFileInformationByHandle:
00000000`76a31b00 eb06            jmp     kernel32!GetFileInformationByHandle (00000000`76a31b08)
00000000`76a31b02 90              nop
00000000`76a31b03 90              nop
00000000`76a31b04 90              nop
00000000`76a31b05 90              nop
00000000`76a31b06 90              nop
00000000`76a31b07 90              nop
00000000`76a31b08 ff25b2ba0800    jmp     qword ptr [kernel32!_imp_GetFileInformationByHandle (00000000`76abd5c0)]
00000000`76a31b0e 90              nop
00000000`76a31b0f 90              nop
00000000`76a31b10 90              nop
00000000`76a31b11 90              nop
00000000`76a31b12 90              nop
00000000`76a31b13 90              nop

 

Specifically, LhRelocateEntryPoint fails because GetFileInformationByHandle starts with a near JMP.
Now obviously I can overcome this by hooking the address where it jumps to (76a31b08) and by performing a "near jump" test at the begining of LhInstallHook() but I'm not sure of any consequences...

Any ideas how to overcome this problem successfuly?

Why M$ put this near JMP there in win7? Is it done for hot patching?

Are you getting any patch submission? 

Thanks,
Eric.

 

Sep 26, 2010 at 11:00 AM
Edited Sep 26, 2010 at 11:02 AM

Hmm... they could easily put in a new jmp @ 76a31b0e (8 bytes take several clockcycles) and then switch to the new jmp by changing the near jmp (2 bytes = single clockcycle).

Have you done a near-jump-detector that will iterate until something suitable is found? Doesnt necessarily have to be implemented into EasyHook itself - it could be done as a seperate helper function (void* realhookaddress = LhGetSafeHookAddress( void* initialTry ) ).

Sep 26, 2010 at 11:26 AM

Nothing fancy, but here is what I've done. It "works for me"
I call it just before LhInstallHook() 

/* 
 * See http://easyhook.codeplex.com/Thread/View.aspx?ThreadId=228607
 *
 * Near JMP hooking is not supported by EasyHook, but luckily near JMP are easy to follow
 * So we hook the address where the near JMP lands instead.
 *
 * If the first opcode of func_address is 0xEB then we'll try to follow it and return the destination 
 * address which should be hooked, if otherwise we just return the func_address itself.
 */ 

PVOID FixNearJMP(PVOID func_address)
{
	UCHAR * pByte;
	UCHAR bytes = 0;

	pByte = (UCHAR *)func_address;

	/* Near JMP */
	if (*pByte == 0xEB) {
		bytes = *(++pByte);
		pByte += bytes + 1;
		return ((PVOID)pByte);
	} else {
		return (func_address);
	}
}
Sep 26, 2010 at 6:01 PM

Roger, looks bulletproof. Thanks for sharing!

Are near-jumps the only things that need to be accounted for? I think the hook's length is 12 bytes (see LhInstallHook), so we actually need 12 bytes of straight-forward code-sequence, dont we?

Sep 27, 2010 at 9:48 AM

No worries :) I think it may be either 5 or 12 bytes long.

Hot patching should be avoided if using this method.

I think that the best way to tackle this issue is to better analyze your target function and offer more "hook" possibilities instead of just failing. The community is responsible for contributing in that area as well...

Another idea, If you could implement paging in user mode without costly transitions I could offer you to implement a swap/paging hook instead of a far-jmp hook :)

This way, even a CRC check would pass.

 

 

Sep 27, 2010 at 3:49 PM

AFAIK the entry of the function is disasmed (otherwise we couldnt construct the trampoline), so all information is present. Problem with later hooking is "preprocessed data" or the stack might have a frame applied to it or ... ... Not sure about a generic approach anymore :(

You could mark the page as non-executable and catch that :) Very slow as well, but as you said - it passes CRC checks.