当前位置 博文首页 > KOOKNUT的博客:InlineHook--Ring3

    KOOKNUT的博客:InlineHook--Ring3

    作者:[db:作者] 时间:2021-07-02 21:28

    实现思路:
    使用GetProcAddress得到函数地址,将函数入口点的前5字节进行替换,使用e9指令进行跳转到Fake函数的地址,然后去执行挂钩函数。
    在程序的实现过程中注意的问题有两个:

    1. 保存源函数实现的前5字节指令,为了恢复钩子。
    2. e9指令后4字节的偏移计算
    	//e9指令后面的数据计算,就是跳转到当前地址加5字节偏移,加e9后面的偏移地址
    	//例如:00DB15E6 E9 A5 3B 00 00       jmp         Sub_1 (0DB5190h) 
    	//00DB15E6(当前地址) + 5 + 00003BA5 = 0DB5190h(目标地址)
    

    测试时候,使用远程线程注入的方式,在目标进程中启动远程线程去加载dll,然后去实现Hook。
    附上关键代码实现:

    #include"Dll.h"
    #include"HookApi_Jmp.h"
    
    CHookApi_Jmp MyHook;
    
    BOOL APIENTRY DllMain(HMODULE hModule,
    	DWORD  ul_reason_for_call,
    	LPVOID lpReserved
    )
    {
    	switch (ul_reason_for_call)
    	{
    	case DLL_PROCESS_ATTACH:
    	{
    		ExampleJmp();
    	}
    	case DLL_THREAD_ATTACH:
    	case DLL_THREAD_DETACH:
    	case DLL_PROCESS_DETACH:
    		break;
    	}
    	return TRUE;
    }
    int WINAPI JmpMessageBoxA(HWND hWnd, LPCTSTR lpText, LPCSTR lpCaption, UINT uType)
    {
    	int ReturnValue = 0;
    	MyHook.SetHookOff();//恢复之后,显示该弹窗消息
    	ReturnValue = MessageBoxA(hWnd, "Hooking MessageBox by Jmp", lpCaption, uType);
    	MyHook.SetHookOn();//继续hook
    	return ReturnValue;
    }
    void WINAPI ExampleJmp()
    {
    	//HookOneAPI保存挂钩函数的地址,替换E9指令
    	MyHook.HookOneAPI(_T("user32.dll"), "MessageBoxA", (FARPROC)JmpMessageBoxA);
    	//SetHookOn实现内存修改
    	MyHook.SetHookOn();
    }
    
    void CHookApi_Jmp::SetHookOn()
    {
    	DWORD OldFlag;
    	WriteProcessMemory(m_ProcessHandle, (void *)m_HookFunctionAddress,
    		(void *)m_NewJmp, 5, &OldFlag);
    }
    
    
    void CHookApi_Jmp::SetHookOff()
    {
    	DWORD OldFlag;
    	WriteProcessMemory(m_ProcessHandle, (void *)m_HookFunctionAddress,
    		(void *)m_OldCode, 5, &OldFlag);
    }
    
    
    void CHookApi_Jmp::HookOneAPI(LPCTSTR ModuleName,
    	LPCSTR ApiName, FARPROC FunctionAddress)
    {
    	m_HookFunctionAddress = GetProcAddress(GetModuleHandle(ModuleName), ApiName);
    	//m_HookFunctionAddress = user32.dll!0x755eea11 (加载符号以获取其他信息)
    	m_ProcessHandle = GetCurrentProcess();
    	m_NewJmp[0] = 0xe9;
    
    	memcpy(m_OldCode, (char *)m_HookFunctionAddress, 5);
    	//m_OldCode 0x0F91C2A0  8b ff 55 8b ec旧指令 前五字节
    	/*
    	8B FF                mov         edi,edi
    	55                   push        ebp
    	8B EC                mov         ebp,esp
    	*/
    	//jmp指令后面的数据计算,就是跳转到当前地址加5字节偏移,加jmp后面的偏移地址
    	//例如:00DB15E6 E9 A5 3B 00 00       jmp         Sub_1 (0DB5190h) 
    	//00DB15E6 + 5 + 00003BA5 = 0DB5190h
    	DWORD*  NewFunctionAddress;
    	NewFunctionAddress = (DWORD*)&m_NewJmp[1];
    	*NewFunctionAddress = (DWORD)FunctionAddress - (DWORD)m_HookFunctionAddress - 5;
    	//FunctionAddress = 0x0f91128a {Dll.dll!JmpMessageBoxA(struct HWND__ *, wchar_t const *, char const *, unsigned int)}
    	//m_HookFunctionAddress = user32.dll!0x755eea11 (加载符号以获取其他信息)
    	//*NewFunctionAddress = 0x9a322874;
    	//0x0F91C2A8  e9 74 28 32 9a
    }
    
    void _tmain()
    {
    	ULONG_PTR ProcessId = GetActiveProcessId("Test.exe");
    	CHAR DllFullPath[MAX_PATH] = { 0 };
    
    	if (ProcessId)
    	{
    		//打开目标进程,获得目标进程句柄
    		HANDLE ProcessHandle = KtOpenProcess(PROCESS_ALL_ACCESS, false, ProcessId);
    		if (ProcessHandle == NULL)
    		{
    			KtCloseHandle(ProcessHandle);
    		}
    
    		GetCurrentDirectory(MAX_PATH, DllFullPath);
    		strcat(DllFullPath, "\\Dll.dll");
    
    
    		StartHook(ProcessHandle, DllFullPath);
    	}
    	getchar();
    }
    BOOL StartHook(HANDLE ProcessHandle, CHAR* DllFullPath)
    {
    	BOOL IsOk = FALSE;
    	ULONG DllFullPathLength = 0;
    	DllFullPathLength = (strlen(DllFullPath) + 1);// '/0'
    	//目标进程空间中申请内存
    	LPVOID VirtualAddress = VirtualAllocEx(ProcessHandle, NULL,
    		DllFullPathLength, MEM_COMMIT, PAGE_READWRITE);
    	int LastError = GetLastError();
    	if (VirtualAddress == NULL)
    	{
    		KtCloseHandle(ProcessHandle);
    		return IsOk;
    	}
    	//目标进程空间中写入数据
    	if (KtProcessMemoryWriteSafe(ProcessHandle, VirtualAddress, DllFullPath,
    		DllFullPathLength, 0) == FALSE)
    	{
    		KtCloseHandle(ProcessHandle);
    		return IsOk;
    	}
    	HANDLE ThreadHandle = CreateRemoteThread(ProcessHandle,
    		NULL, 0, (LPTHREAD_START_ROUTINE)LoadLibrary,     //当前模块中导入函数
    		VirtualAddress, 0, NULL);
    	if (ThreadHandle == NULL)
    	{
    		VirtualFreeEx(ProcessHandle, VirtualAddress, DllFullPathLength, MEM_RELEASE);
    		return IsOk;
    	}
    
    	//等待远程线程结束
    	WaitForSingleObject(ThreadHandle, INFINITE);
    
    
    	if (VirtualAddress != NULL)
    	{
    		VirtualFreeEx(ProcessHandle, VirtualAddress, DllFullPathLength, MEM_RELEASE);
    
    	}
    	if (ProcessHandle)
    	{
    		KtCloseHandle(ProcessHandle);
    	}
    	IsOk = TRUE;
    	return IsOk;
    }
    

    测试程序:

    void _tmain()
    {
    	_tsetlocale(LC_ALL, _T("Chinese"));
    	MessageBoxA(NULL, "World", "Hello", 0);
    	printf("Print Anykey to confirme Hook\r\n");
    	getchar();
    	MessageBoxA(NULL, "World", "Hello", 0);
    }
    

    迟来的更新。。。最近确实有一些事情,没在家好好学习,也没有更新我的博客。青山不改,绿水长流。
    “When all the clouds darken up the skyway, there’s a rainbow highway to be found.
    当乌云密布,彩虹会为你铺就一条道路。”
    参考书籍:
    《Windows应用程序捆绑核心》

    cs