You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1190 lines
36 KiB
1190 lines
36 KiB
/*++
|
|
|
|
Copyright (c) 1990 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
peext.c
|
|
|
|
Abstract:
|
|
|
|
This module contains the PE dump extensions
|
|
|
|
Author:
|
|
|
|
Kent Forschmiedt (kentf) 10-May-1995
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "precomp.h"
|
|
#pragma hdrstop
|
|
#include <time.h>
|
|
|
|
|
|
// STYP_ flags values for MIPS ROM images
|
|
|
|
#define STYP_REG 0x00000000
|
|
#define STYP_TEXT 0x00000020
|
|
#define STYP_INIT 0x80000000
|
|
#define STYP_RDATA 0x00000100
|
|
#define STYP_DATA 0x00000040
|
|
#define STYP_LIT8 0x08000000
|
|
#define STYP_LIT4 0x10000000
|
|
#define STYP_SDATA 0x00000200
|
|
#define STYP_SBSS 0x00000080
|
|
#define STYP_BSS 0x00000400
|
|
#define STYP_LIB 0x40000000
|
|
#define STYP_UCODE 0x00000800
|
|
#define S_NRELOC_OVFL 0x20000000
|
|
|
|
#define IMAGE_SCN_MEM_SYSHEAP 0x00010000 // Obsolete
|
|
#define IMAGE_SCN_MEM_PROTECTED 0x00004000 // Obsolete
|
|
|
|
|
|
const static char * const MachineName[] = {
|
|
"Unknown",
|
|
"i386",
|
|
"Alpha AXP",
|
|
"Alpha AXP64",
|
|
"Intel IA64",
|
|
"AMD 64",
|
|
};
|
|
|
|
const static char * const SubsystemName[] = {
|
|
"Unknown",
|
|
"Native",
|
|
"Windows GUI",
|
|
"Windows CUI",
|
|
"Posix CUI",
|
|
};
|
|
|
|
const static char * const DirectoryEntryName[] = {
|
|
"Export",
|
|
"Import",
|
|
"Resource",
|
|
"Exception",
|
|
"Security",
|
|
"Base Relocation",
|
|
"Debug",
|
|
"Description",
|
|
"Special",
|
|
"Thread Storage",
|
|
"Load Configuration",
|
|
"Bound Import",
|
|
"Import Address Table",
|
|
"Reserved",
|
|
"Reserved",
|
|
"Reserved",
|
|
0
|
|
};
|
|
|
|
typedef enum DFT
|
|
{
|
|
dftUnknown,
|
|
dftObject,
|
|
dftPE,
|
|
dftROM,
|
|
dftDBG,
|
|
dftPEF,
|
|
} DFT;
|
|
|
|
typedef struct NB10I // NB10 debug info
|
|
{
|
|
DWORD nb10; // NB10
|
|
DWORD off; // offset, always 0
|
|
DWORD sig;
|
|
DWORD age;
|
|
} NB10I;
|
|
|
|
IMAGE_NT_HEADERS ImageNtHeaders;
|
|
PIMAGE_FILE_HEADER ImageFileHdr;
|
|
PIMAGE_OPTIONAL_HEADER ImageOptionalHdr;
|
|
PIMAGE_SECTION_HEADER SectionHdrs;
|
|
ULONG64 Base;
|
|
ULONG64 ImageNtHeadersAddr, ImageFileHdrAddr, ImageOptionalHdrAddr, SectionHdrsAddr;
|
|
DFT dft;
|
|
CHAR g_szOptionalHeaderType[MAX_PATH] = {0};
|
|
|
|
VOID
|
|
DumpHeaders (
|
|
VOID
|
|
);
|
|
|
|
VOID
|
|
DumpSections(
|
|
VOID
|
|
);
|
|
|
|
BOOL
|
|
TranslateFilePointerToVirtualAddress(
|
|
IN ULONG64 FilePointer,
|
|
OUT PULONG64 VirtualAddress
|
|
);
|
|
|
|
VOID
|
|
DumpImage(
|
|
ULONG64 xBase,
|
|
BOOL DoHeaders,
|
|
BOOL DoSections
|
|
);
|
|
|
|
VOID
|
|
ImageExtension(
|
|
IN PSTR lpArgs
|
|
);
|
|
|
|
PCHAR
|
|
GetOptHdrType(
|
|
void
|
|
)
|
|
{
|
|
if (!g_szOptionalHeaderType[0])
|
|
{
|
|
strcpy(g_szOptionalHeaderType, "nt!IMAGE_OPTIONAL_HEADER");
|
|
}
|
|
return g_szOptionalHeaderType;
|
|
}
|
|
|
|
VOID
|
|
SetOptHdrType(
|
|
ULONG64 ImageBase,
|
|
ULONG64 ImageFileHeader
|
|
)
|
|
{
|
|
CHAR Buffer[MAX_PATH*2] = {0};
|
|
ULONG MachineType;
|
|
BOOL b64bitImage;
|
|
|
|
if (GetFieldValue(ImageFileHeader, "IMAGE_FILE_HEADER", "Machine", MachineType))
|
|
{
|
|
// default to default for pointer size
|
|
MachineType = IsPtr64() ? IMAGE_FILE_MACHINE_IA64 : IMAGE_FILE_MACHINE_I386;
|
|
}
|
|
if (MachineType == IMAGE_FILE_MACHINE_IA64 ||
|
|
MachineType == IMAGE_FILE_MACHINE_AMD64 ||
|
|
MachineType == IMAGE_FILE_MACHINE_ALPHA64)
|
|
{
|
|
b64bitImage = TRUE;
|
|
} else
|
|
{
|
|
b64bitImage = FALSE;
|
|
}
|
|
|
|
if ((g_ExtSymbols->GetModuleNames(DEBUG_ANY_ID, ImageBase, NULL, 0, NULL,
|
|
Buffer, MAX_PATH, NULL,
|
|
NULL, 0, NULL) == S_OK) &&
|
|
IsPtr64()) // Wee need to do this for WOW64 images only
|
|
{
|
|
StringCchCat(Buffer, sizeof(Buffer), "!IMAGE_OPTIONAL_HEADER");
|
|
if (GetTypeSize(Buffer))
|
|
{
|
|
// Module has IMAGE_OPTIONAL_HEADER type
|
|
StringCchCopy(g_szOptionalHeaderType, sizeof(g_szOptionalHeaderType), Buffer);
|
|
return;
|
|
} else if (b64bitImage)
|
|
{
|
|
// 64 bit images might just have IMAGE_OPTIONAL_HEADER64 defined
|
|
StringCchCat(Buffer, sizeof(Buffer), "64");
|
|
if (GetTypeSize(Buffer))
|
|
{
|
|
// Module has IMAGE_OPTIONAL_HEADER type
|
|
StringCchCopy(g_szOptionalHeaderType, sizeof(g_szOptionalHeaderType), Buffer);
|
|
return;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
if (b64bitImage)
|
|
{
|
|
StringCchCopy(g_szOptionalHeaderType, sizeof(g_szOptionalHeaderType), "IMAGE_OPTIONAL_HEADER64");
|
|
} else
|
|
{
|
|
StringCchCopy(g_szOptionalHeaderType, sizeof(g_szOptionalHeaderType), "IMAGE_OPTIONAL_HEADER");
|
|
}
|
|
}
|
|
|
|
DECLARE_API( dh )
|
|
{
|
|
INIT_API();
|
|
ImageExtension( (PSTR)args );
|
|
EXIT_API();
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
VOID
|
|
ImageExtension(
|
|
IN PSTR lpArgs
|
|
)
|
|
{
|
|
BOOL DoAll;
|
|
BOOL DoSections;
|
|
BOOL DoHeaders;
|
|
CHAR c;
|
|
PCHAR p;
|
|
ULONG64 xBase;
|
|
|
|
//
|
|
// Evaluate the argument string to get the address of the
|
|
// image to dump.
|
|
//
|
|
|
|
DoAll = TRUE;
|
|
DoHeaders = FALSE;
|
|
DoSections = FALSE;
|
|
|
|
xBase = 0;
|
|
|
|
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;
|
|
|
|
default: // invalid switch
|
|
|
|
case 'h': // help
|
|
case 'H':
|
|
case '?':
|
|
|
|
dprintf("Usage: dh [options] address\n");
|
|
dprintf("\n");
|
|
dprintf("Dumps headers from an image based at address.\n");
|
|
dprintf("\n");
|
|
dprintf("Options:\n");
|
|
dprintf("\n");
|
|
dprintf(" -a Dump everything\n");
|
|
dprintf(" -f Dump file headers\n");
|
|
dprintf(" -s Dump section headers\n");
|
|
dprintf("\n");
|
|
|
|
return;
|
|
|
|
case 'f':
|
|
case 'F':
|
|
++lpArgs;
|
|
DoAll = FALSE;
|
|
DoHeaders = TRUE;
|
|
break;
|
|
|
|
case 's':
|
|
case 'S':
|
|
++lpArgs;
|
|
DoAll = FALSE;
|
|
DoSections = TRUE;
|
|
break;
|
|
|
|
}
|
|
|
|
} else if (*lpArgs) {
|
|
|
|
if (xBase != 0) {
|
|
dprintf("Invalid extra argument\n");
|
|
return;
|
|
}
|
|
|
|
p = lpArgs;
|
|
while (*p && !isspace(*p)) {
|
|
p++;
|
|
}
|
|
c = *p;
|
|
*p = 0;
|
|
|
|
xBase = GetExpression(lpArgs);
|
|
|
|
*p = c;
|
|
lpArgs=p;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if ( !xBase ) {
|
|
return;
|
|
}
|
|
|
|
DumpImage(xBase, DoAll || DoHeaders, DoAll || DoSections);
|
|
}
|
|
|
|
VOID
|
|
DumpImage(
|
|
ULONG64 xBase,
|
|
BOOL DoHeaders,
|
|
BOOL DoSections
|
|
)
|
|
{
|
|
IMAGE_DOS_HEADER DosHeader;
|
|
ULONG cb;
|
|
ULONG64 Offset;
|
|
BOOL Ok;
|
|
ULONG OptionalHeaderTypeSize;
|
|
ULONG MachineType;
|
|
|
|
Base = xBase;
|
|
|
|
Ok = ReadMemory(Base, &DosHeader, sizeof(DosHeader), &cb);
|
|
|
|
if (!Ok) {
|
|
dprintf("Can't read file header\n");
|
|
return;
|
|
}
|
|
|
|
if (cb != sizeof(DosHeader) || DosHeader.e_magic != IMAGE_DOS_SIGNATURE) {
|
|
dprintf("No file header.\n");
|
|
return;
|
|
}
|
|
|
|
Offset = Base + DosHeader.e_lfanew;
|
|
|
|
Ok = ReadMemory(Offset, &ImageNtHeaders, sizeof(ImageNtHeaders), &cb);
|
|
ImageNtHeadersAddr = Offset;
|
|
|
|
if (!Ok) {
|
|
dprintf("Can't read optional header\n");
|
|
return;
|
|
}
|
|
|
|
if (InitTypeRead(ImageNtHeadersAddr, IMAGE_NT_HEADERS)) {
|
|
dprintf("Bad file header.\n");
|
|
return;
|
|
}
|
|
|
|
ImageFileHdr = &ImageNtHeaders.FileHeader;
|
|
ImageFileHdrAddr = ReadField(FileHeader);
|
|
ImageOptionalHdr = &ImageNtHeaders.OptionalHeader;
|
|
ImageOptionalHdrAddr = ReadField(OptionalHeader);
|
|
|
|
SetOptHdrType(xBase, ImageFileHdrAddr);
|
|
|
|
if ((ULONG) ReadField(FileHeader.SizeOfOptionalHeader) == GetTypeSize("IMAGE_ROM_OPTIONAL_HEADER")) {
|
|
dft = dftROM;
|
|
} else if (ImageFileHdr->Characteristics & IMAGE_FILE_DLL) {
|
|
dft = dftPE;
|
|
} else if (ImageFileHdr->Characteristics & IMAGE_FILE_EXECUTABLE_IMAGE) {
|
|
dft = dftPE;
|
|
} else if (ImageFileHdr->SizeOfOptionalHeader == 0) {
|
|
dft = dftObject;
|
|
} else {
|
|
dft = dftUnknown;
|
|
}
|
|
|
|
if (DoHeaders) {
|
|
DumpHeaders();
|
|
}
|
|
|
|
OptionalHeaderTypeSize = GetTypeSize(GetOptHdrType());
|
|
|
|
if (DoSections) {
|
|
ULONG SectSize, NumSections;
|
|
ULONG OptHdrOffset = 0;
|
|
|
|
SectSize = GetTypeSize("IMAGE_SECTION_HEADER");
|
|
|
|
// OptionalHeader offset is the same in both 32 and 64 bit binaries, so we not need to
|
|
// set IMAGE_NT_HEADERS type the way we do for IMAGE_OPTIONAL_HEADER
|
|
if (GetFieldOffset("IMAGE_NT_HEADERS", "OptionalHeader", &OptHdrOffset))
|
|
{
|
|
dprintf("Cannot get IMAGE_NT_HEADERS.OptionalHeader type info\n");
|
|
return;
|
|
}
|
|
|
|
InitTypeRead(ImageFileHdrAddr, IMAGE_FILE_HEADER);
|
|
SectionHdrs = (PIMAGE_SECTION_HEADER) malloc((NumSections =(ULONG) ReadField(NumberOfSections) )*
|
|
SectSize);
|
|
__try {
|
|
|
|
SectionHdrsAddr = Offset + OptHdrOffset + OptionalHeaderTypeSize;
|
|
Ok = ReadMemory(
|
|
SectionHdrsAddr,
|
|
SectionHdrs,
|
|
(NumSections) * SectSize,
|
|
&cb);
|
|
|
|
if (!Ok) {
|
|
dprintf("Can't read section headers.\n");
|
|
} else {
|
|
|
|
if (cb != NumSections * SectSize) {
|
|
dprintf("\n***\n*** Some section headers may be missing ***\n***\n\n");
|
|
NumSections = (USHORT)(cb / SectSize);
|
|
}
|
|
|
|
DumpSections( );
|
|
|
|
}
|
|
|
|
}
|
|
__finally {
|
|
|
|
if (SectionHdrs) {
|
|
free(SectionHdrs);
|
|
SectionHdrs = 0;
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
VOID
|
|
DumpHeaders (
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Formats the file header and optional header.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
|
|
{
|
|
int i, j;
|
|
const char *time;
|
|
const char *name;
|
|
DWORD dw;
|
|
ULONG Ptr64;
|
|
ULONG SizeOfOptionalHeader, DirOff, DirSize, OptionalHeaderTypeSize=0;
|
|
time_t TimeDateStamp;
|
|
|
|
|
|
InitTypeRead(ImageFileHdrAddr, IMAGE_FILE_HEADER);
|
|
// Print out file type
|
|
|
|
switch (dft) {
|
|
case dftObject :
|
|
dprintf("\nFile Type: COFF OBJECT\n");
|
|
break;
|
|
|
|
case dftPE :
|
|
if (ReadField(Characteristics) & IMAGE_FILE_DLL) {
|
|
dprintf("\nFile Type: DLL\n");
|
|
} else {
|
|
dprintf("\nFile Type: EXECUTABLE IMAGE\n");
|
|
}
|
|
break;
|
|
|
|
case dftROM :
|
|
dprintf("\nFile Type: ROM IMAGE\n");
|
|
break;
|
|
|
|
default :
|
|
dprintf("\nFile Type: UNKNOWN\n");
|
|
break;
|
|
|
|
}
|
|
|
|
switch (ReadField(Machine)) {
|
|
case IMAGE_FILE_MACHINE_I386 : i = 1; Ptr64 = FALSE; break;
|
|
case IMAGE_FILE_MACHINE_ALPHA : i = 2; Ptr64 = FALSE; break;
|
|
case IMAGE_FILE_MACHINE_ALPHA64 : i = 3; Ptr64 = TRUE; break;
|
|
case IMAGE_FILE_MACHINE_IA64 : i = 4; Ptr64 = TRUE; break;
|
|
case IMAGE_FILE_MACHINE_AMD64 : i = 5; Ptr64 = TRUE; break;
|
|
default : i = 0;
|
|
}
|
|
|
|
dprintf(
|
|
"FILE HEADER VALUES\n"
|
|
"%8hX machine (%s)\n"
|
|
"%8hX number of sections\n"
|
|
"%8lX time date stamp",
|
|
(ULONG) ReadField(Machine),
|
|
MachineName[i],
|
|
(ULONG) ReadField(NumberOfSections),
|
|
TimeDateStamp = (ULONG) ReadField(TimeDateStamp));
|
|
|
|
if ((time = ctime((time_t *) &TimeDateStamp)) != NULL) {
|
|
dprintf( " %s", time);
|
|
}
|
|
dprintf("\n");
|
|
|
|
dprintf(
|
|
"%8lX file pointer to symbol table\n"
|
|
"%8lX number of symbols\n"
|
|
"%8hX size of optional header\n"
|
|
"%8hX characteristics\n",
|
|
(ULONG) ReadField(PointerToSymbolTable),
|
|
(ULONG) ReadField(NumberOfSymbols),
|
|
SizeOfOptionalHeader = (ULONG) ReadField(SizeOfOptionalHeader),
|
|
(ULONG) ReadField(Characteristics));
|
|
|
|
for (dw = (ULONG) ReadField(Characteristics), j = 0; dw; dw >>= 1, j++) {
|
|
if (dw & 1) {
|
|
switch (1 << j) {
|
|
case IMAGE_FILE_RELOCS_STRIPPED : name = "Relocations stripped"; break;
|
|
case IMAGE_FILE_EXECUTABLE_IMAGE : name = "Executable"; break;
|
|
case IMAGE_FILE_LINE_NUMS_STRIPPED : name = "Line numbers stripped"; break;
|
|
case IMAGE_FILE_LOCAL_SYMS_STRIPPED : name = "Symbols stripped"; break;
|
|
case IMAGE_FILE_BYTES_REVERSED_LO : name = "Bytes reversed"; break;
|
|
case IMAGE_FILE_32BIT_MACHINE : name = "32 bit word machine"; break;
|
|
case IMAGE_FILE_DEBUG_STRIPPED : name = "Debug information stripped"; break;
|
|
case IMAGE_FILE_SYSTEM : name = "System"; break;
|
|
case IMAGE_FILE_DLL : name = "DLL"; break;
|
|
case IMAGE_FILE_BYTES_REVERSED_HI : name = ""; break;
|
|
default : name = "RESERVED - UNKNOWN";
|
|
}
|
|
|
|
if (*name) {
|
|
dprintf( " %s\n", name);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (SizeOfOptionalHeader != 0) {
|
|
char szLinkerVersion[30];
|
|
|
|
|
|
OptionalHeaderTypeSize = GetTypeSize(GetOptHdrType());
|
|
GetShortField(ImageOptionalHdrAddr, GetOptHdrType(), 1); // InitTypeRead(ImageOptionalHdrAddr, IMAGE_OPTIONAL_HEADER64);
|
|
|
|
sprintf(szLinkerVersion,
|
|
"%u.%02u",
|
|
(ULONG) ReadField(MajorLinkerVersion),
|
|
(ULONG) ReadField(MinorLinkerVersion));
|
|
|
|
dprintf(
|
|
"\n"
|
|
"OPTIONAL HEADER VALUES\n"
|
|
"%8hX magic #\n"
|
|
"%8s linker version\n"
|
|
"%8lX size of code\n"
|
|
"%8lX size of initialized data\n"
|
|
"%8lX size of uninitialized data\n"
|
|
"%8P address of entry point\n"
|
|
"%8P base of code\n"
|
|
|
|
,
|
|
(ULONG) ReadField(Magic),
|
|
szLinkerVersion,
|
|
(ULONG) ReadField(SizeOfCode),
|
|
(ULONG) ReadField(SizeOfInitializedData),
|
|
(ULONG) ReadField(SizeOfUninitializedData),
|
|
ReadField(AddressOfEntryPoint),
|
|
ReadField(BaseOfCode)
|
|
);
|
|
if (!Ptr64) {
|
|
dprintf("%8P base of data\n",
|
|
ReadField(BaseOfData));
|
|
|
|
}
|
|
}
|
|
|
|
if (dft == dftROM) {
|
|
PIMAGE_ROM_OPTIONAL_HEADER romOptionalHdr;
|
|
|
|
InitTypeRead(ImageOptionalHdrAddr, IMAGE_ROM_OPTIONAL_HEADER);
|
|
// romOptionalHdr = (PIMAGE_ROM_OPTIONAL_HEADER) &ImageOptionalHdr;
|
|
dprintf(
|
|
" ----- rom -----\n"
|
|
"%8lX base of bss\n"
|
|
"%8lX gpr mask\n"
|
|
" cpr mask\n"
|
|
" %08lX %08lX %08lX %08lX\n"
|
|
"%8hX gp value\n",
|
|
(ULONG) ReadField(BaseOfBss),
|
|
(ULONG) ReadField(GprMask),
|
|
(ULONG) ReadField(CprMask[0]),
|
|
(ULONG) ReadField(CprMask[1]),
|
|
(ULONG) ReadField(CprMask[2]),
|
|
(ULONG) ReadField(CprMask[3]),
|
|
(ULONG) ReadField(GpValue));
|
|
}
|
|
|
|
if (SizeOfOptionalHeader == OptionalHeaderTypeSize) {
|
|
char szOSVersion[30];
|
|
char szImageVersion[30];
|
|
char szSubsystemVersion[30];
|
|
|
|
GetShortField(ImageOptionalHdrAddr, GetOptHdrType(), 1); // InitTypeRead(ImageOptionalHdrAddr, IMAGE_OPTIONAL_HEADER64);
|
|
GetFieldOffset(GetOptHdrType(), "DataDirectory", &DirOff);
|
|
|
|
|
|
switch ((ULONG) ReadField(Subsystem)) {
|
|
case IMAGE_SUBSYSTEM_POSIX_CUI : i = 4; break;
|
|
case IMAGE_SUBSYSTEM_WINDOWS_CUI : i = 3; break;
|
|
case IMAGE_SUBSYSTEM_WINDOWS_GUI : i = 2; break;
|
|
case IMAGE_SUBSYSTEM_NATIVE : i = 1; break;
|
|
default : i = 0;
|
|
}
|
|
|
|
sprintf(szOSVersion,
|
|
"%hu.%02hu",
|
|
(USHORT) ReadField(MajorOperatingSystemVersion),
|
|
(USHORT) ReadField(MinorOperatingSystemVersion));
|
|
|
|
sprintf(szImageVersion,
|
|
"%hu.%02hu",
|
|
(USHORT) ReadField(MajorImageVersion),
|
|
(USHORT) ReadField(MinorImageVersion));
|
|
|
|
sprintf(szSubsystemVersion,
|
|
"%hu.%02hu",
|
|
(USHORT) ReadField(MajorSubsystemVersion),
|
|
(USHORT) ReadField(MinorSubsystemVersion));
|
|
|
|
dprintf(
|
|
" ----- new -----\n"
|
|
"%p image base\n"
|
|
"%8lX section alignment\n"
|
|
"%8lX file alignment\n"
|
|
"%8hX subsystem (%s)\n"
|
|
"%8s operating system version\n"
|
|
"%8s image version\n"
|
|
"%8s subsystem version\n",
|
|
ReadField(ImageBase),
|
|
(ULONG) ReadField(SectionAlignment),
|
|
(ULONG) ReadField(FileAlignment),
|
|
(USHORT) ReadField(Subsystem),
|
|
SubsystemName[i],
|
|
szOSVersion,
|
|
szImageVersion,
|
|
szSubsystemVersion);
|
|
dprintf(
|
|
"%8lX size of image\n"
|
|
"%8lX size of headers\n"
|
|
"%8lX checksum\n"
|
|
"%p size of stack reserve\n"
|
|
"%p size of stack commit\n"
|
|
"%p size of heap reserve\n"
|
|
"%p size of heap commit\n",
|
|
(ULONG) ReadField(SizeOfImage),
|
|
(ULONG) ReadField(SizeOfHeaders),
|
|
(ULONG) ReadField(CheckSum),
|
|
ReadField(SizeOfStackReserve),
|
|
ReadField(SizeOfStackCommit),
|
|
ReadField(SizeOfHeapReserve),
|
|
ReadField(SizeOfHeapCommit));
|
|
|
|
dprintf("%p Opt Hdr\n", ImageOptionalHdrAddr);
|
|
DirSize = GetTypeSize("IMAGE_DATA_DIRECTORY");
|
|
|
|
for (i = 0; i < IMAGE_NUMBEROF_DIRECTORY_ENTRIES; i++) {
|
|
if (!DirectoryEntryName[i]) {
|
|
break;
|
|
}
|
|
|
|
InitTypeRead(ImageOptionalHdrAddr + DirOff + i*DirSize, IMAGE_DATA_DIRECTORY);
|
|
dprintf( "%8P [%8lX] address [size] of %s Directory\n",
|
|
ReadField(VirtualAddress),
|
|
(ULONG) ReadField(Size),
|
|
DirectoryEntryName[i]
|
|
);
|
|
}
|
|
|
|
dprintf( "\n" );
|
|
}
|
|
|
|
}
|
|
|
|
|
|
VOID
|
|
DumpSectionHeader (
|
|
IN DWORD i,
|
|
IN ULONG64 Sh
|
|
)
|
|
{
|
|
const char *name;
|
|
char *szUnDName;
|
|
DWORD li, lj;
|
|
WORD memFlags;
|
|
CHAR Name[40];
|
|
|
|
InitTypeRead(Sh, IMAGE_SECTION_HEADER);
|
|
GetFieldValue(Sh, "IMAGE_SECTION_HEADER", "Name", Name);
|
|
|
|
dprintf("\nSECTION HEADER #%hX\n%8.8s name", i, Name);
|
|
|
|
#if 0
|
|
if (Sh->Name[0] == '/') {
|
|
name = SzObjSectionName((char *) Sh->Name, (char *) DumpStringTable);
|
|
|
|
dprintf(" (%s)", name);
|
|
}
|
|
#endif
|
|
dprintf( "\n");
|
|
|
|
dprintf( "%8P %s\n"
|
|
"%8lX virtual address\n"
|
|
"%8lX size of raw data\n"
|
|
"%8lX file pointer to raw data\n"
|
|
"%8lX file pointer to relocation table\n",
|
|
ReadField(Misc.PhysicalAddress),
|
|
(dft == dftObject) ? "physical address" : "virtual size",
|
|
(ULONG) ReadField(VirtualAddress),
|
|
(ULONG) ReadField(SizeOfRawData),
|
|
(ULONG) ReadField(PointerToRawData),
|
|
(ULONG) ReadField(PointerToRelocations));
|
|
|
|
dprintf( "%8lX file pointer to line numbers\n"
|
|
"%8hX number of relocations\n"
|
|
"%8hX number of line numbers\n"
|
|
"%8lX flags\n",
|
|
(ULONG) ReadField(PointerToLinenumbers),
|
|
(ULONG) ReadField(NumberOfRelocations),
|
|
(ULONG) ReadField(NumberOfLinenumbers),
|
|
(ULONG) ReadField(Characteristics));
|
|
|
|
memFlags = 0;
|
|
|
|
li = (ULONG) ReadField(Characteristics);
|
|
|
|
if (dft == dftROM) {
|
|
for (lj = 0L; li; li = li >> 1, lj++) {
|
|
if (li & 1) {
|
|
switch ((li & 1) << lj) {
|
|
case STYP_REG : name = "Regular"; break;
|
|
case STYP_TEXT : name = "Text"; memFlags = 1; break;
|
|
case STYP_INIT : name = "Init Code"; memFlags = 1; break;
|
|
case STYP_RDATA : name = "Data"; memFlags = 2; break;
|
|
case STYP_DATA : name = "Data"; memFlags = 6; break;
|
|
case STYP_LIT8 : name = "Literal 8"; break;
|
|
case STYP_LIT4 : name = "Literal 4"; break;
|
|
case STYP_SDATA : name = "GP Init Data"; memFlags = 6; break;
|
|
case STYP_SBSS : name = "GP Uninit Data"; memFlags = 6; break;
|
|
case STYP_BSS : name = "Uninit Data"; memFlags = 6; break;
|
|
case STYP_LIB : name = "Library"; break;
|
|
case STYP_UCODE : name = "UCode"; break;
|
|
case S_NRELOC_OVFL : name = "Non-Relocatable overlay"; memFlags = 1; break;
|
|
default : name = "RESERVED - UNKNOWN";
|
|
}
|
|
|
|
dprintf( " %s\n", name);
|
|
}
|
|
}
|
|
} else {
|
|
// Clear the padding bits
|
|
|
|
li &= ~0x00700000;
|
|
|
|
for (lj = 0L; li; li = li >> 1, lj++) {
|
|
if (li & 1) {
|
|
switch ((li & 1) << lj) {
|
|
case IMAGE_SCN_TYPE_NO_PAD : name = "No Pad"; break;
|
|
|
|
case IMAGE_SCN_CNT_CODE : name = "Code"; break;
|
|
case IMAGE_SCN_CNT_INITIALIZED_DATA : name = "Initialized Data"; break;
|
|
case IMAGE_SCN_CNT_UNINITIALIZED_DATA : name = "Uninitialized Data"; break;
|
|
|
|
case IMAGE_SCN_LNK_OTHER : name = "Other"; break;
|
|
case IMAGE_SCN_LNK_INFO : name = "Info"; break;
|
|
case IMAGE_SCN_LNK_REMOVE : name = "Remove"; break;
|
|
case IMAGE_SCN_LNK_COMDAT : name = "Communal"; break;
|
|
|
|
case IMAGE_SCN_MEM_DISCARDABLE: name = "Discardable"; break;
|
|
case IMAGE_SCN_MEM_NOT_CACHED: name = "Not Cached"; break;
|
|
case IMAGE_SCN_MEM_NOT_PAGED: name = "Not Paged"; break;
|
|
case IMAGE_SCN_MEM_SHARED : name = "Shared"; break;
|
|
case IMAGE_SCN_MEM_EXECUTE : name = ""; memFlags |= 1; break;
|
|
case IMAGE_SCN_MEM_READ : name = ""; memFlags |= 2; break;
|
|
case IMAGE_SCN_MEM_WRITE : name = ""; memFlags |= 4; break;
|
|
|
|
case IMAGE_SCN_MEM_FARDATA : name = "Far Data"; break;
|
|
case IMAGE_SCN_MEM_SYSHEAP : name = "Sys Heap"; break;
|
|
case IMAGE_SCN_MEM_PURGEABLE: name = "Purgeable or 16-Bit"; break;
|
|
case IMAGE_SCN_MEM_LOCKED : name = "Locked"; break;
|
|
case IMAGE_SCN_MEM_PRELOAD : name = "Preload"; break;
|
|
case IMAGE_SCN_MEM_PROTECTED: name = "Protected"; break;
|
|
|
|
default : name = "RESERVED - UNKNOWN";
|
|
}
|
|
|
|
if (*name) {
|
|
dprintf( " %s\n", name);
|
|
}
|
|
}
|
|
}
|
|
|
|
// print alignment
|
|
|
|
switch ((ULONG) ReadField(Characteristics) & 0x00700000) {
|
|
default: name = "(no align specified)"; break;
|
|
case IMAGE_SCN_ALIGN_1BYTES: name = "1 byte align"; break;
|
|
case IMAGE_SCN_ALIGN_2BYTES: name = "2 byte align"; break;
|
|
case IMAGE_SCN_ALIGN_4BYTES: name = "4 byte align"; break;
|
|
case IMAGE_SCN_ALIGN_8BYTES: name = "8 byte align"; break;
|
|
case IMAGE_SCN_ALIGN_16BYTES: name = "16 byte align"; break;
|
|
case IMAGE_SCN_ALIGN_32BYTES: name = "32 byte align"; break;
|
|
case IMAGE_SCN_ALIGN_64BYTES: name = "64 byte align"; break;
|
|
}
|
|
|
|
dprintf( " %s\n", name);
|
|
}
|
|
|
|
if (memFlags) {
|
|
switch(memFlags) {
|
|
case 1 : name = "Execute Only"; break;
|
|
case 2 : name = "Read Only"; break;
|
|
case 3 : name = "Execute Read"; break;
|
|
case 4 : name = "Write Only"; break;
|
|
case 5 : name = "Execute Write"; break;
|
|
case 6 : name = "Read Write"; break;
|
|
case 7 : name = "Execute Read Write"; break;
|
|
default : name = "Unknown Memory Flags"; break;
|
|
}
|
|
dprintf( " %s\n", name);
|
|
}
|
|
}
|
|
|
|
VOID
|
|
DumpDebugDirectory (
|
|
IN ULONG64 DebugDir
|
|
)
|
|
{
|
|
BOOL Ok;
|
|
DWORD cb;
|
|
NB10I nb10i;
|
|
PIMAGE_DEBUG_MISC miscData;
|
|
PIMAGE_DEBUG_MISC miscDataCur;
|
|
ULONG64 VirtualAddress;
|
|
DWORD len;
|
|
|
|
InitTypeRead(DebugDir, IMAGE_DEBUG_DIRECTORY );
|
|
switch ((ULONG) ReadField(Type)){
|
|
case IMAGE_DEBUG_TYPE_COFF:
|
|
dprintf( "\tcoff ");
|
|
break;
|
|
case IMAGE_DEBUG_TYPE_CODEVIEW:
|
|
dprintf( "\tcv ");
|
|
break;
|
|
case IMAGE_DEBUG_TYPE_FPO:
|
|
dprintf( "\tfpo ");
|
|
break;
|
|
case IMAGE_DEBUG_TYPE_MISC:
|
|
dprintf( "\tmisc ");
|
|
break;
|
|
case IMAGE_DEBUG_TYPE_FIXUP:
|
|
dprintf( "\tfixup ");
|
|
break;
|
|
case IMAGE_DEBUG_TYPE_OMAP_TO_SRC:
|
|
dprintf( "\t-> src ");
|
|
break;
|
|
case IMAGE_DEBUG_TYPE_OMAP_FROM_SRC:
|
|
dprintf( "\tsrc -> ");
|
|
break;
|
|
case IMAGE_DEBUG_TYPE_EXCEPTION:
|
|
dprintf( "\tpdata ");
|
|
break;
|
|
default:
|
|
dprintf( "\t(%6lu)", (ULONG) ReadField(Type));
|
|
break;
|
|
}
|
|
dprintf( "%8x %8x %8x",
|
|
(ULONG) ReadField(SizeOfData),
|
|
(ULONG) ReadField(AddressOfRawData),
|
|
(ULONG) ReadField(PointerToRawData));
|
|
|
|
if ((ULONG) ReadField(PointerToRawData) &&
|
|
(ULONG) ReadField(Type) == IMAGE_DEBUG_TYPE_MISC)
|
|
{
|
|
|
|
if (!TranslateFilePointerToVirtualAddress(ReadField(PointerToRawData), &VirtualAddress)) {
|
|
dprintf(" [Debug data not mapped]\n");
|
|
} else {
|
|
|
|
len = (ULONG) ReadField(SizeOfData);
|
|
miscData = (PIMAGE_DEBUG_MISC) malloc(len);
|
|
if (miscData) {
|
|
Ok = ReadMemory(Base + VirtualAddress, miscData, len, &cb);
|
|
|
|
if (!Ok || cb != len) {
|
|
dprintf("Can't read debug data\n");
|
|
} else {
|
|
|
|
miscDataCur = miscData;
|
|
do {
|
|
if (miscDataCur->DataType == IMAGE_DEBUG_MISC_EXENAME) {
|
|
if (ImageOptionalHdr->MajorLinkerVersion == 2 &&
|
|
ImageOptionalHdr->MinorLinkerVersion < 37) {
|
|
dprintf( "\tImage Name: %s", miscDataCur->Reserved);
|
|
} else {
|
|
dprintf( "\tImage Name: %s", miscDataCur->Data);
|
|
}
|
|
break;
|
|
}
|
|
len -= miscDataCur->Length;
|
|
miscDataCur = (PIMAGE_DEBUG_MISC) ((PCHAR) miscDataCur + miscData->Length);
|
|
} while (len > 0);
|
|
|
|
}
|
|
|
|
free(miscData);
|
|
} else {
|
|
dprintf("Cannot allocate memory for reading debug data\n");
|
|
}
|
|
}
|
|
}
|
|
|
|
if ((ULONG) ReadField(PointerToRawData) &&
|
|
(ULONG) ReadField(Type) == IMAGE_DEBUG_TYPE_CODEVIEW)
|
|
{
|
|
if (!TranslateFilePointerToVirtualAddress((ULONG) ReadField(PointerToRawData), &VirtualAddress)) {
|
|
dprintf(" [Debug data not mapped]\n");
|
|
} else {
|
|
|
|
len = (ULONG) ReadField(SizeOfData);
|
|
|
|
Ok = ReadMemory(Base + VirtualAddress, &nb10i, sizeof(nb10i), &cb);
|
|
|
|
if (!Ok || cb != sizeof(nb10i)) {
|
|
dprintf("Can't read debug data\n");
|
|
} else {
|
|
dprintf( "\tFormat: %4.4s", &nb10i.nb10);
|
|
|
|
if (nb10i.nb10 == '01BN') {
|
|
CHAR PdbName[MAX_PATH];
|
|
|
|
if ((len - sizeof(nb10i) > MAX_PATH))
|
|
len = MAX_PATH;
|
|
|
|
Ok = ReadMemory(Base + VirtualAddress + sizeof(nb10i), PdbName, len-sizeof(nb10i), &cb);
|
|
if (!Ok || cb != len-sizeof(nb10i)) {
|
|
strcpy(PdbName, "<pdb name unavailable>");
|
|
}
|
|
dprintf( ", %x, %x, %s", nb10i.sig, nb10i.age, PdbName);
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
dprintf( "\n");
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
DumpDebugDirectories (
|
|
ULONG64 sh
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Print out the contents of all debug directories
|
|
|
|
Arguments:
|
|
|
|
sh - Section header for section that contains debug dirs
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
int numDebugDirs;
|
|
IMAGE_DEBUG_DIRECTORY debugDir;
|
|
ULONG64 DebugDirAddr;
|
|
ULONG64 pc;
|
|
ULONG64 VA;
|
|
DWORD cb, Sz, DebugDirSize;
|
|
BOOL Ok;
|
|
|
|
Sz = GetTypeSize("IMAGE_DATA_DIRECTORY");
|
|
DebugDirSize = GetTypeSize("IMAGE_DEBUG_DIRECTORY");
|
|
if (dft == dftROM) {
|
|
|
|
GetFieldValue(sh, "IMAGE_SECTION_HEADER", "VirtualAddress", VA);
|
|
DebugDirAddr = Base + VA;
|
|
pc = DebugDirAddr;
|
|
if (InitTypeRead(pc, IMAGE_DEBUG_DIRECTORY)) {
|
|
dprintf("Can't read debug dir @%p\n", pc);
|
|
return;
|
|
}
|
|
|
|
numDebugDirs = 0;
|
|
while (ReadField(Type) != 0) {
|
|
numDebugDirs++;
|
|
pc += DebugDirSize;
|
|
if (InitTypeRead(pc, IMAGE_DEBUG_DIRECTORY)) {
|
|
break;
|
|
}
|
|
}
|
|
} else {
|
|
ULONG Off, DirSize;
|
|
|
|
GetFieldOffset(GetOptHdrType(), "DataDirectory", &Off);
|
|
|
|
GetFieldValue(ImageOptionalHdrAddr + Off + Sz*IMAGE_DIRECTORY_ENTRY_DEBUG,
|
|
"IMAGE_DATA_DIRECTORY", "VirtualAddress", VA);
|
|
GetFieldValue(ImageOptionalHdrAddr + Off + Sz*IMAGE_DIRECTORY_ENTRY_DEBUG,
|
|
"IMAGE_DATA_DIRECTORY", "Size", DirSize);
|
|
|
|
DebugDirAddr = Base + VA; // ImageOptionalHdr->DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress;
|
|
numDebugDirs = DirSize / DebugDirSize;
|
|
// dprintf(" DD @%p, DD addr %p\n", ImageOptionalHdrAddr + Off + Sz*IMAGE_DIRECTORY_ENTRY_DEBUG,
|
|
// DebugDirAddr);
|
|
// ImageOptionalHdr->DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].Size / sizeof(IMAGE_DEBUG_DIRECTORY);
|
|
}
|
|
|
|
dprintf("\n\nDebug Directories(%d)\n",numDebugDirs);
|
|
dprintf("\tType Size Address Pointer\n\n");
|
|
pc = DebugDirAddr;
|
|
while (numDebugDirs) {
|
|
if (InitTypeRead(pc, IMAGE_DEBUG_DIRECTORY)) {
|
|
dprintf("Can't read debug dir @%p\n", pc);
|
|
break;
|
|
}
|
|
DumpDebugDirectory(pc);
|
|
pc += Sz;
|
|
numDebugDirs--;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
DumpSections(
|
|
VOID
|
|
)
|
|
{
|
|
ULONG64 sh;
|
|
const char *p;
|
|
DWORD64 li;
|
|
DWORD cb;
|
|
BOOL Ok;
|
|
ULONG i, j;
|
|
CHAR szName[IMAGE_SIZEOF_SHORT_NAME + 1];
|
|
ULONG NumberOfSections, SectSize, Characteristics;
|
|
|
|
|
|
GetFieldValue(ImageFileHdrAddr, "IMAGE_FILE_HEADER", "NumberOfSections", NumberOfSections);
|
|
GetFieldValue(ImageFileHdrAddr, "IMAGE_FILE_HEADER", "Characteristics", Characteristics);
|
|
SectSize = GetTypeSize("IMAGE_SECTION_HEADER");
|
|
|
|
for (i = 1; i <= NumberOfSections; i++) {
|
|
|
|
sh = SectionHdrsAddr + (i-1)*SectSize;
|
|
|
|
//szName = SzObjSectionName((char *) sh.Name, (char *) DumpStringTable);
|
|
GetFieldValue(sh, "IMAGE_SECTION_HEADER", "Name", szName);
|
|
// strncpy(szName, (char *) sh.Name, IMAGE_SIZEOF_SHORT_NAME);
|
|
szName[IMAGE_SIZEOF_SHORT_NAME] = 0;
|
|
|
|
DumpSectionHeader(i, sh);
|
|
|
|
if (dft == dftROM) {
|
|
|
|
if (!(Characteristics & IMAGE_FILE_DEBUG_STRIPPED)) {
|
|
|
|
// If we're looking at the .rdata section and the symbols
|
|
// aren't stripped, the debug directory must be here.
|
|
|
|
if (!strcmp(szName, ".rdata")) {
|
|
|
|
DumpDebugDirectories(sh);
|
|
|
|
//DumpDebugData(&sh);
|
|
}
|
|
}
|
|
|
|
} else if (dft == dftPE) {
|
|
CHAR tmp[40];
|
|
ULONG64 VA;
|
|
|
|
sprintf(tmp, "DataDirectory[%d].VirtualAddress", IMAGE_DIRECTORY_ENTRY_DEBUG);
|
|
GetFieldValue(ImageOptionalHdrAddr, GetOptHdrType(), tmp, li);
|
|
// dprintf("Opt Hdr %p, %s = %p", ImageOptionalHdrAddr, tmp, li);
|
|
|
|
if (li != 0) {
|
|
InitTypeRead(sh, IMAGE_SECTION_HEADER);
|
|
VA = ReadField(VirtualAddress);
|
|
if (li >= VA && li < (VA + ReadField(SizeOfRawData))) {
|
|
DumpDebugDirectories(sh);
|
|
|
|
//DumpDebugData(&sh);
|
|
}
|
|
}
|
|
|
|
|
|
#if 0
|
|
if (Switch.Dump.PData) {
|
|
li = ImageOptionalHdr->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXCEPTION].VirtualAddress;
|
|
|
|
if ((li != 0) && (li >= sh.VirtualAddress) && (li < sh.VirtualAddress+sh.SizeOfRawData)) {
|
|
DumpFunctionTable(pimage, rgsym, (char *) DumpStringTable, &sh);
|
|
}
|
|
}
|
|
|
|
if (Switch.Dump.Imports) {
|
|
li = ImageOptionalHdr->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;
|
|
|
|
if ((li != 0) && (li >= sh.VirtualAddress) && (li < sh.VirtualAddress+sh.SizeOfRawData)) {
|
|
DumpImports(&sh);
|
|
}
|
|
}
|
|
|
|
if (Switch.Dump.Exports) {
|
|
li = ImageOptionalHdr->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
|
|
|
|
if ((li != 0) && (li >= sh.VirtualAddress) && (li < sh.VirtualAddress+sh.SizeOfRawData)) {
|
|
// UNDONE: Is this check really necessary?
|
|
|
|
if (ImageFileHdr->Machine != IMAGE_FILE_MACHINE_MPPC_601) {
|
|
DumpExports(&sh);
|
|
}
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
BOOL
|
|
TranslateFilePointerToVirtualAddress(
|
|
IN ULONG64 FilePointer,
|
|
OUT PULONG64 VirtualAddress
|
|
)
|
|
{
|
|
ULONG i;
|
|
ULONG64 sh;
|
|
ULONG NumberOfSections, SectSize, Characteristics;
|
|
|
|
|
|
GetFieldValue(ImageFileHdrAddr, "IMAGE_FILE_HEADER", "NumberOfSections", NumberOfSections);
|
|
GetFieldValue(ImageFileHdrAddr, "IMAGE_FILE_HEADER", "Characteristics", Characteristics);
|
|
SectSize = GetTypeSize("IMAGE_SECTION_HEADER");
|
|
|
|
|
|
for (i = 1; i <= NumberOfSections; i++) {
|
|
sh = SectionHdrsAddr + (i-1)*SectSize;
|
|
|
|
InitTypeRead(sh, IMAGE_SECTION_HEADER);
|
|
if (ReadField(PointerToRawData) <= FilePointer &&
|
|
FilePointer < ReadField(PointerToRawData) + ReadField(SizeOfRawData)) {
|
|
|
|
*VirtualAddress = FilePointer - ReadField(PointerToRawData) + ReadField(VirtualAddress);
|
|
return TRUE;
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|