From 6f1fd16f92ccbc41999878fce1dc16c9d4d4e283 Mon Sep 17 00:00:00 2001 From: Alexandre Julliard Date: Fri, 18 Feb 2022 10:00:55 +0100 Subject: [PATCH] winedump: Add dumping of the .apiset PE section. Signed-off-by: Alexandre Julliard --- tools/winedump/main.c | 19 +++--- tools/winedump/pe.c | 107 +++++++++++++++++++++++++++++++++ tools/winedump/winedump.man.in | 12 ++-- 3 files changed, 123 insertions(+), 15 deletions(-) diff --git a/tools/winedump/main.c b/tools/winedump/main.c index fd5b44d637d..f9557983465 100644 --- a/tools/winedump/main.c +++ b/tools/winedump/main.c @@ -207,7 +207,8 @@ static const struct my_option option_table[] = { {"-C", DUMP, 0, do_symdmngl, "-C Turn on symbol demangling"}, {"-f", DUMP, 0, do_dumphead, "-f Dump file header information"}, {"-G", DUMP, 0, do_rawdebug, "-G Dump raw debug information"}, - {"-j", DUMP, 1, do_dumpsect, "-j Dump only the content of section 'sect_name' (import, export, debug, resource, tls, loadcfg, clr, reloc, except)"}, + {"-j", DUMP, 1, do_dumpsect, "-j Dump only the content of section 'sect_name'\n" + " (import, export, debug, resource, tls, loadcfg, clr, reloc, except, apiset)"}, {"-t", DUMP, 0, do_symtable, "-t Dump symbol table"}, {"-x", DUMP, 0, do_dumpall, "-x Dump everything"}, {"sym", DMGL, 0, do_demangle, "sym Demangle C++ symbol and exit"}, @@ -232,22 +233,22 @@ void do_usage (const char *arg) const struct my_option *opt; printf ("Usage: winedump [-h | sym | spec | dump ]\n"); printf ("Mode options (can be put as the mode (sym/spec/dump...) is declared):\n"); - printf ("\tWhen used in --help mode\n"); + printf (" When used in --help mode\n"); for (opt = option_table; opt->name; opt++) if (opt->mode == NONE) - printf ("\t %s\n", opt->usage); - printf ("\tWhen used in sym mode\n"); + printf (" %s\n", opt->usage); + printf (" When used in sym mode\n"); for (opt = option_table; opt->name; opt++) if (opt->mode == DMGL) - printf ("\t %s\n", opt->usage); - printf ("\tWhen used in spec mode\n"); + printf (" %s\n", opt->usage); + printf (" When used in spec mode\n"); for (opt = option_table; opt->name; opt++) if (opt->mode == SPEC) - printf ("\t %s\n", opt->usage); - printf ("\tWhen used in dump mode\n"); + printf (" %s\n", opt->usage); + printf (" When used in dump mode\n"); for (opt = option_table; opt->name; opt++) if (opt->mode == DUMP) - printf ("\t %s\n", opt->usage); + printf (" %s\n", opt->usage); puts (""); exit (1); diff --git a/tools/winedump/pe.c b/tools/winedump/pe.c index 6ff14f95791..2207ed9accc 100644 --- a/tools/winedump/pe.c +++ b/tools/winedump/pe.c @@ -491,6 +491,111 @@ static void dump_sections(const void *base, const void* addr, unsigned num_sect) } } +static char *get_str( char *buffer, unsigned int rva, unsigned int len ) +{ + const WCHAR *wstr = PRD( rva, len ); + char *ret = buffer; + + len /= sizeof(WCHAR); + while (len--) *buffer++ = *wstr++; + *buffer = 0; + return ret; +} + +static void dump_section_apiset(void) +{ + const IMAGE_SECTION_HEADER *sect = IMAGE_FIRST_SECTION(PE_nt_headers); + const UINT *ptr, *entry, *value, *hash; + unsigned int i, j, count, val_count, rva; + char buffer[128]; + + for (i = 0; i < PE_nt_headers->FileHeader.NumberOfSections; i++, sect++) + { + if (strncmp( (const char *)sect->Name, ".apiset", 8 )) continue; + rva = sect->PointerToRawData; + ptr = PRD( rva, sizeof(*ptr) ); + printf( "ApiSet section:\n" ); + switch (ptr[0]) /* version */ + { + case 2: + printf( " Version: %u\n", ptr[0] ); + printf( " Count: %08x\n", ptr[1] ); + count = ptr[1]; + if (!(entry = PRD( rva + 2 * sizeof(*ptr), count * 3 * sizeof(*entry) ))) break; + for (i = 0; i < count; i++, entry += 3) + { + printf( " %s ->", get_str( buffer, rva + entry[0], entry[1] )); + if (!(value = PRD( rva + entry[2], sizeof(*value) ))) break; + val_count = *value++; + for (j = 0; j < val_count; j++, value += 4) + { + putchar( ' ' ); + if (value[1]) printf( "%s:", get_str( buffer, rva + value[0], value[1] )); + printf( "%s", get_str( buffer, rva + value[2], value[3] )); + } + printf( "\n"); + } + break; + case 4: + printf( " Version: %u\n", ptr[0] ); + printf( " Size: %08x\n", ptr[1] ); + printf( " Flags: %08x\n", ptr[2] ); + printf( " Count: %08x\n", ptr[3] ); + count = ptr[3]; + if (!(entry = PRD( rva + 4 * sizeof(*ptr), count * 6 * sizeof(*entry) ))) break; + for (i = 0; i < count; i++, entry += 6) + { + printf( " %08x %s ->", entry[0], get_str( buffer, rva + entry[1], entry[2] )); + if (!(value = PRD( rva + entry[5], sizeof(*value) ))) break; + value++; /* flags */ + val_count = *value++; + for (j = 0; j < val_count; j++, value += 5) + { + putchar( ' ' ); + if (value[1]) printf( "%s:", get_str( buffer, rva + value[1], value[2] )); + printf( "%s", get_str( buffer, rva + value[3], value[4] )); + } + printf( "\n"); + } + break; + case 6: + printf( " Version: %u\n", ptr[0] ); + printf( " Size: %08x\n", ptr[1] ); + printf( " Flags: %08x\n", ptr[2] ); + printf( " Count: %08x\n", ptr[3] ); + printf( " EntryOffset: %08x\n", ptr[4] ); + printf( " HashOffset: %08x\n", ptr[5] ); + printf( " HashFactor: %08x\n", ptr[6] ); + count = ptr[3]; + if (!(entry = PRD( rva + ptr[4], count * 6 * sizeof(*entry) ))) break; + for (i = 0; i < count; i++, entry += 6) + { + printf( " %08x %s ->", entry[0], get_str( buffer, rva + entry[1], entry[2] )); + if (!(value = PRD( rva + entry[4], entry[5] * 5 * sizeof(*value) ))) break; + for (j = 0; j < entry[5]; j++, value += 5) + { + putchar( ' ' ); + if (value[1]) printf( "%s:", get_str( buffer, rva + value[1], value[2] )); + printf( "%s", get_str( buffer, rva + value[3], value[4] )); + } + printf( "\n" ); + } + printf( " Hash table:\n" ); + if (!(hash = PRD( rva + ptr[5], count * 2 * sizeof(*hash) ))) break; + for (i = 0; i < count; i++, hash += 2) + { + entry = PRD( rva + ptr[4] + hash[1] * 6 * sizeof(*entry), 6 * sizeof(*entry) ); + printf( " %08x -> %s\n", hash[0], get_str( buffer, rva + entry[1], entry[3] )); + } + break; + default: + printf( "*** Unknown version %u\n", ptr[0] ); + break; + } + break; + } +} + static void dump_dir_exported_functions(void) { unsigned int size = 0; @@ -2336,6 +2441,8 @@ void pe_dump(void) dump_dir_reloc(); if (all || !strcmp(globals.dumpsect, "except")) dump_dir_exceptions(); + if (all || !strcmp(globals.dumpsect, "apiset")) + dump_section_apiset(); } if (globals.do_symbol_table) dump_symbol_table(); diff --git a/tools/winedump/winedump.man.in b/tools/winedump/winedump.man.in index a915ff49225..56460f26e7c 100644 --- a/tools/winedump/winedump.man.in +++ b/tools/winedump/winedump.man.in @@ -70,12 +70,12 @@ Dumps file header information. This option dumps only the standard PE header structures, along with the COFF sections available in the file. .IP "\fB-j \fIdir_name\fR" -Dumps only the content of directory \fIdir_name\fR, for files -which header points to directories. -For PE files, currently the import, export, debug, resource, -tls and clr directories are implemented. -For NE files, currently the export and resource directories are -implemented. +Dumps only the content of directory \fIdir_name\fR, for files which +header points to directories. For PE files, the \fBimport\fR, +\fBexport\fR, \fBdebug\fR, \fBresource\fR, \fBtls\fR, \fBloadcfg\fR, +\fBclr\fR, \fBreloc\fR and \fBexcept\fR directories, as well as the +\fBapiset\fR section, are implemented. For NE files, the \fBexport\fR +and \fBresource\fR directories are implemented. .IP \fB-x\fR Dumps everything. This command prints all available information (including all