Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unable to hook DestroyCaret function from user32 module #4

Closed
rommar opened this issue Feb 24, 2018 · 4 comments
Closed

Unable to hook DestroyCaret function from user32 module #4

rommar opened this issue Feb 24, 2018 · 4 comments
Assignees
Milestone

Comments

@rommar
Copy link

rommar commented Feb 24, 2018

I want to hook CreateCaret and DestroyCaret functions from user32.dll. Hooking CreateCaret works ok, but DestroyCaret - no.

#include <Windows.h>

typedef BOOL(WINAPI *CreateCaretFuncPtr)(
	_In_ HWND hWnd,
	_In_opt_ HBITMAP hBitmap,
	_In_ int nWidth,
	_In_ int nHeight);

typedef BOOL(WINAPI *DestroyCaretFuncPtr)(VOID);

static CreateCaretFuncPtr CreateCaretOrigFuncPtr = NULL;
static DestroyCaretFuncPtr DestroyCaretOrigFuncPtr = NULL;

static BOOL WINAPI MyCreateCaret(
	_In_ HWND hWnd,
	_In_opt_ HBITMAP hBitmap,
	_In_ int nWidth,
	_In_ int nHeight)
{
	return CreateCaretOrigFuncPtr(hWnd, hBitmap, nWidth, nHeight);
}

static BOOL WINAPI MyDestroyCaret(VOID)
{
	return DestroyCaretOrigFuncPtr();
}

In main function I have:

HMODULE user32ModuleHandle = GetModuleHandle(L"User32");
CreateCaretOrigFuncPtr = (CreateCaretFuncPtr)GetProcAddress(user32ModuleHandle, "CreateCaret");
DestroyCaretOrigFuncPtr = (DestroyCaretFuncPtr)GetProcAddress(user32ModuleHandle, "DestroyCaret");
// will be true
bool createHookSetOk = Mhook_SetHook((PVOID*)&CreateCaretOrigFuncPtr, MyCreateCaret);
// will be false
bool destroyHookSetOk = Mhook_SetHook((PVOID*)&DestroyCaretOrigFuncPtr, MyDestroyCaret);

I studied a bit how mhook works under the hood and I see that the first call to DisassembleAndSkip in Mhook_SetHookEx returns instruction length of 5 bytes for CreateCaret, but 2 bytes for DestroyCaret. ollydbg shows that CreateCaret starts with MOV EAX,1032 (5 bytes long) while DestroyCaret is

759B38C7   6A 06            PUSH 6
759B38C9   E8 1F28FFFF      CALL USER32.759A60ED
759B38CE   C3               RETN

First instruction for DestroyCaret is PUSH which takes 2 bytes. So DisassembleAndSkip returns 2 bytes and we go to else block where a check for IsJumpPresentInFirstFiveBytes takes place. IsJumpPresentInFirstFiveBytes returns false because it checks only for conditional jumps (ITYPE_BRANCHCC). So trampoline is not created.

Could please anyone comment on this situation? Is this a known behavior?

In IsJumpPresentInFirstFiveBytes I tried to add a check for ITYPE_CALL and return true for that and after that I see that my hook is working (gets called). Is there any drawback of such modification?

OS is Windows 7. Application type is x86.

@SergiusTheBest
Copy link
Member

Thanks for reporting. We are looking into this.

@Grivus
Copy link
Member

Grivus commented Feb 27, 2018

Hi, @rommar!

Could please anyone comment on this situation? Is this a known behavior?

First of all, it's a known situation, yes.
To hook some function mhook takes first 5 bytes of that function, save them to some memory location, and instead of them, write the jump to our hook (MyXXXFunction).
After our hook execution, (when you do return OriginalFuncPtr()) it jumps first to saved first 5 bytes of function, execute them, and then jumps back to original function code.
The problem with some call and jump instructions is they use address relative to the next statement, and we can't just move that instructions to another place without breaking the logic.

Originally mhook will just fail to hook functions with such instructions in the beggining.

Is there any drawback of such modification?

So the drawback of your modification is that you will call not original USER32.DestroyCaret after your hook, but something else instead. I would not recomend to do this.

I will investigate the case with DestroyCaret, most probably we will add the logic that fix relative addressing for calls.

Grivus added a commit that referenced this issue Feb 27, 2018
SergiusTheBest added a commit that referenced this issue Feb 27, 2018
Add ability to hook functions with call in first 5 bytes (#4)
@SergiusTheBest SergiusTheBest added this to the 2.5.1 milestone Feb 27, 2018
@SergiusTheBest
Copy link
Member

@rommar The issue should be fixed now. Please check the latest master.

@rommar
Copy link
Author

rommar commented Feb 28, 2018

@SergiusTheBest @Grivus Wow, you are so fast! I confirm that it is working now for both x86 and x64 builds. Thank you!

@rommar rommar closed this as completed Feb 28, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants