841 lines
27 KiB
C
841 lines
27 KiB
C
/* radare - LGPL - Copyright 2008-2014 nibble, pancake */
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <r_types.h>
|
|
#include <r_util.h>
|
|
#include "pe.h"
|
|
|
|
ut64 PE_(r_bin_pe_get_main_offset)(struct PE_(r_bin_pe_obj_t) *bin) {
|
|
struct r_bin_pe_addr_t *entry = PE_(r_bin_pe_get_entrypoint) (bin);
|
|
ut64 addr = 0;
|
|
ut8 buf[512];
|
|
|
|
// option2: /x 8bff558bec83ec20
|
|
if (r_buf_read_at (bin->b, entry->offset, buf, sizeof (buf)) == -1) {
|
|
eprintf ("Error: Cannot read entry at 0x%08"PFMT64x"\n", entry->offset);
|
|
} else {
|
|
if (buf[367] == 0xe8) {
|
|
int delta = (buf[368] | buf[369]<<8 | buf[370]<<16 | buf[371]<<24);
|
|
addr = entry->rva + 367 + 5 + delta;
|
|
}
|
|
}
|
|
free (entry);
|
|
return addr;
|
|
}
|
|
|
|
static PE_DWord PE_(r_bin_pe_rva_to_offset)(struct PE_(r_bin_pe_obj_t)* bin, PE_DWord rva) {
|
|
PE_DWord section_base;
|
|
int i, section_size;
|
|
|
|
for (i = 0; i < bin->nt_headers->file_header.NumberOfSections; i++) {
|
|
section_base = bin->section_header[i].VirtualAddress;
|
|
section_size = bin->section_header[i].Misc.VirtualSize;
|
|
if (rva >= section_base && rva < section_base + section_size)
|
|
return bin->section_header[i].PointerToRawData + (rva - section_base);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
#if 0
|
|
static PE_DWord PE_(r_bin_pe_offset_to_rva)(struct PE_(r_bin_pe_obj_t)* bin, PE_DWord offset)
|
|
{
|
|
PE_DWord section_base;
|
|
int i, section_size;
|
|
|
|
for (i = 0; i < bin->nt_headers->file_header.NumberOfSections; i++) {
|
|
section_base = bin->section_header[i].PointerToRawData;
|
|
section_size = bin->section_header[i].SizeOfRawData;
|
|
if (offset >= section_base && offset < section_base + section_size)
|
|
return bin->section_header[i].VirtualAddress + (offset - section_base);
|
|
}
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
static int PE_(r_bin_pe_get_import_dirs_count)(struct PE_(r_bin_pe_obj_t) *bin) {
|
|
PE_(image_data_directory) *data_dir_import = &bin->nt_headers->optional_header.DataDirectory[PE_IMAGE_DIRECTORY_ENTRY_IMPORT];
|
|
|
|
return (int)(data_dir_import->Size / sizeof(PE_(image_import_directory)) - 1);
|
|
}
|
|
|
|
static int PE_(r_bin_pe_get_delay_import_dirs_count)(struct PE_(r_bin_pe_obj_t) *bin) {
|
|
PE_(image_data_directory) *data_dir_delay_import = \
|
|
&bin->nt_headers->optional_header.DataDirectory[PE_IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT];
|
|
|
|
return (int)(data_dir_delay_import->Size / sizeof(PE_(image_delay_import_directory)) - 1);
|
|
}
|
|
|
|
static int PE_(r_bin_pe_parse_imports)(struct PE_(r_bin_pe_obj_t)* bin, struct r_bin_pe_import_t** importp, int* nimp, char* dll_name, PE_DWord OriginalFirstThunk, PE_DWord FirstThunk) {
|
|
char import_name[PE_NAME_LENGTH + 1], name[PE_NAME_LENGTH + 1];
|
|
PE_Word import_hint, import_ordinal = 0;
|
|
PE_DWord import_table = 0, off = 0;
|
|
int i = 0;
|
|
|
|
if ((off = PE_(r_bin_pe_rva_to_offset)(bin, OriginalFirstThunk)) == 0 &&
|
|
(off = PE_(r_bin_pe_rva_to_offset)(bin, FirstThunk)) == 0)
|
|
return 0;
|
|
|
|
do {
|
|
if (r_buf_read_at (bin->b, off + i * sizeof (PE_DWord),
|
|
(ut8*)&import_table, sizeof (PE_DWord)) == -1) {
|
|
eprintf("Error: read (import table)\n");
|
|
return 0;
|
|
}
|
|
if (import_table) {
|
|
if (import_table & ILT_MASK1) {
|
|
import_ordinal = import_table & ILT_MASK2;
|
|
import_hint = 0;
|
|
snprintf(import_name, PE_NAME_LENGTH, "%s_Ordinal_%i", dll_name, import_ordinal);
|
|
} else {
|
|
import_ordinal ++;
|
|
ut64 off = PE_(r_bin_pe_rva_to_offset)(bin, import_table);
|
|
if (r_buf_read_at (bin->b, off, (ut8*)&import_hint, sizeof (PE_Word)) == -1) {
|
|
eprintf ("Error: read import hint at 0x%08"PFMT64x"\n", off);
|
|
return 0;
|
|
}
|
|
if (r_buf_read_at (bin->b, PE_(r_bin_pe_rva_to_offset)(bin, import_table) + sizeof(PE_Word),
|
|
(ut8*)name, PE_NAME_LENGTH) == -1) {
|
|
eprintf ("Error: read (import name)\n");
|
|
return 0;
|
|
}
|
|
snprintf (import_name, PE_NAME_LENGTH, "%s_%s", dll_name, name);
|
|
}
|
|
if (!(*importp = realloc (*importp, (*nimp+1) * sizeof(struct r_bin_pe_import_t)))) {
|
|
perror ("realloc (import)");
|
|
return R_FALSE;
|
|
}
|
|
memcpy((*importp)[*nimp].name, import_name, PE_NAME_LENGTH);
|
|
(*importp)[*nimp].name[PE_NAME_LENGTH] = '\0';
|
|
(*importp)[*nimp].rva = FirstThunk + i * sizeof (PE_DWord);
|
|
(*importp)[*nimp].offset = PE_(r_bin_pe_rva_to_offset)(bin, FirstThunk) + i * sizeof(PE_DWord);
|
|
(*importp)[*nimp].hint = import_hint;
|
|
(*importp)[*nimp].ordinal = import_ordinal;
|
|
(*importp)[*nimp].last = 0;
|
|
(*nimp)++; i++;
|
|
}
|
|
} while (import_table);
|
|
return i;
|
|
}
|
|
|
|
static int PE_(r_bin_pe_init_hdr)(struct PE_(r_bin_pe_obj_t)* bin) {
|
|
if (!(bin->dos_header = malloc(sizeof(PE_(image_dos_header))))) {
|
|
perror ("malloc (dos header)");
|
|
return R_FALSE;
|
|
}
|
|
if (r_buf_read_at (bin->b, 0, (ut8*)bin->dos_header, sizeof(PE_(image_dos_header))) == -1) {
|
|
eprintf("Error: read (dos header)\n");
|
|
return R_FALSE;
|
|
}
|
|
if (bin->dos_header->e_lfanew > bin->size) {
|
|
eprintf("Invalid e_lfanew field\n");
|
|
return R_FALSE;
|
|
}
|
|
if (!(bin->nt_headers = malloc(sizeof(PE_(image_nt_headers))))) {
|
|
perror("malloc (nt header)");
|
|
return R_FALSE;
|
|
}
|
|
if (r_buf_read_at (bin->b, bin->dos_header->e_lfanew,
|
|
(ut8*)bin->nt_headers, sizeof(PE_(image_nt_headers))) == -1) {
|
|
eprintf ("Error: read (dos header)\n");
|
|
return R_FALSE;
|
|
}
|
|
if (strncmp ((char*)&bin->dos_header->e_magic, "MZ", 2) ||
|
|
strncmp ((char*)&bin->nt_headers->Signature, "PE", 2))
|
|
return R_FALSE;
|
|
return R_TRUE;
|
|
}
|
|
|
|
static int PE_(r_bin_pe_init_sections)(struct PE_(r_bin_pe_obj_t)* bin) {
|
|
int sections_size = sizeof (PE_(image_section_header)) *
|
|
bin->nt_headers->file_header.NumberOfSections;
|
|
if (sections_size > bin->size) {
|
|
eprintf ("Invalid NumberOfSections value\n");
|
|
return R_FALSE;
|
|
}
|
|
if (!(bin->section_header = malloc (sections_size))) {
|
|
perror ("malloc (section header)");
|
|
return R_FALSE;
|
|
}
|
|
if (r_buf_read_at (bin->b, bin->dos_header->e_lfanew + 4 + sizeof (PE_(image_file_header)) +
|
|
bin->nt_headers->file_header.SizeOfOptionalHeader,
|
|
(ut8*)bin->section_header, sections_size) == -1) {
|
|
eprintf ("Error: read (import directory)\n");
|
|
return R_FALSE;
|
|
}
|
|
return R_TRUE;
|
|
}
|
|
|
|
static int PE_(r_bin_pe_init_imports)(struct PE_(r_bin_pe_obj_t) *bin) {
|
|
PE_(image_data_directory) *data_dir_import = \
|
|
&bin->nt_headers->optional_header.DataDirectory[PE_IMAGE_DIRECTORY_ENTRY_IMPORT];
|
|
PE_(image_data_directory) *data_dir_delay_import = \
|
|
&bin->nt_headers->optional_header.DataDirectory[PE_IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT];
|
|
PE_DWord import_dir_offset = PE_(r_bin_pe_rva_to_offset)(bin, data_dir_import->VirtualAddress);
|
|
PE_DWord delay_import_dir_offset = PE_(r_bin_pe_rva_to_offset)(bin, data_dir_delay_import->VirtualAddress);
|
|
int import_dir_size = data_dir_import->Size;
|
|
int delay_import_dir_size = data_dir_delay_import->Size;
|
|
|
|
if (import_dir_offset == 0 && delay_import_dir_offset == 0)
|
|
return R_FALSE;
|
|
if (import_dir_offset != 0) {
|
|
if (import_dir_size>0xffff) {
|
|
eprintf ("Warning: Invalid import directory size: 0x%x\n", import_dir_size);
|
|
import_dir_size = 0xffff;
|
|
}
|
|
if (!(bin->import_directory = malloc(import_dir_size))) {
|
|
perror("malloc (import directory)");
|
|
return R_FALSE;
|
|
}
|
|
if (r_buf_read_at (bin->b, import_dir_offset, (ut8*)bin->import_directory, import_dir_size) == -1) {
|
|
eprintf("Error: read (import directory)\n");
|
|
return R_FALSE;
|
|
}
|
|
}
|
|
if (delay_import_dir_offset != 0) {
|
|
if (!(bin->delay_import_directory = malloc(delay_import_dir_size))) {
|
|
perror("malloc (delay import directory)");
|
|
return R_FALSE;
|
|
}
|
|
if (r_buf_read_at (bin->b, delay_import_dir_offset,
|
|
(ut8*)bin->delay_import_directory, delay_import_dir_size) == -1) {
|
|
eprintf ("Error: read (delay import directory)\n");
|
|
return R_FALSE;
|
|
}
|
|
}
|
|
return R_TRUE;
|
|
}
|
|
|
|
static int PE_(r_bin_pe_init_exports)(struct PE_(r_bin_pe_obj_t) *bin) {
|
|
PE_(image_data_directory) *data_dir_export = \
|
|
&bin->nt_headers->optional_header.DataDirectory[PE_IMAGE_DIRECTORY_ENTRY_EXPORT];
|
|
PE_DWord export_dir_offset = PE_(r_bin_pe_rva_to_offset)(bin, data_dir_export->VirtualAddress);
|
|
|
|
#if 0
|
|
// STAB PARSER
|
|
int i;
|
|
{
|
|
ut8 *stab = NULL;
|
|
int stab_sz = 0;
|
|
ut8 *stabst = NULL;
|
|
int n, stabst_sz = 0;
|
|
|
|
struct r_bin_pe_section_t* sections = PE_(r_bin_pe_get_sections)(bin);
|
|
for (i = 0; i < bin->nt_headers->file_header.NumberOfSections; i++) {
|
|
if (!strcmp (sections[i].name, ".stab")) {
|
|
stab = malloc ( ( stab_sz = sections[i].size ) );
|
|
r_buf_read_at (bin->b, sections[i].offset, stab, stab_sz);
|
|
}
|
|
if (!strcmp (sections[i].name, ".stabst")) {
|
|
stabst_sz = sections[i].size;
|
|
eprintf ("Stab String Table found\n");
|
|
stabst = malloc (sections[i].size);
|
|
r_buf_read_at (bin->b, sections[i].offset, stabst, stabst_sz);
|
|
}
|
|
}
|
|
if (stab && stabst) {
|
|
__attribute__ ((packed))
|
|
struct stab_item {
|
|
#if R_BIN_PE64
|
|
ut64 n_strx; /* index into string table of name */
|
|
#else
|
|
ut32 n_strx; /* index into string table of name */
|
|
#endif
|
|
ut8 n_type; /* type of symbol */
|
|
ut8 n_other; /* misc info (usually empty) */
|
|
ut16 n_desc; /* description field */
|
|
#if R_BIN_PE64
|
|
ut64 n_value; /* value of symbol (bfd_vma) */
|
|
#else
|
|
ut32 n_value; /* value of symbol (bfd_vma) */
|
|
#endif
|
|
};
|
|
eprintf ("SIZE IS %d\n", sizeof (struct stab_item));
|
|
ut8 *p = stab;
|
|
struct stab_item *si = p;
|
|
#if 0
|
|
struct internal_nlist {
|
|
ut32 n_strx; /* index into string table of name */
|
|
ut8 n_type; /* type of symbol */
|
|
ut8 n_other; /* misc info (usually empty) */
|
|
ut16 n_desc; /* description field */
|
|
ut32 n_value; /* value of symbol (bfd_vma) */
|
|
};
|
|
#endif
|
|
n = 0;
|
|
i = 0;
|
|
#define getstring(x) (x<stabst_sz)?stabst+x:"???"
|
|
while (i<stab_sz) {
|
|
printf ("%d vs %d\n", i, stab_sz);
|
|
if (si->n_strx>0) {
|
|
printf ("%d stridx = 0x%x\n", n, si->n_strx);
|
|
printf ("%d string = %s\n", n, getstring (si->n_strx));
|
|
printf ("%d type = 0x%x\n", n, si->n_type);
|
|
printf ("%d value = 0x%llx\n", n, (ut64)si->n_value);
|
|
}
|
|
i += 12; //sizeof (struct stab_item);
|
|
si = stab + i;
|
|
n++;
|
|
}
|
|
|
|
// TODO : iterate over all stab elements
|
|
} else {
|
|
// you failed //
|
|
}
|
|
free (stab);
|
|
free (stabst);
|
|
free (sections);
|
|
}
|
|
#endif
|
|
|
|
if (export_dir_offset == 0) {
|
|
// eprintf ("Warning: Cannot find the offset of the export directory\n");
|
|
return R_FALSE;
|
|
}
|
|
//sdb_setn (DB, "hdr.exports_directory", export_dir_offset);
|
|
//eprintf ("Pexports offset at 0x%"PFMT64x"\n", export_dir_offset);
|
|
if (!(bin->export_directory = malloc(sizeof(PE_(image_export_directory))))) {
|
|
perror ("malloc (export directory)");
|
|
return R_FALSE;
|
|
}
|
|
if (r_buf_read_at (bin->b, export_dir_offset, (ut8*)bin->export_directory,
|
|
sizeof (PE_(image_export_directory))) == -1) {
|
|
eprintf ("Error: read (export directory)\n");
|
|
return R_FALSE;
|
|
}
|
|
return R_TRUE;
|
|
}
|
|
|
|
static int PE_(r_bin_pe_init)(struct PE_(r_bin_pe_obj_t)* bin) {
|
|
bin->dos_header = NULL;
|
|
bin->nt_headers = NULL;
|
|
bin->section_header = NULL;
|
|
bin->export_directory = NULL;
|
|
bin->import_directory = NULL;
|
|
bin->delay_import_directory = NULL;
|
|
bin->endian = 0; /* TODO: get endian */
|
|
if (!PE_(r_bin_pe_init_hdr)(bin)) {
|
|
eprintf ("Warning: File is not PE\n");
|
|
return R_FALSE;
|
|
}
|
|
if (!PE_(r_bin_pe_init_sections)(bin)) {
|
|
eprintf ("Warning: Cannot initialize sections\n");
|
|
return R_FALSE;
|
|
}
|
|
PE_(r_bin_pe_init_imports)(bin);
|
|
PE_(r_bin_pe_init_exports)(bin);
|
|
bin->relocs = NULL;
|
|
return R_TRUE;
|
|
}
|
|
|
|
char* PE_(r_bin_pe_get_arch)(struct PE_(r_bin_pe_obj_t)* bin) {
|
|
char *arch;
|
|
switch (bin->nt_headers->file_header.Machine) {
|
|
case PE_IMAGE_FILE_MACHINE_ALPHA:
|
|
case PE_IMAGE_FILE_MACHINE_ALPHA64:
|
|
arch = strdup("alpha");
|
|
break;
|
|
case PE_IMAGE_FILE_MACHINE_ARM:
|
|
case PE_IMAGE_FILE_MACHINE_THUMB:
|
|
arch = strdup("arm");
|
|
break;
|
|
case PE_IMAGE_FILE_MACHINE_M68K:
|
|
arch = strdup("m68k");
|
|
break;
|
|
case PE_IMAGE_FILE_MACHINE_MIPS16:
|
|
case PE_IMAGE_FILE_MACHINE_MIPSFPU:
|
|
case PE_IMAGE_FILE_MACHINE_MIPSFPU16:
|
|
case PE_IMAGE_FILE_MACHINE_WCEMIPSV2:
|
|
arch = strdup("mips");
|
|
break;
|
|
case PE_IMAGE_FILE_MACHINE_POWERPC:
|
|
case PE_IMAGE_FILE_MACHINE_POWERPCFP:
|
|
arch = strdup("ppc");
|
|
break;
|
|
case PE_IMAGE_FILE_MACHINE_EBC:
|
|
arch = strdup("ebc");
|
|
break;
|
|
default:
|
|
arch = strdup("x86");
|
|
}
|
|
return arch;
|
|
}
|
|
|
|
struct r_bin_pe_addr_t* PE_(r_bin_pe_get_entrypoint)(struct PE_(r_bin_pe_obj_t)* bin) {
|
|
struct r_bin_pe_addr_t *entry = NULL;
|
|
if ((entry = malloc(sizeof(struct r_bin_pe_addr_t))) == NULL) {
|
|
perror("malloc (entrypoint)");
|
|
return NULL;
|
|
}
|
|
entry->rva = bin->nt_headers->optional_header.AddressOfEntryPoint;
|
|
if (entry->rva == 0) // in PE if EP = 0 then EP = baddr
|
|
entry->rva = bin->nt_headers->optional_header.ImageBase;
|
|
entry->offset = PE_(r_bin_pe_rva_to_offset)(bin, entry->rva);
|
|
return entry;
|
|
}
|
|
|
|
struct r_bin_pe_export_t* PE_(r_bin_pe_get_exports)(struct PE_(r_bin_pe_obj_t)* bin) {
|
|
struct r_bin_pe_export_t *exports = NULL;
|
|
PE_Word function_ordinal;
|
|
PE_VWord functions_offset, names_offset, ordinals_offset, function_rva, name_rva, name_offset;
|
|
char function_name[PE_NAME_LENGTH + 1], forwarder_name[PE_NAME_LENGTH + 1];
|
|
char dll_name[PE_NAME_LENGTH + 1], export_name[PE_NAME_LENGTH + 1];
|
|
PE_(image_data_directory) *data_dir_export = \
|
|
&bin->nt_headers->optional_header.DataDirectory[PE_IMAGE_DIRECTORY_ENTRY_EXPORT];
|
|
PE_VWord export_dir_rva = data_dir_export->VirtualAddress;
|
|
int i, export_dir_size = data_dir_export->Size;
|
|
|
|
if (!bin->export_directory)
|
|
return NULL;
|
|
if (!(exports = malloc((bin->export_directory->NumberOfNames + 1) * sizeof(struct r_bin_pe_export_t))))
|
|
return NULL;
|
|
if (r_buf_read_at(bin->b, PE_(r_bin_pe_rva_to_offset)(bin, bin->export_directory->Name),
|
|
(ut8*)dll_name, PE_NAME_LENGTH) == -1) {
|
|
eprintf("Error: read (dll name)\n");
|
|
return NULL;
|
|
}
|
|
functions_offset = PE_(r_bin_pe_rva_to_offset)(bin, bin->export_directory->AddressOfFunctions);
|
|
names_offset = PE_(r_bin_pe_rva_to_offset)(bin, bin->export_directory->AddressOfNames);
|
|
ordinals_offset = PE_(r_bin_pe_rva_to_offset)(bin, bin->export_directory->AddressOfOrdinals);
|
|
for (i = 0; i < bin->export_directory->NumberOfNames; i++) {
|
|
if (r_buf_read_at(bin->b, names_offset + i * sizeof(PE_VWord), (ut8*)&name_rva, sizeof(PE_VWord)) == -1) {
|
|
eprintf ("Error: read (name rva)\n");
|
|
return NULL;
|
|
}
|
|
if (r_buf_read_at(bin->b, ordinals_offset + i * sizeof(PE_Word), (ut8*)&function_ordinal, sizeof(PE_Word)) == -1) {
|
|
eprintf ("Error: read (function ordinal)\n");
|
|
return NULL;
|
|
}
|
|
if (r_buf_read_at (bin->b, functions_offset + function_ordinal * sizeof(PE_VWord), (ut8*)&function_rva, sizeof(PE_VWord)) == -1) {
|
|
eprintf ("Error: read (function rva)\n");
|
|
return NULL;
|
|
}
|
|
name_offset = PE_(r_bin_pe_rva_to_offset)(bin, name_rva);
|
|
if (name_offset) {
|
|
if (r_buf_read_at(bin->b, name_offset, (ut8*)function_name, PE_NAME_LENGTH) == -1) {
|
|
eprintf("Error: read (function name)\n");
|
|
return NULL;
|
|
}
|
|
} else {
|
|
snprintf(function_name, PE_NAME_LENGTH, "Ordinal_%i", function_ordinal);
|
|
}
|
|
snprintf(export_name, PE_NAME_LENGTH, "%s_%s", dll_name, function_name);
|
|
if (function_rva >= export_dir_rva && function_rva < (export_dir_rva + export_dir_size)) {
|
|
if (r_buf_read_at(bin->b, PE_(r_bin_pe_rva_to_offset)(bin, function_rva), (ut8*)forwarder_name, PE_NAME_LENGTH) == -1) {
|
|
eprintf("Error: read (magic)\n");
|
|
return NULL;
|
|
}
|
|
} else {
|
|
snprintf(forwarder_name, PE_NAME_LENGTH, "NONE");
|
|
}
|
|
exports[i].rva = function_rva;
|
|
exports[i].offset = PE_(r_bin_pe_rva_to_offset)(bin, function_rva);
|
|
exports[i].ordinal = function_ordinal;
|
|
memcpy (exports[i].forwarder, forwarder_name, PE_NAME_LENGTH);
|
|
exports[i].forwarder[PE_NAME_LENGTH] = '\0';
|
|
memcpy (exports[i].name, export_name, PE_NAME_LENGTH);
|
|
exports[i].name[PE_NAME_LENGTH] = '\0';
|
|
exports[i].last = 0;
|
|
}
|
|
exports[i].last = 1;
|
|
return exports;
|
|
}
|
|
|
|
int PE_(r_bin_pe_get_file_alignment)(struct PE_(r_bin_pe_obj_t)* bin) {
|
|
return bin->nt_headers->optional_header.FileAlignment;
|
|
}
|
|
|
|
ut64 PE_(r_bin_pe_get_image_base)(struct PE_(r_bin_pe_obj_t)* bin) {
|
|
return (ut64)bin->nt_headers->optional_header.ImageBase;
|
|
}
|
|
|
|
struct r_bin_pe_import_t* PE_(r_bin_pe_get_imports)(struct PE_(r_bin_pe_obj_t) *bin) {
|
|
struct r_bin_pe_import_t *imps, *imports = NULL;
|
|
char dll_name[PE_NAME_LENGTH + 1];
|
|
int import_dirs_count = PE_(r_bin_pe_get_import_dirs_count)(bin);
|
|
int delay_import_dirs_count = PE_(r_bin_pe_get_delay_import_dirs_count)(bin);
|
|
int i, nimp = 0;
|
|
|
|
if (bin->import_directory)
|
|
for (i = 0; i < import_dirs_count; i++) {
|
|
if (r_buf_read_at(bin->b, PE_(r_bin_pe_rva_to_offset)(bin, bin->import_directory[i].Name),
|
|
(ut8*)dll_name, PE_NAME_LENGTH) == -1) {
|
|
eprintf("Error: read (magic)\n");
|
|
return NULL;
|
|
}
|
|
if (!PE_(r_bin_pe_parse_imports)(bin, &imports, &nimp, dll_name,
|
|
bin->import_directory[i].Characteristics, bin->import_directory[i].FirstThunk))
|
|
break;
|
|
}
|
|
if (bin->delay_import_directory)
|
|
for (i = 0; i < delay_import_dirs_count; i++) {
|
|
if (r_buf_read_at(bin->b, PE_(r_bin_pe_rva_to_offset)(bin, bin->delay_import_directory[i].Name),
|
|
(ut8*)dll_name, PE_NAME_LENGTH) == -1) {
|
|
eprintf ("Error: read (magic)\n");
|
|
return NULL;
|
|
}
|
|
if (!PE_(r_bin_pe_parse_imports)(bin, &imports, &nimp, dll_name,
|
|
bin->delay_import_directory[i].DelayImportNameTable, bin->delay_import_directory[i].DelayImportAddressTable))
|
|
break;
|
|
}
|
|
if (nimp) {
|
|
imps = realloc (imports, (nimp+1) * sizeof(struct r_bin_pe_import_t));
|
|
if (!imps) {
|
|
perror ("realloc (import)");
|
|
return NULL;
|
|
}
|
|
imports = imps;
|
|
imports[nimp].last = 1;
|
|
}
|
|
return imports;
|
|
}
|
|
|
|
struct r_bin_pe_lib_t* PE_(r_bin_pe_get_libs)(struct PE_(r_bin_pe_obj_t) *bin) {
|
|
struct r_bin_pe_lib_t *libs = NULL;
|
|
int import_dirs_count = PE_(r_bin_pe_get_import_dirs_count)(bin);
|
|
int delay_import_dirs_count = PE_(r_bin_pe_get_delay_import_dirs_count)(bin);
|
|
int mallocsz, i, j = 0;
|
|
|
|
/* NOTE: import_dirs and delay_import_dirs can be -1 */
|
|
mallocsz = (import_dirs_count + delay_import_dirs_count + 3) * sizeof (struct r_bin_pe_lib_t);
|
|
libs = malloc (mallocsz);
|
|
if (!libs) {
|
|
perror ("malloc (libs)");
|
|
return NULL;
|
|
}
|
|
if (bin->import_directory) {
|
|
for (i = j = 0; i < import_dirs_count; i++, j++) {
|
|
if (r_buf_read_at(bin->b, PE_(r_bin_pe_rva_to_offset)(bin, bin->import_directory[i].Name),
|
|
(ut8*)libs[j].name, PE_STRING_LENGTH) == -1) {
|
|
eprintf("Error: read (libs - import dirs)\n");
|
|
return NULL;
|
|
}
|
|
if (PE_(r_bin_pe_rva_to_offset)(bin, bin->import_directory[i].Characteristics) == 0 &&
|
|
PE_(r_bin_pe_rva_to_offset)(bin, bin->import_directory[i].FirstThunk) == 0)
|
|
break;
|
|
}
|
|
for (i = 0; i < delay_import_dirs_count; i++, j++) {
|
|
if (!bin->delay_import_directory)
|
|
break;
|
|
if (r_buf_read_at (bin->b, PE_(r_bin_pe_rva_to_offset)(bin, bin->delay_import_directory[i].Name),
|
|
(ut8*)libs[j].name, PE_STRING_LENGTH) == -1) {
|
|
eprintf("Error: read (libs - delay import dirs)\n");
|
|
return NULL;
|
|
}
|
|
if (PE_(r_bin_pe_rva_to_offset)(bin, bin->delay_import_directory[i].DelayImportNameTable) == 0 &&
|
|
PE_(r_bin_pe_rva_to_offset)(bin, bin->delay_import_directory[i].DelayImportAddressTable) == 0)
|
|
break;
|
|
}
|
|
}
|
|
for (i = 0; i < j; i++) {
|
|
libs[i].name[PE_STRING_LENGTH-1] = '\0';
|
|
libs[i].last = 0;
|
|
}
|
|
libs[i].last = 1;
|
|
return libs;
|
|
}
|
|
|
|
int PE_(r_bin_pe_get_image_size)(struct PE_(r_bin_pe_obj_t)* bin) {
|
|
return bin->nt_headers->optional_header.SizeOfImage;
|
|
}
|
|
|
|
// TODO: make it const! like in elf
|
|
char* PE_(r_bin_pe_get_machine)(struct PE_(r_bin_pe_obj_t)* bin) {
|
|
char *machine;
|
|
|
|
switch (bin->nt_headers->file_header.Machine) {
|
|
case PE_IMAGE_FILE_MACHINE_ALPHA:
|
|
machine = strdup("Alpha");
|
|
break;
|
|
case PE_IMAGE_FILE_MACHINE_ALPHA64:
|
|
machine = strdup("Alpha 64");
|
|
break;
|
|
case PE_IMAGE_FILE_MACHINE_AM33:
|
|
machine = strdup("AM33");
|
|
break;
|
|
case PE_IMAGE_FILE_MACHINE_AMD64:
|
|
machine = strdup("AMD 64");
|
|
break;
|
|
case PE_IMAGE_FILE_MACHINE_ARM:
|
|
machine = strdup("ARM");
|
|
break;
|
|
case PE_IMAGE_FILE_MACHINE_CEE:
|
|
machine = strdup("CEE");
|
|
break;
|
|
case PE_IMAGE_FILE_MACHINE_CEF:
|
|
machine = strdup("CEF");
|
|
break;
|
|
case PE_IMAGE_FILE_MACHINE_EBC:
|
|
machine = strdup("EBC");
|
|
break;
|
|
case PE_IMAGE_FILE_MACHINE_I386:
|
|
machine = strdup("i386");
|
|
break;
|
|
case PE_IMAGE_FILE_MACHINE_IA64:
|
|
machine = strdup("ia64");
|
|
break;
|
|
case PE_IMAGE_FILE_MACHINE_M32R:
|
|
machine = strdup("M32R");
|
|
break;
|
|
case PE_IMAGE_FILE_MACHINE_M68K:
|
|
machine = strdup("M68K");
|
|
break;
|
|
case PE_IMAGE_FILE_MACHINE_MIPS16:
|
|
machine = strdup("Mips 16");
|
|
break;
|
|
case PE_IMAGE_FILE_MACHINE_MIPSFPU:
|
|
machine = strdup("Mips FPU");
|
|
break;
|
|
case PE_IMAGE_FILE_MACHINE_MIPSFPU16:
|
|
machine = strdup("Mips FPU 16");
|
|
break;
|
|
case PE_IMAGE_FILE_MACHINE_POWERPC:
|
|
machine = strdup("PowerPC");
|
|
break;
|
|
case PE_IMAGE_FILE_MACHINE_POWERPCFP:
|
|
machine = strdup("PowerPC FP");
|
|
break;
|
|
case PE_IMAGE_FILE_MACHINE_R10000:
|
|
machine = strdup("R10000");
|
|
break;
|
|
case PE_IMAGE_FILE_MACHINE_R3000:
|
|
machine = strdup("R3000");
|
|
break;
|
|
case PE_IMAGE_FILE_MACHINE_R4000:
|
|
machine = strdup("R4000");
|
|
break;
|
|
case PE_IMAGE_FILE_MACHINE_SH3:
|
|
machine = strdup("SH3");
|
|
break;
|
|
case PE_IMAGE_FILE_MACHINE_SH3DSP:
|
|
machine = strdup("SH3DSP");
|
|
break;
|
|
case PE_IMAGE_FILE_MACHINE_SH3E:
|
|
machine = strdup("SH3E");
|
|
break;
|
|
case PE_IMAGE_FILE_MACHINE_SH4:
|
|
machine = strdup("SH4");
|
|
break;
|
|
case PE_IMAGE_FILE_MACHINE_SH5:
|
|
machine = strdup("SH5");
|
|
break;
|
|
case PE_IMAGE_FILE_MACHINE_THUMB:
|
|
machine = strdup("Thumb");
|
|
break;
|
|
case PE_IMAGE_FILE_MACHINE_TRICORE:
|
|
machine = strdup("Tricore");
|
|
break;
|
|
case PE_IMAGE_FILE_MACHINE_WCEMIPSV2:
|
|
machine = strdup("WCE Mips V2");
|
|
break;
|
|
default:
|
|
machine = strdup("unknown");
|
|
}
|
|
return machine;
|
|
}
|
|
|
|
// TODO: make it const! like in elf
|
|
char* PE_(r_bin_pe_get_os)(struct PE_(r_bin_pe_obj_t)* bin) {
|
|
char *os;
|
|
|
|
switch (bin->nt_headers->optional_header.Subsystem) {
|
|
case PE_IMAGE_SUBSYSTEM_NATIVE:
|
|
os = strdup("native");
|
|
break;
|
|
case PE_IMAGE_SUBSYSTEM_WINDOWS_GUI:
|
|
case PE_IMAGE_SUBSYSTEM_WINDOWS_CUI:
|
|
case PE_IMAGE_SUBSYSTEM_WINDOWS_CE_GUI:
|
|
os = strdup ("windows");
|
|
break;
|
|
case PE_IMAGE_SUBSYSTEM_POSIX_CUI:
|
|
os = strdup ("posix");
|
|
break;
|
|
case PE_IMAGE_SUBSYSTEM_EFI_APPLICATION:
|
|
case PE_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER:
|
|
case PE_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER:
|
|
case PE_IMAGE_SUBSYSTEM_EFI_ROM:
|
|
os = strdup ("efi");
|
|
break;
|
|
case PE_IMAGE_SUBSYSTEM_XBOX:
|
|
os = strdup ("xbox");
|
|
break;
|
|
default:
|
|
// XXX: this is unknown
|
|
os = strdup ("windows");
|
|
}
|
|
return os;
|
|
}
|
|
|
|
// TODO: make it const
|
|
char* PE_(r_bin_pe_get_class)(struct PE_(r_bin_pe_obj_t)* bin) {
|
|
char *class;
|
|
|
|
switch (bin->nt_headers->optional_header.Magic) {
|
|
case PE_IMAGE_FILE_TYPE_PE32:
|
|
class = strdup("PE32");
|
|
break;
|
|
case PE_IMAGE_FILE_TYPE_PE32PLUS:
|
|
class = strdup("PE32+");
|
|
break;
|
|
default:
|
|
class = strdup("Unknown");
|
|
}
|
|
return class;
|
|
}
|
|
|
|
int PE_(r_bin_pe_get_bits)(struct PE_(r_bin_pe_obj_t)* bin) {
|
|
int bits;
|
|
|
|
switch (bin->nt_headers->optional_header.Magic) {
|
|
case PE_IMAGE_FILE_TYPE_PE32:
|
|
bits = 32;
|
|
break;
|
|
case PE_IMAGE_FILE_TYPE_PE32PLUS:
|
|
bits = 64;
|
|
break;
|
|
default:
|
|
bits = -1;
|
|
}
|
|
return bits;
|
|
}
|
|
|
|
int PE_(r_bin_pe_get_section_alignment)(struct PE_(r_bin_pe_obj_t)* bin) {
|
|
return bin->nt_headers->optional_header.SectionAlignment;
|
|
}
|
|
|
|
struct r_bin_pe_section_t* PE_(r_bin_pe_get_sections)(struct PE_(r_bin_pe_obj_t)* bin) {
|
|
struct r_bin_pe_section_t *sections = NULL;
|
|
PE_(image_section_header) *shdr = bin->section_header;
|
|
int i, sections_count = bin->nt_headers->file_header.NumberOfSections;
|
|
|
|
if ((sections = malloc ((sections_count + 1) * sizeof (struct r_bin_pe_section_t))) == NULL) {
|
|
perror ("malloc (sections)");
|
|
return NULL;
|
|
}
|
|
for (i = 0; i < sections_count; i++) {
|
|
memcpy (sections[i].name, shdr[i].Name, PE_IMAGE_SIZEOF_SHORT_NAME);
|
|
sections[i].name[PE_IMAGE_SIZEOF_SHORT_NAME-1] = '\0';
|
|
sections[i].rva = shdr[i].VirtualAddress;
|
|
sections[i].size = shdr[i].SizeOfRawData;
|
|
sections[i].vsize = shdr[i].Misc.VirtualSize;
|
|
sections[i].offset = shdr[i].PointerToRawData;
|
|
sections[i].flags = shdr[i].Characteristics;
|
|
sections[i].last = 0;
|
|
}
|
|
sections[i].last = 1;
|
|
return sections;
|
|
}
|
|
|
|
char* PE_(r_bin_pe_get_subsystem)(struct PE_(r_bin_pe_obj_t)* bin) {
|
|
char *subsystem;
|
|
|
|
switch (bin->nt_headers->optional_header.Subsystem) {
|
|
case PE_IMAGE_SUBSYSTEM_NATIVE:
|
|
subsystem = strdup("Native");
|
|
break;
|
|
case PE_IMAGE_SUBSYSTEM_WINDOWS_GUI:
|
|
subsystem = strdup("Windows GUI");
|
|
break;
|
|
case PE_IMAGE_SUBSYSTEM_WINDOWS_CUI:
|
|
subsystem = strdup("Windows CUI");
|
|
break;
|
|
case PE_IMAGE_SUBSYSTEM_POSIX_CUI:
|
|
subsystem = strdup("POSIX CUI");
|
|
break;
|
|
case PE_IMAGE_SUBSYSTEM_WINDOWS_CE_GUI:
|
|
subsystem = strdup("Windows CE GUI");
|
|
break;
|
|
case PE_IMAGE_SUBSYSTEM_EFI_APPLICATION:
|
|
subsystem = strdup("EFI Application");
|
|
break;
|
|
case PE_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER:
|
|
subsystem = strdup("EFI Boot Service Driver");
|
|
break;
|
|
case PE_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER:
|
|
subsystem = strdup("EFI Runtime Driver");
|
|
break;
|
|
case PE_IMAGE_SUBSYSTEM_EFI_ROM:
|
|
subsystem = strdup("EFI ROM");
|
|
break;
|
|
case PE_IMAGE_SUBSYSTEM_XBOX:
|
|
subsystem = strdup("XBOX");
|
|
break;
|
|
default:
|
|
subsystem = strdup("Unknown");
|
|
}
|
|
return subsystem;
|
|
}
|
|
|
|
int PE_(r_bin_pe_is_dll)(struct PE_(r_bin_pe_obj_t)* bin) {
|
|
return bin->nt_headers->file_header.Characteristics & PE_IMAGE_FILE_DLL;
|
|
}
|
|
|
|
int PE_(r_bin_pe_is_pie)(struct PE_(r_bin_pe_obj_t)* bin) {
|
|
return bin->nt_headers->optional_header.DllCharacteristics & IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE;
|
|
#if 0
|
|
BOOL aslr = inh->OptionalHeader.DllCharacteristics & IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE;
|
|
//TODO : implement dep?
|
|
BOOL dep = inh->OptionalHeader.DllCharacteristics & IMAGE_DLLCHARACTERISTICS_NX_COMPAT;
|
|
#endif
|
|
}
|
|
|
|
int PE_(r_bin_pe_is_big_endian)(struct PE_(r_bin_pe_obj_t)* bin) {
|
|
return bin->nt_headers->file_header.Characteristics & PE_IMAGE_FILE_BYTES_REVERSED_HI;
|
|
}
|
|
|
|
int PE_(r_bin_pe_is_stripped_relocs)(struct PE_(r_bin_pe_obj_t)* bin) {
|
|
return bin->nt_headers->file_header.Characteristics & PE_IMAGE_FILE_RELOCS_STRIPPED;
|
|
}
|
|
|
|
int PE_(r_bin_pe_is_stripped_line_nums)(struct PE_(r_bin_pe_obj_t)* bin) {
|
|
return bin->nt_headers->file_header.Characteristics & PE_IMAGE_FILE_LINE_NUMS_STRIPPED;
|
|
}
|
|
|
|
int PE_(r_bin_pe_is_stripped_local_syms)(struct PE_(r_bin_pe_obj_t)* bin) {
|
|
return bin->nt_headers->file_header.Characteristics & PE_IMAGE_FILE_LOCAL_SYMS_STRIPPED;
|
|
}
|
|
|
|
int PE_(r_bin_pe_is_stripped_debug)(struct PE_(r_bin_pe_obj_t)* bin) {
|
|
return bin->nt_headers->file_header.Characteristics & PE_IMAGE_FILE_DEBUG_STRIPPED;
|
|
}
|
|
|
|
void* PE_(r_bin_pe_free)(struct PE_(r_bin_pe_obj_t)* bin) {
|
|
if (!bin) return NULL;
|
|
free (bin->dos_header);
|
|
free (bin->nt_headers);
|
|
free (bin->section_header);
|
|
free (bin->export_directory);
|
|
free (bin->import_directory);
|
|
free (bin->delay_import_directory);
|
|
r_buf_free (bin->b);
|
|
bin->b = NULL;
|
|
free (bin);
|
|
return NULL;
|
|
}
|
|
|
|
struct PE_(r_bin_pe_obj_t)* PE_(r_bin_pe_new)(const char* file) {
|
|
ut8 *buf;
|
|
struct PE_(r_bin_pe_obj_t) *bin = R_NEW0 (struct PE_(r_bin_pe_obj_t));
|
|
if (!bin) return NULL;
|
|
bin->file = file;
|
|
if (!(buf = (ut8*)r_file_slurp(file, &bin->size)))
|
|
return PE_(r_bin_pe_free)(bin);
|
|
bin->b = r_buf_new ();
|
|
if (!r_buf_set_bytes (bin->b, buf, bin->size))
|
|
return PE_(r_bin_pe_free)(bin);
|
|
free (buf);
|
|
if (!PE_(r_bin_pe_init)(bin))
|
|
return PE_(r_bin_pe_free)(bin);
|
|
return bin;
|
|
}
|
|
|
|
struct PE_(r_bin_pe_obj_t)* PE_(r_bin_pe_new_buf)(struct r_buf_t *buf) {
|
|
struct PE_(r_bin_pe_obj_t) *bin = R_NEW0 (struct PE_(r_bin_pe_obj_t));
|
|
if (!bin) return NULL;
|
|
bin->b = buf;
|
|
bin->size = buf->length;
|
|
if (!PE_(r_bin_pe_init)(bin))
|
|
return PE_(r_bin_pe_free)(bin);
|
|
return bin;
|
|
}
|