home *** CD-ROM | disk | FTP | other *** search
- /*
- WINMOD.C -- Windows module list browser
-
- From Chapter 5 of "Undocumented Windows" (Addison-Wesley 1992)
- by Andrew Schulman, Dave Maxey and Matt Pietrek
-
- Build using: WINIOBC WINMOD (for Borland C++ v3.00)
- WINIOMS WINMOD (for Microsoft C/SDK)
- */
-
- #include <windows.h>
- #include <stdio.h>
- #include <string.h>
- #include <dos.h>
- #include "winio.h"
- #include "modtable.h"
-
- #ifndef __BORLANDC__
- #define asm _asm
- #define MK_FP(a,b) ((void far *)(((unsigned long)(a) << 16) | (b)))
- #endif
-
- #define NE_SIGNATURE 0x454E
-
- WORD WinVersion;
-
- char *ResourceNames[] =
- {
- "Unknown",
- "Cursor", // 1
- "Bitmap", // 2
- "Icon", // 3
- "Menu", // 4
- "Dialog", // 5
- "String Table", // 6
- "Font Directory", // 7
- "Font", // 8
- "Accelerator", // 9
- "RC Data", //10
- "Error Table", //11
- "Group Cursor", //12
- "Unknown", //13
- "Group Icon", //14
- "Name Table", //15
- "Version info" //16
- };
-
- //---------------------------------------------
- // Converts a global handle to a selector value.
- // The proper way would be to use GlobalLock, but
- // GlobalLock will RIP on certain selectors.
- // TOOLHELP does it like this, so...
- //---------------------------------------------
-
- WORD HandleToSel(HANDLE h)
- {
- // In 3.1, handles = (selectors-1)
- // Valid selectors end in a 7 or a F
- // Thus, we can simply make sure the
- // lowest bit is turned on.
- //
- // In 3.0, handles = (selectors+1)
- // Valid selectors end in a 5 or a D
- // Decrement the handle if it's an
- // even value.
-
- if ( WinVersion == 0x030A )
- h |= 0x0001;
-
- else if ( WinVersion < 0x030A )
- if ( (h & 0x0002) == 0x0002 )
- h--;
-
- return h;
- }
-
- //---------------------------------------------
- // Given a module handle, return back the
- // name of the module.
- //---------------------------------------------
-
- char *GetModuleNameFromHandle(HANDLE handle)
- {
- static char name[129];
- char far *moduleTablePtr;
- WORD residentNamesOffset;
- BYTE cbModuleName;
-
- name[0] = 0; // Null out the return string
-
- // create a pointer to the module table
- moduleTablePtr = GlobalLock(handle);
- GlobalUnlock(handle);
- if ( !moduleTablePtr )
- return name;
-
- // Verify that we're really looking at a module table, by
- // looking for the 'NE' signature. If we are, get the
- // module name out of the resident names table.
- if ( *(WORD far *)moduleTablePtr == NE_SIGNATURE )
- {
- // Obtain the resident names table offset, and point to it
- residentNamesOffset = *(WORD far *)(moduleTablePtr + 0x26);
- moduleTablePtr += residentNamesOffset;
-
- // Get the length of the first entry, which is always
- // the module name.
- cbModuleName = *(BYTE far *)moduleTablePtr;
- moduleTablePtr++;
-
- // Use the far string copy to move the name to our local
- // buffer. Then null terminate the local buffer copy.
- _fstrncpy(name, moduleTablePtr, cbModuleName);
- name[cbModuleName] = 0;
- }
-
- return name;
- }
-
- //---------------------------------------------
- // Display each entry in the resource table
- //---------------------------------------------
-
- void DoResourceTable(char far *ptr)
- {
- RESOURCETYPE far *type;
- RESOURCEINFO far *info;
- WORD align;
- char *resourceTypeName;
- WORD i;
-
- printf("Resources:\n");
-
- // Calculate the resource file alignment size
- align = 1 << (*(WORD far *)ptr);
-
- // Point past the alignment size field, to the first entry
- (char far *)type = ptr+2;
-
- // A resource type ID of 0 indicates the end of the list
- while ( type->ID != 0 )
- {
- // Determine what type this resource is
- if ( (type->ID & 0x7FFF ) <= 16 )
- resourceTypeName = ResourceNames[type->ID & 0x7FFF];
- else if ( type->ID == 0x80CC )
- resourceTypeName = "TrueType font";
- else
- resourceTypeName = "Unknown";
-
- // Display information common to all entry of this type
- printf(" ID: %04X %-20s %04X entries fn(): %Fp\n",
- type->ID, resourceTypeName, type->count, type->function);
-
- // 'C' pointer arithmatic at work here!!!
- (RESOURCETYPE far *)info = type+1;
-
- // Now iterate and display all the entries for this resource type.
- // The "info" pointer always points to the next resource instance
- // to be displayed, and is updated with 'C' pointer arithmatic.
- for (i=0; i < type->count; i++)
- {
- printf(" Offs: %05lX Len: %04lX Flags: %04X"
- " Handle: %04X Usage: %04X\n",
- info->offset * (DWORD)align, info->length*(DWORD)align,
- info->flags, info->handle, info->usage );
- info++;
- }
-
- printf("\n");
-
- // The next resource type immediately follows the end
- // of the preceeding resource. Use this info to point
- // to the next resource type section.
- type = (RESOURCETYPE far *)info;
- }
-
- printf("\n");
- }
-
- //---------------------------------------------
- // Display information about each segment in
- // the modules segment table.
- //---------------------------------------------
-
- void DoSegmentTable(void far *a, WORD count)
- {
- MODULE_TABLE_SEGMENT_RECORD far *st = a;
- WORD segSel;
- WORD i;
-
- printf("Segments:\n");
- printf(" # HNDL FILE_SIZE ALLOC_SIZE TYPE\n");
-
- for ( i=1; i <= count; i++, st++)
- {
- printf
- (
- " %02X %04X %04X %04X %s",
- i,
- st->handle,
- st->segment_length,
- st->alloc_size,
- st->flags.segment_type ? "DATA" : "CODE"
- );
-
- if ( st->handle == 0 )
- goto not_present;
-
- // Determine is the "present" bit is set in the
- // descriptor, and report accordingly
- segSel = HandleToSel(st->handle);
- asm lar ax, [segSel]
- asm test ax, 08000h
- asm jz not_present
-
- printf(" PRESENT");
- asm jmp done
-
- not_present: printf(" NON-PRESENT");
-
- done: printf("\n");
- }
-
- printf("\n");
- }
-
- //---------------------------------------------
- // Displays all the modules that are
- // implicitly linked to.
- //---------------------------------------------
-
- void DoModuleTable(HANDLE far *modtab, WORD count)
- {
- WORD i;
-
- printf("Referenced modules:\n");
- printf(" HNDL NAME\n");
-
- for(i=0; i < count; i++)
- printf(" %04X %s\n", modtab[i],
- GetModuleNameFromHandle(modtab[i]));
-
- printf("\n");
- }
-
- //---------------------------------------------
- // Displays the resident names table. This
- // table always contains the module name.
- // DLL's should have WEP's in this table,
- // and any function that is exported by name
- // will appear in this table.
- //---------------------------------------------
-
- void DoResidentNamesTable(char far *t)
- {
- char buffer[129];
- WORD ordinal;
- BYTE length;
-
- printf("Resident names:\n");
- printf(" ORDN NAME\n");
-
- // A 0 byte indicates the end of the table.
- // Entries are a length byte, followed by
- // the string, followed by the entry ordinal
- while ( *t )
- {
- // Obtain the length of this name
- length = *(BYTE far *)t;
-
- // Copy the string to a local buffer,
- // and null terminate it.
- _fstrncpy(buffer, t+1, length);
- buffer[length] = 0;
-
- // The entry ordinal is a WORD immediately
- // following the name
- ordinal = *(WORD far *)(t + length + 1);
-
- printf(" %04X %s\n", ordinal, buffer);
-
- // bump up the pointer to point to
- // the next entry.
- t+= (length + 3);
- }
-
- printf("\n");
- }
-
- //---------------------------------------------
- // High level function to display information
- // about a module, based upon information in
- // the module table
- //---------------------------------------------
-
- void DisplayModule(HANDLE hModule)
- {
- int width = 25;
- WORD sel;
- unsigned char far *ptr;
- MODULE_TABLE far *mt;
- WORD fileDate, fileTime;
-
- sel = HandleToSel(hModule);
- ptr = (unsigned char far *)mt = MK_FP(sel, 0);
-
- // Perform some weird contortions to extract the
- // filename and date/time. Date/Time fields
- // are in MS-DOS bit encoded format.
- printf("%-*s", width, "File");
- fileDate = *(WORD far *)(ptr+mt->ne_pfileinfo+4);
- fileTime = *(WORD far *)(ptr+mt->ne_pfileinfo+6);
- printf
- (
- "%Fs %02u-%02u-%02u %2u:%02u\n",
- (ptr+mt->ne_pfileinfo+8),
- (fileDate >> 5) & 0xF,
- (fileDate & 0x1F),
- (fileDate >> 9) + 80,
- (fileTime >> 11),
- (fileTime >> 5) & 0x3F
- );
-
- printf("%-*s%04X\n", width, "Usage count", mt->ne_usage);
- printf("%-*s%04X\n", width, "DGROUP segment", mt->ne_autodata);
- printf("%-*s%04X\n", width, "Initial heap size", mt->ne_heap);
- printf("%-*s%04X\n", width, "Initial stack size", mt->ne_stack);
- printf("%-*s%Fp\n", width, "Starting CS:IP", mt->ne_csip);
- printf("%-*s%Fp\n", width, "Starting SS:SP", mt->ne_sssp);
- printf("%-*s%u.%02u\n", width, "Minimum Windows version",
- HIBYTE(mt->ne_expver), LOBYTE(mt->ne_expver));
-
- printf("%-*s", width, "Flags");
-
- if ( mt->ne_flags & NENOTP )
- printf("LIBRARY ");
- if ( mt->ne_flags & NESELFLOAD )
- printf("SELF_LOAD ");
- if ( (mt->ne_flags & NEAPPTYP) == 0x100 )
- printf("NON_WIN_API ");
- if ((mt->ne_flags & NEAPPTYP) == 0x200)
- printf("API_COMPAT ");
- if ( (mt->ne_flags & NEAPPTYP) == 0x300 )
- printf("USES_WINAPI ");
- if ( mt->ne_flags & NENONRES )
- printf("NON_RES_CODE ");
- if ( mt->ne_flags & NELIM32 )
- printf("LIM32 ");
- if ( mt->ne_flags & NEPROT )
- printf("PROT_MODE ");
- if ( mt->ne_flags & NEPPLI )
- printf("PER_PROCESS_INIT ");
- if ( mt->ne_flags & NEINST )
- printf("INSTANCE_DATA ");
- if ( mt->ne_flags & NESHARED )
- printf("SHARED_DATA ");
- printf("\n");
-
- printf("%-*s%05lX\n", width,"Non-res names offset", mt->ne_nrestab);
- printf("%-*s%04X\n", width, "Non-res names size", mt->ne_cbnrestab);
-
- printf("\n");
-
- // Only dump segment table if there are segments
- if ( mt->ne_cseg )
- DoSegmentTable(MK_FP(sel, mt->ne_segtab), mt->ne_cseg);
-
- // Calculate length of resource table. Only dump it if
- // it is a non-zero length
- if ( mt->ne_restab - mt->ne_rsrctab )
- DoResourceTable(MK_FP(sel,mt->ne_rsrctab));
-
- // Only dump module table if 1 or more entries
- if ( mt->ne_cmod )
- DoModuleTable( MK_FP(sel,mt->ne_modtab), mt->ne_cmod);
-
- DoResidentNamesTable( MK_FP(sel, mt->ne_restab) );
-
- printf("\n");
- }
-
- //---------------------------------------------
- // Walks the list of modules in the system,
- // calling DisplayModule to dump each one
- // out in turn
- //---------------------------------------------
-
- void ModuleWalk(void)
- {
- HANDLE thisModule;
- WORD hInstance;
- WORD far *signature_word;
-
- // Get our instance handle, which is also our DS.
- // Hint: You can also obtain this value by using
- // the hInstance passed to WinMain. Also, some
- // compilers store the hInstance in a global
- // variable that is accessible to your code.
- asm mov [hInstance], DS
-
- // An undocumented use of GetModuleHandle. The
- // module handle associated with the passed in
- // DS is returned in AX. The handle of the first
- // module in the system (KERNEL) is returned in DX
- GetModuleHandle( MK_FP(0, hInstance) );
- asm mov [thisModule], DX
-
- // Turn off repainting while we blast out the info
- winio_setbusy();
- winio_setpaint(winio_current(), FALSE);
-
- printf("Double-Click on any line for detailed view\n\n");
- printf("MODULE HANDLE\n");
-
- // The list is terminated by a NULL next module handle
- while ( thisModule )
- {
- // Create a far pointer to the module table.
- // Verify that we have a valid table by
- // looking for the 'NE' signature. Abort
- // if not found
- signature_word = MK_FP(thisModule, 0);
- if ( *signature_word != NE_SIGNATURE )
- {
- printf("Error in following module chain\n");
- break;
- }
-
- printf
- (
- "%-8s %04X\n",
- GetModuleNameFromHandle(thisModule),
- thisModule
- );
-
- // The next module handle is at offset 6
- // in the module table
- thisModule = *(HANDLE far *)MK_FP(thisModule, 6);
- }
-
- // Turn the repainting back on, and position to the top of the list
- winio_setpaint(winio_current(), TRUE);
- winio_resetbusy();
- winio_home(winio_current());
- }
-
- void DumpModule(HWND hwnd, LPSTR line, int i)
- {
- char moduleName[80];
- char buffer[80];
- HANDLE hModule;
- int returnCode;
- HWND newWindow;
-
- _fstrcpy(buffer, line);
-
- returnCode = sscanf(buffer, "%s %x", moduleName, &hModule);
-
- if ( returnCode != 2 )
- {
- MessageBox(NULL, "Not a valid line", "Error",
- MB_OK | MB_ICONEXCLAMATION);
- return;
- }
-
- if ( GetModuleHandle(moduleName) != hModule )
- {
- MessageBox(NULL, "Module no longer exist", "Error",
- MB_OK | MB_ICONEXCLAMATION);
- return;
- }
-
- sprintf(buffer, "WinMod: %s", moduleName);
-
- newWindow = winio_window(buffer, 0x4000, WW_HASMENU);
- winio_setcurrent(newWindow);
-
- // Turn off repaints while blasting out the data
- winio_setbusy();
- winio_setpaint(winio_current(), FALSE);
-
- DisplayModule(hModule);
-
- // Turn repaints back on, and position to the top of the info
- winio_setpaint(winio_current(), TRUE);
- winio_resetbusy();
- winio_home(newWindow);
- }
-
- int main()
- {
- winio_about("WINMOD"
- "\nWindows module list browser"
- "\n\nFrom Chapter 5 of"
- "\n\"Undocumented Windows\" (Addison-Wesley, 1992)"
- "\nby Andrew Schulman, David Maxey and Matt Pietrek"
- );
-
- // GetVersion returns in AX register. Flip the byte registers to
- // produce a sensible version, with the major revision in ah, and
- // the minor revision in AL. When done, store away in WinVersion.
- GetVersion();
- asm xchg ah, al
- asm mov [WinVersion], ax
-
- // Create the list of modules for the user to click on
- ModuleWalk();
-
- // Install a double click handler
- winio_setlinefn(winio_current(), DumpModule);
-
- return 0;
- }
-
-