home *** CD-ROM | disk | FTP | other *** search
/ Liren Large Software Subsidy 10 / 10.iso / l / l430 / 1.ddi / CHAP5.ZIP / WINMOD.C < prev    next >
Encoding:
C/C++ Source or Header  |  1992-06-10  |  15.2 KB  |  516 lines

  1. /*
  2.     WINMOD.C -- Windows module list browser
  3.  
  4.     From Chapter 5 of "Undocumented Windows" (Addison-Wesley 1992)
  5.     by Andrew Schulman, Dave Maxey and Matt Pietrek
  6.  
  7.     Build using: WINIOBC WINMOD (for Borland C++ v3.00)
  8.                  WINIOMS WINMOD (for Microsoft C/SDK)
  9. */
  10.  
  11. #include <windows.h>
  12. #include <stdio.h>
  13. #include <string.h>
  14. #include <dos.h>
  15. #include "winio.h"
  16. #include "modtable.h"
  17.  
  18. #ifndef __BORLANDC__
  19. #define asm _asm
  20. #define MK_FP(a,b)  ((void far *)(((unsigned long)(a) << 16) | (b))) 
  21. #endif
  22.  
  23. #define NE_SIGNATURE 0x454E
  24.  
  25. WORD WinVersion;
  26.  
  27. char *ResourceNames[] =
  28. {
  29.     "Unknown",
  30.     "Cursor",           // 1
  31.     "Bitmap",           // 2
  32.     "Icon",             // 3
  33.     "Menu",             // 4
  34.     "Dialog",           // 5
  35.     "String Table",     // 6
  36.     "Font Directory",   // 7
  37.     "Font",             // 8
  38.     "Accelerator",      // 9
  39.     "RC Data",          //10
  40.     "Error Table",      //11
  41.     "Group Cursor",     //12
  42.     "Unknown",          //13
  43.     "Group Icon",       //14
  44.     "Name Table",       //15
  45.     "Version info"      //16
  46. };
  47.  
  48. //---------------------------------------------
  49. // Converts a global handle to a selector value.
  50. // The proper way would be to use GlobalLock, but
  51. // GlobalLock will RIP on certain selectors.
  52. // TOOLHELP does it like this, so...
  53. //---------------------------------------------
  54.  
  55. WORD HandleToSel(HANDLE h)
  56. {
  57.     // In 3.1, handles = (selectors-1)
  58.     // Valid selectors end in a 7 or a F
  59.     // Thus, we can simply make sure the
  60.     // lowest bit is turned on.
  61.     // 
  62.     // In 3.0, handles = (selectors+1)
  63.     // Valid selectors end in a 5 or a D
  64.     // Decrement the handle if it's an
  65.     // even value.
  66.  
  67.     if ( WinVersion == 0x030A )
  68.         h |= 0x0001;
  69.         
  70.     else if ( WinVersion < 0x030A )
  71.         if ( (h & 0x0002) == 0x0002 )
  72.             h--;
  73.         
  74.     return h;
  75. }
  76.  
  77. //---------------------------------------------
  78. // Given a module handle, return back the
  79. // name of the module.
  80. //---------------------------------------------
  81.  
  82. char *GetModuleNameFromHandle(HANDLE handle)
  83. {
  84.     static char name[129];
  85.     char far *moduleTablePtr;
  86.     WORD residentNamesOffset;
  87.     BYTE cbModuleName;
  88.     
  89.     name[0] = 0;    // Null out the return string
  90.     
  91.     // create a pointer to the module table
  92.     moduleTablePtr = GlobalLock(handle);
  93.     GlobalUnlock(handle);
  94.     if ( !moduleTablePtr )
  95.         return name;
  96.  
  97.     // Verify that we're really looking at a module table, by
  98.     // looking for the 'NE' signature.  If we are, get the
  99.     // module name out of the resident names table.
  100.     if ( *(WORD far *)moduleTablePtr == NE_SIGNATURE )
  101.     {
  102.         // Obtain the resident names table offset, and point to it
  103.         residentNamesOffset = *(WORD far *)(moduleTablePtr + 0x26);
  104.         moduleTablePtr += residentNamesOffset;
  105.         
  106.         // Get the length of the first entry, which is always
  107.         // the module name.
  108.         cbModuleName = *(BYTE far *)moduleTablePtr;
  109.         moduleTablePtr++;
  110.         
  111.         // Use the far string copy to move the name to our local
  112.         // buffer.  Then null terminate the local buffer copy.
  113.         _fstrncpy(name, moduleTablePtr, cbModuleName);
  114.         name[cbModuleName] = 0;
  115.     }
  116.     
  117.     return name;
  118. }
  119.  
  120. //---------------------------------------------
  121. // Display each entry in the resource table
  122. //---------------------------------------------
  123.  
  124. void DoResourceTable(char far *ptr)
  125. {
  126.     RESOURCETYPE far *type;
  127.     RESOURCEINFO far *info;
  128.     WORD align;
  129.     char *resourceTypeName;
  130.     WORD i;
  131.  
  132.     printf("Resources:\n");
  133.  
  134.     // Calculate the resource file alignment size
  135.     align = 1 << (*(WORD far *)ptr);
  136.     
  137.     // Point past the alignment size field, to the first entry
  138.     (char far *)type = ptr+2;
  139.  
  140.     // A resource type ID of 0 indicates the end of the list
  141.     while ( type->ID != 0 )
  142.     {
  143.         // Determine what type this resource is
  144.         if ( (type->ID & 0x7FFF ) <= 16 )
  145.             resourceTypeName = ResourceNames[type->ID & 0x7FFF];
  146.         else if ( type->ID == 0x80CC )
  147.             resourceTypeName = "TrueType font";
  148.         else
  149.             resourceTypeName = "Unknown";
  150.         
  151.         // Display information common to all entry of this type
  152.         printf("  ID: %04X %-20s %04X entries  fn(): %Fp\n",
  153.             type->ID, resourceTypeName, type->count, type->function);
  154.         
  155.         // 'C' pointer arithmatic at work here!!!
  156.         (RESOURCETYPE far *)info = type+1;
  157.         
  158.         // Now iterate and display all the entries for this resource type.
  159.         // The "info" pointer always points to the next resource instance
  160.         // to be displayed, and is updated with 'C' pointer arithmatic.
  161.         for (i=0; i < type->count; i++)
  162.         {
  163.             printf("  Offs: %05lX  Len: %04lX  Flags: %04X"
  164.                    "  Handle: %04X  Usage: %04X\n",
  165.                 info->offset * (DWORD)align, info->length*(DWORD)align,
  166.                 info->flags, info->handle, info->usage );
  167.             info++;
  168.         }
  169.         
  170.         printf("\n");
  171.         
  172.         // The next resource type immediately follows the end
  173.         // of the preceeding resource.  Use this info to point
  174.         // to the next resource type section.
  175.         type = (RESOURCETYPE far *)info;        
  176.     }
  177.     
  178.     printf("\n");   
  179. }
  180.  
  181. //---------------------------------------------
  182. // Display information about each segment in
  183. // the modules segment table.
  184. //---------------------------------------------
  185.  
  186. void DoSegmentTable(void far *a, WORD count)
  187. {
  188.     MODULE_TABLE_SEGMENT_RECORD far *st = a;
  189.     WORD segSel;
  190.     WORD i;
  191.  
  192.     printf("Segments:\n");
  193.     printf("   #  HNDL  FILE_SIZE  ALLOC_SIZE  TYPE\n");
  194.     
  195.     for ( i=1; i <= count; i++, st++)
  196.     {
  197.         printf
  198.         (
  199.            "  %02X  %04X       %04X        %04X  %s",
  200.             i,
  201.             st->handle,
  202.             st->segment_length,
  203.             st->alloc_size,
  204.             st->flags.segment_type ? "DATA" : "CODE"
  205.         );
  206.         
  207.         if ( st->handle == 0 )
  208.             goto not_present;
  209.  
  210.         // Determine is the "present" bit is set in the 
  211.         // descriptor, and report accordingly
  212.         segSel = HandleToSel(st->handle);
  213.         asm     lar     ax, [segSel]
  214.         asm     test    ax, 08000h
  215.         asm     jz      not_present
  216.         
  217.         printf(" PRESENT");
  218.         asm     jmp     done
  219.             
  220.         not_present:    printf(" NON-PRESENT");
  221.             
  222.         done:           printf("\n");
  223.     }
  224.  
  225.     printf("\n");
  226. }
  227.  
  228. //---------------------------------------------
  229. // Displays all the modules that are
  230. // implicitly linked to.
  231. //---------------------------------------------
  232.  
  233. void DoModuleTable(HANDLE far *modtab, WORD count)
  234. {
  235.     WORD i;
  236.  
  237.     printf("Referenced modules:\n");
  238.     printf("  HNDL  NAME\n");
  239.     
  240.     for(i=0; i < count; i++)
  241.         printf("  %04X  %s\n", modtab[i], 
  242.             GetModuleNameFromHandle(modtab[i]));
  243.     
  244.     printf("\n");   
  245. }
  246.  
  247. //---------------------------------------------
  248. // Displays the resident names table.  This
  249. // table always contains the module name.
  250. // DLL's should have WEP's in this table,
  251. // and any function that is exported by name
  252. // will appear in this table.
  253. //---------------------------------------------
  254.  
  255. void DoResidentNamesTable(char far *t)
  256. {
  257.     char buffer[129];
  258.     WORD ordinal;
  259.     BYTE length;
  260.     
  261.     printf("Resident names:\n");
  262.     printf("  ORDN  NAME\n");
  263.  
  264.     // A 0 byte indicates the end of the table.
  265.     // Entries are a length byte, followed by
  266.     // the string, followed by the entry ordinal
  267.     while ( *t )
  268.     {
  269.         // Obtain the length of this name
  270.         length = *(BYTE far *)t;
  271.         
  272.         // Copy the string to a local buffer,
  273.         // and null terminate it.
  274.         _fstrncpy(buffer, t+1, length);
  275.         buffer[length] = 0;
  276.         
  277.         // The entry ordinal is a WORD immediately
  278.         // following the name
  279.         ordinal = *(WORD far *)(t + length + 1);
  280.         
  281.         printf("  %04X  %s\n", ordinal, buffer);
  282.         
  283.         // bump up the pointer to point to
  284.         // the next entry.  
  285.         t+= (length + 3);
  286.     }
  287.     
  288.     printf("\n");
  289. }
  290.  
  291. //---------------------------------------------
  292. // High level function to display information
  293. // about a module, based upon information in
  294. // the module table
  295. //---------------------------------------------
  296.  
  297. void DisplayModule(HANDLE hModule)
  298. {
  299.     int width = 25;
  300.     WORD sel;
  301.     unsigned char far *ptr;
  302.     MODULE_TABLE far *mt;
  303.     WORD fileDate, fileTime;
  304.         
  305.     sel = HandleToSel(hModule);
  306.     ptr = (unsigned char far *)mt = MK_FP(sel, 0);
  307.  
  308.     // Perform some weird contortions to extract the
  309.     // filename and date/time.  Date/Time fields
  310.     // are in MS-DOS bit encoded format.
  311.     printf("%-*s", width, "File");  
  312.     fileDate = *(WORD far *)(ptr+mt->ne_pfileinfo+4);
  313.     fileTime = *(WORD far *)(ptr+mt->ne_pfileinfo+6);
  314.     printf
  315.     (
  316.         "%Fs  %02u-%02u-%02u %2u:%02u\n",
  317.         (ptr+mt->ne_pfileinfo+8),
  318.         (fileDate >> 5) & 0xF,
  319.         (fileDate & 0x1F),
  320.         (fileDate >> 9) + 80,
  321.         (fileTime >> 11),
  322.         (fileTime >> 5) & 0x3F
  323.     );
  324.  
  325.     printf("%-*s%04X\n", width, "Usage count", mt->ne_usage);
  326.     printf("%-*s%04X\n", width, "DGROUP segment", mt->ne_autodata);
  327.     printf("%-*s%04X\n", width, "Initial heap size", mt->ne_heap);
  328.     printf("%-*s%04X\n", width, "Initial stack size", mt->ne_stack);
  329.     printf("%-*s%Fp\n", width, "Starting CS:IP", mt->ne_csip);
  330.     printf("%-*s%Fp\n", width, "Starting SS:SP", mt->ne_sssp);
  331.     printf("%-*s%u.%02u\n", width, "Minimum Windows version",
  332.         HIBYTE(mt->ne_expver), LOBYTE(mt->ne_expver));
  333.  
  334.     printf("%-*s", width, "Flags");
  335.  
  336.     if ( mt->ne_flags & NENOTP )
  337.         printf("LIBRARY ");
  338.     if ( mt->ne_flags & NESELFLOAD )
  339.         printf("SELF_LOAD ");
  340.     if ( (mt->ne_flags & NEAPPTYP) == 0x100 )
  341.         printf("NON_WIN_API ");
  342.     if ((mt->ne_flags & NEAPPTYP) == 0x200)
  343.         printf("API_COMPAT ");
  344.     if ( (mt->ne_flags & NEAPPTYP) == 0x300 )
  345.         printf("USES_WINAPI ");
  346.     if ( mt->ne_flags & NENONRES )
  347.         printf("NON_RES_CODE ");
  348.     if ( mt->ne_flags & NELIM32 )
  349.         printf("LIM32 ");
  350.     if ( mt->ne_flags & NEPROT )
  351.         printf("PROT_MODE ");
  352.     if ( mt->ne_flags & NEPPLI )
  353.         printf("PER_PROCESS_INIT ");
  354.     if ( mt->ne_flags & NEINST )
  355.         printf("INSTANCE_DATA ");
  356.     if ( mt->ne_flags & NESHARED )
  357.         printf("SHARED_DATA ");
  358.     printf("\n");
  359.     
  360.     printf("%-*s%05lX\n", width,"Non-res names offset", mt->ne_nrestab);
  361.     printf("%-*s%04X\n", width, "Non-res names size", mt->ne_cbnrestab);    
  362.  
  363.     printf("\n");
  364.  
  365.     // Only dump segment table if there are segments
  366.     if ( mt->ne_cseg )
  367.         DoSegmentTable(MK_FP(sel, mt->ne_segtab), mt->ne_cseg);
  368.     
  369.     // Calculate length of resource table.  Only dump it if
  370.     // it is a non-zero length
  371.     if ( mt->ne_restab - mt->ne_rsrctab )
  372.         DoResourceTable(MK_FP(sel,mt->ne_rsrctab));
  373.  
  374.     // Only dump module table if 1 or more entries
  375.     if ( mt->ne_cmod )
  376.         DoModuleTable( MK_FP(sel,mt->ne_modtab), mt->ne_cmod);
  377.     
  378.     DoResidentNamesTable( MK_FP(sel, mt->ne_restab) );
  379.     
  380.     printf("\n");
  381. }
  382.  
  383. //---------------------------------------------
  384. // Walks the list of modules in the system,
  385. // calling DisplayModule to dump each one
  386. // out in turn
  387. //---------------------------------------------
  388.  
  389. void ModuleWalk(void)
  390. {
  391.     HANDLE  thisModule;
  392.     WORD    hInstance;
  393.     WORD    far *signature_word;
  394.  
  395.     // Get our instance handle, which is also our DS.
  396.     // Hint: You can also obtain this value by using
  397.     // the hInstance passed to WinMain.  Also, some
  398.     // compilers store the hInstance in a global
  399.     // variable that is accessible to your code.
  400.     asm     mov     [hInstance], DS
  401.  
  402.     // An undocumented use of GetModuleHandle.  The
  403.     // module handle associated with the passed in
  404.     // DS is returned in AX.  The handle of the first
  405.     // module in the system (KERNEL) is returned in DX
  406.     GetModuleHandle( MK_FP(0, hInstance) );
  407.     asm     mov     [thisModule], DX
  408.  
  409.     //  Turn off repainting while we blast out the info
  410.     winio_setbusy();
  411.     winio_setpaint(winio_current(), FALSE);
  412.     
  413.     printf("Double-Click on any line for detailed view\n\n");
  414.     printf("MODULE    HANDLE\n");
  415.  
  416.     // The list is terminated by a NULL next module handle
  417.     while ( thisModule )     
  418.     {   
  419.         // Create a far pointer to the module table.
  420.         // Verify that we have a valid table by
  421.         // looking for the 'NE' signature.  Abort
  422.         // if not found
  423.         signature_word = MK_FP(thisModule, 0);
  424.         if ( *signature_word != NE_SIGNATURE )
  425.         {
  426.             printf("Error in following module chain\n");
  427.             break;
  428.         }
  429.     
  430.         printf
  431.         (
  432.             "%-8s    %04X\n",
  433.             GetModuleNameFromHandle(thisModule),
  434.             thisModule
  435.         );
  436.             
  437.         // The next module handle is at offset 6
  438.         // in the module table
  439.         thisModule = *(HANDLE far *)MK_FP(thisModule, 6);
  440.     }
  441.  
  442.     // Turn the repainting back on, and position to the top of the list
  443.     winio_setpaint(winio_current(), TRUE);
  444.     winio_resetbusy();
  445.     winio_home(winio_current());
  446. }
  447.  
  448. void DumpModule(HWND hwnd, LPSTR line, int i)
  449. {
  450.     char moduleName[80];
  451.     char buffer[80];
  452.     HANDLE hModule;
  453.     int returnCode;
  454.     HWND newWindow;
  455.     
  456.     _fstrcpy(buffer, line);
  457.     
  458.     returnCode = sscanf(buffer, "%s %x", moduleName, &hModule);
  459.     
  460.     if ( returnCode != 2 )
  461.     {
  462.         MessageBox(NULL, "Not a valid line", "Error",
  463.                     MB_OK | MB_ICONEXCLAMATION);
  464.         return;
  465.     }
  466.     
  467.     if ( GetModuleHandle(moduleName) != hModule )
  468.     {
  469.         MessageBox(NULL, "Module no longer exist", "Error",
  470.                     MB_OK | MB_ICONEXCLAMATION);
  471.         return;
  472.     }
  473.  
  474.     sprintf(buffer, "WinMod: %s", moduleName);
  475.  
  476.     newWindow = winio_window(buffer, 0x4000, WW_HASMENU);
  477.     winio_setcurrent(newWindow);
  478.  
  479.     // Turn off repaints while blasting out the data
  480.     winio_setbusy();
  481.     winio_setpaint(winio_current(), FALSE);
  482.     
  483.     DisplayModule(hModule);
  484.  
  485.     // Turn repaints back on, and position to the top of the info
  486.     winio_setpaint(winio_current(), TRUE);
  487.     winio_resetbusy();
  488.     winio_home(newWindow);
  489. }
  490.  
  491. int main()
  492. {
  493.     winio_about("WINMOD"
  494.         "\nWindows module list browser"
  495.         "\n\nFrom Chapter 5 of"
  496.         "\n\"Undocumented Windows\" (Addison-Wesley, 1992)"
  497.         "\nby Andrew Schulman, David Maxey and Matt Pietrek"
  498.         );
  499.     
  500.     // GetVersion returns in AX register.  Flip the byte registers to
  501.     // produce a sensible version, with the major revision in ah, and
  502.     // the minor revision in AL.  When done, store away in WinVersion.
  503.     GetVersion();
  504.     asm     xchg    ah, al
  505.     asm     mov     [WinVersion], ax
  506.     
  507.     // Create the list of modules for the user to click on
  508.     ModuleWalk();
  509.  
  510.     // Install a double click handler
  511.     winio_setlinefn(winio_current(), DumpModule);
  512.         
  513.     return 0;
  514. }
  515.  
  516.