有的时候,我们需要对程序读写文件的时候进行监控,尤其是文件的数据是保密的,而且不能直接存储在磁盘上。举个最简单的例子来说,当我们有个文件在磁盘上,而这个文件是加密的,这时候在程序打开文件的时候,通过输入密钥进行解密了,但是这些解密了的数据,是不能写回磁盘的,只能放在RAM中,这时候如果程序想通过正常的文件操作来访问数据的话,那么这就需要我们来对这个文件操作的API下钩子函数了。
对于钩子函数的介绍,可以通过下面的几篇文章来了解,前提是必须了解PE格式中的输入表区块内容。
1. http://zhidao.baidu.com/question/56417343.html
2. http://baike.baidu.com/view/1037259?wtp=tt-
3. http://zhidao.baidu.com/question/5555707.html
等等,百度上一大相关文章。
在网上看了不少这方面的资料,发现很多东西写的都好散,没有封装起来,因此我就花了点功夫,把它封装了起来,还没完全测试,先把代码共享一下,如果各位有什么bug的话,请留言,我会尽快改进的。
--------------------------------------------
------------- HooAPI.h -----------------
--------------------------------------------
#pragma once #include<vector> #include "Toolhelp.h" struct HookAPIEntry{ // 这个是模块的名字,比如usr32.dll CString strMoudleName ; // 这个是需要下钩子的API函数 CString strFunctionName ; // API函数的原始地址 PROC pOriginalProc ; // API函数的新地址 PROC pNewProc ; HookAPIEntry(){ pOriginalProc = pNewProc = NULL ; }; }; typedef HookAPIEntry * PHookAPIEntry ; typedef HookAPIEntry * LPHookAPIEntry ; typedef std::vector<PHookAPIEntry> HookAPIEntryList ; typedef HookAPIEntryList * PHookAPIEntryList ; typedef HookAPIEntryList * LPHookAPIEntryList ; typedef std::vector<PHookAPIEntry>::iterator HookAPIEntryPos ; class CHookAPI { public: CHookAPI(void); ~CHookAPI(void); public: // 对钩子函数列表的操作 HRESULT AddHookAPIEntry(const HookAPIEntry & entry ) ; HRESULT AddHookAPIEntry(CString strMoudleName,CString strFunctionName,PROC pNewProc) ; HRESULT FindHookAPIEntry(CString strMoudleName,CString strFunctionName,LPHookAPIEntry * pResult); HRESULT DeleteHookAPIEntry(CString strMoudleName,CString strFunctionName) ; HRESULT ClearAllAPIEntry( void ) ; HRESULT ReHookAllMoudleAPI( void ) ; HRESULT UnHookAllMoudleAPI( void ) ; HRESULT GetHookAPIEntryByNewAddress(PROC pNewAddress,LPHookAPIEntry * pResult) ; protected: HRESULT HookMoudleAPI(const HookAPIEntry & hookentry); HRESULT UnHookMoudleAPI(const HookAPIEntry & hookentry); HRESULT HookMoudleAPI(HMODULE hmoudle,const HookAPIEntry & hookentry); HRESULT UnHookMoudleAPI(HMODULE hmoudle,const HookAPIEntry & hookentry); HRESULT ReplaceMoudleAPI(HMODULE hmoudleCaller, const CString &strMoudleName, PROC pCurAddress,PROC pNewAddress); HRESULT GetProcessAddress(const CString &strMoudleName,const CString &strFunctionName, PROC * pAddress ) ; HRESULT UpdateOriginalProc( HookAPIEntry & hookentry); protected: // 需要下钩子的函数集合 HookAPIEntryList m_HookAPIEntryList ; // 系统的信息 SYSTEM_INFO m_si; };
--------------------------------------------
------------- HooAPI.cpp -----------------
--------------------------------------------
#include "StdAfx.h" #include "HookAPI.h" #include "Dbghelp.h" #pragma comment(lib , "imagehlp.lib") #pragma comment(lib , "Dbghelp.lib") CHookAPI::CHookAPI(void) { GetSystemInfo(&m_si) ; } CHookAPI::~CHookAPI(void) { } //// HRESULT CHookAPI::AddHookAPIEntry(const HookAPIEntry & entry ) { // 已经存在了,就不用添加了 if( S_OK == FindHookAPIEntry(entry.strMoudleName,entry.strFunctionName,NULL ) ) return S_FALSE ; LPHookAPIEntry pentry = new HookAPIEntry() ; * pentry = entry ; m_HookAPIEntryList.push_back(pentry) ; UpdateOriginalProc(*pentry) ; HookMoudleAPI(entry); return S_OK ; } HRESULT CHookAPI::AddHookAPIEntry(CString strMoudleName,CString strFunctionName,PROC pNewProc) { if( S_OK == FindHookAPIEntry(strMoudleName,strFunctionName,NULL ) ) return S_FALSE ; LPHookAPIEntry pentry = new HookAPIEntry() ; pentry->strMoudleName = strMoudleName ; pentry->strFunctionName = strFunctionName ; pentry->pNewProc = pNewProc ; m_HookAPIEntryList.push_back(pentry) ; UpdateOriginalProc(*pentry) ; HookMoudleAPI(*pentry); return S_OK ; } HRESULT CHookAPI::FindHookAPIEntry(CString strMoudleName,CString strFunctionName,LPHookAPIEntry * pResult){ HookAPIEntryPos pos ; for( pos = m_HookAPIEntryList.begin(); pos != m_HookAPIEntryList.end() ; pos ++ ){ PHookAPIEntry pHookAPIEntry = * pos ; if( NULL != pHookAPIEntry && pHookAPIEntry->strMoudleName.CompareNoCase(strMoudleName) == 0 && pHookAPIEntry->strFunctionName.Compare(strFunctionName) == 0 ){ // 已经找到了 if( pResult == NULL ) * pResult = pHookAPIEntry ; return S_OK ; } }; return S_FALSE ; } HRESULT CHookAPI::DeleteHookAPIEntry(CString strMoudleName,CString strFunctionName) { HookAPIEntryPos pos ; for( pos = m_HookAPIEntryList.begin(); pos != m_HookAPIEntryList.end() ; pos ++ ){ PHookAPIEntry pHookAPIEntry = * pos ; if( NULL != pHookAPIEntry && pHookAPIEntry->strMoudleName.CompareNoCase(strMoudleName) == 0 && pHookAPIEntry->strFunctionName.Compare(strFunctionName) == 0 ){ // 已经找到了 UnHookMoudleAPI(*pHookAPIEntry) ; m_HookAPIEntryList.erase(pos) ; delete pHookAPIEntry ; pHookAPIEntry = NULL ; return S_OK ; } }; return S_OK ; } HRESULT CHookAPI::ClearAllAPIEntry( void ) { UnHookAllMoudleAPI() ; HookAPIEntryPos pos ; PHookAPIEntry pHookAPIEntry = NULL ; while( m_HookAPIEntryList.size() > 0 ) { pos = m_HookAPIEntryList.begin() ; pHookAPIEntry = * pos ; m_HookAPIEntryList.erase(pos) ; if( NULL == pHookAPIEntry ){ delete pHookAPIEntry ; pHookAPIEntry = NULL ; } } return S_OK ; } HRESULT CHookAPI::GetHookAPIEntryByNewAddress(PROC pNewAddress,LPHookAPIEntry * pResult ) { HookAPIEntryPos pos ; for( pos = m_HookAPIEntryList.begin(); pos != m_HookAPIEntryList.end() ; pos ++ ){ PHookAPIEntry pHookAPIEntry = * pos ; if( NULL != pHookAPIEntry && pHookAPIEntry->pNewProc == pNewAddress){ // 已经找到了 if( NULL != pResult ){ * pResult = * pos ; return S_OK ; } } }; return S_FALSE ; } HRESULT CHookAPI::UpdateOriginalProc( HookAPIEntry & hookentry){ if(S_OK != GetProcessAddress(hookentry.strMoudleName, hookentry.strFunctionName,&hookentry.pOriginalProc)){ ASSERT(FALSE) ; return S_FALSE ; } if (hookentry.pOriginalProc > m_si.lpMaximumApplicationAddress) { PBYTE pb = (PBYTE) hookentry.pOriginalProc; if (pb[0] == 0x86){ PVOID pv = * (PVOID*) &pb[1]; hookentry.pOriginalProc = (PROC) pv; } } return S_OK ; } HRESULT CHookAPI::GetProcessAddress(const CString &strMoudleName,const CString&strFunctionName,FARPROC * pAddress ){ * pAddress = ::GetProcAddress(GetModuleHandle(strMoudleName), strFunctionName) ; return S_OK ; } HRESULT CHookAPI::ReHookAllMoudleAPI( void ) { CToolhelp th(TH32CS_SNAPMODULE, GetCurrentProcessId()); MODULEENTRY32 me = { sizeof(me) }; for (BOOL fOk = th.ModuleFirst(&me); fOk; fOk = th.ModuleNext(&me)) { //TRACE(me.szModule); // 监控所有的有关文件读写情况 HookAPIEntryPos pos ; for( pos = m_HookAPIEntryList.begin(); pos != m_HookAPIEntryList.end() ; pos ++ ){ PHookAPIEntry pHookAPIEntry = * pos ; if(pHookAPIEntry == NULL ){ ASSERT(FALSE) ; continue ; } // 重新获取一下原来的地址 if( pHookAPIEntry->pOriginalProc == NULL ){ if(S_OK != UpdateOriginalProc(*pHookAPIEntry)){ ASSERT(FALSE) ; continue ; } } // 对所有模块的输入表进行替换 HookMoudleAPI(me.hModule,*pHookAPIEntry) ; } }; return S_OK ; } HRESULT CHookAPI::UnHookAllMoudleAPI( void ) { CToolhelp th(TH32CS_SNAPMODULE, GetCurrentProcessId()); MODULEENTRY32 me = { sizeof(me) }; for (BOOL fOk = th.ModuleFirst(&me); fOk; fOk = th.ModuleNext(&me)) { //TRACE(me.szModule); // 监控所有的有关文件读写情况 HookAPIEntryPos pos ; for( pos = m_HookAPIEntryList.begin(); pos != m_HookAPIEntryList.end() ; pos ++ ){ PHookAPIEntry pHookAPIEntry = * pos ; if(pHookAPIEntry == NULL ){ ASSERT(FALSE) ; continue ; } // 重新获取一下原来的地址 if( pHookAPIEntry->pOriginalProc == NULL ){ if(S_OK != UpdateOriginalProc(*pHookAPIEntry)){ ASSERT(FALSE) ; continue ; } } // 对所有模块的输入表进行替换 UnHookMoudleAPI(me.hModule,*pHookAPIEntry) ; } }; return S_OK ; } HRESULT CHookAPI::HookMoudleAPI(const HookAPIEntry & hookentry){ CToolhelp th(TH32CS_SNAPMODULE, GetCurrentProcessId()); MODULEENTRY32 me = { sizeof(me) }; for (BOOL fOk = th.ModuleFirst(&me); fOk; fOk = th.ModuleNext(&me)) { //TRACE(me.szModule); // 监控所有的有关文件读写情况 HookMoudleAPI(me.hModule,hookentry) ; }; return S_OK ; } HRESULT CHookAPI::HookMoudleAPI(HMODULE hmoudle,const HookAPIEntry & hookentry){ return ReplaceMoudleAPI(hmoudle,hookentry.strMoudleName,hookentry.pOriginalProc,hookentry.pNewProc); } HRESULT CHookAPI::UnHookMoudleAPI(const HookAPIEntry & hookentry){ CToolhelp th(TH32CS_SNAPMODULE, GetCurrentProcessId()); MODULEENTRY32 me = { sizeof(me) }; for (BOOL fOk = th.ModuleFirst(&me); fOk; fOk = th.ModuleNext(&me)) { //TRACE(me.szModule); // 监控所有的有关文件读写情况 UnHookMoudleAPI(me.hModule,hookentry) ; }; return S_OK ; } HRESULT CHookAPI::UnHookMoudleAPI(HMODULE hmoudle,const HookAPIEntry & hookentry){ return ReplaceMoudleAPI(hmoudle,hookentry.strMoudleName,hookentry.pNewProc,hookentry.pOriginalProc); } HRESULT CHookAPI::ReplaceMoudleAPI(HMODULE hmoduleCaller, const CString &strMoudleName, PROC pCurAddress,PROC pNewAddress){ // 找到的IAT表 ULONG lsize = 0 ; PIMAGE_SECTION_HEADER psecHeader ; PIMAGE_IMPORT_DESCRIPTOR pImportDesc = (PIMAGE_IMPORT_DESCRIPTOR) ImageDirectoryEntryToDataEx(hmoduleCaller,TRUE,IMAGE_DIRECTORY_ENTRY_IMPORT,&lsize,&psecHeader); if( pImportDesc == NULL ){ // ASSERT(FALSE) ; return S_FALSE ; } // 找输入表的相应的模块 while( pImportDesc->Name != 0){ // RVA CString strdllname = (PSTR)((PBYTE)hmoduleCaller + pImportDesc->Name); if( strdllname.CompareNoCase(strMoudleName) == 0 ) break ; pImportDesc ++ ; } if( pImportDesc->Name == 0){ //ASSERT(FALSE) ; return S_FALSE ; } // 找输入表的函数地址,FirstThunk为RVA PIMAGE_THUNK_DATA pThunk=(PIMAGE_THUNK_DATA)((PBYTE)hmoduleCaller + pImportDesc->FirstThunk); PROC* ppfn; while( pThunk->u1.Function != 0 ){ ppfn = (PROC*)&pThunk->u1.Function; if( *ppfn == pCurAddress ){ // 找到了这个输入表中的函数地址,将其修改一下 MEMORY_BASIC_INFORMATION mbi; VirtualQuery(ppfn,&mbi,sizeof(MEMORY_BASIC_INFORMATION)); VirtualProtect(mbi.BaseAddress,mbi.RegionSize,PAGE_READWRITE,&mbi.Protect); *ppfn=*pNewAddress; DWORD dwOldProtect; VirtualProtect(mbi.BaseAddress,mbi.RegionSize,mbi.Protect,&dwOldProtect); return S_OK ; } pThunk ++ ; } return S_OK ; }
--------------------------------------------
------------- ToolHelp.h -----------------
--------------------------------------------
#pragma once #include "stdafx.h" /////////////////////////////////////////////////////////////////////////////// #include <tlhelp32.h> #include <tchar.h> #define chINRANGE(low, Num, High) (((low) <= (Num)) && ((Num) <= (High))) /////////////////////////////////////////////////////////////////////////////// class CToolhelp { private: HANDLE m_hSnapshot; public: CToolhelp(DWORD dwFlags = 0, DWORD dwProcessID = 0); ~CToolhelp(); BOOL CreateSnapshot(DWORD dwFlags, DWORD dwProcessID = 0); BOOL ProcessFirst(PPROCESSENTRY32 ppe) const; BOOL ProcessNext(PPROCESSENTRY32 ppe) const; BOOL ProcessFind(DWORD dwProcessId, PPROCESSENTRY32 ppe) const; BOOL ModuleFirst(PMODULEENTRY32 pme) const; BOOL ModuleNext(PMODULEENTRY32 pme) const; BOOL ModuleFind(PVOID pvBaseAddr, PMODULEENTRY32 pme) const; BOOL ModuleFind(PTSTR pszModName, PMODULEENTRY32 pme) const; BOOL ThreadFirst(PTHREADENTRY32 pte) const; BOOL ThreadNext(PTHREADENTRY32 pte) const; BOOL HeapListFirst(PHEAPLIST32 phl) const; BOOL HeapListNext(PHEAPLIST32 phl) const; int HowManyHeaps() const; // Note: The heap block functions do not reference a snapshot and // just walk the process's heap from the beginning each time. Infinite // loops can occur if the target process changes its heap while the // functions below are enumerating the blocks in the heap. BOOL HeapFirst(PHEAPENTRY32 phe, DWORD dwProcessID, UINT_PTR dwHeapID) const; BOOL HeapNext(PHEAPENTRY32 phe) const; int HowManyBlocksInHeap(DWORD dwProcessID, DWORD dwHeapId) const; BOOL IsAHeap(HANDLE hProcess, PVOID pvBlock, PDWORD pdwFlags) const; public: static BOOL EnableDebugPrivilege(BOOL fEnable = TRUE); static BOOL ReadProcessMemory(DWORD dwProcessID, LPCVOID pvBaseAddress, PVOID pvBuffer, DWORD cbRead, PDWORD pdwNumberOfBytesRead = NULL); };
--------------------------------------------
------------- ToolHelp.cpp -----------------
--------------------------------------------
/////////////////////////////////////////////////////////////////////////////// inline CToolhelp::CToolhelp(DWORD dwFlags, DWORD dwProcessID) { m_hSnapshot = INVALID_HANDLE_VALUE; CreateSnapshot(dwFlags, dwProcessID); } /////////////////////////////////////////////////////////////////////////////// inline CToolhelp::~CToolhelp() { if (m_hSnapshot != INVALID_HANDLE_VALUE) CloseHandle(m_hSnapshot); } /////////////////////////////////////////////////////////////////////////////// inline int CToolhelp::CreateSnapshot(DWORD dwFlags, DWORD dwProcessID) { if (m_hSnapshot != INVALID_HANDLE_VALUE) CloseHandle(m_hSnapshot); if (dwFlags == 0) { m_hSnapshot = INVALID_HANDLE_VALUE; } else { m_hSnapshot = CreateToolhelp32Snapshot(dwFlags, dwProcessID); } return(m_hSnapshot != INVALID_HANDLE_VALUE); } /////////////////////////////////////////////////////////////////////////////// inline BOOL CToolhelp::EnableDebugPrivilege(BOOL fEnable) { // Enabling the debug privilege allows the application to see // information about service applications BOOL fOk = FALSE; // Assume function fails HANDLE hToken; // Try to open this process's access token if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken)) { // Attempt to modify the "Debug" privilege TOKEN_PRIVILEGES tp; tp.PrivilegeCount = 1; LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &tp.Privileges[0].Luid); tp.Privileges[0].Attributes = fEnable ? SE_PRIVILEGE_ENABLED : 0; AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(tp), NULL, NULL); fOk = (GetLastError() == ERROR_SUCCESS); CloseHandle(hToken); } return(fOk); } /////////////////////////////////////////////////////////////////////////////// inline BOOL CToolhelp::ReadProcessMemory(DWORD dwProcessID, LPCVOID pvBaseAddress, PVOID pvBuffer, DWORD cbRead, PDWORD pdwNumberOfBytesRead) { return(Toolhelp32ReadProcessMemory(dwProcessID, pvBaseAddress, pvBuffer, cbRead, pdwNumberOfBytesRead)); } /////////////////////////////////////////////////////////////////////////////// inline BOOL CToolhelp::ProcessFirst(PPROCESSENTRY32 ppe) const { BOOL fOk = Process32First(m_hSnapshot, ppe); if (fOk && (ppe->th32ProcessID == 0)) fOk = ProcessNext(ppe); // Remove the "[System Process]" (PID = 0) return(fOk); } inline BOOL CToolhelp::ProcessNext(PPROCESSENTRY32 ppe) const { BOOL fOk = Process32Next(m_hSnapshot, ppe); if (fOk && (ppe->th32ProcessID == 0)) fOk = ProcessNext(ppe); // Remove the "[System Process]" (PID = 0) return(fOk); } inline BOOL CToolhelp::ProcessFind(DWORD dwProcessId, PPROCESSENTRY32 ppe) const { BOOL fFound = FALSE; for (BOOL fOk = ProcessFirst(ppe); fOk; fOk = ProcessNext(ppe)) { fFound = (ppe->th32ProcessID == dwProcessId); if (fFound) break; } return(fFound); } /////////////////////////////////////////////////////////////////////////////// inline BOOL CToolhelp::ModuleFirst(PMODULEENTRY32 pme) const { return(Module32First(m_hSnapshot, pme)); } inline BOOL CToolhelp::ModuleNext(PMODULEENTRY32 pme) const { return(Module32Next(m_hSnapshot, pme)); } inline BOOL CToolhelp::ModuleFind(PVOID pvBaseAddr, PMODULEENTRY32 pme) const { BOOL fFound = FALSE; for (BOOL fOk = ModuleFirst(pme); fOk; fOk = ModuleNext(pme)) { fFound = (pme->modBaseAddr == pvBaseAddr); if (fFound) break; } return(fFound); } inline BOOL CToolhelp::ModuleFind(PTSTR pszModName, PMODULEENTRY32 pme) const { BOOL fFound = FALSE; for (BOOL fOk = ModuleFirst(pme); fOk; fOk = ModuleNext(pme)) { fFound = (lstrcmpi(pme->szModule, pszModName) == 0) || (lstrcmpi(pme->szExePath, pszModName) == 0); if (fFound) break; } return(fFound); } /////////////////////////////////////////////////////////////////////////////// inline BOOL CToolhelp::ThreadFirst(PTHREADENTRY32 pte) const { return(Thread32First(m_hSnapshot, pte)); } inline BOOL CToolhelp::ThreadNext(PTHREADENTRY32 pte) const { return(Thread32Next(m_hSnapshot, pte)); } /////////////////////////////////////////////////////////////////////////////// inline int CToolhelp::HowManyHeaps() const { int nHowManyHeaps = 0; HEAPLIST32 hl = { sizeof(hl) }; for (BOOL fOk = HeapListFirst(&hl); fOk; fOk = HeapListNext(&hl)) nHowManyHeaps++; return(nHowManyHeaps); } inline int CToolhelp::HowManyBlocksInHeap(DWORD dwProcessID, DWORD dwHeapID) const { int nHowManyBlocksInHeap = 0; HEAPENTRY32 he = { sizeof(he) }; BOOL fOk = HeapFirst(&he, dwProcessID, dwHeapID); for (; fOk; fOk = HeapNext(&he)) nHowManyBlocksInHeap++; return(nHowManyBlocksInHeap); } inline BOOL CToolhelp::HeapListFirst(PHEAPLIST32 phl) const { return(Heap32ListFirst(m_hSnapshot, phl)); } inline BOOL CToolhelp::HeapListNext(PHEAPLIST32 phl) const { return(Heap32ListNext(m_hSnapshot, phl)); } inline BOOL CToolhelp::HeapFirst(PHEAPENTRY32 phe, DWORD dwProcessID, UINT_PTR dwHeapID) const { return(Heap32First(phe, dwProcessID, dwHeapID)); } inline BOOL CToolhelp::HeapNext(PHEAPENTRY32 phe) const { return(Heap32Next(phe)); } inline BOOL CToolhelp::IsAHeap(HANDLE hProcess, PVOID pvBlock, PDWORD pdwFlags) const { HEAPLIST32 hl = { sizeof(hl) }; for (BOOL fOkHL = HeapListFirst(&hl); fOkHL; fOkHL = HeapListNext(&hl)) { HEAPENTRY32 he = { sizeof(he) }; BOOL fOkHE = HeapFirst(&he, hl.th32ProcessID, hl.th32HeapID); for (; fOkHE; fOkHE = HeapNext(&he)) { MEMORY_BASIC_INFORMATION mbi; VirtualQueryEx(hProcess, (PVOID) he.dwAddress, &mbi, sizeof(mbi)); if (chINRANGE(mbi.AllocationBase, pvBlock, (PBYTE) mbi.AllocationBase + mbi.RegionSize)) { *pdwFlags = hl.dwFlags; return(TRUE); } } } return(FALSE); }
//////////////////////////////// End of File //////////////////////////////////
Jekkay Hu,胡杨
2010-12-18