ut64 r_bin_mz_get_main_vaddr(struct r_bin_mz_obj_t *bin) { int entry; int n; ut8 b[512]; if (!bin || !bin->b) { return 0LL; } entry = r_bin_mz_get_entrypoint (bin); ZERO_FILL (b); if (r_buf_read_at (bin->b, entry, b, sizeof (b)) < 0) { eprintf ("Warning: Cannot read entry at 0x%08"PFMT32x "\n", (ut32) entry); return 0LL; } // MSVC if (b[0] == 0xb4 && b[1] == 0x30) { // ff 36 XX XX push XXXX // ff 36 XX XX push argv // ff 36 XX XX push argc // 9a XX XX XX XX lcall _main // 50 push ax for (n = 0; n < sizeof (b) - 18; n++) { if (b[n] == 0xff && b[n + 4] == 0xff && b[n + 8] == 0xff && b[n + 12] == 0x9a && b[n + 17] == 0x50) { const ut16 call_addr = r_read_ble16 (b + n + 13, 0);; const ut16 call_seg = r_read_ble16 (b + n + 15, 0);; const ut64 call_dst = r_bin_mz_seg_to_paddr (bin, call_seg) + call_addr; return call_dst; } } } return 0LL; }
int r_bin_mz_get_entrypoint (const struct r_bin_mz_obj_t *bin) { #if 0 ut16 cs = r_read_ble16 (buf + 0x16, false); ut16 ip = r_read_ble16 (buf + 0x14, false); ut16 pa = ((r_read_ble16 (buf + 8 , false) + cs) << 4) + ip; #endif /* Value of CS in DOS header may be negative */ const short cs = bin->dos_header->cs; ut32 pa = bin->dos_header->header_paragraphs + cs; const ut32 paddr = (pa<<4) + bin->dos_header->ip; if (paddr < bin->dos_file_size) { return paddr; } return -1; }
static bool checkEntrypoint(const ut8 *buf, ut64 length) { st16 cs = r_read_ble16 (buf + 0x16, false); ut16 ip = r_read_ble16 (buf + 0x14, false); ut32 pa = ((r_read_ble16 (buf + 8 , false) + cs) << 4) + ip; /* A minimal MZ header is 0x1B bytes. Header length is measured in * 16-byte paragraphs so the minimum header must occupy 2 paragraphs. * This means that the entrypoint should be at least 0x20 unless someone * cleverly fit a few instructions inside the header. */ pa &= 0xffff; if (pa >= 0x20 && pa + 1 < length) { ut16 pe = r_read_ble16 (buf + 0x3c, false); if (pe < length && length > 0x104 && !memcmp (buf + pe, "PE", 2)) { return false; } return true; } return false; }
static int riscv_op(RAnal *anal, RAnalOp *op, ut64 addr, const ut8 *data, int len) { const int no_alias = 1; struct riscv_opcode *o = NULL; ut64 word = 0; int xlen = anal->bits; op->size = 4; op->addr = addr; op->type = R_ANAL_OP_TYPE_UNK; word = (len >= sizeof (ut64))? r_read_ble64 (data, anal->big_endian): r_read_ble16 (data, anal->big_endian); o = get_opcode (word); if (word == UT64_MAX) { op->type = R_ANAL_OP_TYPE_ILL; return -1; } if (!o || !o->name) return op->size; for (; o < &riscv_opcodes[NUMOPCODES]; o++) { // XXX ASAN segfault if ( !(o->match_func)(o, word) ) continue; if ( no_alias && (o->pinfo & INSN_ALIAS) ) continue; if ( isdigit ((int)(o->subset[0])) && atoi (o->subset) != xlen) continue; else { break; } } if (!o || !o->name) { return -1; } // branch/jumps/calls/rets if (is_any ("jal")) { // decide wether it's ret or call int rd = (word >> OP_SH_RD) & OP_MASK_RD; op->type = (rd == 0) ? R_ANAL_OP_TYPE_RET: R_ANAL_OP_TYPE_CALL; op->jump = EXTRACT_UJTYPE_IMM (word) + addr; op->fail = addr + 4; } else if (is_any ("jr")) {
static bool check_bytes(const ut8 *buf, ut64 length) { ut16 new_exe_header_offset; if (!buf || length <= 0x3d) { return false; } // Check for MZ magic. if (memcmp (buf, "MZ", 2) && memcmp (buf, "ZM", 2)) { return false; } // See if there is a new exe header. new_exe_header_offset = r_read_ble16 (buf + 0x3c, false); if (length > new_exe_header_offset + 2) { // check for PE if (!memcmp (buf + new_exe_header_offset, "PE", 2) && (length > new_exe_header_offset + 0x20) && !memcmp (buf + new_exe_header_offset + 0x18, "\x0b\x01", 2)) { return false; } // Check for New Executable, LE/LX or Phar Lap executable if (!memcmp (buf + new_exe_header_offset, "NE", 2) || !memcmp (buf + new_exe_header_offset, "LE", 2) || !memcmp (buf + new_exe_header_offset, "LX", 2) || !memcmp (buf + new_exe_header_offset, "PL", 2)) { if (!checkEntrypoint (buf, length)) { return false; } } } // Raw plain MZ executable (watcom) if (!checkEntrypoint (buf, length)) { return false; } return true; }
static int r_buf_fcpy_at (RBuffer *b, ut64 addr, ut8 *buf, const char *fmt, int n, int write) { ut64 len, check_len; int i, j, k, tsize, bigendian, m = 1; if (!b || b->empty) return 0; if (b->fd != -1) { eprintf ("r_buf_fcpy_at not supported yet for r_buf_new_file\n"); return 0; } if (addr == R_BUF_CUR) addr = b->cur; else addr -= b->base; if (addr == UT64_MAX || addr > b->length) return -1; tsize = 2; for (i = len = 0; i < n; i++) for (j = 0; fmt[j]; j++) { switch (fmt[j]) { #ifdef _MSC_VER case'0':case'1':case'2':case'3':case'4':case'5':case'6':case'7':case'8':case'9': #else case '0'...'9': #endif if (m == 1) m = r_num_get (NULL, &fmt[j]); continue; case 's': tsize = 2; bigendian = 0; break; case 'S': tsize = 2; bigendian = 1; break; case 'i': tsize = 4; bigendian = 0; break; case 'I': tsize = 4; bigendian = 1; break; case 'l': tsize = 8; bigendian = 0; break; case 'L': tsize = 8; bigendian = 1; break; case 'c': tsize = 1; bigendian = 0; break; default: return -1; } /* Avoid read/write out of bound. tsize and m are not user controled, then don't need to check possible overflow. */ if (!UT64_ADD (&check_len, len, tsize*m)) return -1; if (!UT64_ADD (&check_len, check_len, addr)) return -1; if (check_len > b->length) { return check_len; // return -1; } for (k = 0; k < m; k++) { ut8* src1 = &b->buf[len+(k*tsize)]; ut8* src2 = &b->buf[addr+len+(k*tsize)]; void* dest1 = &buf[addr+len+(k*tsize)]; void* dest2 = &buf[len+(k*tsize)]; ut8* dest1_8 = (ut8*)dest1; ut16* dest1_16 = (ut16*)dest1; ut32* dest1_32 = (ut32*)dest1; ut64* dest1_64 = (ut64*)dest1; ut8* dest2_8 = (ut8*)dest2; ut16* dest2_16 = (ut16*)dest2; ut32* dest2_32 = (ut32*)dest2; ut64* dest2_64 = (ut64*)dest2; if (write) { switch (tsize) { case 1: *dest1_8 = r_read_ble8 (src1); break; case 2: *dest1_16 = r_read_ble16 (src1, bigendian); break; case 4: *dest1_32 = r_read_ble32 (src1, bigendian); break; case 8: *dest1_64 = r_read_ble64 (src1, bigendian); break; } } else { switch (tsize) { case 1: *dest2_8 = r_read_ble8 (src2); break; case 2: *dest2_16 = r_read_ble16 (src2, bigendian); break; case 4: *dest2_32 = r_read_ble32 (src2, bigendian); break; case 8: *dest2_64 = r_read_ble64 (src2, bigendian); break; } } } len += tsize * m; m = 1; } b->cur = addr + len; return len; }
R_API ut64 r_reg_get_value(RReg *reg, RRegItem *item) { RRegSet *regset; int off; ut64 ret = 0LL; if (!reg || !item) { return 0LL; } off = BITS2BYTES (item->offset); regset = ®->regset[item->arena]; switch (item->size) { case 1: { int offset = item->offset / 8; if (offset + item->size >= regset->arena->size) { break; } ret = (regset->arena->bytes[offset] & (1 << (item->offset % 8))) ? 1 : 0; } break; case 4: if (regset->arena->size - off - 1 >= 0) { ret = (r_read_at_ble8 (regset->arena->bytes, off)) & 0xF; } break; case 8: if (regset->arena->size - off - 1 >= 0) { ret = r_read_at_ble8 (regset->arena->bytes, off); } break; case 16: if (regset->arena->size - off - 2 >= 0) { ret = r_read_ble16 (regset->arena->bytes + off, reg->big_endian); } break; case 27: if (off + 3 < regset->arena->size) { ret = r_read_me27 (regset->arena->bytes + off, 0); } break; case 32: if (off + 4 <= regset->arena->size) { ret = r_read_ble32 (regset->arena->bytes + off, reg->big_endian); } else { eprintf ("r_reg_get_value: 32bit oob read %d\n", off); } break; case 64: if (regset->arena->bytes && (off + 8 <= regset->arena->size)) { ret = r_read_ble64 (regset->arena->bytes + off, reg->big_endian); } else { eprintf ("r_reg_get_value: null or oob arena for current regset\n"); } break; case 80: // long double case 96: // long floating value // FIXME: It is a precision loss, please implement me properly! ret = (ut64)r_reg_get_longdouble (reg, item); break; default: eprintf ("r_reg_get_value: Bit size %d not supported\n", item->size); break; } return ret; }