home *** CD-ROM | disk | FTP | other *** search
/ Windows Graphics Programming / Feng_Yuan_Win32_GDI_DirectX.iso / Samples / Chapt_04 / Diver / Function.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2000-05-11  |  14.9 KB  |  645 lines

  1. //-----------------------------------------------------------------------------------//
  2. //              Windows Graphics Programming: Win32 GDI and DirectDraw               //
  3. //                             ISBN  0-13-086985-6                                   //
  4. //                                                                                   //
  5. //  Written            by  Yuan, Feng                             www.fengyuan.com   //
  6. //  Copyright (c) 2000 by  Hewlett-Packard Company                www.hp.com         //
  7. //  Published          by  Prentice Hall PTR, Prentice-Hall, Inc. www.phptr.com      //
  8. //                                                                                   //
  9. //  FileName   : function.cpp                                                         //
  10. //  Description: KFuncTable class                                                    //
  11. //  Version    : 1.00.000, May 31, 2000                                              //
  12. //-----------------------------------------------------------------------------------//
  13.  
  14. #define NOCRYPT
  15.  
  16. #include <windows.h> 
  17. #include <string.h>
  18. #include <assert.h>
  19.  
  20. #include "..\..\include\Decoder.h"
  21. #include "..\..\include\atom.h"
  22.  
  23. #include "Function.h"
  24. #include "Format.h"
  25. #include "Report.h"
  26. #include "Diver.h"
  27. #include "..\Patcher\Patcher.h"
  28.  
  29. bool HackCopy(void * pDest, void * pSource, DWORD nSize);
  30.  
  31. /*
  32. {
  33. #ifdef WRITE_PROCESS
  34.  
  35.     static HANDLE hCurProcess = 0;
  36.  
  37.     DWORD dwWritten;
  38.  
  39.     bool rslt;
  40.     
  41.     if ( hCurProcess==0 )
  42.         hCurProcess = GetCurrentProcess();
  43.  
  44.     rslt = WriteProcessMemory(hCurProcess, pDest, pSource, nSize, & dwWritten) != 0;
  45.  
  46.     return rslt && (dwWritten==nSize);
  47.  
  48. #else
  49.  
  50.     __try
  51.     {
  52.         memcpy(pDest, pSource, nSize);
  53.     }
  54.     __except ( EXCEPTION_EXECUTE_HANDLER )
  55.     {
  56.         __try
  57.         {
  58.             MEMORY_BASIC_INFORMATION mbi;
  59.             
  60.             VirtualQuery(pDest, & mbi, sizeof(mbi));
  61.             VirtualProtect(mbi.BaseAddress, mbi.RegionSize, PAGE_READWRITE, & mbi.Protect);
  62.  
  63.             memcpy(pDest, pSource, nSize);
  64.         }
  65.         __except ( EXCEPTION_EXECUTE_HANDLER )
  66.         {
  67.             return false;
  68.         }
  69.     }
  70.  
  71.     return true;
  72.  
  73. #endif
  74. }
  75. */
  76.  
  77.  
  78. FARPROC KFuncTable::GetProcAddr(int funcid)
  79. {
  80.     int mod = m_func[funcid].f_module;
  81.  
  82.     switch ( m_func[funcid].f_kind )
  83.     {
  84.         case FUNC_COMMETHOD:
  85.         {
  86.             const unsigned * pFunc = (const unsigned *) VTable(mod);
  87.             assert(pFunc);
  88.  
  89.             return (FARPROC) pFunc[m_func[funcid].f_methodid];
  90.         }
  91.         break;
  92.  
  93.         case FUNC_WIN32API:
  94.         {
  95.             HINSTANCE hModule = ModHandle(m_func[funcid].f_module);
  96.             assert(hModule);
  97.  
  98.             FARPROC fp = GetProcAddress(hModule, GetFuncName(funcid));
  99.  
  100. //            assert(fp);
  101.  
  102.             if ( fp==NULL )
  103.             {
  104.                 char temp[128];
  105.  
  106.                 wsprintf(temp, "Not found module %d at %x, func %s at %x",
  107.                     m_func[funcid].f_module, hModule, GetFuncName(funcid), fp);
  108.  
  109.                 Send(M_TEXT, 0, 0, temp);
  110.             }
  111.  
  112.             return fp;
  113.         }
  114.  
  115.         case FUNC_SYSCALL:
  116.             return m_func[funcid].f_oldaddress;
  117.  
  118.         default:
  119.             assert(false);
  120.     }
  121.  
  122.     return NULL;
  123. }
  124.  
  125.  
  126. int KFuncTable::DefPara(const char * paratype, const char *name)
  127. {
  128.     if ( m_parano > MAX_PARA )
  129.     {
  130.         assert(0);
  131.         return -1;
  132.     }
  133.     
  134.     if ( (m_lastmodule<0) || (m_lastfunc<0) )
  135.         return -1;
  136.     
  137.     m_func[m_lastfunc].f_parano ++;        
  138.     
  139.     int len = strlen(paratype);
  140.     const char * pSpace = strchr(paratype, ' ');
  141.     
  142.     if ( pSpace )
  143.         len = (int) pSpace - (int) paratype;
  144.  
  145.     char temp[64];
  146.  
  147.     assert(64>len);
  148.     memcpy(temp, paratype, len);
  149.     temp[len] = 0;
  150.  
  151.     m_para[m_parano].p_type = AddAtom(temp);
  152.     m_para[m_parano].p_name = AddAtom(name);    
  153.     
  154.     return m_parano ++; 
  155. }
  156.  
  157.  
  158. void KFunction::InitStub(int index, FARPROC newaddress)
  159. {
  160.     f_stub[0]                  = 0x68;               // push
  161.     *((int *)(f_stub+1))      = index;              // index
  162.     f_stub[5]                  = 0xE9;               // jmp relative
  163.     *((unsigned *)(f_stub+6)) = (unsigned) newaddress - (unsigned) (f_stub+10);
  164. }
  165.  
  166.  
  167. #define field_this 0
  168.  
  169. int KFuncTable::AddFunc(unsigned ord, const char *name, unsigned opt,
  170.                         int     parano,
  171.                         const char * paratype,
  172.                         int     kind,
  173.                         const void *  oldaddr)
  174. {
  175.     if ( (m_funcno > MAX_FUNC) || (m_lastmodule<0) )
  176.     {
  177.         assert(0);
  178.         m_lastfunc = -1;
  179.  
  180.         return -1;
  181.     }
  182.  
  183.     m_lastfunc = m_funcno ++;
  184.  
  185.     m_func[m_lastfunc].f_kind       = kind;
  186.     m_func[m_lastfunc].f_module     = m_lastmodule;
  187.     m_func[m_lastfunc].InitStub(m_lastfunc, (FARPROC) ProxyProlog);
  188.     m_func[m_lastfunc].f_methodid   = ord;
  189.     m_func[m_lastfunc].f_name       = AddAtom(name);
  190.     m_func[m_lastfunc].f_parano     = 0;
  191.     m_func[m_lastfunc].f_firstpara  = m_parano;
  192.     m_func[m_lastfunc].f_class      = opt;
  193.     m_func[m_lastfunc].f_hooked     = FALSE;
  194.  
  195.     m_func[m_lastfunc].f_totaltime  = 0;
  196.     m_func[m_lastfunc].f_callno     = 0;
  197.  
  198.     for (int i=0; i<parano; i++)
  199.     {
  200.         DefPara(paratype);
  201.  
  202.         if ( i < (parano-1) )
  203.         {
  204.             paratype = strchr(paratype, ' ') + 1;
  205.  
  206.             if ( paratype==(const char *) 1 )
  207.             {
  208.                 assert(false);
  209.  
  210.                 paratype = NULL;
  211.             }
  212.         }
  213.     }
  214.     
  215.     if ( oldaddr )
  216.         m_func[m_lastfunc].f_oldaddress = (FARPROC) oldaddr;
  217.     else
  218.         m_func[m_lastfunc].f_oldaddress = GetProcAddr(m_lastfunc);
  219.     
  220.     return m_lastfunc;
  221. }
  222.  
  223.  
  224. void KFuncTable::Initialize(void)
  225. {
  226.     KModuleTable::Initialize();
  227.     
  228.     m_funcno  = 0;
  229.     m_parano  = 0;
  230.         
  231.     Initialize_API();
  232. }
  233.  
  234.  
  235. FARPROC KFuncTable::LookupInterceptedAPI(FARPROC address, int & id)
  236. {
  237.     for (int i=0; i<m_funcno; i++)
  238.     {
  239.         if ( (m_func[i].f_kind==FUNC_WIN32API) && !m_func[i].f_hooked )
  240.         if ( m_func[i].f_oldaddress == address )
  241.         {
  242.             id = i;
  243.             return m_func[i].f_newaddress();
  244.         }
  245.     }
  246.  
  247. /*
  248.     // If it's Chicago, and the app is being debugged (as this app is)
  249.     // the loader doesn't fix up the calls to point directly at the
  250.     // DLL's entry point.  Instead, the address in the .idata section
  251.     // points to a PUSH xxxxxxxx / JMP yyyyyyyy stub.  The address in
  252.     // xxxxxxxx points to another stub: PUSH aaaaaaaa / JMP bbbbbbbb.
  253.     // The address in aaaaaaaa is the real address of the function in the
  254.     // DLL.  This ugly code verifies we're looking at this stub setup,
  255.     // and if so, grabs the real DLL entry point, and scans through
  256.     // the InterceptedAPIArray list of addresses again.
  257.     // ***WARNING*** ***WARNING*** ***WARNING*** ***WARNING*** 
  258.     // This code is subject to change, and is current only as of 9/94.
  259.  
  260.     if ((GetVersion() & 0xC0000000) == 0xC0000000)
  261.     {
  262.         if ( (unsigned) address < 0x80000000 )  // Only shared, system DLLs
  263.             return NULL;                        // have stubs
  264.         
  265.         if ( IsBadReadPtr(address, 9) || (*(PBYTE)address != 0x68)
  266.              || (*((PBYTE)address+5) != 0xE9) )
  267.             return NULL;
  268.  
  269.         FARPROC stubAddress = * (FARPROC *)((PBYTE) address+1);
  270.  
  271.         for (int i=0; i<m_funcno; i++ )
  272.             if (!m_func[i].f_isvfunc)
  273.             {
  274.                 FARPROC lunacy = m_func[i].f_oldaddress;
  275.             
  276.                 if ( lunacy == stubAddress )
  277.                     return m_func[i].f_newaddress();
  278.             
  279.                 if ( !IsBadReadPtr(lunacy, 9) && 
  280.                      (*(PBYTE)lunacy == 0x68) && 
  281.                      (*((PBYTE)lunacy+5) == 0xE9) )
  282.                 {
  283.                     lunacy = * (FARPROC *)( ((PBYTE)lunacy)+1);
  284.                 
  285.                     if ( lunacy == stubAddress )
  286.                         return m_func[i].f_newaddress();
  287.                 }
  288.             }
  289.     }
  290. */
  291.  
  292.     return NULL;
  293. }
  294.  
  295. _declspec(naked) void SysCall_00(void)
  296. {
  297.     __asm lea    edx, [esp+4]
  298.     __asm int    0x2E
  299.     __asm ret
  300. }
  301.  
  302. _declspec(naked) void SysCall_04(void)
  303. {
  304.     __asm lea    edx, [esp+4]
  305.     __asm int    0x2E
  306.     __asm ret    4
  307. }
  308.  
  309. _declspec(naked) void SysCall_08(void)
  310. {
  311.     __asm lea    edx, [esp+4]
  312.     __asm int    0x2E
  313.     __asm ret    8
  314. }
  315.  
  316. _declspec(naked) void SysCall_0C(void)
  317. {
  318.     __asm lea    edx, [esp+4]
  319.     __asm int    0x2E
  320.     __asm ret    0x0c
  321. }
  322.  
  323. _declspec(naked) void SysCall_10(void)
  324. {
  325.     __asm lea    edx, [esp+4]
  326.     __asm int    0x2E
  327.     __asm ret    0x10
  328. }
  329.  
  330. _declspec(naked) void SysCall_14(void)
  331. {
  332.     __asm lea    edx, [esp+4]
  333.     __asm int    0x2E
  334.     __asm ret    0x14
  335. }
  336.  
  337. _declspec(naked) void SysCall_18(void)
  338. {
  339.     __asm lea    edx, [esp+4]
  340.     __asm int    0x2E
  341.     __asm ret    0x18
  342. }
  343.  
  344. _declspec(naked) void SysCall_1C(void)
  345. {
  346.     __asm lea    edx, [esp+4]
  347.     __asm int    0x2E
  348.     __asm ret    0x1C
  349. }
  350.  
  351. _declspec(naked) void SysCall_20(void)
  352. {
  353.     __asm lea    edx, [esp+4]
  354.     __asm int    0x2E
  355.     __asm ret    0x20
  356. }
  357.  
  358. _declspec(naked) void SysCall_24(void)
  359. {
  360.     __asm lea    edx, [esp+4]
  361.     __asm int    0x2E
  362.     __asm ret    0x24
  363. }
  364.  
  365. _declspec(naked) void SysCall_28(void)
  366. {
  367.     __asm lea    edx, [esp+4]
  368.     __asm int    0x2E
  369.     __asm ret    0x28
  370. }
  371.  
  372. _declspec(naked) void SysCall_2C(void)
  373. {
  374.     __asm lea    edx, [esp+4]
  375.     __asm int    0x2E
  376.     __asm ret    0x2C
  377. }
  378.  
  379. _declspec(naked) void SysCall_30(void)
  380. {
  381.     __asm lea    edx, [esp+4]
  382.     __asm int    0x2E
  383.     __asm ret    0x30
  384. }
  385.  
  386. _declspec(naked) void SysCall_34(void)
  387. {
  388.     __asm lea    edx, [esp+4]
  389.     __asm int    0x2E
  390.     __asm ret    0x34
  391. }
  392.  
  393. _declspec(naked) void SysCall_38(void)
  394. {
  395.     __asm lea    edx, [esp+4]
  396.     __asm int    0x2E
  397.     __asm ret    0x38
  398. }
  399.  
  400. _declspec(naked) void SysCall_3C(void)
  401. {
  402.     __asm lea    edx, [esp+4]
  403.     __asm int    0x2E
  404.     __asm ret    0x3C
  405. }
  406.  
  407. _declspec(naked) void SysCall_40(void)
  408. {
  409.     __asm lea    edx, [esp+4]
  410.     __asm int    0x2E
  411.     __asm ret    0x40
  412. }
  413. _declspec(naked) void SysCall_44(void)
  414. {
  415.     __asm lea    edx, [esp+4]
  416.     __asm int    0x2E
  417.     __asm ret    0x44
  418. }
  419.  
  420. _declspec(naked) void SysCall_48(void)
  421. {
  422.     __asm lea    edx, [esp+4]
  423.     __asm int    0x2E
  424.     __asm ret    0x48
  425. }
  426.  
  427. _declspec(naked) void SysCall_4C(void)
  428. {
  429.     __asm lea    edx, [esp+4]
  430.     __asm int    0x2E
  431.     __asm ret    0x4C
  432. }
  433.  
  434. _declspec(naked) void SysCall_50(void)
  435. {
  436.     __asm lea    edx, [esp+4]
  437.     __asm int    0x2E
  438.     __asm ret    0x50
  439. }
  440.  
  441. const void * SysCall_Stub [] =
  442. {
  443.     SysCall_00,
  444.     SysCall_04,
  445.     SysCall_08,
  446.     SysCall_0C,
  447.  
  448.     SysCall_10,
  449.     SysCall_14,
  450.     SysCall_18,
  451.     SysCall_1C,
  452.  
  453.     SysCall_20,
  454.     SysCall_24,
  455.     SysCall_28,
  456.     SysCall_2C,
  457.  
  458.     SysCall_30,
  459.     SysCall_34,
  460.     SysCall_38,
  461.     SysCall_3C,
  462.  
  463.     SysCall_40,
  464.     SysCall_44,
  465.     SysCall_48,
  466.     SysCall_4C,
  467.     
  468.     SysCall_50
  469. };
  470.  
  471.  
  472. int KFuncTable::InterceptSysCall(void)
  473. {
  474.     int no = 0;
  475.  
  476.     for (int i=0; i<m_funcno; i++)
  477.         if ( (m_func[i].f_kind==FUNC_SYSCALL) && !m_func[i].f_hooked )
  478.         {            
  479.             unsigned char * p = (unsigned char *) m_func[i].f_oldaddress;
  480.  
  481.             // B8 DB 10 00 00     mov         eax,10DBh
  482.             // 8D 54 24 04        lea         edx,[esp+4]
  483.             // CD 2E              int         2Eh
  484.             // C3                 ret
  485.  
  486.             // verify that the destination follows a system call pattern
  487.             if ( ! IsBadReadPtr(p, 12) )
  488.             if ( (p[0]==0xB8) && 
  489.                  (p[5]==0x8D) && (p[6]==0x54) && (p[7]==0x24) && (p[8]==0x04) &&
  490.                  (p[9]==0xCD) && (p[10]==0x2E) )
  491.             {
  492.                 // let ProxyProlog return control to our SysCall_xx routines
  493.                 // f_parano counts return type, so decrease by 1
  494.                 m_func[i].f_oldaddress = (FARPROC) SysCall_Stub[m_func[i].f_parano-1];
  495.  
  496.                 unsigned char Link[6];
  497.  
  498.                             Link[0] = 0xE9;
  499.             * (unsigned *) (Link+1)    = (unsigned) m_func[i].f_newaddress() - 
  500.                                       (unsigned) ( p +10);
  501.                             Link[5] = 0x90;
  502.  
  503.                 HackCopy(p+5, Link, 6);
  504.  
  505.                 m_func[i].f_hooked = TRUE;
  506.                 no ++;
  507.             }
  508.  
  509.         }
  510.  
  511.     return no;
  512. }
  513.  
  514.  
  515. int KFuncTable::InterceptCom(void)
  516. {
  517.     int no = 0;
  518.     
  519.     for (int i=0; i<m_funcno; i++)
  520.         if ( (m_func[i].f_kind==FUNC_COMMETHOD) && !m_func[i].f_hooked )
  521.         {            
  522.             if ( HackMethod(VTable(m_func[i].f_module), 
  523.                             m_func[i].f_methodid, 
  524.                             m_func[i].f_newaddress()) )
  525.             {
  526.                 m_func[i].f_hooked = TRUE;
  527.                 no ++;
  528.             }
  529.  
  530.         }
  531.  
  532.     return no;
  533. }
  534.  
  535.  
  536. int KFuncTable::InterceptWin32(const char        *Caller,
  537.                                const char        *Callee,
  538.                                PIMAGE_THUNK_DATA  pName,
  539.                                PIMAGE_THUNK_DATA  pThunk,
  540.                                const char        *baseAddress)
  541. {
  542.     int no = 0;
  543.     
  544.     // if module not added to module table, quit
  545.     if (LookupModule(Caller, Callee) == -1)
  546.         return 0;
  547.  
  548.     
  549.     while ( pThunk->u1.Function )
  550.     {
  551.         int id;
  552.  
  553.         PBYTE   pFunctionName        = (PBYTE) ( baseAddress + (unsigned) pName->u1.ForwarderString + 2);
  554.         FARPROC pInterceptedFunction = LookupInterceptedAPI((FARPROC) pThunk->u1.Function, id);
  555.  
  556.         if ( pInterceptedFunction )
  557.             if ( HackCopy(& pThunk->u1.Function, & pInterceptedFunction, sizeof(FARPROC)) )
  558.             {
  559.                 m_func[id].f_hooked = TRUE;
  560.                 no ++;
  561.             }    
  562.             
  563.         pName ++;
  564.         pThunk++;
  565.     }
  566.  
  567.     return no;
  568. }
  569.  
  570.  
  571. int KFuncTable::InterceptWin32(const char *ModuleName, const char * baseAddress)
  572. {
  573.     int no = 0;
  574.  
  575.     PIMAGE_DOS_HEADER pDOSHeader = (PIMAGE_DOS_HEADER) baseAddress;
  576.     
  577.     if ( IsBadReadPtr(baseAddress, sizeof(PIMAGE_NT_HEADERS)) )
  578.         return 0;
  579.     
  580.     if ( pDOSHeader->e_magic != IMAGE_DOS_SIGNATURE )
  581.         return 0;
  582.  
  583.     PIMAGE_NT_HEADERS pNTHeader = (PIMAGE_NT_HEADERS) ( baseAddress + pDOSHeader->e_lfanew);
  584.     if ( pNTHeader->Signature != IMAGE_NT_SIGNATURE )
  585.         return 0;
  586.     
  587.     PIMAGE_IMPORT_DESCRIPTOR pImportDesc = 
  588.         (PIMAGE_IMPORT_DESCRIPTOR) ( baseAddress + 
  589.         pNTHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress );
  590.                         
  591.     // Bail out if the RVA of the imports section is 0 (it doesn't exist)
  592.     if ( pImportDesc == (PIMAGE_IMPORT_DESCRIPTOR) pNTHeader )
  593.         return 0;
  594.  
  595.     while ( pImportDesc->Name )
  596.     {
  597.         no += InterceptWin32(ModuleName,
  598.                              (const char *) ( baseAddress + pImportDesc->Name ),
  599.                              (PIMAGE_THUNK_DATA) ( baseAddress + (unsigned) pImportDesc->OriginalFirstThunk),
  600.                              (PIMAGE_THUNK_DATA) ( baseAddress + (unsigned) pImportDesc->FirstThunk),
  601.                              baseAddress);
  602.         pImportDesc++;
  603.     }
  604.     
  605.     return no;
  606. }
  607.  
  608.  
  609. KPatcher directpatcher;
  610.  
  611. int KFuncTable::InterceptWin32(void)
  612. {
  613.     int no = 0;
  614.  
  615. //    DebugBreak();
  616.  
  617.     for (int i=0; i<m_funcno; i++)
  618.         if ( (m_func[i].f_kind==FUNC_WIN32API) & !m_func[i].f_hooked )
  619.         // if there is an unhooked win32 function
  620.         {
  621.             int module = m_func[i].f_module;
  622.  
  623.             // if caller and callee are the same module, patch function target
  624.             if ( strcmp(CallerName(module), CalleeName(module))==0 )
  625.             {
  626.                 if ( directpatcher.Patch(ModHandle(module), GetFuncName(i), 
  627.                                          i, ProxyProlog,
  628.                                          (unsigned long *) &  m_func[i].f_oldaddress) )
  629.                     no ++;
  630.             }
  631.             else
  632.             {
  633.                 const char *caller  = CallerName(module);
  634.                 const char *address = (const char *) ModHandle(module);
  635.  
  636.                 // if caller module is loaded into current process, hack in it.
  637.                 if (address)
  638.                     no += InterceptWin32(caller, address);
  639.             }
  640.         }
  641.  
  642.     return no;
  643. }
  644.  
  645.