home *** CD-ROM | disk | FTP | other *** search
/ Windows Graphics Programming / Feng_Yuan_Win32_GDI_DirectX.iso / Samples / include / ImageModule.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2000-05-11  |  10.7 KB  |  405 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   : imagemodule.cpp                                                     //
  10. //  Description: Using ImageHlp API for debug symbol querying                        //
  11. //  Version    : 1.00.000, May 31, 2000                                              //
  12. //-----------------------------------------------------------------------------------//
  13.  
  14. #define STRICT
  15. #define NOCRYPT
  16. #define WIN32_LEAN_AND_MEAN
  17.  
  18. // the newer imagehlp.h includes <wintrust.h>, the two macros fakes the include
  19. #define WINTRUST_H
  20. #define LPWIN_CERTIFICATE LPVOID
  21.  
  22. #include <windows.h>
  23. #include <imagehlp.h>
  24. #include <assert.h>
  25. #include <tchar.h>
  26. #include <stdio.h>
  27. #include <stdarg.h>
  28. #include <time.h>
  29.  
  30. #include "ImageModule.h"
  31.  
  32. KImageModule::KImageModule(HWND hOutput)
  33. {
  34.     m_hProcess          = GetCurrentProcess();
  35.     m_hOutput          = hOutput;
  36.  
  37.     m_bDecoratedNames = false;
  38.     m_bShowFPO          = false;
  39.     m_bForPogy          = false;
  40.     m_bLoaded          = false;
  41. }
  42.  
  43.  
  44. KImageModule::~KImageModule()
  45. {
  46.     Unload();
  47. }
  48.  
  49.  
  50. bool KImageModule::Load(char * filename, char *sympath)
  51. {
  52.     _tcscpy(m_modulename, filename);
  53.  
  54.     memset(& m_image, 0, sizeof(m_image));
  55.     
  56.     m_imagebase_loaded = (DWORD) GetModuleHandle(filename);
  57.  
  58.     if ( m_imagebase_loaded ) // module is already loaded, for example GDI32.DLL
  59.     {
  60.         m_imagebase_default = m_imagebase_loaded;
  61.         m_bLoaded            = false;
  62.  
  63.         PIMAGE_NT_HEADERS pNTHeader = ImageNtHeader((void *)m_imagebase_loaded);
  64.  
  65.         Output("%s already loaded at 0x%x %s\n", filename, m_imagebase_loaded,
  66.             ctime( (time_t *) & pNTHeader->FileHeader.TimeDateStamp));
  67.     }
  68.     else
  69.     {
  70.         if ( MapAndLoad(filename, NULL, & m_image, FALSE, TRUE) )
  71.             Output("%s loaded at 0x%x %s\n", m_image.ModuleName, m_image.MappedAddress, 
  72.                 ctime( (time_t *) & m_image.FileHeader->FileHeader.TimeDateStamp));
  73.         else
  74.         {
  75.             Output("Unable to load %s\n", filename);
  76.  
  77.             return false;
  78.         }
  79.  
  80.         m_imagebase_loaded  = (DWORD) m_image.MappedAddress;
  81.         m_imagebase_default = m_image.FileHeader->OptionalHeader.ImageBase;
  82.         m_bLoaded           = true;
  83.     }
  84.  
  85.     
  86.     if ( !SymInitialize(m_hProcess, sympath, FALSE) ) 
  87.     {
  88.         Output("SymInitialize failed\n\n");
  89.         return false;
  90.     }
  91.  
  92.     
  93.     m_symbolbase = SymLoadModule(m_hProcess, NULL, filename, 0, m_imagebase_loaded, 0 );
  94.     
  95.     if ( m_symbolbase==0 )
  96.     {
  97.         Output("SymLoadModule failed\n\n");
  98.         return false;
  99.     }
  100.  
  101.     IMAGEHLP_MODULE im;
  102.     im.SizeOfStruct = sizeof(im);
  103.  
  104.     SymGetModuleInfo( m_hProcess, m_symbolbase, &im );
  105.     
  106.     Output("""%s"" loaded. %s\n", im.LoadedImageName, ctime((time_t *) & im.TimeDateStamp));
  107.     
  108.     return true;
  109. }
  110.  
  111.  
  112. void KImageModule::Unload(void)
  113. {
  114.     SymUnloadModule(m_hProcess, m_symbolbase);
  115.     SymCleanup(m_hProcess);
  116.  
  117.     if ( m_image.ModuleName )
  118.         UnMapAndLoad(& m_image);
  119.  
  120.  
  121. const IMAGEHLP_SYMBOL * KImageModule::ImageGetSymbol(const char * name)
  122. {
  123.     char localname[MAX_PATH];
  124.  
  125.     memset(m_is, 0, sizeof(m_is));
  126.     m_is[0].SizeOfStruct  = sizeof(IMAGEHLP_SYMBOL);
  127.     m_is[0].MaxNameLength = sizeof(m_is) - sizeof(m_is[0]);
  128.     
  129.     // The silly implementation in imagehlp.dll will try to change the '!' in name
  130.     // to 0, which generates an access violation, because name would came from read-only
  131.     // constant data. Make a local copy to solve the problem
  132.     strcpy(localname, name);
  133.     
  134.     if ( SymGetSymFromName(m_hProcess, localname, m_is) )
  135.     {
  136.         // On Win2K RC1, m_is[0].Address is a valid address, m_pidi->ReservedMappedBase=NULL
  137.         if ( m_symbolbase )
  138.             m_is[0].Address += m_imagebase_default - m_symbolbase;
  139.         
  140.         return & m_is[0];
  141.     }
  142.     else
  143.     {
  144.         DWORD err = GetLastError();
  145.         return NULL;
  146.     }
  147. }
  148.  
  149.  
  150. bool KImageModule::LoadSystemModule(char * module, char* extension)
  151. {
  152.     char SymbolDir[MAX_PATH];
  153.  
  154.     GetSystemDirectory(SymbolDir, sizeof(SymbolDir)); // c:\winnt\system32
  155.  
  156.     char * p = strchr(SymbolDir, '\\');     // first '\\'
  157.     while ( p && strchr(p+1, '\\') )       // last '\\'    
  158.         p = strchr(p+1, '\\');
  159.  
  160.     if ( p )                                // c:\winnt
  161.         * p = NULL;
  162.  
  163.     strcat(SymbolDir, "\\symbols\\");
  164.     strcat(SymbolDir, extension);
  165.  
  166.     return Load(module, SymbolDir);
  167. }
  168.  
  169.  
  170. void KImageModule::ShowFPO(ULONG SymbolAddress)
  171. {
  172.     if ( m_bShowFPO )
  173.     {
  174.         const FPO_DATA * pFPO = (const FPO_DATA *) SymFunctionTableAccess(m_hProcess, SymbolAddress);
  175.         
  176.         if ( pFPO )
  177.         {
  178.             Output("         ");
  179.             Output("s=%4d l=%2d, p=%2d, e=%2d, r=%2d, s=%d, b=%d, f=%d\n",
  180.                     pFPO->cbProcSize,
  181.                     pFPO->cdwLocals,
  182.                     pFPO->cdwParams,
  183.                     pFPO->cbProlog,
  184.                     pFPO->cbRegs,
  185.                     pFPO->fHasSEH,
  186.                     pFPO->fUseBP,
  187.                     pFPO->cbFrame);
  188.         }
  189.     }
  190. }
  191.  
  192.  
  193. void KImageModule::TranslateName(LPSTR SymbolName)
  194. {
  195.     // If "decorated" names were specified, and if the name is "decorated," 
  196.     // undecorate it so that a human readable version can be displayed. 
  197.     
  198.     if ( m_bDecoratedNames /* && ('?' == *SymbolName) */ ) 
  199.     { 
  200.         char szUndecoratedName[0x400]; // Make symbol name buffers for the 
  201.         char szDecoratedName[0x400]; // decorated & undecorated versions 
  202.  
  203.         // Make a copy of the original SymbolName, so that we can modify it 
  204.  
  205.         lstrcpy( szDecoratedName, SymbolName ); 
  206.  
  207.         PSTR pEnd = szDecoratedName + lstrlen( szDecoratedName ); 
  208.  
  209.         // Strip everything off the end until we reach a 'Z' 
  210.  
  211.         //    while ( (pEnd > szDecoratedName) && (*pEnd != 'Z') ) 
  212.         //        *pEnd-- = 0; 
  213.  
  214.         // Call the IMAGEHLP function to undecorate the name 
  215.  
  216.         if ( 0 != UnDecorateSymbolName( szDecoratedName, szUndecoratedName, 
  217.             sizeof(szUndecoratedName), UNDNAME_COMPLETE | UNDNAME_32_BIT_DECODE ) ) 
  218.         { 
  219.             // End the output line with the undecorated name 
  220.             Output("         %s\n", szUndecoratedName ); 
  221.         } 
  222.     } 
  223. }
  224.  
  225.  
  226. // translate symbol va address symbva to RVA symbva - mappedBase
  227. // translate RVA to pointer within the loaded image
  228. const unsigned char * KImageModule::GetImagePointer(unsigned symbva)
  229. {
  230.     assert(m_imagebase_loaded);
  231.  
  232.     return (const unsigned char *) 
  233.         ImageRvaToVa(m_image.FileHeader, (void *) m_imagebase_loaded, 
  234.                         symbva - m_imagebase_default, NULL);
  235. }
  236.  
  237. // translate actual loaded pointer to to pointer within the loaded image
  238. const unsigned char * KImageModule::Address2ImagePointer(unsigned addr)
  239. {
  240.     assert(m_imagebase_loaded);
  241.  
  242.     return (const unsigned char *) 
  243.         ImageRvaToVa(m_image.FileHeader, (void *) m_imagebase_loaded, 
  244.                         addr - m_image.FileHeader->OptionalHeader.ImageBase, NULL);
  245. }
  246.  
  247.  
  248. BOOL KImageModule::EnumSymbolsCallback(LPSTR SymbolName, ULONG SymbolAddress, ULONG SymbolSize) 
  249.     unsigned callid = 0;
  250.     unsigned parano = 0;
  251.  
  252.     // translate symbol address SymbolAddress to RVA SymbolAddress - mappedBase
  253.     // translate RVA to pointer within the loaded image
  254.     const unsigned char * p;
  255.     
  256.     if ( m_bLoaded )
  257.         p = GetImagePointer(SymbolAddress);
  258.     else
  259.         p = (const unsigned char *) SymbolAddress;
  260.  
  261.     // Checking for system service call pattern
  262.     if ( ! IsBadReadPtr(p, 14) )
  263.     if ( (p[0]==0xB8) &&                                                  // mov eax, <callid>
  264.          (p[5]==0x8D) && (p[6]==0x54) && (p[7]==0x24) && (p[8]==0x04) &&  // lea edx, [esp+4]
  265.          (p[9]==0xCD) && (p[10]==0x2E) )                                  // int 2E
  266.     {
  267.         callid = * (unsigned *) (p+1);
  268.             
  269.         if ( p[11]==0xC2 )                                                  // ret <parasize>    
  270.             parano = * (unsigned short *) (p+12) / 4;
  271.     }
  272.     
  273.     if ( callid )
  274.     {
  275.         const IMAGEHLP_SYMBOL * pSymbol = ImageGetSymbol(SymbolName);
  276.  
  277.         // print out the RVA, and the symbol name passed to us. 
  278.         if ( m_bForPogy )
  279.         {                
  280.             Output( "D %s(", SymbolName);
  281.             for (unsigned i=0; i<parano; i++)
  282.             {
  283.                 Output("D");
  284.                 if ( i != (parano-1) )
  285.                     Output(",");
  286.             }
  287.             Output("), %08X, %x\n", pSymbol->Address, callid);
  288.         }
  289.         else
  290.         {
  291.             Output( "syscall(0x%04x, %2d) %08X %s!%s\n", callid, parano, pSymbol->Address, m_modulename, SymbolName); 
  292.     
  293.             ShowFPO(SymbolAddress);
  294.             TranslateName(SymbolName);
  295.         }
  296.         m_nCount ++;
  297.     }
  298.  
  299.     return TRUE; 
  300.  
  301.  
  302. BOOL CALLBACK EnumSymbolsCallback(LPSTR SymbolName, ULONG SymbolAddress, ULONG SymbolSize, 
  303.                                   PVOID UserContext ) 
  304. {
  305.     assert( ! IsBadReadPtr(UserContext, sizeof(KImageModule)) );
  306.  
  307.     return ((KImageModule *) UserContext)->EnumSymbolsCallback(SymbolName, SymbolAddress, SymbolSize);
  308. }
  309.  
  310.  
  311. void KImageModule::EnumerateSymbols(bool bForPogy)
  312. {
  313.     m_nCount  = 0;
  314.     m_bForPogy = bForPogy;
  315.  
  316.     SymEnumerateSymbols(m_hProcess, m_imagebase_loaded, ::EnumSymbolsCallback, this);
  317.  
  318.     Output("%d total syscalls found\n\n", m_nCount);
  319. }
  320.  
  321.  
  322. void KImageModule::ShowSysCallTable(const char * tablename, unsigned base)
  323. {
  324.     const IMAGEHLP_SYMBOL * pSymbol = ImageGetSymbol(tablename);
  325.  
  326.     if ( pSymbol==NULL )
  327.         Output("Unable to locate symbol %s\n", tablename);
  328.     else
  329.     {
  330.         int count = base;
  331.  
  332.         const unsigned * p = (const unsigned *) Address2ImagePointer(pSymbol->Address);
  333.  
  334.         while ( ! IsBadReadPtr(p, sizeof(unsigned)) )
  335.         {
  336.             unsigned q = * p;
  337.  
  338.             if ( q > (unsigned) (m_image.FileHeader->OptionalHeader.ImageBase) )
  339.             {
  340.                 DWORD           displacement;
  341.             //    IMAGEHLP_SYMBOL symbol;
  342.  
  343.                 memset(m_is, 0, sizeof(m_is));
  344.                 m_is[0].SizeOfStruct  = sizeof(IMAGEHLP_SYMBOL);
  345.                 m_is[0].MaxNameLength = sizeof(m_is) - sizeof(m_is[0]);
  346.     
  347.                 unsigned q1 = q;
  348.  
  349.                 // W2k RC1 imagehlp does not need translation
  350.                 if ( m_symbolbase )
  351.                     q1 = q1 - m_imagebase_default + m_symbolbase;
  352.  
  353.                 if ( SymGetSymFromAddr(m_hProcess, q1, & displacement, m_is) )
  354.                 {
  355.                     IMAGEHLP_LINE line;
  356.  
  357.                     line.SizeOfStruct = sizeof(line);
  358.  
  359.                     if ( SymGetLineFromAddr(m_hProcess, q1, & displacement, & line) )
  360.                     {
  361.                     }
  362.  
  363.                     Output("syscall(%4x) %s\n", count, m_is[0].Name);
  364.                     count ++;
  365.                 }
  366.             }
  367.             else
  368.                 break;
  369.             p++;
  370.         }
  371.  
  372.         Output("%d system calls found\n", count - base);
  373.     }
  374. }
  375.  
  376.  
  377. void KImageModule::va_Output(const char * format, va_list argptr)
  378. {
  379.     char buffer[1024];
  380.     
  381.     vsprintf(buffer, format, argptr);
  382.  
  383.     if ( m_hOutput )
  384.     {
  385.         SendMessage(m_hOutput, EM_SETSEL, 0xFFFFFF, 0xFFFFFF);
  386.         SendMessage(m_hOutput, EM_REPLACESEL, 0, (LPARAM) buffer);
  387.     }
  388.     else
  389.         OutputDebugString(buffer);
  390. }
  391.  
  392.  
  393. void KImageModule::Output(const char * format, ...)
  394. {
  395.     va_list ap;
  396.  
  397.     va_start(ap, format);
  398.     va_Output(format, ap);
  399.     va_end(ap);
  400. }
  401.  
  402.