521 lines
15 KiB
C++
521 lines
15 KiB
C++
|
/*++
|
||
|
|
||
|
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();
|
||
|
GetPebAddress( 0, &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, "\\",
|
||
|
(PVOID) &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, "PEB", "Ldr", PebLdrAddress);
|
||
|
if (InitTypeRead(PebLdrAddress, PEB_LDR_DATA)) {
|
||
|
dprintf( " Unable to read 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("PEB_LDR_DATA","InMemoryOrderModuleList", &Offset);
|
||
|
OrderModuleListStart = PebLdrAddress + Offset;
|
||
|
Next = ReadField(InMemoryOrderModuleList.Flink);
|
||
|
break;
|
||
|
|
||
|
case Init:
|
||
|
GetFieldOffset("PEB_LDR_DATA","InInitializationOrderModuleList", &Offset);
|
||
|
OrderModuleListStart = PebLdrAddress + Offset;
|
||
|
Next = ReadField(InInitializationOrderModuleList.Flink);
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
case Load:
|
||
|
GetFieldOffset("PEB_LDR_DATA","InLoadOrderModuleList", &Offset);
|
||
|
OrderModuleListStart = PebLdrAddress + Offset;
|
||
|
Next = ReadField(InLoadOrderModuleList.Flink);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
while (Next != OrderModuleListStart) {
|
||
|
if (CheckControlC()) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
|
||
|
switch (OrderList) {
|
||
|
case Memory:
|
||
|
GetFieldOffset("LDR_DATA_TABLE_ENTRY","InMemoryOrderLinks", &Offset);
|
||
|
pLdrEntry = Next - Offset;
|
||
|
break;
|
||
|
|
||
|
case Init:
|
||
|
GetFieldOffset("LDR_DATA_TABLE_ENTRY","InInitializationOrderLinks", &Offset);
|
||
|
pLdrEntry = Next - Offset;
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
case Load:
|
||
|
GetFieldOffset("LDR_DATA_TABLE_ENTRY","InLoadOrderLinks", &Offset);
|
||
|
pLdrEntry = Next - Offset;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Capture LdrEntry
|
||
|
//
|
||
|
dumpsingleentry:
|
||
|
|
||
|
|
||
|
if (InitTypeRead(pLdrEntry, LDR_DATA_TABLE_ENTRY)) {
|
||
|
dprintf( " Unable to read Ldr Entry at %p\n", pLdrEntry );
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
ZeroMemory( StringData, sizeof( StringData ) );
|
||
|
b = ReadMemory( ReadField(FullDllName.Buffer),
|
||
|
StringData,
|
||
|
(ULONG) ReadField(FullDllName.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;
|
||
|
}
|
||
|
}
|
||
|
}
|