您的位置:首页 > 其它

VC进程相关的学习(四)(API截获)

2010-08-21 16:02 441 查看
0 PE文件(.exe)

a 一开始是一段Dos程序,就是那个“必须运行在XXX环境”的警告头(IMAGE_DOS_SIGNATURE)。

b 接着这个DOS头,首先是IMAGE_NT_HEADER,都是一些PE文件信息,在它的尾端是Data Directory数据表,能快速决定PE的段(section)地址。

c 下来是IMAGE_SECTION_HEADER的列表,记录着每一个段的信息。

d 再下来就是段数据,执行代码,数据资源那些东东了。
这些东西会放在地址0x400000的地方,就是Histance的值,程序开始的位置。

在这些段里,有一个".idata"段(输入数据段),该地方有着IAT,加载的DLL的API都在这里,大概像这个样子:
JWP DWORD PTR [XXXXXXXXX]
或者
CALL DWORD PTR [XXXXXXXXX]
这里面的XXXXXXXX,就是系统API所在的位置,所以我们要做的就是,把XXXXXXXX改成我们的函数地址,执行完我们的函数再杀回来就好了。

导入地址表(IAT):Import Address Table 由于导入函数就是被程序调用但其执行代码又不在程序中的函数,这些函数的代码位于一个或者多个DLL 中.当PE文件被装入内存的时候,Windows装载器才将DLL装入,并将调用导入函数的指令和函数实际所处的地址联系起来(动态连接),这操作就需要导入表完成,其中导入地址表就指示函数实际地址。

1 程序指令内存空间的写入

因为指令空间有Windows的保护,不能直接指针指过去修改,需要如下操作

void MyHook::_writeProcessMemorySystem(LPVOID pDec, LPVOID pSrc, UINT nLength)
{
MEMORY_BASIC_INFORMATION mbi_thunk;
VirtualQuery(pDec, &mbi_thunk, sizeof(MEMORY_BASIC_INFORMATION));									// 查询页信息
VirtualProtect(mbi_thunk.BaseAddress, mbi_thunk.RegionSize, PAGE_READWRITE, &mbi_thunk.Protect);	// 改变页的保护信息为读写
memcpy(pDec, pSrc, nLength);
DWORD dwOldProtect;
VirtualProtect(mbi_thunk.BaseAddress, mbi_thunk.RegionSize, mbi_thunk.Protect, &dwOldProtect);		// 恢复保护属性
}


2 查找DLL模块的IAT

PIMAGE_IMPORT_DESCRIPTOR MyHook::_locationIAT(string strImportMod)
{
// 检查是否为DOS程序,DOS程序没有IAT
PIMAGE_DOS_HEADER pDosHeader = static_cast<PIMAGE_DOS_HEADER>(_handle);
if(pDosHeader->e_magic != IMAGE_DOS_SIGNATURE)
{
return NULL;
}
// 检查是否为NT程序
PIMAGE_NT_HEADERS pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)pDosHeader + (DWORD)(pDosHeader->e_lfanew));
if(pNTHeader->Signature != IMAGE_NT_SIGNATURE)
{
return NULL;
}
// 检查是否有IAT
if(pNTHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress == 0)
{
return NULL;
}
// 定位第一个IAT
PIMAGE_IMPORT_DESCRIPTOR pImportDesc = (PIMAGE_IMPORT_DESCRIPTOR)((DWORD)pDosHeader + (DWORD)(pNTHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress));
while(pImportDesc->Name)
{
// 如果有名字,获取其名字
PSTR szCurrMod = (PSTR)((DWORD)pDosHeader + (DWORD)(pImportDesc->Name));
if(stricmp(szCurrMod, strImportMod.c_str()) == 0)
{
// 找到了就停下来
break;
}
pImportDesc++;
}
if(pImportDesc->Name == NULL)
{
return NULL;
}
return pImportDesc;
}


3 查找IAT中的函数

OOL MyHook::hookAPIByName(std::string strImportMod, MyHook::HOOKAPI *pHookApi)
{
_handle = g_hInstance;
if(_state == MYHOOK_NULL)
{
return FALSE;
}
PIMAGE_IMPORT_DESCRIPTOR pImportDesc = _locationIAT(strImportMod);
if(pImportDesc == NULL)
{
return FALSE;
}

PIMAGE_THUNK_DATA pOrigThunk = (PIMAGE_THUNK_DATA)((DWORD)_handle + (DWORD)(pImportDesc->OriginalFirstThunk));	// 第一个THUNK
PIMAGE_THUNK_DATA pRealThunk = (PIMAGE_THUNK_DATA)((DWORD)_handle + (DWORD)(pImportDesc->FirstThunk));			// 第一个IAT的THUNK

// 查找IAT,替换函数
while(pOrigThunk->u1.Function)
{
// 检查此THUNK是否为IAT项
if((pOrigThunk->u1.Ordinal & IMAGE_ORDINAL_FLAG) != IMAGE_ORDINAL_FLAG)
{
// 获取此IAT的函数名
PIMAGE_IMPORT_BY_NAME pByName = (PIMAGE_IMPORT_BY_NAME)((DWORD)_handle + (DWORD)(pOrigThunk->u1.AddressOfData));
if(pByName->Name[0] == '/0')
{
return FALSE;
}
// 检测是否为所找的函数
if(stricmp(pHookApi->strFunctionName.c_str(), (char*)pByName->Name) == 0)
{
if(pHookApi->pOldFunc != NULL)
{
pHookApi->pOldFunc = (PROC)pRealThunk->u1.Function;
}
_writeProcessMemorySystem((LPVOID)&(pRealThunk->u1.Function), (LPVOID)&(pHookApi->pNewFunc), sizeof(DWORD));
Funs[pHookApi->strFunctionName] = *pHookApi;
}
}
pOrigThunk++;
pRealThunk++;
}
SetLastError(ERROR_SUCCESS);
return TRUE;
}


4 使用范例

typedef int(WINAPI *Mb)(HWND, LPCSTR, LPCSTR, UINT);
static int WINAPI MessageBoxA1(HWND hWnd, LPCSTR p1, LPCSTR p2, UINT uType)
{
Mb func = (Mb)(MyHook::instance().Funs["MessageBoxA"].pOldFunc);
return func(hWnd, "HOOK", "HOOK", uType);
}

VARIANT_BOOL  STDMETHODCALLTYPE CMyRock::OnMouseClick(IHTMLEventObj* _pEvtObj)
{
// IHTMLEventObj里包括了当前所有操作信息,具体按F1吧
// 如果VARIANT_FALSE将忽略此事件
MyHook::HOOKAPI api;
api.strFunctionName = std::string("MessageBoxA");
api.pNewFunc = (PROC)MessageBoxA1;
MyHook::instance().hookAPIByName("user32.dll", &api);
MessageBoxA(NULL, "1111111111111111", "1111111111111111111", 0);
return VARIANT_TRUE;
}


5 注意:通过IE测试发现,此种方法只能获取用Depneds看到在上面加载的DLL,而后来加载的,以及DLL加载的DLL都是无法获得的。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: