Skip to content

Instantly share code, notes, and snippets.

@ynkdir
Created December 24, 2023 13:10
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ynkdir/7c5b28544e18d92e10da6cc5707cab7c to your computer and use it in GitHub Desktop.
Save ynkdir/7c5b28544e18d92e10da6cc5707cab7c to your computer and use it in GitHub Desktop.
mydumpbin
// mydumpbin.c
//
// Reference:
// http://msdn.microsoft.com/msdnmag/issues/02/03/PE2/default.aspx
// http://forums.belution.com/ja/vc/000/234/78s.shtml
// http://nienie.com/~masapico/api_ImageDirectoryEntryToData.html
// http://www.geocities.jp/i96815/windows/win09.html
// http://hp.vector.co.jp/authors/VA050396/index.html
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#define TO_DOS_HEADER(base) ((PIMAGE_DOS_HEADER)(base))
#define TO_NT_HEADERS(base) ((PIMAGE_NT_HEADERS)((LPBYTE)(base) + TO_DOS_HEADER(base)->e_lfanew))
/* VC8/include/delayimp.h */
#if !defined(_DELAY_IMP_VER)
typedef DWORD RVA;
typedef struct ImgDelayDescr {
DWORD grAttrs; // attributes
RVA rvaDLLName; // RVA to dll name
RVA rvaHmod; // RVA of module handle
RVA rvaIAT; // RVA of the IAT
RVA rvaINT; // RVA of the INT
RVA rvaBoundIAT; // RVA of the optional bound IAT
RVA rvaUnloadIAT; // RVA of optional copy of original IAT
DWORD dwTimeStamp; // 0 if not bound,
// O.W. date/time stamp of DLL bound to (Old BIND)
} ImgDelayDescr, * PImgDelayDescr;
enum DLAttr { // Delay Load Attributes
dlattrRva = 0x1, // RVAs are used instead of pointers
// Having this set indicates a VC7.0
// and above delay load descriptor.
};
#endif
static size_t fgetsize(FILE *f);
static int read_file(const char *path, char **pbuf, size_t *psize);
static DWORD_PTR load_library(const char *modulepath);
static PVOID MyImageDirectoryEntryToData(LPVOID Base, BOOLEAN MappedAsImage, USHORT DirectoryEntry, PULONG Size);
static DWORD_PTR load_module(const char *modulepath);
static void dump_dependents(DWORD_PTR Base);
static void dump_imports(DWORD_PTR Base);
static void dump_bound_imports(DWORD_PTR Base);
static void dump_delay_imports(DWORD_PTR Base);
static void dump_exports(DWORD_PTR Base);
static size_t
fgetsize(FILE *f)
{
fpos_t cur;
fpos_t end;
if (fgetpos(f, &cur) != 0)
return (size_t)-1;
if (fseek(f, 0L, SEEK_END) != 0)
return (size_t)-1;
if (fgetpos(f, &end) != 0)
return (size_t)-1;
if (fsetpos(f, &cur) != 0)
return (size_t)-1;
return (size_t)end;
}
static int
read_file(const char *path, char **pbuf, size_t *psize)
{
FILE *f;
size_t size;
char *buf;
f = fopen(path, "rb");
if (f == NULL)
return -1;
size = fgetsize(f);
if (size == (size_t)-1) {
fclose(f);
return -1;
}
buf = malloc(size);
if (buf == NULL) {
fclose(f);
return -1;
}
if (fread(buf, 1, size, f) != size) {
fclose(f);
free(buf);
return -1;
}
fclose(f);
*pbuf = buf;
*psize = size;
return 0;
}
static DWORD_PTR
load_library(const char *modulepath)
{
char *p;
char *base;
size_t size;
PIMAGE_DOS_HEADER pdos;
PIMAGE_NT_HEADERS pnt;
PIMAGE_SECTION_HEADER psec;
DWORD i;
if (read_file(modulepath, &p, &size) != 0)
return 0;
// check dos header
pdos = TO_DOS_HEADER(p);
if (pdos->e_magic != IMAGE_DOS_SIGNATURE || pdos->e_lfanew == 0) {
free(p);
return 0; // not executable file
}
// check nt header
pnt = TO_NT_HEADERS(p);
if (pnt->Signature != IMAGE_NT_SIGNATURE
|| pnt->OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR_MAGIC) {
free(p);
return 0; // not PE file
}
// get section table
psec = (PIMAGE_SECTION_HEADER)(pnt + 1);
base = malloc(pnt->OptionalHeader.SizeOfImage);
if (base == NULL) {
free(p);
return 0;
}
// copy header
memcpy(base, p, pnt->OptionalHeader.SizeOfHeaders);
// copy section data
for (i = 0; i < pnt->FileHeader.NumberOfSections; i++) {
if (psec[i].PointerToRawData) {
memcpy(&base[psec[i].VirtualAddress],
&p[psec[i].PointerToRawData],
psec[i].SizeOfRawData);
}
}
free(p);
return (DWORD_PTR)base;
}
/*
* The formal way is
* imagehlp.h or dbghelp.h
* imagehlp.lib or dbghelp.lib
* ImageDirectoryEntryToData()
*
* Size is whole data size (including dll name buffer, for example). It is not
* size of result pointer.
* If result is array, last one is zero filled as sentinel.
*/
static PVOID
MyImageDirectoryEntryToData(LPVOID Base, BOOLEAN MappedAsImage, USHORT DirectoryEntry, PULONG Size)
{
/* TODO: MappedAsImage? */
PIMAGE_DATA_DIRECTORY p;
p = TO_NT_HEADERS(Base)->OptionalHeader.DataDirectory + DirectoryEntry;
if (p->VirtualAddress == 0) {
*Size = 0;
return NULL;
}
*Size = p->Size;
return (PVOID)((LPBYTE)Base + p->VirtualAddress);
}
static DWORD_PTR
load_module(const char *modulepath)
{
DWORD_PTR Base;
printf("Dump of file %s\n", modulepath);
printf("\n");
//Base = (DWORD_PTR)LoadLibrary(modulepath);
Base = load_library(modulepath);
if (Base == 0) {
printf("fatal error: cannot open '%s'\n", modulepath);
exit(1);
}
if (TO_NT_HEADERS(Base)->FileHeader.Characteristics & IMAGE_FILE_DLL)
printf("File Type: DLL\n");
else
printf("File Type: EXECUTABLE IMAGE\n");
printf("\n");
return Base;
}
static void
dump_dependents(DWORD_PTR Base)
{
ULONG Size;
PIMAGE_IMPORT_DESCRIPTOR Imp;
Imp = MyImageDirectoryEntryToData(
(LPVOID)Base,
TRUE,
IMAGE_DIRECTORY_ENTRY_IMPORT,
&Size);
if (Imp == NULL)
return;
printf(" Image has the following dependencies:\n");
printf("\n");
for ( ; Imp->OriginalFirstThunk != 0; ++Imp)
printf(" %s\n", (char *)Base + Imp->Name);
printf("\n");
}
static void
dump_imports(DWORD_PTR Base)
{
ULONG Size;
PIMAGE_IMPORT_DESCRIPTOR Imp;
PIMAGE_THUNK_DATA Name; /* Import Name Table */
PIMAGE_THUNK_DATA Addr; /* Import Address Table */
PIMAGE_IMPORT_BY_NAME ImpName;
Imp = MyImageDirectoryEntryToData(
(LPVOID)Base,
TRUE,
IMAGE_DIRECTORY_ENTRY_IMPORT,
&Size);
if (Imp == NULL)
return;
printf(" Section contains the following imports:\n");
printf("\n");
for ( ; Imp->OriginalFirstThunk != 0; ++Imp) {
Addr = (PIMAGE_THUNK_DATA)(Base + Imp->FirstThunk);
Name = (PIMAGE_THUNK_DATA)(Base + Imp->OriginalFirstThunk);
printf(" %s\n", (char *)Base + Imp->Name);
printf(" %08zX Import Address Table\n", (DWORD_PTR)Addr);
printf(" %08zX Import Name Table\n", (DWORD_PTR)Name);
printf(" %8X time date stamp\n", Imp->TimeDateStamp);
printf(" %08X Index of first forwarder reference\n", Imp->ForwarderChain);
printf("\n");
for ( ; Addr->u1.Function != 0; ++Addr, ++Name) {
if (IMAGE_SNAP_BY_ORDINAL(Name->u1.Ordinal)) {
printf(" %08zX Ordinal %zd\n", Addr->u1.Function, IMAGE_ORDINAL(Name->u1.Ordinal));
} else {
ImpName = (PIMAGE_IMPORT_BY_NAME)(Base + Name->u1.AddressOfData);
printf(" %08zX %6X %s\n", Addr->u1.Function, ImpName->Hint, ImpName->Name);
}
}
printf("\n");
}
}
static void
dump_bound_imports(DWORD_PTR Base)
{
ULONG Size;
PIMAGE_BOUND_IMPORT_DESCRIPTOR BoundBase;
PIMAGE_BOUND_IMPORT_DESCRIPTOR Bound;
int i;
BoundBase = MyImageDirectoryEntryToData(
(LPVOID)Base,
TRUE,
IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT,
&Size);
if (BoundBase == NULL)
return;
printf("Header contains the following bound import information:\n");
for (Bound = BoundBase ; Bound->TimeDateStamp != 0; ++Bound) {
printf(" Bound to %s [%8X] %s",
(LPBYTE)BoundBase + Bound->OffsetModuleName,
Bound->TimeDateStamp,
ctime((time_t *)&Bound->TimeDateStamp));
if (Bound->NumberOfModuleForwarderRefs != 0) {
for (i = Bound->NumberOfModuleForwarderRefs; i != 0; --i) {
++Bound;
printf(" Contained forwarders bound to %s [%8X] %s",
(LPBYTE)BoundBase + Bound->OffsetModuleName,
Bound->TimeDateStamp,
ctime((time_t *)&Bound->TimeDateStamp));
}
}
}
printf("\n");
}
static void
dump_delay_imports(DWORD_PTR Base)
{
ULONG Size;
PImgDelayDescr Delay;
PIMAGE_THUNK_DATA Name; /* Import Name Table */
PIMAGE_THUNK_DATA Addr; /* Import Address Table */
PIMAGE_IMPORT_BY_NAME ImpName;
Delay = MyImageDirectoryEntryToData(
(LPVOID)Base,
TRUE,
IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT,
&Size);
if (Delay == NULL)
return;
printf("Section contains the following delay load imports:\n");
printf("\n");
for ( ; Delay->rvaHmod != 0; ++Delay) {
printf(" %s\n", (char *)Base + Delay->rvaDLLName);
printf(" %08X Characteristics\n", Delay->grAttrs);
printf(" %08zX Address of HMODULE\n", Base + Delay->rvaHmod);
printf(" %08zX Import Address Table\n", Base + Delay->rvaIAT);
printf(" %08zX Import Name Table\n", Base + Delay->rvaINT);
printf(" %08zX Bound Import Name Table\n",
(Delay->rvaBoundIAT == 0) ? 0 : Base + Delay->rvaBoundIAT);
printf(" %08zX Unload Import Name Table\n",
(Delay->rvaUnloadIAT == 0) ? 0 : Base + Delay->rvaUnloadIAT);
printf(" %8X time date stamp\n", Delay->dwTimeStamp);
printf("\n");
Addr = (PIMAGE_THUNK_DATA)(Base + Delay->rvaIAT);
Name = (PIMAGE_THUNK_DATA)(Base + Delay->rvaINT);
for ( ; Addr->u1.Function != 0; ++Addr, ++Name) {
if (IMAGE_SNAP_BY_ORDINAL(Name->u1.Ordinal)) {
printf(" %08zX Ordinal %zd\n", Addr->u1.Function, IMAGE_ORDINAL(Name->u1.Ordinal));
} else {
ImpName = (PIMAGE_IMPORT_BY_NAME)(Base + Name->u1.AddressOfData);
printf(" %08zX %8X %s\n", Addr->u1.Function, ImpName->Hint, ImpName->Name);
}
}
printf("\n");
}
printf("\n");
}
static void
dump_exports(DWORD_PTR Base)
{
ULONG Size;
PIMAGE_EXPORT_DIRECTORY Exp;
WORD *Ordinal;
DWORD *Addr;
DWORD *Name;
DWORD hint;
char buf[32];
Exp = MyImageDirectoryEntryToData(
(LPVOID)Base,
TRUE,
IMAGE_DIRECTORY_ENTRY_EXPORT,
&Size);
if (Exp == NULL)
return;
printf(" Section contains the following exports for %s\n", (char *)Base + Exp->Name);
printf("\n");
printf(" %08X characteristics\n", Exp->Characteristics);
printf(" %8X time date stamp %s", Exp->TimeDateStamp, ctime((time_t *)(&Exp->TimeDateStamp)));
sprintf(buf, "%d.%02d", Exp->MajorVersion, Exp->MinorVersion);
printf(" %8s version\n", buf);
printf(" %8d ordinal base\n", Exp->Base);
printf(" %8d number of functions\n", Exp->NumberOfFunctions);
printf(" %8d number of names\n", Exp->NumberOfNames);
printf("\n");
printf(" ordinal hint RVA name\n");
printf("\n");
Ordinal = (WORD *)(Base + Exp->AddressOfNameOrdinals);
Addr = (DWORD *)(Base + Exp->AddressOfFunctions);
Name = (DWORD *)(Base + Exp->AddressOfNames);
for (hint = 0; hint < Exp->NumberOfNames; ++hint) {
printf(" %7d %4X %08X %s\n",
Exp->Base + Ordinal[hint],
hint,
Addr[Ordinal[hint]],
(char *)Base + Name[hint]);
}
}
int
main(int argc, char **argv)
{
DWORD_PTR Base;
if (argc == 3 && _stricmp(argv[1] + 1, "DEPENDENTS") == 0) {
Base = load_module(argv[2]);
dump_dependents(Base);
} else if (argc == 3 && _stricmp(argv[1] + 1, "EXPORTS") == 0) {
Base = load_module(argv[2]);
dump_exports(Base);
} else if (argc == 3 && _stricmp(argv[1] + 1, "IMPORTS") == 0) {
Base = load_module(argv[2]);
dump_imports(Base);
dump_bound_imports(Base);
dump_delay_imports(Base);
} else {
printf("usage: %s [option] [file]\n", argv[0]);
printf("\n");
printf(" /DEPENDENTS\n");
printf(" /EXPORTS\n");
printf(" /IMPORTS\n");
}
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment