/*++ Copyright (c) 1992-2000 Microsoft Corporation Module Name: dlls.c Revision History: --*/ #include "precomp.h" #pragma hdrstop VOID DllsExtension( PCSTR lpArgumentString, ULONG64 ProcessPeb ); DECLARE_API( dlls ) /*++ Routine Description: Dump user mode dlls (Kernel debugging) Arguments: args - [address [detail]] Return Value: None --*/ { ULONG64 Process, Peb; INIT_API(); Peb = GetExpression("@$peb"); DllsExtension( args, Peb ); EXIT_API(); return S_OK; } void ShowImageVersionInfo( ULONG64 DllBase ) { VS_FIXEDFILEINFO FixedVer; ULONG SizeRead; CHAR VersionBuffer[100]; CHAR FileStr[MAX_PATH]= {0}; BOOL ResFileVerStrOk = FALSE; BOOL ResProdVerStrOk = FALSE; struct LANGANDCODEPAGE { WORD wLanguage; WORD wCodePage; } Translate; if (g_ExtSymbols->GetModuleVersionInformation(DEBUG_ANY_ID, DllBase, "\\VarFileInfo\\Translation", (PVOID) &Translate, sizeof(Translate), &SizeRead) == S_OK) { sprintf(VersionBuffer, "\\StringFileInfo\\%04X%04X\\CompanyName", Translate.wLanguage, Translate.wCodePage); if (g_ExtSymbols->GetModuleVersionInformation(DEBUG_ANY_ID, DllBase, VersionBuffer, (PVOID) FileStr, sizeof(FileStr), &SizeRead) == S_OK) { FileStr[SizeRead] = 0; dprintf(" Company Name %s\n", FileStr); } sprintf(VersionBuffer, "\\StringFileInfo\\%04X%04X\\ProductName", Translate.wLanguage, Translate.wCodePage); if (g_ExtSymbols->GetModuleVersionInformation(DEBUG_ANY_ID, DllBase, VersionBuffer, (PVOID) FileStr, sizeof(FileStr), &SizeRead) == S_OK) { FileStr[SizeRead] = 0; dprintf(" Product Name %s\n", FileStr); } sprintf(VersionBuffer, "\\StringFileInfo\\%04X%04X\\ProductVersion", Translate.wLanguage, Translate.wCodePage); if (g_ExtSymbols->GetModuleVersionInformation(DEBUG_ANY_ID, DllBase, VersionBuffer, (PVOID) FileStr, sizeof(FileStr), &SizeRead) == S_OK) { ResProdVerStrOk = TRUE; FileStr[SizeRead] = 0; dprintf(" Product Version %s\n", FileStr); } sprintf(VersionBuffer, "\\StringFileInfo\\%04X%04X\\OriginalFilename", Translate.wLanguage, Translate.wCodePage); if (g_ExtSymbols->GetModuleVersionInformation(DEBUG_ANY_ID, DllBase, VersionBuffer, (PVOID) FileStr, sizeof(FileStr), &SizeRead) == S_OK) { FileStr[SizeRead] = 0; dprintf(" Original Filename %s\n", FileStr); } sprintf(VersionBuffer, "\\StringFileInfo\\%04X%04X\\FileDescription", Translate.wLanguage, Translate.wCodePage); if (g_ExtSymbols->GetModuleVersionInformation(DEBUG_ANY_ID, DllBase, VersionBuffer, (PVOID) FileStr, sizeof(FileStr), &SizeRead) == S_OK) { FileStr[SizeRead] = 0; dprintf(" File Description %s\n", FileStr); } sprintf(VersionBuffer, "\\StringFileInfo\\%04X%04X\\FileVersion", Translate.wLanguage, Translate.wCodePage); if (g_ExtSymbols->GetModuleVersionInformation(DEBUG_ANY_ID, DllBase, VersionBuffer, (PVOID) FileStr, sizeof(FileStr), &SizeRead) == S_OK) { FileStr[SizeRead] = 0; dprintf(" File Version %s\n", FileStr); ResFileVerStrOk = TRUE; } } if (g_ExtSymbols->GetModuleVersionInformation(DEBUG_ANY_ID, DllBase, "\\", &FixedVer, sizeof(FixedVer), &SizeRead) == S_OK) { if (!ResFileVerStrOk) { dprintf(" File version %d.%d.%d.%d\n", FixedVer.dwFileVersionMS >> 16, FixedVer.dwFileVersionMS & 0xFFFF, FixedVer.dwFileVersionLS >> 16, FixedVer.dwFileVersionLS & 0xFFFF); } if (!ResProdVerStrOk) { dprintf(" Product Version %d.%d.%d.%d\n", FixedVer.dwProductVersionMS >> 16, FixedVer.dwProductVersionMS & 0xFFFF, FixedVer.dwProductVersionLS >> 16, FixedVer.dwProductVersionLS & 0xFFFF); } } } typedef enum { Memory = 1, Load = 2, Init = 3 } ELOAD_ORDER; VOID DllsExtension( PCSTR lpArgumentString, ULONG64 ProcessPeb ) { BOOL b; ULONG64 pLdrEntry; ULONG64 PebLdrAddress; ULONG Offset; ULONG64 Next; WCHAR StringData[MAX_PATH+1]; BOOL SingleEntry; BOOL DoHeaders; BOOL DoSections; BOOL DoAll; BOOL ShowVersionInfo; PSTR lpArgs = (PSTR)lpArgumentString; PSTR p; ULONG64 addrContaining = 0; ELOAD_ORDER OrderList = Load; ULONG64 OrderModuleListStart; ULONG64 DllBase; SingleEntry = FALSE; DoAll = FALSE; DoHeaders = FALSE; DoSections = FALSE; ShowVersionInfo = FALSE; #if 0 while ( lpArgumentString != NULL && *lpArgumentString ) { if (*lpArgumentString != ' ') { sscanf(lpArgumentString,"%lx",&pLdrEntry); SingleEntry = TRUE; goto dumpsingleentry; } lpArgumentString++; } #endif while (*lpArgs) { while (isspace(*lpArgs)) { lpArgs++; } if (*lpArgs == '/' || *lpArgs == '-') { // process switch switch (*++lpArgs) { case 'a': // dump everything we can case 'A': ++lpArgs; DoAll = TRUE; break; case 'c': // dump only the dll containing the specified address case 'C': lpArgs += 2; // step over the c and the space. addrContaining = GetExpression(lpArgs); while (*lpArgs && (!isspace(*lpArgs))) { lpArgs++; } if (addrContaining != 0) { dprintf("Dump dll containing 0x%p:\n", addrContaining); } else { dprintf("-c flag requires and address arguement\n"); return; } break; default: // invalid switch case 'h': // help case 'H': case '?': dprintf("Usage: dlls [options] [address]\n"); dprintf("\n"); dprintf("Displays loader table entries. Optionally\n"); dprintf("dumps image and section headers.\n"); dprintf("\n"); dprintf("Options:\n"); dprintf("\n"); dprintf(" -a Dump everything\n"); dprintf(" -c nnn Dump dll containing address nnn\n"); dprintf(" -f Dump file headers\n"); dprintf(" -i Dump dll's in Init order\n"); dprintf(" -l Dump dll's in Load order (the default)\n"); dprintf(" -m Dump dll's in Memory order\n"); dprintf(" -s Dump section headers\n"); dprintf(" -v Dump version info from resource section\n"); dprintf("\n"); return; case 'f': case 'F': ++lpArgs; DoAll = FALSE; DoHeaders = TRUE; break; case 'm': // dump in memory order case 'M': ++lpArgs; OrderList = Memory; break; case 'i': // dump in init order case 'I': ++lpArgs; OrderList = Init; break; case 'l': // dump in load order case 'L': ++lpArgs; OrderList = Load; break; case 's': case 'S': ++lpArgs; DoAll = FALSE; DoSections = TRUE; break; case 'v': case 'V': ++lpArgs; ShowVersionInfo = TRUE; break; } } else if (*lpArgs) { CHAR c; if (SingleEntry) { dprintf("Invalid extra argument\n"); return; } p = lpArgs; while (*p && !isspace(*p)) { p++; } c = *p; *p = 0; pLdrEntry = GetExpression(lpArgs); SingleEntry = TRUE; *p = c; lpArgs=p; } } if (SingleEntry) { goto dumpsingleentry; } // // Capture PebLdrData // GetFieldValue(ProcessPeb, "nt!_PEB", "Ldr", PebLdrAddress); if (InitTypeRead(PebLdrAddress, nt!_PEB_LDR_DATA)) { dprintf( " Unable to read nt!_PEB_LDR_DATA type at %p\n", PebLdrAddress ); return; } // // Walk through the loaded module table and display all ldr data // switch (OrderList) { case Memory: GetFieldOffset("nt!_PEB_LDR_DATA","InMemoryOrderModuleList", &Offset); OrderModuleListStart = PebLdrAddress + Offset; Next = ReadField(InMemoryOrderModuleList.Flink); break; case Init: GetFieldOffset("nt!_PEB_LDR_DATA","InInitializationOrderModuleList", &Offset); OrderModuleListStart = PebLdrAddress + Offset; Next = ReadField(InInitializationOrderModuleList.Flink); break; default: case Load: GetFieldOffset("nt!_PEB_LDR_DATA","InLoadOrderModuleList", &Offset); OrderModuleListStart = PebLdrAddress + Offset; Next = ReadField(InLoadOrderModuleList.Flink); break; } while (Next != OrderModuleListStart) { ULONG Length; if (CheckControlC()) { return; } switch (OrderList) { case Memory: GetFieldOffset("nt!_LDR_DATA_TABLE_ENTRY","InMemoryOrderLinks", &Offset); pLdrEntry = Next - Offset; break; case Init: GetFieldOffset("nt!_LDR_DATA_TABLE_ENTRY","InInitializationOrderLinks", &Offset); pLdrEntry = Next - Offset; break; default: case Load: GetFieldOffset("nt!_LDR_DATA_TABLE_ENTRY","InLoadOrderLinks", &Offset); pLdrEntry = Next - Offset; break; } // // Capture LdrEntry // dumpsingleentry: if (InitTypeRead(pLdrEntry, nt!_LDR_DATA_TABLE_ENTRY)) { dprintf( " Unable to read Ldr Entry at %p\n", pLdrEntry ); return; } Length = (ULONG) ReadField(FullDllName.Length); if (Length >= sizeof(StringData)) { Length = sizeof(StringData) -1; } ZeroMemory( StringData, sizeof( StringData ) ); b = ReadMemory( ReadField(FullDllName.Buffer), StringData, Length, NULL ); if (!b) { dprintf( " Unable to read Module Name\n" ); ZeroMemory( StringData, sizeof( StringData ) ); } // // Dump the ldr entry data // (dump all the entries if no containing address specified) // if ((addrContaining == 0) || ((ReadField(DllBase) <= addrContaining) && (addrContaining <= (ReadField(DllBase) + ReadField(SizeOfImage))) ) ) { ULONG Flags; dprintf( "\n" ); dprintf( "0x%08p: %ws\n", pLdrEntry, StringData[0] ? StringData : L"Unknown Module" ); dprintf( " Base 0x%08p EntryPoint 0x%08p Size 0x%08p\n", DllBase = ReadField(DllBase), ReadField(EntryPoint), ReadField(SizeOfImage) ); dprintf( " Flags 0x%08x LoadCount 0x%08x TlsIndex 0x%08x\n", Flags = (ULONG) ReadField(Flags), (ULONG) ReadField(LoadCount), (ULONG) ReadField(TlsIndex) ); if (Flags & LDRP_STATIC_LINK) { dprintf( " LDRP_STATIC_LINK\n" ); } if (Flags & LDRP_IMAGE_DLL) { dprintf( " LDRP_IMAGE_DLL\n" ); } if (Flags & LDRP_LOAD_IN_PROGRESS) { dprintf( " LDRP_LOAD_IN_PROGRESS\n" ); } if (Flags & LDRP_UNLOAD_IN_PROGRESS) { dprintf( " LDRP_UNLOAD_IN_PROGRESS\n" ); } if (Flags & LDRP_ENTRY_PROCESSED) { dprintf( " LDRP_ENTRY_PROCESSED\n" ); } if (Flags & LDRP_ENTRY_INSERTED) { dprintf( " LDRP_ENTRY_INSERTED\n" ); } if (Flags & LDRP_CURRENT_LOAD) { dprintf( " LDRP_CURRENT_LOAD\n" ); } if (Flags & LDRP_FAILED_BUILTIN_LOAD) { dprintf( " LDRP_FAILED_BUILTIN_LOAD\n" ); } if (Flags & LDRP_DONT_CALL_FOR_THREADS) { dprintf( " LDRP_DONT_CALL_FOR_THREADS\n" ); } if (Flags & LDRP_PROCESS_ATTACH_CALLED) { dprintf( " LDRP_PROCESS_ATTACH_CALLED\n" ); } if (Flags & LDRP_DEBUG_SYMBOLS_LOADED) { dprintf( " LDRP_DEBUG_SYMBOLS_LOADED\n" ); } if (Flags & LDRP_IMAGE_NOT_AT_BASE) { dprintf( " LDRP_IMAGE_NOT_AT_BASE\n" ); } if (Flags & LDRP_COR_IMAGE) { dprintf( " LDRP_COR_IMAGE\n" ); } if (Flags & LDRP_COR_OWNS_UNMAP) { dprintf( " LDR_COR_OWNS_UNMAP\n" ); } if (ShowVersionInfo) { ShowImageVersionInfo(DllBase); } } switch (OrderList) { case Memory: Next = ReadField(InMemoryOrderLinks.Flink); break; case Init: Next = ReadField(InInitializationOrderLinks.Flink); break; default: case Load: Next = ReadField(InLoadOrderLinks.Flink); break; } if (DoAll || DoHeaders || DoSections) { DumpImage( ReadField(DllBase), DoAll || DoHeaders, DoAll || DoSections ); } if (SingleEntry) { return; } } }