ApiHook.cpp
上传用户:jstlsd
上传日期:2007-01-13
资源大小:186k
文件大小:29k
源码类别:

钩子与API截获

开发平台:

Visual C++

  1. //---------------------------------------------------------------------------
  2. //
  3. // ApiHook.cpp
  4. //
  5. // SUBSYSTEM: 
  6. // API Hooking system
  7. // MODULE:    
  8. // ApiHook is the main module of the hooking system
  9. //
  10. // DESCRIPTION:
  11. //
  12. // AUTHOR: Ivo Ivanov (ivopi@hotmail.com) 
  13. //              Some part of ReplaceInOneModule() implementation is based 
  14. //              on code published by Jeffrey Richter and John Robbins.
  15. //
  16. // DATE: 2000 May 05,  version 1.0 
  17. //              2001 June 29, version 2.0
  18. //              2002 November 30. version 2.1
  19. //
  20. // FIXES:
  21. //              - 2002 May 08
  22. //                Fixed bug that used to cause an access violation 
  23. //                if a hooked application calls GetProcAddress() API with an 
  24. //                ordinal value rather than string function name. For more 
  25. //                details see the implementation of 
  26. //                CHookedFunction* CHookedFunctions::GetHookedFunction( 
  27. //                    PCSTR pszCalleeModName, PCSTR pszFuncName )
  28. //              - 2002 July 25
  29. //                In the implementation of CApiHookMgr::AddHook() method
  30. //                a newly created object CHookedFunction must be always inserted 
  31. //                in the collection, even the HookImport() method returns FALSE. 
  32. //                This solve the problem with dynamically imported functions that 
  33. //                haven't been found in the IAT during the initial call to AddHook() 
  34. //              - 2002 August 27
  35. //                Fixed bug related to storing incorrect values of the full path 
  36. //                name of the DLL in the map. In fact we need to get only the name 
  37. //                and extension parts of the full file name.
  38. //              - 2002 November 30
  39. //                Added two methods of class CHookedFunctions 
  40. //                (GetFunctionNameFromExportSection() and GetFunctionNameByOrdinal()) 
  41. //                for handling scenarios where the function for spying is imported by 
  42. //                number. This should allow a user of the library to easily intercept 
  43. //                Windows socket APIs that are usually imported by ordinal value.
  44. //                Added critical section in CApiHookMgr::MyGetProcAddress() method 
  45. //                                                                         
  46. //---------------------------------------------------------------------------
  47. //---------------------------------------------------------------------------
  48. //
  49. // Includes
  50. //  
  51. //---------------------------------------------------------------------------
  52. #include "..CommonCommon.h"
  53. #include "ApiHook.h"
  54. #include "..CommonSysUtils.h"
  55. #include "..CommonLockMgr.h"
  56. #include "..CommonCustomMessages.h"
  57. #include <imagehlp.h>
  58. #pragma comment(lib, "imagehlp.lib")
  59. #include "ModuleScope.h"
  60. //---------------------------------------------------------------------------
  61. //
  62. // class CApiHookMgr
  63. //  
  64. //---------------------------------------------------------------------------
  65. //---------------------------------------------------------------------------
  66. //
  67. // File scope constants and typedefs
  68. //
  69. //---------------------------------------------------------------------------
  70. typedef struct 
  71. {
  72. char szCalleeModName[MAX_PATH]; 
  73. char szFuncName[MAX_PATH];
  74. } API_FUNC_ID;
  75. const API_FUNC_ID MANDATORY_API_FUNCS[] =
  76. {
  77. {"Kernel32.dll", "LoadLibraryA"},
  78. {"Kernel32.dll", "LoadLibraryW"},
  79. {"Kernel32.dll", "LoadLibraryExA"},
  80. {"Kernel32.dll", "LoadLibraryExW"},
  81. {"Kernel32.dll", "GetProcAddress"}
  82. };
  83. // This macro evaluates to the number of elements in MANDATORY_API_FUNCS
  84. #define NUMBER_OF_MANDATORY_API_FUNCS (sizeof(MANDATORY_API_FUNCS) / sizeof(MANDATORY_API_FUNCS[0])) 
  85. //---------------------------------------------------------------------------
  86. //
  87. // Static members
  88. //
  89. //---------------------------------------------------------------------------
  90. CModuleScope*     CApiHookMgr::sm_pModuleScope     = NULL;
  91. CHookedFunctions* CApiHookMgr::sm_pHookedFunctions = NULL;
  92. CCSWrapper        CApiHookMgr::sm_CritSec;
  93. //---------------------------------------------------------------------------
  94. // CApiHookMgr
  95. // 
  96. // Ctor
  97. //---------------------------------------------------------------------------
  98. CApiHookMgr::CApiHookMgr(
  99. CModuleScope* pModuleScope
  100. )
  101. {
  102. sm_pModuleScope = pModuleScope;
  103. //
  104. // Obtain the handle to the DLL which code executes
  105. //
  106. m_hmodThisInstance   = ModuleFromAddress(CApiHookMgr::MyGetProcAddress);
  107. //
  108. // No system functions have been hooked up yet
  109. //
  110. m_bSystemFuncsHooked = FALSE;
  111. //
  112. // Create an instance of the map container
  113. //
  114. sm_pHookedFunctions  = new CHookedFunctions(this); 
  115. }
  116. //---------------------------------------------------------------------------
  117. // ~CApiHookMgr
  118. // 
  119. // Dtor
  120. //---------------------------------------------------------------------------
  121. CApiHookMgr::~CApiHookMgr()
  122. {
  123. UnHookAllFuncs();
  124. delete sm_pHookedFunctions;
  125. }
  126. //---------------------------------------------------------------------------
  127. // HookSystemFuncs
  128. // 
  129. // Hook all needed system functions in order to trap loading libraries
  130. //---------------------------------------------------------------------------
  131. BOOL CApiHookMgr::HookSystemFuncs()
  132. {
  133. BOOL bResult;
  134. if (TRUE != m_bSystemFuncsHooked)
  135. {
  136. bResult = HookImport(
  137. "Kernel32.dll", 
  138. "LoadLibraryA", 
  139. (PROC) CApiHookMgr::MyLoadLibraryA
  140. );
  141. bResult = HookImport(
  142. "Kernel32.dll", 
  143. "LoadLibraryW",
  144. (PROC) CApiHookMgr::MyLoadLibraryW
  145. ) || bResult;
  146. bResult = HookImport(
  147. "Kernel32.dll", 
  148. "LoadLibraryExA",
  149. (PROC) CApiHookMgr::MyLoadLibraryExA
  150. ) || bResult;
  151. bResult = HookImport(
  152. "Kernel32.dll", 
  153. "LoadLibraryExW",
  154. (PROC) CApiHookMgr::MyLoadLibraryExW
  155. ) || bResult;
  156. bResult = HookImport(
  157. "Kernel32.dll", 
  158. "GetProcAddress",
  159. (PROC) CApiHookMgr::MyGetProcAddress
  160. ) || bResult;
  161. m_bSystemFuncsHooked = bResult;
  162. } // if
  163. return m_bSystemFuncsHooked;
  164. }
  165. //---------------------------------------------------------------------------
  166. // UnHookAllFuncs
  167. // 
  168. // Unhook all functions and restore original ones
  169. //---------------------------------------------------------------------------
  170. void CApiHookMgr::UnHookAllFuncs()
  171. {
  172. if (TRUE == m_bSystemFuncsHooked)
  173. {
  174. CHookedFunction* pHook;
  175. CHookedFunctions::const_iterator itr;
  176. for (itr = sm_pHookedFunctions->begin(); 
  177. itr != sm_pHookedFunctions->end(); 
  178. ++itr)
  179. {
  180. pHook = itr->second;
  181. pHook->UnHookImport();
  182. delete pHook;
  183. } // for
  184. sm_pHookedFunctions->clear();
  185. m_bSystemFuncsHooked = FALSE;
  186. } // if
  187. }
  188. //
  189. // Indicates whether there is hooked function
  190. //
  191. BOOL CApiHookMgr::AreThereHookedFunctions()
  192. {
  193. return (sm_pHookedFunctions->size() > 0);
  194. }
  195. //---------------------------------------------------------------------------
  196. // HookImport
  197. //
  198. // Hook up an API function
  199. //---------------------------------------------------------------------------
  200. BOOL CApiHookMgr::HookImport(
  201. PCSTR pszCalleeModName, 
  202. PCSTR pszFuncName, 
  203. PROC  pfnHook
  204. )
  205. {
  206. CLockMgr<CCSWrapper>  lockMgr(sm_CritSec, TRUE);
  207. BOOL                  bResult = FALSE;
  208. PROC                  pfnOrig = NULL;
  209. try
  210. {
  211. if (!sm_pHookedFunctions->GetHookedFunction(
  212. pszCalleeModName, 
  213. pszFuncName
  214. ))
  215. {
  216. pfnOrig = GetProcAddressWindows(
  217. ::GetModuleHandleA(pszCalleeModName),
  218. pszFuncName
  219. );
  220. //
  221. // It's possible that the requested module is not loaded yet
  222. // so lets try to load it.
  223. //
  224. if (NULL == pfnOrig)
  225. {
  226. HMODULE hmod = ::LoadLibraryA(pszCalleeModName);
  227. if (NULL != hmod)
  228. pfnOrig = GetProcAddressWindows(
  229. ::GetModuleHandleA(pszCalleeModName),
  230. pszFuncName
  231. );
  232. } // if
  233. if (NULL != pfnOrig)
  234. bResult = AddHook(
  235. pszCalleeModName, 
  236. pszFuncName, 
  237. pfnOrig,
  238. pfnHook
  239. );
  240. } // if
  241. }
  242. catch(...)
  243. {
  244. } // try..catch
  245. return bResult;
  246. }
  247. //---------------------------------------------------------------------------
  248. // UnHookImport
  249. //
  250. // Restores original API function address in IAT
  251. //---------------------------------------------------------------------------
  252. BOOL CApiHookMgr::UnHookImport(
  253. PCSTR pszCalleeModName, 
  254. PCSTR pszFuncName
  255. )
  256. {
  257. CLockMgr<CCSWrapper>  lockMgr(sm_CritSec, TRUE);
  258. BOOL bResult = TRUE;
  259. try
  260. {
  261. bResult = RemoveHook(pszCalleeModName, pszFuncName);
  262. }
  263. catch (...)
  264. {
  265. }
  266. return bResult;
  267. }
  268. //---------------------------------------------------------------------------
  269. // AddHook
  270. //
  271. // Add a hook to the internally supported container
  272. //---------------------------------------------------------------------------
  273. BOOL CApiHookMgr::AddHook(
  274. PCSTR pszCalleeModName, 
  275. PCSTR pszFuncName, 
  276. PROC  pfnOrig,
  277. PROC  pfnHook
  278. )
  279. {
  280. BOOL             bResult = FALSE;
  281. CHookedFunction* pHook   = NULL;
  282. if (!sm_pHookedFunctions->GetHookedFunction(
  283. pszCalleeModName, 
  284. pszFuncName
  285. ))
  286. {
  287. pHook = new CHookedFunction(
  288. sm_pHookedFunctions,
  289. pszCalleeModName, 
  290. pszFuncName, 
  291. pfnOrig,
  292. pfnHook
  293. );
  294. // We must create the hook and insert it in the container
  295. pHook->HookImport();
  296. bResult = sm_pHookedFunctions->AddHook(pHook);
  297. } // if
  298. return bResult;
  299. }
  300. //---------------------------------------------------------------------------
  301. // RemoveHook
  302. //
  303. // Remove a hook from the internally supported container
  304. //---------------------------------------------------------------------------
  305. BOOL CApiHookMgr::RemoveHook(
  306. PCSTR pszCalleeModName, 
  307. PCSTR pszFuncName
  308. )
  309. {
  310. BOOL             bResult = FALSE;
  311. CHookedFunction *pHook   = NULL;
  312. pHook = sm_pHookedFunctions->GetHookedFunction(
  313. pszCalleeModName, 
  314. pszFuncName
  315. );
  316. if ( NULL != pHook )
  317. {
  318. bResult = pHook->UnHookImport();
  319. if ( bResult )
  320. {
  321. bResult = sm_pHookedFunctions->RemoveHook( pHook );
  322. if ( bResult )
  323. delete pHook;
  324. } // if
  325. } // if
  326. return bResult;
  327. }
  328. //---------------------------------------------------------------------------
  329. // HackModuleOnLoad
  330. //
  331. // Used when a DLL is newly loaded after hooking a function
  332. //---------------------------------------------------------------------------
  333. void WINAPI CApiHookMgr::HackModuleOnLoad(HMODULE hmod, DWORD dwFlags)
  334. {
  335. //
  336. // If a new module is loaded, just hook it
  337. //
  338. if ((hmod != NULL) && ((dwFlags & LOAD_LIBRARY_AS_DATAFILE) == 0)) 
  339. {
  340. CLockMgr<CCSWrapper>  lockMgr(sm_CritSec, TRUE);
  341. CHookedFunction* pHook;
  342. CHookedFunctions::const_iterator itr;
  343. for (itr = sm_pHookedFunctions->begin(); 
  344. itr != sm_pHookedFunctions->end(); 
  345. ++itr)
  346. {
  347. pHook = itr->second;
  348. pHook->ReplaceInOneModule(
  349. pHook->Get_CalleeModName(), 
  350. pHook->Get_pfnOrig(), 
  351. pHook->Get_pfnHook(), 
  352. hmod
  353. );
  354. } // for
  355. } // if
  356. }
  357. //---------------------------------------------------------------------------
  358. //
  359. // System API hooks prototypes
  360. //
  361. //---------------------------------------------------------------------------
  362. //---------------------------------------------------------------------------
  363. // MyLoadLibraryA
  364. //
  365. // 
  366. //---------------------------------------------------------------------------
  367. HMODULE WINAPI CApiHookMgr::MyLoadLibraryA(PCSTR pszModuleName)
  368. {
  369. HMODULE hmod = ::LoadLibraryA(pszModuleName);
  370. HackModuleOnLoad(hmod, 0);
  371. return hmod;
  372. }
  373. //---------------------------------------------------------------------------
  374. // MyLoadLibraryW
  375. //
  376. // 
  377. //---------------------------------------------------------------------------
  378. HMODULE WINAPI CApiHookMgr::MyLoadLibraryW(PCWSTR pszModuleName)
  379. {
  380. HMODULE hmod = ::LoadLibraryW(pszModuleName);
  381. HackModuleOnLoad(hmod, 0);
  382. return hmod;
  383. }
  384. //---------------------------------------------------------------------------
  385. // MyLoadLibraryExA
  386. //
  387. // 
  388. //---------------------------------------------------------------------------
  389. HMODULE WINAPI CApiHookMgr::MyLoadLibraryExA(
  390. PCSTR  pszModuleName, 
  391. HANDLE hFile, 
  392. DWORD dwFlags)
  393. {
  394. HMODULE hmod = ::LoadLibraryExA(pszModuleName, hFile, dwFlags);
  395. HackModuleOnLoad(hmod, 0);
  396. return hmod;
  397. }
  398. //---------------------------------------------------------------------------
  399. // MyLoadLibraryExW
  400. //
  401. // 
  402. //---------------------------------------------------------------------------
  403. HMODULE WINAPI CApiHookMgr::MyLoadLibraryExW(
  404. PCWSTR pszModuleName, 
  405. HANDLE hFile, 
  406. DWORD dwFlags)
  407. {
  408. HMODULE hmod = ::LoadLibraryExW(pszModuleName, hFile, dwFlags);
  409. HackModuleOnLoad(hmod, 0);
  410. return hmod;
  411. }
  412. //---------------------------------------------------------------------------
  413. // MyGetProcAddress
  414. //
  415. // 
  416. //---------------------------------------------------------------------------
  417. FARPROC WINAPI CApiHookMgr::MyGetProcAddress(HMODULE hmod, PCSTR pszProcName)
  418. {
  419. // It is possible that multiple threads will call hooked GetProcAddress() 
  420. // API, therefore we should make it thread safe because it accesses sm_pHookedFunctions 
  421. // shared container.
  422. CLockMgr<CCSWrapper>  lockMgr(sm_CritSec, TRUE);
  423. //
  424. // Get the original address of the function
  425. //
  426. FARPROC pfn = GetProcAddressWindows(hmod, pszProcName);
  427. //
  428. // Attempt to locate if the function has been hijacked
  429. //
  430. CHookedFunction* pFuncHook = 
  431. sm_pHookedFunctions->GetHookedFunction(
  432. hmod, 
  433. pszProcName
  434. );
  435. if (NULL != pFuncHook)
  436. //
  437. // The address to return matches an address we want to hook
  438. // Return the hook function address instead
  439. //
  440. pfn = pFuncHook->Get_pfnHook();
  441. return pfn;
  442. }
  443. //---------------------------------------------------------------------------
  444. // GetProcAddressWindows
  445. //
  446. // Returns original address of the API function
  447. //---------------------------------------------------------------------------
  448. FARPROC WINAPI CApiHookMgr::GetProcAddressWindows(HMODULE hmod, PCSTR pszProcName)
  449. {
  450. return ::GetProcAddress(hmod, pszProcName);
  451. }
  452. //---------------------------------------------------------------------------
  453. //
  454. // class CHookedFunction
  455. //  
  456. //---------------------------------------------------------------------------
  457. //
  458. // The highest private memory address (used for Windows 9x only)
  459. //
  460. PVOID CHookedFunction::sm_pvMaxAppAddr = NULL;
  461. //
  462. // The PUSH opcode on x86 platforms
  463. //
  464. const BYTE cPushOpCode = 0x68;   
  465. //---------------------------------------------------------------------------
  466. // CHookedFunction
  467. //  
  468. //
  469. //---------------------------------------------------------------------------
  470. CHookedFunction::CHookedFunction(
  471. CHookedFunctions* pHookedFunctions,
  472. PCSTR             pszCalleeModName, 
  473. PCSTR             pszFuncName, 
  474. PROC              pfnOrig,
  475. PROC              pfnHook
  476. ):
  477. m_pHookedFunctions(pHookedFunctions),
  478. m_bHooked(FALSE),
  479. m_pfnOrig(pfnOrig),
  480. m_pfnHook(pfnHook)
  481. {
  482. strcpy(m_szCalleeModName, pszCalleeModName); 
  483. strcpy(m_szFuncName, pszFuncName);
  484. if (sm_pvMaxAppAddr == NULL) 
  485. {
  486. //
  487. // Functions with address above lpMaximumApplicationAddress require
  488. // special processing (Windows 9x only)
  489. //
  490. SYSTEM_INFO si;
  491. GetSystemInfo(&si);
  492. sm_pvMaxAppAddr = si.lpMaximumApplicationAddress;
  493. } // if
  494.    
  495. if (m_pfnOrig > sm_pvMaxAppAddr) 
  496. {
  497. //
  498. // The address is in a shared DLL; the address needs fixing up 
  499. //
  500. PBYTE pb = (PBYTE) m_pfnOrig;
  501. if (pb[0] == cPushOpCode) 
  502. {
  503. //
  504. // Skip over the PUSH op code and grab the real address
  505. //
  506. PVOID pv = * (PVOID*) &pb[1];
  507. m_pfnOrig = (PROC) pv;
  508. } // if
  509. } // if
  510. }
  511. //---------------------------------------------------------------------------
  512. // ~CHookedFunction
  513. //  
  514. //
  515. //---------------------------------------------------------------------------
  516. CHookedFunction::~CHookedFunction()
  517. {
  518. UnHookImport();
  519. }
  520. PCSTR CHookedFunction::Get_CalleeModName() const
  521. {
  522. return const_cast<PCSTR>(m_szCalleeModName);
  523. }
  524. PCSTR CHookedFunction::Get_FuncName() const
  525. {
  526. return const_cast<PCSTR>(m_szFuncName);
  527. }
  528. PROC CHookedFunction::Get_pfnHook() const
  529. {
  530. return m_pfnHook;
  531. }
  532. PROC CHookedFunction::Get_pfnOrig() const
  533. {
  534. return m_pfnOrig;
  535. }
  536. //---------------------------------------------------------------------------
  537. // HookImport
  538. //  
  539. // Set up a new hook function
  540. //---------------------------------------------------------------------------
  541. BOOL CHookedFunction::HookImport()
  542. {
  543. m_bHooked = DoHook(TRUE, m_pfnOrig, m_pfnHook);
  544. return m_bHooked;
  545. }
  546. //---------------------------------------------------------------------------
  547. // UnHookImport
  548. //  
  549. // Restore the original API handler
  550. //---------------------------------------------------------------------------
  551. BOOL CHookedFunction::UnHookImport()
  552. {
  553. if (m_bHooked)
  554. m_bHooked = !DoHook(FALSE, m_pfnHook, m_pfnOrig);
  555. return !m_bHooked;
  556. }
  557. //---------------------------------------------------------------------------
  558. // ReplaceInAllModules
  559. //  
  560. // Replace the address of a imported function entry  in all modules
  561. //---------------------------------------------------------------------------
  562. BOOL CHookedFunction::ReplaceInAllModules(
  563. BOOL  bHookOrRestore,
  564. PCSTR pszCalleeModName, 
  565. PROC  pfnCurrent, 
  566. PROC  pfnNew
  567. {
  568. BOOL bResult = FALSE;
  569. if ((NULL != pfnCurrent) && (NULL != pfnNew))
  570. {
  571. BOOL                bReplace  = FALSE;
  572. CExeModuleInstance  *pProcess = NULL;
  573. CTaskManager        taskManager; 
  574. CModuleInstance     *pModule;
  575. //
  576. // Retrieves information about current process and modules. 
  577. // The taskManager dynamically decides whether to use ToolHelp 
  578. // library or PSAPI
  579. //
  580. taskManager.PopulateProcess(::GetCurrentProcessId(), TRUE);
  581. pProcess = taskManager.GetProcessById(::GetCurrentProcessId());
  582. if (NULL != pProcess)
  583. {
  584. // Enumerates all modules loaded by (pProcess) process
  585. for (int i = 0; i < pProcess->GetModuleCount(); i++)
  586. {
  587. pModule = pProcess->GetModuleByIndex(i);
  588. bReplace = 
  589. (pModule->Get_Module() != ModuleFromAddress(CApiHookMgr::MyLoadLibraryA)); 
  590. // We don't hook functions in our own modules
  591. if (bReplace)
  592. // Hook this function in this module
  593. bResult = ReplaceInOneModule(
  594. pszCalleeModName, 
  595. pfnCurrent, 
  596. pfnNew, 
  597. pModule->Get_Module()
  598. ) || bResult;
  599. } // for
  600. // Hook this function in the executable as well
  601. bResult = ReplaceInOneModule(
  602. pszCalleeModName, 
  603. pfnCurrent, 
  604. pfnNew, 
  605. pProcess->Get_Module()
  606. ) || bResult;
  607. } // if
  608. } // if
  609. return bResult;
  610. }
  611. //---------------------------------------------------------------------------
  612. // ReplaceInOneModule
  613. //  
  614. // Replace the address of the function in the IAT of a specific module
  615. //---------------------------------------------------------------------------
  616. BOOL CHookedFunction::ReplaceInOneModule(
  617. PCSTR   pszCalleeModName, 
  618. PROC    pfnCurrent, 
  619. PROC    pfnNew, 
  620. HMODULE hmodCaller
  621. {
  622. BOOL bResult = FALSE;
  623. __try
  624. {
  625. ULONG ulSize;
  626. // Get the address of the module's import section
  627. PIMAGE_IMPORT_DESCRIPTOR pImportDesc = 
  628. (PIMAGE_IMPORT_DESCRIPTOR)ImageDirectoryEntryToData(
  629. hmodCaller, 
  630. TRUE, 
  631. IMAGE_DIRECTORY_ENTRY_IMPORT, 
  632. &ulSize
  633. );
  634. // Does this module has import section ?
  635. if (pImportDesc == NULL)
  636. __leave;  
  637. // Loop through all descriptors and
  638. // find the import descriptor containing references to callee's functions
  639. while (pImportDesc->Name)
  640. {
  641. PSTR pszModName = (PSTR)((PBYTE) hmodCaller + pImportDesc->Name);
  642. if (stricmp(pszModName, pszCalleeModName) == 0) 
  643. break;   // Found
  644. pImportDesc++;
  645. } // while
  646. // Does this module import any functions from this callee ?
  647. if (pImportDesc->Name == 0)
  648. __leave;  
  649. // Get caller's IAT 
  650. PIMAGE_THUNK_DATA pThunk = 
  651. (PIMAGE_THUNK_DATA)( (PBYTE) hmodCaller + pImportDesc->FirstThunk );
  652. // Replace current function address with new one
  653. while (pThunk->u1.Function)
  654. {
  655. // Get the address of the function address
  656. PROC* ppfn = (PROC*) &pThunk->u1.Function;
  657. // Is this the function we're looking for?
  658. BOOL bFound = (*ppfn == pfnCurrent);
  659. // Is this Windows 9x
  660. if (!bFound && (*ppfn > sm_pvMaxAppAddr)) 
  661. {
  662. PBYTE pbInFunc = (PBYTE) *ppfn;
  663. // Is this a wrapper (debug thunk) represented by PUSH instruction?
  664. if (pbInFunc[0] == cPushOpCode) 
  665. {
  666. ppfn = (PROC*) &pbInFunc[1];
  667. // Is this the function we're looking for?
  668. bFound = (*ppfn == pfnCurrent);
  669. } // if
  670. } // if
  671. if (bFound) 
  672. {
  673. MEMORY_BASIC_INFORMATION mbi;
  674. ::VirtualQuery(ppfn, &mbi, sizeof(MEMORY_BASIC_INFORMATION));
  675. // In order to provide writable access to this part of the 
  676. // memory we need to change the memory protection
  677. if (FALSE == ::VirtualProtect(
  678. mbi.BaseAddress,
  679. mbi.RegionSize,
  680. PAGE_READWRITE,
  681. &mbi.Protect)
  682. )
  683. __leave;
  684. // Hook the function.
  685.                 *ppfn = *pfnNew;
  686. bResult = TRUE;
  687. // Restore the protection back
  688.                 DWORD dwOldProtect;
  689. ::VirtualProtect(
  690. mbi.BaseAddress,
  691. mbi.RegionSize,
  692. mbi.Protect,
  693. &dwOldProtect
  694. );
  695. break;
  696. } // if
  697. pThunk++;
  698. } // while
  699. }
  700. __finally
  701. {
  702. // do nothing
  703. }
  704. // This function is not in the caller's import section
  705. return bResult;
  706. }
  707. //---------------------------------------------------------------------------
  708. // DoHook
  709. //  
  710. // Perform actual replacing of function pointers
  711. //---------------------------------------------------------------------------
  712. BOOL CHookedFunction::DoHook(
  713. BOOL bHookOrRestore,
  714. PROC pfnCurrent, 
  715. PROC pfnNew
  716. )
  717. {
  718. // Hook this function in all currently loaded modules
  719. return ReplaceInAllModules(
  720. bHookOrRestore, 
  721. m_szCalleeModName, 
  722. pfnCurrent, 
  723. pfnNew
  724. );
  725. }
  726. //
  727. // Indicates whether the hooked function is mandatory one
  728. //
  729. BOOL CHookedFunction::IsMandatory()
  730. {
  731. BOOL bResult = FALSE;
  732. API_FUNC_ID apiFuncId;
  733. for (int i = 0; i < NUMBER_OF_MANDATORY_API_FUNCS; i++)
  734. {
  735. apiFuncId = MANDATORY_API_FUNCS[i];
  736. if ( (0==stricmp(apiFuncId.szCalleeModName, m_szCalleeModName)) &&
  737.      (0==stricmp(apiFuncId.szFuncName, m_szFuncName)) )
  738. {
  739. bResult = TRUE;
  740. break;
  741. } // if
  742. } // for
  743. return bResult;
  744. }
  745. //---------------------------------------------------------------------------
  746. // 
  747. // class CHookedFunctions 
  748. //
  749. //---------------------------------------------------------------------------
  750. CHookedFunctions::CHookedFunctions(CApiHookMgr* pApiHookMgr):
  751. m_pApiHookMgr(pApiHookMgr)
  752. {
  753. }
  754. CHookedFunctions::~CHookedFunctions()
  755. {
  756. }
  757. //---------------------------------------------------------------------------
  758. // GetHookedFunction
  759. //  
  760. // Return the address of an CHookedFunction object
  761. //---------------------------------------------------------------------------
  762. CHookedFunction* CHookedFunctions::GetHookedFunction(
  763. HMODULE hmodOriginal, 
  764. PCSTR   pszFuncName
  765. )
  766. {
  767. char szFileName[MAX_PATH];
  768. ::GetModuleFileName(hmodOriginal, szFileName, MAX_PATH);
  769. // We must extract only the name and the extension
  770. ExtractModuleFileName(szFileName);
  771. return GetHookedFunction(szFileName, pszFuncName);
  772. }
  773. //---------------------------------------------------------------------------
  774. // GetFunctionNameFromExportSection
  775. //  
  776. // Return the name of the function from EAT by its ordinal value
  777. //---------------------------------------------------------------------------
  778. BOOL CHookedFunctions::GetFunctionNameFromExportSection(
  779. HMODULE hmodOriginal,
  780. DWORD   dwFuncOrdinalNum,
  781. PSTR    pszFuncName
  782. {
  783. BOOL bResult = FALSE;
  784. // Make sure we return a valid string (atleast an empty one)
  785. strcpy(pszFuncName, "");
  786. __try
  787. {
  788. ULONG ulSize;
  789. // Get the address of the module's export section
  790. PIMAGE_EXPORT_DIRECTORY pExportDir = 
  791. (PIMAGE_EXPORT_DIRECTORY)ImageDirectoryEntryToData(
  792. hmodOriginal, 
  793. TRUE, 
  794. IMAGE_DIRECTORY_ENTRY_EXPORT, 
  795. &ulSize
  796. );
  797. // Does this module has export section ?
  798. if (pExportDir == NULL)
  799. __leave;  
  800. // Get the name of the DLL
  801. PSTR pszDllName = reinterpret_cast<PSTR>( pExportDir->Name + (DWORD)hmodOriginal);
  802. // Get the starting ordinal value. By default is 1, but
  803. // is not required to be so
  804. DWORD dwFuncNumber = pExportDir->Base;
  805. // The number of entries in the EAT
  806. DWORD dwNumberOfExported = pExportDir->NumberOfFunctions;
  807. // Get the address of the ENT
  808. PDWORD pdwFunctions = (PDWORD)( pExportDir->AddressOfFunctions + (DWORD)hmodOriginal);
  809. //  Get the export ordinal table
  810. PWORD pwOrdinals = (PWORD)(pExportDir->AddressOfNameOrdinals + (DWORD)hmodOriginal);
  811. // Get the address of the array with all names
  812. DWORD *pszFuncNames = (DWORD *)(pExportDir->AddressOfNames + (DWORD)hmodOriginal);
  813. PSTR pszExpFunName;
  814. // Walk through all of the entries and try to locate the
  815. // one we are looking for
  816. for (long i = 0; i < dwNumberOfExported; i++, pdwFunctions++)
  817. {
  818. DWORD entryPointRVA = *pdwFunctions;
  819. if ( entryPointRVA == 0 )   // Skip over gaps in exported function
  820. continue;               // ordinals (the entrypoint is 0 for
  821. // these functions).
  822. // See if this function has an associated name exported for it.
  823. for ( unsigned j=0; j < pExportDir->NumberOfNames; j++ )
  824. {
  825. // Note that pwOrdinals[x] return values starting form 0.. (not from 1)
  826. if ( pwOrdinals[j] == i  )
  827. {
  828. pszExpFunName = (PSTR)(pszFuncNames[j] + (DWORD)hmodOriginal);
  829. // Is this the same ordinal value ?
  830. // Notice that we need to add 1 to pwOrdinals[j] to get actual 
  831. // number
  832. if (dwFuncOrdinalNum == pwOrdinals[j] + 1)
  833. {
  834. if ((pszExpFunName != NULL) && (strlen(pszExpFunName) > 0))
  835. strcpy(pszFuncName, pszExpFunName);
  836. __leave;
  837. }
  838. }
  839. }
  840. } // for
  841. }
  842. __finally
  843. {
  844. // do nothing
  845. }
  846. // This function is not in the caller's import section
  847. return bResult;
  848. }
  849. //---------------------------------------------------------------------------
  850. // GetFunctionNameByOrdinal
  851. //  
  852. // Return the name of the function by its ordinal value
  853. //---------------------------------------------------------------------------
  854. void CHookedFunctions::GetFunctionNameByOrdinal(
  855. PCSTR   pszCalleeModName, 
  856. DWORD   dwFuncOrdinalNum,
  857. PSTR    pszFuncName
  858. )
  859. {
  860. HMODULE hmodOriginal = ::GetModuleHandle(pszCalleeModName);
  861. // Take the name from the export section of the DLL
  862. GetFunctionNameFromExportSection(hmodOriginal, dwFuncOrdinalNum, pszFuncName);
  863. }
  864. //---------------------------------------------------------------------------
  865. // GetHookedFunction
  866. //  
  867. // Return the address of an CHookedFunction object
  868. //---------------------------------------------------------------------------
  869. CHookedFunction* CHookedFunctions::GetHookedFunction( 
  870. PCSTR   pszCalleeModName, 
  871. PCSTR   pszFuncName
  872. )
  873. {
  874. CHookedFunction* pHook = NULL;
  875. char szFuncName[MAX_PATH];
  876. //
  877. // Prevent accessing invalid pointers and examine values 
  878. // for APIs exported by ordinal
  879. //
  880. if ( (pszFuncName) && 
  881.      ((DWORD)pszFuncName > 0xFFFF) && 
  882.  strlen(pszFuncName) ) 
  883. {
  884. strcpy(szFuncName, pszFuncName);
  885. } // if
  886. else
  887. {
  888. GetFunctionNameByOrdinal(pszCalleeModName, (DWORD)pszFuncName, szFuncName);
  889. }
  890. // Search in the map only if we have found the name of the requested function
  891. if (strlen(szFuncName) > 0)
  892. {
  893. char szKey[MAX_PATH];
  894. sprintf(
  895. szKey, 
  896. "<%s><%s>", 
  897. pszCalleeModName,
  898. szFuncName
  899. );
  900. // iterators can be used to check if an entry is in the map
  901. CHookedFunctions::const_iterator citr = find( szKey );
  902. if ( citr != end() )
  903. pHook = citr->second;
  904. } // if
  905. return pHook;
  906. }
  907. //---------------------------------------------------------------------------
  908. // AddHook
  909. //  
  910. // Add a new object to the container
  911. //---------------------------------------------------------------------------
  912. BOOL CHookedFunctions::AddHook(CHookedFunction* pHook)
  913. {
  914. BOOL bResult = FALSE;
  915. if (NULL != pHook)
  916. {
  917. char szKey[MAX_PATH];
  918. sprintf(
  919. szKey, 
  920. "<%s><%s>", 
  921. pHook->Get_CalleeModName(),
  922. pHook->Get_FuncName()
  923. );
  924. // Find where szKey is or should be
  925. CHookedFunctions::iterator lb = lower_bound(szKey);
  926. //
  927. // when an "add" is performed, insert() is more efficient
  928. // than operator[].
  929. // For more details see -item 24 page 109 "Effective STL" by Meyers
  930. //
  931. // Adds pair(pszKey, pObject) to the map
  932. insert( lb, value_type(szKey, pHook) );
  933. //
  934. // added to the map
  935. //
  936. bResult = TRUE;
  937. } // if
  938. return bResult;
  939. }
  940. //---------------------------------------------------------------------------
  941. // RemoveHook
  942. //  
  943. // Remove exising object pointer from the container
  944. //---------------------------------------------------------------------------
  945. BOOL CHookedFunctions::RemoveHook(CHookedFunction* pHook)
  946. {
  947. BOOL bResult = FALSE;
  948. try
  949. {
  950. if (NULL != pHook)
  951. {
  952. char szKey[MAX_PATH];
  953. sprintf(
  954. szKey, 
  955. "<%s><%s>", 
  956. pHook->Get_CalleeModName(),
  957. pHook->Get_FuncName()
  958. );
  959. //
  960. // Find where szKey is located 
  961. //
  962. CHookedFunctions::iterator itr = find(szKey);
  963. if (itr != end())
  964. {
  965. delete itr->second;
  966. erase(itr);
  967. }
  968. bResult = TRUE;
  969. } // if
  970. }
  971. catch (...)
  972. {
  973. bResult = FALSE;
  974. }
  975. return bResult;
  976. }
  977. //----------------------End of file -----------------------------------------