summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/internal/perk_impl.h64
-rw-r--r--src/main/pe_get_image_meta.c184
-rw-r--r--src/main/pe_map_raw_image.c40
-rw-r--r--src/main/perk.c116
-rw-r--r--src/output/pe_output_export_symbols.c24
-rw-r--r--src/reader/pe_read_coff_header.c37
-rw-r--r--src/reader/pe_read_dos_header.c52
-rw-r--r--src/reader/pe_read_export_header.c32
-rw-r--r--src/reader/pe_read_import_header.c46
-rw-r--r--src/reader/pe_read_optional_header.c139
-rw-r--r--src/reader/pe_read_section_header.c37
11 files changed, 771 insertions, 0 deletions
diff --git a/src/internal/perk_impl.h b/src/internal/perk_impl.h
new file mode 100644
index 0000000..497ddbe
--- /dev/null
+++ b/src/internal/perk_impl.h
@@ -0,0 +1,64 @@
+#ifndef PERK_IMPL_H
+#define PERK_IMPL_H
+
+#include <stdint.h>
+#include <endian.h>
+
+/* internal structures */
+struct perk_ctx {
+ int argc;
+ char ** argv;
+ char ** envp;
+ const char * fname;
+ int status;
+ int flags;
+ int fd;
+ FILE * fout;
+ FILE * tmp;
+ struct pe_raw_image map;
+};
+
+#if (BYTE_ORDER == LITTLE_ENDIAN)
+
+static inline uint16_t pe_read_short(const unsigned char * raw)
+{
+ return *(uint16_t *)raw;
+}
+
+static inline uint32_t pe_read_long(const unsigned char * raw)
+{
+ return *(uint32_t *)raw;
+}
+
+static inline uint64_t pe_read_quad(const unsigned char * raw)
+{
+ return *(uint64_t *)raw;
+}
+
+#else
+
+static inline uint16_t pe_read_short(unsigned char * raw)
+{
+ uint16_t x = *(uint16_t *)raw;
+ return x<<8 | x>>8;
+}
+
+static inline uint32_t pe_swap_long(uint32_t x)
+{
+ return x<<24 | (x<<8) & 0xff0000 | (x>>8) & 0xff00 | x>>24;
+}
+
+static inline uint32_t pe_read_long(unsigned char * raw)
+{
+ return pe_swap_long(*(uint32_t *)raw);
+}
+
+static inline uint64_t pe_read_quad(unsigned char * raw)
+{
+ uint64_t x = *(uint64_t *)raw;
+ return ((uint64_t)pe_swap_long(x)<<32) | pe_swap_long(x>>32);
+}
+
+#endif
+
+#endif
diff --git a/src/main/pe_get_image_meta.c b/src/main/pe_get_image_meta.c
new file mode 100644
index 0000000..454f233
--- /dev/null
+++ b/src/main/pe_get_image_meta.c
@@ -0,0 +1,184 @@
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+#include <perk/perk.h>
+#include "perk_impl.h"
+
+static int pe_free_image_meta_impl (struct pe_image_meta * meta, int status)
+{
+ if (!meta) return 0;
+
+ free(meta->sectbl);
+ free(meta);
+
+ return status;
+}
+
+int pe_free_image_meta (struct pe_image_meta * meta)
+{
+ return pe_free_image_meta_impl(meta,0);
+}
+
+int pe_get_named_section_index (const struct pe_image_meta * m, const char * name)
+{
+ int i; for (i=0; i<m->coff.num_of_sections; i++)
+ if (!(strcmp(name,m->sectbl[i].name)))
+ return i;
+
+ return -1;
+}
+
+int pe_get_block_section_index (const struct pe_image_meta * m, const struct pe_block * block)
+{
+ int i;
+ uint32_t low,high;
+
+ for (i=0; i<m->coff.num_of_sections; i++) {
+ low = m->sectbl[i].virtual_addr;
+ high = low + m->sectbl[i].virtual_size;
+
+ if ((block->rva >= low) && (block->rva + block->size <= high))
+ return i;
+ }
+
+ return -1;
+}
+
+int pe_get_image_meta (const struct pe_raw_image * image, struct pe_image_meta ** meta)
+{
+ int i,j,s,status;
+ struct pe_image_meta * m;
+ char * base = image->addr;
+
+ if (!(m = calloc(1,sizeof(*m))))
+ return errno;
+
+ m->ados = (struct pe_image_dos_hdr *)base;
+
+ if ((status = (pe_read_dos_header(m->ados,&m->dos))))
+ return pe_free_image_meta_impl(m,status);
+
+ m->acoff = (struct pe_coff_file_hdr *)(base + m->dos.dos_lfanew);
+
+ if ((status = (pe_read_coff_header(m->acoff,&m->coff))))
+ return pe_free_image_meta_impl(m,status);
+
+ m->aopt = (union pe_opt_hdr *)((char *)m->acoff + sizeof(m->coff));
+
+ if ((status = (pe_read_optional_header(m->aopt,&m->opt))))
+ return pe_free_image_meta_impl(m,status);
+
+ m->asectbl = (struct pe_sec_hdr *)((char *)m->aopt + m->coff.size_of_opt_hdr);
+
+ if (!(m->sectbl = calloc(m->coff.num_of_sections,sizeof(*(m->sectbl)))))
+ return pe_free_image_meta_impl(m,status);
+
+ for (i=0; i<m->coff.num_of_sections; i++)
+ pe_read_section_header(&m->asectbl[i],&m->sectbl[i]);
+
+ /* .edata */
+ i = pe_get_named_section_index(m,".edata");
+ s = pe_get_block_section_index(m,&m->opt.dirs.export_tbl);
+
+ if ((i >= 0) && (i != s))
+ return pe_free_image_meta_impl(m,PERK_MALFORMED_IMAGE);
+
+ if (i >= 0 ) {
+ m->hedata = &m->sectbl[i];
+ m->aedata = (struct pe_export_hdr *)(base + m->sectbl[i].ptr_to_raw_data);
+ } else if (s >= 0) {
+ m->hedata = &m->sectbl[s];
+ m->aedata = (struct pe_export_hdr *)(base + m->sectbl[s].ptr_to_raw_data
+ + m->opt.dirs.export_tbl.rva - m->sectbl[s].virtual_addr);
+ }
+
+ if (m->aedata)
+ pe_read_export_header(m->aedata,&m->edata);
+
+ /* .idata */
+ struct pe_import_hdr * pidata;
+ struct pe_import_lookup_item * pitem;
+
+ i = pe_get_named_section_index(m,".idata");
+ s = pe_get_block_section_index(m,&m->opt.dirs.import_tbl);
+
+ if ((i >= 0) && (i != s))
+ return pe_free_image_meta_impl(m,PERK_MALFORMED_IMAGE);
+
+ if (i >= 0 ) {
+ m->hidata = &m->sectbl[i];
+ m->aidata = (struct pe_import_hdr *)(base + m->sectbl[i].ptr_to_raw_data);
+ } else if (s >= 0) {
+ m->hidata = &m->sectbl[s];
+ m->aidata = (struct pe_import_hdr *)(base + m->sectbl[s].ptr_to_raw_data
+ + m->opt.dirs.import_tbl.rva - m->sectbl[s].virtual_addr);
+ }
+
+ if (m->aidata) {
+ /* num of implibs */
+ for (pidata=m->aidata; pidata->name_rva[0]; pidata++,m->summary.num_of_implibs++);
+
+ /* import headers */
+ if (!(m->idata = calloc(m->summary.num_of_implibs,sizeof(*(m->idata)))))
+ return pe_free_image_meta_impl(m,status);
+
+ for (i=0; i<m->summary.num_of_implibs; i++) {
+ pe_read_import_header(&m->aidata[i],&m->idata[i]);
+
+ m->idata[i].name = base + m->hidata->ptr_to_raw_data
+ + m->idata[i].name_rva - m->hidata->virtual_addr;
+
+ m->idata[i].aitems = (struct pe_import_lookup_item *)(base + m->hidata->ptr_to_raw_data
+ + m->idata[i].import_lookup_tbl_rva - m->hidata->virtual_addr);
+
+ printf("%s\n",m->idata[i].name);
+
+ /* items */
+ m->idata[i].count = 0;
+ for (pitem=m->idata[i].aitems; *(uint32_t *)pitem->u.hint_name_tbl_rva; pitem++)
+ m->idata[i].count++;
+
+ if (!(m->idata[i].items = calloc(m->idata[i].count,sizeof(*(m->idata[i].items)))))
+ return pe_free_image_meta_impl(m,status);
+
+ for (j=0; j<m->idata[i].count; j++) {
+ if ((status = pe_read_import_lookup_item(
+ &(m->idata[i].aitems[j]),
+ &(m->idata[i].items[j]),
+ m->opt.std.magic)))
+ return pe_free_image_meta_impl(m,status);
+
+ switch (m->opt.std.magic) {
+ case PE_MAGIC_PE32:
+ m->idata[i].items[j].flags = m->idata[i].items[j].u.import_lookup_entry_32;
+ break;
+
+ case PE_MAGIC_PE32_PLUS:
+ m->idata[i].items[j].flags = (m->idata[i].items[j].u.import_lookup_entry_64 >> 32);
+ break;
+ }
+
+ struct pe_hint_name_entry * pentry = (struct pe_hint_name_entry *)(base + m->hidata->ptr_to_raw_data
+ + m->idata[i].items[j].u.hint_name_tbl_rva - m->hidata->virtual_addr);
+
+ if (m->idata[i].items[j].flags)
+ m->idata[i].items[j].hint = pe_read_short(pentry->hint);
+ else {
+ m->idata[i].items[j].name = (char *)pentry->name;
+ printf("%s\n",m->idata[i].items[j].name);
+ }
+ }
+ }
+ }
+
+ /* image */
+ m->image.addr = image->addr;
+ m->image.size = image->size;
+
+ /* all done */
+ *meta = m;
+ return 0;
+}
diff --git a/src/main/pe_map_raw_image.c b/src/main/pe_map_raw_image.c
new file mode 100644
index 0000000..8ae95d9
--- /dev/null
+++ b/src/main/pe_map_raw_image.c
@@ -0,0 +1,40 @@
+#include <stdint.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <errno.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <perk/perk.h>
+
+int pe_map_raw_image (int fd, const char * fname, struct pe_raw_image * map)
+{
+ struct stat stat;
+ int nfd, ret;
+
+ if ((nfd = !fd))
+ fd = open(fname,O_RDONLY | O_CLOEXEC);
+
+ if ((fd < 0) || (fstat(fd,&stat) < 0))
+ return errno;
+
+ map->size = stat.st_size;
+ map->addr = (char *)mmap(0,map->size,PROT_READ,MAP_PRIVATE,fd,0);
+
+ if (map->addr == MAP_FAILED) {
+ map->addr = 0;
+ ret = PERK_MAP_ERROR;
+ } else
+ ret = 0;
+
+ if (nfd) close(fd);
+
+ return ret;
+}
+
+int pe_unmap_raw_image (struct pe_raw_image * map)
+{
+ return munmap(map->addr, map->size);
+};
diff --git a/src/main/perk.c b/src/main/perk.c
new file mode 100644
index 0000000..5fe8f17
--- /dev/null
+++ b/src/main/perk.c
@@ -0,0 +1,116 @@
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <malloc.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <errno.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <perk/perk.h>
+#include "perk_impl.h"
+
+static int perk_parse_opts(struct perk_ctx * ctx)
+{
+ int i;
+ char * ch;
+ const char ** popt;
+
+ for (i=1; i<ctx->argc; i++) {
+ ch = ctx->argv[i];
+
+ if (*ch == '-') {
+ switch (*++ch) {
+ case 'i':
+ popt = &ctx->fname;
+ break;
+ case 'h':
+ ctx->flags = PERK_HELP;
+ return 0;
+ default:
+ ctx->status = PERK_BAD_OPT;
+ return ctx->status;
+ }
+
+ while ((*++ch == '\t') || (*ch == ' '));
+
+ if (!*ch) {
+ if (++i < ctx->argc)
+ *popt = ctx->argv[i];
+ else
+ ctx->status = PERK_BAD_OPT_VAL;
+ } else
+ *popt = ch;
+ } else if (!ctx->fname)
+ ctx->fname = ch;
+ else
+ ctx->status = PERK_BAD_OPT;
+
+ }
+
+ return ctx->status;
+}
+
+
+static int perk_map_input(struct perk_ctx * ctx)
+{
+ ctx->fd = open(ctx->fname,O_RDONLY | O_CLOEXEC);
+
+ if (ctx->fd < 0) {
+ ctx->status = PERK_IO_ERROR;
+ return ctx->status;
+ }
+
+ ctx->status = pe_map_raw_image(ctx->fd,0,&ctx->map);
+
+ return ctx->status;
+}
+
+
+static int perk_exit(struct perk_ctx * ctx)
+{
+ if (ctx->map.addr)
+ pe_unmap_raw_image(&ctx->map);
+
+ return ctx->status;
+}
+
+
+static int perk_run(struct perk_ctx * ctx)
+{
+ struct pe_image_meta * meta;
+
+ if (perk_map_input(ctx))
+ return perk_exit(ctx);
+
+ if ((ctx->status = pe_get_image_meta(&ctx->map,&meta)))
+ return perk_exit(ctx);
+
+ /* pre-alpha default output */
+ pe_output_export_symbols(
+ meta,
+ PERK_OUTPUT_FORMAT_LIST | PERK_OUTPUT_FIELD_NAME,
+ stdout);
+
+ ctx->status = pe_free_image_meta(meta);
+
+ return perk_exit(ctx);
+}
+
+static int perk_main(int argc, char * argv[], char * envp[])
+{
+ struct perk_ctx ctx = {argc,argv,envp};
+
+ if (perk_parse_opts(&ctx))
+ return ctx.status;
+ else
+ return perk_run(&ctx);
+}
+
+#ifdef PERK_APP
+extern __typeof(perk_main) main __attribute__((alias("perk_main")));
+#endif
diff --git a/src/output/pe_output_export_symbols.c b/src/output/pe_output_export_symbols.c
new file mode 100644
index 0000000..192bca3
--- /dev/null
+++ b/src/output/pe_output_export_symbols.c
@@ -0,0 +1,24 @@
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+#include <perk/perk.h>
+
+int pe_output_export_symbols (const struct pe_image_meta * m, uint32_t flags, FILE * f)
+{
+ uint32_t offset;
+ uint32_t * symrva;
+ int i;
+
+ if (!m->hedata) return 0;
+
+ offset = m->hedata->virtual_addr - m->hedata->ptr_to_raw_data;
+ symrva = (uint32_t *)(m->image.addr + (m->edata.name_ptr_rva - offset));
+
+ for (i=0; i<m->edata.num_of_name_ptrs; i++)
+ fprintf(f,"%s\n",(char *)(m->image.addr + symrva[i] - offset));
+
+ return 0;
+}
diff --git a/src/reader/pe_read_coff_header.c b/src/reader/pe_read_coff_header.c
new file mode 100644
index 0000000..e7bdf8a
--- /dev/null
+++ b/src/reader/pe_read_coff_header.c
@@ -0,0 +1,37 @@
+#include <endian.h>
+#include <string.h>
+
+#include <perk/perk.h>
+#include "perk_impl.h"
+
+int pe_read_coff_header(const struct pe_coff_file_hdr * p, struct pe_meta_coff_file_hdr * m)
+{
+ if ((p->signature[0] != 'P') || (p->signature[1] != 'E')
+ || *(uint16_t *)&p->signature[2])
+ return PERK_BAD_COFF_HEADER;
+
+ #if (BYTE_ORDER == LITTLE_ENDIAN)
+
+ memcpy(m,p,sizeof(*p));
+
+ #else
+
+ m->signature[0] = p->signature[0];
+ m->signature[1] = p->signature[1];
+ m->signature[2] = p->signature[2];
+ m->signature[3] = p->signature[3];
+
+ m->machine = pe_read_short(p->machine);
+ m->num_of_sections = pe_read_short(p->num_of_sections);
+
+ m->time_date_stamp = pe_read_long(p->time_date_stamp);
+ m->ptr_to_sym_tbl = pe_read_long(p->ptr_to_sym_tbl);
+ m->num_of_syms = pe_read_long(p->num_of_syms);
+
+ m->size_of_opt_hdr = pe_read_short(p->size_of_opt_hdr);
+ m->characteristics = pe_read_short(p->characteristics);
+
+ #endif
+
+ return 0;
+};
diff --git a/src/reader/pe_read_dos_header.c b/src/reader/pe_read_dos_header.c
new file mode 100644
index 0000000..75b7d31
--- /dev/null
+++ b/src/reader/pe_read_dos_header.c
@@ -0,0 +1,52 @@
+#include <endian.h>
+#include <string.h>
+
+#include <perk/perk.h>
+#include "perk_impl.h"
+
+int pe_read_dos_header(const struct pe_image_dos_hdr * p, struct pe_meta_image_dos_hdr * m)
+{
+ int i;
+
+ if ((p->dos_magic[0] != 'M') || (p->dos_magic[1] != 'Z'))
+ return PERK_BAD_DOS_HEADER;
+
+ #if (BYTE_ORDER == LITTLE_ENDIAN)
+
+ memcpy(m,p,sizeof(*p));
+
+ #else
+
+ m->dos_magic[0] = p->dos_magic[0];
+ m->dos_magic[1] = p->dos_magic[1];
+
+ m->dos_cblp = pe_read_short(p->dos_cblp);
+ m->dos_cp = pe_read_short(p->dos_cp);
+ m->dos_crlc = pe_read_short(p->dos_crlc);
+ m->dos_cparhdr = pe_read_short(p->dos_cparhdr);
+ m->dos_minalloc = pe_read_short(p->dos_minalloc);
+ m->dos_maxalloc = pe_read_short(p->dos_maxalloc);
+ m->dos_ss = pe_read_short(p->dos_ss);
+ m->dos_sp = pe_read_short(p->dos_sp);
+ m->dos_csum = pe_read_short(p->dos_csum);
+ m->dos_ip = pe_read_short(p->dos_ip);
+ m->dos_cs = pe_read_short(p->dos_cs);
+ m->dos_lfarlc = pe_read_short(p->dos_lfarlc);
+ m->dos_ovno = pe_read_short(p->dos_ovno);
+
+
+ for (i=0; i<4; i++)
+ m->dos_res[i] = pe_read_short(&p->dos_res[2*i]);
+
+ m->dos_oemid = pe_read_short(p->dos_oemid);
+ m->dos_oeminfo = pe_read_short(p->dos_oeminfo);
+
+ for (i=0; i<10; i++)
+ m->dos_res2[i] = pe_read_short(&p->dos_res2[2*i]);
+
+ m->dos_lfanew = pe_read_long(p->dos_lfanew);
+
+ #endif
+
+ return 0;
+};
diff --git a/src/reader/pe_read_export_header.c b/src/reader/pe_read_export_header.c
new file mode 100644
index 0000000..6a959c9
--- /dev/null
+++ b/src/reader/pe_read_export_header.c
@@ -0,0 +1,32 @@
+#include <endian.h>
+#include <string.h>
+
+#include <perk/perk.h>
+#include "perk_impl.h"
+
+int pe_read_export_header(const struct pe_export_hdr * p, struct pe_meta_export_hdr * m)
+{
+ #if (BYTE_ORDER == LITTLE_ENDIAN)
+
+ memcpy(m,p,sizeof(*p));
+
+ #else
+
+ m->export_flags = pe_read_long(p->export_flags);
+ m->time_date_stamp = pe_read_long(p->time_date_stamp);
+
+ m->major_ver = pe_read_short(p->major_ver);
+ m->minor_ver = pe_read_short(p->minor_ver);
+
+ m->name_rva = pe_read_long(p->name_rva);
+ m->ordinal_base = pe_read_long(p->ordinal_base);
+ m->addr_tbl_entries = pe_read_long(p->addr_tbl_entries);
+ m->num_of_name_ptrs = pe_read_long(p->num_of_name_ptrs);
+ m->export_addr_tbl_rva = pe_read_long(p->export_addr_tbl_rva);
+ m->name_ptr_rva = pe_read_long(p->name_ptr_rva);
+ m->ordinal_tbl_rva = pe_read_long(p->ordinal_tbl_rva);
+
+ #endif
+
+ return 0;
+};
diff --git a/src/reader/pe_read_import_header.c b/src/reader/pe_read_import_header.c
new file mode 100644
index 0000000..7d71143
--- /dev/null
+++ b/src/reader/pe_read_import_header.c
@@ -0,0 +1,46 @@
+#include <endian.h>
+#include <string.h>
+
+#include <perk/perk.h>
+#include "perk_impl.h"
+
+int pe_read_import_header(const struct pe_import_hdr * p, struct pe_meta_import_hdr * m)
+{
+ #if (BYTE_ORDER == LITTLE_ENDIAN)
+
+ memcpy(m,p,sizeof(*p));
+
+ #else
+
+ m->import_lookup_tbl_rva = pe_read_long(p->import_lookup_tbl_rva);
+ m->time_date_stamp = pe_read_long(p->time_date_stamp);
+ m->forwarder_chain = pe_read_long(p>forwarder_chain);
+ m->name_rva = pe_read_long(p->name_rva);
+ m->import_addr_tbl_rva = pe_read_long(p>import_addr_tbl_rva);
+
+ #endif
+
+ m->name = 0;
+ m->aitems = 0;
+
+ return 0;
+};
+
+int pe_read_import_lookup_item(
+ const struct pe_import_lookup_item * p,
+ struct pe_meta_import_lookup_item * m,
+ uint32_t magic)
+{
+ switch (magic) {
+ case PE_MAGIC_PE32:
+ m->u.import_lookup_entry_64 = pe_read_long(p->u.import_lookup_entry_32);
+ return 0;
+
+ case PE_MAGIC_PE32_PLUS:
+ m->u.import_lookup_entry_64 = pe_read_quad(p->u.import_lookup_entry_64);
+ return 0;
+
+ default:
+ return PERK_BAD_IMAGE_TYPE;
+ }
+};
diff --git a/src/reader/pe_read_optional_header.c b/src/reader/pe_read_optional_header.c
new file mode 100644
index 0000000..701c6a9
--- /dev/null
+++ b/src/reader/pe_read_optional_header.c
@@ -0,0 +1,139 @@
+#include <endian.h>
+#include <string.h>
+
+#include <perk/perk.h>
+#include "perk_impl.h"
+
+int pe_read_optional_header(const union pe_opt_hdr * p, struct pe_meta_opt_hdr * m)
+{
+ struct pe_opt_hdr_std * astd;
+ struct pe_opt_hdr_vers * avers;
+ struct pe_opt_hdr_align * aalign;
+ struct pe_opt_hdr_img * aimg;
+ struct pe_opt_hdr_ldr * aldr;
+ struct pe_opt_hdr_dirs * adirs;
+ size_t sdirs;
+
+ m->std.magic = pe_read_short(p->opt_hdr_32.magic);
+ memset(&m->dirs,0,sizeof(m->dirs));
+
+ #if (BYTE_ORDER == LITTLE_ENDIAN)
+
+ memcpy(&m->std,p,sizeof(struct pe_meta_opt_hdr_std));
+
+ switch (m->std.magic) {
+ case PE_MAGIC_PE32:
+ memcpy(&m->vers,&p->opt_hdr_32.major_os_ver,sizeof(struct pe_meta_opt_hdr_vers));
+ memcpy(&m->align,&p->opt_hdr_32.section_align,sizeof(struct pe_meta_opt_hdr_align));
+ memcpy(&m->img,&p->opt_hdr_32.size_of_image,sizeof(struct pe_meta_opt_hdr_img));
+ memcpy(&m->ldr,&p->opt_hdr_32.loader_flags,sizeof(struct pe_meta_opt_hdr_ldr));
+
+ if (m->ldr.rva_and_sizes > 0x10)
+ return PERK_BAD_IMAGE_TYPE;
+ else
+ memcpy(&m->dirs,&p->opt_hdr_32.export_tbl,sizeof(struct pe_meta_opt_hdr_dirs));
+
+ break;
+
+ case PE_MAGIC_PE32_PLUS:
+ memcpy(&m->vers,&p->opt_hdr_64.major_os_ver,sizeof(struct pe_meta_opt_hdr_vers));
+ memcpy(&m->align,&p->opt_hdr_64.section_align,sizeof(struct pe_meta_opt_hdr_align));
+ memcpy(&m->img,&p->opt_hdr_64.size_of_image,sizeof(struct pe_meta_opt_hdr_img));
+ memcpy(&m->ldr,&p->opt_hdr_64.loader_flags,sizeof(struct pe_meta_opt_hdr_ldr));
+
+ if (m->ldr.rva_and_sizes > 0x10)
+ return PERK_BAD_IMAGE_TYPE;
+ else
+ memcpy(&m->dirs,&p->opt_hdr_64.export_tbl,sizeof(struct pe_meta_opt_hdr_dirs));
+
+ break;
+
+ default:
+ return PERK_BAD_IMAGE_TYPE;
+ };
+
+ #else
+
+ astd = (struct pe_opt_hdr_std *)p;
+
+ switch (m->std.magic) {
+ case PE_MAGIC_PE32:
+ avers = (struct pe_opt_hdr_std *)&p->opt_hdr_32.major_os_ver;
+ aalign = (struct pe_opt_hdr_std *)&p->opt_hdr_32.section_align;
+ aimg = (struct pe_opt_hdr_img *)&p->opt_hdr_32.size_of_image;
+ aldr = (struct pe_opt_hdr_ldr *)&p->opt_hdr_32.loader_flags;
+ adirs = (struct pe_opt_hdr_dirs *)&p->opt_hdr_32.export_tbl;
+ break;
+
+ case PE_MAGIC_PE32_PLUS:
+ avers = (struct pe_opt_hdr_std *)&p->opt_hdr_64.major_os_ver;
+ aalign = (struct pe_opt_hdr_std *)&p->opt_hdr_64.section_align;
+ aimg = (struct pe_opt_hdr_img *)&p->opt_hdr_64.size_of_image;
+ aldr = (struct pe_opt_hdr_ldr *)&p->opt_hdr_64.loader_flags;
+ adirs = (struct pe_opt_hdr_dirs *)&p->opt_hdr_64.export_tbl;
+ break;
+
+ default:
+ return PERK_BAD_IMAGE_TYPE;
+ }
+
+ /* std */
+ m->std.major_linker_ver = astd->major_linker_ver;
+ m->std.minor_linker_ver = astd->minor_linker_ver;
+
+ m->std.size_of_code = pe_read_long(astd->size_of_code);
+ m->std.size_of_initialized_data = pe_read_long(astd->size_of_initialized_data);
+ m->std.size_of_uninitialized_data = pe_read_long(astd->size_of_uninitialized_data);
+ m->std.entry_point = pe_read_long(astd->entry_point);
+ m->std.base_of_code = pe_read_long(astd->base_of_code);
+
+ /* vers */
+ m->vers.major_os_ver = pe_read_short(avers->major_os_ver);
+ m->vers.minor_os_ver = pe_read_short(avers->minor_os_ver);
+ m->vers.major_image_ver = pe_read_short(avers->major_image_ver);
+ m->vers.minor_image_ver = pe_read_short(avers->minor_image_ver);
+ m->vers.major_subsys_ver = pe_read_short(avers->major_subsys_ver);
+ m->vers.minor_subsys_ver = pe_read_short(avers->minor_subsys_ver);
+
+ m->vers.win32_ver = pe_read_long(avers->win32_ver);
+
+ /* align */
+ m->align.section_align = pe_read_long(aalign->section_align);
+ m->align.file_align = pe_read_long(aalign->file_align);
+
+ /* img */
+ m->img.size_of_image = pe_read_long(aimg->size_of_image);
+ m->img.size_of_headers = pe_read_long(aimg->size_of_headers);
+ m->img.checksum = pe_read_long(aimg->checksum);
+
+ m->img.subsystem = pe_read_short(aimg->subsystem);
+ m->img.dll_characteristics = pe_read_short(aimg->dll_characteristics);
+
+ /* ldr */
+ m->ldr.loader_flags = pe_read_long(aldr->loader_flags);
+ m->ldr.rva_and_sizes = pe_read_long(aldr->rva_and_sizes);
+
+ #endif
+
+ switch (m->std.magic) {
+ case PE_MAGIC_PE32:
+ m->mem.base_of_data = pe_read_long(p->opt_hdr_32.base_of_data);
+ m->mem.image_base = pe_read_long(p->opt_hdr_32.image_base);
+ m->mem.size_of_stack_reserve = pe_read_long(p->opt_hdr_32.size_of_stack_reserve);
+ m->mem.size_of_stack_commit = pe_read_long(p->opt_hdr_32.size_of_stack_commit);
+ m->mem.size_of_heap_reserve = pe_read_long(p->opt_hdr_32.size_of_heap_reserve);
+ m->mem.size_of_heap_commit = pe_read_long(p->opt_hdr_32.size_of_heap_commit);
+ break;
+
+ case PE_MAGIC_PE32_PLUS:
+ m->mem.base_of_data = (uint64_t)-1;
+ m->mem.image_base = pe_read_quad(p->opt_hdr_64.image_base);
+ m->mem.size_of_stack_reserve = pe_read_quad(p->opt_hdr_64.size_of_stack_reserve);
+ m->mem.size_of_stack_commit = pe_read_quad(p->opt_hdr_64.size_of_stack_commit);
+ m->mem.size_of_heap_reserve = pe_read_quad(p->opt_hdr_64.size_of_heap_reserve);
+ m->mem.size_of_heap_commit = pe_read_quad(p->opt_hdr_64.size_of_heap_commit);
+ break;
+ };
+
+ return 0;
+};
diff --git a/src/reader/pe_read_section_header.c b/src/reader/pe_read_section_header.c
new file mode 100644
index 0000000..1a37f63
--- /dev/null
+++ b/src/reader/pe_read_section_header.c
@@ -0,0 +1,37 @@
+#include <endian.h>
+#include <string.h>
+
+#include <perk/perk.h>
+#include "perk_impl.h"
+
+int pe_read_section_header(const struct pe_sec_hdr * p, struct pe_meta_sec_hdr * m)
+{
+ /* name: meta struct conveniently contains null termination */
+ memset(m,0,sizeof(m->name));
+ memcpy(m,p,sizeof(p->name));
+
+ /* todo: long name support */
+ m->long_name = 0;
+
+ #if (BYTE_ORDER == LITTLE_ENDIAN)
+
+ memcpy(&m->virtual_size,&p->virtual_size,sizeof(*p)-sizeof(p->name));
+
+ #else
+
+ m->virtual_size = pe_read_long(p->virtual_size);
+ m->virtual_addr = pe_read_long(p->virtual_addr);
+ m->size_of_raw_data = pe_read_long(p->size_of_raw_data);
+ m->ptr_to_raw_data = pe_read_long(p->ptr_to_raw_data);
+ m->ptr_to_relocs = pe_read_long(p->ptr_to_relocs);
+ m->ptr_to_line_nums = pe_read_long(p->ptr_to_linu_nums);
+
+ m->num_of_relocs = pe_read_short(p->num_of_relocs);
+ m->num_of_line_nums = pe_read_short(p->num_of_line_nums);
+
+ m->characteristics = pe_read_long(p->characteristics);
+
+ #endif
+
+ return 0;
+};