Hook是一个非常强大的技巧,利用Hook,不仅可以起到监控进程,做自己想做的事,而且可以利用hook来进行一些check。
给出下面的main函数:
#include <stdio.h>
#include <Windows.h>
#pragma warning(disable:4996)
//key : ccaaa
int main()
{
char s[256] = "\0";
if (NULL == LoadLibrary(L"F:\\桌面\\c语言\\HOOK_DLLLL\\Debug\\HOOK_DLLLL.dll")) {
printf("%d\n", GetLastError());
}
printf("input key : ");
scanf("%s", s);
MessageBoxW(0, L"win", L"yingyingying", MB_OK);
return 0;
}
例如我们可以Hook MessageBoxW,并将验证藏在MessageBoxW中,让它跟MessageBox的第一个参数的值挂钩,相应的dll代码如下:
// dllmain.cpp : 定义 DLL 应用程序的入口点。
#include "stdafx.h"
#include <stdio.h>
#include <stdlib.h>
typedef int(*TYPE_MessageBox)(HWND, LPCWSTR, LPCWSTR, UINT);
typedef void(*MyHookProc)();
WCHAR *lose = L"lose";
WCHAR *fail = L"fail";
BYTE temp[5];
TYPE_MessageBox funcAddr;
void RestoreHook()
{
int i;
for (i = 0; i < 5; i++) {
*((unsigned char *)funcAddr + i) = temp[i];
}
}
_declspec(naked) void MyHook()
{
_asm {//[ebp + 8]
push ebp
mov ebp, esp
mov eax, [ebp + 8] //get HWND
cmp eax, 1
je success //if success
mov eax, lose //替换第二个参数
mov [ebp + 12], eax //替换第三个参数
mov eax, fail
mov [ebp + 16], eax
success :
mov [ebp + 8], 0 //清零(NULL) 因为我们实际上并没有指定任何handle
call RestoreHook //恢复原本的MessageBoxW
mov esp,ebp
pop ebp
mov eax,funcAddr
jmp eax //跳到原本的函数执行
}
}
void MyHookMessageBox()
{
HMODULE hProc = NULL;
WCHAR *libName = L"user32.dll";
BYTE code[5] = {0xE9 };
DWORD oldProtect;
hProc = GetModuleHandle((LPCWSTR)libName);
if (!hProc) {
printf("%d\n", GetLastError());
}
funcAddr = (TYPE_MessageBox)GetProcAddress(hProc, "MessageBoxW");//获得函数地址
memcpy(temp, (void *)funcAddr, 5 * sizeof(BYTE));//保存原本
*((int *)(code + 1)) = (int)MyHook - (int)funcAddr - 5;//这里的jmp是相对跳转 不好理解的可以动手算一下
VirtualProtect(funcAddr, 5, PAGE_EXECUTE_READWRITE, &oldProtect);//代码页赋予写权限 因为我们要memcpy
memcpy(funcAddr, code, 5 * sizeof(BYTE));
VirtualProtect(funcAddr, 5, oldProtect, NULL);//恢复之前的页属性
}
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
MyHookMessageBox();
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
当我们运行程序时,正常来说应该是显示yingyingying的,但是被hook之后显示出了这个。
所以需要将主函数的MessageBoxW的第一个参数改为1。
其实我们可以在dll里再放置一个计数器;并在主函数里任意隐蔽位置执行n个MessageBox进行混淆和一个最终的验证flag值以用于最终验证,每调用一次MessageBox就增加一次计数器,我们可以自定义到达哪个值,会进行一次hook验证,如果不符合,最终的flag值就为false,然后恢复原本的MessageBoxW,接着正常执行,直到最后验证。我这里就简单的提示一下,等鄙人有时间再完善。