User:Kmcguire
Portable Executable 32 File Header And NT Header Structure
typedef struct {
uint32_t signature;
uint16_t cputype;
uint16_t objcnt;
uint32_t tdstamp;
uint32_t reserved1;
uint32_t reserved2;
uint16_t nthdrsize;
uint16_t flags;
uint16_t reserved3;
uint16_t lmajor;
uint16_t lminor;
uint16_t reserved4;
uint32_t reserved5;
uint32_t reserved6;
uint32_t entrypointrva;
uint32_t reserved7;
uint32_t reserved8;
uint32_t imagebase;
uint32_t objectalign;
uint32_t filealign;
uint16_t osmajor;
uint16_t osminor;
uint16_t usermajor;
uint16_t userminor;
uint16_t subsysmajor;
uint16_t subsysminor;
uint32_t reserved9;
uint32_t imagesize;
uint32_t hdrsize;
uint32_t filechecksum;
uint16_t subsystem;
uint16_t dllflags;
uint32_t stackreservesize;
uint32_t stackcommitsize;
uint32_t heapreservesize;
uint32_t heapcommitsize;
uint32_t reserved10;
uint32_t _rvasizes;
struct {
uint32_t rva;
uint32_t size;
} tables[];
} win32_pe32_fhdr;
#define WIN32_PE32_TABLE_EXPORT 0x00
#define WIN32_PE32_TABLE_IMPORT 0x01
#define WIN32_PE32_TABLE_RESOURCE 0x02
#define WIN32_PE32_TABLE_EXCEPTION 0x03
#define WIN32_PE32_TABLE_SECURITY 0x04
#define WIN32_PE32_TABLE_FIXUP 0x05
#define WIN32_PE32_TABLE_DEBUG 0x06
#define WIN32_PE32_TABLE_IMAGEDESC 0x07
#define WIN32_PE32_TABLE_MACHSPEC 0x08
#define WIN32_PE32_TABLE_THREADLOC 0x09
#define WIN32_PE32_TABLE_UNKNOWN1 0x0A
#define WIN32_PE32_TABLE_UNKNOWN2 0x0B
#define WIN32_PE32_TABLE_IMPORTADDR 0x0C
#define WIN32_PE32_TABLE_UNKNOWN3 0x0D
#define WIN32_PE32_TABLE_CLRRTHDR 0x0E
Common Language Runtime Header
typedef struct {
uint32_t rva;
uint32_t size;
} win32_clr20_datadir;
/* http://ntcore.com/files/dotnetformat.htm */
typedef struct {
uint32_t cb;
uint16_t rtmajor;
uint16_t rtminor;
win32_clr20_datadir meta;
uint32_t flags;
uint32_t entrypointrva; /* entry point rva */
win32_clr20_datadir resources; /* resources */
win32_clr20_datadir strongnamsig; /* strong name signature */
win32_clr20_datadir codemantab; /* code manager table */
win32_clr20_datadir vtabfixups; /* vtable fixups */
win32_clr20_datadir exaddrtabjumps; /* export address table jumps */
} win32_clr20_hdr;
Accessing PE32 Headers
win32_pe32_fhdr *fhdr;
win32_pe32_ohdr *ohdr;
uint32_t pe_off;
/* get pe32 header offset */
pe_off = ((uint32_t*)(buffer + 0x3c))[0];
printf("peoff:%x\n", pe_off);
if(memcmp(buffer + pe_off, "PE\0\0", 4) == 0)
{
printf("Yes, this is a PE header.\n");
}else{
printf("No, this is not a PE header.\n");
}
fhdr = (win32_pe32_fhdr*)(buffer + pe_off);
printf("imagebase: %x\n", fhdr->imagebase);
Accessing CLR Header
printf("CLRRTHDR_RVA:%x\nCLRRTHDR_SIZE:%x\n",
fhdr->tables[WIN32_PE32_TABLE_CLRRTHDR].rva,
fhdr->tables[WIN32_PE32_TABLE_CLRRTHDR].size);
clr_rva = fhdr->tables[WIN32_PE32_TABLE_CLRRTHDR].rva;
clr_size = fhdr->tables[WIN32_PE32_TABLE_CLRRTHDR].size;
/*
The array of objects follow the headers. But, my header does
not include the size for the data dictionary array. So to
include that we get the number of entries in the data dictionary
and multiple this by eight since each one is eight bytes in PE32.
*/
ohdr = (win32_pe32_ohdr*)(buffer + pe_off + sizeof(win32_pe32_fhdr) + (fhdr->_rvasizes * 8));
/* find the object that the CLRRTHDR is in and point header there */
for(x = 0; x < fhdr->objcnt; ++x)
{
printf("object rva %x %s\n", ohdr[x].rva, &ohdr[x].name[0]);
if(clr_rva >= ohdr[x].rva)
{
/* calculating relative to file offset not memory */
clr_off = ohdr[x].poff + (clr_rva - ohdr[x].rva);
printf("found object for CLRRTHDR, with rva %x\n", ohdr[x].rva);
break;
}
}
clr_hdr = (uint8_t*)(buffer + clr_off);
Accessing CLR Meta-Data Header
printf("clr-metatable:%x [size:%x]\n", clr_hdr->meta.rva, clr_hdr->meta.size);
meta_rva = clr_hdr->meta.rva;
meta_size = clr_hdr->meta.size;
/* find the object that the metadata is in and point header there */
for(x = 0; x < fhdr->objcnt; ++x)
{
printf("object rva %x %s\n", ohdr[x].rva, &ohdr[x].name[0]);
if(meta_rva >= ohdr[x].rva)
{
/* calculating relative to file offset not memory */
meta_off = ohdr[x].poff + (meta_rva - ohdr[x].rva);
printf("found object for CLR-METADATA, with rva %x\n", ohdr[x].rva);
break;
}
}
/* offset is relative to our buffer so that (buffer + meta_off) is start and meta_size is size */
CLR Meta-Data Container Structure
#define UINT16_AT(x) (*((uint16_t*)(x)))
#define UINT32_AT(x) (*((uint32_t*)(x)))
typedef struct {
uint8_t *name; /* ASCII name */
uint8_t *data; /* if non-zero is buffer */
} win_clr20_meta_stream;
typedef struct {
uint16_t strmcnt; /* the number of array items below */
win_clr20_meta_stream *strms; /* an array just like they are read in */
win_clr20_meta_stream strmbyid[5]; /* copy of strms, but indexed by WIN_CLR20_META_ */
uint8_t heapoffsetsizes; /* heap offset sizes */
uint32_t valid[2]; /* qword(64bit) tells which tables are present */
uint32_t sorted[2]; /* qword(64bit) tells which tables are sorted */
win_clr20_meta_table tables[64]; /* all the known tables that are supported */
} win_clr20_meta;
#define WIN_CLR20_META_TABLES 0x00
#define WIN_CLR20_META_USTRINGS 0x01
#define WIN_CLR20_META_STRINGS 0x02
#define WIN_CLR20_META_BLOB 0x03
#define WIN_CLR20_META_GUID 0x04
Read CLR Meta-Data Streams Into Memory
/* read clr metadata */
int xxxx_clr_meta_read(uint8_t *buffer, uint32_t len, win_clr20_meta *meta)
{
uint16_t ver_major;
uint16_t ver_minor;
uint16_t ver_strlen;
uint16_t strmcnt;
uint32_t x;
uint32_t y;
uint16_t strm_off;
uint16_t strm_size;
uint8_t *_buffer;
_buffer = buffer;
if(UINT32_AT(buffer) != 0x424A5342)
{
printf("invalid clr metadata signature\n");
return 0;
}
ver_major = UINT16_AT(buffer + 4 + 0);
ver_minor = UINT16_AT(buffer + 4 + 2);
printf("meta data ver:%x.%x\n", ver_major, ver_minor);
ASSERT((ver_major == 1) && (ver_minor == 1));
/* jump over signature, version, and reserved */
buffer += 4 + 4 + 4;
/* display and jump over version string */
ver_strlen = UINT32_AT(buffer);
ASSERT((ver_strlen & 0x3) == 0x0); /* has to be multiple of 4 */
printf("ver_strlen:%u\n", ver_strlen);
printf("ver:%s\n", buffer + 4);
buffer += 4 + ver_strlen;
/* jump over flags; 16 bit field; supposed to always be zero;
but apparently it is not always zero oddly enough..
ASSERT(UINT16_AT(buffer) != 0x0); */
buffer += 2;
strmcnt = UINT16_AT(buffer);
buffer += 2;
printf("MetaDataStreamCount:%u\n", strmcnt);
/* read each metadata stream header */
meta->strmcnt = strmcnt;
meta->strms = (win_clr20_meta_stream*)malloc(sizeof(win_clr20_meta_stream) * strmcnt);
for(x = 0; x < strmcnt; ++x)
{
/* read offset and size then copy into newly allocated buffer */
printf("off:%x,size:%x,name:%s\n", UINT32_AT(buffer), UINT32_AT(buffer + 4), buffer + 8);
meta->strms[x].data = (uint8_t*)malloc(UINT32_AT(buffer + 4));
memcpy(meta->strms[x].data, _buffer + UINT32_AT(buffer), UINT32_AT(buffer + 4));
buffer += 4 + 4;
/* read stream name (stop at zero byte) */
y = 0;
while(buffer[y] != 0x00)
{
++y;
}
++y;
y = ((y & 3) > 0 ? (y & (~3)) + 4 : y);
meta->strms[x].name = (uint8_t*)malloc(y + 1);
memcpy(meta->strms[x].name, buffer, y + 1);
/* advance to next offset and size pair */
buffer += y;
}
return 1;
}
Interpreting Meta-Data Tables From #~ Stream Field Description
This allows us to write a function to interpret the table data that follows the header in the #~ meta-data stream. The indexes can vary in size by what tables they reference so we have to create a letter for each specific index which refers to specific tables so that during run-time we can calculate the index size needed.
In my opinion this was done to conserve space, but I am not sure.
#define CLR20_META_TMODULE 0x0
#define CLR20_META_TTYPEREF 0x01
#define CLR20_META_TTYPEDEF 0x02
#define CLR20_META_TFIELD 0x03
#define CLR20_META_TMETHODDEF 0x04
#define CLR20_META_TPARAM 0x05
#define CLR20_META_TIFACEIMPL 0x06 /* interface implementation table */
#define CLR20_META_TMEMBERREF 0x07
#define CLR20_META_TCONSTANT 0x08
#define CLR20_META_TCUSTOMATTRI 0x09
#define CLR20_META_TFIELDMARSHAL 0x0A
#define CLR20_META_TDECLSECURITY 0x0B
#define CLR20_META_TCLASSLAYOUT 0x0C
#define CLR20_META_TFIELDLAYOUT 0x0D
#define CLR20_META_TSTANDALONGSIG 0x0E
#define CLR20_META_TEVENTMAP 0x0F
#define CLR20_META_TEVENT 0x10
#define CLR20_META_TPROPERTY 0x11
#define CLR20_META_TMETHODSEMAN 0x12
#define CLR20_META_TMETHODIMPL 0x13
#define CLR20_META_TMODULEREF 0x14
#define CLR20_META_TIMPLMAP 0x15
#define CLR20_META_TFIELDRVA 0x16
#define CLR20_META_TASSEMBLY 0x17
#define CLR20_META_TASSEMBLYPROC 0x18
#define CLR20_META_TASSEMBLYOS 0x19
#define CLR20_META_TASSEMBLYREF 0x1A
#define CLR20_META_TASSEMBLYREFPROC 0x1B
#define CLR20_META_TASSEMBLYREFOS 0x1C
#define CLR20_META_TFILE 0x1D
#define CLR20_META_TEXPORTEDTYPE 0x1E
#define CLR20_META_TMANIFESTRES 0x1F
#define CLR20_META_TNESTEDCLASS 0x20
#define CLR20_META_TGENERICPARAM 0x21
#define CLR20_META_TGENERICPARAMCONST 0x22
#define CLR20_META_TPROPERTYMAP 0x23
#define CLR20_META_TTYPESPEC 0x24
uint8_t *WIN_CLR20_META_TFIELDS[64] =
{
[CLR20_META_TMODULE] = "2SGGG",
[CLR20_META_TTYPEREF] = "RSS", /* META_TTYPEREF */
[CLR20_META_TTYPEDEF] = "4SSTFM", /* META_TTYPEDEF */
[CLR20_META_TFIELD] = "2SB", /* META_TFIELD */
[CLR20_META_TMETHODDEF] = "422SBP", /* META_TMETHODDEF */
[CLR20_META_TPARAM] = "22S", /* META_TPARAM */
[CLR20_META_TIFACEIMPL] = "DT", /* META_TIFACEIMPL */
[CLR20_META_TMEMBERREF] = "ESB", /* META_TMEMBERREF */
[CLR20_META_TCONSTANT] = "11HB", /* META_TCONSTANT */
[CLR20_META_TCUSTOMATTRI] = "CIB", /* META_TCUSTOMATTRI */
[CLR20_META_TFIELDMARSHAL] = "OB", /* META_TFIELDMARSHAL */
[CLR20_META_TDECLSECURITY] = "2AB", /* META_TDECLSECURITY */
[CLR20_META_TCLASSLAYOUT] = "24D", /* META_TCLASSLAYOUT */
[CLR20_META_TFIELDLAYOUT] = "4F",
[CLR20_META_TSTANDALONGSIG] = "B",
[CLR20_META_TEVENTMAP] = "DV",
[CLR20_META_TEVENT] = "2ST",
[CLR20_META_TPROPERTYMAP] = "DY",
[CLR20_META_TPROPERTY] = "2SB",
[CLR20_META_TMETHODSEMAN] = "2MS",
[CLR20_META_TMETHODIMPL] = "DII",
[CLR20_META_TMODULEREF] = "S",
[CLR20_META_TTYPESPEC] = "B",
[CLR20_META_TIMPLMAP] = "2USN",
[CLR20_META_TFIELDRVA] = "4F",
[CLR20_META_TASSEMBLY] = "422224BSS",
[CLR20_META_TASSEMBLYPROC] = "4",
[CLR20_META_TASSEMBLYOS] = "444",
[CLR20_META_TASSEMBLYREF] = "22224BSSB",
[CLR20_META_TASSEMBLYREFPROC] = "4J",
[CLR20_META_TASSEMBLYREFOS] = "444J",
[CLR20_META_TFILE] = "4SB",
[CLR20_META_TEXPORTEDTYPE] = "44SSB",
[CLR20_META_TMANIFESTRES] = "44SB",
[CLR20_META_TNESTEDCLASS] = "DD",
[CLR20_META_TGENERICPARAM] = "22KS",
[CLR20_META_TGENERICPARAMCONST]= "LT"
};