mirror of
https://github.com/radareorg/radare2.git
synced 2025-02-02 19:55:14 +00:00
521 lines
14 KiB
C
521 lines
14 KiB
C
/* radare - LGPL - Copyright 2009-2015 - nibble, pancake */
|
|
|
|
#include <r_types.h>
|
|
#include <r_util.h>
|
|
#include <r_lib.h>
|
|
#include <r_bin.h>
|
|
#include "pe/pe.h"
|
|
|
|
static int check(RBinFile *arch);
|
|
static int check_bytes(const ut8 *buf, ut64 length);
|
|
|
|
static Sdb* get_sdb (RBinObject *o) {
|
|
struct PE_(r_bin_pe_obj_t) *bin;
|
|
if (!o || !o->bin_obj) return NULL;
|
|
bin = (struct PE_(r_bin_pe_obj_t) *) o->bin_obj;
|
|
if (bin && bin->kv) return bin->kv;
|
|
return NULL;
|
|
}
|
|
|
|
static void * load_bytes(RBinFile *arch, const ut8 *buf, ut64 sz, ut64 loadaddr, Sdb *sdb){
|
|
struct PE_(r_bin_pe_obj_t) *res = NULL;
|
|
RBuffer *tbuf = NULL;
|
|
if (!buf || sz == 0 || sz == UT64_MAX) return NULL;
|
|
tbuf = r_buf_new();
|
|
r_buf_set_bytes (tbuf, buf, sz);
|
|
res = PE_(r_bin_pe_new_buf) (tbuf);
|
|
if (res) sdb_ns_set (sdb, "info", res->kv);
|
|
r_buf_free (tbuf);
|
|
return res;
|
|
}
|
|
|
|
static int load(RBinFile *arch) {
|
|
void *res;
|
|
const ut8 *bytes;
|
|
ut64 sz;
|
|
|
|
if (!arch || !arch->o)
|
|
return false;
|
|
|
|
bytes = r_buf_buffer (arch->buf);
|
|
sz = r_buf_size (arch->buf);
|
|
res = load_bytes (arch, bytes, sz, arch->o->loadaddr, arch->sdb);
|
|
arch->o->bin_obj = res;
|
|
return res? true: false;
|
|
}
|
|
|
|
static int destroy(RBinFile *arch) {
|
|
PE_(r_bin_pe_free) ((struct PE_(r_bin_pe_obj_t)*)arch->o->bin_obj);
|
|
return true;
|
|
}
|
|
|
|
static ut64 baddr(RBinFile *arch) {
|
|
return PE_(r_bin_pe_get_image_base) (arch->o->bin_obj);
|
|
}
|
|
|
|
static RBinAddr* binsym(RBinFile *arch, int type) {
|
|
struct r_bin_pe_addr_t *peaddr = NULL;
|
|
RBinAddr *ret = NULL;
|
|
if (arch && arch->o && arch->o->bin_obj)
|
|
switch (type) {
|
|
case R_BIN_SYM_MAIN:
|
|
peaddr = PE_(r_bin_pe_get_main_vaddr) (arch->o->bin_obj);
|
|
break;
|
|
}
|
|
if (peaddr && (ret = R_NEW0 (RBinAddr))) {
|
|
ret->paddr = peaddr->paddr;
|
|
ret->vaddr = peaddr->vaddr;
|
|
}
|
|
free (peaddr);
|
|
return ret;
|
|
}
|
|
|
|
static RList* entries(RBinFile *arch) {
|
|
RList* ret;
|
|
RBinAddr *ptr = NULL;
|
|
struct r_bin_pe_addr_t *entry = NULL;
|
|
|
|
if (!(ret = r_list_new ()))
|
|
return NULL;
|
|
ret->free = free;
|
|
if (!(entry = PE_(r_bin_pe_get_entrypoint) (arch->o->bin_obj)))
|
|
return ret;
|
|
if ((ptr = R_NEW (RBinAddr))) {
|
|
ptr->paddr = entry->paddr;
|
|
ptr->vaddr = entry->vaddr;
|
|
r_list_append (ret, ptr);
|
|
}
|
|
free (entry);
|
|
return ret;
|
|
}
|
|
|
|
static RList* sections(RBinFile *arch) {
|
|
RList *ret = NULL;
|
|
RBinSection *ptr = NULL;
|
|
struct r_bin_pe_section_t *sections = NULL;
|
|
ut64 ba = baddr (arch);
|
|
int i;
|
|
if (!(ret = r_list_new ()))
|
|
return NULL;
|
|
ret->free = free;
|
|
if (!(sections = PE_(r_bin_pe_get_sections)(arch->o->bin_obj))){
|
|
r_list_free (ret);
|
|
return NULL;
|
|
}
|
|
for (i = 0; !sections[i].last; i++) {
|
|
if (!(ptr = R_NEW0 (RBinSection)))
|
|
break;
|
|
if (sections[i].name[0])
|
|
strncpy (ptr->name, (char*)sections[i].name,
|
|
R_BIN_SIZEOF_STRINGS);
|
|
ptr->size = sections[i].size;
|
|
ptr->vsize = sections[i].vsize;
|
|
ptr->paddr = sections[i].paddr;
|
|
ptr->vaddr = sections[i].vaddr + ba;
|
|
ptr->add = true;
|
|
ptr->srwx = R_BIN_SCN_MAP;
|
|
if (R_BIN_PE_SCN_IS_EXECUTABLE (sections[i].flags))
|
|
ptr->srwx |= R_BIN_SCN_EXECUTABLE;
|
|
if (R_BIN_PE_SCN_IS_WRITABLE (sections[i].flags))
|
|
ptr->srwx |= R_BIN_SCN_WRITABLE;
|
|
if (R_BIN_PE_SCN_IS_READABLE (sections[i].flags))
|
|
ptr->srwx |= R_BIN_SCN_READABLE;
|
|
if (R_BIN_PE_SCN_IS_SHAREABLE (sections[i].flags))
|
|
ptr->srwx |= R_BIN_SCN_SHAREABLE;
|
|
r_list_append (ret, ptr);
|
|
}
|
|
free (sections);
|
|
return ret;
|
|
}
|
|
|
|
static RList* symbols(RBinFile *arch) {
|
|
RList *ret = NULL;
|
|
RBinSymbol *ptr = NULL;
|
|
struct r_bin_pe_export_t *symbols = NULL;
|
|
struct r_bin_pe_import_t *imports = NULL;
|
|
int i;
|
|
|
|
if (!(ret = r_list_new ()))
|
|
return NULL;
|
|
ret->free = free;
|
|
if ((symbols = PE_(r_bin_pe_get_exports)(arch->o->bin_obj))) {
|
|
for (i = 0; !symbols[i].last; i++) {
|
|
if (!(ptr = R_NEW0 (RBinSymbol)))
|
|
break;
|
|
ptr->name = strdup ((char *)symbols[i].name);
|
|
ptr->forwarder = r_str_const ((char *)symbols[i].forwarder);
|
|
//strncpy (ptr->bind, "NONE", R_BIN_SIZEOF_STRINGS);
|
|
ptr->bind = r_str_const ("GLOBAL");
|
|
ptr->type = r_str_const ("FUNC");
|
|
ptr->size = 0;
|
|
ptr->vaddr = symbols[i].vaddr;
|
|
ptr->paddr = symbols[i].paddr;
|
|
ptr->ordinal = symbols[i].ordinal;
|
|
r_list_append (ret, ptr);
|
|
}
|
|
free (symbols);
|
|
}
|
|
|
|
if ((imports = PE_(r_bin_pe_get_imports)(arch->o->bin_obj))) {
|
|
for (i = 0; !imports[i].last; i++) {
|
|
if (!(ptr = R_NEW0 (RBinSymbol)))
|
|
break;
|
|
//strncpy (ptr->name, (char*)symbols[i].name, R_BIN_SIZEOF_STRINGS);
|
|
ptr->name = r_str_newf ("imp.%s", imports[i].name);
|
|
//strncpy (ptr->forwarder, (char*)imports[i].forwarder, R_BIN_SIZEOF_STRINGS);
|
|
ptr->bind = r_str_const ("NONE");
|
|
ptr->type = r_str_const ("FUNC");
|
|
ptr->size = 0;
|
|
ptr->vaddr = imports[i].vaddr;
|
|
ptr->paddr = imports[i].paddr;
|
|
ptr->ordinal = imports[i].ordinal;
|
|
r_list_append (ret, ptr);
|
|
}
|
|
free (imports);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
static void filter_import(ut8 *n) {
|
|
int I;
|
|
for (I=0; n[I]; I++) {
|
|
if (n[I]<30 || n[I]>=0x7f) {
|
|
n[I] = 0;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
static RList* imports(RBinFile *arch) {
|
|
RList *ret = NULL, *relocs = NULL;
|
|
RBinImport *ptr = NULL;
|
|
RBinReloc *rel = NULL;
|
|
struct r_bin_pe_import_t *imports = NULL;
|
|
int i;
|
|
|
|
if (!arch || !arch->o || !arch->o->bin_obj)
|
|
return NULL;
|
|
if (!(ret = r_list_new ()) || !(relocs = r_list_new ()))
|
|
return NULL;
|
|
|
|
ret->free = free;
|
|
relocs->free = free;
|
|
|
|
((struct PE_(r_bin_pe_obj_t)*)arch->o->bin_obj)->relocs = relocs;
|
|
|
|
if (!(imports = PE_(r_bin_pe_get_imports)(arch->o->bin_obj)))
|
|
return ret;
|
|
for (i = 0; !imports[i].last; i++) {
|
|
if (!(ptr = R_NEW0 (RBinImport)))
|
|
break;
|
|
filter_import (imports[i].name);
|
|
ptr->name = strdup ((char*)imports[i].name);
|
|
ptr->bind = r_str_const ("NONE");
|
|
ptr->type = r_str_const ("FUNC");
|
|
ptr->ordinal = imports[i].ordinal;
|
|
// NOTE(eddyb) a PE hint is just an optional possible DLL export table
|
|
// index for the import. There is no point in exposing it.
|
|
//ptr->hint = imports[i].hint;
|
|
r_list_append (ret, ptr);
|
|
|
|
if (!(rel = R_NEW0 (RBinReloc)))
|
|
break;
|
|
#ifdef R_BIN_PE64
|
|
rel->type = R_BIN_RELOC_64;
|
|
#else
|
|
rel->type = R_BIN_RELOC_32;
|
|
#endif
|
|
rel->additive = 0;
|
|
rel->import = ptr;
|
|
rel->addend = 0;
|
|
rel->vaddr = imports[i].vaddr;
|
|
rel->paddr = imports[i].paddr;
|
|
r_list_append (relocs, rel);
|
|
}
|
|
free (imports);
|
|
return ret;
|
|
}
|
|
|
|
static RList* relocs(RBinFile *arch) {
|
|
struct PE_(r_bin_pe_obj_t)* obj= arch->o->bin_obj;
|
|
if (obj) return obj->relocs;
|
|
return NULL;
|
|
}
|
|
|
|
static RList* libs(RBinFile *arch) {
|
|
struct r_bin_pe_lib_t *libs = NULL;
|
|
RList *ret = NULL;
|
|
char *ptr = NULL;
|
|
int i;
|
|
|
|
if (!(ret = r_list_new ()))
|
|
return NULL;
|
|
ret->free = free;
|
|
if (!(libs = PE_(r_bin_pe_get_libs)(arch->o->bin_obj)))
|
|
return ret;
|
|
for (i = 0; !libs[i].last; i++) {
|
|
ptr = strdup (libs[i].name);
|
|
r_list_append (ret, ptr);
|
|
}
|
|
free (libs);
|
|
return ret;
|
|
}
|
|
|
|
static int is_dot_net(RBinFile *arch) {
|
|
struct r_bin_pe_lib_t *libs = NULL;
|
|
int i;
|
|
if (!(libs = PE_(r_bin_pe_get_libs)(arch->o->bin_obj)))
|
|
return false;
|
|
for (i = 0; !libs[i].last; i++) {
|
|
if (!strcmp (libs[i].name, "mscoree.dll")) {
|
|
free (libs);
|
|
return true;
|
|
}
|
|
}
|
|
free (libs);
|
|
return false;
|
|
}
|
|
|
|
static int is_vb6(RBinFile *arch) {
|
|
struct r_bin_pe_lib_t *libs = NULL;
|
|
int i;
|
|
if (!(libs = PE_(r_bin_pe_get_libs)(arch->o->bin_obj)))
|
|
return false;
|
|
for (i = 0; !libs[i].last; i++) {
|
|
if (!strcmp (libs[i].name, "msvbvm60.dll")) {
|
|
free (libs);
|
|
return true;
|
|
}
|
|
}
|
|
free (libs);
|
|
return false;
|
|
}
|
|
|
|
static int has_canary(RBinFile *arch) {
|
|
const RList* imports_list = imports (arch);
|
|
RListIter *iter;
|
|
RBinImport *import;
|
|
// TODO: use O(1) when imports sdbized
|
|
if (imports_list) {
|
|
r_list_foreach (imports_list, iter, import)
|
|
if (!strcmp (import->name, "__security_init_cookie")) {
|
|
//r_list_free (imports_list);
|
|
return 1;
|
|
}
|
|
// DO NOT FREE IT! r_list_free (imports_list);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int haschr(const RBinFile* arch, ut16 dllCharacteristic) {
|
|
const ut8 *buf;
|
|
unsigned int idx;
|
|
ut64 sz;
|
|
if (!arch) return false;
|
|
buf = r_buf_buffer (arch->buf);
|
|
if (!buf) return false;
|
|
sz = r_buf_size (arch->buf);
|
|
idx = (buf[0x3c] | (buf[0x3d]<<8));
|
|
if (sz < idx + 0x5E)
|
|
return false;
|
|
return ((*(ut16*)(buf + idx + 0x5E)) & \
|
|
dllCharacteristic);
|
|
}
|
|
|
|
static RBinInfo* info(RBinFile *arch) {
|
|
SDebugInfo di = {{0}};
|
|
RBinInfo *ret = R_NEW0 (RBinInfo);
|
|
if (!ret) return NULL;
|
|
arch->file = strdup (arch->file);
|
|
ret->bclass = PE_(r_bin_pe_get_class) (arch->o->bin_obj);
|
|
ret->rclass = strdup ("pe");
|
|
ret->os = PE_(r_bin_pe_get_os) (arch->o->bin_obj);
|
|
ret->arch = PE_(r_bin_pe_get_arch) (arch->o->bin_obj);
|
|
ret->machine = PE_(r_bin_pe_get_machine) (arch->o->bin_obj);
|
|
ret->subsystem = PE_(r_bin_pe_get_subsystem) (arch->o->bin_obj);
|
|
if (is_dot_net (arch)) {
|
|
ret->lang = "msil";
|
|
}
|
|
if (is_vb6 (arch)) {
|
|
ret->lang = "vb";
|
|
}
|
|
if (PE_(r_bin_pe_is_dll) (arch->o->bin_obj))
|
|
ret->type = strdup ("DLL (Dynamic Link Library)");
|
|
else ret->type = strdup ("EXEC (Executable file)");
|
|
ret->bits = PE_(r_bin_pe_get_bits) (arch->o->bin_obj);
|
|
ret->big_endian = PE_(r_bin_pe_is_big_endian) (arch->o->bin_obj);
|
|
ret->dbg_info = 0;
|
|
ret->has_canary = has_canary (arch);
|
|
ret->has_nx = haschr (arch, IMAGE_DLL_CHARACTERISTICS_NX_COMPAT);
|
|
ret->has_pi = haschr (arch, IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE);
|
|
|
|
sdb_bool_set (arch->sdb, "pe.canary", has_canary(arch), 0);
|
|
sdb_bool_set (arch->sdb, "pe.highva", haschr(arch, IMAGE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA), 0);
|
|
sdb_bool_set (arch->sdb, "pe.aslr", haschr(arch, IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE), 0);
|
|
sdb_bool_set (arch->sdb, "pe.forceintegrity", haschr(arch, IMAGE_DLL_CHARACTERISTICS_FORCE_INTEGRITY), 0);
|
|
sdb_bool_set (arch->sdb, "pe.nx", haschr(arch, IMAGE_DLL_CHARACTERISTICS_NX_COMPAT), 0);
|
|
sdb_bool_set (arch->sdb, "pe.isolation", !haschr(arch, IMAGE_DLL_CHARACTERISTICS_FORCE_INTEGRITY), 0);
|
|
sdb_bool_set (arch->sdb, "pe.seh", !haschr(arch, IMAGE_DLLCHARACTERISTICS_NO_SEH), 0);
|
|
sdb_bool_set (arch->sdb, "pe.bind", !haschr(arch, IMAGE_DLLCHARACTERISTICS_NO_BIND), 0);
|
|
sdb_bool_set (arch->sdb, "pe.appcontainer", haschr(arch, IMAGE_DLLCHARACTERISTICS_APPCONTAINER), 0);
|
|
sdb_bool_set (arch->sdb, "pe.wdmdriver", haschr(arch, IMAGE_DLLCHARACTERISTICS_WDM_DRIVER), 0);
|
|
sdb_bool_set (arch->sdb, "pe.guardcf", haschr(arch, IMAGE_DLLCHARACTERISTICS_GUARD_CF), 0);
|
|
sdb_bool_set (arch->sdb, "pe.terminalserveraware", haschr(arch, IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE), 0);
|
|
sdb_num_set (arch->sdb, "pe.bits", ret->bits, 0);
|
|
|
|
ret->has_va = true;
|
|
if (!PE_(r_bin_pe_is_stripped_debug) (arch->o->bin_obj))
|
|
ret->dbg_info |= R_BIN_DBG_STRIPPED;
|
|
if (PE_(r_bin_pe_is_stripped_line_nums) (arch->o->bin_obj))
|
|
ret->dbg_info |= R_BIN_DBG_LINENUMS;
|
|
if (PE_(r_bin_pe_is_stripped_local_syms) (arch->o->bin_obj))
|
|
ret->dbg_info |= R_BIN_DBG_SYMS;
|
|
if (PE_(r_bin_pe_is_stripped_relocs) (arch->o->bin_obj))
|
|
ret->dbg_info |= R_BIN_DBG_RELOCS;
|
|
|
|
if (PE_(r_bin_pe_get_debug_data)(arch->o->bin_obj, &di)) {
|
|
ret->guid = r_str_ndup (di.guidstr, GUIDSTR_LEN);
|
|
if (ret->guid) {
|
|
ret->debug_file_name = r_str_ndup (di.file_name, DBG_FILE_NAME_LEN);
|
|
if (!ret->debug_file_name) {
|
|
R_FREE (ret->guid);
|
|
}
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
static ut64 get_vaddr (RBinFile *arch, ut64 baddr, ut64 paddr, ut64 vaddr) {
|
|
return baddr + vaddr;
|
|
}
|
|
|
|
#if !R_BIN_PE64
|
|
static int check(RBinFile *arch) {
|
|
const ut8 *bytes = arch ? r_buf_buffer (arch->buf) : NULL;
|
|
ut64 sz = arch ? r_buf_size (arch->buf): 0;
|
|
return check_bytes (bytes, sz);
|
|
|
|
}
|
|
|
|
static int check_bytes(const ut8 *buf, ut64 length) {
|
|
unsigned int idx;
|
|
if (!buf) return false;
|
|
if (length <= 0x3d)
|
|
return false;
|
|
idx = (buf[0x3c] | (buf[0x3d]<<8));
|
|
if (length > idx+0x18+2)
|
|
if (!memcmp (buf, "MZ", 2) &&
|
|
!memcmp (buf+idx, "PE", 2) &&
|
|
!memcmp (buf+idx+0x18, "\x0b\x01", 2))
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
/* inspired in http://www.phreedom.org/solar/code/tinype/tiny.97/tiny.asm */
|
|
static RBuffer* create(RBin* bin, const ut8 *code, int codelen, const ut8 *data, int datalen) {
|
|
ut32 hdrsize, p_start, p_opthdr, p_sections, p_lsrlc, n;
|
|
ut32 baddr = 0x400000;
|
|
RBuffer *buf = r_buf_new ();
|
|
|
|
#define B(x,y) r_buf_append_bytes(buf,(const ut8*)x,y)
|
|
#define H(x) r_buf_append_ut16(buf,x)
|
|
#define D(x) r_buf_append_ut32(buf,x)
|
|
#define Z(x) r_buf_append_nbytes(buf,x)
|
|
#define W(x,y,z) r_buf_write_at(buf,x,(const ut8*)y,z)
|
|
#define WZ(x,y) p_tmp=buf->length;Z(x);W(p_tmp,y,strlen(y))
|
|
|
|
B ("MZ\x00\x00", 4); // MZ Header
|
|
B ("PE\x00\x00", 4); // PE Signature
|
|
H (0x14c); // Machine
|
|
H (1); // Number of sections
|
|
D (0); // Timestamp (Unused)
|
|
D (0); // PointerToSymbolTable (Unused)
|
|
D (0); // NumberOfSymbols (Unused)
|
|
p_lsrlc = buf->length;
|
|
H (-1); // SizeOfOptionalHeader
|
|
H (0x103); // Characteristics
|
|
|
|
/* Optional Header */
|
|
p_opthdr = buf->length;
|
|
H (0x10b); // Magic
|
|
B ("\x08\x00", 2); // (Major/Minor)LinkerVersion (Unused)
|
|
|
|
p_sections = buf->length;
|
|
n = p_sections-p_opthdr;
|
|
W (p_lsrlc, &n, 2); // Fix SizeOfOptionalHeader
|
|
|
|
/* Sections */
|
|
p_start = 0x7c; //HACK: Headersize
|
|
hdrsize = 0x7c;
|
|
|
|
D (R_ROUND (codelen, 4)); // SizeOfCode (Unused)
|
|
D (0); // SizeOfInitializedData (Unused)
|
|
D (codelen); // codesize
|
|
D (p_start);
|
|
D (codelen);
|
|
D (p_start);
|
|
D (baddr); // ImageBase
|
|
D (4); // SectionAlignment
|
|
D (4); // FileAlignment
|
|
H (4); // MajorOperatingSystemVersion (Unused)
|
|
H (0); // MinorOperatingSystemVersion (Unused)
|
|
H (0); // MajorImageVersion (Unused)
|
|
H (0); // MinorImageVersion (Unused)
|
|
H (4); // MajorSubsystemVersion
|
|
H (0); // MinorSubsystemVersion (Unused)
|
|
D (0); // Win32VersionValue (Unused)
|
|
D ((R_ROUND (hdrsize, 4)) + (R_ROUND (codelen, 4))); // SizeOfImage
|
|
D (R_ROUND (hdrsize, 4)); // SizeOfHeaders
|
|
D (0); // CheckSum (Unused)
|
|
H (2); // Subsystem (Win32 GUI)
|
|
H (0x400); // DllCharacteristics (Unused)
|
|
D (0x100000); // SizeOfStackReserve (Unused)
|
|
D (0x1000); // SizeOfStackCommit
|
|
D (0x100000); // SizeOfHeapReserve
|
|
D (0x1000); // SizeOfHeapCommit (Unused)
|
|
D (0); // LoaderFlags (Unused)
|
|
D (0); // NumberOfRvaAndSizes (Unused)
|
|
B (code, codelen);
|
|
|
|
if (data && datalen>0) {
|
|
//ut32 data_section = buf->length;
|
|
eprintf ("Warning: DATA section not support for PE yet\n");
|
|
B (data, datalen);
|
|
}
|
|
return buf;
|
|
}
|
|
|
|
struct r_bin_plugin_t r_bin_plugin_pe = {
|
|
.name = "pe",
|
|
.desc = "PE bin plugin",
|
|
.license = "LGPL3",
|
|
.get_sdb = &get_sdb,
|
|
.load = &load,
|
|
.load_bytes = &load_bytes,
|
|
.destroy = &destroy,
|
|
.check = &check,
|
|
.check_bytes = &check_bytes,
|
|
.baddr = &baddr,
|
|
.binsym = &binsym,
|
|
.entries = &entries,
|
|
.sections = §ions,
|
|
.symbols = &symbols,
|
|
.imports = &imports,
|
|
.info = &info,
|
|
.libs = &libs,
|
|
.relocs = &relocs,
|
|
.minstrlen = 4,
|
|
.create = &create,
|
|
.get_vaddr = &get_vaddr
|
|
};
|
|
|
|
#ifndef CORELIB
|
|
struct r_lib_struct_t radare_plugin = {
|
|
.type = R_LIB_TYPE_BIN,
|
|
.data = &r_bin_plugin_pe,
|
|
.version = R2_VERSION
|
|
};
|
|
#endif
|
|
#endif
|