Commit 385ce627 authored by Alexandre Julliard's avatar Alexandre Julliard

winedump: Dump the alternate version of some data directories for hybrid PE dlls.

parent 41e708da
......@@ -33,6 +33,7 @@
#define IMAGE_DLLCHARACTERISTICS_PREFER_NATIVE 0x0010 /* Wine extension */
static const IMAGE_NT_HEADERS32* PE_nt_headers;
static const IMAGE_NT_HEADERS32* PE_alt_headers; /* alternative headers for hybrid dlls */
static const char builtin_signature[] = "Wine builtin DLL";
static const char fakedll_signature[] = "Wine placeholder DLL";
......@@ -105,11 +106,11 @@ void print_fake_dll( void )
}
}
static const void *get_dir_and_size(unsigned int idx, unsigned int *size)
static const void *get_data_dir(const IMAGE_NT_HEADERS32 *hdr, unsigned int idx, unsigned int *size)
{
if(PE_nt_headers->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC)
if(hdr->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC)
{
const IMAGE_OPTIONAL_HEADER64 *opt = (const IMAGE_OPTIONAL_HEADER64*)&PE_nt_headers->OptionalHeader;
const IMAGE_OPTIONAL_HEADER64 *opt = (const IMAGE_OPTIONAL_HEADER64*)&hdr->OptionalHeader;
if (idx >= opt->NumberOfRvaAndSizes)
return NULL;
if(size)
......@@ -119,7 +120,7 @@ static const void *get_dir_and_size(unsigned int idx, unsigned int *size)
}
else
{
const IMAGE_OPTIONAL_HEADER32 *opt = (const IMAGE_OPTIONAL_HEADER32*)&PE_nt_headers->OptionalHeader;
const IMAGE_OPTIONAL_HEADER32 *opt = (const IMAGE_OPTIONAL_HEADER32*)&hdr->OptionalHeader;
if (idx >= opt->NumberOfRvaAndSizes)
return NULL;
if(size)
......@@ -129,11 +130,25 @@ static const void *get_dir_and_size(unsigned int idx, unsigned int *size)
}
}
static const void *get_dir_and_size(unsigned int idx, unsigned int *size)
{
return get_data_dir( PE_nt_headers, idx, size );
}
static const void* get_dir(unsigned idx)
{
return get_dir_and_size(idx, 0);
}
static const void *get_alt_dir_and_size(unsigned int idx, unsigned int *size)
{
const void *dir;
if (!PE_alt_headers) return NULL;
dir = get_data_dir( PE_alt_headers, idx, size );
if (dir == get_dir(idx)) return NULL;
return dir;
}
static const char * const DirectoryNames[16] = {
"EXPORT", "IMPORT", "RESOURCE", "EXCEPTION",
"SECURITY", "BASERELOC", "DEBUG", "ARCHITECTURE",
......@@ -386,9 +401,8 @@ void dump_file_header(const IMAGE_FILE_HEADER *fileHeader, BOOL is_hybrid)
}
printf(" Machine: %04X (%s)\n", fileHeader->Machine, name);
printf(" Number of Sections: %d\n", fileHeader->NumberOfSections);
printf(" TimeDateStamp: %08X (%s) offset %lu\n",
(UINT)fileHeader->TimeDateStamp, get_time_str(fileHeader->TimeDateStamp),
Offset(&(fileHeader->TimeDateStamp)));
printf(" TimeDateStamp: %08X (%s)\n",
(UINT)fileHeader->TimeDateStamp, get_time_str(fileHeader->TimeDateStamp));
printf(" PointerToSymbolTable: %08X\n", (UINT)fileHeader->PointerToSymbolTable);
printf(" NumberOfSymbols: %08X\n", (UINT)fileHeader->NumberOfSymbols);
printf(" SizeOfOptionalHeader: %04X\n", (UINT)fileHeader->SizeOfOptionalHeader);
......@@ -417,7 +431,13 @@ void dump_file_header(const IMAGE_FILE_HEADER *fileHeader, BOOL is_hybrid)
static void dump_pe_header(void)
{
dump_file_header(&PE_nt_headers->FileHeader, get_hybrid_metadata() != 0);
dump_optional_header((const IMAGE_OPTIONAL_HEADER32*)&PE_nt_headers->OptionalHeader, PE_nt_headers->FileHeader.SizeOfOptionalHeader);
dump_optional_header((const IMAGE_OPTIONAL_HEADER32*)&PE_nt_headers->OptionalHeader,
PE_nt_headers->FileHeader.SizeOfOptionalHeader);
if (!PE_alt_headers) return;
printf( "Alternate Headers\n\n");
dump_file_header(&PE_alt_headers->FileHeader, FALSE);
dump_optional_header((const IMAGE_OPTIONAL_HEADER32*)&PE_alt_headers->OptionalHeader,
PE_alt_headers->FileHeader.SizeOfOptionalHeader);
}
void dump_section_characteristics(DWORD characteristics, const char* sep)
......@@ -641,58 +661,65 @@ static void dump_section_apiset(void)
static void dump_dir_exported_functions(void)
{
unsigned int size = 0;
const IMAGE_EXPORT_DIRECTORY*exportDir = get_dir_and_size(IMAGE_FILE_EXPORT_DIRECTORY, &size);
UINT i, *funcs;
unsigned int size[2] = { 0 };
const IMAGE_EXPORT_DIRECTORY *dirs[2];
UINT dir, i, *funcs;
const UINT *pFunc;
const UINT *pName;
const WORD *pOrdl;
if (!exportDir) return;
dirs[0] = get_dir_and_size(IMAGE_FILE_EXPORT_DIRECTORY, &size[0]);
if (!dirs[0]) return;
dirs[1] = get_alt_dir_and_size(IMAGE_FILE_EXPORT_DIRECTORY, &size[1]);
printf("Exports table:\n");
for (dir = 0; dir < 2 && dirs[dir]; dir++)
{
if (dir) printf("Alternate (%s) exports table:\n",
get_machine_str(PE_alt_headers->FileHeader.Machine));
else printf("Exports table:\n");
printf("\n");
printf(" Name: %s\n", (const char*)RVA(exportDir->Name, sizeof(DWORD)));
printf(" Characteristics: %08x\n", (UINT)exportDir->Characteristics);
printf(" Name: %s\n", (const char*)RVA(dirs[dir]->Name, sizeof(DWORD)));
printf(" Characteristics: %08x\n", (UINT)dirs[dir]->Characteristics);
printf(" TimeDateStamp: %08X %s\n",
(UINT)exportDir->TimeDateStamp, get_time_str(exportDir->TimeDateStamp));
printf(" Version: %u.%02u\n", exportDir->MajorVersion, exportDir->MinorVersion);
printf(" Ordinal base: %u\n", (UINT)exportDir->Base);
printf(" # of functions: %u\n", (UINT)exportDir->NumberOfFunctions);
printf(" # of Names: %u\n", (UINT)exportDir->NumberOfNames);
printf("Addresses of functions: %08X\n", (UINT)exportDir->AddressOfFunctions);
printf("Addresses of name ordinals: %08X\n", (UINT)exportDir->AddressOfNameOrdinals);
printf("Addresses of names: %08X\n", (UINT)exportDir->AddressOfNames);
(UINT)dirs[dir]->TimeDateStamp, get_time_str(dirs[dir]->TimeDateStamp));
printf(" Version: %u.%02u\n", dirs[dir]->MajorVersion, dirs[dir]->MinorVersion);
printf(" Ordinal base: %u\n", (UINT)dirs[dir]->Base);
printf(" # of functions: %u\n", (UINT)dirs[dir]->NumberOfFunctions);
printf(" # of Names: %u\n", (UINT)dirs[dir]->NumberOfNames);
printf("Addresses of functions: %08X\n", (UINT)dirs[dir]->AddressOfFunctions);
printf("Addresses of name ordinals: %08X\n", (UINT)dirs[dir]->AddressOfNameOrdinals);
printf("Addresses of names: %08X\n", (UINT)dirs[dir]->AddressOfNames);
printf("\n");
printf(" Entry Pt Ordn Name\n");
pFunc = RVA(exportDir->AddressOfFunctions, exportDir->NumberOfFunctions * sizeof(DWORD));
pFunc = RVA(dirs[dir]->AddressOfFunctions, dirs[dir]->NumberOfFunctions * sizeof(DWORD));
if (!pFunc) {printf("Can't grab functions' address table\n"); return;}
pName = RVA(exportDir->AddressOfNames, exportDir->NumberOfNames * sizeof(DWORD));
pOrdl = RVA(exportDir->AddressOfNameOrdinals, exportDir->NumberOfNames * sizeof(WORD));
pName = RVA(dirs[dir]->AddressOfNames, dirs[dir]->NumberOfNames * sizeof(DWORD));
pOrdl = RVA(dirs[dir]->AddressOfNameOrdinals, dirs[dir]->NumberOfNames * sizeof(WORD));
funcs = calloc( exportDir->NumberOfFunctions, sizeof(*funcs) );
funcs = calloc( dirs[dir]->NumberOfFunctions, sizeof(*funcs) );
if (!funcs) fatal("no memory");
for (i = 0; i < exportDir->NumberOfNames; i++) funcs[pOrdl[i]] = pName[i];
for (i = 0; i < dirs[dir]->NumberOfNames; i++) funcs[pOrdl[i]] = pName[i];
for (i = 0; i < exportDir->NumberOfFunctions; i++)
for (i = 0; i < dirs[dir]->NumberOfFunctions; i++)
{
if (!pFunc[i]) continue;
printf(" %08X %5u ", pFunc[i], (UINT)exportDir->Base + i);
printf(" %08X %5u ", pFunc[i], (UINT)dirs[dir]->Base + i);
if (funcs[i])
printf("%s", get_symbol_str((const char*)RVA(funcs[i], sizeof(DWORD))));
else
printf("<by ordinal>");
/* check for forwarded function */
if ((const char *)RVA(pFunc[i],1) >= (const char *)exportDir &&
(const char *)RVA(pFunc[i],1) < (const char *)exportDir + size)
if ((const char *)RVA(pFunc[i],1) >= (const char *)dirs[dir] &&
(const char *)RVA(pFunc[i],1) < (const char *)dirs[dir] + size[dir])
printf(" (-> %s)", (const char *)RVA(pFunc[i],1));
printf("\n");
}
free(funcs);
printf("\n");
}
}
......@@ -1652,34 +1679,43 @@ static void dump_arm64_unwind_info( const struct runtime_function_arm64 *func )
static void dump_dir_exceptions(void)
{
unsigned int i, size = 0;
const void *funcs = get_dir_and_size(IMAGE_FILE_EXCEPTION_DIRECTORY, &size);
const IMAGE_FILE_HEADER *file_header = &PE_nt_headers->FileHeader;
unsigned int i, dir, size, sizes[2] = { 0 };
const void *funcs[2];
const IMAGE_FILE_HEADER *file_header;
if (!funcs) return;
funcs[0] = get_dir_and_size(IMAGE_FILE_EXCEPTION_DIRECTORY, &sizes[0]);
if (!funcs[0]) return;
funcs[1] = get_alt_dir_and_size(IMAGE_FILE_EXCEPTION_DIRECTORY, &sizes[1]);
for (dir = 0; dir < 2 && funcs[dir]; dir++)
{
size = sizes[dir];
file_header = dir ? &PE_alt_headers->FileHeader : &PE_nt_headers->FileHeader;
switch (file_header->Machine)
{
case IMAGE_FILE_MACHINE_AMD64:
size /= sizeof(struct runtime_function_x86_64);
printf( "Exception info (%u functions):\n", size );
for (i = 0; i < size; i++) dump_x86_64_unwind_info( (struct runtime_function_x86_64*)funcs + i );
printf( "%s exception info (%u functions):\n", get_machine_str( file_header->Machine ), size );
for (i = 0; i < size; i++) dump_x86_64_unwind_info( (struct runtime_function_x86_64*)funcs[dir] + i );
break;
case IMAGE_FILE_MACHINE_ARMNT:
size /= sizeof(struct runtime_function_armnt);
printf( "Exception info (%u functions):\n", size );
for (i = 0; i < size; i++) dump_armnt_unwind_info( (struct runtime_function_armnt*)funcs + i );
printf( "%s exception info (%u functions):\n", get_machine_str( file_header->Machine ), size );
for (i = 0; i < size; i++) dump_armnt_unwind_info( (struct runtime_function_armnt*)funcs[dir] + i );
break;
case IMAGE_FILE_MACHINE_ARM64:
size /= sizeof(struct runtime_function_arm64);
printf( "Exception info (%u functions):\n", size );
for (i = 0; i < size; i++) dump_arm64_unwind_info( (struct runtime_function_arm64*)funcs + i );
printf( "%s exception info (%u functions):\n", get_machine_str( file_header->Machine ), size );
for (i = 0; i < size; i++) dump_arm64_unwind_info( (struct runtime_function_arm64*)funcs[dir] + i );
break;
default:
printf( "Exception information not supported for %s binaries\n",
get_machine_str(file_header->Machine));
break;
}
printf( "\n" );
}
}
......@@ -1765,13 +1801,23 @@ static void dump_dir_imported_functions(void)
static void dump_dir_loadconfig(void)
{
unsigned int size;
const IMAGE_LOAD_CONFIG_DIRECTORY32 *loadcfg32 = get_dir_and_size(IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG, &size);
const IMAGE_LOAD_CONFIG_DIRECTORY64 *loadcfg64 = (void*)loadcfg32;
unsigned int dir, size, sizes[2];
const IMAGE_LOAD_CONFIG_DIRECTORY32 *dirs[2];
if (!loadcfg32) return;
size = min( size, loadcfg32->Size );
dirs[0] = get_dir_and_size(IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG, &sizes[0]);
if (!dirs[0]) return;
dirs[1] = get_alt_dir_and_size(IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG, &sizes[1]);
for (dir = 0; dir < 2 && dirs[dir]; dir++)
{
const IMAGE_LOAD_CONFIG_DIRECTORY32 *loadcfg32 = dirs[dir];
const IMAGE_LOAD_CONFIG_DIRECTORY64 *loadcfg64 = (void*)loadcfg32;
size = min( sizes[dir], loadcfg32->Size );
if (dir)
printf( "\nAlternate (%s) loadconfig\n",
get_machine_str( PE_alt_headers->FileHeader.Machine ));
else
printf( "Loadconfig\n" );
print_dword( "Size", loadcfg32->Size );
print_dword( "TimeDateStamp", loadcfg32->TimeDateStamp );
......@@ -1899,6 +1945,7 @@ static void dump_dir_loadconfig(void)
if (size <= offsetof( IMAGE_LOAD_CONFIG_DIRECTORY32, GuardMemcpyFunctionPointer )) return;
print_dword( "GuardMemcpyFunctionPointer", loadcfg32->GuardMemcpyFunctionPointer );
}
}
}
static void dump_dir_delay_imported_functions(void)
......@@ -2137,35 +2184,42 @@ static void dump_dynamic_relocs( const char *ptr, unsigned int size, ULONGLONG s
}
}
static void dump_dir_dynamic_reloc(void)
static const IMAGE_DYNAMIC_RELOCATION_TABLE *get_dyn_reloc_table(void)
{
unsigned int size, section, offset;
const char *ptr, *end;
const IMAGE_SECTION_HEADER *sec;
const IMAGE_DYNAMIC_RELOCATION_TABLE *table;
if (PE_nt_headers->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC)
{
const IMAGE_LOAD_CONFIG_DIRECTORY64 *cfg = get_dir_and_size(IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG, &size);
if (!cfg) return;
if (!cfg) return NULL;
size = min( size, cfg->Size );
if (size <= offsetof( IMAGE_LOAD_CONFIG_DIRECTORY64, DynamicValueRelocTableSection )) return;
if (size <= offsetof( IMAGE_LOAD_CONFIG_DIRECTORY64, DynamicValueRelocTableSection )) return NULL;
offset = cfg->DynamicValueRelocTableOffset;
section = cfg->DynamicValueRelocTableSection;
}
else
{
const IMAGE_LOAD_CONFIG_DIRECTORY32 *cfg = get_dir_and_size(IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG, &size);
if (!cfg) return;
if (!cfg) return NULL;
size = min( size, cfg->Size );
if (size <= offsetof( IMAGE_LOAD_CONFIG_DIRECTORY32, DynamicValueRelocTableSection )) return;
if (size <= offsetof( IMAGE_LOAD_CONFIG_DIRECTORY32, DynamicValueRelocTableSection )) return NULL;
offset = cfg->DynamicValueRelocTableOffset;
section = cfg->DynamicValueRelocTableSection;
}
if (!section || section > PE_nt_headers->FileHeader.NumberOfSections) return;
if (!section || section > PE_nt_headers->FileHeader.NumberOfSections) return NULL;
sec = IMAGE_FIRST_SECTION( PE_nt_headers ) + section - 1;
if (offset >= sec->SizeOfRawData) return;
table = PRD( sec->PointerToRawData + offset, sizeof(*table) );
if (offset >= sec->SizeOfRawData) return NULL;
return PRD( sec->PointerToRawData + offset, sizeof(*table) );
}
static void dump_dir_dynamic_reloc(void)
{
const char *ptr, *end;
const IMAGE_DYNAMIC_RELOCATION_TABLE *table = get_dyn_reloc_table();
if (!table) return;
printf( "Dynamic relocations (version %u)\n\n", (UINT)table->Version );
ptr = (const char *)(table + 1);
......@@ -2207,6 +2261,117 @@ static void dump_dir_dynamic_reloc(void)
printf( "\n" );
}
static const IMAGE_BASE_RELOCATION *get_armx_relocs( unsigned int *size )
{
const char *ptr, *end;
const IMAGE_DYNAMIC_RELOCATION_TABLE *table = get_dyn_reloc_table();
if (!table) return NULL;
ptr = (const char *)(table + 1);
end = ptr + table->Size;
while (ptr < end)
{
switch (table->Version)
{
case 1:
if (PE_nt_headers->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC)
{
const IMAGE_DYNAMIC_RELOCATION64 *reloc = (const IMAGE_DYNAMIC_RELOCATION64 *)ptr;
if (reloc->Symbol == IMAGE_DYNAMIC_RELOCATION_ARM64X)
{
*size = reloc->BaseRelocSize;
return (const IMAGE_BASE_RELOCATION *)(reloc + 1);
}
ptr += sizeof(*reloc) + reloc->BaseRelocSize;
}
else
{
const IMAGE_DYNAMIC_RELOCATION32 *reloc = (const IMAGE_DYNAMIC_RELOCATION32 *)ptr;
if (reloc->Symbol == IMAGE_DYNAMIC_RELOCATION_ARM64X)
{
*size = reloc->BaseRelocSize;
return (const IMAGE_BASE_RELOCATION *)(reloc + 1);
}
ptr += sizeof(*reloc) + reloc->BaseRelocSize;
}
break;
case 2:
if (PE_nt_headers->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC)
{
const IMAGE_DYNAMIC_RELOCATION64_V2 *reloc = (const IMAGE_DYNAMIC_RELOCATION64_V2 *)ptr;
if (reloc->Symbol == IMAGE_DYNAMIC_RELOCATION_ARM64X)
{
*size = reloc->FixupInfoSize;
return (const IMAGE_BASE_RELOCATION *)(reloc + 1);
}
ptr += reloc->HeaderSize + reloc->FixupInfoSize;
}
else
{
const IMAGE_DYNAMIC_RELOCATION32_V2 *reloc = (const IMAGE_DYNAMIC_RELOCATION32_V2 *)ptr;
if (reloc->Symbol == IMAGE_DYNAMIC_RELOCATION_ARM64X)
{
*size = reloc->FixupInfoSize;
return (const IMAGE_BASE_RELOCATION *)(reloc + 1);
}
ptr += reloc->HeaderSize + reloc->FixupInfoSize;
}
break;
}
}
return NULL;
}
static const IMAGE_NT_HEADERS32 *get_alt_header( void )
{
unsigned int page_size, size;
const IMAGE_BASE_RELOCATION *end, *reloc = get_armx_relocs( &size );
char *alt_dos;
const IMAGE_NT_HEADERS32 *hdr;
if (!reloc) return NULL;
page_size = PE_nt_headers->OptionalHeader.SectionAlignment;
alt_dos = malloc( page_size );
memcpy( alt_dos, PRD(0, page_size), page_size );
end = (const IMAGE_BASE_RELOCATION *)((const char *)reloc + size);
hdr = (const IMAGE_NT_HEADERS32 *)(alt_dos + ((IMAGE_DOS_HEADER *)alt_dos)->e_lfanew);
while (reloc < end - 1 && reloc->SizeOfBlock)
{
const USHORT *rel = (const USHORT *)(reloc + 1);
const USHORT *rel_end = (const USHORT *)reloc + reloc->SizeOfBlock / sizeof(USHORT);
if (!reloc->VirtualAddress) /* only apply relocs to page 0 */
{
while (rel < rel_end && *rel)
{
USHORT offset = *rel & 0xfff;
USHORT type = (*rel >> 12) & 3;
USHORT arg = *rel >> 14;
int val;
rel++;
switch (type)
{
case 0: /* zero-fill */
memset( alt_dos + offset, 0, 1 << arg );
break;
case 1: /* set value */
memcpy( alt_dos + offset, rel, 1 << arg );
rel += (1 << arg) / sizeof(USHORT);
break;
case 2: /* add value */
val = (unsigned int)*rel++ * ((arg & 2) ? 8 : 4);
if (arg & 1) val = -val;
*(int *)(alt_dos + offset) += val;
break;
}
}
}
reloc = (const IMAGE_BASE_RELOCATION *)rel_end;
}
return hdr;
}
static void dump_dir_reloc(void)
{
unsigned int i, size = 0;
......@@ -2673,6 +2838,7 @@ enum FileSig get_kind_exec(void)
void pe_dump(void)
{
PE_nt_headers = get_nt_header();
PE_alt_headers = get_alt_header();
print_fake_dll();
if (globals.do_dumpheader)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment