|
|
e2e2c2 |
/***************************************************************/
|
|
|
e2e2c2 |
/* perk: PE Resource Kit */
|
|
|
e2e2c2 |
/* Copyright (C) 2015--2016 Z. Gilboa */
|
|
|
e2e2c2 |
/* Released under GPLv2 and GPLv3; see COPYING.PERK. */
|
|
|
e2e2c2 |
/***************************************************************/
|
|
|
e2e2c2 |
|
|
|
c0fbae |
#include <stdint.h>
|
|
|
c0fbae |
#include <stdlib.h>
|
|
|
c0fbae |
#include <stdio.h>
|
|
|
c0fbae |
#include <string.h>
|
|
|
c0fbae |
|
|
|
c0fbae |
#include <perk/perk.h>
|
|
|
413f56 |
#include "perk_reader_impl.h"
|
|
|
c0fbae |
|
|
|
2b7f36 |
static int pe_free_image_meta_impl(struct pe_image_meta * meta, int status)
|
|
|
c0fbae |
{
|
|
|
c3f597 |
int i;
|
|
|
4e9e98 |
|
|
|
fa22b4 |
if (meta) {
|
|
|
b5c6e6 |
for (i=0; i<meta->summary.nimplibs; i++)
|
|
|
fa22b4 |
free(meta->idata[i].items);
|
|
|
c0fbae |
|
|
|
fa22b4 |
free(meta->idata);
|
|
|
fa22b4 |
free(meta->sectbl);
|
|
|
fa22b4 |
free(meta);
|
|
|
fa22b4 |
}
|
|
|
da8e21 |
|
|
|
da8e21 |
return status;
|
|
|
c0fbae |
}
|
|
|
c0fbae |
|
|
|
2b7f36 |
void pe_free_image_meta(struct pe_image_meta * meta)
|
|
|
c0fbae |
{
|
|
|
fa22b4 |
pe_free_image_meta_impl(meta,0);
|
|
|
c0fbae |
}
|
|
|
c0fbae |
|
|
|
2b7f36 |
int pe_get_named_section_index(const struct pe_image_meta * m, const char * name)
|
|
|
c0fbae |
{
|
|
|
c0fbae |
int i; for (i=0; i<m->coff.num_of_sections; i++)
|
|
|
c0fbae |
if (!(strcmp(name,m->sectbl[i].name)))
|
|
|
c0fbae |
return i;
|
|
|
c0fbae |
|
|
|
c0fbae |
return -1;
|
|
|
c0fbae |
}
|
|
|
c0fbae |
|
|
|
2b7f36 |
int pe_get_block_section_index(const struct pe_image_meta * m, const struct pe_block * block)
|
|
|
c0fbae |
{
|
|
|
c0fbae |
int i;
|
|
|
c0fbae |
uint32_t low,high;
|
|
|
c0fbae |
|
|
|
c0fbae |
for (i=0; i<m->coff.num_of_sections; i++) {
|
|
|
c0fbae |
low = m->sectbl[i].virtual_addr;
|
|
|
c0fbae |
high = low + m->sectbl[i].virtual_size;
|
|
|
c0fbae |
|
|
|
c0fbae |
if ((block->rva >= low) && (block->rva + block->size <= high))
|
|
|
c0fbae |
return i;
|
|
|
c0fbae |
}
|
|
|
c0fbae |
|
|
|
c0fbae |
return -1;
|
|
|
c0fbae |
}
|
|
|
c0fbae |
|
|
|
2b7f36 |
int pe_get_image_meta(const struct pe_raw_image * image, struct pe_image_meta ** meta)
|
|
|
c0fbae |
{
|
|
|
c3f597 |
int i,s,status;
|
|
|
c3f597 |
unsigned j;
|
|
|
c0fbae |
struct pe_image_meta * m;
|
|
|
c0fbae |
char * base = image->addr;
|
|
|
c0fbae |
|
|
|
c0fbae |
if (!(m = calloc(1,sizeof(*m))))
|
|
|
fa22b4 |
return -1;
|
|
|
c0fbae |
|
|
|
c0fbae |
m->ados = (struct pe_image_dos_hdr *)base;
|
|
|
c0fbae |
|
|
|
c0fbae |
if ((status = (pe_read_dos_header(m->ados,&m->dos))))
|
|
|
c0fbae |
return pe_free_image_meta_impl(m,status);
|
|
|
c0fbae |
|
|
|
c0fbae |
m->acoff = (struct pe_coff_file_hdr *)(base + m->dos.dos_lfanew);
|
|
|
c0fbae |
|
|
|
c0fbae |
if ((status = (pe_read_coff_header(m->acoff,&m->coff))))
|
|
|
c0fbae |
return pe_free_image_meta_impl(m,status);
|
|
|
c0fbae |
|
|
|
c0fbae |
m->aopt = (union pe_opt_hdr *)((char *)m->acoff + sizeof(m->coff));
|
|
|
c0fbae |
|
|
|
c0fbae |
if ((status = (pe_read_optional_header(m->aopt,&m->opt))))
|
|
|
c0fbae |
return pe_free_image_meta_impl(m,status);
|
|
|
c0fbae |
|
|
|
c0fbae |
m->asectbl = (struct pe_sec_hdr *)((char *)m->aopt + m->coff.size_of_opt_hdr);
|
|
|
c0fbae |
|
|
|
c0fbae |
if (!(m->sectbl = calloc(m->coff.num_of_sections,sizeof(*(m->sectbl)))))
|
|
|
c0fbae |
return pe_free_image_meta_impl(m,status);
|
|
|
c0fbae |
|
|
|
c0fbae |
for (i=0; i<m->coff.num_of_sections; i++)
|
|
|
c0fbae |
pe_read_section_header(&m->asectbl[i],&m->sectbl[i]);
|
|
|
c0fbae |
|
|
|
c0fbae |
/* .edata */
|
|
|
c0fbae |
i = pe_get_named_section_index(m,".edata");
|
|
|
c0fbae |
s = pe_get_block_section_index(m,&m->opt.dirs.export_tbl);
|
|
|
c0fbae |
|
|
|
c0fbae |
if ((i >= 0) && (i != s))
|
|
|
c0fbae |
return pe_free_image_meta_impl(m,PERK_MALFORMED_IMAGE);
|
|
|
c0fbae |
|
|
|
ed9e7f |
if (s >= 0) {
|
|
|
c0fbae |
m->hedata = &m->sectbl[s];
|
|
|
c0fbae |
m->aedata = (struct pe_export_hdr *)(base + m->sectbl[s].ptr_to_raw_data
|
|
|
c0fbae |
+ m->opt.dirs.export_tbl.rva - m->sectbl[s].virtual_addr);
|
|
|
ed9e7f |
} else if (i >= 0) {
|
|
|
ed9e7f |
m->hedata = &m->sectbl[i];
|
|
|
ed9e7f |
m->aedata = (struct pe_export_hdr *)(base + m->sectbl[i].ptr_to_raw_data);
|
|
|
c0fbae |
}
|
|
|
c0fbae |
|
|
|
c0fbae |
if (m->aedata)
|
|
|
c0fbae |
pe_read_export_header(m->aedata,&m->edata);
|
|
|
c0fbae |
|
|
|
c0fbae |
/* .idata */
|
|
|
c0fbae |
struct pe_import_hdr * pidata;
|
|
|
7d4d3d |
union pe_import_lookup_item * pitem;
|
|
|
c0fbae |
|
|
|
c0fbae |
i = pe_get_named_section_index(m,".idata");
|
|
|
c0fbae |
s = pe_get_block_section_index(m,&m->opt.dirs.import_tbl);
|
|
|
c0fbae |
|
|
|
c0fbae |
if ((i >= 0) && (i != s))
|
|
|
c0fbae |
return pe_free_image_meta_impl(m,PERK_MALFORMED_IMAGE);
|
|
|
c0fbae |
|
|
|
ed9e7f |
if (s >= 0) {
|
|
|
c0fbae |
m->hidata = &m->sectbl[s];
|
|
|
c0fbae |
m->aidata = (struct pe_import_hdr *)(base + m->sectbl[s].ptr_to_raw_data
|
|
|
c0fbae |
+ m->opt.dirs.import_tbl.rva - m->sectbl[s].virtual_addr);
|
|
|
ed9e7f |
} else if (i >= 0) {
|
|
|
ed9e7f |
m->hidata = &m->sectbl[i];
|
|
|
ed9e7f |
m->aidata = (struct pe_import_hdr *)(base + m->sectbl[i].ptr_to_raw_data);
|
|
|
c0fbae |
}
|
|
|
c0fbae |
|
|
|
c0fbae |
if (m->aidata) {
|
|
|
c0fbae |
/* num of implibs */
|
|
|
063803 |
for (pidata=m->aidata; pidata->name_rva[0]; pidata++,m->summary.nimplibs++)
|
|
|
063803 |
(void)0;
|
|
|
c0fbae |
|
|
|
c0fbae |
/* import headers */
|
|
|
b5c6e6 |
if (!(m->idata = calloc(m->summary.nimplibs,sizeof(*(m->idata)))))
|
|
|
c0fbae |
return pe_free_image_meta_impl(m,status);
|
|
|
c0fbae |
|
|
|
b5c6e6 |
for (i=0; i<m->summary.nimplibs; i++) {
|
|
|
c0fbae |
pe_read_import_header(&m->aidata[i],&m->idata[i]);
|
|
|
c0fbae |
|
|
|
c0fbae |
m->idata[i].name = base + m->hidata->ptr_to_raw_data
|
|
|
c0fbae |
+ m->idata[i].name_rva - m->hidata->virtual_addr;
|
|
|
c0fbae |
|
|
|
82a0a1 |
if (m->idata[i].import_lookup_tbl_rva)
|
|
|
7d4d3d |
m->idata[i].aitems = (union pe_import_lookup_item *)(base + m->hidata->ptr_to_raw_data
|
|
|
82a0a1 |
+ m->idata[i].import_lookup_tbl_rva - m->hidata->virtual_addr);
|
|
|
c0fbae |
|
|
|
c0fbae |
/* items */
|
|
|
7d801c |
uint32_t * hint;
|
|
|
c0fbae |
m->idata[i].count = 0;
|
|
|
7d801c |
|
|
|
82a0a1 |
if (m->idata[i].import_lookup_tbl_rva) {
|
|
|
7d801c |
pitem = m->idata[i].aitems;
|
|
|
7d801c |
hint = (uint32_t *)pitem->hint_name_tbl_rva;
|
|
|
7d801c |
|
|
|
7d801c |
for (; *hint; hint=(uint32_t *)((++pitem)->hint_name_tbl_rva))
|
|
|
82a0a1 |
m->idata[i].count++;
|
|
|
c0fbae |
|
|
|
82a0a1 |
if (!(m->idata[i].items = calloc(m->idata[i].count,sizeof(*(m->idata[i].items)))))
|
|
|
82a0a1 |
return pe_free_image_meta_impl(m,status);
|
|
|
82a0a1 |
}
|
|
|
c0fbae |
|
|
|
c0fbae |
for (j=0; j<m->idata[i].count; j++) {
|
|
|
c0fbae |
if ((status = pe_read_import_lookup_item(
|
|
|
c0fbae |
&(m->idata[i].aitems[j]),
|
|
|
c0fbae |
&(m->idata[i].items[j]),
|
|
|
c0fbae |
m->opt.std.magic)))
|
|
|
c0fbae |
return pe_free_image_meta_impl(m,status);
|
|
|
c0fbae |
|
|
|
c0fbae |
switch (m->opt.std.magic) {
|
|
|
c0fbae |
case PE_MAGIC_PE32:
|
|
|
c0fbae |
m->idata[i].items[j].flags = m->idata[i].items[j].u.import_lookup_entry_32;
|
|
|
c0fbae |
break;
|
|
|
c0fbae |
|
|
|
c0fbae |
case PE_MAGIC_PE32_PLUS:
|
|
|
c0fbae |
m->idata[i].items[j].flags = (m->idata[i].items[j].u.import_lookup_entry_64 >> 32);
|
|
|
c0fbae |
break;
|
|
|
c0fbae |
}
|
|
|
c0fbae |
|
|
|
e5e018 |
if (!m->idata[i].items[j].flags) {
|
|
|
e5e018 |
struct pe_hint_name_entry * pentry =
|
|
|
e5e018 |
(struct pe_hint_name_entry *)(base + m->hidata->ptr_to_raw_data
|
|
|
e5e018 |
+ m->idata[i].items[j].u.hint_name_tbl_rva - m->hidata->virtual_addr);
|
|
|
c0fbae |
|
|
|
c0fbae |
m->idata[i].items[j].name = (char *)pentry->name;
|
|
|
c0fbae |
}
|
|
|
c0fbae |
}
|
|
|
c0fbae |
}
|
|
|
c0fbae |
}
|
|
|
c0fbae |
|
|
|
c0fbae |
/* image */
|
|
|
c0fbae |
m->image.addr = image->addr;
|
|
|
c0fbae |
m->image.size = image->size;
|
|
|
c0fbae |
|
|
|
c0fbae |
/* all done */
|
|
|
c0fbae |
*meta = m;
|
|
|
c0fbae |
return 0;
|
|
|
c0fbae |
}
|