Blame src/logic/pe_get_image_meta.c

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
{
4e9e98
	unsigned 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
{
c0fbae
	int i,j,s,status;
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 */
b5c6e6
		for (pidata=m->aidata; pidata->name_rva[0]; pidata++,m->summary.nimplibs++);
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
}