mirror of
https://github.com/radareorg/radare2.git
synced 2025-02-10 16:23:08 +00:00
2463 lines
81 KiB
C
2463 lines
81 KiB
C
/* radare - LGPL - Copyright 2008-2015 nibble, pancake, inisider */
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <r_types.h>
|
|
#include <r_util.h>
|
|
#include "pe.h"
|
|
#include <sys/time.h>
|
|
#include <time.h>
|
|
|
|
#define PE_IMAGE_FILE_MACHINE_RPI2 452
|
|
|
|
struct SCV_NB10_HEADER;
|
|
typedef struct {
|
|
ut8 signature[4];
|
|
ut32 offset;
|
|
ut32 timestamp;
|
|
ut32 age;
|
|
ut8 *file_name;
|
|
void (*free)(struct SCV_NB10_HEADER *cv_nb10_header);
|
|
} SCV_NB10_HEADER;
|
|
|
|
typedef struct {
|
|
ut32 data1;
|
|
ut16 data2;
|
|
ut16 data3;
|
|
ut8 data4[8];
|
|
} SGUID;
|
|
|
|
struct SCV_RSDS_HEADER;
|
|
typedef struct {
|
|
ut8 signature[4];
|
|
SGUID guid;
|
|
ut32 age;
|
|
ut8 *file_name;
|
|
|
|
void (*free)(struct SCV_RSDS_HEADER *rsds_hdr);
|
|
} SCV_RSDS_HEADER;
|
|
|
|
static inline int is_thumb (struct PE_(r_bin_pe_obj_t)* bin) {
|
|
return bin->nt_headers->optional_header.AddressOfEntryPoint & 1;
|
|
}
|
|
|
|
static inline int is_arm (struct PE_(r_bin_pe_obj_t)* bin) {
|
|
switch (bin->nt_headers->file_header.Machine) {
|
|
case PE_IMAGE_FILE_MACHINE_RPI2: // 462
|
|
case PE_IMAGE_FILE_MACHINE_ARM:
|
|
case PE_IMAGE_FILE_MACHINE_THUMB:
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
struct r_bin_pe_addr_t *PE_(r_bin_pe_get_main_vaddr)(struct PE_(r_bin_pe_obj_t) *bin) {
|
|
struct r_bin_pe_addr_t *entry;
|
|
ut8 b[512];
|
|
|
|
if (!bin || !bin->b)
|
|
return 0LL;
|
|
|
|
entry = PE_(r_bin_pe_get_entrypoint) (bin);
|
|
|
|
// option2: /x 8bff558bec83ec20
|
|
b[367] = 0;
|
|
if (r_buf_read_at (bin->b, entry->paddr, b, sizeof (b)) < 0) {
|
|
eprintf ("Warning: Cannot read entry at 0x%08"PFMT64x"\n",
|
|
entry->paddr);
|
|
free (entry);
|
|
return NULL;
|
|
}
|
|
|
|
/* Decode the jmp instruction, this gets the address of the 'main'
|
|
* function for PE produced by a compiler whose name someone forgot to
|
|
* write down. */
|
|
if (b[367] == 0xe8) {
|
|
const ut32 jmp_dst = b[368] | (b[369]<<8) | (b[370]<<16) | (b[371]<<24);
|
|
entry->paddr += 367 + 5 + jmp_dst;
|
|
entry->vaddr += 367 + 5 + jmp_dst;
|
|
return entry;
|
|
}
|
|
free (entry);
|
|
return NULL;
|
|
}
|
|
|
|
#define RBinPEObj struct PE_(r_bin_pe_obj_t)
|
|
static PE_DWord bin_pe_rva_to_paddr(RBinPEObj* 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 rva;
|
|
}
|
|
|
|
static PE_DWord bin_pe_rva_to_va(RBinPEObj* bin, PE_DWord rva) {
|
|
return bin->nt_headers->optional_header.ImageBase + rva;
|
|
}
|
|
|
|
#if 0
|
|
static PE_DWord PE_(r_bin_pe_paddr_to_vaddr)(struct PE_(r_bin_pe_obj_t)* bin, PE_DWord paddr)
|
|
{
|
|
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 (paddr >= section_base && paddr < section_base + section_size)
|
|
return bin->section_header[i].VirtualAddress + (paddr - section_base);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int PE_(r_bin_pe_get_import_dirs_count)(struct PE_(r_bin_pe_obj_t) *bin) {
|
|
if (!bin || !bin->nt_headers)
|
|
return 0;
|
|
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;
|
|
if (!bin || !bin->nt_headers)
|
|
return 0;
|
|
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);
|
|
}
|
|
#endif
|
|
|
|
static char *resolveModuleOrdinal(Sdb *sdb, const char *module, int ordinal) {
|
|
#if 0
|
|
char res[128], *foo;
|
|
Sdb *db = sdb_ns_path (sdb, "bin/pe", 0);
|
|
if (!db) return NULL;
|
|
db = sdb_ns (db, module, 0);
|
|
if (!db) return NULL;
|
|
#endif
|
|
Sdb *db = sdb;
|
|
char *foo = sdb_get (db, sdb_fmt (0, "%d", ordinal), 0);
|
|
if (foo && *foo) {
|
|
return foo;
|
|
} else free (foo); // should never happen
|
|
return NULL;
|
|
}
|
|
|
|
static int bin_pe_parse_imports(struct PE_(r_bin_pe_obj_t)* bin,
|
|
struct r_bin_pe_import_t** importp, int* nimp,
|
|
const char* dll_name,
|
|
PE_DWord OriginalFirstThunk,
|
|
PE_DWord FirstThunk) {
|
|
|
|
char import_name[PE_NAME_LENGTH + 1];
|
|
char name[PE_NAME_LENGTH + 1];
|
|
PE_Word import_hint, import_ordinal = 0;
|
|
PE_DWord import_table = 0, off = 0;
|
|
int i = 0, len;
|
|
Sdb *db = NULL;
|
|
char *sdb_module = NULL;
|
|
char *symname;
|
|
char *filename;
|
|
char *symdllname = NULL;
|
|
|
|
if (!dll_name || *dll_name == '0')
|
|
return 0;
|
|
|
|
if ((off = bin_pe_rva_to_paddr(bin, OriginalFirstThunk)) == 0 &&
|
|
(off = bin_pe_rva_to_paddr(bin, FirstThunk)) == 0)
|
|
return 0;
|
|
|
|
do {
|
|
if (import_ordinal >= UT16_MAX) break;
|
|
if (off + i * sizeof(PE_DWord) > bin->size) break;
|
|
len = r_buf_read_at (bin->b, off + i * sizeof (PE_DWord),
|
|
(ut8*)&import_table, sizeof (PE_DWord));
|
|
if (len == -1 || len == 0) {
|
|
eprintf("Warning: read (import table)\n");
|
|
goto error;
|
|
}
|
|
else 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);
|
|
free (symdllname);
|
|
strncpy (name, dll_name, sizeof (name)-1);
|
|
name[sizeof(name)-1] = 0;
|
|
symdllname = strdup (name);
|
|
|
|
// remove the trailling ".dll"
|
|
size_t len = strlen (symdllname);
|
|
r_str_case(symdllname, 0);
|
|
len = len < 4 ? 0 : len - 4;
|
|
symdllname[len] = 0;
|
|
|
|
if (!sdb_module || strcmp (symdllname, sdb_module)) {
|
|
sdb_free (db);
|
|
db = NULL;
|
|
free (sdb_module);
|
|
sdb_module = strdup (symdllname);
|
|
filename = sdb_fmt (1, "%s.sdb", symdllname);
|
|
if (r_file_exists (filename)) {
|
|
db = sdb_new (NULL, filename, 0);
|
|
} else {
|
|
#if __WINDOWS__
|
|
filename = sdb_fmt (1, "share/radare2/"R2_VERSION"/format/dll/%s.sdb", symdllname);
|
|
#else
|
|
filename = sdb_fmt (1, R2_PREFIX"/share/radare2/" R2_VERSION"/format/dll/%s.sdb", symdllname);
|
|
#endif
|
|
if (r_file_exists (filename)) {
|
|
db = sdb_new (NULL, filename, 0);
|
|
}
|
|
}
|
|
}
|
|
if (db) {
|
|
symname = resolveModuleOrdinal (db, symdllname, import_ordinal);
|
|
if (symname) {
|
|
snprintf (import_name,
|
|
PE_NAME_LENGTH,
|
|
"%s_%s", dll_name, symname);
|
|
}
|
|
} else {
|
|
eprintf ("Cannot find %s\n", filename);
|
|
|
|
}
|
|
} else {
|
|
import_ordinal++;
|
|
const ut64 off = bin_pe_rva_to_paddr(bin, import_table);
|
|
if (off > bin->size || (off + sizeof (PE_Word)) > bin->size) {
|
|
eprintf ("Warning: off > bin->size\n");
|
|
goto error;
|
|
}
|
|
len = r_buf_read_at (bin->b, off, (ut8*)&import_hint, sizeof (PE_Word));
|
|
if (len < 1) {
|
|
eprintf ("Warning: read import hint at 0x%08"PFMT64x"\n", off);
|
|
goto error;
|
|
}
|
|
name[0] = '\0';
|
|
len = r_buf_read_at (bin->b, off + sizeof(PE_Word),
|
|
(ut8*)name, PE_NAME_LENGTH);
|
|
if (len < 1) {
|
|
eprintf ("Warning: read (import name)\n");
|
|
goto error;
|
|
} else if (!*name) {
|
|
break;
|
|
}
|
|
name[PE_NAME_LENGTH] = '\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)))) {
|
|
r_sys_perror ("realloc (import)");
|
|
goto error;
|
|
}
|
|
memcpy((*importp)[*nimp].name, import_name, PE_NAME_LENGTH);
|
|
(*importp)[*nimp].name[PE_NAME_LENGTH] = '\0';
|
|
(*importp)[*nimp].vaddr = bin_pe_rva_to_va (bin, FirstThunk + i * sizeof (PE_DWord));
|
|
(*importp)[*nimp].paddr = bin_pe_rva_to_paddr (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);
|
|
|
|
free (symdllname);
|
|
free (sdb_module);
|
|
return i;
|
|
|
|
error:
|
|
free (symdllname);
|
|
free (sdb_module);
|
|
return false;
|
|
}
|
|
|
|
static int bin_pe_init_hdr(struct PE_(r_bin_pe_obj_t)* bin) {
|
|
if (!(bin->dos_header = malloc(sizeof(PE_(image_dos_header))))) {
|
|
r_sys_perror ("malloc (dos header)");
|
|
return false;
|
|
}
|
|
if (r_buf_read_at (bin->b, 0, (ut8*)bin->dos_header, sizeof(PE_(image_dos_header))) == -1) {
|
|
eprintf("Warning: read (dos header)\n");
|
|
return false;
|
|
}
|
|
sdb_num_set (bin->kv, "pe_dos_header.offset", 0, 0);
|
|
sdb_set (bin->kv, "pe_dos_header.format", "[2]zwwwwwwwwwwwww[4]www[10]wx"
|
|
" e_magic e_cblp e_cp e_crlc e_cparhdr e_minalloc e_maxalloc"
|
|
" e_ss e_sp e_csum e_ip e_cs e_lfarlc e_ovno e_res e_oemid"
|
|
" e_oeminfo e_res2 e_lfanew", 0);
|
|
if (bin->dos_header->e_lfanew > (unsigned int)bin->size) {
|
|
eprintf("Invalid e_lfanew field\n");
|
|
return false;
|
|
}
|
|
if (!(bin->nt_headers = malloc (sizeof (PE_(image_nt_headers))))) {
|
|
r_sys_perror("malloc (nt header)");
|
|
return false;
|
|
}
|
|
bin->nt_header_offset = bin->dos_header->e_lfanew;
|
|
if (r_buf_read_at (bin->b, bin->dos_header->e_lfanew,
|
|
(ut8*)bin->nt_headers, sizeof (PE_(image_nt_headers))) == -1) {
|
|
eprintf ("Warning: read (dos header)\n");
|
|
return false;
|
|
}
|
|
sdb_set (bin->kv, "pe_magic.cparse", "enum pe_magic { IMAGE_NT_OPTIONAL_HDR32_MAGIC=0x10b, IMAGE_NT_OPTIONAL_HDR64_MAGIC=0x20b, IMAGE_ROM_OPTIONAL_HDR_MAGIC=0x107 };", 0);
|
|
sdb_set (bin->kv, "pe_subsystem.cparse", "enum pe_subsystem { IMAGE_SUBSYSTEM_UNKNOWN=0, IMAGE_SUBSYSTEM_NATIVE=1, IMAGE_SUBSYSTEM_WINDOWS_GUI=2, "
|
|
" IMAGE_SUBSYSTEM_WINDOWS_CUI=3, IMAGE_SUBSYSTEM_OS2_CUI=5, IMAGE_SUBSYSTEM_POSIX_CUI=7, IMAGE_SUBSYSTEM_WINDOWS_CE_GUI=9, "
|
|
" IMAGE_SUBSYSTEM_EFI_APPLICATION=10, IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER=11, IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER=12, "
|
|
" IMAGE_SUBSYSTEM_EFI_ROM=13, IMAGE_SUBSYSTEM_XBOX=14, IMAGE_SUBSYSTEM_WINDOWS_BOOT_APPLICATION=16 };", 0);
|
|
sdb_set (bin->kv, "pe_dllcharacteristics.cparse", "enum pe_dllcharacteristics { IMAGE_LIBRARY_PROCESS_INIT=0x0001, IMAGE_LIBRARY_PROCESS_TERM=0x0002, "
|
|
" IMAGE_LIBRARY_THREAD_INIT=0x0004, IMAGE_LIBRARY_THREAD_TERM=0x0008, IMAGE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA=0x0020, "
|
|
" IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE=0x0040, IMAGE_DLLCHARACTERISTICS_FORCE_INTEGRITY=0x0080, "
|
|
" IMAGE_DLLCHARACTERISTICS_NX_COMPAT=0x0100, IMAGE_DLLCHARACTERISTICS_NO_ISOLATION=0x0200,IMAGE_DLLCHARACTERISTICS_NO_SEH=0x0400, "
|
|
" IMAGE_DLLCHARACTERISTICS_NO_BIND=0x0800, IMAGE_DLLCHARACTERISTICS_APPCONTAINER=0x1000, IMAGE_DLLCHARACTERISTICS_WDM_DRIVER=0x2000, "
|
|
" IMAGE_DLLCHARACTERISTICS_GUARD_CF=0x4000, IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE=0x8000};", 0);
|
|
#if R_BIN_PE64
|
|
sdb_num_set (bin->kv, "pe_nt_image_headers64.offset", bin->dos_header->e_lfanew, 0);
|
|
sdb_set (bin->kv, "pe_nt_image_headers64.format", "[4]z?? signature (pe_image_file_header)fileHeader (pe_image_optional_header64)optionalHeader", 0);
|
|
sdb_set (bin->kv, "pe_image_optional_header64.format", "[2]Ebbxxxxxqxxwwwwwwxxxx[2]E[2]Bqqqqxx[16]?"
|
|
" (pe_magic)magic majorLinkerVersion minorLinkerVersion sizeOfCode sizeOfInitializedData"
|
|
" sizeOfUninitializedData addressOfEntryPoint baseOfCode imageBase"
|
|
" sectionAlignment fileAlignment majorOperatingSystemVersion minorOperatingSystemVersion"
|
|
" majorImageVersion minorImageVersion majorSubsystemVersion minorSubsystemVersion"
|
|
" win32VersionValue sizeOfImage sizeOfHeaders checkSum (pe_subsystem)subsystem (pe_dllcharacteristics)dllCharacteristics"
|
|
" sizeOfStackReserve sizeOfStackCommit sizeOfHeapReserve sizeOfHeapCommit loaderFlags"
|
|
" numberOfRvaAndSizes (pe_image_data_directory)dataDirectory", 0);
|
|
#else
|
|
sdb_num_set (bin->kv, "pe_nt_image_headers32.offset", bin->dos_header->e_lfanew, 0);
|
|
sdb_set (bin->kv, "pe_nt_image_headers32.format", "[4]z?? signature (pe_image_file_header)fileHeader (pe_image_optional_header32)optionalHeader", 0);
|
|
sdb_set (bin->kv, "pe_image_optional_header32.format", "[2]Ebbxxxxxxxxxwwwwwwxxxx[2]E[2]Bxxxxxx[16]?"
|
|
" (pe_magic)magic majorLinkerVersion minorLinkerVersion sizeOfCode sizeOfInitializedData"
|
|
" sizeOfUninitializedData addressOfEntryPoint baseOfCode baseOfData imageBase"
|
|
" sectionAlignment fileAlignment majorOperatingSystemVersion minorOperatingSystemVersion"
|
|
" majorImageVersion minorImageVersion majorSubsystemVersion minorSubsystemVersion"
|
|
" win32VersionValue sizeOfImage sizeOfHeaders checkSum (pe_subsystem)subsystem (pe_dllcharacteristics)dllCharacteristics"
|
|
" sizeOfStackReserve sizeOfStackCommit sizeOfHeapReserve sizeOfHeapCommit loaderFlags numberOfRvaAndSizes"
|
|
" (pe_image_data_directory)dataDirectory", 0);
|
|
#endif
|
|
sdb_set (bin->kv, "pe_machine.cparse", "enum pe_machine { IMAGE_FILE_MACHINE_I386=0x014c, IMAGE_FILE_MACHINE_IA64=0x0200, IMAGE_FILE_MACHINE_AMD64=0x8664 };", 0);
|
|
sdb_set (bin->kv, "pe_characteristics.cparse", "enum pe_characteristics { "
|
|
" IMAGE_FILE_RELOCS_STRIPPED=0x0001, IMAGE_FILE_EXECUTABLE_IMAGE=0x0002, IMAGE_FILE_LINE_NUMS_STRIPPED=0x0004, "
|
|
" IMAGE_FILE_LOCAL_SYMS_STRIPPED=0x0008, IMAGE_FILE_AGGRESIVE_WS_TRIM=0x0010, IMAGE_FILE_LARGE_ADDRESS_AWARE=0x0020, "
|
|
" IMAGE_FILE_BYTES_REVERSED_LO=0x0080, IMAGE_FILE_32BIT_MACHINE=0x0100, IMAGE_FILE_DEBUG_STRIPPED=0x0200, "
|
|
" IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP=0x0400, IMAGE_FILE_NET_RUN_FROM_SWAP=0x0800, IMAGE_FILE_SYSTEM=0x1000, "
|
|
" IMAGE_FILE_DLL=0x2000, IMAGE_FILE_UP_SYSTEM_ONLY=0x4000, IMAGE_FILE_BYTES_REVERSED_HI=0x8000 };", 0);
|
|
sdb_set (bin->kv, "pe_image_file_header.format", "[2]Ewtxxw[2]B"
|
|
" (pe_machine)machine numberOfSections timeDateStamp pointerToSymbolTable"
|
|
" numberOfSymbols sizeOfOptionalHeader (pe_characteristics)characteristics", 0);
|
|
sdb_set (bin->kv, "pe_image_data_directory.format", "xx virtualAddress size",0);
|
|
|
|
// adding compile time to the SDB
|
|
{
|
|
struct my_timezone {
|
|
int tz_minuteswest; /* minutes west of Greenwich */
|
|
int tz_dsttime; /* type of DST correction */
|
|
} tz;
|
|
struct timeval tv;
|
|
int gmtoff;
|
|
char *timestr;
|
|
time_t ts = (time_t)bin->nt_headers->file_header.TimeDateStamp;
|
|
sdb_num_set (bin->kv, "image_file_header.TimeDateStamp",
|
|
bin->nt_headers->file_header.TimeDateStamp, 0);
|
|
gettimeofday (&tv, (void*)&tz);
|
|
gmtoff = (int)(tz.tz_minuteswest*60); // in seconds
|
|
ts += gmtoff;
|
|
timestr = r_str_chop (strdup (ctime (&ts)));
|
|
// gmt offset for pe date is t->tm_gmtoff
|
|
sdb_set_owned (bin->kv,
|
|
"image_file_header.TimeDateStamp_string",
|
|
timestr, 0);
|
|
}
|
|
|
|
if (strncmp ((char*)&bin->dos_header->e_magic, "MZ", 2) ||
|
|
strncmp ((char*)&bin->nt_headers->Signature, "PE", 2))
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
typedef struct {
|
|
ut64 shortname;
|
|
ut32 value;
|
|
ut16 secnum;
|
|
ut16 symtype;
|
|
ut8 symclass;
|
|
ut8 numaux;
|
|
} SymbolRecord;
|
|
|
|
static struct r_bin_pe_export_t* parse_symbol_table(struct PE_(r_bin_pe_obj_t)* bin, struct r_bin_pe_export_t *exports, int sz) {
|
|
ut64 off, num = 0;
|
|
const int srsz = 18; // symbol record size
|
|
struct r_bin_pe_section_t* sections;
|
|
struct r_bin_pe_export_t* exp;
|
|
int bufsz, I, i, shsz;
|
|
SymbolRecord *sr;
|
|
ut64 text_off = 0LL;
|
|
ut64 text_rva = 0LL;
|
|
ut64 text = 0LL;
|
|
int textn = 0;
|
|
int exports_sz;
|
|
int symctr = 0;
|
|
char *buf;
|
|
|
|
if (!bin || !bin->nt_headers)
|
|
return NULL;
|
|
off = bin->nt_headers->file_header.PointerToSymbolTable;
|
|
num = bin->nt_headers->file_header.NumberOfSymbols;
|
|
shsz = bufsz = num * srsz;
|
|
if (bufsz<1 || bufsz>bin->size)
|
|
return NULL;
|
|
buf = calloc (num, srsz);
|
|
if (!buf)
|
|
return NULL;
|
|
exports_sz = sizeof (struct r_bin_pe_export_t)*num;
|
|
if (exports) {
|
|
int osz = sz;
|
|
sz += exports_sz;
|
|
exports = realloc (exports, sz);
|
|
if (!exports) {
|
|
free (buf);
|
|
return NULL;
|
|
}
|
|
exp = (struct r_bin_pe_export_t*) (((const ut8*)exports) + osz);
|
|
} else {
|
|
sz = exports_sz;
|
|
exports = malloc (sz);
|
|
exp = exports;
|
|
}
|
|
|
|
sections = PE_(r_bin_pe_get_sections)(bin);
|
|
for (i = 0; i < bin->nt_headers->file_header.NumberOfSections; i++) {
|
|
if (!strcmp ((char*)sections[i].name, ".text")) {
|
|
text_rva = sections[i].vaddr;
|
|
text_off = sections[i].paddr;
|
|
textn = i +1;
|
|
}
|
|
}
|
|
#undef D
|
|
#define D if (0)
|
|
text = text_rva; // text_off // TODO: io.va
|
|
symctr = 0;
|
|
if (r_buf_read_at (bin->b, off, (ut8*)buf, bufsz)) {
|
|
for (I=0; I<shsz; I += srsz) {
|
|
sr = (SymbolRecord *) (buf+I);
|
|
//eprintf ("SECNUM %d\n", sr->secnum);
|
|
if (sr->secnum == textn) {
|
|
if (sr->symtype == 32) {
|
|
char shortname[9];
|
|
memcpy (shortname, &sr->shortname, 8);
|
|
shortname[8] = 0;
|
|
if (*shortname) {
|
|
D printf ("0x%08"PFMT64x" %s\n", text + sr->value, shortname);
|
|
strncpy ((char*)exp[symctr].name, shortname, PE_NAME_LENGTH-1);
|
|
} else {
|
|
char *longname, name[128];
|
|
ut32 *idx = (ut32 *) (buf+I+4) ;
|
|
if (r_buf_read_at (bin->b, off+ *idx+shsz, (ut8*)name, 128)) {// == 128) {
|
|
longname = name;
|
|
name[sizeof(name)-1] = 0;
|
|
D printf ("0x%08"PFMT64x" %s\n", text + sr->value, longname);
|
|
strncpy ((char*)exp[symctr].name, longname, PE_NAME_LENGTH-1);
|
|
} else {
|
|
D printf ("0x%08"PFMT64x" unk_%d\n", text + sr->value, I/srsz);
|
|
sprintf ((char*)exp[symctr].name, "unk_%d", symctr);
|
|
}
|
|
}
|
|
exp[symctr].name[PE_NAME_LENGTH] = 0;
|
|
exp[symctr].vaddr = bin_pe_rva_to_va (bin, text_rva + sr->value);
|
|
exp[symctr].paddr = text_off+sr->value;
|
|
exp[symctr].ordinal = symctr;
|
|
exp[symctr].forwarder[0] = 0;
|
|
exp[symctr].last = 0;
|
|
symctr ++;
|
|
}
|
|
}
|
|
} // for
|
|
} // if read ok
|
|
exp[symctr].last = 1;
|
|
free (sections);
|
|
free (buf);
|
|
return exports;
|
|
}
|
|
|
|
static int bin_pe_init_sections(struct PE_(r_bin_pe_obj_t)* bin) {
|
|
int num_of_sections = bin->nt_headers->file_header.NumberOfSections;
|
|
int sections_size;
|
|
if (num_of_sections<1) {
|
|
//eprintf("Warning: Invalid number of sections\n");
|
|
return true;
|
|
}
|
|
sections_size = sizeof (PE_(image_section_header)) * num_of_sections;
|
|
|
|
if (sections_size > bin->size) {
|
|
eprintf ("Invalid NumberOfSections value\n");
|
|
return false;
|
|
}
|
|
if (!(bin->section_header = malloc (sections_size))) {
|
|
r_sys_perror ("malloc (section header)");
|
|
return 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 ("Warning: read (sections)\n");
|
|
return false;
|
|
}
|
|
#if 0
|
|
Each symbol table entry includes a name, storage class, type, value and section number. Short names (8 characters or fewer) are stored directly in the symbol table; longer names are stored as an paddr into the string table at the end of the COFF object.
|
|
|
|
================================================================
|
|
COFF SYMBOL TABLE RECORDS (18 BYTES)
|
|
================================================================
|
|
record
|
|
paddr
|
|
|
|
struct symrec {
|
|
union {
|
|
char string[8]; // short name
|
|
struct {
|
|
ut32 seros;
|
|
ut32 stridx;
|
|
} stridx;
|
|
} name;
|
|
ut32 value;
|
|
ut16 secnum;
|
|
ut16 symtype;
|
|
ut8 symclass;
|
|
ut8 numaux;
|
|
}
|
|
-------------------------------------------------------
|
|
0 | 8-char symbol name |
|
|
| or 32-bit zeroes followed by 32-bit |
|
|
| index into string table |
|
|
-------------------------------------------------------
|
|
8 | symbol value |
|
|
-------------------------------------------------------
|
|
0Ch | section number | symbol type |
|
|
-------------------------------------------------------
|
|
10h | sym class | num aux |
|
|
---------------------------
|
|
12h
|
|
|
|
#endif
|
|
return true;
|
|
}
|
|
|
|
static int 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_paddr = bin_pe_rva_to_paddr(bin,
|
|
data_dir_import->VirtualAddress);
|
|
PE_DWord import_dir_offset = bin_pe_rva_to_paddr(bin,
|
|
data_dir_import->VirtualAddress);
|
|
PE_DWord delay_import_dir_offset = data_dir_delay_import?
|
|
bin_pe_rva_to_paddr(bin, data_dir_delay_import->VirtualAddress): 0;
|
|
PE_(image_import_directory) *import_dir = NULL;
|
|
PE_(image_import_directory) *new_import_dir = NULL;
|
|
PE_(image_import_directory) *curr_import_dir = NULL;
|
|
PE_(image_delay_import_directory) *delay_import_dir = NULL;
|
|
PE_(image_delay_import_directory) *curr_delay_import_dir = NULL;
|
|
int dir_size = sizeof (PE_(image_import_directory));
|
|
int delay_import_size = sizeof (PE_(image_delay_import_directory));
|
|
int indx = 0;
|
|
int rr, count = 0;
|
|
int import_dir_size = data_dir_import->Size;
|
|
int delay_import_dir_size = data_dir_delay_import->Size;
|
|
/// HACK to modify import size because of begin 0.. this may report wrong info con corkami tests
|
|
if (import_dir_size == 0) {
|
|
// asume 1 entry for each
|
|
import_dir_size = data_dir_import->Size = 0xffff;
|
|
}
|
|
if (delay_import_dir_size == 0) {
|
|
// asume 1 entry for each
|
|
delay_import_dir_size = data_dir_delay_import->Size = 0xffff;
|
|
}
|
|
int maxidsz = R_MIN ((PE_DWord)bin->size,
|
|
import_dir_offset+import_dir_size);
|
|
maxidsz -= import_dir_offset;
|
|
if (maxidsz<0) maxidsz = 0;
|
|
//int maxcount = maxidsz/ sizeof (struct r_bin_pe_import_t);
|
|
|
|
free (bin->import_directory);
|
|
bin->import_directory = NULL;
|
|
if (import_dir_paddr != 0) {
|
|
if (import_dir_size<1 || import_dir_size>maxidsz) {
|
|
eprintf ("Warning: Invalid import directory size: 0x%x is now 0x%x\n",
|
|
import_dir_size, maxidsz);
|
|
import_dir_size = maxidsz;
|
|
}
|
|
bin->import_directory_offset = import_dir_offset;
|
|
count = 0;
|
|
do {
|
|
indx++;
|
|
if (((2+indx)*dir_size) > import_dir_size) {
|
|
break; //goto fail;
|
|
}
|
|
new_import_dir = (PE_(image_import_directory) *)realloc (
|
|
import_dir, ((1+indx) * dir_size));
|
|
if (!new_import_dir) {
|
|
r_sys_perror ("malloc (import directory)");
|
|
free (import_dir);
|
|
import_dir = NULL;
|
|
break; //
|
|
// goto fail;
|
|
}
|
|
import_dir = new_import_dir;
|
|
new_import_dir = NULL;
|
|
curr_import_dir = import_dir + (indx - 1);
|
|
if (r_buf_read_at (bin->b, import_dir_offset + (indx - 1) * dir_size,
|
|
(ut8*)(curr_import_dir), dir_size) == -1) {
|
|
eprintf ("Warning: read (import directory)\n");
|
|
free (import_dir);
|
|
import_dir = NULL;
|
|
break; //return false;
|
|
}
|
|
count ++;
|
|
} while (curr_import_dir->FirstThunk != 0 || curr_import_dir->Name != 0 ||
|
|
curr_import_dir->TimeDateStamp != 0 || curr_import_dir->Characteristics != 0 ||
|
|
curr_import_dir->ForwarderChain != 0);
|
|
|
|
bin->import_directory = import_dir;
|
|
bin->import_directory_size = import_dir_size;
|
|
}
|
|
|
|
indx = 0;
|
|
if (bin->b->length >0)
|
|
if ((delay_import_dir_offset != 0) && (delay_import_dir_offset < (ut32)bin->b->length)) {
|
|
ut64 off;
|
|
bin->delay_import_directory_offset = delay_import_dir_offset;
|
|
do {
|
|
indx++;
|
|
off = indx * delay_import_size;
|
|
if (off >= bin->b->length) {
|
|
eprintf ("Warning: Cannot find end of import symbols\n");
|
|
break;
|
|
}
|
|
delay_import_dir = (PE_(image_delay_import_directory) *)realloc (
|
|
delay_import_dir, (indx * delay_import_size)+1);
|
|
if (delay_import_dir == 0) {
|
|
r_sys_perror ("malloc (delay import directory)");
|
|
free (delay_import_dir);
|
|
return false;
|
|
}
|
|
|
|
curr_delay_import_dir = delay_import_dir + (indx - 1);
|
|
|
|
rr = r_buf_read_at (bin->b, delay_import_dir_offset + (indx - 1) * delay_import_size,
|
|
(ut8*)(curr_delay_import_dir), dir_size);
|
|
if (rr != dir_size) {
|
|
eprintf("Warning: read (delay import directory)\n");
|
|
goto fail;
|
|
}
|
|
} while (curr_delay_import_dir->Name != 0);
|
|
|
|
bin->delay_import_directory = delay_import_dir;
|
|
}
|
|
|
|
return true;
|
|
fail:
|
|
free (import_dir);
|
|
import_dir = NULL;
|
|
bin->import_directory = import_dir;
|
|
free (delay_import_dir);
|
|
return false;
|
|
}
|
|
|
|
static int 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_paddr = bin_pe_rva_to_paddr
|
|
(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].paddr, 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].paddr, 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
|
|
};
|
|
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) {
|
|
switch (si->n_type) {
|
|
case 0x80: // LSYM
|
|
if (si->n_desc>0 && si->n_value) {
|
|
eprintf ("MAIN SYMBOL %d %d %d %s\n",
|
|
si->n_strx,
|
|
si->n_desc,
|
|
si->n_value,
|
|
getstring (si->n_strx+si->n_desc));
|
|
}
|
|
break;
|
|
}
|
|
if (si->n_type == 0x64) {
|
|
printf ("SYMBOL 0x%x = %d (%s)\n", (ut32)si->n_value, (int)si->n_strx,
|
|
getstring (si->n_strx)
|
|
);
|
|
}
|
|
#if 1
|
|
printf ("%d stridx = 0x%x\n", n, si->n_strx);
|
|
printf ("%d string = %s\n", n, getstring (si->n_strx));
|
|
printf ("%d desc = %d (%s)\n", n, si->n_desc, getstring (si->n_desc));
|
|
printf ("%d type = 0x%x\n", n, si->n_type);
|
|
printf ("%d value = 0x%llx\n", n, (ut64)si->n_value);
|
|
#endif
|
|
}
|
|
//i += 12; //sizeof (struct stab_item);
|
|
i += 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_paddr == 0) {
|
|
// This export-dir-paddr should only appear in DLL files
|
|
//eprintf ("Warning: Cannot find the paddr of the export directory\n");
|
|
return false;
|
|
}
|
|
//sdb_setn (DB, "hdr.exports_directory", export_dir_paddr);
|
|
//eprintf ("Pexports paddr at 0x%"PFMT64x"\n", export_dir_paddr);
|
|
if (!(bin->export_directory = malloc (sizeof(PE_(image_export_directory))))) {
|
|
r_sys_perror ("malloc (export directory)");
|
|
return false;
|
|
}
|
|
if (r_buf_read_at (bin->b, export_dir_paddr, (ut8*)bin->export_directory,
|
|
sizeof (PE_(image_export_directory))) == -1) {
|
|
eprintf ("Warning: read (export directory)\n");
|
|
free (bin->export_directory);
|
|
bin->export_directory = NULL;
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
static int bin_pe_init_resource(struct PE_(r_bin_pe_obj_t)* bin) {
|
|
PE_(image_data_directory) *resource_dir = \
|
|
&bin->nt_headers->optional_header.DataDirectory[ \
|
|
PE_IMAGE_DIRECTORY_ENTRY_RESOURCE];
|
|
PE_DWord resource_dir_paddr = bin_pe_rva_to_paddr
|
|
(bin, resource_dir->VirtualAddress);
|
|
if (resource_dir_paddr == 0) {
|
|
return false;
|
|
}
|
|
if (!(bin->resource_directory = malloc (sizeof(*bin->resource_directory)))) {
|
|
r_sys_perror ("malloc (resource directory)");
|
|
return false;
|
|
}
|
|
if (r_buf_read_at (bin->b, resource_dir_paddr, (ut8*)bin->resource_directory,
|
|
sizeof (*bin->resource_directory)) != sizeof (*bin->resource_directory)) {
|
|
eprintf ("Warning: read (resource directory)\n");
|
|
free (bin->resource_directory);
|
|
bin->resource_directory = NULL;
|
|
return false;
|
|
}
|
|
bin->resource_directory_offset = resource_dir_paddr;
|
|
return true;
|
|
}
|
|
|
|
static void free_Var(Var *var) {
|
|
if (var) {
|
|
free(var->szKey);
|
|
free(var->Value);
|
|
free(var);
|
|
}
|
|
}
|
|
|
|
static void free_VarFileInfo(VarFileInfo *varFileInfo) {
|
|
if (varFileInfo) {
|
|
free(varFileInfo->szKey);
|
|
if (varFileInfo->Children) {
|
|
ut32 children = 0;
|
|
for (;children < varFileInfo->numOfChildren; children++) {
|
|
free_Var(varFileInfo->Children[children]);
|
|
}
|
|
free(varFileInfo->Children);
|
|
}
|
|
free(varFileInfo);
|
|
}
|
|
}
|
|
|
|
static void free_String(String *string) {
|
|
if (string) {
|
|
free(string->szKey);
|
|
free(string->Value);
|
|
free(string);
|
|
}
|
|
}
|
|
|
|
static void free_StringTable(StringTable *stringTable) {
|
|
if (stringTable) {
|
|
free(stringTable->szKey);
|
|
if (stringTable->Children) {
|
|
ut32 childrenST = 0;
|
|
for (;childrenST < stringTable->numOfChildren; childrenST++) {
|
|
free_String(stringTable->Children[childrenST]);
|
|
}
|
|
free(stringTable->Children);
|
|
}
|
|
free(stringTable);
|
|
}
|
|
}
|
|
|
|
static void free_StringFileInfo(StringFileInfo *stringFileInfo) {
|
|
if (stringFileInfo) {
|
|
free(stringFileInfo->szKey);
|
|
if (stringFileInfo->Children) {
|
|
ut32 childrenSFI = 0;
|
|
for (;childrenSFI < stringFileInfo->numOfChildren; childrenSFI++) {
|
|
free_StringTable(stringFileInfo->Children[childrenSFI]);
|
|
}
|
|
free(stringFileInfo->Children);
|
|
}
|
|
free(stringFileInfo);
|
|
}
|
|
}
|
|
|
|
#define align32(x) x = ((x & 0x3) == 0)? x: (x & ~0x3) + 0x4;
|
|
|
|
static void free_VS_VERSIONINFO(PE_VS_VERSIONINFO *vs_VersionInfo) {
|
|
if (vs_VersionInfo) {
|
|
free(vs_VersionInfo->szKey);
|
|
free(vs_VersionInfo->Value);
|
|
free_VarFileInfo(vs_VersionInfo->varFileInfo);
|
|
free_StringFileInfo(vs_VersionInfo->stringFileInfo);
|
|
free(vs_VersionInfo);
|
|
}
|
|
}
|
|
|
|
void PE_(free_VS_VERSIONINFO)(PE_VS_VERSIONINFO *vs_VersionInfo) {
|
|
free_VS_VERSIONINFO(vs_VersionInfo);
|
|
}
|
|
|
|
static Var *Pe_r_bin_pe_parse_var(struct PE_(r_bin_pe_obj_t)* bin, PE_DWord *curAddr) {
|
|
Var *var = calloc (1, sizeof(*var));
|
|
if (var == NULL) {
|
|
eprintf ("Warning: calloc (Var)\n");
|
|
return NULL;
|
|
}
|
|
|
|
if (r_buf_read_at(bin->b, *curAddr, (ut8*)&var->wLength, sizeof(var->wLength)) != sizeof(var->wLength)) {
|
|
eprintf ("Warning: read (Var wLength)\n");
|
|
free_Var(var);
|
|
return NULL;
|
|
}
|
|
*curAddr += sizeof(var->wLength);
|
|
|
|
if (r_buf_read_at(bin->b, *curAddr, (ut8*)&var->wValueLength, sizeof(var->wValueLength)) != sizeof(var->wValueLength)) {
|
|
eprintf ("Warning: read (Var wValueLength)\n");
|
|
free_Var(var);
|
|
return NULL;
|
|
}
|
|
*curAddr += sizeof(var->wValueLength);
|
|
|
|
if (r_buf_read_at(bin->b, *curAddr, (ut8*)&var->wType, sizeof(var->wType)) != sizeof(var->wType)) {
|
|
eprintf ("Warning: read (Var wType)\n");
|
|
free_Var(var);
|
|
return NULL;
|
|
}
|
|
*curAddr += sizeof(var->wType);
|
|
|
|
if (var->wType != 0 && var->wType != 1) {
|
|
eprintf ("Warning: check (Var wType)\n");
|
|
free_Var(var);
|
|
return NULL;
|
|
}
|
|
|
|
var->szKey = (ut16 *) malloc (TRANSLATION_UTF_16_LEN); //L"Translation"
|
|
if (var->szKey == NULL) {
|
|
eprintf ("Warning: malloc (Var szKey)\n");
|
|
free_Var(var);
|
|
return NULL;
|
|
}
|
|
|
|
if (r_buf_read_at(bin->b, *curAddr, (ut8*)var->szKey, TRANSLATION_UTF_16_LEN) != TRANSLATION_UTF_16_LEN) {
|
|
eprintf ("Warning: read (Var szKey)\n");
|
|
free_Var(var);
|
|
return NULL;
|
|
}
|
|
*curAddr += TRANSLATION_UTF_16_LEN;
|
|
|
|
if (memcmp(var->szKey, TRANSLATION_UTF_16, TRANSLATION_UTF_16_LEN) != 0) {
|
|
eprintf ("Warning: check (Var szKey)\n");
|
|
free_Var(var);
|
|
return NULL;
|
|
}
|
|
|
|
align32(*curAddr);
|
|
|
|
var->numOfValues = var->wValueLength / 4;
|
|
if (var->numOfValues == 0) {
|
|
eprintf ("Warning: check (Var numOfValues)\n");
|
|
free_Var(var);
|
|
return NULL;
|
|
}
|
|
|
|
var->Value = (ut32 *) malloc (var->wValueLength);
|
|
if (var->Value == NULL) {
|
|
eprintf ("Warning: malloc (Var Value)\n");
|
|
free_Var(var);
|
|
return NULL;
|
|
}
|
|
|
|
if (r_buf_read_at(bin->b, *curAddr, (ut8*)var->Value, var->wValueLength) != var->wValueLength) {
|
|
eprintf ("Warning: read (Var Value)\n");
|
|
free_Var(var);
|
|
return NULL;
|
|
}
|
|
*curAddr += var->wValueLength;
|
|
|
|
return var;
|
|
}
|
|
|
|
static VarFileInfo *Pe_r_bin_pe_parse_var_file_info(struct PE_(r_bin_pe_obj_t)* bin, PE_DWord *curAddr) {
|
|
VarFileInfo *varFileInfo = calloc (1, sizeof(*varFileInfo));
|
|
if (varFileInfo == NULL) {
|
|
eprintf ("Warning: calloc (VarFileInfo)\n");
|
|
return NULL;
|
|
}
|
|
|
|
PE_DWord startAddr = *curAddr;
|
|
|
|
if (r_buf_read_at(bin->b, *curAddr, (ut8*)&varFileInfo->wLength, sizeof(varFileInfo->wLength)) != sizeof(varFileInfo->wLength)) {
|
|
eprintf ("Warning: read (VarFileInfo wLength)\n");
|
|
free_VarFileInfo(varFileInfo);
|
|
return NULL;
|
|
}
|
|
*curAddr += sizeof(varFileInfo->wLength);
|
|
|
|
if (r_buf_read_at(bin->b, *curAddr, (ut8*)&varFileInfo->wValueLength, sizeof(varFileInfo->wValueLength)) != sizeof(varFileInfo->wValueLength)) {
|
|
eprintf ("Warning: read (VarFileInfo wValueLength)\n");
|
|
free_VarFileInfo(varFileInfo);
|
|
return NULL;
|
|
}
|
|
*curAddr += sizeof(varFileInfo->wValueLength);
|
|
|
|
if (varFileInfo->wValueLength != 0) {
|
|
eprintf ("Warning: check (VarFileInfo wValueLength)\n");
|
|
free_VarFileInfo(varFileInfo);
|
|
return NULL;
|
|
}
|
|
|
|
if (r_buf_read_at(bin->b, *curAddr, (ut8*)&varFileInfo->wType, sizeof(varFileInfo->wType)) != sizeof(varFileInfo->wType)) {
|
|
eprintf ("Warning: read (VarFileInfo wType)\n");
|
|
free_VarFileInfo(varFileInfo);
|
|
return NULL;
|
|
}
|
|
*curAddr += sizeof(varFileInfo->wType);
|
|
|
|
if (varFileInfo->wType != 0 && varFileInfo->wType != 1) {
|
|
eprintf ("Warning: check (VarFileInfo wType)\n");
|
|
free_VarFileInfo(varFileInfo);
|
|
return NULL;
|
|
}
|
|
|
|
varFileInfo->szKey = (ut16 *) malloc (VARFILEINFO_UTF_16_LEN); //L"VarFileInfo"
|
|
if (varFileInfo->szKey == NULL) {
|
|
eprintf ("Warning: malloc (VarFileInfo szKey)\n");
|
|
free_VarFileInfo(varFileInfo);
|
|
return NULL;
|
|
}
|
|
|
|
if (r_buf_read_at(bin->b, *curAddr, (ut8*)varFileInfo->szKey, VARFILEINFO_UTF_16_LEN) != VARFILEINFO_UTF_16_LEN) {
|
|
eprintf ("Warning: read (VarFileInfo szKey)\n");
|
|
free_VarFileInfo(varFileInfo);
|
|
return NULL;
|
|
}
|
|
*curAddr += VARFILEINFO_UTF_16_LEN;
|
|
|
|
if (memcmp(varFileInfo->szKey, VARFILEINFO_UTF_16, VARFILEINFO_UTF_16_LEN) != 0) {
|
|
eprintf ("Warning: check (VarFileInfo szKey)\n");
|
|
free_VarFileInfo(varFileInfo);
|
|
return NULL;
|
|
}
|
|
|
|
align32(*curAddr);
|
|
|
|
while (startAddr + varFileInfo->wLength > *curAddr) {
|
|
Var **tmp = (Var **) realloc(varFileInfo->Children, (varFileInfo->numOfChildren + 1) * sizeof(*varFileInfo->Children));
|
|
if (tmp == NULL) {
|
|
eprintf ("Warning: realloc (VarFileInfo Children)\n");
|
|
free_VarFileInfo(varFileInfo);
|
|
return NULL;
|
|
}
|
|
varFileInfo->Children = tmp;
|
|
if ((varFileInfo->Children[varFileInfo->numOfChildren] = Pe_r_bin_pe_parse_var(bin, curAddr)) == NULL) {
|
|
eprintf ("Warning: bad parsing Var\n");
|
|
free_VarFileInfo(varFileInfo);
|
|
return NULL;
|
|
}
|
|
varFileInfo->numOfChildren++;
|
|
align32(*curAddr);
|
|
}
|
|
return varFileInfo;
|
|
}
|
|
|
|
static String *Pe_r_bin_pe_parse_string(struct PE_(r_bin_pe_obj_t)* bin, PE_DWord *curAddr) {
|
|
String *string = calloc (1, sizeof(*string));
|
|
if (string == NULL) {
|
|
eprintf ("Warning: calloc (String)\n");
|
|
return NULL;
|
|
}
|
|
|
|
if (r_buf_read_at(bin->b, *curAddr, (ut8*)&string->wLength, sizeof(string->wLength)) != sizeof(string->wLength)) {
|
|
eprintf ("Warning: read (String wLength)\n");
|
|
free_String(string);
|
|
return NULL;
|
|
}
|
|
*curAddr += sizeof(string->wLength);
|
|
|
|
if (r_buf_read_at(bin->b, *curAddr, (ut8*)&string->wValueLength, sizeof(string->wValueLength)) != sizeof(string->wValueLength)) {
|
|
eprintf ("Warning: read (String wValueLength)\n");
|
|
free_String(string);
|
|
return NULL;
|
|
}
|
|
*curAddr += sizeof(string->wValueLength);
|
|
|
|
if (r_buf_read_at(bin->b, *curAddr, (ut8*)&string->wType, sizeof(string->wType)) != sizeof(string->wType)) {
|
|
eprintf ("Warning: read (String wType)\n");
|
|
free_String(string);
|
|
return NULL;
|
|
}
|
|
*curAddr += sizeof(string->wType);
|
|
|
|
if (string->wType != 0 && string->wType != 1) {
|
|
eprintf ("Warning: check (String wType)\n");
|
|
free_String(string);
|
|
return NULL;
|
|
}
|
|
|
|
string->wKeyLen = string->wLength - string->wValueLength * 2 - sizeof(string->wLength) * 3;
|
|
string->szKey = (ut16 *) malloc (string->wKeyLen); //If there was padding, we would read it in string
|
|
if (string->szKey == NULL) {
|
|
eprintf ("Warning: malloc (String szKey)\n");
|
|
free_String(string);
|
|
return NULL;
|
|
}
|
|
|
|
if (r_buf_read_at(bin->b, *curAddr, (ut8*)string->szKey, string->wKeyLen) != string->wKeyLen) {
|
|
eprintf ("Warning: read (String szKey)\n");
|
|
free_String(string);
|
|
return NULL;
|
|
}
|
|
*curAddr += string->wKeyLen;
|
|
|
|
align32(*curAddr);
|
|
|
|
string->Value = (ut16 *) calloc (string->wValueLength, 2);
|
|
if (string->Value == NULL) {
|
|
eprintf ("Warning: malloc (String Value)\n");
|
|
free_String(string);
|
|
return NULL;
|
|
}
|
|
|
|
if (r_buf_read_at(bin->b, *curAddr, (ut8*)string->Value, string->wValueLength * 2) != string->wValueLength * 2) {
|
|
eprintf ("Warning: read (String Value)\n");
|
|
free_String(string);
|
|
return NULL;
|
|
}
|
|
*curAddr += string->wValueLength * 2;
|
|
|
|
return string;
|
|
}
|
|
|
|
static StringTable *Pe_r_bin_pe_parse_string_table(struct PE_(r_bin_pe_obj_t)* bin, PE_DWord *curAddr) {
|
|
StringTable *stringTable = calloc (1, sizeof(*stringTable));
|
|
if (stringTable == NULL) {
|
|
eprintf ("Warning: calloc (stringTable)\n");
|
|
return NULL;
|
|
}
|
|
|
|
PE_DWord startAddr = *curAddr;
|
|
if (r_buf_read_at(bin->b, *curAddr, (ut8*)&stringTable->wLength, sizeof(stringTable->wLength)) != sizeof(stringTable->wLength)) {
|
|
eprintf ("Warning: read (StringTable wLength)\n");
|
|
free_StringTable(stringTable);
|
|
return NULL;
|
|
}
|
|
*curAddr += sizeof(stringTable->wLength);
|
|
|
|
if (r_buf_read_at(bin->b, *curAddr, (ut8*)&stringTable->wValueLength, sizeof(stringTable->wValueLength)) != sizeof(stringTable->wValueLength)) {
|
|
eprintf ("Warning: read (StringTable wValueLength)\n");
|
|
free_StringTable(stringTable);
|
|
return NULL;
|
|
}
|
|
*curAddr += sizeof(stringTable->wValueLength);
|
|
|
|
if (stringTable->wValueLength != 0) {
|
|
eprintf ("Warning: check (StringTable wValueLength)\n");
|
|
free_StringTable(stringTable);
|
|
return NULL;
|
|
}
|
|
|
|
if (r_buf_read_at(bin->b, *curAddr, (ut8*)&stringTable->wType, sizeof(stringTable->wType)) != sizeof(stringTable->wType)) {
|
|
eprintf ("Warning: read (StringTable wType)\n");
|
|
free_StringTable(stringTable);
|
|
return NULL;
|
|
}
|
|
*curAddr += sizeof(stringTable->wType);
|
|
|
|
if (stringTable->wType != 0 && stringTable->wType != 1) {
|
|
eprintf ("Warning: check (StringTable wType)\n");
|
|
free_StringTable(stringTable);
|
|
return NULL;
|
|
}
|
|
|
|
stringTable->szKey = (ut16 *) malloc (EIGHT_HEX_DIG_UTF_16_LEN); //EIGHT_HEX_DIG_UTF_16_LEN
|
|
if (stringTable->szKey == NULL) {
|
|
eprintf ("Warning: malloc (stringTable szKey)\n");
|
|
free_StringTable(stringTable);
|
|
return NULL;
|
|
}
|
|
|
|
if (r_buf_read_at(bin->b, *curAddr, (ut8*)stringTable->szKey, EIGHT_HEX_DIG_UTF_16_LEN) != EIGHT_HEX_DIG_UTF_16_LEN) {
|
|
eprintf ("Warning: read (StringTable szKey)\n");
|
|
free_StringTable(stringTable);
|
|
return NULL;
|
|
}
|
|
*curAddr += EIGHT_HEX_DIG_UTF_16_LEN;
|
|
|
|
align32(*curAddr);
|
|
|
|
while (startAddr + stringTable->wLength > *curAddr) {
|
|
String **tmp = (String **) realloc(stringTable->Children, (stringTable->numOfChildren + 1) * sizeof(*stringTable->Children));
|
|
if (tmp == NULL) {
|
|
eprintf ("Warning: realloc (StringTable Children)\n");
|
|
free_StringTable(stringTable);
|
|
return NULL;
|
|
}
|
|
stringTable->Children = tmp;
|
|
if ((stringTable->Children[stringTable->numOfChildren] = Pe_r_bin_pe_parse_string(bin, curAddr)) == NULL) {
|
|
eprintf ("Warning: bad parsing String\n");
|
|
free_StringTable(stringTable);
|
|
return NULL;
|
|
}
|
|
stringTable->numOfChildren++;
|
|
align32(*curAddr);
|
|
}
|
|
|
|
if (stringTable->numOfChildren == 0) {
|
|
eprintf ("Warning: check (StringTable numOfChildren)\n");
|
|
free_StringTable(stringTable);
|
|
return NULL;
|
|
}
|
|
|
|
return stringTable;
|
|
}
|
|
|
|
static StringFileInfo *Pe_r_bin_pe_parse_string_file_info(struct PE_(r_bin_pe_obj_t)* bin, PE_DWord *curAddr) {
|
|
StringFileInfo *stringFileInfo = calloc (1, sizeof(*stringFileInfo));
|
|
if (stringFileInfo == NULL) {
|
|
eprintf ("Warning: calloc (StringFileInfo)\n");
|
|
return NULL;
|
|
}
|
|
|
|
PE_DWord startAddr = *curAddr;
|
|
|
|
if (r_buf_read_at(bin->b, *curAddr, (ut8*)&stringFileInfo->wLength, sizeof(stringFileInfo->wLength)) != sizeof(stringFileInfo->wLength)) {
|
|
eprintf ("Warning: read (StringFileInfo wLength)\n");
|
|
free_StringFileInfo(stringFileInfo);
|
|
return NULL;
|
|
}
|
|
*curAddr += sizeof(stringFileInfo->wLength);
|
|
|
|
if (r_buf_read_at(bin->b, *curAddr, (ut8*)&stringFileInfo->wValueLength, sizeof(stringFileInfo->wValueLength)) != sizeof(stringFileInfo->wValueLength)) {
|
|
eprintf ("Warning: read (StringFileInfo wValueLength)\n");
|
|
free_StringFileInfo(stringFileInfo);
|
|
return NULL;
|
|
}
|
|
*curAddr += sizeof(stringFileInfo->wValueLength);
|
|
|
|
if (stringFileInfo->wValueLength != 0) {
|
|
eprintf ("Warning: check (StringFileInfo wValueLength)\n");
|
|
free_StringFileInfo(stringFileInfo);
|
|
return NULL;
|
|
}
|
|
|
|
if (r_buf_read_at(bin->b, *curAddr, (ut8*)&stringFileInfo->wType, sizeof(stringFileInfo->wType)) != sizeof(stringFileInfo->wType)) {
|
|
eprintf ("Warning: read (StringFileInfo wType)\n");
|
|
free_StringFileInfo(stringFileInfo);
|
|
return NULL;
|
|
}
|
|
*curAddr += sizeof(stringFileInfo->wType);
|
|
|
|
if (stringFileInfo->wType != 0 && stringFileInfo->wType != 1) {
|
|
eprintf ("Warning: check (StringFileInfo wType)\n");
|
|
free_StringFileInfo(stringFileInfo);
|
|
return NULL;
|
|
}
|
|
|
|
stringFileInfo->szKey = (ut16 *) malloc (STRINGFILEINFO_UTF_16_LEN); //L"StringFileInfo"
|
|
if (stringFileInfo->szKey == NULL) {
|
|
eprintf ("Warning: malloc (StringFileInfo szKey)\n");
|
|
free_StringFileInfo(stringFileInfo);
|
|
return NULL;
|
|
}
|
|
|
|
if (r_buf_read_at(bin->b, *curAddr, (ut8*)stringFileInfo->szKey, STRINGFILEINFO_UTF_16_LEN) != STRINGFILEINFO_UTF_16_LEN) {
|
|
eprintf ("Warning: read (StringFileInfo szKey)\n");
|
|
free_StringFileInfo(stringFileInfo);
|
|
return NULL;
|
|
}
|
|
*curAddr += STRINGFILEINFO_UTF_16_LEN;
|
|
|
|
if (memcmp(stringFileInfo->szKey, STRINGFILEINFO_UTF_16, STRINGFILEINFO_UTF_16_LEN) != 0) {
|
|
eprintf ("Warning: check (StringFileInfo szKey)\n");
|
|
free_StringFileInfo(stringFileInfo);
|
|
return NULL;
|
|
}
|
|
|
|
align32(*curAddr);
|
|
|
|
while (startAddr + stringFileInfo->wLength > *curAddr) {
|
|
StringTable **tmp = (StringTable **) realloc(stringFileInfo->Children, (stringFileInfo->numOfChildren + 1) * sizeof(*stringFileInfo->Children));
|
|
if (tmp == NULL) {
|
|
eprintf ("Warning: realloc (StringFileInfo Children)\n");
|
|
free_StringFileInfo(stringFileInfo);
|
|
return NULL;
|
|
}
|
|
stringFileInfo->Children = tmp;
|
|
if ((stringFileInfo->Children[stringFileInfo->numOfChildren] = Pe_r_bin_pe_parse_string_table(bin, curAddr)) == NULL) {
|
|
eprintf ("Warning: bad parsing StringTable\n");
|
|
free_StringFileInfo(stringFileInfo);
|
|
return NULL;
|
|
}
|
|
stringFileInfo->numOfChildren++;
|
|
align32(*curAddr);
|
|
}
|
|
|
|
if (stringFileInfo->numOfChildren == 0) {
|
|
eprintf ("Warning: check (StringFileInfo numOfChildren)\n");
|
|
free_StringFileInfo(stringFileInfo);
|
|
return NULL;
|
|
}
|
|
|
|
return stringFileInfo;
|
|
}
|
|
|
|
static PE_VS_VERSIONINFO *Pe_r_bin_pe_parse_version_info(struct PE_(r_bin_pe_obj_t)* bin, PE_DWord version_info_paddr) {
|
|
PE_VS_VERSIONINFO *vs_VersionInfo = calloc (1, sizeof(*vs_VersionInfo));
|
|
if (vs_VersionInfo == NULL) {
|
|
eprintf ("Warning: calloc (VS_VERSIONINFO)\n");
|
|
return NULL;
|
|
}
|
|
|
|
PE_DWord startAddr = version_info_paddr;
|
|
PE_DWord curAddr = version_info_paddr;
|
|
|
|
//align32(curAddr); // XXX: do we really need this? Because in msdn
|
|
//wLength is The length, in bytes, of the VS_VERSIONINFO structure.
|
|
//This length does not include any padding that aligns any subsequent
|
|
//version resource data on a 32-bit boundary.
|
|
//Mb we are in subsequent version resource data and not aligned.
|
|
|
|
if (r_buf_read_at(bin->b, curAddr, (ut8*)&vs_VersionInfo->wLength, sizeof(vs_VersionInfo->wLength)) != sizeof(vs_VersionInfo->wLength)) {
|
|
eprintf ("Warning: read (VS_VERSIONINFO wLength)\n");
|
|
free_VS_VERSIONINFO(vs_VersionInfo);
|
|
return NULL;
|
|
}
|
|
curAddr += sizeof(vs_VersionInfo->wLength);
|
|
|
|
if (r_buf_read_at(bin->b, curAddr, (ut8*)&vs_VersionInfo->wValueLength, sizeof(vs_VersionInfo->wValueLength)) != sizeof(vs_VersionInfo->wValueLength)) {
|
|
eprintf ("Warning: read (VS_VERSIONINFO wValueLength)\n");
|
|
free_VS_VERSIONINFO(vs_VersionInfo);
|
|
return NULL;
|
|
}
|
|
curAddr += sizeof(vs_VersionInfo->wValueLength);
|
|
|
|
if (r_buf_read_at(bin->b, curAddr, (ut8*)&vs_VersionInfo->wType, sizeof(vs_VersionInfo->wType)) != sizeof(vs_VersionInfo->wType)) {
|
|
eprintf ("Warning: read (VS_VERSIONINFO wType)\n");
|
|
free_VS_VERSIONINFO(vs_VersionInfo);
|
|
return NULL;
|
|
}
|
|
curAddr += sizeof(vs_VersionInfo->wType);
|
|
|
|
if (vs_VersionInfo->wType != 0 && vs_VersionInfo->wType != 1) {
|
|
eprintf ("Warning: check (VS_VERSIONINFO wType)\n");
|
|
free_VS_VERSIONINFO(vs_VersionInfo);
|
|
return NULL;
|
|
}
|
|
|
|
vs_VersionInfo->szKey = (ut16 *) malloc (VS_VERSION_INFO_UTF_16_LEN); //L"VS_VERSION_INFO"
|
|
if (vs_VersionInfo->szKey == NULL) {
|
|
eprintf ("Warning: malloc (VS_VERSIONINFO szKey)\n");
|
|
free_VS_VERSIONINFO(vs_VersionInfo);
|
|
return NULL;
|
|
}
|
|
|
|
if (r_buf_read_at (bin->b, curAddr, (ut8*)vs_VersionInfo->szKey, VS_VERSION_INFO_UTF_16_LEN) != VS_VERSION_INFO_UTF_16_LEN) {
|
|
eprintf ("Warning: read (VS_VERSIONINFO szKey)\n");
|
|
free_VS_VERSIONINFO(vs_VersionInfo);
|
|
return NULL;
|
|
}
|
|
curAddr += VS_VERSION_INFO_UTF_16_LEN;
|
|
|
|
if (memcmp (vs_VersionInfo->szKey, VS_VERSION_INFO_UTF_16, VS_VERSION_INFO_UTF_16_LEN)) {
|
|
eprintf ("Warning: check (VS_VERSIONINFO szKey)\n");
|
|
free_VS_VERSIONINFO(vs_VersionInfo);
|
|
return NULL;
|
|
}
|
|
|
|
align32 (curAddr);
|
|
|
|
if (vs_VersionInfo->wValueLength) {
|
|
if (vs_VersionInfo->wValueLength != sizeof (*vs_VersionInfo->Value)) {
|
|
eprintf ("Warning: check (VS_VERSIONINFO wValueLength != sizeof PE_VS_FIXEDFILEINFO)\n");
|
|
free_VS_VERSIONINFO (vs_VersionInfo);
|
|
return NULL;
|
|
}
|
|
|
|
vs_VersionInfo->Value = (PE_VS_FIXEDFILEINFO *) malloc (sizeof(*vs_VersionInfo->Value));
|
|
if (vs_VersionInfo->Value == NULL) {
|
|
eprintf ("Warning: malloc (VS_VERSIONINFO Value)\n");
|
|
free_VS_VERSIONINFO (vs_VersionInfo);
|
|
return NULL;
|
|
}
|
|
|
|
const int sz = sizeof(*vs_VersionInfo->Value);
|
|
if (r_buf_read_at (bin->b, curAddr, (ut8*)vs_VersionInfo->Value, sz) != sz) {
|
|
eprintf ("Warning: read (VS_VERSIONINFO Value)\n");
|
|
free_VS_VERSIONINFO(vs_VersionInfo);
|
|
return NULL;
|
|
}
|
|
|
|
if (vs_VersionInfo->Value->dwSignature != 0xFEEF04BD) {
|
|
eprintf ("Warning: check (PE_VS_FIXEDFILEINFO signature) 0x%08x\n",
|
|
vs_VersionInfo->Value->dwSignature);
|
|
free_VS_VERSIONINFO(vs_VersionInfo);
|
|
return NULL;
|
|
}
|
|
curAddr += sizeof(*vs_VersionInfo->Value);
|
|
|
|
align32(curAddr);
|
|
}
|
|
|
|
if (startAddr + vs_VersionInfo->wLength > curAddr) {
|
|
char t = '\0';
|
|
if (r_buf_read_at(bin->b, curAddr + 3 * sizeof(ut16), (ut8*)&t, 1) != 1) {
|
|
eprintf ("Warning: read (VS_VERSIONINFO Children V or S)\n");
|
|
free_VS_VERSIONINFO(vs_VersionInfo);
|
|
return NULL;
|
|
}
|
|
if (!(t == 'S' || t == 'V')) {
|
|
eprintf ("Warning: bad type (VS_VERSIONINFO Children)\n");
|
|
free_VS_VERSIONINFO(vs_VersionInfo);
|
|
return NULL;
|
|
}
|
|
if (t == 'S') {
|
|
if ((vs_VersionInfo->stringFileInfo = Pe_r_bin_pe_parse_string_file_info(bin, &curAddr)) == NULL) {
|
|
eprintf ("Warning: bad parsing (VS_VERSIONINFO StringFileInfo)\n");
|
|
free_VS_VERSIONINFO(vs_VersionInfo);
|
|
return NULL;
|
|
}
|
|
}
|
|
if (t == 'V') {
|
|
if ((vs_VersionInfo->varFileInfo = Pe_r_bin_pe_parse_var_file_info(bin, &curAddr)) == NULL) {
|
|
eprintf ("Warning: bad parsing (VS_VERSIONINFO VarFileInfo)\n");
|
|
free_VS_VERSIONINFO(vs_VersionInfo);
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
align32(curAddr);
|
|
|
|
if (startAddr + vs_VersionInfo->wLength > curAddr) {
|
|
if (t == 'V') {
|
|
if ((vs_VersionInfo->stringFileInfo = Pe_r_bin_pe_parse_string_file_info(bin, &curAddr)) == NULL) {
|
|
eprintf ("Warning: bad parsing (VS_VERSIONINFO StringFileInfo)\n");
|
|
free_VS_VERSIONINFO(vs_VersionInfo);
|
|
return NULL;
|
|
}
|
|
} else if (t == 'S') {
|
|
if ((vs_VersionInfo->varFileInfo = Pe_r_bin_pe_parse_var_file_info(bin, &curAddr)) == NULL) {
|
|
eprintf ("Warning: bad parsing (VS_VERSIONINFO VarFileInfo)\n");
|
|
free_VS_VERSIONINFO(vs_VersionInfo);
|
|
return NULL;
|
|
}
|
|
}
|
|
if (startAddr + vs_VersionInfo->wLength > curAddr) {
|
|
eprintf ("Warning: bad parsing (VS_VERSIONINFO wLength left)\n");
|
|
free_VS_VERSIONINFO(vs_VersionInfo);
|
|
return NULL;
|
|
}
|
|
}
|
|
}
|
|
return vs_VersionInfo;
|
|
}
|
|
|
|
static Sdb *Pe_r_bin_store_var(Var *var) {
|
|
unsigned int i = 0;
|
|
char key[20];
|
|
Sdb *sdb = NULL;
|
|
if (var) {
|
|
sdb = sdb_new0();
|
|
if (sdb) {
|
|
for (; i < var->numOfValues; i++) {
|
|
snprintf(key, 20, "%d", i);
|
|
sdb_num_set(sdb, key, var->Value[i], 0);
|
|
}
|
|
}
|
|
}
|
|
return sdb;
|
|
}
|
|
|
|
static Sdb *Pe_r_bin_store_var_file_info(VarFileInfo *varFileInfo) {
|
|
char key[20];
|
|
if (varFileInfo == NULL)
|
|
return NULL;
|
|
Sdb *sdb = sdb_new0();
|
|
if (sdb == NULL)
|
|
return NULL;
|
|
unsigned int i = 0;
|
|
for (; i < varFileInfo->numOfChildren; i++) {
|
|
snprintf(key, 20, "var%d", i);
|
|
sdb_ns_set (sdb, key, Pe_r_bin_store_var(varFileInfo->Children[i]));
|
|
}
|
|
return sdb;
|
|
}
|
|
|
|
static Sdb *Pe_r_bin_store_string(String *string) {
|
|
if (string == NULL)
|
|
return NULL;
|
|
Sdb *sdb = sdb_new0();
|
|
if (sdb == NULL)
|
|
return NULL;
|
|
char *encodedKey = sdb_encode((unsigned char *) string->szKey, string->wKeyLen);
|
|
if (encodedKey == NULL) {
|
|
sdb_free(sdb);
|
|
return NULL;
|
|
}
|
|
char *encodedVal = sdb_encode((unsigned char *) string->Value, string->wValueLength * 2);
|
|
if (encodedVal == NULL) {
|
|
free(encodedKey);
|
|
sdb_free(sdb);
|
|
return NULL;
|
|
}
|
|
sdb_set(sdb, "key", encodedKey, 0);
|
|
sdb_set(sdb, "value", encodedVal, 0);
|
|
return sdb;
|
|
}
|
|
|
|
static Sdb *Pe_r_bin_store_string_table(StringTable *stringTable) {
|
|
char key[20];
|
|
if (stringTable == NULL)
|
|
return NULL;
|
|
Sdb *sdb = sdb_new0();
|
|
if (sdb == NULL)
|
|
return NULL;
|
|
char *encodedKey = sdb_encode((unsigned char *) stringTable->szKey, EIGHT_HEX_DIG_UTF_16_LEN);
|
|
if (encodedKey == NULL) {
|
|
sdb_free(sdb);
|
|
return NULL;
|
|
}
|
|
sdb_set(sdb, "key", encodedKey, 0);
|
|
int i = 0;
|
|
for (; i < stringTable->numOfChildren; i++) {
|
|
snprintf(key, 20, "string%d", i);
|
|
sdb_ns_set (sdb, key, Pe_r_bin_store_string(stringTable->Children[i]));
|
|
}
|
|
return sdb;
|
|
}
|
|
|
|
static Sdb *Pe_r_bin_store_string_file_info(StringFileInfo *stringFileInfo) {
|
|
char key[30];
|
|
if (stringFileInfo == NULL)
|
|
return NULL;
|
|
Sdb *sdb = sdb_new0();
|
|
if (sdb == NULL)
|
|
return NULL;
|
|
int i = 0;
|
|
for (; i < stringFileInfo->numOfChildren; i++) {
|
|
snprintf(key, 30, "stringtable%d", i);
|
|
sdb_ns_set (sdb, key, Pe_r_bin_store_string_table(stringFileInfo->Children[i]));
|
|
}
|
|
return sdb;
|
|
}
|
|
|
|
static Sdb *Pe_r_bin_store_fixed_file_info(PE_VS_FIXEDFILEINFO *vs_fixedFileInfo) {
|
|
if (vs_fixedFileInfo == NULL)
|
|
return NULL;
|
|
Sdb *sdb = sdb_new0();
|
|
if (sdb == NULL)
|
|
return NULL;
|
|
sdb_num_set(sdb, "Signature", vs_fixedFileInfo->dwSignature, 0);
|
|
sdb_num_set(sdb, "StrucVersion", vs_fixedFileInfo->dwStrucVersion, 0);
|
|
sdb_num_set(sdb, "FileVersionMS", vs_fixedFileInfo->dwFileVersionMS, 0);
|
|
sdb_num_set(sdb, "FileVersionLS", vs_fixedFileInfo->dwFileVersionLS, 0);
|
|
sdb_num_set(sdb, "ProductVersionMS", vs_fixedFileInfo->dwProductVersionMS, 0);
|
|
sdb_num_set(sdb, "ProductVersionLS", vs_fixedFileInfo->dwProductVersionLS, 0);
|
|
sdb_num_set(sdb, "FileFlagsMask", vs_fixedFileInfo->dwFileFlagsMask, 0);
|
|
sdb_num_set(sdb, "FileFlags", vs_fixedFileInfo->dwFileFlags, 0);
|
|
sdb_num_set(sdb, "FileOS", vs_fixedFileInfo->dwFileOS, 0);
|
|
sdb_num_set(sdb, "FileType", vs_fixedFileInfo->dwFileType, 0);
|
|
sdb_num_set(sdb, "FileSubtype", vs_fixedFileInfo->dwFileSubtype, 0);
|
|
sdb_num_set(sdb, "FileDateMS", vs_fixedFileInfo->dwFileDateMS, 0);
|
|
sdb_num_set(sdb, "FileDateLS", vs_fixedFileInfo->dwFileDateLS, 0);
|
|
return sdb;
|
|
}
|
|
|
|
static Sdb *Pe_r_bin_store_resource_version_info(PE_VS_VERSIONINFO *vs_VersionInfo) {
|
|
if (vs_VersionInfo == NULL)
|
|
return NULL;
|
|
Sdb *sdb = sdb_new0();
|
|
if (sdb == NULL)
|
|
return NULL;
|
|
if (vs_VersionInfo->Value)
|
|
sdb_ns_set (sdb, "fixed_file_info", Pe_r_bin_store_fixed_file_info(vs_VersionInfo->Value));
|
|
if (vs_VersionInfo->varFileInfo)
|
|
sdb_ns_set (sdb, "var_file_info", Pe_r_bin_store_var_file_info(vs_VersionInfo->varFileInfo));
|
|
if (vs_VersionInfo->stringFileInfo)
|
|
sdb_ns_set (sdb, "string_file_info", Pe_r_bin_store_string_file_info(vs_VersionInfo->stringFileInfo));
|
|
return sdb;
|
|
}
|
|
|
|
void PE_(r_bin_store_all_resource_version_info)(struct PE_(r_bin_pe_obj_t)* bin) {
|
|
char key[30];
|
|
if (bin == NULL || bin->resource_directory == NULL)
|
|
return;
|
|
int counter = 0;
|
|
Sdb *sdb = sdb_new0();
|
|
if (sdb == NULL)
|
|
return;
|
|
// XXX: assume there is only 3 layers in the tree
|
|
ut32 totalRes = bin->resource_directory->NumberOfNamedEntries + bin->resource_directory->NumberOfIdEntries;
|
|
ut32 curRes = bin->resource_directory->NumberOfNamedEntries;
|
|
for (; curRes < totalRes; curRes++) {
|
|
Pe_image_resource_directory_entry typeEntry;
|
|
if (r_buf_read_at (bin->b, bin->resource_directory_offset + sizeof (*bin->resource_directory) + curRes * sizeof (typeEntry),
|
|
(ut8*)&typeEntry, sizeof (typeEntry)) != sizeof (typeEntry)) {
|
|
eprintf ("Warning: read (resource type directory entry)\n");
|
|
sdb_free (sdb);
|
|
return;
|
|
}
|
|
if (!typeEntry.u1.s.NameIsString && typeEntry.u1.Id == PE_RESOURCE_ENTRY_VERSION) {
|
|
Pe_image_resource_directory identDir;
|
|
if (r_buf_read_at (bin->b, bin->resource_directory_offset + typeEntry.u2.s.OffsetToDirectory,
|
|
(ut8*)&identDir, sizeof (identDir)) != sizeof (identDir)) {
|
|
eprintf ("Warning: read (resource identifier directory)\n");
|
|
sdb_free (sdb);
|
|
return;
|
|
}
|
|
ut32 totalIdent = identDir.NumberOfNamedEntries + identDir.NumberOfIdEntries;
|
|
ut32 curIdent = 0;
|
|
for (; curIdent < totalIdent; curIdent++) {
|
|
Pe_image_resource_directory_entry identEntry;
|
|
if (r_buf_read_at (bin->b, bin->resource_directory_offset + typeEntry.u2.s.OffsetToDirectory + sizeof (identDir) +
|
|
curIdent * sizeof (identEntry), (ut8*)&identEntry, sizeof (identEntry)) != sizeof (identEntry)) {
|
|
eprintf ("Warning: read (resource identifier entry)\n");
|
|
sdb_free (sdb);
|
|
return;
|
|
}
|
|
if (!identEntry.u2.s.DataIsDirectory)
|
|
continue;
|
|
Pe_image_resource_directory langDir;
|
|
if (r_buf_read_at (bin->b, bin->resource_directory_offset + identEntry.u2.s.OffsetToDirectory,
|
|
(ut8*)&langDir, sizeof (langDir)) != sizeof (langDir)) {
|
|
eprintf ("Warning: read (resource language directory)\n");
|
|
sdb_free (sdb);
|
|
return;
|
|
}
|
|
ut32 totalLang = langDir.NumberOfNamedEntries + langDir.NumberOfIdEntries;
|
|
ut32 curLang = 0;
|
|
for (; curLang < totalLang; curLang++) {
|
|
Pe_image_resource_directory_entry langEntry;
|
|
if (r_buf_read_at (bin->b, bin->resource_directory_offset + identEntry.u2.s.OffsetToDirectory + sizeof (langDir) +
|
|
curLang * sizeof (langEntry), (ut8*)&langEntry, sizeof (langEntry)) != sizeof (langEntry)) {
|
|
eprintf ("Warning: read (resource language entry)\n");
|
|
sdb_free (sdb);
|
|
return;
|
|
}
|
|
if (langEntry.u2.s.DataIsDirectory)
|
|
continue;
|
|
Pe_image_resource_data_entry data;
|
|
if (r_buf_read_at (bin->b, bin->resource_directory_offset + langEntry.u2.OffsetToData,
|
|
(ut8*)&data, sizeof (data)) != sizeof (data)) {
|
|
eprintf ("Warning: read (resource data entry)\n");
|
|
sdb_free (sdb);
|
|
return;
|
|
}
|
|
PE_DWord data_paddr = bin_pe_rva_to_paddr(bin, data.OffsetToData);
|
|
if (data_paddr == 0) {
|
|
eprintf ("Warning: bad RVA in resource data entry\n");
|
|
sdb_free (sdb);
|
|
return;
|
|
}
|
|
PE_DWord cur_paddr = data_paddr;
|
|
if ((cur_paddr & 0x3) != 0) {
|
|
// XXX: mb align address and read structure?
|
|
eprintf ("Warning: not aligned version info address\n");
|
|
continue;
|
|
}
|
|
while(cur_paddr < data_paddr + data.Size) {
|
|
PE_VS_VERSIONINFO *vs_VersionInfo = Pe_r_bin_pe_parse_version_info(bin, cur_paddr);
|
|
if (vs_VersionInfo) {
|
|
snprintf(key, 30, "VS_VERSIONINFO%d", counter++);
|
|
sdb_ns_set (sdb, key, Pe_r_bin_store_resource_version_info(vs_VersionInfo));
|
|
} else {
|
|
break;
|
|
}
|
|
cur_paddr += vs_VersionInfo->wLength;
|
|
free_VS_VERSIONINFO(vs_VersionInfo);
|
|
align32(cur_paddr);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
sdb_ns_set (bin->kv, "vs_version_info", sdb);
|
|
}
|
|
|
|
static int 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->resource_directory = NULL;
|
|
bin->delay_import_directory = NULL;
|
|
bin->endian = 0; /* TODO: get endian */
|
|
if (!bin_pe_init_hdr(bin)) {
|
|
eprintf ("Warning: File is not PE\n");
|
|
return false;
|
|
}
|
|
if (!bin_pe_init_sections(bin)) {
|
|
eprintf ("Warning: Cannot initialize sections\n");
|
|
return false;
|
|
}
|
|
bin_pe_init_imports(bin);
|
|
bin_pe_init_exports(bin);
|
|
bin_pe_init_resource(bin);
|
|
PE_(r_bin_store_all_resource_version_info)(bin);
|
|
bin->relocs = NULL;
|
|
return true;
|
|
}
|
|
|
|
char* PE_(r_bin_pe_get_arch)(struct PE_(r_bin_pe_obj_t)* bin) {
|
|
char *arch;
|
|
if (!bin || !bin->nt_headers)
|
|
return strdup ("x86");
|
|
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_RPI2: // 462
|
|
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;
|
|
PE_DWord pe_entry;
|
|
|
|
if (!bin || !bin->nt_headers)
|
|
return NULL;
|
|
if ((entry = malloc (sizeof (struct r_bin_pe_addr_t))) == NULL) {
|
|
r_sys_perror("malloc (entrypoint)");
|
|
return NULL;
|
|
}
|
|
pe_entry = bin->nt_headers->optional_header.AddressOfEntryPoint;
|
|
entry->vaddr = bin_pe_rva_to_va (bin, pe_entry);
|
|
entry->paddr = bin_pe_rva_to_paddr (bin, pe_entry);
|
|
|
|
if (is_arm (bin) && entry->vaddr & 1) {
|
|
entry->vaddr--;
|
|
if (entry->paddr & 1) {
|
|
entry->paddr--;
|
|
}
|
|
}
|
|
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 *exp, *exports = NULL;
|
|
PE_Word function_ordinal;
|
|
PE_VWord functions_paddr, names_paddr, ordinals_paddr, function_rva, name_vaddr, name_paddr;
|
|
char function_name[PE_NAME_LENGTH + 1], forwarder_name[PE_NAME_LENGTH + 1];
|
|
char dll_name[PE_NAME_LENGTH + 1], export_name[256];
|
|
PE_(image_data_directory) *data_dir_export;
|
|
PE_VWord export_dir_rva ;
|
|
int n,i, export_dir_size;
|
|
int exports_sz = 0;
|
|
if (!bin || !bin->nt_headers)
|
|
return NULL;
|
|
data_dir_export = &bin->nt_headers->optional_header.DataDirectory[PE_IMAGE_DIRECTORY_ENTRY_EXPORT];
|
|
export_dir_rva = data_dir_export->VirtualAddress;
|
|
export_dir_size = data_dir_export->Size;
|
|
if (bin->export_directory && bin->export_directory->NumberOfFunctions<0xfff) {
|
|
exports_sz = (bin->export_directory->NumberOfFunctions + 1) * sizeof (struct r_bin_pe_export_t);
|
|
if (!(exports = malloc (exports_sz)))
|
|
return NULL;
|
|
if (r_buf_read_at (bin->b, bin_pe_rva_to_paddr(bin, bin->export_directory->Name),(ut8*)dll_name, PE_NAME_LENGTH) == -1) {
|
|
eprintf ("Warning: read (dll name)\n");
|
|
free (exports);
|
|
return NULL;
|
|
}
|
|
functions_paddr = bin_pe_rva_to_paddr(bin,bin->export_directory->AddressOfFunctions);
|
|
names_paddr = bin_pe_rva_to_paddr(bin, bin->export_directory->AddressOfNames);
|
|
ordinals_paddr = bin_pe_rva_to_paddr(bin,bin->export_directory->AddressOfOrdinals);
|
|
for (i=0;i<bin->export_directory->NumberOfFunctions;i++) {
|
|
// get vaddr from AddressOfFunctions array
|
|
int ret = r_buf_read_at (bin->b, functions_paddr + i * sizeof(PE_VWord),
|
|
(ut8*)&function_rva, sizeof(PE_VWord));
|
|
if (!ret) break;
|
|
// have exports by name?
|
|
if (bin->export_directory->NumberOfNames!=0) {
|
|
// search for value of i into AddressOfOrdinals
|
|
name_vaddr=0;
|
|
for (n=0; n<bin->export_directory->NumberOfNames;n++) {
|
|
int ret = r_buf_read_at (bin->b,
|
|
ordinals_paddr + n * sizeof(PE_Word),
|
|
(ut8*)&function_ordinal,sizeof (PE_Word));
|
|
if (ret<1) break;
|
|
// if exist this index into AddressOfOrdinals
|
|
if (i==function_ordinal) {
|
|
// get the VA of export name from AddressOfNames
|
|
r_buf_read_at (bin->b, names_paddr + n * sizeof (PE_VWord), (ut8*)&name_vaddr,sizeof (PE_VWord));
|
|
break;
|
|
}
|
|
}
|
|
// have a address into name_vaddr?
|
|
if (name_vaddr) {
|
|
// get the name of the Export
|
|
name_paddr = bin_pe_rva_to_paddr(bin, name_vaddr);
|
|
if (-1 == r_buf_read_at(bin->b, name_paddr,(ut8*)function_name, PE_NAME_LENGTH)) {
|
|
eprintf("Warning: read (function name)\n");
|
|
free (exports);
|
|
return NULL;
|
|
}
|
|
}
|
|
else { // No name export, get the ordinal
|
|
snprintf (function_name, PE_NAME_LENGTH, "Ordinal_%i", i+1);
|
|
}
|
|
}
|
|
else { // if dont export by name exist, get the ordinal taking in mind the Base value.
|
|
function_ordinal=i+bin->export_directory->Base;
|
|
snprintf (function_name, PE_NAME_LENGTH, "Ordinal_%i", function_ordinal);
|
|
}
|
|
// check if VA are into export directory, this mean a forwarder export
|
|
if (function_rva >= export_dir_rva && function_rva < (export_dir_rva + export_dir_size)) {
|
|
// if forwarder, the VA point to Forwarded name
|
|
if (r_buf_read_at (bin->b, bin_pe_rva_to_paddr(bin, function_rva),(ut8*)forwarder_name, PE_NAME_LENGTH) == -1) {
|
|
eprintf ("Warning: read (magic)\n");
|
|
free (exports);
|
|
return NULL;
|
|
}
|
|
}
|
|
else { // no forwarder export
|
|
snprintf (forwarder_name, PE_NAME_LENGTH, "NONE");
|
|
}
|
|
dll_name[PE_NAME_LENGTH]='\0';
|
|
function_name[PE_NAME_LENGTH]='\0';
|
|
snprintf (export_name, sizeof (export_name)-1, "%s_%s", dll_name, function_name);
|
|
exports[i].vaddr = bin_pe_rva_to_va (bin, function_rva);
|
|
exports[i].paddr = bin_pe_rva_to_paddr (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;
|
|
}
|
|
exp = parse_symbol_table (bin, exports, exports_sz - 1);
|
|
if (exp)
|
|
exports = exp;
|
|
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) {
|
|
if (!bin || !bin->nt_headers)
|
|
return 0LL;
|
|
return (ut64)bin->nt_headers->optional_header.ImageBase;
|
|
}
|
|
|
|
static void free_rsdr_hdr(SCV_RSDS_HEADER *rsds_hdr) {
|
|
R_FREE(rsds_hdr->file_name);
|
|
}
|
|
|
|
static void init_rsdr_hdr(SCV_RSDS_HEADER *rsds_hdr) {
|
|
memset (rsds_hdr, 0, sizeof (SCV_RSDS_HEADER));
|
|
rsds_hdr->free = (void (*)(struct SCV_RSDS_HEADER *)) free_rsdr_hdr;
|
|
}
|
|
|
|
static void free_cv_nb10_header(SCV_NB10_HEADER *cv_nb10_header) {
|
|
R_FREE(cv_nb10_header->file_name);
|
|
}
|
|
|
|
static void init_cv_nb10_header(SCV_NB10_HEADER *cv_nb10_header) {
|
|
memset (cv_nb10_header, 0, sizeof (SCV_NB10_HEADER));
|
|
cv_nb10_header->free = (void (*)(struct SCV_NB10_HEADER *)) free_cv_nb10_header;
|
|
}
|
|
|
|
static void get_rsds(ut8 *dbg_data, SCV_RSDS_HEADER *res) {
|
|
const int rsds_sz = 4 + sizeof (SGUID) + 4;
|
|
memcpy (res, dbg_data, rsds_sz);
|
|
res->file_name = (ut8 *)strdup ((const char *)dbg_data + rsds_sz);
|
|
}
|
|
|
|
static void get_nb10(ut8 *dbg_data, SCV_NB10_HEADER *res) {
|
|
const int nb10sz = 16;
|
|
memcpy(res, dbg_data, nb10sz);
|
|
res->file_name = (ut8 *)strdup ((const char *)dbg_data + nb10sz);
|
|
}
|
|
|
|
static int get_debug_info(PE_(image_debug_directory_entry) *dbg_dir_entry, ut8 *dbg_data, SDebugInfo *res) {
|
|
#define SIZEOF_FILE_NAME 255
|
|
int i = 0;
|
|
|
|
if (dbg_data == NULL)
|
|
return 0;
|
|
|
|
switch (dbg_dir_entry->Type) {
|
|
case IMAGE_DEBUG_TYPE_CODEVIEW:
|
|
if (strncmp((char *)dbg_data, "RSDS", 4) == 0) {
|
|
SCV_RSDS_HEADER rsds_hdr;
|
|
init_rsdr_hdr (&rsds_hdr);
|
|
get_rsds (dbg_data, &rsds_hdr);
|
|
snprintf ((st8 *) res->guidstr, GUIDSTR_LEN,
|
|
"%08x%04x%04x%02x%02x%02x%02x%02x%02x%02x%02x%x",
|
|
rsds_hdr.guid.data1,
|
|
rsds_hdr.guid.data2,
|
|
rsds_hdr.guid.data3,
|
|
rsds_hdr.guid.data4[0],
|
|
rsds_hdr.guid.data4[1],
|
|
rsds_hdr.guid.data4[2],
|
|
rsds_hdr.guid.data4[3],
|
|
rsds_hdr.guid.data4[4],
|
|
rsds_hdr.guid.data4[5],
|
|
rsds_hdr.guid.data4[6],
|
|
rsds_hdr.guid.data4[7],
|
|
rsds_hdr.age);
|
|
strncpy (res->file_name, (const char*)
|
|
rsds_hdr.file_name, sizeof (res->file_name));
|
|
res->file_name[sizeof (res->file_name)-1] = 0;
|
|
rsds_hdr.free ((struct SCV_RSDS_HEADER *)&rsds_hdr);
|
|
} else if (strncmp((const char *)dbg_data, "NB10", 4) == 0) {
|
|
SCV_NB10_HEADER nb10_hdr;
|
|
init_cv_nb10_header (&nb10_hdr);
|
|
get_nb10 (dbg_data, &nb10_hdr);
|
|
snprintf ((st8 *) res->guidstr, sizeof (res->guidstr),
|
|
"%x%x", nb10_hdr.timestamp, nb10_hdr.age);
|
|
strncpy (res->file_name, (const char *)
|
|
nb10_hdr.file_name, sizeof(res->file_name)-1);
|
|
res->file_name[sizeof (res->file_name)-1] = 0;
|
|
nb10_hdr.free ((struct SCV_NB10_HEADER *)&nb10_hdr);
|
|
} else {
|
|
eprintf ("CodeView section not NB10 or RSDS\n");
|
|
return 0;
|
|
}
|
|
break;
|
|
default:
|
|
//eprintf("get_debug_info(): not supported type\n");
|
|
return 0;
|
|
}
|
|
|
|
while (i < 33) {
|
|
res->guidstr[i] = toupper ((int)res->guidstr[i]);
|
|
i++;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
int PE_(r_bin_pe_get_debug_data)(struct PE_(r_bin_pe_obj_t) *bin, SDebugInfo *res) {
|
|
PE_(image_debug_directory_entry) *img_dbg_dir_entry = NULL;
|
|
PE_(image_data_directory) *dbg_dir;
|
|
PE_DWord dbg_dir_offset;
|
|
ut8 *dbg_data = 0;
|
|
int result = 0;
|
|
if (!bin) return 0;
|
|
dbg_dir = &bin->nt_headers->optional_header.DataDirectory[6/*IMAGE_DIRECTORY_ENTRY_DEBUG*/];
|
|
dbg_dir_offset = bin_pe_rva_to_paddr(bin, dbg_dir->VirtualAddress);
|
|
if ((int)dbg_dir_offset<0 || dbg_dir_offset>= bin->size)
|
|
return false;
|
|
if (dbg_dir_offset >= bin->b->length)
|
|
return false;
|
|
img_dbg_dir_entry = (PE_(image_debug_directory_entry)*)(bin->b->buf + dbg_dir_offset);
|
|
if ((bin->b->length - dbg_dir_offset)< sizeof (PE_(image_debug_directory_entry))) {
|
|
return false;
|
|
}
|
|
if (img_dbg_dir_entry) {
|
|
ut32 dbg_data_poff = R_MIN (img_dbg_dir_entry->PointerToRawData, bin->b->length);
|
|
int dbg_data_len = R_MIN (img_dbg_dir_entry->SizeOfData, bin->b->length - dbg_data_poff);
|
|
if (dbg_data_len<1) {
|
|
return false;
|
|
}
|
|
dbg_data = (ut8 *) malloc (dbg_data_len + 1);
|
|
if (dbg_data) {
|
|
r_buf_read_at (bin->b, dbg_data_poff, dbg_data, dbg_data_len);
|
|
result = get_debug_info(img_dbg_dir_entry, dbg_data, res);
|
|
R_FREE(dbg_data);
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
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 nimp = 0;
|
|
PE_DWord dll_name_offset = 0;
|
|
PE_DWord paddr = 0;
|
|
PE_DWord import_func_name_offset;
|
|
PE_(image_import_directory) *curr_import_dir = NULL;
|
|
PE_(image_delay_import_directory) *curr_delay_import_dir = 0;
|
|
|
|
if (!bin) return NULL;
|
|
if (bin->import_directory_offset >= bin->size) return NULL;
|
|
if (bin->import_directory_offset + 32 >= bin->size) return NULL;
|
|
|
|
if (bin->import_directory_offset < bin->size && bin->import_directory_offset > 0) {
|
|
void *last;
|
|
curr_import_dir = (PE_(image_import_directory)*)(bin->b->buf + bin->import_directory_offset);
|
|
dll_name_offset = curr_import_dir->Name;
|
|
|
|
if (bin->import_directory_offset < 1) return NULL;
|
|
if (bin->import_directory_size < 1) return NULL;
|
|
|
|
if (bin->import_directory_offset + bin->import_directory_size > bin->size) {
|
|
eprintf ("Warning: read (import directory too big)\n");
|
|
bin->import_directory_size = bin->size - bin->import_directory_offset;
|
|
}
|
|
last = (char *)curr_import_dir + bin->import_directory_size;
|
|
while ((void*)(curr_import_dir + 1) <= last && (
|
|
curr_import_dir->FirstThunk != 0 || curr_import_dir->Name != 0 ||
|
|
curr_import_dir->TimeDateStamp != 0 || curr_import_dir->Characteristics != 0 ||
|
|
curr_import_dir->ForwarderChain != 0)) {
|
|
dll_name_offset = curr_import_dir->Name;
|
|
paddr = bin_pe_rva_to_paddr (bin, dll_name_offset);
|
|
if (paddr > bin->size || paddr + PE_NAME_LENGTH > bin->size) {
|
|
return NULL;
|
|
}
|
|
int rr = r_buf_read_at (bin->b, paddr,
|
|
(ut8*)dll_name, PE_NAME_LENGTH);
|
|
if (rr != PE_NAME_LENGTH) {
|
|
eprintf ("Warning: read (magic)\n");
|
|
return NULL;
|
|
}
|
|
dll_name[PE_NAME_LENGTH] = '\0';
|
|
if (!bin_pe_parse_imports (bin, &imports, &nimp, dll_name,
|
|
curr_import_dir->Characteristics,
|
|
curr_import_dir->FirstThunk)) {
|
|
break;
|
|
}
|
|
curr_import_dir++;
|
|
}
|
|
}
|
|
|
|
if (bin->delay_import_directory_offset < bin->size && bin->delay_import_directory_offset > 0) {
|
|
curr_delay_import_dir = (PE_(image_delay_import_directory)*) (
|
|
bin->b->buf + bin->delay_import_directory_offset);
|
|
|
|
if (curr_delay_import_dir->Attributes == 0) {
|
|
dll_name_offset = bin_pe_rva_to_paddr(bin,
|
|
curr_delay_import_dir->Name - PE_(r_bin_pe_get_image_base)(bin));
|
|
import_func_name_offset = curr_delay_import_dir->DelayImportNameTable -
|
|
PE_(r_bin_pe_get_image_base)(bin);
|
|
} else {
|
|
dll_name_offset = bin_pe_rva_to_paddr(bin, curr_delay_import_dir->Name);
|
|
import_func_name_offset = curr_delay_import_dir->DelayImportNameTable;
|
|
}
|
|
|
|
while ((curr_delay_import_dir->Name != 0) && (curr_delay_import_dir->DelayImportAddressTable !=0)) {
|
|
if (dll_name_offset > bin->size || dll_name_offset + PE_NAME_LENGTH > bin->size) {
|
|
return NULL;
|
|
}
|
|
int rr = r_buf_read_at (bin->b, dll_name_offset, (ut8*)dll_name, PE_NAME_LENGTH);
|
|
if (rr < 5) {
|
|
eprintf ("Warning: read (magic)\n");
|
|
return NULL;
|
|
}
|
|
|
|
dll_name[PE_NAME_LENGTH] = '\0';
|
|
if (!bin_pe_parse_imports (bin, &imports, &nimp, dll_name,
|
|
import_func_name_offset,
|
|
curr_delay_import_dir->DelayImportAddressTable))
|
|
break;
|
|
curr_delay_import_dir++;
|
|
}
|
|
}
|
|
|
|
if (nimp) {
|
|
imps = realloc (imports, (nimp + 1) * sizeof(struct r_bin_pe_import_t));
|
|
if (!imps) {
|
|
r_sys_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) {
|
|
if (!bin) return NULL;
|
|
struct r_bin_pe_lib_t *libs = NULL;
|
|
PE_(image_import_directory) *curr_import_dir = NULL;
|
|
PE_(image_delay_import_directory) *curr_delay_import_dir = NULL;
|
|
PE_DWord name_off = 0;
|
|
int index = 0;
|
|
int len = 0;
|
|
int max_libs = 20;
|
|
libs = calloc (max_libs+1, sizeof(struct r_bin_pe_lib_t));
|
|
if (!libs) {
|
|
r_sys_perror ("malloc (libs)");
|
|
return NULL;
|
|
}
|
|
|
|
if (bin->import_directory_offset + bin->import_directory_size > bin->b->length) {
|
|
eprintf ("import directory offset bigger than file\n");
|
|
bin->import_directory_size = bin->b->length - bin->import_directory_offset;
|
|
//return NULL;
|
|
}
|
|
RStrHT *lib_map = r_strht_new();
|
|
if (bin->import_directory_offset < bin->size && bin->import_directory_offset > 0) {
|
|
void *last = NULL;
|
|
// normal imports
|
|
curr_import_dir = (PE_(image_import_directory)*)(
|
|
bin->b->buf + bin->import_directory_offset);
|
|
if (bin->import_directory_offset+bin->import_directory_size > bin->b->length) {
|
|
// chop
|
|
bin->import_directory_size = bin->b->length - bin->import_directory_offset;
|
|
eprintf ("Warning: read libs (import directory too big) %d %d size %d\n",
|
|
(int)bin->import_directory_offset, (int)bin->import_directory_size,
|
|
(int)bin->b->length);
|
|
//return NULL;
|
|
}
|
|
last = (char *)curr_import_dir + bin->import_directory_size;
|
|
while ((void*)(curr_import_dir+1) <= last && (
|
|
curr_import_dir->FirstThunk != 0 || curr_import_dir->Name != 0 ||
|
|
curr_import_dir->TimeDateStamp != 0 || curr_import_dir->Characteristics != 0 ||
|
|
curr_import_dir->ForwarderChain != 0)) {
|
|
name_off = bin_pe_rva_to_paddr(bin, curr_import_dir->Name);
|
|
len = r_buf_read_at (bin->b, name_off, (ut8*)libs[index].name, PE_STRING_LENGTH);
|
|
if (libs[index].name[0] == 0) { // minimum string length
|
|
goto next;
|
|
}
|
|
if (len <2 || libs[index].name[0] == 0) { // minimum string length
|
|
eprintf ("Warning: read (libs - import dirs) %d\n", len);
|
|
break;
|
|
}
|
|
libs[index].name[len-1] = '\0';
|
|
r_str_case (libs[index].name, 0);
|
|
if (r_strht_get (lib_map, libs[index].name) == NULL) {
|
|
r_strht_set (lib_map, libs[index].name, "a");
|
|
libs[index++].last = 0;
|
|
if (index >= max_libs) {
|
|
libs = realloc (libs, (max_libs * 2) * sizeof (struct r_bin_pe_lib_t));
|
|
if (!libs) {
|
|
r_sys_perror ("realloc (libs)");
|
|
r_strht_free (lib_map);
|
|
return NULL;
|
|
}
|
|
max_libs *= 2;
|
|
}
|
|
}
|
|
next:
|
|
curr_import_dir++;
|
|
}
|
|
}
|
|
|
|
if (bin->delay_import_directory_offset < bin->size && bin->delay_import_directory_offset > 0) {
|
|
curr_delay_import_dir = (PE_(image_delay_import_directory)*)(
|
|
bin->b->buf + bin->delay_import_directory_offset);
|
|
while (curr_delay_import_dir->Name != 0 && curr_delay_import_dir->DelayImportNameTable != 0) {
|
|
name_off = bin_pe_rva_to_paddr(bin, curr_delay_import_dir->Name);
|
|
len = r_buf_read_at (bin->b, name_off, (ut8*)libs[index].name, PE_STRING_LENGTH);
|
|
if (len != PE_STRING_LENGTH) {
|
|
eprintf ("Warning: read (libs - delay import dirs)\n");
|
|
break;
|
|
}
|
|
libs[index].name[len-1] = '\0';
|
|
r_str_case (libs[index].name, 0);
|
|
if (r_strht_get (lib_map, libs[index].name) == NULL) {
|
|
r_strht_set (lib_map, libs[index].name, "a");
|
|
libs[index++].last = 0;
|
|
if (index >= max_libs) {
|
|
libs = realloc (libs, (max_libs * 2) * sizeof (struct r_bin_pe_lib_t));
|
|
if (!libs) {
|
|
r_strht_free (lib_map);
|
|
r_sys_perror ("realloc (libs)");
|
|
return NULL;
|
|
}
|
|
max_libs *= 2;
|
|
}
|
|
}
|
|
curr_delay_import_dir++;
|
|
if ((const ut8*)(curr_delay_import_dir+1) >= (const ut8*)(bin->b->buf+bin->size)) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
r_strht_free (lib_map);
|
|
libs[index].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 = NULL;
|
|
|
|
if (bin && bin->nt_headers)
|
|
switch (bin->nt_headers->file_header.Machine) {
|
|
case PE_IMAGE_FILE_MACHINE_ALPHA: machine = "Alpha"; break;
|
|
case PE_IMAGE_FILE_MACHINE_ALPHA64: machine = "Alpha 64"; break;
|
|
case PE_IMAGE_FILE_MACHINE_AM33: machine = "AM33"; break;
|
|
case PE_IMAGE_FILE_MACHINE_AMD64: machine = "AMD 64"; break;
|
|
case PE_IMAGE_FILE_MACHINE_ARM: machine = "ARM"; break;
|
|
case PE_IMAGE_FILE_MACHINE_CEE: machine = "CEE"; break;
|
|
case PE_IMAGE_FILE_MACHINE_CEF: machine = "CEF"; break;
|
|
case PE_IMAGE_FILE_MACHINE_EBC: machine = "EBC"; break;
|
|
case PE_IMAGE_FILE_MACHINE_I386: machine = "i386"; break;
|
|
case PE_IMAGE_FILE_MACHINE_IA64: machine = "ia64"; break;
|
|
case PE_IMAGE_FILE_MACHINE_M32R: machine = "M32R"; break;
|
|
case PE_IMAGE_FILE_MACHINE_M68K: machine = "M68K"; break;
|
|
case PE_IMAGE_FILE_MACHINE_MIPS16: machine = "Mips 16"; break;
|
|
case PE_IMAGE_FILE_MACHINE_MIPSFPU: machine = "Mips FPU"; break;
|
|
case PE_IMAGE_FILE_MACHINE_MIPSFPU16: machine = "Mips FPU 16"; break;
|
|
case PE_IMAGE_FILE_MACHINE_POWERPC: machine = "PowerPC"; break;
|
|
case PE_IMAGE_FILE_MACHINE_POWERPCFP: machine = "PowerPC FP"; break;
|
|
case PE_IMAGE_FILE_MACHINE_R10000: machine = "R10000"; break;
|
|
case PE_IMAGE_FILE_MACHINE_R3000: machine = "R3000"; break;
|
|
case PE_IMAGE_FILE_MACHINE_R4000: machine = "R4000"; break;
|
|
case PE_IMAGE_FILE_MACHINE_SH3: machine = "SH3"; break;
|
|
case PE_IMAGE_FILE_MACHINE_SH3DSP: machine = "SH3DSP"; break;
|
|
case PE_IMAGE_FILE_MACHINE_SH3E: machine = "SH3E"; break;
|
|
case PE_IMAGE_FILE_MACHINE_SH4: machine = "SH4"; break;
|
|
case PE_IMAGE_FILE_MACHINE_SH5: machine = "SH5"; break;
|
|
case PE_IMAGE_FILE_MACHINE_THUMB: machine = "Thumb"; break;
|
|
case PE_IMAGE_FILE_MACHINE_TRICORE: machine = "Tricore"; break;
|
|
case PE_IMAGE_FILE_MACHINE_WCEMIPSV2: machine = "WCE Mips V2"; break;
|
|
default: machine = "unknown";
|
|
}
|
|
return machine? strdup (machine): NULL;
|
|
}
|
|
|
|
// TODO: make it const! like in elf
|
|
char* PE_(r_bin_pe_get_os)(struct PE_(r_bin_pe_obj_t)* bin) {
|
|
char *os;
|
|
if (!bin || !bin->nt_headers)
|
|
return NULL;
|
|
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) {
|
|
if (bin && bin->nt_headers)
|
|
switch (bin->nt_headers->optional_header.Magic) {
|
|
case PE_IMAGE_FILE_TYPE_PE32: return strdup("PE32");
|
|
case PE_IMAGE_FILE_TYPE_PE32PLUS: return strdup("PE32+");
|
|
default: return strdup("Unknown");
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
int PE_(r_bin_pe_get_bits)(struct PE_(r_bin_pe_obj_t)* bin) {
|
|
int bits = 32;
|
|
if (bin && bin->nt_headers) {
|
|
if (is_arm (bin)) {
|
|
if (is_thumb (bin)) {
|
|
bits = 16;
|
|
}
|
|
} else {
|
|
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) {
|
|
if (!bin || !bin->nt_headers)
|
|
return 0;
|
|
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;
|
|
int i, sections_count;
|
|
|
|
if (!bin || !bin->nt_headers)
|
|
return NULL;
|
|
shdr = bin->section_header;
|
|
sections_count = bin->nt_headers->file_header.NumberOfSections;
|
|
if (sections_count == 0xffff)
|
|
sections_count = 16; // hackaround for 65k sections file
|
|
sections = calloc (sections_count + 1, sizeof (struct r_bin_pe_section_t));
|
|
if (!sections) {
|
|
r_sys_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].vaddr = shdr[i].VirtualAddress;
|
|
sections[i].size = shdr[i].SizeOfRawData;
|
|
sections[i].vsize = shdr[i].Misc.VirtualSize;
|
|
sections[i].paddr = 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 = NULL;
|
|
if (bin && bin->nt_headers)
|
|
switch (bin->nt_headers->optional_header.Subsystem) {
|
|
case PE_IMAGE_SUBSYSTEM_NATIVE:
|
|
subsystem = "Native"; break;
|
|
case PE_IMAGE_SUBSYSTEM_WINDOWS_GUI:
|
|
subsystem = "Windows GUI"; break;
|
|
case PE_IMAGE_SUBSYSTEM_WINDOWS_CUI:
|
|
subsystem = "Windows CUI"; break;
|
|
case PE_IMAGE_SUBSYSTEM_POSIX_CUI:
|
|
subsystem = "POSIX CUI"; break;
|
|
case PE_IMAGE_SUBSYSTEM_WINDOWS_CE_GUI:
|
|
subsystem = "Windows CE GUI"; break;
|
|
case PE_IMAGE_SUBSYSTEM_EFI_APPLICATION:
|
|
subsystem = "EFI Application"; break;
|
|
case PE_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER:
|
|
subsystem = "EFI Boot Service Driver"; break;
|
|
case PE_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER:
|
|
subsystem = "EFI Runtime Driver"; break;
|
|
case PE_IMAGE_SUBSYSTEM_EFI_ROM:
|
|
subsystem = "EFI ROM"; break;
|
|
case PE_IMAGE_SUBSYSTEM_XBOX:
|
|
subsystem = "XBOX"; break;
|
|
default: subsystem = "Unknown";
|
|
}
|
|
return subsystem? strdup (subsystem): NULL;
|
|
}
|
|
|
|
#define HASCHR(x) bin->nt_headers->file_header.Characteristics & x
|
|
|
|
int PE_(r_bin_pe_is_dll)(struct PE_(r_bin_pe_obj_t)* bin) {
|
|
if (!bin || !bin->nt_headers)
|
|
return false;
|
|
return HASCHR (PE_IMAGE_FILE_DLL);
|
|
}
|
|
|
|
int PE_(r_bin_pe_is_pie)(struct PE_(r_bin_pe_obj_t)* bin) {
|
|
if (!bin || !bin->nt_headers)
|
|
return false;
|
|
return HASCHR (IMAGE_DLL_CHARACTERISTICS_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) {
|
|
ut16 arch;
|
|
if (!bin || !bin->nt_headers)
|
|
return false;
|
|
arch = bin->nt_headers->file_header.Machine;
|
|
if (arch == PE_IMAGE_FILE_MACHINE_I386 ||
|
|
arch == PE_IMAGE_FILE_MACHINE_AMD64) return false;
|
|
return HASCHR (PE_IMAGE_FILE_BYTES_REVERSED_HI);
|
|
}
|
|
|
|
int PE_(r_bin_pe_is_stripped_relocs)(struct PE_(r_bin_pe_obj_t)* bin) {
|
|
if (!bin || !bin->nt_headers)
|
|
return false;
|
|
return HASCHR (PE_IMAGE_FILE_RELOCS_STRIPPED);
|
|
}
|
|
|
|
int PE_(r_bin_pe_is_stripped_line_nums)(struct PE_(r_bin_pe_obj_t)* bin) {
|
|
if (!bin || !bin->nt_headers)
|
|
return false;
|
|
return HASCHR (PE_IMAGE_FILE_LINE_NUMS_STRIPPED);
|
|
}
|
|
|
|
int PE_(r_bin_pe_is_stripped_local_syms)(struct PE_(r_bin_pe_obj_t)* bin) {
|
|
if (!bin || !bin->nt_headers)
|
|
return false;
|
|
return HASCHR (PE_IMAGE_FILE_LOCAL_SYMS_STRIPPED);
|
|
}
|
|
|
|
int PE_(r_bin_pe_is_stripped_debug)(struct PE_(r_bin_pe_obj_t)* bin) {
|
|
if (!bin || !bin->nt_headers)
|
|
return false;
|
|
return HASCHR (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->resource_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)) {
|
|
free (buf);
|
|
return PE_(r_bin_pe_free)(bin);
|
|
}
|
|
free (buf);
|
|
if (!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->kv = sdb_new0 ();
|
|
bin->b = r_buf_new ();
|
|
bin->size = buf->length;
|
|
if (!r_buf_set_bytes (bin->b, buf->buf, bin->size)){
|
|
return PE_(r_bin_pe_free)(bin);
|
|
}
|
|
if (!bin_pe_init(bin))
|
|
return PE_(r_bin_pe_free)(bin);
|
|
return bin;
|
|
}
|