1/* radare - LGPL - Copyright 2009-2019 - nibble, pancake, alvarofe */ 2 3#include <r_types.h> 4#include <r_util.h> 5#include <r_lib.h> 6#include <r_bin.h> 7#include "../i/private.h" 8#include "pe/pe.h" 9 10static Sdb* get_sdb (RBinFile *bf) { 11 RBinObject *o = bf->o; 12 struct PE_(r_bin_pe_obj_t) *bin; 13 if (!o || !o->bin_obj) { 14 return NULL; 15 } 16 bin = (struct PE_(r_bin_pe_obj_t) *) o->bin_obj; 17 return bin? bin->kv: NULL; 18} 19 20static bool load_buffer(RBinFile *bf, void **bin_obj, RBuffer *buf, ut64 loadaddr, Sdb *sdb) { 21 r_return_val_if_fail (bf && bin_obj && buf, false); 22 struct PE_(r_bin_pe_obj_t) *res = PE_(r_bin_pe_new_buf) (buf, bf->rbin->verbose); 23 if (res) { 24 sdb_ns_set (sdb, "info", res->kv); 25 *bin_obj = res; 26 return true; 27 } 28 return false; 29} 30 31static void destroy(RBinFile *bf) { 32 PE_(r_bin_pe_free) ((struct PE_(r_bin_pe_obj_t)*)bf->o->bin_obj); 33} 34 35static ut64 baddr(RBinFile *bf) { 36 return PE_(r_bin_pe_get_image_base) (bf->o->bin_obj); 37} 38 39static RBinAddr* binsym(RBinFile *bf, int type) { 40 struct r_bin_pe_addr_t *peaddr = NULL; 41 RBinAddr *ret = NULL; 42 if (bf && bf->o && bf->o->bin_obj) { 43 switch (type) { 44 case R_BIN_SYM_MAIN: 45 peaddr = PE_(r_bin_pe_get_main_vaddr) (bf->o->bin_obj); 46 break; 47 } 48 } 49 if (peaddr && (ret = R_NEW0 (RBinAddr))) { 50 ret->paddr = peaddr->paddr; 51 ret->vaddr = peaddr->vaddr; 52 } 53 free (peaddr); 54 return ret; 55} 56 57static void add_tls_callbacks(RBinFile *bf, RList* list) { 58 PE_DWord paddr, vaddr, haddr; 59 int count = 0; 60 RBinAddr *ptr = NULL; 61 struct PE_(r_bin_pe_obj_t) *bin = (struct PE_(r_bin_pe_obj_t) *) (bf->o->bin_obj); 62 char *key; 63 64 do { 65 key = sdb_fmt ("pe.tls_callback%d_paddr", count); 66 paddr = sdb_num_get (bin->kv, key, 0); 67 if (!paddr) { 68 break; 69 } 70 71 key = sdb_fmt ("pe.tls_callback%d_vaddr", count); 72 vaddr = sdb_num_get (bin->kv, key, 0); 73 if (!vaddr) { 74 break; 75 } 76 77 key = sdb_fmt ("pe.tls_callback%d_haddr", count); 78 haddr = sdb_num_get (bin->kv, key, 0); 79 if (!haddr) { 80 break; 81 } 82 if ((ptr = R_NEW0 (RBinAddr))) { 83 ptr->paddr = paddr; 84 ptr->vaddr = vaddr; 85 ptr->hpaddr = haddr; 86 ptr->type = R_BIN_ENTRY_TYPE_TLS; 87 r_list_append (list, ptr); 88 } 89 count++; 90 } while (vaddr); 91} 92 93static RList* entries(RBinFile *bf) { 94 struct r_bin_pe_addr_t *entry = NULL; 95 RBinAddr *ptr = NULL; 96 RList* ret; 97 98 if (!(ret = r_list_newf (free))) { 99 return NULL; 100 } 101 if (!(entry = PE_(r_bin_pe_get_entrypoint) (bf->o->bin_obj))) { 102 return ret; 103 } 104 if ((ptr = R_NEW0 (RBinAddr))) { 105 ptr->paddr = entry->paddr; 106 ptr->vaddr = entry->vaddr; 107 ptr->hpaddr = entry->haddr; 108 ptr->type = R_BIN_ENTRY_TYPE_PROGRAM; 109 r_list_append (ret, ptr); 110 } 111 free (entry); 112 // get TLS callback addresses 113 add_tls_callbacks (bf, ret); 114 115 return ret; 116} 117 118static RList* sections(RBinFile *bf) { 119 RList *ret = NULL; 120 RBinSection *ptr = NULL; 121 struct r_bin_pe_section_t *sections = NULL; 122 struct PE_(r_bin_pe_obj_t) *bin = (struct PE_(r_bin_pe_obj_t)*)bf->o->bin_obj; 123 ut64 ba = baddr (bf); 124 int i; 125 if (!(ret = r_list_newf ((RListFree)r_bin_section_free))) { 126 return NULL; 127 } 128 if (!bin || !(sections = bin->sections)){ 129 r_list_free (ret); 130 return NULL; 131 } 132 PE_(r_bin_pe_check_sections) (bin, §ions); 133 for (i = 0; !sections[i].last; i++) { 134 if (!(ptr = R_NEW0 (RBinSection))) { 135 break; 136 } 137 if (sections[i].name[0]) { 138 ptr->name = strdup ((char*)sections[i].name); 139 } else { 140 ptr->name = strdup (""); 141 } 142 ptr->size = sections[i].size; 143 if (ptr->size > bin->size) { 144 if (sections[i].vsize < bin->size) { 145 ptr->size = sections[i].vsize; 146 } else { 147 //hack give it page size 148 ptr->size = 4096; 149 } 150 } 151 ptr->vsize = sections[i].vsize; 152 if (!ptr->vsize && ptr->size) { 153 ptr->vsize = ptr->size; 154 } 155 ptr->paddr = sections[i].paddr; 156 ptr->vaddr = sections[i].vaddr + ba; 157 ptr->add = true; 158 ptr->perm = 0; 159 if (R_BIN_PE_SCN_IS_EXECUTABLE (sections[i].perm)) { 160 ptr->perm |= R_PERM_X; 161 ptr->perm |= R_PERM_R; // implicit 162 } 163 if (R_BIN_PE_SCN_IS_WRITABLE (sections[i].perm)) { 164 ptr->perm |= R_PERM_W; 165 } 166 if (R_BIN_PE_SCN_IS_READABLE (sections[i].perm)) { 167 ptr->perm |= R_PERM_R; 168 } 169 // this is causing may tests to fail because rx != srx 170 if (R_BIN_PE_SCN_IS_SHAREABLE (sections[i].perm)) { 171 ptr->perm |= R_PERM_SHAR; 172 } 173 if ((ptr->perm & R_PERM_RW) && !(ptr->perm & R_PERM_X) && ptr->size > 0) { 174 if (!strcmp (ptr->name, ".rsrc") || 175 !strcmp (ptr->name, ".data") || 176 !strcmp (ptr->name, ".rdata")) { 177 ptr->is_data = true; 178 } 179 } 180 r_list_append (ret, ptr); 181 } 182 return ret; 183} 184 185static void find_pe_overlay(RBinFile *bf) { 186 ut64 pe_overlay_size; 187 ut64 pe_overlay_offset = PE_(bin_pe_get_overlay) (bf->o->bin_obj, &pe_overlay_size); 188 if (pe_overlay_offset) { 189 sdb_num_set (bf->sdb, "pe_overlay.offset", pe_overlay_offset, 0); 190 sdb_num_set (bf->sdb, "pe_overlay.size", pe_overlay_size, 0); 191 } 192} 193 194static RList* symbols(RBinFile *bf) { 195 RList *ret = NULL; 196 RBinSymbol *ptr = NULL; 197 struct r_bin_pe_export_t *symbols = NULL; 198 struct r_bin_pe_import_t *imports = NULL; 199 int i; 200 201 if (!(ret = r_list_newf (free))) { 202 return NULL; 203 } 204 if ((symbols = PE_(r_bin_pe_get_exports)(bf->o->bin_obj))) { 205 for (i = 0; !symbols[i].last; i++) { 206 if (!(ptr = R_NEW0 (RBinSymbol))) { 207 break; 208 } 209 ptr->name = strdup ((char *)symbols[i].name); 210 ptr->libname = *symbols[i].libname ? strdup ((char *)symbols[i].libname) : NULL; 211 ptr->forwarder = r_str_constpool_get (&bf->rbin->constpool, (char *)symbols[i].forwarder); 212 //strncpy (ptr->bind, "NONE", R_BIN_SIZEOF_STRINGS); 213 ptr->bind = R_BIN_BIND_GLOBAL_STR; 214 ptr->type = R_BIN_TYPE_FUNC_STR; 215 ptr->size = 0; 216 ptr->vaddr = symbols[i].vaddr; 217 ptr->paddr = symbols[i].paddr; 218 ptr->ordinal = symbols[i].ordinal; 219 r_list_append (ret, ptr); 220 } 221 free (symbols); 222 } 223 224 225 if ((imports = PE_(r_bin_pe_get_imports)(bf->o->bin_obj))) { 226 for (i = 0; !imports[i].last; i++) { 227 if (!(ptr = R_NEW0 (RBinSymbol))) { 228 break; 229 } 230 //strncpy (ptr->name, (char*)symbols[i].name, R_BIN_SIZEOF_STRINGS); 231 ptr->name = strdup ((const char *)imports[i].name); 232 ptr->libname = strdup ((const char *)imports[i].libname); 233 ptr->is_imported = true; 234 //strncpy (ptr->forwarder, (char*)imports[i].forwarder, R_BIN_SIZEOF_STRINGS); 235 ptr->bind = "NONE"; 236 ptr->type = R_BIN_TYPE_FUNC_STR; 237 ptr->size = 0; 238 ptr->vaddr = imports[i].vaddr; 239 ptr->paddr = imports[i].paddr; 240 ptr->ordinal = imports[i].ordinal; 241 r_list_append (ret, ptr); 242 } 243 free (imports); 244 } 245 find_pe_overlay(bf); 246 return ret; 247} 248 249static void filter_import(ut8 *n) { 250 int I; 251 for (I = 0; n[I]; I++) { 252 if (n[I] < 30 || n[I] >= 0x7f) { 253 n[I] = 0; 254 break; 255 } 256 } 257} 258 259static RList* imports(RBinFile *bf) { 260 RList *ret = NULL, *relocs = NULL; 261 RBinImport *ptr = NULL; 262 RBinReloc *rel = NULL; 263 struct r_bin_pe_import_t *imports = NULL; 264 int i; 265 266 if (!bf || !bf->o || !bf->o->bin_obj) { 267 return NULL; 268 } 269 if (!(ret = r_list_newf (r_bin_import_free))) { 270 return NULL; 271 } 272 273 // XXX: has_canary is causing problems! thus we need to check and clean here until it is fixed! 274 if (((struct PE_(r_bin_pe_obj_t)*)bf->o->bin_obj)->relocs) { 275 r_list_free (((struct PE_(r_bin_pe_obj_t)*)bf->o->bin_obj)->relocs); 276 } 277 278 if (!(relocs = r_list_newf (free))) { 279 free (ret); 280 return NULL; 281 } 282 ((struct PE_(r_bin_pe_obj_t)*)bf->o->bin_obj)->relocs = relocs; 283 284 if (!(imports = PE_(r_bin_pe_get_imports)(bf->o->bin_obj))) { 285 return ret; 286 } 287 for (i = 0; !imports[i].last; i++) { 288 if (!(ptr = R_NEW0 (RBinImport))) { 289 break; 290 } 291 filter_import (imports[i].name); 292 ptr->name = strdup ((char*)imports[i].name); 293 ptr->libname = strdup ((char*)imports[i].libname); 294 ptr->bind = "NONE"; 295 ptr->type = "FUNC"; 296 ptr->ordinal = imports[i].ordinal; 297 // NOTE(eddyb) a PE hint is just an optional possible DLL export table 298 // index for the import. There is no point in exposing it. 299 //ptr->hint = imports[i].hint; 300 r_list_append (ret, ptr); 301 302 if (!(rel = R_NEW0 (RBinReloc))) { 303 break; 304 } 305#ifdef R_BIN_PE64 306 rel->type = R_BIN_RELOC_64; 307#else 308 rel->type = R_BIN_RELOC_32; 309#endif 310 rel->additive = 0; 311 rel->import = ptr; 312 rel->addend = 0; 313 { 314 ut8 addr[4]; 315 r_buf_read_at (bf->buf, imports[i].paddr, addr, 4); 316 ut64 newaddr = (ut64) r_read_le32 (&addr); 317 rel->vaddr = newaddr; 318 } 319 rel->paddr = imports[i].paddr; 320 r_list_append (relocs, rel); 321 } 322 free (imports); 323 return ret; 324} 325 326static RList* relocs(RBinFile *bf) { 327 struct PE_(r_bin_pe_obj_t)* obj= bf->o->bin_obj; 328 if (obj) { 329 return obj->relocs; 330 } 331 return NULL; 332} 333 334static RList* libs(RBinFile *bf) { 335 struct r_bin_pe_lib_t *libs = NULL; 336 RList *ret = NULL; 337 char *ptr = NULL; 338 int i; 339 340 if (!(ret = r_list_new ())) { 341 return NULL; 342 } 343 ret->free = free; 344 if (!(libs = PE_(r_bin_pe_get_libs)(bf->o->bin_obj))) { 345 return ret; 346 } 347 for (i = 0; !libs[i].last; i++) { 348 ptr = strdup (libs[i].name); 349 r_list_append (ret, ptr); 350 } 351 free (libs); 352 return ret; 353} 354 355static int is_dot_net(RBinFile *bf) { 356 struct r_bin_pe_lib_t *libs = NULL; 357 int i; 358 if (!(libs = PE_(r_bin_pe_get_libs)(bf->o->bin_obj))) { 359 return false; 360 } 361 for (i = 0; !libs[i].last; i++) { 362 if (!strcmp (libs[i].name, "mscoree.dll")) { 363 free (libs); 364 return true; 365 } 366 } 367 free (libs); 368 return false; 369} 370 371static int is_vb6(RBinFile *bf) { 372 struct r_bin_pe_lib_t *libs = NULL; 373 int i; 374 if (!(libs = PE_(r_bin_pe_get_libs)(bf->o->bin_obj))) { 375 return false; 376 } 377 for (i = 0; !libs[i].last; i++) { 378 if (!strcmp (libs[i].name, "msvbvm60.dll")) { 379 free (libs); 380 return true; 381 } 382 } 383 free (libs); 384 return false; 385} 386 387static int has_canary(RBinFile *bf) { 388 // XXX: We only need imports here but this causes leaks, we need to wait for the below. This is a horrible solution! 389 // TODO: use O(1) when imports sdbized 390 RListIter *iter; 391 struct PE_ (r_bin_pe_obj_t) *bin = bf->o->bin_obj; 392 if (bin) { 393 const RList* relocs_list = bin->relocs; 394 RBinReloc *rel; 395 if (relocs_list) { 396 r_list_foreach (relocs_list, iter, rel) { 397 if (!strcmp (rel->import->name, "__security_init_cookie")) { 398 return true; 399 } 400 } 401 } 402 } else { // rabin2 needs this as it will not initialise bin 403 const RList* imports_list = imports (bf); 404 RBinImport *imp; 405 if (imports_list) { 406 r_list_foreach (imports_list, iter, imp) { 407 if (!strcmp (imp->name, "__security_init_cookie")) { 408 return true; 409 } 410 } 411 } 412 } 413 return false; 414} 415 416static int haschr(const RBinFile* bf, ut16 dllCharacteristic) { 417 const ut8 *buf; 418 unsigned int idx; 419 ut64 sz; 420 if (!bf) { 421 return false; 422 } 423 buf = r_buf_data (bf->buf, &sz); 424 if (!buf) { 425 return false; 426 } 427 idx = (buf[0x3c] | (buf[0x3d]<<8)); 428 if (idx + 0x5E + 1 >= sz ) { 429 return false; 430 } 431 //it's funny here idx+0x5E can be 158 and sz 159 but with 432 //the cast it reads two bytes until 160 433 return ((*(ut16*)(buf + idx + 0x5E)) & dllCharacteristic); 434} 435 436static RBinInfo* info(RBinFile *bf) { 437 struct PE_ (r_bin_pe_obj_t) *bin; 438 SDebugInfo di = {{0}}; 439 RBinInfo *ret = R_NEW0 (RBinInfo); 440 ut32 claimed_checksum, actual_checksum, pe_overlay; 441 442 if (!ret) { 443 return NULL; 444 } 445 bin = bf->o->bin_obj; 446 ret->file = strdup (bf->file); 447 ret->bclass = PE_(r_bin_pe_get_class) (bf->o->bin_obj); 448 ret->rclass = strdup ("pe"); 449 ret->os = PE_(r_bin_pe_get_os) (bf->o->bin_obj); 450 ret->arch = PE_(r_bin_pe_get_arch) (bf->o->bin_obj); 451 ret->machine = PE_(r_bin_pe_get_machine) (bf->o->bin_obj); 452 ret->subsystem = PE_(r_bin_pe_get_subsystem) (bf->o->bin_obj); 453 ret->default_cc = PE_(r_bin_pe_get_cc) (bf->o->bin_obj); 454 if (is_dot_net (bf)) { 455 ret->lang = "cil"; 456 } 457 if (is_vb6 (bf)) { 458 ret->lang = "vb"; 459 } 460 if (PE_(r_bin_pe_is_dll) (bf->o->bin_obj)) { 461 ret->type = strdup ("DLL (Dynamic Link Library)"); 462 } else { 463 ret->type = strdup ("EXEC (Executable file)"); 464 } 465 claimed_checksum = PE_(bin_pe_get_claimed_checksum) (bf->o->bin_obj); 466 actual_checksum = PE_(bin_pe_get_actual_checksum) (bf->o->bin_obj); 467 pe_overlay = sdb_num_get (bf->sdb, "pe_overlay.size", 0); 468 ret->bits = PE_(r_bin_pe_get_bits) (bf->o->bin_obj); 469 ret->big_endian = PE_(r_bin_pe_is_big_endian) (bf->o->bin_obj); 470 ret->dbg_info = 0; 471 ret->has_lit = true; 472 ret->has_canary = has_canary (bf); 473 ret->has_nx = haschr (bf, IMAGE_DLL_CHARACTERISTICS_NX_COMPAT); 474 ret->has_pi = haschr (bf, IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE); 475 ret->claimed_checksum = strdup (sdb_fmt ("0x%08x", claimed_checksum)); 476 ret->actual_checksum = strdup (sdb_fmt ("0x%08x", actual_checksum)); 477 ret->pe_overlay = pe_overlay > 0; 478 ret->signature = bin ? bin->is_signed : false; 479 ret->file_hashes = r_list_newf ((RListFree) r_bin_file_hash_free); 480 Sdb *db = sdb_ns (bf->sdb, "pe", true); 481 sdb_bool_set (db, "canary", has_canary (bf), 0); 482 sdb_bool_set (db, "highva", haschr (bf, IMAGE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA), 0); 483 sdb_bool_set (db, "aslr", haschr (bf, IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE), 0); 484 sdb_bool_set (db, "forceintegrity", haschr (bf, IMAGE_DLL_CHARACTERISTICS_FORCE_INTEGRITY), 0); 485 sdb_bool_set (db, "nx", haschr (bf, IMAGE_DLL_CHARACTERISTICS_NX_COMPAT), 0); 486 sdb_bool_set (db, "isolation", !haschr (bf, IMAGE_DLL_CHARACTERISTICS_FORCE_INTEGRITY), 0); 487 sdb_bool_set (db, "seh", !haschr (bf, IMAGE_DLLCHARACTERISTICS_NO_SEH), 0); 488 sdb_bool_set (db, "bind", !haschr (bf, IMAGE_DLLCHARACTERISTICS_NO_BIND), 0); 489 sdb_bool_set (db, "appcontainer", haschr (bf, IMAGE_DLLCHARACTERISTICS_APPCONTAINER), 0); 490 sdb_bool_set (db, "wdmdriver", haschr (bf, IMAGE_DLLCHARACTERISTICS_WDM_DRIVER), 0); 491 sdb_bool_set (db, "guardcf", haschr (bf, IMAGE_DLLCHARACTERISTICS_GUARD_CF), 0); 492 sdb_bool_set (db, "terminalserveraware", haschr (bf, IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE), 0); 493 sdb_num_set (db, "bits", ret->bits, 0); 494 sdb_set (db, "claimed_checksum", ret->claimed_checksum, 0); 495 sdb_set (db, "actual_checksum", ret->actual_checksum, 0); 496 sdb_bool_set (db, "is_authhash_valid", PE_(bin_pe_is_authhash_valid) (bf->o->bin_obj), 0); 497 498 ret->has_va = true; 499 500 if (PE_(r_bin_pe_is_stripped_debug) (bf->o->bin_obj)) { 501 ret->dbg_info |= R_BIN_DBG_STRIPPED; 502 } 503 if (PE_(r_bin_pe_is_stripped_line_nums) (bf->o->bin_obj)) { 504 ret->dbg_info |= R_BIN_DBG_LINENUMS; 505 } 506 if (PE_(r_bin_pe_is_stripped_local_syms) (bf->o->bin_obj)) { 507 ret->dbg_info |= R_BIN_DBG_SYMS; 508 } 509 if (PE_(r_bin_pe_is_stripped_relocs) (bf->o->bin_obj)) { 510 ret->dbg_info |= R_BIN_DBG_RELOCS; 511 } 512 if (PE_(r_bin_pe_get_debug_data)(bf->o->bin_obj, &di)) { 513 ret->guid = r_str_ndup (di.guidstr, GUIDSTR_LEN); 514 if (ret->guid) { 515 ret->debug_file_name = r_str_ndup (di.file_name, DBG_FILE_NAME_LEN); 516 if (!ret->debug_file_name) { 517 R_FREE (ret->guid); 518 } 519 } 520 } 521 522 return ret; 523} 524 525static ut64 get_vaddr (RBinFile *bf, ut64 baddr, ut64 paddr, ut64 vaddr) { 526 return baddr + vaddr; 527} 528 529static RList *compute_hashes(RBinFile *bf) { 530 RList *file_hashes = r_list_newf ((RListFree) r_bin_file_hash_free); 531 const char *authentihash = PE_(bin_pe_compute_authentihash) (bf->o->bin_obj); 532 if (authentihash) { 533 RBinFileHash *authhash = R_NEW0 (RBinFileHash); 534 if (authhash) { 535 authhash->type = strdup ("authentihash"); 536 authhash->hex = authentihash; 537 r_list_push (file_hashes, authhash); 538 } 539 } 540 541 return file_hashes; 542} 543