diff --git a/binr/rabin2/rabin2.c b/binr/rabin2/rabin2.c index 0a6f96dfd6..771994f960 100644 --- a/binr/rabin2/rabin2.c +++ b/binr/rabin2/rabin2.c @@ -33,6 +33,7 @@ #define ACTION_EXTRACT 0x1000 #define ACTION_RELOCS 0x2000 #define ACTION_LISTARCHS 0x4000 +#define ACTION_CREATE 0x8000 static struct r_lib_t *l; static struct r_bin_t *bin = NULL; @@ -42,36 +43,38 @@ static int va = R_FALSE; static ut64 gbaddr = 0LL; static char* file = NULL; static char* output = "out"; +static char* create = NULL; static ut64 at = 0LL; static char *name = NULL; static int rabin_show_help() { printf ("rabin2 [options] [file]\n" - " -A List archs\n" - " -a [arch_bits] Set arch\n" - " -f [str] Select sub-bin named str\n" - " -b [addr] Override baddr\n" - " -e Entrypoint\n" - " -M Main\n" - " -i Imports (symbols imported from libraries)\n" - " -s Symbols (exports)\n" - " -S Sections\n" - " -z Strings\n" - " -I Binary info\n" - " -H Header fields\n" - " -l Linked libraries\n" - " -R Relocations\n" - " -O [str] Write/Extract operations (str=help for help)\n" - " -o [str] Output file/folder for write operations (out by default)\n" - " -r radare output\n" - " -v Use vaddr in radare output\n" - " -m [addr] Show source line at addr\n" - " -L List supported bin plugins\n" - " -@ [addr] Show section, symbol or import at addr\n" - " -n [str] Show section, symbol or import named str\n" - " -x Extract bins contained in file\n" - " -V Show version information\n" - " -h This help\n"); + " -A list archs\n" + " -a [arch_bits] set arch\n" + " -b [addr] override baddr\n" + " -c [fmt:C:D] create [fmt] binary with Code and Data hexpairs (see -a)\n" + " -e entrypoint\n" + " -f [str] select sub-bin named str\n" + " -i imports (symbols imported from libraries)\n" + " -s symbols (exports)\n" + " -S sections\n" + " -M main (show address of main symbol)\n" + " -z strings\n" + " -I binary info\n" + " -H header fields\n" + " -l linked libraries\n" + " -R relocations\n" + " -O [str] write/extract operations (str=help for help)\n" + " -o [str] output file/folder for write operations (out by default)\n" + " -r radare output\n" + " -v use vaddr in radare output\n" + " -m [addr] show source line at addr\n" + " -L list supported bin plugins\n" + " -@ [addr] show section, symbol or import at addr\n" + " -n [str] show section, symbol or import named str\n" + " -x extract bins contained in file\n" + " -V show version information\n" + " -h this help\n"); return 1; } @@ -105,13 +108,13 @@ static int rabin_show_entrypoints() { static int rabin_show_main() { RBinAddr *binmain; - ut64 baddr = gbaddr?gbaddr:r_bin_get_baddr (bin); + ut64 baddr = gbaddr? gbaddr: r_bin_get_baddr (bin); if ((binmain = r_bin_get_sym (bin, R_BIN_SYM_MAIN)) == NULL) return R_FALSE; if (rad) { printf ("fs symbols\n"); - printf ("f main @ 0x%08"PFMT64x"\n", va?baddr+binmain->rva:binmain->offset); + printf ("f main @ 0x%08"PFMT64x"\n", va? baddr+binmain->rva: binmain->offset); } else { eprintf ("[Main]\n"); printf ("addr=0x%08"PFMT64x" off=0x%08"PFMT64x"\n", @@ -127,7 +130,7 @@ static int rabin_extract(int all) { // XXX: Wrong for w32 (/) if (all) { for (i=0; inarch; i++) { - r_bin_set_archidx (bin, i); + r_bin_select_idx (bin, i); if (bin->curarch.info == NULL) { eprintf ("No extract info found.\n"); } else { @@ -199,18 +202,22 @@ static int rabin_show_relocs() { if ((relocs = r_bin_get_relocs (bin)) == NULL) return R_FALSE; - if (rad) printf ("fs relocs\n"); - else eprintf ("[Relocations]\n"); - - r_list_foreach (relocs, iter, reloc) { - if (rad) printf ("f reloc.%s @ 0x%08"PFMT64x"\n", reloc->name, va?baddr+reloc->rva:reloc->offset); - else printf ("sym=%02i addr=0x%08"PFMT64x" off=0x%08"PFMT64x" type=0x%08x %s\n", + if (rad) { + printf ("fs relocs\n"); + r_list_foreach (relocs, iter, reloc) { + printf ("f reloc.%s @ 0x%08"PFMT64x"\n", reloc->name, va?baddr+reloc->rva:reloc->offset); + i++; + } + } else { + eprintf ("[Relocations]\n"); + r_list_foreach (relocs, iter, reloc) { + printf ("sym=%02i addr=0x%08"PFMT64x" off=0x%08"PFMT64x" type=0x%08x %s\n", reloc->sym, baddr+reloc->rva, reloc->offset, reloc->type, reloc->name); - i++; + i++; + } + eprintf ("\n%i relocations\n", i); } - if (!rad) eprintf ("\n%i relocations\n", i); - return R_TRUE; } @@ -665,7 +672,7 @@ int main(int argc, char **argv) { r_lib_opendir (l, LIBDIR"/radare2/"); } - while ((c = getopt (argc, argv, "Af:a:B:b:Mm:n:@:VisSzIHelRwO:o:rvLhx")) != -1) { + while ((c = getopt (argc, argv, "Af:a:B:b:c:Mm:n:@:VisSzIHelRwO:o:rvLhx")) != -1) { switch(c) { case 'A': action |= ACTION_LISTARCHS; @@ -673,6 +680,10 @@ int main(int argc, char **argv) { case 'a': if (optarg) arch = strdup (optarg); break; + case 'c': + action = ACTION_CREATE; + create = strdup (optarg); + break; case 'f': if (optarg) arch_name = strdup (optarg); break; @@ -759,10 +770,6 @@ int main(int argc, char **argv) { if (action == ACTION_HELP || action == ACTION_UNK || file == NULL) return rabin_show_help (); - if (!r_bin_load (bin, file, R_FALSE) && !r_bin_load (bin, file, R_TRUE)) { - eprintf ("r_bin: Cannot open '%s'\n", file); - return 1; - } if (arch) { char *ptr; ptr = strchr (arch, '_'); @@ -771,8 +778,48 @@ int main(int argc, char **argv) { bits = r_num_math (NULL, ptr+1); } } + if (action & ACTION_CREATE) { + RBuffer *b; + int datalen, codelen; + ut8 *data = NULL, *code = NULL; + char *p2, *p = strchr (create, ':'); + if (!p) { + eprintf ("Invalid format for -c flag. Use 'format:codehexpair:datahexpair'\n"); + return 1; + } + *p++ = 0; + p2 = strchr (p, ':'); + if (p2) { + // has data + *p2++ = 0; + data = malloc (strlen (p2)); + datalen = r_hex_str2bin (p2, data); + } + code = malloc (strlen (p)); + codelen = r_hex_str2bin (p, code); + if (!arch) arch = "x86"; + if (!bits) bits = 32; + + if (!r_bin_use_arch (bin, arch, bits, create)) { + eprintf ("Cannot set arch\n"); + return 1; + } + b = r_bin_create (bin, code, codelen, data, datalen); + if (b) { + if (r_file_dump (file, b->buf, b->length)) + eprintf ("dumped %d bytes in '%s'\n", b->length, file); + else eprintf ("error dumping into a.out\n"); + r_buf_free (b); + } else eprintf ("Cannot create binary for this format '%s'.\n", create); + r_bin_free (bin); + return 0; + } + if (!r_bin_load (bin, file, R_FALSE) && !r_bin_load (bin, file, R_TRUE)) { + eprintf ("r_bin: Cannot open '%s'\n", file); + return 1; + } if (action & ACTION_LISTARCHS && (arch || bits || arch_name)) { - if (!r_bin_set_arch (bin, arch, bits, arch_name)) { + if (!r_bin_select (bin, arch, bits, arch_name)) { r_bin_list_archs (bin); free (arch); r_bin_free (bin); diff --git a/libr/bin/bin.c b/libr/bin/bin.c index 968060b9cb..5cd048c10f 100644 --- a/libr/bin/bin.c +++ b/libr/bin/bin.c @@ -357,10 +357,26 @@ R_API RBin* r_bin_new() { return bin; } -R_API int r_bin_set_arch(RBin *bin, const char *arch, int bits, const char *name) { +// TODO: handle ARCH and BITS +R_API int r_bin_use_arch(RBin *bin, const char *arch, int bits, const char *name) { + struct list_head *pos; + + list_for_each_prev(pos, &bin->bins) { + RBinPlugin *h = list_entry (pos, RBinPlugin, list); + if (!strcmp (name, h->name)) { + bin->curarch.curplugin = h; +// TODO: set bits and name + return R_TRUE; + } + } + return R_FALSE; +} + +// TODO: rename to r_bin_select +R_API int r_bin_select(RBin *bin, const char *arch, int bits, const char *name) { int i; for (i = 0; i < bin->narch; i++) { - r_bin_set_archidx (bin, i); + r_bin_select_idx (bin, i); if (!bin->curarch.info || !bin->curarch.file || (arch && !strstr (bin->curarch.info->arch, arch)) || (bits && bits != bin->curarch.info->bits) || @@ -371,7 +387,8 @@ R_API int r_bin_set_arch(RBin *bin, const char *arch, int bits, const char *name return R_FALSE; } -R_API int r_bin_set_archidx(RBin *bin, int idx) { +// TODO: rename to r_bin_select_idx +R_API int r_bin_select_idx(RBin *bin, int idx) { r_bin_free_items (bin); if (r_bin_extract (bin, idx)) return r_bin_init_items (bin, R_FALSE); @@ -381,7 +398,7 @@ R_API int r_bin_set_archidx(RBin *bin, int idx) { R_API void r_bin_list_archs(RBin *bin) { int i; for (i = 0; i < bin->narch; i++) - if (r_bin_set_archidx (bin, i) && bin->curarch.info) + if (r_bin_select_idx (bin, i) && bin->curarch.info) printf ("%03i %s %s_%i (%s)\n", i, bin->curarch.file, bin->curarch.info->arch, bin->curarch.info->bits, bin->curarch.info->machine); @@ -403,6 +420,13 @@ R_API void r_bin_bind (RBin *bin, RBinBind *b) { b->get_offset = getoffset; } +R_API RBuffer *r_bin_create (RBin *bin, const ut8 *code, int codelen, const ut8 *data, int datalen) { + RBinArch *a = &bin->curarch; + if (a && a->curplugin && a->curplugin->create) + return a->curplugin->create (bin, code, codelen, data, datalen); + return NULL; +} + R_API RBinObj *r_bin_get_object(RBin *bin, int flags) { int i; RBinObj *obj = R_NEW (RBinObj); diff --git a/libr/bin/p/bin_mach0.c b/libr/bin/p/bin_mach0.c index 40c621d843..4d27322b17 100644 --- a/libr/bin/p/bin_mach0.c +++ b/libr/bin/p/bin_mach0.c @@ -190,6 +190,154 @@ static int check(RBinArch *arch) { return R_FALSE; } +#if 0 +typedef struct r_bin_create_t { + int arch; + ut8 *code; + int codelen; + ut8 *data; + int datalen; +} RBinCreate; +#endif + +static RBuffer* create(RBin* bin, const ut8 *code, int codelen, const ut8 *data, int datalen) { + ut32 filesize, codeva, datava; + ut32 ncmds, cmdsize, magiclen, headerlen; + ut32 p_codefsz, p_codeva, p_codesz, p_codepa; + ut32 p_datafsz, p_datava, p_datasz, p_datapa; + ut32 p_cmdsize, p_entry, p_tmp; + ut32 baddr = 0x1000; + RBuffer *buf = r_buf_new (); + +#define B(x,y) r_buf_append_bytes(buf,(const ut8*)x,y) +#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)) + + /* MACH0 HEADER */ + B ("\xce\xfa\xed\xfe", 4); // header + D (7); // cpu type (x86) + D (3); // subtype (i386-all) + D (2); // filetype (executable) + + + if (data && datalen>0) { + ncmds = 3; + cmdsize = 0; + } else { + ncmds = 2; + cmdsize = 0; + } + + /* COMMANDS */ + D (ncmds); // ncmds + p_cmdsize = buf->length; + D (-1); // cmdsize + D (0); // flags + magiclen = buf->length; + + /* TEXT SEGMENT */ + D (1); // cmd.LC_SEGMENT + D (124); // sizeof (cmd) + WZ (16, "__TEXT"); + D (baddr); // vmaddr + D (0x1000); // vmsize XXX + D (0); // fileoff + p_codefsz = buf->length; + D (-1); // filesize + D (7); // maxprot + D (5); // initprot + D (1); // nsects + D (0); // flags + WZ (16, "__text"); + WZ (16, "__TEXT"); + p_codeva = buf->length; // virtual address + D (-1); + p_codesz = buf->length; // size of code (end-start) + D (-1); + p_codepa = buf->length; // code - baddr + D (-1); //_start-0x1000); + D (2); // align + D (0); // reloff + D (0); // nrelocs + D (0); // flags + D (0); // reserved + D (0); + + if (data && datalen>0) { + /* DATA SEGMENT */ + D (1); // cmd.LC_SEGMENT + D (124); // sizeof (cmd) + p_tmp = buf->length; + Z (16); + W (p_tmp, "__TEXT", 6); // segment name + D (0x2000); // vmaddr + D (0x1000); // vmsize + D (0); // fileoff + p_datafsz = buf->length; + D (-1); // filesize + D (6); // maxprot + D (6); // initprot + D (1); // nsects + D (0); // flags + + WZ (16, "__data"); + WZ (16, "__DATA"); + + p_datava = buf->length; + D (-1); + p_datasz = buf->length; + D (-1); + p_datapa = buf->length; + D (-1); //_start-0x1000); + D (2); // align + D (0); // reloff + D (0); // nrelocs + D (0); // flags + D (0); // reserved + D (0); + } + + /* THREAD STATE */ + D (5); // LC_UNIXTHREAD + D (80); // sizeof (cmd) + D (1); // i386-thread-state + D (16); // thread-state-count + p_entry = buf->length + (10*sizeof (ut32)); + Z (16 * sizeof (ut32)); + + headerlen = buf->length - magiclen; + + codeva = buf->length + baddr; + datava = buf->length + codelen + baddr; + W (p_entry, &codeva, 4); // set PC + + /* fill header variables */ + W (p_cmdsize, &headerlen, 4); + filesize = magiclen + headerlen + codelen + datalen; + // TEXT SEGMENT // + W (p_codefsz, &filesize, 4); + W (p_codeva, &codeva, 4); + W (p_codesz, &codelen, 4); + p_tmp = codeva - baddr; + W (p_codepa, &p_tmp, 4); + + B (code, codelen); + + if (data && datalen>0) { + /* append data */ + W (p_datafsz, &filesize, 4); + W (p_datava, &datava, 4); + W (p_datasz, &datalen, 4); + p_tmp = datava - baddr; + W (p_datapa, &p_tmp, 4); + B (data, datalen); + } + + return buf; +} + struct r_bin_plugin_t r_bin_plugin_mach0 = { .name = "mach0", .desc = "mach0 bin plugin", @@ -211,6 +359,7 @@ struct r_bin_plugin_t r_bin_plugin_mach0 = { .relocs = NULL, .meta = NULL, .write = NULL, + .create = &create, }; #ifndef CORELIB diff --git a/libr/bin/t/Makefile b/libr/bin/t/Makefile index 61e39e3118..5c72aa85f8 100644 --- a/libr/bin/t/Makefile +++ b/libr/bin/t/Makefile @@ -7,7 +7,7 @@ LIBS+=${DL_LIBS} LDPATH=-L.. -L../../util LDPATH+=-lr_util -all: test_meta${EXT_EXE} rpathdel${EXT_EXE} +all: test_meta${EXT_EXE} rpathdel${EXT_EXE} test_create${EXT_EXE} test_meta${EXT_EXE}: test_meta.o ${CC} test_meta.o ${LDPATH} ${LDFLAGS} -o test_meta${EXT_EXE} @@ -15,6 +15,9 @@ test_meta${EXT_EXE}: test_meta.o rpathdel${EXT_EXE}: rpathdel.o ${CC} rpathdel.o ${LDPATH} ${LDFLAGS} -o rpathdel${EXT_EXE} +test_create${EXT_EXE}: test_create.o + ${CC} test_create.o ${LDPATH} ${LDFLAGS} -o test_create${EXT_EXE} + myclean: rm -f test_meta${EXT_EXE} test_meta.o rpathdel${EXT_EXE} rpathdel.o diff --git a/libr/bin/t/test_create.c b/libr/bin/t/test_create.c new file mode 100644 index 0000000000..fa38331bbc --- /dev/null +++ b/libr/bin/t/test_create.c @@ -0,0 +1,22 @@ +#include + +int main () { +#define _BUFFER_SIZE 64 + unsigned char code[64] = { + 0x31, 0xc0, 0x40, 0x68, 0x2a, 0x00, 0x00, 0x00, 0x81, 0xec, 0x04, + 0x00, 0x00, 0x00, 0xcd, 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; + RBuffer *b; + RBin *bin = r_bin_new (); + if (!r_bin_use_arch (bin, "x86", 32, "mach0")) { + eprintf ("Cannot set arch\n"); + return 1; + } + b = r_bin_create (bin, code, _BUFFER_SIZE, NULL, 0); + if (b) { + if (r_file_dump ("a.out", b->buf, b->length)) + eprintf ("dumped %d bytes in a.out\n", b->length); + else eprintf ("error dumping into a.out\n"); + } else eprintf ("So fucking oops\n"); + r_bin_free (bin); + r_buf_free (b); +} diff --git a/libr/include/r_bin.h b/libr/include/r_bin.h index fe0b747502..60adc9b5bd 100644 --- a/libr/include/r_bin.h +++ b/libr/include/r_bin.h @@ -104,6 +104,7 @@ typedef struct r_bin_plugin_t { struct r_bin_meta_t *meta; struct r_bin_write_t *write; int (*get_offset)(RBinArch *arch, int type, int idx); + RBuffer* (*create)(RBin *bin, const ut8 *code, int codelen, const ut8 *data, int datalen); struct list_head list; // TODO deprecate!!! } RBinPlugin; @@ -253,10 +254,12 @@ R_API int r_bin_has_dbg_linenums (RBin *bin); R_API int r_bin_has_dbg_syms (RBin *bin); R_API int r_bin_has_dbg_relocs (RBin *bin); R_API RBin* r_bin_new(); -R_API int r_bin_set_arch(RBin *bin, const char *arch, int bits, const char *name); -R_API int r_bin_set_archidx(RBin *bin, int idx); +R_API int r_bin_use_arch(RBin *bin, const char *arch, int bits, const char *name); +R_API int r_bin_select(RBin *bin, const char *arch, int bits, const char *name); +R_API int r_bin_select_idx(RBin *bin, int idx); R_API void r_bin_list_archs(RBin *bin); R_API void r_bin_set_user_ptr(RBin *bin, void *user); +R_API RBuffer *r_bin_create (RBin *bin, const ut8 *code, int codelen, const ut8 *data, int datalen); /* bin_meta.c */ R_API int r_bin_meta_get_line(RBin *bin, ut64 addr, char *file, int len, int *line); R_API char *r_bin_meta_get_source_line(RBin *bin, ut64 addr); diff --git a/libr/include/r_util.h b/libr/include/r_util.h index 9abb672d8b..94130852b4 100644 --- a/libr/include/r_util.h +++ b/libr/include/r_util.h @@ -192,6 +192,8 @@ R_API RBuffer *r_buf_new(); R_API int r_buf_set_bits(RBuffer *b, int bitoff, int bitsize, ut64 value); R_API int r_buf_set_bytes(RBuffer *b, ut8 *buf, int length); R_API int r_buf_append_bytes(RBuffer *b, const ut8 *buf, int length); +R_API int r_buf_append_nbytes(RBuffer *b, int length); +R_API int r_buf_append_ut32(RBuffer *b, ut32 n); R_API int r_buf_prepend_bytes(RBuffer *b, const ut8 *buf, int length); R_API char *r_buf_to_string(RBuffer *b); R_API int r_buf_read_at(RBuffer *b, ut64 addr, ut8 *buf, int len); diff --git a/libr/util/buf.c b/libr/util/buf.c index 94a3610407..b31bb0ead2 100644 --- a/libr/util/buf.c +++ b/libr/util/buf.c @@ -14,10 +14,8 @@ struct r_class_t { #define r_buf_init(x) r_buf_class->init #endif -R_API struct r_buf_t *r_buf_new() { - RBuffer *b; - - b = R_NEW (RBuffer); +R_API RBuffer *r_buf_new() { + RBuffer *b = R_NEW (RBuffer); if (b) { b->buf = NULL; b->length = 0; @@ -67,6 +65,22 @@ R_API int r_buf_append_bytes(RBuffer *b, const ut8 *buf, int length) { return R_TRUE; } +R_API int r_buf_append_nbytes(RBuffer *b, int length) { + if (!(b->buf = realloc (b->buf, b->length+length))) + return R_FALSE; + memset (b->buf+b->length, 0, length); + b->length += length; + return R_TRUE; +} + +R_API int r_buf_append_ut32(RBuffer *b, ut32 n) { + if (!(b->buf = realloc (b->buf, b->length+sizeof (n)))) + return R_FALSE; + memcpy (b->buf+b->length, &n, sizeof (n)); + b->length += sizeof (n); + return R_TRUE; +} + static int r_buf_cpy(RBuffer *b, ut64 addr, ut8 *dst, const ut8 *src, int len, int write) { int end; addr = (addr==R_BUF_CUR)? b->cur: addr-b->base;