今天研究了一下HOOK 其他进程API的方法
有2个前提
1. 使用远程线程注入, 具体可以参考《Windows核心编程》中22-InjLib里面的代码
2. 更改被注入线程所要调用的API地址
2.1 方法一:实用一个网上一个大牛写的类CHookInfo
HookInfo.h
typedef struct _HOOKSTRUCT { FARPROC pfFunAddr; //用于保存API函数地址 BYTE OldCode[5]; //保存原API前5个字节 BYTE NewCode[5]; //JMP XXXX其中XXXXJMP的地址 }HOOKSTRUCT; class CHookInfo { public: CHookInfo(TCHAR *strDllName, char *strFunName, DWORD dwMyFunAddr); //HOOK 钩子的构造处理函数 //strDllName用于传入模块文件名 //strFunName用于传入模块里的函数名 //dwMyFunAddr用于传入处理函数的地址(代理函数的地址) virtual ~CHookInfo(); //HOOK 钩子的析构函数 HOOKSTRUCT *pHook; //HOOK结构 void HookStatus(BOOL blnHook); //关闭/打开HOOK状态 }; CHookInfo::CHookInfo(TCHAR *strDllName, char *strFunName, DWORD dwMyFunAddr) { pHook = new HOOKSTRUCT; HMODULE hModule = LoadLibrary(strDllName); //载入strDllName模块 //纪录函数地址 pHook-> pfFunAddr = GetProcAddress(hModule,strFunName); //在strDllName模块里检索strFunName函数的地址,GetProcAddress就是返回strFunName函数的地址 FreeLibrary(hModule); //卸载strDllName模块 if(pHook-> pfFunAddr == NULL) { return ; } //备份原函数的前5个字节,一般的WIN32 API以__stdcall声明的API理论上都可以这样进行HOOK (师傅的注释) memcpy(pHook->OldCode, pHook->pfFunAddr, 5); //memcpy:功能:由pHook-> pfFunAddr所指内存区域复制5个字节到pHook-> OldCode所指内存区域。说明:pHook-> pfFunAddr和pHook-> OldCode所指内存区域不能重叠,函数返回指向pHook-> OldCode的指针。 pHook->NewCode[0] = 0xe9; //构造JMP ,JMP(字节值:0xe9)是汇编指令:程序无条件转移指令 DWORD dwJmpAddr = dwMyFunAddr - (DWORD)pHook->pfFunAddr - 5; //计算JMP地址(我想这里是技术点!) memcpy(&pHook->NewCode[1], &dwJmpAddr, 4); HookStatus(TRUE);//开始进行HOOK } CHookInfo::~CHookInfo() { HookStatus(FALSE);//关闭HOOK恢复原函数 } void CHookInfo::HookStatus(BOOL blnHook) { if(blnHook) { WriteProcessMemory((HANDLE)-1, pHook-> pfFunAddr, pHook-> NewCode, 5, 0);//替换函数地址 : (HANDLE)-1进程的句柄,pHook-> pfFunAddr进程地址,pHook-> NewCode数据存放地址,5数据的长度,0实际数据的长度 } else { WriteProcessMemory((HANDLE)-1, pHook-> pfFunAddr, pHook-> OldCode, 5, 0);//还原函数地址 } }
//#pragma comment(lib,"th32.lib")
#include "..\CommonFiles\CmnHdr.h" /* See Appendix A. */
#include <tchar.h>
#include "trace.h"
#include "HookInfo.h"
#include <iostream>
using namespace std;
#include "windows.h"
#include "process.h"
#include "tlhelp32.h"
#include "stdio.h"
//#pragma comment(lib, "th32.lib")
PIMAGE_DOS_HEADER pDosHeader;
PIMAGE_NT_HEADERS pNTHeaders;
PIMAGE_OPTIONAL_HEADER pOptHeader;
PIMAGE_IMPORT_DESCRIPTOR pImportDescriptor;
PIMAGE_THUNK_DATA pThunkData;
PIMAGE_IMPORT_BY_NAME pImportByName;
HMODULE hMod;
// 定义MessageBoxA函数原型
typedef int (WINAPI *PFNMESSAGEBOX)(HWND, LPCSTR, LPCSTR, UINT uType);
int WINAPI MessageBoxProxy(IN HWND hWnd, IN LPCSTR lpText, IN LPCSTR lpCaption, IN UINT uType);
int * addr = (int *)MessageBoxW; //保存函数的入口地址
int * myaddr = (int *)MessageBoxProxy;
void ThreadProc(void *param);//线程函数
int WINAPI MyMessageBox(HWND hWnd, LPCWSTR lpText, LPCWSTR lpCaption, UINT uType)
{
wcout<<L"hWnd:"<<(int)hWnd<<endl;
wcout<<L"lpText:"<<lpText<<endl;
wcout<<L"lpCaption:"<<lpCaption<<endl;
wcout<<L"uType:"<<uType<<endl<<endl;
_TRACE(_T("嘿嘿! 调用了我的MessageBox了\n"));
return 0;
}
void TestTP();
//new messagebox function
int WINAPI MessageBoxProxy(IN HWND hWnd, IN LPCSTR lpText, IN LPCSTR lpCaption, IN UINT uType)
{
//return ((PFNMESSAGEBOX)addr)(NULL, "gxter_test", "gxter_title", 0);
//这个地方可以写出对这个API函数的处理代码
_TRACE(_T("哈哈!使用我的Dll了\n"));
return 1;
}
//-------------------------------------------------------主函数开始
BOOL WINAPI DllMain(HINSTANCE hinstDLL,DWORD fdwReason,LPVOID lpvReserved)
{
if (fdwReason == DLL_PROCESS_ATTACH) {
//_TRACE(_T("00\n"));
//_beginthread(ThreadProc,0,NULL);
//_TRACE(_T("11\n"));
//CHookInfo hookInfo(_T("User32.Dll"), "MessageBoxW", (DWORD)MyMessageBox);
TestTP();
while (1) {}
_TRACE(_T("22\n"));
}
return TRUE;
}
//结束进程的函数
void TestTP()
{
//------------hook api----------------
//_TRACE(_T("TR 00\n"));
hMod = GetModuleHandle(NULL);
//_TRACE(_T("TR 11\n"));
pDosHeader = (PIMAGE_DOS_HEADER)hMod;
pNTHeaders = (PIMAGE_NT_HEADERS)((BYTE *)hMod + pDosHeader->e_lfanew);
pOptHeader = (PIMAGE_OPTIONAL_HEADER)&(pNTHeaders->OptionalHeader);
pImportDescriptor = (PIMAGE_IMPORT_DESCRIPTOR)((BYTE *)hMod + pOptHeader->DataDirectory[1].VirtualAddress);
//_TRACE(_T("TR 22\n"));
while (pImportDescriptor->FirstThunk) {
_TRACE(_T("TR 33\n"));
char * dllname = (char *)((BYTE *)hMod + pImportDescriptor->Name);
TCHAR wszDomain[256];
MultiByteToWideChar(CP_ACP, 0, dllname,
strlen(dllname)+1, wszDomain, sizeof(wszDomain)/sizeof(wszDomain[0]));
//_TRACE(_T("%s\n"), wszDomain);
pThunkData = (PIMAGE_THUNK_DATA)((BYTE *)hMod + pImportDescriptor->OriginalFirstThunk);
int no = 1;
while (pThunkData->u1.Function) {
char * funname = (char *)((BYTE *)hMod + (DWORD)pThunkData->u1.AddressOfData + 2);
PDWORD lpAddr = (DWORD *)((BYTE *)hMod + (DWORD)pImportDescriptor->FirstThunk) + (no-1);
// 测试代码(HH)
TCHAR szUser32[] = _T("USER32.dll");
if (0 == memcmp(szUser32, wszDomain, sizeof(TCHAR)*2)) {
_TRACE(_T("*lpAdd:%X PK addr:%X\n"), *lpAddr, addr);
}
//修改内存的部分
if ((*lpAddr) == (int)addr) {
_TRACE(_T("MessageBoxW addr is : %X\n"), *lpAddr);
//修改内存页的属性
DWORD dwOLD;
MEMORY_BASIC_INFORMATION mbi;
VirtualQuery(lpAddr,&mbi,sizeof(mbi));
VirtualProtect(lpAddr,sizeof(DWORD),PAGE_READWRITE,&dwOLD);
WriteProcessMemory(GetCurrentProcess(),
lpAddr, &myaddr, sizeof(DWORD), NULL);
//恢复内存页的属性
//VirtualProtect(lpAddr,sizeof(DWORD),dwOLD,0);
}
//---------
no ++;
pThunkData++;
}
_TRACE(_T("%s有%d个函数\n"), wszDomain, no);
pImportDescriptor++;
}
_TRACE(_T("TR End\n"));
//-------------------HOOK END-----------------
}
还学到了一个知识就是,函数地址和函数参数是放在不同的位置的。
参数是放在独立的栈中的。而函数地址是放在另一个地方的,暂时学习就这么多。
以后有又明白的部分再添加。