static int __core_patch_bracket(RCore *core, const char *str, ut64 *noff) { char tmp[128]; char *s, *p, *q, *off; RBuffer *b = r_buf_new (); if (!b) { return 0; } p = off = strdup (str); if (!p) { r_buf_free (b); return 0; } for (;*p;) { if (*p=='\n') { *p++ = 0; } else { p++; continue; } if (*str == '}') break; if ((q = strstr (str, "${"))) { char *end = strchr (q+2,'}'); if (end) { *q = *end = 0; *noff = r_num_math (core->num, q+2); r_buf_append_bytes (b, (const ut8*)str, strlen (str)); snprintf (tmp, sizeof (tmp), "0x%08"PFMT64x, *noff); r_buf_append_bytes (b, (const ut8*)tmp, strlen (tmp)); r_buf_append_bytes (b, (const ut8*)end+1, strlen (end+1)); } } else { r_buf_append_bytes (b, (const ut8*)str, strlen (str)); } str = p; } s = r_buf_to_string (b); r_egg_load (core->egg, s, 0); free (s); r_egg_compile (core->egg); r_egg_assemble (core->egg); r_buf_free (b); b = r_egg_get_bin (core->egg); if (strcmp (off, "+")) { *noff = r_num_math (core->num, off); } r_core_write_at (core, *noff, b->buf, b->length); *noff += b->length; free (off); return 1; }
R_API bool r_buf_append_ut32(RBuffer *b, ut32 n) { if (b->empty) b->length = b->empty = 0; if (b->fd != -1) { return r_buf_append_bytes (b, (const ut8*)&n, sizeof (n)); } if (!(b->buf = realloc (b->buf, b->length+sizeof (n)))) return false; memmove (b->buf+b->length, &n, sizeof (n)); b->length += sizeof (n); return true; }
R_API char *r_buf_free_to_string (RBuffer *b) { char *p; if (!b) return NULL; if (b->mmap) { p = r_buf_to_string (b); } else { r_buf_append_bytes (b, (const ut8*)"", 1); p = (char *)b->buf; } free (b); return p; }
R_API bool r_buf_append_buf(RBuffer *b, RBuffer *a) { if (!b) return false; if (b->fd != -1) { r_buf_append_bytes (b, a->buf, a->length); return true; } if (b->empty) { b->length = 0; b->empty = 0; } if ((b->buf = realloc (b->buf, b->length + a->length))) { memmove (b->buf+b->length, a->buf, a->length); b->length += a->length; return true; } return false; }
R_API char *r_buf_free_to_string(RBuffer *b) { char *p; if (!b) { return NULL; } if (b->mmap) { p = r_buf_to_string (b); } else { r_buf_append_bytes (b, (const ut8*)"", 1); p = malloc (b->length + 1); if (!p) { return NULL; } memmove (p, b->buf, b->length); p[b->length] = 0; } r_buf_free (b); return p; }
R_API int r_buf_append_string (RBuffer *b, const char *str) { return r_buf_append_bytes (b, (const ut8*)str, strlen (str)); }
static RBuffer *build (REgg *egg) { RBuffer *buf, *sc; ut8 aux[32], nkey; const char *default_key = DEFAULT_XOR_KEY; char *key = r_egg_option_get (egg, "key"); int i; if (!key || !*key) { free (key); key = strdup (default_key); eprintf ("XOR key not provided. Using (%s) as the key\n", key); } nkey = r_num_math (NULL, key); if (nkey == 0) { eprintf ("Invalid key (%s)\n", key); free (key); return false; } if (nkey != (nkey & 0xff)) { nkey &= 0xff; eprintf ("xor key wrapped to (%d)\n", nkey); } if (r_buf_size (egg->bin) > 240) { // XXX eprintf ("shellcode is too long :(\n"); free (key); return NULL; } sc = egg->bin; // hack if (!r_buf_size (sc)) { eprintf ("No shellcode found!\n"); free (key); return NULL; } for (i = 0; i<r_buf_size (sc); i++) { // eprintf ("%02x -> %02x\n", sc->buf[i], sc->buf[i] ^nkey); if ((r_buf_read8_at (sc, i) ^ nkey)==0) { eprintf ("This xor key generates null bytes. Try again.\n"); free (key); return NULL; } } buf = r_buf_new (); sc = r_buf_new (); // TODO: alphanumeric? :D // This is the x86-32/64 xor encoder r_buf_append_buf (sc, egg->bin); if (egg->arch == R_SYS_ARCH_X86) { #define STUBLEN 18 ut8 stub[STUBLEN] = "\xe8\xff\xff\xff\xff" // call $$+4 "\xc1" // ffc1 = inc ecx "\x5e" // pop esi "\x48\x83\xc6\x0d" // add rsi, xx ... 64bit // loop0: "\x30\x1e" // xor [esi], bl "\x48\xff\xc6" // inc rsi "\xe2\xf9"; // loop loop0 // ecx = length aux[0] = 0x6a; // push length aux[1] = r_buf_size (sc); aux[2] = 0x59; // pop ecx // ebx = key aux[3] = 0x6a; // push key aux[4] = nkey; aux[5] = 0x5b; // pop ebx r_buf_set_bytes (buf, aux, 6); r_buf_append_bytes (buf, stub, STUBLEN); for (i = 0; i<r_buf_size (sc); i++) { ut8 v = r_buf_read8_at (sc, i) ^ nkey; r_buf_write_at (sc, i, &v, sizeof (v)); } r_buf_append_buf (buf, sc); } r_buf_free (sc); free (key); return buf; }
static RBuffer *build (REgg *egg) { RBuffer *buf, *sc; ut8 aux[32], nkey; int i; char *key = r_egg_option_get (egg, "key"); if (!key || !*key) { eprintf ("Invalid key (null)\n"); return R_FALSE; } nkey = r_num_math (NULL, key); if (nkey == 0) { eprintf ("Invalid key (%s)\n", key); return R_FALSE; } if (nkey != (nkey & 0xff)) { nkey &= 0xff; eprintf ("xor key wrapped to (%d)\n", nkey); } if (egg->bin->length > 240) { // XXX eprintf ("shellcode is too long :(\n"); return NULL; } sc = egg->bin; // hack for (i = 0; i<sc->length; i++) { // eprintf ("%02x -> %02x\n", sc->buf[i], sc->buf[i] ^nkey); if ((sc->buf[i]^nkey)==0) { eprintf ("This xor key generates null bytes. Try again.\n"); return NULL; } } buf = r_buf_new (); sc = r_buf_new (); // TODO: alphanumeric? :D // This is the x86-32/64 xor encoder r_buf_append_buf (sc, egg->bin); if (egg->arch == R_SYS_ARCH_X86) { #define STUBLEN 18 ut8 stub[STUBLEN] = "\xe8\xff\xff\xff\xff" // call $$+4 "\xc1" // ffc1 = inc ecx "\x5e" // pop esi "\x48\x83\xc6\x0d" // add rsi, xx ... 64bit // loop0: "\x30\x1e" // xor [esi], bl "\x48\xff\xc6" // inc rsi "\xe2\xf9"; // loop loop0 // ecx = length aux[0] = 0x6a; // push length aux[1] = sc->length; aux[2] = 0x59; // pop ecx // ebx = key aux[3] = 0x6a; // push key aux[4] = nkey; aux[5] = 0x5b; // pop ebx r_buf_set_bytes (buf, aux, 6); r_buf_append_bytes (buf, stub, STUBLEN); for (i = 0; i<sc->length; i++) { // eprintf ("%02x -> %02x\n", sc->buf[i], sc->buf[i] ^nkey); sc->buf[i]^=nkey; } r_buf_append_buf (buf, sc); } r_buf_free (sc); return buf; }
/* TODO: Needs more testing and ERROR HANDLING */ struct r_bin_dyldcache_lib_t *r_bin_dyldcache_extract(struct r_bin_dyldcache_obj_t* bin, int idx, int *nlib) { struct r_bin_dyldcache_lib_t *ret = NULL; struct mach_header *mh; RBuffer* dbuf; ut64 curoffset, liboff, libla, libpath, linkedit_offset; ut8 *data, *cmdptr; char *libname; int cmd, libsz = 0; if (bin->nlibs < 0 || idx < 0 || idx > bin->nlibs) return NULL; *nlib = bin->nlibs; ret = R_NEW0 (struct r_bin_dyldcache_lib_t); if (!ret) { perror ("malloc (ret)"); return NULL; } curoffset = bin->hdr.startaddr+idx*32; libla = *(ut64*)(bin->b->buf+curoffset); liboff = libla - *(ut64*)&bin->b->buf[bin->hdr.baseaddroff]; if (liboff > bin->size) { eprintf ("Corrupted file\n"); free (ret); return NULL; } ret->offset = liboff; libpath = *(ut64*)(bin->b->buf+curoffset + 24); /* Locate lib hdr in cache */ data = bin->b->buf+liboff; mh = (struct mach_header *)data; /* Check it is mach-o */ if (mh->magic != 0xfeedface) { eprintf ("Not mach-o\n"); free (ret); return NULL; } /* Write mach-o hdr */ if (!(dbuf = r_buf_new ())) { eprintf ("new (dbuf)\n"); free (ret); return NULL; } r_buf_set_bytes (dbuf, data, sizeof (struct mach_header)); cmdptr = data + sizeof(struct mach_header); /* Write load commands */ for (cmd = 0; cmd < mh->ncmds; cmd++) { struct load_command *lc = (struct load_command *)cmdptr; cmdptr += lc->cmdsize; r_buf_append_bytes (dbuf, (ut8*)lc, lc->cmdsize); } /* Write segments */ for (cmd = linkedit_offset = 0, cmdptr = data + sizeof (struct mach_header); cmd < mh->ncmds; cmd++) { struct load_command *lc = (struct load_command *)cmdptr; cmdptr += lc->cmdsize; switch (lc->cmd) { case LC_SEGMENT: { /* Write segment and patch offset */ struct segment_command *seg = (struct segment_command *)lc; int t = seg->filesize; if (seg->fileoff+seg->filesize > bin->b->length) t = bin->b->length - seg->fileoff; r_buf_append_bytes (dbuf, bin->b->buf+seg->fileoff, t); r_bin_dyldcache_apply_patch (dbuf, dbuf->length, (ut64)((size_t)&seg->fileoff - (size_t)data)); /* Patch section offsets */ int sect_offset = seg->fileoff - libsz; libsz = dbuf->length; if (!strcmp(seg->segname, "__LINKEDIT")) linkedit_offset = sect_offset; if (seg->nsects > 0) { struct section *sects = (struct section *)((ut8 *)seg + sizeof(struct segment_command)); int nsect; for (nsect = 0; nsect < seg->nsects; nsect++) { if (sects[nsect].offset > libsz) { r_bin_dyldcache_apply_patch (dbuf, sects[nsect].offset - sect_offset, (ut64)((size_t)§s[nsect].offset - (size_t)data)); } } } } break; case LC_SYMTAB: { struct symtab_command *st = (struct symtab_command *)lc; NZ_OFFSET (st->symoff); NZ_OFFSET (st->stroff); } break; case LC_DYSYMTAB: { struct dysymtab_command *st = (struct dysymtab_command *)lc; NZ_OFFSET (st->tocoff); NZ_OFFSET (st->modtaboff); NZ_OFFSET (st->extrefsymoff); NZ_OFFSET (st->indirectsymoff); NZ_OFFSET (st->extreloff); NZ_OFFSET (st->locreloff); } break; case LC_DYLD_INFO: case LC_DYLD_INFO_ONLY: { struct dyld_info_command *st = (struct dyld_info_command *)lc; NZ_OFFSET (st->rebase_off); NZ_OFFSET (st->bind_off); NZ_OFFSET (st->weak_bind_off); NZ_OFFSET (st->lazy_bind_off); NZ_OFFSET (st->export_off); } break; } } /* Fill r_bin_dyldcache_lib_t ret */ ret->b = dbuf; libname = (char*)(bin->b->buf+libpath); strncpy (ret->path, libname, sizeof (ret->path)-1); ret->size = libsz; return ret; }
// http://code.google.com/p/smali/wiki/TypesMethodsAndFields R_API char *r_bin_demangle_java(const char *str) { const char *w = NULL; int is_array = 0; const char *ptr; int is_ret = 0; int wlen = 0; RBuffer *buf; int n = 0; char *ret; ptr = strchr (str, '('); if (!ptr) return NULL; buf = r_buf_new (); if (!buf) return NULL; r_buf_append_bytes (buf, (const ut8*)str, (int)(size_t)(ptr-str)); r_buf_append_bytes (buf, (const ut8*)" (", 2); while (*str) { switch (*str) { case ')': is_ret = 1; break; case '[': is_array = 1; break; case 'L': str++; ptr = strchr (str, ';'); if (ptr) { w = str; wlen = (int)(size_t)(ptr-str); } str = ptr; break; case 'I': w = "int"; wlen = 3; break; case 'C': w = "char"; wlen = 4; break; case 'B': w = "byte"; wlen = 4; break; case 'V': w = "void"; wlen = 4; break; case 'J': w = "long"; wlen = 4; break; case 'F': w = "float"; wlen = 5; break; case 'S': w = "short"; wlen = 5; break; case 'D': w = "double"; wlen = 6; break; case 'Z': w = "boolean"; wlen = 7; break; } if (w) { if (is_ret) { r_buf_prepend_bytes (buf, (const ut8*)" ", 1); r_buf_prepend_bytes (buf, (const ut8*)w, wlen); r_buf_append_bytes (buf, (const ut8*)")", 1); break; } else { if (n++>0) r_buf_append_bytes (buf, (const ut8*)", ", 2); r_buf_append_bytes (buf, (const ut8*)w, wlen); } if (is_array) { r_buf_append_bytes (buf, (const ut8*)"[]", 2); is_array = 0; } } w = NULL; if (!str) break; str++; } ret = r_buf_to_string (buf); r_buf_free (buf); return ret; }
R_API int r_core_patch (RCore *core, const char *patch) { char *p, *p2, *q, str[200], tmp[64]; ut64 noff = 0LL; FILE *fd = r_sandbox_fopen (patch, "r"); if (fd==NULL) { eprintf ("Cannot open patch file\n"); return 1; } while (!feof (fd)) { fgets (str, sizeof (str), fd); if (*str=='#' || *str=='\n' || *str=='\r') continue; if (*str==':') { r_core_cmd0 (core, str+1); continue; } if (*str=='.' || *str=='!') { r_core_cmd0 (core, str); continue; } p = strchr (str+1, ' '); if (p) { *p = 0; for (++p; *p==' '; p++); // XXX: skipsspaces here switch (*p) { case '{': { char *s, *off = strdup (str); RBuffer *b = r_buf_new (); while (!feof (fd)) { fgets (str, sizeof (str), fd); if (*str=='}') break; if ((q=strstr (str, "${"))) { char *end = strchr (q+2,'}'); if (end) { *q = *end = 0; noff = r_num_math (core->num, q+2); r_buf_append_bytes (b, (const ut8*)str, strlen (str)); snprintf (tmp, sizeof (tmp), "0x%08"PFMT64x, noff); r_buf_append_bytes (b, (const ut8*)tmp, strlen (tmp)); r_buf_append_bytes (b, (const ut8*)end+1, strlen (end+1)); } } else r_buf_append_bytes (b, (const ut8*)str, strlen (str)); } s = r_buf_to_string (b); r_egg_load (core->egg, s, 0); free (s); r_egg_compile (core->egg); r_egg_assemble (core->egg); r_buf_free (b); b = r_egg_get_bin (core->egg); if (strcmp (off, "+")) noff = r_num_math (core->num, off); r_core_write_at (core, noff, b->buf, b->length); noff += b->length; r_buf_free (b); free (off); } break; case '"': p2 = strchr (p+1,'"'); if (p2) *p2=0; r_core_cmdf (core, "s %s", str); r_core_cmdf (core, "\"w %s\"", p+1); break; case ':': r_core_cmdf (core, "s %s", str); r_core_cmdf (core, "wa %s", p); break; default: r_core_cmdf (core, "s %s", str); r_core_cmdf (core, "wx %s", p); break; } } } fclose (fd); return 0; }