static char *getarg2(struct Getarg *gop, int n, const char *setstr) { csh handle = gop->handle; cs_insn *insn = gop->insn; cs_ppc_op op; static char words[3][64]; if (n<0 || n>=3) return NULL; op = INSOP (n); switch (op.type) { case PPC_OP_INVALID: strcpy (words[n], "invalid"); break; case PPC_OP_REG: snprintf (words[n], sizeof (words[n]), "%s%s", cs_reg_name (handle, op.reg), setstr); break; case PPC_OP_IMM: snprintf (words[n], sizeof (words[n]), "0x%"PFMT64x"%s", (ut64)(ut32)op.imm, setstr); break; case PPC_OP_MEM: snprintf (words[n], sizeof (words[n]), "%"PFMT64d",%s,+,%s", (ut64)op.mem.disp, cs_reg_name (handle, op.mem.base), setstr); break; case PPC_OP_CRX: // Condition Register field words[n][0] = 0; break; } return words[n]; }
static const char *arg(csh *handle, cs_insn *insn, char *buf, int n) { *buf = 0; switch (insn->detail->mips.operands[n].type) { case MIPS_OP_INVALID: break; case MIPS_OP_REG: sprintf (buf, "%s", cs_reg_name (*handle, insn->detail->mips.operands[n].reg)); break; case MIPS_OP_IMM: { st64 x = (st64)insn->detail->mips.operands[n].imm; sprintf (buf, "%"PFMT64d, x); } break; case MIPS_OP_MEM: { int disp = insn->detail->mips.operands[n].mem.disp; if (disp<0) { sprintf (buf, "%"PFMT64d",%s,-", (ut64)-insn->detail->mips.operands[n].mem.disp, cs_reg_name (*handle, insn->detail->mips.operands[n].mem.base)); } else { sprintf (buf, "%s,%"PFMT64d",+", cs_reg_name (*handle, insn->detail->mips.operands[n].mem.base), (ut64)insn->detail->mips.operands[n].mem.disp); } } break; } return buf; }
static void print_insn_detail(cs_insn *ins) { cs_mips *mips = &(ins->mips); if (mips->op_count) printf("\top_count: %u\n", mips->op_count); int i; for (i = 0; i < mips->op_count; i++) { cs_mips_op *op = &(mips->operands[i]); switch((int)op->type) { default: break; case MIPS_OP_REG: printf("\t\toperands[%u].type: REG = %s\n", i, cs_reg_name(handle, op->reg)); break; case MIPS_OP_IMM: printf("\t\toperands[%u].type: IMM = 0x%"PRIx64 "\n", i, op->imm); break; case MIPS_OP_MEM: printf("\t\toperands[%u].type: MEM\n", i); if (op->mem.base != X86_REG_INVALID) printf("\t\t\toperands[%u].mem.base: REG = %s\n", i, cs_reg_name(handle, op->mem.base)); if (op->mem.disp != 0) printf("\t\t\toperands[%u].mem.disp: 0x%" PRIx64 "\n", i, op->mem.disp); break; } } printf("\n"); }
static void print_insn_detail(cs_insn *ins) { cs_arm64 *arm64 = &(ins->detail->arm64); int i; if (arm64->op_count) printf("\top_count: %u\n", arm64->op_count); for (i = 0; i < arm64->op_count; i++) { cs_arm64_op *op = &(arm64->operands[i]); switch(op->type) { default: break; case ARM64_OP_REG: printf("\t\toperands[%u].type: REG = %s\n", i, cs_reg_name(handle, op->reg)); break; case ARM64_OP_IMM: printf("\t\toperands[%u].type: IMM = 0x%x\n", i, op->imm); break; case ARM64_OP_FP: printf("\t\toperands[%u].type: FP = %f\n", i, op->fp); break; case ARM64_OP_MEM: printf("\t\toperands[%u].type: MEM\n", i); if (op->mem.base != ARM64_REG_INVALID) printf("\t\t\toperands[%u].mem.base: REG = %s\n", i, cs_reg_name(handle, op->mem.base)); if (op->mem.index != ARM64_REG_INVALID) printf("\t\t\toperands[%u].mem.index: REG = %s\n", i, cs_reg_name(handle, op->mem.index)); if (op->mem.disp != 0) printf("\t\t\toperands[%u].mem.disp: 0x%x\n", i, op->mem.disp); break; case ARM64_OP_CIMM: printf("\t\toperands[%u].type: C-IMM = %u\n", i, op->imm); break; } if (op->shift.type != ARM64_SFT_INVALID && op->shift.value) printf("\t\t\tShift: type = %u, value = %u\n", op->shift.type, op->shift.value); if (op->ext != ARM64_EXT_INVALID) printf("\t\t\tExt: %u\n", op->ext); } if (arm64->cc != ARM64_CC_INVALID) printf("\tCode condition: %u\n", arm64->cc); if (arm64->update_flags) printf("\tUpdate-flags: True\n"); if (arm64->writeback) printf("\tWrite-back: True\n"); printf("\n"); }
char *get_detail_sysz(csh *handle, cs_mode mode, cs_insn *ins) { cs_sysz *sysz; int i; char *result; result = (char *)malloc(sizeof(char)); result[0] = '\0'; if (ins->detail == NULL) return result; sysz = &(ins->detail->sysz); if (sysz->op_count) add_str(&result, " ; op_count: %u", sysz->op_count); for (i = 0; i < sysz->op_count; i++) { cs_sysz_op *op = &(sysz->operands[i]); switch((int)op->type) { default: break; case SYSZ_OP_REG: add_str(&result, " ; operands[%u].type: REG = %s", i, cs_reg_name(*handle, op->reg)); break; case SYSZ_OP_ACREG: add_str(&result, " ; operands[%u].type: ACREG = %u", i, op->reg); break; case SYSZ_OP_IMM: add_str(&result, " ; operands[%u].type: IMM = 0x%" PRIx64 "", i, op->imm); break; case SYSZ_OP_MEM: add_str(&result, " ; operands[%u].type: MEM", i); if (op->mem.base != SYSZ_REG_INVALID) add_str(&result, " ; operands[%u].mem.base: REG = %s", i, cs_reg_name(*handle, op->mem.base)); if (op->mem.index != SYSZ_REG_INVALID) add_str(&result, " ; operands[%u].mem.index: REG = %s", i, cs_reg_name(*handle, op->mem.index)); if (op->mem.length != 0) add_str(&result, " ; operands[%u].mem.length: 0x%" PRIx64 "", i, op->mem.length); if (op->mem.disp != 0) add_str(&result, " ; operands[%u].mem.disp: 0x%" PRIx64 "", i, op->mem.disp); break; } } if (sysz->cc != 0) add_str(&result, " ; Code condition: %u", sysz->cc); return result; }
static void print_insn_detail(cs_insn *ins) { cs_sysz *sysz; int i; // detail can be NULL on "data" instruction if SKIPDATA option is turned ON if (ins->detail == NULL) return; sysz = &(ins->detail->sysz); if (sysz->op_count) printf("\top_count: %u\n", sysz->op_count); for (i = 0; i < sysz->op_count; i++) { cs_sysz_op *op = &(sysz->operands[i]); switch((int)op->type) { default: break; case SYSZ_OP_REG: printf("\t\toperands[%u].type: REG = %s\n", i, cs_reg_name(handle, op->reg)); break; case SYSZ_OP_ACREG: printf("\t\toperands[%u].type: ACREG = %u\n", i, op->reg); break; case SYSZ_OP_IMM: printf("\t\toperands[%u].type: IMM = 0x%"PRIx64"\n", i, op->imm); break; case SYSZ_OP_MEM: printf("\t\toperands[%u].type: MEM\n", i); if (op->mem.base != SYSZ_REG_INVALID) printf("\t\t\toperands[%u].mem.base: REG = %s\n", i, cs_reg_name(handle, op->mem.base)); if (op->mem.index != SYSZ_REG_INVALID) printf("\t\t\toperands[%u].mem.index: REG = %s\n", i, cs_reg_name(handle, op->mem.index)); if (op->mem.length != 0) printf("\t\t\toperands[%u].mem.length: 0x%"PRIx64"\n", i, op->mem.length); if (op->mem.disp != 0) printf("\t\t\toperands[%u].mem.disp: 0x%"PRIx64"\n", i, op->mem.disp); break; } } if (sysz->cc != 0) printf("\tCode condition: %u\n", sysz->cc); printf("\n"); }
static void opex(RStrBuf *buf, csh handle, cs_insn *insn) { int i; r_strbuf_init (buf); r_strbuf_append (buf, "{"); cs_m68k *x = &insn->detail->m68k; r_strbuf_append (buf, "\"operands\":["); for (i = 0; i < x->op_count; i++) { cs_m68k_op *op = &x->operands[i]; if (i > 0) { r_strbuf_append (buf, ","); } r_strbuf_append (buf, "{"); switch (op->type) { case M68K_OP_REG: r_strbuf_append (buf, "\"type\":\"reg\""); r_strbuf_appendf (buf, ",\"value\":\"%s\"", cs_reg_name (handle, op->reg)); break; case M68K_OP_IMM: r_strbuf_append (buf, "\"type\":\"imm\""); r_strbuf_appendf (buf, ",\"value\":%"PFMT64d, op->imm); break; case M68K_OP_MEM: r_strbuf_append (buf, "\"type\":\"mem\""); if (op->mem.base_reg != M68K_REG_INVALID) { r_strbuf_appendf (buf, ",\"base_reg\":\"%s\"", cs_reg_name (handle, op->mem.base_reg)); } if (op->mem.index_reg != M68K_REG_INVALID) { r_strbuf_appendf (buf, ",\"base_reg\":\"%s\"", cs_reg_name (handle, op->mem.index_reg)); } if (op->mem.in_base_reg != M68K_REG_INVALID) { r_strbuf_appendf (buf, ",\"base_reg\":\"%s\"", cs_reg_name (handle, op->mem.in_base_reg)); } r_strbuf_appendf (buf, ",\"in_disp\":%"PFMT64d"", op->mem.in_disp); r_strbuf_appendf (buf, ",\"out_disp\":%"PFMT64d"", op->mem.out_disp); r_strbuf_appendf (buf, ",\"disp\":%"PFMT64d"", (st64)op->mem.disp); r_strbuf_appendf (buf, ",\"scale\":%"PFMT64d"", (st64)op->mem.scale); r_strbuf_appendf (buf, ",\"bitfield\":%"PFMT64d"", (st64)op->mem.bitfield); r_strbuf_appendf (buf, ",\"width\":%"PFMT64d"", (st64)op->mem.width); r_strbuf_appendf (buf, ",\"offset\":%"PFMT64d"", (st64)op->mem.offset); r_strbuf_appendf (buf, ",\"index_size\":%"PFMT64d"", (st64)op->mem.index_size); break; default: r_strbuf_append (buf, "\"type\":\"invalid\""); break; } r_strbuf_append (buf, "}"); } r_strbuf_append (buf, "]}"); }
static const char *arg(RAnal *a, csh *handle, cs_insn *insn, char *buf, int n) { buf[0] = 0; switch (insn->detail->arm.operands[n].type) { case ARM_OP_REG: sprintf (buf, "%s", cs_reg_name (*handle, insn->detail->arm.operands[n].reg)); break; case ARM_OP_IMM: if (a->bits == 64) { // 64bit only sprintf (buf, "%"PFMT64d, (ut64) insn->detail->arm.operands[n].imm); } else { // 32bit only sprintf (buf, "%"PFMT64d, (ut64)(ut32) insn->detail->arm.operands[n].imm); } break; case ARM_OP_MEM: // TODO break; default: break; } return buf; }
static void print_insn_detail(cs_insn *ins) { cs_sparc *sparc; int i; // detail can be NULL on "data" instruction if SKIPDATA option is turned ON if (ins->detail == NULL) return; sparc = &(ins->detail->sparc); if (sparc->op_count) printf("\top_count: %u\n", sparc->op_count); for (i = 0; i < sparc->op_count; i++) { cs_sparc_op *op = &(sparc->operands[i]); switch((int)op->type) { default: break; case SPARC_OP_REG: printf("\t\toperands[%u].type: REG = %s\n", i, cs_reg_name(handle, op->reg)); break; case SPARC_OP_IMM: printf("\t\toperands[%u].type: IMM = 0x%x\n", i, op->imm); break; case SPARC_OP_MEM: printf("\t\toperands[%u].type: MEM\n", i); if (op->mem.base != X86_REG_INVALID) printf("\t\t\toperands[%u].mem.base: REG = %s\n", i, cs_reg_name(handle, op->mem.base)); if (op->mem.index != X86_REG_INVALID) printf("\t\t\toperands[%u].mem.index: REG = %s\n", i, cs_reg_name(handle, op->mem.index)); if (op->mem.disp != 0) printf("\t\t\toperands[%u].mem.disp: 0x%x\n", i, op->mem.disp); break; } } if (sparc->cc != 0) printf("\tCode condition: %u\n", sparc->cc); if (sparc->hint != 0) printf("\tHint code: %u\n", sparc->hint); printf("\n"); }
static int parse_reg_name(RRegItem *reg, csh handle, cs_insn *insn, int reg_num) { if (!reg) { return -1; } switch (OPERAND (reg_num).type) { case MIPS_OP_REG: reg->name = (char *)cs_reg_name (handle, OPERAND (reg_num).reg); break; case MIPS_OP_MEM: if (OPERAND (reg_num).mem.base != MIPS_REG_INVALID) { reg->name = (char *)cs_reg_name (handle, OPERAND (reg_num).mem.base); } default: break; } return 0; }
char *get_detail_xcore(csh *handle, cs_mode mode, cs_insn *ins) { cs_xcore *xcore; int i; char *result; result = (char *)malloc(sizeof(char)); result[0] = '\0'; if (ins->detail == NULL) return result; xcore = &(ins->detail->xcore); if (xcore->op_count) add_str(&result, " ; op_count: %u", xcore->op_count); for (i = 0; i < xcore->op_count; i++) { cs_xcore_op *op = &(xcore->operands[i]); switch((int)op->type) { default: break; case XCORE_OP_REG: add_str(&result, " ; operands[%u].type: REG = %s", i, cs_reg_name(*handle, op->reg)); break; case XCORE_OP_IMM: add_str(&result, " ; operands[%u].type: IMM = 0x%x", i, op->imm); break; case XCORE_OP_MEM: add_str(&result, " ; operands[%u].type: MEM", i); if (op->mem.base != XCORE_REG_INVALID) add_str(&result, " ; operands[%u].mem.base: REG = %s", i, cs_reg_name(*handle, op->mem.base)); if (op->mem.index != XCORE_REG_INVALID) add_str(&result, " ; operands[%u].mem.index: REG = %s", i, cs_reg_name(*handle, op->mem.index)); if (op->mem.disp != 0) add_str(&result, " ; operands[%u].mem.disp: 0x%x", i, op->mem.disp); if (op->mem.direct != 1) add_str(&result, " ; operands[%u].mem.direct: -1", i); break; } } return result; }
static int parse_reg_name(RRegItem *reg, csh handle, cs_insn *insn, int reg_num) { if (!reg) { return -1; } switch (INSOP (reg_num).type) { case PPC_OP_REG: reg->name = (char *)cs_reg_name (handle, INSOP (reg_num).reg); break; case PPC_OP_MEM: if (INSOP (reg_num).mem.base != PPC_REG_INVALID) { reg->name = (char *)cs_reg_name (handle, INSOP (reg_num).mem.base); } break; default : break; } return 0; }
static void print_read_write_regs(cs_detail* detail) { int i; for (i = 0; i < detail->regs_read_count; ++i) { uint16_t reg_id = detail->regs_read[i]; const char* reg_name = cs_reg_name(handle, reg_id); printf("\treading from reg: %s\n", reg_name); } for (i = 0; i < detail->regs_write_count; ++i) { uint16_t reg_id = detail->regs_write[i]; const char* reg_name = cs_reg_name(handle, reg_id); printf("\twriting to reg: %s\n", reg_name); } }
static void print_insn_detail(cs_insn *ins) { int i; cs_mips *mips; // detail can be NULL on "data" instruction if SKIPDATA option is turned ON if (ins->detail == NULL) return; mips = &(ins->detail->mips); if (mips->op_count) printf("\top_count: %u\n", mips->op_count); for (i = 0; i < mips->op_count; i++) { cs_mips_op *op = &(mips->operands[i]); switch((int)op->type) { default: break; case MIPS_OP_REG: printf("\t\toperands[%u].type: REG = %s\n", i, cs_reg_name(handle, op->reg)); break; case MIPS_OP_IMM: printf("\t\toperands[%u].type: IMM = 0x%"PRIx64 "\n", i, op->imm); break; case MIPS_OP_MEM: printf("\t\toperands[%u].type: MEM\n", i); if (op->mem.base != X86_REG_INVALID) printf("\t\t\toperands[%u].mem.base: REG = %s\n", i, cs_reg_name(handle, op->mem.base)); if (op->mem.disp != 0) printf("\t\t\toperands[%u].mem.disp: 0x%" PRIx64 "\n", i, op->mem.disp); break; } } printf("\n"); }
static void opex(RStrBuf *buf, csh handle, cs_insn *insn) { int i; r_strbuf_init (buf); r_strbuf_append (buf, "{"); cs_sysz *x = &insn->detail->sysz; r_strbuf_append (buf, "\"operands\":["); for (i = 0; i < x->op_count; i++) { cs_sysz_op *op = &x->operands[i]; if (i > 0) { r_strbuf_append (buf, ","); } r_strbuf_append (buf, "{"); switch (op->type) { case SYSZ_OP_REG: r_strbuf_append (buf, "\"type\":\"reg\""); r_strbuf_appendf (buf, ",\"value\":\"%s\"", cs_reg_name (handle, op->reg)); break; case SYSZ_OP_IMM: r_strbuf_append (buf, "\"type\":\"imm\""); r_strbuf_appendf (buf, ",\"value\":%"PFMT64d, op->imm); break; case SYSZ_OP_MEM: r_strbuf_append (buf, "\"type\":\"mem\""); if (op->mem.base != SYSZ_REG_INVALID) { r_strbuf_appendf (buf, ",\"base\":\"%s\"", cs_reg_name (handle, op->mem.base)); } r_strbuf_appendf (buf, ",\"index\":%"PFMT64d"", (st64) op->mem.index); r_strbuf_appendf (buf, ",\"length\":%"PFMT64d"", (st64) op->mem.length); r_strbuf_appendf (buf, ",\"disp\":%"PFMT64d"", (st64) op->mem.disp); break; default: r_strbuf_append (buf, "\"type\":\"invalid\""); break; } r_strbuf_append (buf, "}"); } r_strbuf_append (buf, "]}"); }
void print_insn_detail_riscv(csh handle, cs_insn *ins) { cs_riscv *riscv; int i; // detail can be NULL on "data" instruction if SKIPDATA option is turned ON if (ins->detail == NULL) return; riscv = &(ins->detail->riscv); if (riscv->op_count) printf("\top_count: %u\n", riscv->op_count); for (i = 0; i < riscv->op_count; i++) { cs_riscv_op *op = &(riscv->operands[i]); switch((int)op->type) { default: break; case RISCV_OP_REG: printf("\t\toperands[%u].type: REG = %s\n", i, cs_reg_name(handle, op->reg)); break; case RISCV_OP_IMM: printf("\t\toperands[%u].type: IMM = 0x%lx\n", i, (long)op->imm); break; case RISCV_OP_MEM: printf("\t\toperands[%u].type: MEM\n", i); if (op->mem.base != RISCV_REG_INVALID) printf("\t\t\toperands[%u].mem.base: REG = %s\n", i, cs_reg_name(handle, op->mem.base)); if (op->mem.disp != 0) printf("\t\t\toperands[%u].mem.disp: 0x%lx\n", i, (long)op->mem.disp); break; } } printf("\n"); }
static void print_read_write_regs(csh handle, cs_detail *detail) { int i; if (detail->regs_read_count > 0) { printf("\tRegisters read:"); for (i = 0; i < detail->regs_read_count; ++i) printf(" %s", cs_reg_name(handle, detail->regs_read[i])); printf("\n"); } if (detail->regs_write_count > 0) { printf("\tRegisters modified:"); for (i = 0; i < detail->regs_write_count; ++i) printf(" %s", cs_reg_name(handle, detail->regs_write[i])); printf("\n"); } }
static const char *arg(csh *handle, cs_insn *insn, char *buf, int n) { switch (insn->detail->arm.operands[n].type) { case ARM_OP_REG: sprintf (buf, "%s", cs_reg_name (*handle, insn->detail->arm.operands[n].reg)); break; case ARM_OP_IMM: sprintf (buf, "%d", insn->detail->arm.operands[n].imm); break; case ARM_OP_MEM: // TODO break; } return buf; }
char *get_detail_mos65xx(csh *handle, cs_mode mode, cs_insn *ins) { int i; cs_mos65xx *mos65xx; char *result; result = (char *)malloc(sizeof(char)); result[0] = '\0'; if (ins->detail == NULL) return result; mos65xx = &(ins->detail->mos65xx); add_str(&result, " ; address mode: %s", get_am_name(mos65xx->am)); add_str(&result, " ; modifies flags: %s", mos65xx->modifies_flags ? "true": "false"); if (mos65xx->op_count) add_str(&result, " ; op_count: %u", mos65xx->op_count); for (i = 0; i < mos65xx->op_count; i++) { cs_mos65xx_op *op = &(mos65xx->operands[i]); switch((int)op->type) { default: break; case MOS65XX_OP_REG: add_str(&result, " ; operands[%u].type: REG = %s", i, cs_reg_name(*handle, op->reg)); break; case MOS65XX_OP_IMM: add_str(&result, " ; operands[%u].type: IMM = 0x%x", i, op->imm); break; case MOS65XX_OP_MEM: add_str(&result, " ; operands[%u].type: MEM = 0x%x", i, op->mem); break; } } return result; }
static void print_insn_detail(cs_insn *ins) { cs_arm *arm; int i; // detail can be NULL on "data" instruction if SKIPDATA option is turned ON if (ins->detail == NULL) return; arm = &(ins->detail->arm); if (arm->op_count) printf("\top_count: %u\n", arm->op_count); for (i = 0; i < arm->op_count; i++) { cs_arm_op *op = &(arm->operands[i]); switch((int)op->type) { default: break; case ARM_OP_REG: printf("\t\toperands[%u].type: REG = %s\n", i, cs_reg_name(handle, op->reg)); break; case ARM_OP_IMM: printf("\t\toperands[%u].type: IMM = 0x%x\n", i, op->imm); break; case ARM_OP_FP: #if defined(_KERNEL_MODE) // Issue #681: Windows kernel does not support formatting float point printf("\t\toperands[%u].type: FP = <float_point_unsupported>\n", i); #else printf("\t\toperands[%u].type: FP = %f\n", i, op->fp); #endif break; case ARM_OP_MEM: printf("\t\toperands[%u].type: MEM\n", i); if (op->mem.base != X86_REG_INVALID) printf("\t\t\toperands[%u].mem.base: REG = %s\n", i, cs_reg_name(handle, op->mem.base)); if (op->mem.index != X86_REG_INVALID) printf("\t\t\toperands[%u].mem.index: REG = %s\n", i, cs_reg_name(handle, op->mem.index)); if (op->mem.scale != 1) printf("\t\t\toperands[%u].mem.scale: %u\n", i, op->mem.scale); if (op->mem.disp != 0) printf("\t\t\toperands[%u].mem.disp: 0x%x\n", i, op->mem.disp); break; case ARM_OP_PIMM: printf("\t\toperands[%u].type: P-IMM = %u\n", i, op->imm); break; case ARM_OP_CIMM: printf("\t\toperands[%u].type: C-IMM = %u\n", i, op->imm); break; case ARM_OP_SETEND: printf("\t\toperands[%u].type: SETEND = %s\n", i, op->setend == ARM_SETEND_BE? "be" : "le"); break; case ARM_OP_SYSREG: printf("\t\toperands[%u].type: SYSREG = %u\n", i, op->reg); break; } if (op->shift.type != ARM_SFT_INVALID && op->shift.value) { if (op->shift.type < ARM_SFT_ASR_REG) // shift with constant value printf("\t\t\tShift: %u = %u\n", op->shift.type, op->shift.value); else // shift with register printf("\t\t\tShift: %u = %s\n", op->shift.type, cs_reg_name(handle, op->shift.value)); } if (op->vector_index != -1) { printf("\t\toperands[%u].vector_index = %u\n", i, op->vector_index); } if (op->subtracted) printf("\t\tSubtracted: True\n"); } if (arm->cc != ARM_CC_AL && arm->cc != ARM_CC_INVALID) printf("\tCode condition: %u\n", arm->cc); if (arm->update_flags) printf("\tUpdate-flags: True\n"); if (arm->writeback) printf("\tWrite-back: True\n"); if (arm->cps_mode) printf("\tCPSI-mode: %u\n", arm->cps_mode); if (arm->cps_flag) printf("\tCPSI-flag: %u\n", arm->cps_flag); if (arm->vector_data) printf("\tVector-data: %u\n", arm->vector_data); if (arm->vector_size) printf("\tVector-size: %u\n", arm->vector_size); if (arm->usermode) printf("\tUser-mode: True\n"); if (arm->mem_barrier) printf("\tMemory-barrier: %u\n", arm->mem_barrier); printf("\n"); }
const char* Capstone::RegName(x86_reg reg) const { return cs_reg_name(mHandle, reg); }
static void print_insn_detail(cs_insn *ins) { cs_arm64 *arm64; int i; cs_regs regs_read, regs_write; uint8_t regs_read_count, regs_write_count; // detail can be NULL if SKIPDATA option is turned ON if (ins->detail == NULL) return; arm64 = &(ins->detail->arm64); if (arm64->op_count) printf("\top_count: %u\n", arm64->op_count); for (i = 0; i < arm64->op_count; i++) { cs_arm64_op *op = &(arm64->operands[i]); switch(op->type) { default: break; case ARM64_OP_REG: printf("\t\toperands[%u].type: REG = %s\n", i, cs_reg_name(handle, op->reg)); break; case ARM64_OP_IMM: printf("\t\toperands[%u].type: IMM = 0x%"PRIx64 "\n", i, op->imm); break; case ARM64_OP_FP: printf("\t\toperands[%u].type: FP = %f\n", i, op->fp); break; case ARM64_OP_MEM: printf("\t\toperands[%u].type: MEM\n", i); if (op->mem.base != ARM64_REG_INVALID) printf("\t\t\toperands[%u].mem.base: REG = %s\n", i, cs_reg_name(handle, op->mem.base)); if (op->mem.index != ARM64_REG_INVALID) printf("\t\t\toperands[%u].mem.index: REG = %s\n", i, cs_reg_name(handle, op->mem.index)); if (op->mem.disp != 0) printf("\t\t\toperands[%u].mem.disp: 0x%x\n", i, op->mem.disp); break; case ARM64_OP_CIMM: printf("\t\toperands[%u].type: C-IMM = %u\n", i, (int)op->imm); break; case ARM64_OP_REG_MRS: printf("\t\toperands[%u].type: REG_MRS = 0x%x\n", i, op->reg); break; case ARM64_OP_REG_MSR: printf("\t\toperands[%u].type: REG_MSR = 0x%x\n", i, op->reg); break; case ARM64_OP_PSTATE: printf("\t\toperands[%u].type: PSTATE = 0x%x\n", i, op->pstate); break; case ARM64_OP_SYS: printf("\t\toperands[%u].type: SYS = 0x%x\n", i, op->sys); break; case ARM64_OP_PREFETCH: printf("\t\toperands[%u].type: PREFETCH = 0x%x\n", i, op->prefetch); break; case ARM64_OP_BARRIER: printf("\t\toperands[%u].type: BARRIER = 0x%x\n", i, op->barrier); break; } uint8_t access = op->access; switch(access) { default: break; case CS_AC_READ: printf("\t\toperands[%u].access: READ\n", i); break; case CS_AC_WRITE: printf("\t\toperands[%u].access: WRITE\n", i); break; case CS_AC_READ | CS_AC_WRITE: printf("\t\toperands[%u].access: READ | WRITE\n", i); break; } if (op->shift.type != ARM64_SFT_INVALID && op->shift.value) printf("\t\t\tShift: type = %u, value = %u\n", op->shift.type, op->shift.value); if (op->ext != ARM64_EXT_INVALID) printf("\t\t\tExt: %u\n", op->ext); if (op->vas != ARM64_VAS_INVALID) printf("\t\t\tVector Arrangement Specifier: 0x%x\n", op->vas); if (op->vess != ARM64_VESS_INVALID) printf("\t\t\tVector Element Size Specifier: %u\n", op->vess); if (op->vector_index != -1) printf("\t\t\tVector Index: %u\n", op->vector_index); } if (arm64->update_flags) printf("\tUpdate-flags: True\n"); if (arm64->writeback) printf("\tWrite-back: True\n"); if (arm64->cc) printf("\tCode-condition: %u\n", arm64->cc); // Print out all registers accessed by this instruction (either implicit or explicit) if (!cs_regs_access(handle, ins, regs_read, ®s_read_count, regs_write, ®s_write_count)) { if (regs_read_count) { printf("\tRegisters read:"); for(i = 0; i < regs_read_count; i++) { printf(" %s", cs_reg_name(handle, regs_read[i])); } printf("\n"); } if (regs_write_count) { printf("\tRegisters modified:"); for(i = 0; i < regs_write_count; i++) { printf(" %s", cs_reg_name(handle, regs_write[i])); } printf("\n"); } } printf("\n"); }
static void print_insn_detail(cs_insn *ins) { cs_arm *arm = &(ins->detail->arm); if (arm->op_count) printf("\top_count: %u\n", arm->op_count); int i; for (i = 0; i < arm->op_count; i++) { cs_arm_op *op = &(arm->operands[i]); switch((int)op->type) { default: break; case ARM_OP_REG: printf("\t\toperands[%u].type: REG = %s\n", i, cs_reg_name(handle, op->reg)); break; case ARM_OP_IMM: printf("\t\toperands[%u].type: IMM = 0x%x\n", i, op->imm); break; case ARM_OP_FP: printf("\t\toperands[%u].type: FP = %f\n", i, op->fp); break; case ARM_OP_MEM: printf("\t\toperands[%u].type: MEM\n", i); if (op->mem.base != X86_REG_INVALID) printf("\t\t\toperands[%u].mem.base: REG = %s\n", i, cs_reg_name(handle, op->mem.base)); if (op->mem.index != X86_REG_INVALID) printf("\t\t\toperands[%u].mem.index: REG = %s\n", i, cs_reg_name(handle, op->mem.index)); if (op->mem.scale != 1) printf("\t\t\toperands[%u].mem.scale: %u\n", i, op->mem.scale); if (op->mem.disp != 0) printf("\t\t\toperands[%u].mem.disp: 0x%x\n", i, op->mem.disp); break; case ARM_OP_PIMM: printf("\t\toperands[%u].type: P-IMM = %u\n", i, op->imm); break; case ARM_OP_CIMM: printf("\t\toperands[%u].type: C-IMM = %u\n", i, op->imm); break; } if (op->shift.type != ARM_SFT_INVALID && op->shift.value) { if (op->shift.type < ARM_SFT_ASR_REG) // shift with constant value printf("\t\t\tShift: %u = %u\n", op->shift.type, op->shift.value); else // shift with register printf("\t\t\tShift: %u = %s\n", op->shift.type, cs_reg_name(handle, op->shift.value)); } } if (arm->cc != ARM_CC_AL && arm->cc != ARM_CC_INVALID) printf("\tCode condition: %u\n", arm->cc); if (arm->update_flags) printf("\tUpdate-flags: True\n"); if (arm->writeback) printf("\tWrite-back: True\n"); printf("\n"); }
static int analop(RAnal *a, RAnalOp *op, ut64 addr, const ut8 *buf, int len) { static int omode = 0; #if USE_ITER_API static #endif cs_insn *insn = NULL; int mode = (a->bits==64)? CS_MODE_64: (a->bits==32)? CS_MODE_32: (a->bits==16)? CS_MODE_16: 0; int n, ret; int regsz = 4; if (handle && mode != omode) { cs_close (&handle); handle = 0; } omode = mode; if (handle == 0) { ret = cs_open (CS_ARCH_X86, mode, &handle); if (ret != CS_ERR_OK) { handle = 0; return 0; } } #if 0 if (len>3 && !memcmp (buf, "\xff\xff\xff\xff", 4)) return 0; #endif switch (a->bits) { case 64: regsz = 8; break; case 16: regsz = 2; break; default: regsz = 4; break; // 32 } memset (op, '\0', sizeof (RAnalOp)); op->cycles = 1; // aprox op->type = R_ANAL_OP_TYPE_NULL; op->jump = UT64_MAX; op->fail = UT64_MAX; op->ptr = op->val = UT64_MAX; op->src[0] = NULL; op->src[1] = NULL; op->size = 0; op->delay = 0; r_strbuf_init (&op->esil); cs_option (handle, CS_OPT_DETAIL, CS_OPT_ON); // capstone-next #if USE_ITER_API { ut64 naddr = addr; size_t size = len; if (insn == NULL) insn = cs_malloc (handle); n = cs_disasm_iter (handle, (const uint8_t**)&buf, &size, (uint64_t*)&naddr, insn); } #else n = cs_disasm (handle, (const ut8*)buf, len, addr, 1, &insn); #endif struct Getarg gop = { .handle = handle, .insn = insn, .bits = a->bits }; if (n<1) { op->type = R_ANAL_OP_TYPE_ILL; } else { int rs = a->bits/8; const char *pc = (a->bits==16)?"ip": (a->bits==32)?"eip":"rip"; const char *sp = (a->bits==16)?"sp": (a->bits==32)?"esp":"rsp"; const char *bp = (a->bits==16)?"bp": (a->bits==32)?"ebp":"rbp"; op->size = insn->size; op->family = R_ANAL_OP_FAMILY_CPU; // almost everything is CPU op->prefix = 0; switch (insn->detail->x86.prefix[0]) { case X86_PREFIX_REPNE: op->prefix |= R_ANAL_OP_PREFIX_REPNE; break; case X86_PREFIX_REP: op->prefix |= R_ANAL_OP_PREFIX_REP; break; case X86_PREFIX_LOCK: op->prefix |= R_ANAL_OP_PREFIX_LOCK; break; } switch (insn->id) { case X86_INS_FNOP: op->family = R_ANAL_OP_FAMILY_FPU; /* fallthru */ case X86_INS_NOP: case X86_INS_PAUSE: op->type = R_ANAL_OP_TYPE_NOP; if (a->decode) esilprintf (op, ","); break; case X86_INS_HLT: op->type = R_ANAL_OP_TYPE_TRAP; break; case X86_INS_FBLD: case X86_INS_FBSTP: case X86_INS_FCOMPP: case X86_INS_FDECSTP: case X86_INS_FEMMS: case X86_INS_FFREE: case X86_INS_FICOM: case X86_INS_FICOMP: case X86_INS_FINCSTP: case X86_INS_FNCLEX: case X86_INS_FNINIT: case X86_INS_FNSTCW: case X86_INS_FNSTSW: case X86_INS_FPATAN: case X86_INS_FPREM: case X86_INS_FPREM1: case X86_INS_FPTAN: #if CS_API_MAJOR >=4 case X86_INS_FFREEP: #endif case X86_INS_FRNDINT: case X86_INS_FRSTOR: case X86_INS_FNSAVE: case X86_INS_FSCALE: case X86_INS_FSETPM: case X86_INS_FSINCOS: case X86_INS_FNSTENV: case X86_INS_FXAM: case X86_INS_FXSAVE: case X86_INS_FXSAVE64: case X86_INS_FXTRACT: case X86_INS_FYL2X: case X86_INS_FYL2XP1: case X86_INS_FISTTP: case X86_INS_FSQRT: case X86_INS_FXCH: op->family = R_ANAL_OP_FAMILY_FPU; op->type = R_ANAL_OP_TYPE_STORE; break; case X86_INS_FTST: case X86_INS_FUCOMPI: case X86_INS_FUCOMI: case X86_INS_FUCOMPP: case X86_INS_FUCOMP: case X86_INS_FUCOM: op->family = R_ANAL_OP_FAMILY_FPU; op->type = R_ANAL_OP_TYPE_CMP; break; case X86_INS_FABS: op->type = R_ANAL_OP_TYPE_ABS; op->family = R_ANAL_OP_FAMILY_FPU; break; case X86_INS_FLDCW: case X86_INS_FLDENV: case X86_INS_FLDL2E: case X86_INS_FLDL2T: case X86_INS_FLDLG2: case X86_INS_FLDLN2: case X86_INS_FLDPI: case X86_INS_FLDZ: case X86_INS_FLD1: case X86_INS_FLD: op->type = R_ANAL_OP_TYPE_LOAD; op->family = R_ANAL_OP_FAMILY_FPU; break; case X86_INS_FIST: case X86_INS_FISTP: case X86_INS_FST: case X86_INS_FSTP: case X86_INS_FSTPNCE: case X86_INS_FXRSTOR: case X86_INS_FXRSTOR64: op->type = R_ANAL_OP_TYPE_STORE; op->family = R_ANAL_OP_FAMILY_FPU; break; case X86_INS_FDIV: case X86_INS_FIDIV: case X86_INS_FDIVP: case X86_INS_FDIVR: case X86_INS_FIDIVR: case X86_INS_FDIVRP: op->type = R_ANAL_OP_TYPE_DIV; op->family = R_ANAL_OP_FAMILY_FPU; break; case X86_INS_FSUBR: case X86_INS_FISUBR: case X86_INS_FSUBRP: case X86_INS_FSUB: case X86_INS_FISUB: case X86_INS_FSUBP: op->type = R_ANAL_OP_TYPE_SUB; op->family = R_ANAL_OP_FAMILY_FPU; break; case X86_INS_FMUL: case X86_INS_FIMUL: case X86_INS_FMULP: op->type = R_ANAL_OP_TYPE_MUL; op->family = R_ANAL_OP_FAMILY_FPU; break; case X86_INS_CLI: case X86_INS_STI: op->type = R_ANAL_OP_TYPE_SWI; op->family = R_ANAL_OP_FAMILY_PRIV; break; case X86_INS_CLC: case X86_INS_STC: case X86_INS_CLAC: case X86_INS_CLGI: case X86_INS_CLTS: #if CS_API_MAJOR >= 4 case X86_INS_CLWB: #endif case X86_INS_STAC: case X86_INS_STGI: op->type = R_ANAL_OP_TYPE_MOV; break; // cmov case X86_INS_SETNE: case X86_INS_SETNO: case X86_INS_SETNP: case X86_INS_SETNS: case X86_INS_SETO: case X86_INS_SETP: case X86_INS_SETS: case X86_INS_SETL: case X86_INS_SETLE: case X86_INS_SETB: case X86_INS_SETG: case X86_INS_SETAE: case X86_INS_SETA: case X86_INS_SETBE: case X86_INS_SETE: case X86_INS_SETGE: op->type = R_ANAL_OP_TYPE_CMOV; op->family = 0; if (a->decode) { char *dst = getarg (&gop, 0, 0, NULL); switch (insn->id) { case X86_INS_SETE: esilprintf (op, "zf,%s,=", dst); break; case X86_INS_SETNE: esilprintf (op, "zf,!,%s,=", dst); break; case X86_INS_SETO: esilprintf (op, "of,%s,=", dst); break; case X86_INS_SETNO: esilprintf (op, "of,!,%s,=", dst); break; case X86_INS_SETP: esilprintf (op, "pf,%s,=", dst); break; case X86_INS_SETNP: esilprintf (op, "pf,!,%s,=", dst); break; case X86_INS_SETS: esilprintf (op, "sf,%s,=", dst); break; case X86_INS_SETNS: esilprintf (op, "sf,!,%s,=", dst); break; case X86_INS_SETB: esilprintf (op, "cf,%s,=", dst); break; case X86_INS_SETAE: esilprintf (op, "cf,!,%s,=", dst); break; /* TODO */ #if 0 SETLE/SETNG Sets the byte in the operand to 1 if the Zero Flag is set or the Sign Flag is not equal to the Overflow Flag, otherwise sets the operand to 0. SETBE/SETNA Sets the byte in the operand to 1 if the Carry Flag or the Zero Flag is set, otherwise sets the operand to 0. SETL/SETNGE Sets the byte in the operand to 1 if the Sign Flag is not equal to the Overflow Flag, otherwise sets the operand to 0. case X86_INS_SETL: esilprintf (op, "pf,!,%s,=", dst); break; case X86_INS_SETLE: esilprintf (op, "pf,!,%s,=", dst); break; case X86_INS_SETG: esilprintf (op, "pf,!,%s,=", dst); break; case X86_INS_SETA: esilprintf (op, "pf,!,%s,=", dst); break; case X86_INS_SETBE: esilprintf (op, "pf,!,%s,=", dst); break; case X86_INS_SETGE: esilprintf (op, "pf,!,%s,=", dst); break; break; #endif } free (dst); } break; // cmov case X86_INS_FCMOVBE: case X86_INS_FCMOVB: case X86_INS_FCMOVNBE: case X86_INS_FCMOVNB: case X86_INS_FCMOVE: case X86_INS_FCMOVNE: case X86_INS_FCMOVNU: case X86_INS_FCMOVU: op->family = R_ANAL_OP_FAMILY_FPU; op->type = R_ANAL_OP_TYPE_MOV; break; case X86_INS_CMOVA: case X86_INS_CMOVAE: case X86_INS_CMOVB: case X86_INS_CMOVBE: case X86_INS_CMOVE: case X86_INS_CMOVG: case X86_INS_CMOVGE: case X86_INS_CMOVL: case X86_INS_CMOVLE: case X86_INS_CMOVNE: case X86_INS_CMOVNO: case X86_INS_CMOVNP: case X86_INS_CMOVNS: case X86_INS_CMOVO: case X86_INS_CMOVP: case X86_INS_CMOVS: op->type = R_ANAL_OP_TYPE_CMOV; break; // mov case X86_INS_MOVSS: case X86_INS_MOV: case X86_INS_MOVAPS: case X86_INS_MOVAPD: case X86_INS_MOVZX: case X86_INS_MOVUPS: case X86_INS_MOVABS: case X86_INS_MOVHPD: case X86_INS_MOVHPS: case X86_INS_MOVLPD: case X86_INS_MOVLPS: case X86_INS_MOVBE: case X86_INS_MOVSB: case X86_INS_MOVSD: case X86_INS_MOVSQ: case X86_INS_MOVSX: case X86_INS_MOVSXD: case X86_INS_MOVSW: case X86_INS_MOVD: case X86_INS_MOVQ: case X86_INS_MOVDQ2Q: { op->type = R_ANAL_OP_TYPE_MOV; op->ptr = UT64_MAX; switch (INSOP(0).type) { case X86_OP_MEM: op->ptr = INSOP(0).mem.disp; op->refptr = INSOP(0).size; if (INSOP(0).mem.base == X86_REG_RIP) { op->ptr += addr + insn->size; } else if (INSOP(0).mem.base == X86_REG_RBP || INSOP(0).mem.base == X86_REG_EBP) { op->stackop = R_ANAL_STACK_SET; op->stackptr = regsz; } else { if (op->ptr < 0x1000) op->ptr = UT64_MAX; } if (a->decode) { if (op->prefix & R_ANAL_OP_PREFIX_REP) { int width = INSOP(0).size; const char *src = cs_reg_name(handle, INSOP(1).mem.base); const char *dst = cs_reg_name(handle, INSOP(0).mem.base); const char *counter = (a->bits==16)?"cx": (a->bits==32)?"ecx":"rcx"; esilprintf (op, "%s,!,?{,BREAK,},%s,NUM,%s,NUM,"\ "%s,[%d],%s,=[%d],df,?{,%d,%s,-=,%d,%s,-=,},"\ "df,!,?{,%d,%s,+=,%d,%s,+=,},%s,--=,%s," \ "?{,8,GOTO,},%s,=,%s,=", counter, src, dst, src, width, dst, width, width, src, width, dst, width, src, width, dst, counter, counter, dst, src); } else { char *src = getarg (&gop, 1, 0, NULL); char *dst = getarg (&gop, 0, 1, NULL); esilprintf (op, "%s,%s", src, dst); free (src); free (dst); } } break; case X86_OP_REG: { char *dst = getarg (&gop, 0, 0, NULL); op->dst = r_anal_value_new (); op->dst->reg = r_reg_get (a->reg, dst, R_REG_TYPE_GPR); op->src[0] = r_anal_value_new (); if (INSOP(1).type == X86_OP_MEM) { op->src[0]->delta = INSOP(1).mem.disp; } free (dst); } default: if (a->decode) { char *src = getarg (&gop, 1, 0, NULL); char *dst = getarg (&gop, 0, 0, NULL); esilprintf (op, "%s,%s,=", src, dst); free (src); free (dst); } break; } if (op->refptr<1 || op->ptr == UT64_MAX) { switch (INSOP(1).type) { case X86_OP_MEM: op->ptr = INSOP(1).mem.disp; op->refptr = INSOP(1).size; if (INSOP(1).mem.base == X86_REG_RIP) { op->ptr += addr + insn->size; } else if (INSOP(1).mem.base == X86_REG_RBP || INSOP(1).mem.base == X86_REG_EBP) { op->stackop = R_ANAL_STACK_GET; op->stackptr = regsz; } break; case X86_OP_IMM: if (INSOP(1).imm > 10) op->ptr = INSOP(1).imm; break; default: break; } } } break; case X86_INS_ROL: case X86_INS_RCL: // TODO: RCL Still does not work as intended // - Set flags op->type = R_ANAL_OP_TYPE_ROL; if (a->decode) { char *src = getarg (&gop, 1, 0, NULL); char *dst = getarg (&gop, 0, 0, NULL); esilprintf (op, "%s,%s,<<<,%s,=", src, dst, dst); free (src); free (dst); } break; case X86_INS_ROR: case X86_INS_RCR: // TODO: RCR Still does not work as intended // - Set flags op->type = R_ANAL_OP_TYPE_ROR; if (a->decode) { char *src = getarg (&gop, 1, 0, NULL); char *dst = getarg (&gop, 0, 0, NULL); esilprintf (op, "%s,%s,>>>,%s,=", src, dst, dst); free (src); free (dst); } break; case X86_INS_SHL: case X86_INS_SHLD: case X86_INS_SHLX: // TODO: Set CF: Carry flag is the last bit shifted out due to // this operation. It is undefined for SHL and SHR where the // number of bits shifted is greater than the size of the // destination. op->type = R_ANAL_OP_TYPE_SHL; if (a->decode) { char *src = getarg (&gop, 1, 0, NULL); char *dst = getarg (&gop, 0, 1, "<<"); esilprintf (op, "%s,%s,$z,zf,=,$p,pf,=,$s,sf,=", src, dst); free (src); free (dst); } break; case X86_INS_SAR: case X86_INS_SARX: // TODO: Set CF. See case X86_INS_SHL for more details. op->type = R_ANAL_OP_TYPE_SAR; if (a->decode) { char *src = getarg (&gop, 1, 0, NULL); char *dst = getarg (&gop, 0, 1, ">>"); esilprintf (op, "%s,%s,$z,zf,=,$p,pf,=,$s,sf,=", src, dst); free (src); free (dst); } break; case X86_INS_SAL: // TODO: Set CF: See case X86_INS_SAL for more details. op->type = R_ANAL_OP_TYPE_SAL; if (a->decode) { char *src = getarg (&gop, 1, 0, NULL); char *dst = getarg (&gop, 0, 1, "<<"); esilprintf (op, "%s,%s,$z,zf,=,$p,pf,=,$s,sf,=", src, dst); free (src); free (dst); } break; case X86_INS_SALC: op->type = R_ANAL_OP_TYPE_SAL; if (a->decode) { esilprintf (op, "$z,DUP,zf,=,al,="); } break; case X86_INS_SHR: case X86_INS_SHRD: case X86_INS_SHRX: // TODO: Set CF: See case X86_INS_SAL for more details. op->type = R_ANAL_OP_TYPE_SHR; if (a->decode) { char *src = getarg (&gop, 1, 0, NULL); char *dst = getarg (&gop, 0, 0, NULL); esilprintf (op, "%s,%s,>>=,$z,zf,=,$p,pf,=,$s,sf,=", src, dst); free (src); free (dst); } break; case X86_INS_CMP: case X86_INS_CMPPD: case X86_INS_CMPPS: case X86_INS_CMPSW: case X86_INS_CMPSD: case X86_INS_CMPSQ: case X86_INS_CMPSB: case X86_INS_CMPSS: case X86_INS_TEST: if (insn->id == X86_INS_TEST) { op->type = R_ANAL_OP_TYPE_ACMP; //compare via and if (a->decode) { char *src = getarg (&gop, 1, 0, NULL); char *dst = getarg (&gop, 0, 0, NULL); esilprintf (op, "0,%s,%s,&,==,$z,zf,=,$p,pf,=,$s,sf,=,0,cf,=,0,of,=", src, dst); free (src); free (dst); } } else { op->type = R_ANAL_OP_TYPE_CMP; if (a->decode) { char *src = getarg (&gop, 1, 0, NULL); char *dst = getarg (&gop, 0, 0, NULL); esilprintf (op, "%s,%s,==,$z,zf,=,$b%d,cf,=,$p,pf,=,$s,sf,=", src, dst, (INSOP(0).size*8)); free (src); free (dst); } } switch (INSOP(0).type) { case X86_OP_MEM: op->ptr = INSOP(0).mem.disp; op->refptr = INSOP(0).size; if (INSOP(0).mem.base == X86_REG_RIP) { op->ptr += addr + insn->size; } else if (INSOP(0).mem.base == X86_REG_RBP || INSOP(0).mem.base == X86_REG_EBP) { op->stackop = R_ANAL_STACK_SET; op->stackptr = regsz; } op->ptr = INSOP(1).imm; break; default: switch (INSOP(1).type) { case X86_OP_MEM: op->ptr = INSOP(1).mem.disp; op->refptr = INSOP(1).size; if (INSOP(1).mem.base == X86_REG_RIP) { op->ptr += addr + insn->size; } else if (INSOP(1).mem.base == X86_REG_RBP || INSOP(1).mem.base == X86_REG_EBP) { op->stackop = R_ANAL_STACK_SET; op->stackptr = regsz; } break; case X86_OP_IMM: op->ptr = INSOP(1).imm; break; default: break; } break; } break; case X86_INS_LEA: op->type = R_ANAL_OP_TYPE_LEA; if (a->decode) { char *src = getarg (&gop, 0, 0, NULL); char *dst = getarg (&gop, 1, 2, NULL); esilprintf (op, "%s,%s,=", dst, src); free (src); free (dst); } switch (INSOP(1).type) { case X86_OP_MEM: op->ptr = INSOP(1).mem.disp; op->refptr = INSOP(1).size; switch (INSOP(1).mem.base) { case X86_REG_RIP: op->ptr += addr + op->size; break; case X86_REG_RBP: case X86_REG_EBP: op->stackop = R_ANAL_STACK_GET; op->stackptr = regsz; break; default: /* unhandled */ break; } break; case X86_OP_IMM: if (INSOP(1).imm > 10) op->ptr = INSOP(1).imm; break; default: break; } break; case X86_INS_ENTER: case X86_INS_PUSH: case X86_INS_PUSHAW: case X86_INS_PUSHAL: case X86_INS_PUSHF: { char *dst = getarg (&gop, 0, 0, NULL); esilprintf (op, "%d,%s,-=,%s,%s,=[%d]", rs, sp, dst, sp, rs); free (dst); } switch (INSOP(0).type) { case X86_OP_IMM: op->ptr = INSOP(0).imm; op->type = R_ANAL_OP_TYPE_PUSH; break; default: op->type = R_ANAL_OP_TYPE_UPUSH; break; } op->stackop = R_ANAL_STACK_INC; op->stackptr = regsz; break; case X86_INS_LEAVE: op->type = R_ANAL_OP_TYPE_POP; if (a->decode) { esilprintf (op, "%s,%s,=,%s,[%d],%s,=,%d,%s,+=", bp, sp, sp, rs, bp, rs, sp); } op->stackop = R_ANAL_STACK_INC; op->stackptr = -regsz; break; case X86_INS_POP: case X86_INS_POPF: case X86_INS_POPAW: case X86_INS_POPAL: case X86_INS_POPCNT: op->type = R_ANAL_OP_TYPE_POP; if (a->decode) { char *dst = getarg (&gop, 0, 0, NULL); esilprintf (op, "%s,[%d],%s,=,%d,%s,+=", sp, rs, dst, rs, sp); free (dst); } op->stackop = R_ANAL_STACK_INC; op->stackptr = -regsz; break; case X86_INS_RET: case X86_INS_RETF: case X86_INS_RETFQ: case X86_INS_IRET: case X86_INS_IRETD: case X86_INS_IRETQ: case X86_INS_SYSRET: op->type = R_ANAL_OP_TYPE_RET; if (a->decode) esilprintf (op, "%s,[%d],%s,=,%d,%s,+=", sp, rs, pc, rs, sp); op->stackop = R_ANAL_STACK_INC; op->stackptr = -regsz; break; case X86_INS_INT3: if (a->decode) esilprintf (op, "3,$"); op->type = R_ANAL_OP_TYPE_TRAP; // TRAP break; case X86_INS_INT1: if (a->decode) esilprintf (op, "1,$"); op->type = R_ANAL_OP_TYPE_SWI; // TRAP break; case X86_INS_INT: if (a->decode) esilprintf (op, "%d,$", R_ABS((int)INSOP(0).imm)); op->type = R_ANAL_OP_TYPE_SWI; break; case X86_INS_SYSCALL: op->type = R_ANAL_OP_TYPE_SWI; break; case X86_INS_INTO: case X86_INS_VMCALL: case X86_INS_VMMCALL: op->type = R_ANAL_OP_TYPE_TRAP; if (a->decode) esilprintf (op, "%d,$", (int)INSOP(0).imm); break; case X86_INS_JL: case X86_INS_JLE: case X86_INS_JA: case X86_INS_JAE: case X86_INS_JB: case X86_INS_JBE: case X86_INS_JCXZ: case X86_INS_JECXZ: case X86_INS_JRCXZ: case X86_INS_JO: case X86_INS_JNO: case X86_INS_JS: case X86_INS_JNS: case X86_INS_JP: case X86_INS_JNP: case X86_INS_JE: case X86_INS_JNE: case X86_INS_JG: case X86_INS_JGE: case X86_INS_LOOP: case X86_INS_LOOPE: case X86_INS_LOOPNE: op->type = R_ANAL_OP_TYPE_CJMP; op->jump = INSOP(0).imm; op->fail = addr+op->size; const char *cnt = (a->bits==16)?"cx":(a->bits==32)?"ecx":"rcx"; if (a->decode) { char *dst = getarg (&gop, 0, 2, NULL); switch (insn->id) { case X86_INS_JL: esilprintf (op, "of,sf,^,?{,%s,%s,=,}", dst, pc); break; case X86_INS_JLE: esilprintf (op, "of,sf,^,zf,|,?{,%s,%s,=,}", dst, pc); break; case X86_INS_JA: esilprintf (op, "cf,zf,|,!,?{,%s,%s,=,}",dst, pc); break; case X86_INS_JAE: esilprintf (op, "cf,!,?{,%s,%s,=,}", dst, pc); break; case X86_INS_JB: esilprintf (op, "cf,?{,%s,%s,=,}", dst, pc); break; case X86_INS_JO: esilprintf (op, "of,?{,%s,%s,=,}", dst, pc); break; case X86_INS_JNO: esilprintf (op, "of,!,?{,%s,%s,=,}", dst, pc); break; case X86_INS_JE: esilprintf (op, "zf,?{,%s,%s,=,}", dst, pc); break; case X86_INS_JGE: esilprintf (op, "of,!,sf,^,?{,%s,%s,=,}", dst, pc); break; case X86_INS_JNE: esilprintf (op, "zf,!,?{,%s,%s,=,}", dst, pc); break; case X86_INS_JG: esilprintf (op, "sf,of,!,^,zf,!,&,?{,%s,%s,=,}", dst, pc); break; case X86_INS_JS: esilprintf (op, "sf,?{,%s,%s,=,}", dst, pc); break; case X86_INS_JNS: esilprintf (op, "sf,!,?{,%s,%s,=,}", dst, pc); break; case X86_INS_JP: esilprintf (op, "pf,?{,%s,%s,=,}", dst, pc); break; case X86_INS_JNP: esilprintf (op, "pf,!,?{,%s,%s,=,}", dst, pc); break; case X86_INS_JBE: esilprintf (op, "zf,cf,|,?{,%s,%s,=,}", dst, pc); break; case X86_INS_JCXZ: esilprintf (op, "cx,!,?{,%s,%s,=,}", dst, pc); break; case X86_INS_JECXZ: esilprintf (op, "ecx,!,?{,%s,%s,=,}", dst, pc); break; case X86_INS_JRCXZ: esilprintf (op, "rcx,!,?{,%s,%s,=,}", dst, pc); break; case X86_INS_LOOP: esilprintf (op, "1,%s,-=,%s,?{,%s,%s,=,}", cnt, cnt, dst, pc); break; case X86_INS_LOOPE: esilprintf (op, "1,%s,-=,%s,?{,zf,?{,%s,%s,=,},}", cnt, cnt, dst, pc); break; case X86_INS_LOOPNE: esilprintf (op, "1,%s,-=,%s,?{,zf,!,?{,%s,%s,=,},}", cnt, cnt, dst, pc); break; } free (dst); } break; case X86_INS_CALL: case X86_INS_LCALL: switch (INSOP(0).type) { case X86_OP_IMM: op->type = R_ANAL_OP_TYPE_CALL; // TODO: what if UCALL? // TODO: use imm_size op->jump = INSOP(0).imm; op->fail = addr+op->size; break; case X86_OP_MEM: op->type = R_ANAL_OP_TYPE_UCALL; op->jump = UT64_MAX; if (INSOP(0).mem.base == 0) { op->ptr = INSOP(0).mem.disp; } break; default: op->type = R_ANAL_OP_TYPE_UCALL; op->jump = UT64_MAX; break; } if (a->decode) { char* arg = getarg (&gop, 0, 0, NULL); esilprintf (op, "%s," "%d,%s,-=,%s," "=[]," "%s,%s,=", pc, rs, sp, sp, arg, pc); free (arg); } break; case X86_INS_JMP: case X86_INS_LJMP: if (a->decode) { char *src = getarg (&gop, 0, 0, NULL); esilprintf (op, "%s,%s,=", src, pc); free (src); } // TODO: what if UJMP? switch (INSOP(0).type) { case X86_OP_IMM: op->jump = INSOP(0).imm; op->type = R_ANAL_OP_TYPE_JMP; if (a->decode) { ut64 dst = INSOP(0).imm; esilprintf (op, "0x%"PFMT64x",%s,=", dst, pc); } break; case X86_OP_MEM: op->type = R_ANAL_OP_TYPE_UJMP; op->ptr = INSOP(0).mem.disp; if (INSOP(0).mem.base == X86_REG_RIP) { op->ptr += addr + insn->size; op->refptr = 8; } else { cs_x86_op in = INSOP(0); if (in.mem.index == 0 && in.mem.base == 0 && in.mem.scale == 1) { if (a->decode) { esilprintf (op, "0x%"PFMT64x",[],%s,=", op->ptr, pc); } } } break; case X86_OP_REG: { char *src = getarg (&gop, 0, 0, NULL); op->src[0] = r_anal_value_new (); op->src[0]->reg = r_reg_get (a->reg, src, R_REG_TYPE_GPR); free (src); //XXX fallthrough } case X86_OP_FP: default: // other? op->type = R_ANAL_OP_TYPE_UJMP; op->ptr = UT64_MAX; break; } break; case X86_INS_IN: case X86_INS_INSW: case X86_INS_INSD: case X86_INS_INSB: op->type = R_ANAL_OP_TYPE_IO; op->type2 = 0; break; case X86_INS_OUT: case X86_INS_OUTSB: case X86_INS_OUTSD: case X86_INS_OUTSW: op->type = R_ANAL_OP_TYPE_IO; op->type2 = 1; break; case X86_INS_VXORPD: case X86_INS_VXORPS: case X86_INS_VPXORD: case X86_INS_VPXORQ: case X86_INS_VPXOR: case X86_INS_XORPS: case X86_INS_KXORW: case X86_INS_PXOR: case X86_INS_XOR: op->type = R_ANAL_OP_TYPE_XOR; if (a->decode) { char *src = getarg (&gop, 1, 0, NULL); char *dst = getarg (&gop, 0, 1, "^"); esilprintf (op, "%s,%s,$z,zf,=,$p,pf,=,$s,sf,=,0,cf,=,0,of,=", src, dst); free (src); free (dst); } break; case X86_INS_OR: // The OF and CF flags are cleared; the SF, ZF, and PF flags are // set according to the result. The state of the AF flag is // undefined. op->type = R_ANAL_OP_TYPE_OR; if (a->decode) { char *src = getarg (&gop, 1, 0, NULL); char *dst = getarg (&gop, 0, 0, NULL); esilprintf (op, "%s,%s,|=,0,of,=,0,cf,=,$s,sf,=,$z,zf,=,$p,pf,=", src, dst); free (src); free (dst); } break; case X86_INS_INC: // The CF flag is not affected. The OF, SF, ZF, AF, and PF flags // are set according to the result. op->type = R_ANAL_OP_TYPE_ADD; op->val = 1; if (a->decode) { char *src = getarg (&gop, 0, 0, NULL); if (strchr (src, '[')) { char *dst = r_str_replace (strdup (src), "[", "=[", 1); esilprintf (op, "1,%s,++,%s,$o,of,=,$s,sf,=,$z,zf,=,$p,pf,=", src, dst); free (dst); } else { esilprintf (op, "%s,++=,$o,of,=,$s,sf,=,$z,zf,=,$p,pf,=", src); } free (src); } break; case X86_INS_DEC: // The CF flag is not affected. The OF, SF, ZF, AF, and PF flags // are set according to the result. op->type = R_ANAL_OP_TYPE_SUB; op->val = 1; if (a->decode) { char *src = getarg (&gop, 0, 0, NULL); //esilprintf (op, "%s,--=,$o,of,=,$s,sf,=,$z,zf,=,$p,pf,=", src); esilprintf (op, "1,%s,[4],-,%s,=[4],$o,of,=,$s,sf,=,$z,zf,=,$p,pf,=", src, src); free (src); } break; case X86_INS_PSUBB: case X86_INS_PSUBW: case X86_INS_PSUBD: case X86_INS_PSUBQ: case X86_INS_PSUBSB: case X86_INS_PSUBSW: case X86_INS_PSUBUSB: case X86_INS_PSUBUSW: op->type = R_ANAL_OP_TYPE_SUB; if (a->decode) { char *src = getarg (&gop, 1, 0, NULL); char *dst = getarg (&gop, 0, 1, "-"); esilprintf (op, "%s,%s", src, dst); free(src); free(dst); } break; case X86_INS_SUB: op->type = R_ANAL_OP_TYPE_SUB; if (a->decode) { char *src = getarg (&gop, 1, 0, NULL); char *dst = getarg (&gop, 0, 1, "-"); // Set OF, SF, ZF, AF, PF, and CF flags. // We use $b rather than $c here as the carry flag really // represents a "borrow" esilprintf (op, "%s,%s,$o,of,=,$s,sf,=,$z,zf,=,$p,pf,=,$b,cf,=", src, dst); free (src); free (dst); } if (INSOP(0).type == X86_OP_REG && INSOP(1).type == X86_OP_IMM) { if (INSOP(0).reg == X86_REG_RSP || INSOP(0).reg == X86_REG_ESP) { op->stackop = R_ANAL_STACK_INC; op->stackptr = INSOP(1).imm; } } break; case X86_INS_SBB: // dst = dst - (src + cf) op->type = R_ANAL_OP_TYPE_SUB; if (a->decode) { char *src = getarg (&gop, 1, 0, NULL); char *dst = getarg (&gop, 0, 0, NULL); esilprintf (op, "cf,%s,+,%s,-=,$o,of,=,$s,sf,=,$z,zf,=,$p,pf,=,$b,cf,=", src, dst); free (src); free (dst); } break; case X86_INS_LIDT: op->type = R_ANAL_OP_TYPE_LOAD; op->family = R_ANAL_OP_FAMILY_PRIV; break; case X86_INS_SIDT: op->type = R_ANAL_OP_TYPE_STORE; op->family = R_ANAL_OP_FAMILY_PRIV; break; case X86_INS_RDRAND: case X86_INS_RDSEED: case X86_INS_RDMSR: case X86_INS_RDPMC: case X86_INS_RDTSC: case X86_INS_RDTSCP: case X86_INS_CRC32: case X86_INS_SHA1MSG1: case X86_INS_SHA1MSG2: case X86_INS_SHA1NEXTE: case X86_INS_SHA1RNDS4: case X86_INS_SHA256MSG1: case X86_INS_SHA256MSG2: case X86_INS_SHA256RNDS2: case X86_INS_AESDECLAST: case X86_INS_AESDEC: case X86_INS_AESENCLAST: case X86_INS_AESENC: case X86_INS_AESIMC: case X86_INS_AESKEYGENASSIST: // AES instructions op->family = R_ANAL_OP_FAMILY_CRYPTO; op->type = R_ANAL_OP_TYPE_MOV; // XXX break; case X86_INS_AND: case X86_INS_ANDN: case X86_INS_ANDPD: case X86_INS_ANDPS: case X86_INS_ANDNPD: case X86_INS_ANDNPS: op->type = R_ANAL_OP_TYPE_AND; if (a->decode) { char *src = getarg (&gop, 1, 0, NULL); char *dst = getarg (&gop, 0, 1, "&"); esilprintf (op, "%s,%s,0,of,=,0,cf,=,$z,zf,=,$s,sf,=,$o,pf,=", src, dst); free (src); free (dst); } break; case X86_INS_IDIV: op->type = R_ANAL_OP_TYPE_DIV; if (a->decode) { char *a0 = getarg (&gop, 0, 0, NULL); char *a1 = getarg (&gop, 1, 0, NULL); char *a2 = getarg (&gop, 2, 0, NULL); // TODO update flags & handle signedness if (!a2 && !a1) { // TODO: IDIV rbx not implemented. this is just a workaround // http://www.tptp.cc/mirrors/siyobik.info/instruction/IDIV.html // Divides (signed) the value in the AX, DX:AX, or EDX:EAX registers (dividend) by the source operand (divisor) and stores the result in the AX (AH:AL), DX:AX, or EDX:EAX registers. The source operand can be a general-purpose register or a memory location. The action of this instruction depends on the operand size (dividend/divisor), as shown in the following table: // IDIV RBX == RDX:RAX /= RBX esilprintf (op, "%s,%s,/=", a0, "rax"); } else { esilprintf (op, "%s,%s,/,%s,=", a2, a1, a0); } free (a0); free (a1); free (a2); } break; case X86_INS_DIV: op->type = R_ANAL_OP_TYPE_DIV; if (a->decode) { int width = INSOP(0).size; char *dst = getarg (&gop, 0, 0, NULL); const char *r_ax = (width==2)?"ax": (width==4)?"eax":"rax"; const char *r_dx = (width==2)?"dx": (width==4)?"edx":"rdx"; // TODO update flags & handle signedness esilprintf (op, "%s,%s,%%,%s,=,%s,%s,/,%s,=", dst, r_ax, r_dx, dst, r_ax, r_ax); free (dst); } break; case X86_INS_IMUL: op->type = R_ANAL_OP_TYPE_MUL; if (a->decode) { char *a0 = getarg (&gop, 0, 0, NULL); char *a1 = getarg (&gop, 1, 0, NULL); char *a2 = getarg (&gop, 2, 0, NULL); if (a2) { // TODO update flags & handle signedness esilprintf (op, "%s,%s,*,%s,=", a2, a1, a0); free (a2); } else { if (a1) { esilprintf (op, "%s,%s,*=", a1, a0); } else { esilprintf (op, "%s,%s,*=", a0, "rax"); } } free (a0); free (a1); } break; case X86_INS_MUL: case X86_INS_MULX: case X86_INS_MULPD: case X86_INS_MULPS: case X86_INS_MULSD: case X86_INS_MULSS: op->type = R_ANAL_OP_TYPE_MUL; if (a->decode) { char *src = getarg (&gop, 1, 0, NULL); char *dst = getarg (&gop, 0, 1, "*"); if (!src && dst) { switch (dst[0]) { case 'r': src = strdup ("rax"); break; case 'e': src = strdup ("eax"); break; default: src = strdup ("al"); break; } } esilprintf (op, "%s,%s", src, dst); free (src); free (dst); } break; case X86_INS_PACKSSDW: case X86_INS_PACKSSWB: case X86_INS_PACKUSWB: op->type = R_ANAL_OP_TYPE_MOV; op->family = R_ANAL_OP_FAMILY_MMX; break; case X86_INS_PADDB: case X86_INS_PADDD: case X86_INS_PADDW: case X86_INS_PADDSB: case X86_INS_PADDSW: case X86_INS_PADDUSB: case X86_INS_PADDUSW: op->type = R_ANAL_OP_TYPE_ADD; op->family = R_ANAL_OP_FAMILY_MMX; break; case X86_INS_XCHG: op->type = R_ANAL_OP_TYPE_MOV; op->family = R_ANAL_OP_FAMILY_CPU; { char *src = getarg (&gop, 1, 0, NULL); char *dst = getarg (&gop, 0, 1, NULL); esilprintf (op, "%s,%s,%s,=,%s,=", src, dst, src, dst); free (src); free (dst); } break; case X86_INS_XADD: /* xchg + add */ op->type = R_ANAL_OP_TYPE_ADD; op->family = R_ANAL_OP_FAMILY_CPU; { char *src = getarg (&gop, 1, 0, NULL); char *dst = getarg (&gop, 0, 1, NULL); if (src == dst) { esilprintf (op, "%s,%s,+,%s", src, dst, dst); } else { esilprintf (op, "%s,%s,%s,=,%s,=," "%s,%s,+,%s", src, dst, src, dst, src, dst, dst); } free (src); free (dst); } break; case X86_INS_FADD: case X86_INS_FADDP: op->family = R_ANAL_OP_FAMILY_FPU; /* pass thru */ case X86_INS_ADDPS: case X86_INS_ADDSD: case X86_INS_ADDSS: case X86_INS_ADDSUBPD: case X86_INS_ADDSUBPS: case X86_INS_ADDPD: // The OF, SF, ZF, AF, CF, and PF flags are set according to the // result. op->type = R_ANAL_OP_TYPE_ADD; if (a->decode) { if (INSOP(0).type == X86_OP_MEM) { char *src = getarg (&gop, 1, 0, NULL); char *src2 = getarg (&gop, 0, 0, NULL); char *dst = getarg (&gop, 0, 1, NULL); esilprintf (op, "%s,%s,+,%s", src, src2, dst); free (src); free (src2); free (dst); } else { char *src = getarg (&gop, 1, 0, NULL); char *dst = getarg (&gop, 0, 1, "+"); esilprintf (op, "%s,%s", src, dst); free (src); free (dst); } } if (INSOP(0).type == X86_OP_REG && INSOP(1).type == X86_OP_IMM) { if (INSOP(0).reg == X86_REG_RSP || INSOP(0).reg == X86_REG_ESP) { op->stackop = R_ANAL_STACK_INC; op->stackptr = -INSOP(1).imm; } } break; case X86_INS_ADD: // The OF, SF, ZF, AF, CF, and PF flags are set according to the // result. op->type = R_ANAL_OP_TYPE_ADD; if (a->decode) { if (INSOP(0).type == X86_OP_MEM) { char *src = getarg (&gop, 1, 0, NULL); char *src2 = getarg (&gop, 0, 0, NULL); char *dst = getarg (&gop, 0, 1, NULL); esilprintf (op, "%s,%s,+,%s,$o,of,=,$s,sf,=,$z,zf,=,$p,pf,=,$c,cf,=", src, src2, dst); free (src); free (src2); free (dst); } else { char *src = getarg (&gop, 1, 0, NULL); char *dst = getarg (&gop, 0, 1, "+"); esilprintf (op, "%s,%s,$o,of,=,$s,sf,=,$z,zf,=,$p,pf,=,$c,cf,=", src, dst); free (src); free (dst); } } if (INSOP(0).type == X86_OP_REG && INSOP(1).type == X86_OP_IMM) { if (INSOP(0).reg == X86_REG_RSP || INSOP(0).reg == X86_REG_ESP) { op->stackop = R_ANAL_STACK_INC; op->stackptr = -INSOP(1).imm; } } break; case X86_INS_ADC: op->type = R_ANAL_OP_TYPE_ADD; if (a->decode) { char *src = getarg (&gop, 1, 0, NULL); char *dst = getarg (&gop, 0, 0, NULL); // dst = dst + src + cf // NOTE: We would like to add the carry first before adding the // source to ensure that the flag computation from $c belongs // to the operation of adding dst += src rather than the one // that adds carry (as esil only keeps track of the last // addition to set the flags). esilprintf (op, "cf,%s,+,%s,+=,$o,of,=,$s,sf,=,$z,zf,=,$p,pf,=,$c,cf,=", src, dst); free (src); free (dst); } break; /* Direction flag */ case X86_INS_CLD: op->type = R_ANAL_OP_TYPE_MOV; if (a->decode) esilprintf (op, "0,df,="); break; case X86_INS_STD: op->type = R_ANAL_OP_TYPE_MOV; if (a->decode) esilprintf (op, "1,df,="); break; } switch (insn->id) { case X86_INS_MOVAPS: //cvtss2sd case X86_INS_ADDSD: //cvtss2sd case X86_INS_SUBSD: //cvtss2sd case X86_INS_MULSD: //cvtss2sd case X86_INS_CVTSS2SD: //cvtss2sd case X86_INS_MOVSS: case X86_INS_MOVSD: op->family = R_ANAL_OP_FAMILY_MMX; break; } } //#if X86_GRP_PRIVILEGE>0 if (insn) { #if HAVE_CSGRP_PRIVILEGE if (cs_insn_group (handle, insn, X86_GRP_PRIVILEGE)) op->family = R_ANAL_OP_FAMILY_PRIV; #endif #if !USE_ITER_API cs_free (insn, n); #endif } //cs_close (&handle); return op->size; }
/** * Translates operand N to esil * * @param handle csh * @param insn cs_insn * @param n Operand index * @param set if 1 it adds set (=) to the operand * @param setoper Extra operation for the set (^, -, +, etc...) * @return char* with the esil operand */ static char *getarg(csh handle, cs_insn *insn, int n, int set, char *setop) { char buf[64]; char *setarg = setop? setop : ""; cs_x86_op op = {0}; if (!insn->detail) return NULL; buf[0] = 0; if (n<0 || n>=INSOPS) return NULL; op = INSOP (n); switch (op.type) { case X86_OP_INVALID: return strdup ("invalid"); case X86_OP_REG: if (set == 1) { snprintf (buf, sizeof (buf), "%s,%s=", cs_reg_name (handle, op.reg), setarg); return strdup (buf); } else { return strdup (cs_reg_name (handle, op.reg)); } case X86_OP_IMM: if (set == 1) snprintf (buf, sizeof (buf), "%"PFMT64d",%s=[%d]", (ut64)op.imm, setarg, op.size); else snprintf (buf, sizeof (buf), "%"PFMT64d, (ut64)op.imm); return strdup (buf); case X86_OP_MEM: { const char *base = cs_reg_name (handle, op.mem.base); const char *index = cs_reg_name (handle, op.mem.index); int scale = op.mem.scale; st64 disp = op.mem.disp; if (scale>1) { if (set>1) { if (base) { if (disp) { snprintf (buf, sizeof (buf), "%s,0x%x,+,%d,*", base, (int)disp, scale); } else { snprintf (buf, sizeof (buf), "%s,%d,*", base, scale); } } else { if (disp) { snprintf (buf, sizeof (buf), "%d,0x%x,*,[%d]", scale, (int)disp, op.size); } else { snprintf (buf, sizeof (buf), "%d,[%d]", scale, op.size); } } } else { if (base) { if (disp) { snprintf (buf, sizeof (buf), "0x%x,%s,+,%d,*,[%d]", (int)disp, base, scale, op.size); } else { snprintf (buf, sizeof (buf), "%s,%d,*,[%d]", base, scale, op.size); } } else { if (disp) { snprintf (buf, sizeof (buf), "0x%x,%d,*,[%d]", (int)disp, scale, op.size); } else { snprintf (buf, sizeof (buf), "%d,[%d]", scale, op.size); } } } } else { if (set>1) { if (base) { if (disp) { int v = (int)disp; if (v<0) { snprintf (buf, sizeof (buf), "0x%x,%s,-", -v, base); } else { snprintf (buf, sizeof (buf), "0x%x,%s,+", v, base); } } else { snprintf (buf, sizeof (buf), "%s", base); } } else { if (disp) { snprintf (buf, sizeof (buf), "%d", (int)disp); } } } else { if (base) { if (disp) { int v = (int)disp; if (v<0) { snprintf (buf, sizeof (buf), "0x%x,%s,-,%s%s[%d]", -(int)disp, base, setarg, set?"=":"", op.size); } else { snprintf (buf, sizeof (buf), "0x%x,%s,+,%s%s[%d]", (int)disp, base, setarg, set?"=":"", op.size); } } else { if (index) if (set) snprintf (buf, sizeof (buf), "%s,%s,+,%s=[%d]", base, index, setarg, op.size); else snprintf (buf, sizeof (buf), "%s,%s,+", base, index); else snprintf (buf, sizeof (buf), "%s,%s%s[%d]", base, setarg, set?"=":"", op.size); } } else { if (disp) { snprintf (buf, sizeof (buf), "0x%x,%s%s[%d]", (int)disp, setarg, set?"=":"", op.size); } else { snprintf (buf, sizeof (buf), "%s%s,[%d]", setarg, set?"=":"", op.size); } } } } } return strdup (buf); case X86_OP_FP: break; } return strdup ("PoP"); }
static int analop(RAnal *a, RAnalOp *op, ut64 addr, const ut8 *buf, int len) { static int omode = 0; #if USE_ITER_API static #endif cs_insn *insn = NULL; int mode = (a->bits==64)? CS_MODE_64: (a->bits==32)? CS_MODE_32: (a->bits==16)? CS_MODE_16: 0; int n, ret; int regsz = 4; if (handle && mode != omode) { cs_close (&handle); handle = 0; } omode = mode; if (handle == 0) { ret = cs_open (CS_ARCH_X86, mode, &handle); if (ret != CS_ERR_OK) { handle = 0; return 0; } } switch (a->bits) { case 64: regsz = 8; break; case 16: regsz = 2; break; default: case 32: regsz = 4; break; } memset (op, '\0', sizeof (RAnalOp)); op->cycles = 1; // aprox op->type = R_ANAL_OP_TYPE_NULL; op->jump = UT64_MAX; op->fail = UT64_MAX; op->ptr = op->val = UT64_MAX; op->src[0] = NULL; op->src[1] = NULL; op->size = 0; op->delay = 0; r_strbuf_init (&op->esil); cs_option (handle, CS_OPT_DETAIL, CS_OPT_ON); // capstone-next #if USE_ITER_API { ut64 naddr = addr; size_t size = len; if (insn == NULL) insn = cs_malloc (handle); n = cs_disasm_iter (handle, (const uint8_t**)&buf, &size, (uint64_t*)&naddr, insn); } #else n = cs_disasm (handle, (const ut8*)buf, len, addr, 1, &insn); #endif struct Getarg gop = { .handle = handle, .insn = insn, .bits = a->bits }; if (n<1) { op->type = R_ANAL_OP_TYPE_ILL; } else { int rs = a->bits/8; const char *pc = (a->bits==16)?"ip": (a->bits==32)?"eip":"rip"; const char *sp = (a->bits==16)?"sp": (a->bits==32)?"esp":"rsp"; const char *bp = (a->bits==16)?"bp": (a->bits==32)?"ebp":"rbp"; op->size = insn->size; op->family = 0; op->prefix = 0; switch (insn->detail->x86.prefix[0]) { case X86_PREFIX_REPNE: op->prefix |= R_ANAL_OP_PREFIX_REPNE; break; case X86_PREFIX_REP: op->prefix |= R_ANAL_OP_PREFIX_REP; break; case X86_PREFIX_LOCK: op->prefix |= R_ANAL_OP_PREFIX_LOCK; break; } switch (insn->id) { case X86_INS_FNOP: case X86_INS_NOP: case X86_INS_PAUSE: op->type = R_ANAL_OP_TYPE_NOP; if (a->decode) esilprintf (op, ","); break; case X86_INS_HLT: op->type = R_ANAL_OP_TYPE_TRAP; break; case X86_INS_FBLD: case X86_INS_FBSTP: case X86_INS_FCOMPP: case X86_INS_FDECSTP: case X86_INS_FEMMS: case X86_INS_FFREE: case X86_INS_FICOM: case X86_INS_FICOMP: case X86_INS_FINCSTP: case X86_INS_FNCLEX: case X86_INS_FNINIT: case X86_INS_FNSTCW: case X86_INS_FNSTSW: case X86_INS_FPATAN: case X86_INS_FPREM: case X86_INS_FPREM1: case X86_INS_FPTAN: #if CS_API_MAJOR >=4 case X86_INS_FFREEP: #endif case X86_INS_FRNDINT: case X86_INS_FRSTOR: case X86_INS_FNSAVE: case X86_INS_FSCALE: case X86_INS_FSETPM: case X86_INS_FSINCOS: case X86_INS_FNSTENV: case X86_INS_FXAM: case X86_INS_FXSAVE: case X86_INS_FXSAVE64: case X86_INS_FXTRACT: case X86_INS_FYL2X: case X86_INS_FYL2XP1: case X86_INS_FISTTP: case X86_INS_FSQRT: case X86_INS_FXCH: case X86_INS_FTST: case X86_INS_FUCOMPI: case X86_INS_FUCOMI: case X86_INS_FUCOMPP: case X86_INS_FUCOMP: case X86_INS_FUCOM: op->type = R_ANAL_OP_TYPE_SUB; op->family = R_ANAL_OP_FAMILY_FPU; break; case X86_INS_FLDCW: case X86_INS_FLDENV: case X86_INS_FLDL2E: case X86_INS_FLDL2T: case X86_INS_FLDLG2: case X86_INS_FLDLN2: case X86_INS_FLDPI: case X86_INS_FLDZ: case X86_INS_FLD1: case X86_INS_FLD: op->type = R_ANAL_OP_TYPE_LOAD; op->family = R_ANAL_OP_FAMILY_FPU; break; case X86_INS_FIST: case X86_INS_FISTP: case X86_INS_FST: case X86_INS_FSTP: case X86_INS_FSTPNCE: case X86_INS_FXRSTOR: case X86_INS_FXRSTOR64: op->type = R_ANAL_OP_TYPE_STORE; op->family = R_ANAL_OP_FAMILY_FPU; break; case X86_INS_FDIV: case X86_INS_FIDIV: case X86_INS_FDIVP: case X86_INS_FDIVR: case X86_INS_FIDIVR: case X86_INS_FDIVRP: case X86_INS_FSUBR: case X86_INS_FISUBR: case X86_INS_FSUBRP: case X86_INS_FSUB: case X86_INS_FISUB: case X86_INS_FSUBP: op->type = R_ANAL_OP_TYPE_SUB; op->family = R_ANAL_OP_FAMILY_FPU; break; case X86_INS_FMUL: case X86_INS_FIMUL: case X86_INS_FMULP: op->type = R_ANAL_OP_TYPE_MUL; op->family = R_ANAL_OP_FAMILY_FPU; break; case X86_INS_CLI: case X86_INS_STI: op->type = R_ANAL_OP_TYPE_SWI; op->family = R_ANAL_OP_FAMILY_PRIV; break; case X86_INS_CLC: case X86_INS_STC: case X86_INS_CLAC: case X86_INS_CLGI: case X86_INS_CLTS: case X86_INS_CLWB: case X86_INS_STAC: case X86_INS_STGI: op->type = R_ANAL_OP_TYPE_MOV; op->family = R_ANAL_OP_FAMILY_CPU; break; // cmov case X86_INS_SETNE: case X86_INS_SETNO: case X86_INS_SETNP: case X86_INS_SETNS: case X86_INS_SETO: case X86_INS_SETP: case X86_INS_SETS: case X86_INS_SETL: case X86_INS_SETLE: case X86_INS_SETB: case X86_INS_SETG: case X86_INS_SETAE: case X86_INS_SETA: case X86_INS_SETBE: case X86_INS_SETE: case X86_INS_SETGE: op->type = R_ANAL_OP_TYPE_CMOV; op->family = 0; if (a->decode) { char *dst = getarg (&gop, 0, 0, NULL); switch (insn->id) { case X86_INS_SETE: esilprintf (op, "zf,%s,=", dst); break; case X86_INS_SETNE: esilprintf (op, "zf,!,%s,=", dst); break; case X86_INS_SETO: esilprintf (op, "of,%s,=", dst); break; case X86_INS_SETNO: esilprintf (op, "of,!,%s,=", dst); break; case X86_INS_SETP: esilprintf (op, "pf,%s,=", dst); break; case X86_INS_SETNP: esilprintf (op, "pf,!,%s,=", dst); break; case X86_INS_SETS: esilprintf (op, "sf,%s,=", dst); break; case X86_INS_SETNS: esilprintf (op, "sf,!,%s,=", dst); break; case X86_INS_SETB: esilprintf (op, "cf,%s,=", dst); break; case X86_INS_SETAE: esilprintf (op, "cf,!,%s,=", dst); break; /* TODO */ #if 0 SETLE/SETNG Sets the byte in the operand to 1 if the Zero Flag is set or the Sign Flag is not equal to the Overflow Flag, otherwise sets the operand to 0. SETBE/SETNA Sets the byte in the operand to 1 if the Carry Flag or the Zero Flag is set, otherwise sets the operand to 0. SETL/SETNGE Sets the byte in the operand to 1 if the Sign Flag is not equal to the Overflow Flag, otherwise sets the operand to 0. case X86_INS_SETL: esilprintf (op, "pf,!,%s,=", dst); break; case X86_INS_SETLE: esilprintf (op, "pf,!,%s,=", dst); break; case X86_INS_SETG: esilprintf (op, "pf,!,%s,=", dst); break; case X86_INS_SETA: esilprintf (op, "pf,!,%s,=", dst); break; case X86_INS_SETBE: esilprintf (op, "pf,!,%s,=", dst); break; case X86_INS_SETGE: esilprintf (op, "pf,!,%s,=", dst); break; break; #endif } free (dst); } break; // cmov case X86_INS_MOVSS: case X86_INS_CMOVA: case X86_INS_CMOVAE: case X86_INS_CMOVB: case X86_INS_CMOVBE: case X86_INS_FCMOVBE: case X86_INS_FCMOVB: case X86_INS_CMOVE: case X86_INS_FCMOVE: case X86_INS_CMOVG: case X86_INS_CMOVGE: case X86_INS_CMOVL: case X86_INS_CMOVLE: case X86_INS_FCMOVNBE: case X86_INS_FCMOVNB: case X86_INS_CMOVNE: case X86_INS_FCMOVNE: case X86_INS_CMOVNO: case X86_INS_CMOVNP: case X86_INS_FCMOVNU: case X86_INS_CMOVNS: case X86_INS_CMOVO: case X86_INS_CMOVP: case X86_INS_FCMOVU: case X86_INS_CMOVS: // mov case X86_INS_MOV: case X86_INS_MOVAPS: case X86_INS_MOVAPD: case X86_INS_MOVZX: case X86_INS_MOVUPS: case X86_INS_MOVABS: case X86_INS_MOVHPD: case X86_INS_MOVHPS: case X86_INS_MOVLPD: case X86_INS_MOVLPS: case X86_INS_MOVBE: case X86_INS_MOVSB: case X86_INS_MOVSD: case X86_INS_MOVSQ: case X86_INS_MOVSX: case X86_INS_MOVSXD: case X86_INS_MOVSW: case X86_INS_MOVD: case X86_INS_MOVQ: case X86_INS_MOVDQ2Q: { op->type = R_ANAL_OP_TYPE_MOV; op->ptr = UT64_MAX; switch (INSOP(0).type) { case X86_OP_MEM: op->ptr = INSOP(0).mem.disp; op->refptr = INSOP(0).size; if (INSOP(0).mem.base == X86_REG_RIP) { op->ptr += addr + insn->size; } else if (INSOP(0).mem.base == X86_REG_RBP || INSOP(0).mem.base == X86_REG_EBP) { op->ptr = UT64_MAX; op->stackop = R_ANAL_STACK_SET; op->stackptr = regsz; } else { op->ptr = UT64_MAX; } if (a->decode) { if (op->prefix & R_ANAL_OP_PREFIX_REP) { int width = INSOP(0).size; const char *src = cs_reg_name(handle, INSOP(1).mem.base); const char *dst = cs_reg_name(handle, INSOP(0).mem.base); const char *counter = (a->bits==16)?"cx": (a->bits==32)?"ecx":"rcx"; esilprintf (op, "%s,!,?{,BREAK,},%s,DUP,%s,DUP,"\ "%s,[%d],%s,=[%d],df,?{,%d,%s,-=,%d,%s,-=,},"\ "df,!,?{,%d,%s,+=,%d,%s,+=,},%s,--=,%s," \ "?{,8,GOTO,},%s,=,%s,=", counter, src, dst, src, width, dst, width, width, src, width, dst, width, src, width, dst, counter, counter, dst, src); } else { char *src = getarg (&gop, 1, 0, NULL); char *dst = getarg (&gop, 0, 1, NULL); esilprintf (op, "%s,%s", src, dst); free (src); free (dst); } } break; default: if (a->decode) { char *src = getarg (&gop, 1, 0, NULL); char *dst = getarg (&gop, 0, 0, NULL); esilprintf (op, "%s,%s,=", src, dst); free (src); free (dst); } break; } if (op->refptr<1 || op->ptr == UT64_MAX) { switch (INSOP(1).type) { case X86_OP_MEM: op->ptr = INSOP(1).mem.disp; op->refptr = INSOP(1).size; if (INSOP(1).mem.base == X86_REG_RIP) { op->ptr += addr + insn->size; } else if (INSOP(1).mem.base == X86_REG_RBP || INSOP(1).mem.base == X86_REG_EBP) { op->stackop = R_ANAL_STACK_GET; op->stackptr = regsz; } break; case X86_OP_IMM: if (INSOP(1).imm > 10) op->ptr = INSOP(1).imm; break; default: break; } } } break; case X86_INS_SHL: case X86_INS_SHLD: case X86_INS_SHLX: op->type = R_ANAL_OP_TYPE_SHL; if (a->decode) { char *src = getarg (&gop, 1, 0, NULL); char *dst = getarg (&gop, 0, 1, "<<"); esilprintf (op, "%s,%s,$z,zf,=", src, dst); free (src); free (dst); } break; case X86_INS_SAR: case X86_INS_SARX: op->type = R_ANAL_OP_TYPE_SAR; if (a->decode) { char *src = getarg (&gop, 1, 0, NULL); char *dst = getarg (&gop, 0, 1, ">>"); esilprintf (op, "%s,%s,$z,zf,=", src, dst); free (src); free (dst); } break; case X86_INS_SAL: op->type = R_ANAL_OP_TYPE_SAL; if (a->decode) { char *src = getarg (&gop, 1, 0, NULL); char *dst = getarg (&gop, 0, 1, "<<"); esilprintf (op, "%s,%s,$z,zf,=", src, dst); free (src); free (dst); } break; case X86_INS_SALC: op->type = R_ANAL_OP_TYPE_SAL; if (a->decode) { esilprintf (op, "$z,DUP,zf,=,al,="); } break; case X86_INS_SHR: case X86_INS_SHRD: case X86_INS_SHRX: op->type = R_ANAL_OP_TYPE_SHR; if (a->decode) { char *src = getarg (&gop, 1, 0, NULL); char *dst = getarg (&gop, 0, 0, NULL); esilprintf (op, "%s,%s,>>=,$z,zf,=", src, dst); free (src); free (dst); } break; case X86_INS_CMP: case X86_INS_CMPPD: case X86_INS_CMPPS: case X86_INS_CMPSW: case X86_INS_CMPSD: case X86_INS_CMPSQ: case X86_INS_CMPSB: case X86_INS_CMPSS: case X86_INS_TEST: if (insn->id == X86_INS_TEST) { op->type = R_ANAL_OP_TYPE_ACMP; //compare via and if (a->decode) { char *src = getarg (&gop, 1, 0, NULL); char *dst = getarg (&gop, 0, 0, NULL); esilprintf (op, "0,%s,%s,&,==,$z,zf,=,$p,pf,=,$s,sf,=,0,cf,=,0,of,=", src, dst); free (src); free (dst); } } else { op->type = R_ANAL_OP_TYPE_CMP; if (a->decode) { char *src = getarg (&gop, 1, 0, NULL); char *dst = getarg (&gop, 0, 0, NULL); esilprintf (op, "%s,%s,==,$z,zf,=,$b%d,cf,=,$p,pf,=,$s,sf,=", src, dst, (INSOP(0).size*8)); free (src); free (dst); } } switch (INSOP(0).type) { case X86_OP_MEM: op->ptr = INSOP(0).mem.disp; op->refptr = INSOP(0).size; if (INSOP(0).mem.base == X86_REG_RIP) { op->ptr += addr + insn->size; } else if (INSOP(0).mem.base == X86_REG_RBP || INSOP(0).mem.base == X86_REG_EBP) { op->stackop = R_ANAL_STACK_SET; op->stackptr = regsz; } op->ptr = INSOP(1).imm; break; default: switch (INSOP(1).type) { case X86_OP_MEM: op->ptr = INSOP(1).mem.disp; op->refptr = INSOP(1).size; if (INSOP(1).mem.base == X86_REG_RIP) { op->ptr += addr + insn->size; } else if (INSOP(1).mem.base == X86_REG_RBP || INSOP(1).mem.base == X86_REG_EBP) { op->stackop = R_ANAL_STACK_SET; op->stackptr = regsz; } break; case X86_OP_IMM: op->ptr = INSOP(1).imm; break; default: break; } break; } break; case X86_INS_LEA: op->type = R_ANAL_OP_TYPE_LEA; if (a->decode) { char *src = getarg (&gop, 0, 0, NULL); char *dst = getarg (&gop, 1, 2, NULL); esilprintf (op, "%s,%s,=", dst, src); free (src); free (dst); } switch (INSOP(1).type) { case X86_OP_MEM: op->ptr = INSOP(1).mem.disp; op->refptr = INSOP(1).size; switch (INSOP(1).mem.base) { case X86_REG_RIP: op->ptr += addr + op->size; break; case X86_REG_RBP: case X86_REG_EBP: op->stackop = R_ANAL_STACK_GET; op->stackptr = regsz; break; default: /* unhandled */ break; } break; case X86_OP_IMM: if (INSOP(1).imm > 10) op->ptr = INSOP(1).imm; break; default: break; } break; case X86_INS_ENTER: case X86_INS_PUSH: case X86_INS_PUSHAW: case X86_INS_PUSHAL: case X86_INS_PUSHF: { char *dst = getarg (&gop, 0, 0, NULL); esilprintf (op, "%d,%s,-=,%s,%s,=[%d]", rs, sp, dst, sp, rs); free (dst); } switch (INSOP(0).type) { case X86_OP_IMM: op->ptr = INSOP(0).imm; op->type = R_ANAL_OP_TYPE_PUSH; break; default: op->type = R_ANAL_OP_TYPE_UPUSH; break; } op->stackop = R_ANAL_STACK_INC; op->stackptr = regsz; break; case X86_INS_LEAVE: op->type = R_ANAL_OP_TYPE_POP; if (a->decode) { esilprintf (op, "%s,%s,=,%s,[%d],%s,=,%d,%s,+=", bp, sp, sp, rs, bp, rs, sp); } op->stackop = R_ANAL_STACK_INC; op->stackptr = -regsz; break; case X86_INS_POP: case X86_INS_POPF: case X86_INS_POPAW: case X86_INS_POPAL: case X86_INS_POPCNT: op->type = R_ANAL_OP_TYPE_POP; if (a->decode) { char *dst = getarg (&gop, 0, 0, NULL); esilprintf (op, "%s,[%d],%s,=,%d,%s,+=", sp, rs, dst, rs, sp); free (dst); } op->stackop = R_ANAL_STACK_INC; op->stackptr = -regsz; break; case X86_INS_RET: case X86_INS_RETF: case X86_INS_RETFQ: case X86_INS_IRET: case X86_INS_IRETD: case X86_INS_IRETQ: case X86_INS_SYSRET: op->type = R_ANAL_OP_TYPE_RET; if (a->decode) esilprintf (op, "%s,[%d],%s,=,%d,%s,+=", sp, rs, pc, rs, sp); op->stackop = R_ANAL_STACK_INC; op->stackptr = -regsz; break; case X86_INS_INT3: if (a->decode) esilprintf (op, "3,$"); op->type = R_ANAL_OP_TYPE_TRAP; // TRAP break; case X86_INS_INT1: if (a->decode) esilprintf (op, "1,$"); op->type = R_ANAL_OP_TYPE_SWI; // TRAP break; case X86_INS_INT: if (a->decode) esilprintf (op, "%d,$", R_ABS((int)INSOP(0).imm)); op->type = R_ANAL_OP_TYPE_SWI; break; case X86_INS_SYSCALL: op->type = R_ANAL_OP_TYPE_SWI; break; case X86_INS_INTO: case X86_INS_VMCALL: case X86_INS_VMMCALL: op->type = R_ANAL_OP_TYPE_TRAP; if (a->decode) esilprintf (op, "%d,$", (int)INSOP(0).imm); break; case X86_INS_JL: case X86_INS_JLE: case X86_INS_JA: case X86_INS_JAE: case X86_INS_JB: case X86_INS_JBE: case X86_INS_JCXZ: case X86_INS_JECXZ: case X86_INS_JRCXZ: case X86_INS_JO: case X86_INS_JNO: case X86_INS_JS: case X86_INS_JNS: case X86_INS_JP: case X86_INS_JNP: case X86_INS_JE: case X86_INS_JNE: case X86_INS_JG: case X86_INS_JGE: case X86_INS_LOOP: case X86_INS_LOOPE: case X86_INS_LOOPNE: op->type = R_ANAL_OP_TYPE_CJMP; op->jump = INSOP(0).imm; op->fail = addr+op->size; const char *cnt = (a->bits==16)?"cx":(a->bits==32)?"ecx":"rcx"; if (a->decode) { char *dst = getarg (&gop, 0, 2, NULL); switch (insn->id) { case X86_INS_JL: esilprintf (op, "of,sf,^,?{,%s,%s,=,}", dst, pc); break; case X86_INS_JLE: esilprintf (op, "of,sf,^,zf,|,?{,%s,%s,=,}", dst, pc); break; case X86_INS_JA: esilprintf (op, "cf,zf,|,!,?{,%s,%s,=,}",dst, pc); break; case X86_INS_JAE: esilprintf (op, "cf,!,?{,%s,%s,=,}", dst, pc); break; case X86_INS_JB: esilprintf (op, "cf,?{,%s,%s,=,}", dst, pc); break; case X86_INS_JO: esilprintf (op, "of,?{,%s,%s,=,}", dst, pc); break; case X86_INS_JNO: esilprintf (op, "of,!,?{,%s,%s,=,}", dst, pc); break; case X86_INS_JE: esilprintf (op, "zf,?{,%s,%s,=,}", dst, pc); break; case X86_INS_JGE: esilprintf (op, "of,!,sf,^,?{,%s,%s,=,}", dst, pc); break; case X86_INS_JNE: esilprintf (op, "zf,!,?{,%s,%s,=,}", dst, pc); break; case X86_INS_JG: esilprintf (op, "sf,of,!,^,zf,!,&,?{,%s,%s,=,}", dst, pc); break; case X86_INS_JS: esilprintf (op, "sf,?{,%s,%s,=,}", dst, pc); break; case X86_INS_JNS: esilprintf (op, "sf,!,?{,%s,%s,=,}", dst, pc); break; case X86_INS_JP: esilprintf (op, "pf,?{,%s,%s,=,}", dst, pc); break; case X86_INS_JNP: esilprintf (op, "pf,!,?{,%s,%s,=,}", dst, pc); break; case X86_INS_JBE: esilprintf (op, "zf,cf,|,?{,%s,%s,=,}", dst, pc); break; case X86_INS_JCXZ: esilprintf (op, "cx,!,?{,%s,%s,=,}", dst, pc); break; case X86_INS_JECXZ: esilprintf (op, "ecx,!,?{,%s,%s,=,}", dst, pc); break; case X86_INS_JRCXZ: esilprintf (op, "rcx,!,?{,%s,%s,=,}", dst, pc); break; case X86_INS_LOOP: esilprintf (op, "1,%s,-=,%s,?{,%s,%s,=,}", cnt, cnt, dst, pc); break; case X86_INS_LOOPE: esilprintf (op, "1,%s,-=,%s,?{,zf,?{,%s,%s,=,},}", cnt, cnt, dst, pc); break; case X86_INS_LOOPNE: esilprintf (op, "1,%s,-=,%s,?{,zf,!,?{,%s,%s,=,},}", cnt, cnt, dst, pc); break; } free (dst); } break; case X86_INS_CALL: case X86_INS_LCALL: switch (INSOP(0).type) { case X86_OP_IMM: op->type = R_ANAL_OP_TYPE_CALL; // TODO: what if UCALL? // TODO: use imm_size op->jump = INSOP(0).imm; op->fail = addr+op->size; break; case X86_OP_MEM: op->type = R_ANAL_OP_TYPE_UCALL; op->jump = UT64_MAX; if (INSOP(0).mem.base == 0) { op->ptr = INSOP(0).mem.disp; } break; default: op->type = R_ANAL_OP_TYPE_UCALL; op->jump = UT64_MAX; break; } if (a->decode) { char* arg = getarg (&gop, 0, 0, NULL); esilprintf (op, "%s," "%d,%s,-=,%s," "=[]," "%s,%s,=", pc, rs, sp, sp, arg, pc); free (arg); } break; case X86_INS_JMP: case X86_INS_LJMP: if (a->decode) { char *src = getarg (&gop, 0, 0, NULL); esilprintf (op, "%s,%s,=", src, pc); free (src); } // TODO: what if UJMP? switch (INSOP(0).type) { case X86_OP_IMM: op->jump = INSOP(0).imm; op->type = R_ANAL_OP_TYPE_JMP; if (a->decode) { ut64 dst = INSOP(0).imm; esilprintf (op, "0x%"PFMT64x",%s,=", dst, pc); } break; case X86_OP_MEM: op->type = R_ANAL_OP_TYPE_UJMP; if (INSOP(0).mem.base == X86_REG_RIP) { op->ptr = INSOP(0).mem.disp; op->ptr += addr + insn->size; op->refptr = 8; } else { cs_x86_op in = INSOP(0); if (in.mem.index == 0 && in.mem.base == 0 && in.mem.scale == 1) { op->type = R_ANAL_OP_TYPE_UJMP; op->ptr = in.mem.disp; if (a->decode) { esilprintf (op, "0x%"PFMT64x",[],%s,=", op->ptr, pc); } } } break; case X86_OP_REG: case X86_OP_FP: default: // other? op->type = R_ANAL_OP_TYPE_UJMP; break; } break; case X86_INS_IN: case X86_INS_INSW: case X86_INS_INSD: case X86_INS_INSB: case X86_INS_OUT: case X86_INS_OUTSB: case X86_INS_OUTSD: case X86_INS_OUTSW: op->type = R_ANAL_OP_TYPE_IO; break; case X86_INS_VXORPD: case X86_INS_VXORPS: case X86_INS_VPXORD: case X86_INS_VPXORQ: case X86_INS_VPXOR: case X86_INS_XORPS: case X86_INS_KXORW: case X86_INS_PXOR: case X86_INS_XOR: op->type = R_ANAL_OP_TYPE_XOR; if (a->decode) { char *src = getarg (&gop, 1, 0, NULL); char *dst = getarg (&gop, 0, 1, "^"); esilprintf (op, "%s,%s,$z,zf,=,$p,pf,=,0,cf,=,0,of,=,$s,sf,=", src, dst); free (src); free (dst); } break; case X86_INS_OR: op->type = R_ANAL_OP_TYPE_OR; if (a->decode) { char *src = getarg (&gop, 1, 0, NULL); char *dst = getarg (&gop, 0, 0, NULL); esilprintf (op, "%s,%s,|=", src, dst); free (src); free (dst); } break; case X86_INS_INC: op->type = R_ANAL_OP_TYPE_ADD; op->val = 1; if (a->decode) { char *src = getarg (&gop, 0, 0, NULL); esilprintf (op, "%s,++=", src); free (src); } break; case X86_INS_DEC: op->type = R_ANAL_OP_TYPE_SUB; op->val = 1; if (a->decode) { char *src = getarg (&gop, 0, 0, NULL); esilprintf (op, "%s,--=", src); free (src); } break; case X86_INS_SUB: case X86_INS_PSUBB: case X86_INS_PSUBW: case X86_INS_PSUBD: case X86_INS_PSUBQ: case X86_INS_PSUBSB: case X86_INS_PSUBSW: case X86_INS_PSUBUSB: case X86_INS_PSUBUSW: op->type = R_ANAL_OP_TYPE_SUB; if (a->decode) { char *src = getarg (&gop, 1, 0, NULL); char *dst = getarg (&gop, 0, 1, "-"); esilprintf (op, "%s,%s,$c,cf,=,$z,zf,=,$s,sf,=,$o,of,=", src, dst); // TODO: update flags free (src); free (dst); } if (INSOP(0).type == X86_OP_REG && INSOP(1).type == X86_OP_IMM) { if (INSOP(0).reg == X86_REG_RSP || INSOP(0).reg == X86_REG_ESP) { op->stackop = R_ANAL_STACK_INC; op->stackptr = INSOP(1).imm; } } break; case X86_INS_LIDT: op->type = R_ANAL_OP_TYPE_LOAD; op->family = R_ANAL_OP_FAMILY_PRIV; break; case X86_INS_SIDT: op->type = R_ANAL_OP_TYPE_STORE; op->family = R_ANAL_OP_FAMILY_PRIV; break; case X86_INS_RDRAND: case X86_INS_RDSEED: case X86_INS_RDMSR: case X86_INS_RDPMC: case X86_INS_RDTSC: case X86_INS_RDTSCP: case X86_INS_CRC32: case X86_INS_SHA1MSG1: case X86_INS_SHA1MSG2: case X86_INS_SHA1NEXTE: case X86_INS_SHA1RNDS4: case X86_INS_SHA256MSG1: case X86_INS_SHA256MSG2: case X86_INS_SHA256RNDS2: case X86_INS_AESDECLAST: case X86_INS_AESDEC: case X86_INS_AESENCLAST: case X86_INS_AESENC: case X86_INS_AESIMC: case X86_INS_AESKEYGENASSIST: // AES instructions op->family = R_ANAL_OP_FAMILY_CRYPTO; op->type = R_ANAL_OP_TYPE_MOV; // XXX break; case X86_INS_AND: case X86_INS_ANDN: case X86_INS_ANDPD: case X86_INS_ANDPS: case X86_INS_ANDNPD: case X86_INS_ANDNPS: op->type = R_ANAL_OP_TYPE_AND; if (a->decode) { char *src = getarg (&gop, 1, 0, NULL); char *dst = getarg (&gop, 0, 1, "&"); // TODO: update of = cf = 0 // TODO: update sf, zf and pf // TODO: af is undefined esilprintf (op, "0,of,=,0,cf,=," // set carry and overflow flags "%s,%s," // set reg value "$z,zf,=," // update zero flag "$s,sf,=," // update sign flag "$o,pf,=", // update parity flag // TODO: add sign and parity flags here src, dst); free (src); free (dst); } break; case X86_INS_DIV: case X86_INS_IDIV: op->type = R_ANAL_OP_TYPE_DIV; if (a->decode) { int width = INSOP(0).size; char *dst = getarg (&gop, 0, 0, NULL); const char *r_ax = (width==2)?"ax": (width==4)?"eax":"rax"; const char *r_dx = (width==2)?"dx": (width==4)?"edx":"rdx"; // TODO update flags & handle signedness esilprintf (op, "%s,%s,%%,%s,=,%s,%s,/,%s,=", dst, r_ax, r_dx, dst, r_ax, r_ax); free (dst); } break; case X86_INS_MUL: case X86_INS_MULX: case X86_INS_MULPD: case X86_INS_MULPS: case X86_INS_MULSD: case X86_INS_MULSS: op->type = R_ANAL_OP_TYPE_MUL; if (a->decode) { char *src = getarg (&gop, 1, 0, NULL); char *dst = getarg (&gop, 0, 1, "*"); if (!src && dst) { switch (dst[0]) { case 'r': src = strdup ("rax"); break; case 'e': src = strdup ("eax"); break; default: src = strdup ("al"); break; } } esilprintf (op, "%s,%s", src, dst); free (src); free (dst); } break; case X86_INS_PACKSSDW: case X86_INS_PACKSSWB: case X86_INS_PACKUSWB: op->type = R_ANAL_OP_TYPE_MOV; op->family = R_ANAL_OP_FAMILY_MMX; break; case X86_INS_PADDB: case X86_INS_PADDD: case X86_INS_PADDW: case X86_INS_PADDSB: case X86_INS_PADDSW: case X86_INS_PADDUSB: case X86_INS_PADDUSW: op->type = R_ANAL_OP_TYPE_ADD; op->family = R_ANAL_OP_FAMILY_MMX; break; case X86_INS_FADD: case X86_INS_FADDP: op->family = R_ANAL_OP_FAMILY_FPU; /* pass thru */ case X86_INS_ADD: case X86_INS_ADDPS: case X86_INS_ADDSD: case X86_INS_ADDSS: case X86_INS_ADDSUBPD: case X86_INS_ADDSUBPS: case X86_INS_ADDPD: case X86_INS_XADD: op->type = R_ANAL_OP_TYPE_ADD; if (a->decode) { if (INSOP(0).type == X86_OP_MEM) { char *src = getarg (&gop, 1, 0, NULL); char *src2 = getarg (&gop, 0, 0, NULL); char *dst = getarg (&gop, 0, 1, NULL); // TODO: update flags esilprintf (op, "%s,%s,+,%s", src, src2, dst); free (src); free (src2); free (dst); } else { char *src = getarg (&gop, 1, 0, NULL); char *dst = getarg (&gop, 0, 1, "+"); esilprintf (op, "%s,%s", src, dst); // TODO: update flags free (src); free (dst); } } if (INSOP(0).type == X86_OP_REG && INSOP(1).type == X86_OP_IMM) { if (INSOP(0).reg == X86_REG_RSP || INSOP(0).reg == X86_REG_ESP) { op->stackop = R_ANAL_STACK_INC; op->stackptr = -INSOP(1).imm; } } break; /* Direction flag */ case X86_INS_CLD: op->type = R_ANAL_OP_TYPE_MOV; op->family = R_ANAL_OP_FAMILY_CPU; if (a->decode) esilprintf (op, "0,df,="); break; case X86_INS_STD: op->type = R_ANAL_OP_TYPE_MOV; op->family = R_ANAL_OP_FAMILY_CPU; if (a->decode) esilprintf (op, "1,df,="); break; } switch (insn->id) { case X86_INS_MOVAPS: //cvtss2sd case X86_INS_ADDSD: //cvtss2sd case X86_INS_SUBSD: //cvtss2sd case X86_INS_MULSD: //cvtss2sd case X86_INS_CVTSS2SD: //cvtss2sd case X86_INS_MOVSS: case X86_INS_MOVSD: op->family = R_ANAL_OP_FAMILY_MMX; break; } } //#if X86_GRP_PRIVILEGE>0 if (insn) { #if HAVE_CSGRP_PRIVILEGE if (cs_insn_group (handle, insn, X86_GRP_PRIVILEGE)) op->family = R_ANAL_OP_FAMILY_PRIV; #endif #if !USE_ITER_API cs_free (insn, n); #endif } //cs_close (&handle); return op->size; }
/** * Translates operand N to esil * * @param handle csh * @param insn cs_insn * @param n Operand index * @param set if 1 it adds set (=) to the operand * @param setoper Extra operation for the set (^, -, +, etc...) * @return char* with the esil operand */ static char *getarg(struct Getarg* gop, int n, int set, char *setop) { csh handle = gop->handle; cs_insn *insn = gop->insn; char buf[64]; char *setarg = setop? setop : ""; cs_x86_op op; if (!insn->detail) return NULL; buf[0] = 0; if (n<0 || n>=INSOPS) return NULL; op = INSOP (n); switch (op.type) { case X86_OP_INVALID: return strdup ("invalid"); case X86_OP_REG: if (set == 1) { snprintf (buf, sizeof (buf), "%s,%s=", cs_reg_name (handle, op.reg), setarg); return strdup (buf); } else { if (gop->bits == 64) { switch (op.reg) { case X86_REG_EAX: op.reg = X86_REG_RAX; break; case X86_REG_EBX: op.reg = X86_REG_RBX; break; case X86_REG_ECX: op.reg = X86_REG_RCX; break; case X86_REG_EDX: op.reg = X86_REG_RDX; break; case X86_REG_ESI: op.reg = X86_REG_RSI; break; case X86_REG_EDI: op.reg = X86_REG_RDI; break; #if 0 case X86_REG_ESP: op.reg = X86_REG_RSP; break; case X86_REG_EBP: op.reg = X86_REG_RBP; break; #endif default: break; } } return strdup (cs_reg_name (handle, op.reg)); } case X86_OP_IMM: if (set == 1) snprintf (buf, sizeof (buf), "%"PFMT64d",%s=[%d]", (ut64)op.imm, setarg, op.size); else snprintf (buf, sizeof (buf), "%"PFMT64d, (ut64)op.imm); return strdup (buf); case X86_OP_MEM: { const char *base = cs_reg_name (handle, op.mem.base); const char *index = cs_reg_name (handle, op.mem.index); int scale = op.mem.scale; st64 disp = op.mem.disp; if (scale>1) { if (set>1) { if (base) { if (disp) { snprintf (buf, sizeof (buf), "%s,0x%x,+,%d,*", base, (int)disp, scale); } else { snprintf (buf, sizeof (buf), "%s,%d,*", base, scale); } } else { if (disp) { snprintf (buf, sizeof (buf), "%d,0x%x,*,[%d]", scale, (int)disp, op.size); } else { snprintf (buf, sizeof (buf), "%d,[%d]", scale, op.size); } } } else { if (base) { if (disp) { snprintf (buf, sizeof (buf), "0x%x,%s,+,%d,*,[%d]", (int)disp, base, scale, op.size); } else { snprintf (buf, sizeof (buf), "%s,%d,*,[%d]", base, scale, op.size); } } else { if (disp) { snprintf (buf, sizeof (buf), "0x%x,%d,*,[%d]", (int)disp, scale, op.size); } else { snprintf (buf, sizeof (buf), "%d,[%d]", scale, op.size); } } } } else { if (set>1) { if (base) { if (disp) { int v = (int)disp; if (v<0) { snprintf (buf, sizeof (buf), "0x%x,%s,-", -v, base); } else { snprintf (buf, sizeof (buf), "0x%x,%s,+", v, base); } } else { snprintf (buf, sizeof (buf), "%s", base); } } else { if (disp) { snprintf (buf, sizeof (buf), "%d", (int)disp); } } } else { if (base) { if (disp) { int v = (int)disp; if (v<0) { snprintf (buf, sizeof (buf), "0x%x,%s,-,%s%s[%d]", -(int)disp, base, setarg, set?"=":"", op.size); } else { snprintf (buf, sizeof (buf), "0x%x,%s,+,%s%s[%d]", (int)disp, base, setarg, set?"=":"", op.size); } } else { if (index) if (set) snprintf (buf, sizeof (buf), "%s,%s,+,%s=[%d]", base, index, setarg, op.size); else snprintf (buf, sizeof (buf), "%s,%s,+", base, index); else snprintf (buf, sizeof (buf), "%s,%s%s[%d]", base, setarg, set?"=":"", op.size); } } else { if (disp) { snprintf (buf, sizeof (buf), "0x%x,%s%s[%d]", (int)disp, setarg, set?"=":"", op.size); } else { snprintf (buf, sizeof (buf), "%s%s,[%d]", setarg, set?"=":"", op.size); } } } } } return strdup (buf); case X86_OP_FP: break; } return strdup ("PoP"); }
static void test() { #ifdef CAPSTONE_HAS_X86 #define X86_CODE16 "\x8d\x4c\x32\x08\x01\xd8\x81\xc6\x34\x12\x00\x00" #define X86_CODE32 "\x8d\x4c\x32\x08\x01\xd8\x81\xc6\x34\x12\x00\x00" //#define X86_CODE32 "\x0f\xa7\xc0" // xstorerng #define X86_CODE64 "\x55\x48\x8b\x05\xb8\x13\x00\x00" #endif #ifdef CAPSTONE_HAS_ARM //#define ARM_CODE "\x04\xe0\x2d\xe5" #define ARM_CODE "\xED\xFF\xFF\xEB\x04\xe0\x2d\xe5\x00\x00\x00\x00\xe0\x83\x22\xe5\xf1\x02\x03\x0e\x00\x00\xa0\xe3\x02\x30\xc1\xe7\x00\x00\x53\xe3" #define ARM_CODE2 "\x10\xf1\x10\xe7\x11\xf2\x31\xe7\xdc\xa1\x2e\xf3\xe8\x4e\x62\xf3" #define THUMB_CODE "\x70\x47\xeb\x46\x83\xb0\xc9\x68" #define THUMB_CODE2 "\x4f\xf0\x00\x01\xbd\xe8\x00\x88\xd1\xe8\x00\xf0" #define THUMB_MCLASS "\xef\xf3\x02\x80" #define ARMV8 "\xe0\x3b\xb2\xee\x42\x00\x01\xe1\x51\xf0\x7f\xf5" #endif #ifdef CAPSTONE_HAS_MIPS #define MIPS_CODE "\x0C\x10\x00\x97\x00\x00\x00\x00\x24\x02\x00\x0c\x8f\xa2\x00\x00\x34\x21\x34\x56\x00\x80\x04\x08" //#define MIPS_CODE "\x21\x38\x00\x01" //#define MIPS_CODE "\x21\x30\xe6\x70" //#define MIPS_CODE "\x1c\x00\x40\x14" #define MIPS_CODE2 "\x56\x34\x21\x34\xc2\x17\x01\x00" #define MIPS_32R6M "\x00\x07\x00\x07\x00\x11\x93\x7c\x01\x8c\x8b\x7c\x00\xc7\x48\xd0" #define MIPS_32R6 "\xec\x80\x00\x19\x7c\x43\x22\xa0" #endif #ifdef CAPSTONE_HAS_ARM64 //#define ARM64_CODE "\xe1\x0b\x40\xb9" // ldr w1, [sp, #0x8] //#define ARM64_CODE "\x00\x40\x21\x4b" // sub w0, w0, w1, uxtw //#define ARM64_CODE "\x21\x7c\x02\x9b" // mul x1, x1, x2 //#define ARM64_CODE "\x20\x74\x0b\xd5" // dc zva, x0 //#define ARM64_CODE "\x20\xfc\x02\x9b" // mneg x0, x1, x2 //#define ARM64_CODE "\x21\x7c\x02\x9b\x21\x7c\x00\x53\x00\x40\x21\x4b\xe1\x0b\x40\xb9\x10\x20\x21\x1e" //#define ARM64_CODE "\x21\x7c\x00\x53" #define ARM64_CODE "\x09\x00\x38\xd5\xbf\x40\x00\xd5\x0c\x05\x13\xd5\x20\x50\x02\x0e\x20\xe4\x3d\x0f\x00\x18\xa0\x5f\xa2\x00\xae\x9e\x9f\x37\x03\xd5\xbf\x33\x03\xd5\xdf\x3f\x03\xd5\x21\x7c\x02\x9b\x21\x7c\x00\x53\x00\x40\x21\x4b\xe1\x0b\x40\xb9\x20\x04\x81\xda\x20\x08\x02\x8b\x10\x5b\xe8\x3c" #endif //#define THUMB_CODE "\x0a\xbf" // itet eq //#define X86_CODE32 "\x77\x04" // ja +6 #ifdef CAPSTONE_HAS_PPC #define PPC_CODE "\x80\x20\x00\x00\x80\x3f\x00\x00\x10\x43\x23\x0e\xd0\x44\x00\x80\x4c\x43\x22\x02\x2d\x03\x00\x80\x7c\x43\x20\x14\x7c\x43\x20\x93\x4f\x20\x00\x21\x4c\xc8\x00\x21\x40\x82\x00\x14" #define PPC_CODE2 "\x10\x60\x2a\x10\x10\x64\x28\x88\x7c\x4a\x5d\x0f" #endif #ifdef CAPSTONE_HAS_SPARC #define SPARC_CODE "\x80\xa0\x40\x02\x85\xc2\x60\x08\x85\xe8\x20\x01\x81\xe8\x00\x00\x90\x10\x20\x01\xd5\xf6\x10\x16\x21\x00\x00\x0a\x86\x00\x40\x02\x01\x00\x00\x00\x12\xbf\xff\xff\x10\xbf\xff\xff\xa0\x02\x00\x09\x0d\xbf\xff\xff\xd4\x20\x60\x00\xd4\x4e\x00\x16\x2a\xc2\x80\x03" #define SPARCV9_CODE "\x81\xa8\x0a\x24\x89\xa0\x10\x20\x89\xa0\x1a\x60\x89\xa0\x00\xe0" #endif #ifdef CAPSTONE_HAS_SYSZ #define SYSZ_CODE "\xed\x00\x00\x00\x00\x1a\x5a\x0f\x1f\xff\xc2\x09\x80\x00\x00\x00\x07\xf7\xeb\x2a\xff\xff\x7f\x57\xe3\x01\xff\xff\x7f\x57\xeb\x00\xf0\x00\x00\x24\xb2\x4f\x00\x78" #endif #ifdef CAPSTONE_HAS_XCORE #define XCORE_CODE "\xfe\x0f\xfe\x17\x13\x17\xc6\xfe\xec\x17\x97\xf8\xec\x4f\x1f\xfd\xec\x37\x07\xf2\x45\x5b\xf9\xfa\x02\x06\x1b\x10" #endif #ifdef CAPSTONE_HAS_M68K #define M68K_CODE "\xd4\x40\x87\x5a\x4e\x71\x02\xb4\xc0\xde\xc0\xde\x5c\x00\x1d\x80\x71\x12\x01\x23\xf2\x3c\x44\x22\x40\x49\x0e\x56\x54\xc5\xf2\x3c\x44\x00\x44\x7a\x00\x00\xf2\x00\x0a\x28" #endif struct platform platforms[] = { #ifdef CAPSTONE_HAS_X86 { CS_ARCH_X86, CS_MODE_16, (unsigned char *)X86_CODE16, sizeof(X86_CODE32) - 1, "X86 16bit (Intel syntax)" }, { CS_ARCH_X86, CS_MODE_32, (unsigned char *)X86_CODE32, sizeof(X86_CODE32) - 1, "X86 32bit (ATT syntax)", CS_OPT_SYNTAX, CS_OPT_SYNTAX_ATT, }, { CS_ARCH_X86, CS_MODE_32, (unsigned char *)X86_CODE32, sizeof(X86_CODE32) - 1, "X86 32 (Intel syntax)" }, { CS_ARCH_X86, CS_MODE_64, (unsigned char *)X86_CODE64, sizeof(X86_CODE64) - 1, "X86 64 (Intel syntax)" }, #endif #ifdef CAPSTONE_HAS_ARM { CS_ARCH_ARM, CS_MODE_ARM, (unsigned char *)ARM_CODE, sizeof(ARM_CODE) - 1, "ARM" }, { CS_ARCH_ARM, CS_MODE_THUMB, (unsigned char *)THUMB_CODE2, sizeof(THUMB_CODE2) - 1, "THUMB-2" }, { CS_ARCH_ARM, CS_MODE_ARM, (unsigned char *)ARM_CODE2, sizeof(ARM_CODE2) - 1, "ARM: Cortex-A15 + NEON" }, { CS_ARCH_ARM, CS_MODE_THUMB, (unsigned char *)THUMB_CODE, sizeof(THUMB_CODE) - 1, "THUMB" }, { CS_ARCH_ARM, (cs_mode)(CS_MODE_THUMB + CS_MODE_MCLASS), (unsigned char*)THUMB_MCLASS, sizeof(THUMB_MCLASS) - 1, "Thumb-MClass" }, { CS_ARCH_ARM, (cs_mode)(CS_MODE_ARM + CS_MODE_V8), (unsigned char*)ARMV8, sizeof(ARMV8) - 1, "Arm-V8" }, #endif #ifdef CAPSTONE_HAS_MIPS { CS_ARCH_MIPS, (cs_mode)(CS_MODE_MIPS32 + CS_MODE_BIG_ENDIAN), (unsigned char *)MIPS_CODE, sizeof(MIPS_CODE) - 1, "MIPS-32 (Big-endian)" }, { CS_ARCH_MIPS, (cs_mode)(CS_MODE_MIPS64 + CS_MODE_LITTLE_ENDIAN), (unsigned char *)MIPS_CODE2, sizeof(MIPS_CODE2) - 1, "MIPS-64-EL (Little-endian)" }, { CS_ARCH_MIPS, (cs_mode)(CS_MODE_MIPS32R6 + CS_MODE_MICRO + CS_MODE_BIG_ENDIAN), (unsigned char*)MIPS_32R6M, sizeof(MIPS_32R6M) - 1, "MIPS-32R6 | Micro (Big-endian)" }, { CS_ARCH_MIPS, (cs_mode)(CS_MODE_MIPS32R6 + CS_MODE_BIG_ENDIAN), (unsigned char*)MIPS_32R6, sizeof(MIPS_32R6) - 1, "MIPS-32R6 (Big-endian)" }, #endif #ifdef CAPSTONE_HAS_ARM64 { CS_ARCH_ARM64, CS_MODE_ARM, (unsigned char *)ARM64_CODE, sizeof(ARM64_CODE) - 1, "ARM-64" }, #endif #ifdef CAPSTONE_HAS_PPC { CS_ARCH_PPC, CS_MODE_BIG_ENDIAN, (unsigned char*)PPC_CODE, sizeof(PPC_CODE) - 1, "PPC-64" }, { CS_ARCH_PPC, CS_MODE_BIG_ENDIAN + CS_MODE_QPX, (unsigned char*)PPC_CODE2, sizeof(PPC_CODE2) - 1, "PPC-64 + QPX", }, #endif #ifdef CAPSTONE_HAS_SPARC { CS_ARCH_SPARC, CS_MODE_BIG_ENDIAN, (unsigned char*)SPARC_CODE, sizeof(SPARC_CODE) - 1, "Sparc" }, { CS_ARCH_SPARC, (cs_mode)(CS_MODE_BIG_ENDIAN + CS_MODE_V9), (unsigned char*)SPARCV9_CODE, sizeof(SPARCV9_CODE) - 1, "SparcV9" }, #endif #ifdef CAPSTONE_HAS_SYSZ { CS_ARCH_SYSZ, (cs_mode)0, (unsigned char*)SYSZ_CODE, sizeof(SYSZ_CODE) - 1, "SystemZ" }, #endif #ifdef CAPSTONE_HAS_XCORE { CS_ARCH_XCORE, (cs_mode)0, (unsigned char*)XCORE_CODE, sizeof(XCORE_CODE) - 1, "XCore" }, #endif #ifdef CAPSTONE_HAS_M68K { CS_ARCH_M68K, CS_MODE_BIG_ENDIAN | CS_MODE_M68K_040, (unsigned char*)M68K_CODE, sizeof(M68K_CODE) - 1, "M68K", }, #endif }; csh handle; uint64_t address = 0x1000; cs_insn *all_insn; cs_detail *detail; int i; size_t count; cs_err err; for (i = 0; i < sizeof(platforms)/sizeof(platforms[0]); i++) { printf("****************\n"); printf("Platform: %s\n", platforms[i].comment); err = cs_open(platforms[i].arch, platforms[i].mode, &handle); if (err) { printf("Failed on cs_open() with error returned: %u\n", err); abort(); } if (platforms[i].opt_type) cs_option(handle, platforms[i].opt_type, platforms[i].opt_value); cs_option(handle, CS_OPT_DETAIL, CS_OPT_ON); count = cs_disasm(handle, platforms[i].code, platforms[i].size, address, 0, &all_insn); if (count) { size_t j; int n; print_string_hex(platforms[i].code, platforms[i].size); printf("Disasm:\n"); for (j = 0; j < count; j++) { cs_insn *in = &(all_insn[j]); printf("0x%"PRIx64":\t%s\t\t%s // insn-ID: %u, insn-mnem: %s\n", in->address, in->mnemonic, in->op_str, in->id, cs_insn_name(handle, in->id)); // print implicit registers used by this instruction detail = in->detail; if (detail->regs_read_count > 0) { printf("\tImplicit registers read: "); for (n = 0; n < detail->regs_read_count; n++) { printf("%s ", cs_reg_name(handle, detail->regs_read[n])); } printf("\n"); } // print implicit registers modified by this instruction if (detail->regs_write_count > 0) { printf("\tImplicit registers modified: "); for (n = 0; n < detail->regs_write_count; n++) { printf("%s ", cs_reg_name(handle, detail->regs_write[n])); } printf("\n"); } // print the groups this instruction belong to if (detail->groups_count > 0) { printf("\tThis instruction belongs to groups: "); for (n = 0; n < detail->groups_count; n++) { printf("%s ", cs_group_name(handle, detail->groups[n])); } printf("\n"); } } // print out the next offset, after the last insn printf("0x%"PRIx64":\n", all_insn[j-1].address + all_insn[j-1].size); // free memory allocated by cs_disasm() cs_free(all_insn, count); } else { printf("****************\n"); printf("Platform: %s\n", platforms[i].comment); print_string_hex(platforms[i].code, platforms[i].size); printf("ERROR: Failed to disasm given code!\n"); abort(); } printf("\n"); cs_close(&handle); } }
static void print_insn_detail(cs_insn *ins) { cs_arm64 *arm64; int i; // detail can be NULL if SKIPDATA option is turned ON if (ins->detail == NULL) return; arm64 = &(ins->detail->arm64); if (arm64->op_count) printf("\top_count: %u\n", arm64->op_count); for (i = 0; i < arm64->op_count; i++) { cs_arm64_op *op = &(arm64->operands[i]); switch(op->type) { default: break; case ARM64_OP_REG: printf("\t\toperands[%u].type: REG = %s\n", i, cs_reg_name(handle, op->reg)); break; case ARM64_OP_IMM: printf("\t\toperands[%u].type: IMM = 0x%"PRIx64 "\n", i, op->imm); break; case ARM64_OP_FP: printf("\t\toperands[%u].type: FP = %f\n", i, op->fp); break; case ARM64_OP_MEM: printf("\t\toperands[%u].type: MEM\n", i); if (op->mem.base != ARM64_REG_INVALID) printf("\t\t\toperands[%u].mem.base: REG = %s\n", i, cs_reg_name(handle, op->mem.base)); if (op->mem.index != ARM64_REG_INVALID) printf("\t\t\toperands[%u].mem.index: REG = %s\n", i, cs_reg_name(handle, op->mem.index)); if (op->mem.disp != 0) printf("\t\t\toperands[%u].mem.disp: 0x%x\n", i, op->mem.disp); break; case ARM64_OP_CIMM: printf("\t\toperands[%u].type: C-IMM = %u\n", i, (int)op->imm); break; case ARM64_OP_REG_MRS: printf("\t\toperands[%u].type: REG_MRS = 0x%x\n", i, op->reg); break; case ARM64_OP_REG_MSR: printf("\t\toperands[%u].type: REG_MSR = 0x%x\n", i, op->reg); break; case ARM64_OP_PSTATE: printf("\t\toperands[%u].type: PSTATE = 0x%x\n", i, op->pstate); break; case ARM64_OP_SYS: printf("\t\toperands[%u].type: SYS = 0x%x\n", i, op->sys); break; case ARM64_OP_PREFETCH: printf("\t\toperands[%u].type: PREFETCH = 0x%x\n", i, op->prefetch); break; case ARM64_OP_BARRIER: printf("\t\toperands[%u].type: BARRIER = 0x%x\n", i, op->barrier); break; } if (op->shift.type != ARM64_SFT_INVALID && op->shift.value) printf("\t\t\tShift: type = %u, value = %u\n", op->shift.type, op->shift.value); if (op->ext != ARM64_EXT_INVALID) printf("\t\t\tExt: %u\n", op->ext); if (op->vas != ARM64_VAS_INVALID) printf("\t\t\tVector Arrangement Specifier: 0x%x\n", op->vas); if (op->vess != ARM64_VESS_INVALID) printf("\t\t\tVector Element Size Specifier: %u\n", op->vess); if (op->vector_index != -1) printf("\t\t\tVector Index: %u\n", op->vector_index); } if (arm64->update_flags) printf("\tUpdate-flags: True\n"); if (arm64->writeback) printf("\tWrite-back: True\n"); if (arm64->cc) printf("\tCode-condition: %u\n", arm64->cc); printf("\n"); }
static void test() { #ifdef CAPSTONE_HAS_X86 #define X86_CODE16 "\x8d\x4c\x32\x08\x01\xd8\x81\xc6\x34\x12\x00\x00" #define X86_CODE32 "\x8d\x4c\x32\x08\x01\xd8\x81\xc6\x34\x12\x00\x00" #define X86_CODE64 "\x55\x48\x8b\x05\xb8\x13\x00\x00" #endif #ifdef CAPSTONE_HAS_ARM #define ARM_CODE "\xED\xFF\xFF\xEB\x04\xe0\x2d\xe5\x00\x00\x00\x00\xe0\x83\x22\xe5\xf1\x02\x03\x0e\x00\x00\xa0\xe3\x02\x30\xc1\xe7\x00\x00\x53\xe3" #define ARM_CODE2 "\x10\xf1\x10\xe7\x11\xf2\x31\xe7\xdc\xa1\x2e\xf3\xe8\x4e\x62\xf3" #define THUMB_CODE "\x70\x47\xeb\x46\x83\xb0\xc9\x68" #define THUMB_CODE2 "\x4f\xf0\x00\x01\xbd\xe8\x00\x88\xd1\xe8\x00\xf0" #endif #ifdef CAPSTONE_HAS_MIPS #define MIPS_CODE "\x0C\x10\x00\x97\x00\x00\x00\x00\x24\x02\x00\x0c\x8f\xa2\x00\x00\x34\x21\x34\x56\x00\x80\x04\x08" #define MIPS_CODE2 "\x56\x34\x21\x34\xc2\x17\x01\x00" #endif #ifdef CAPSTONE_HAS_ARM64 #define ARM64_CODE "\x09\x00\x38\xd5\xbf\x40\x00\xd5\x0c\x05\x13\xd5\x20\x50\x02\x0e\x20\xe4\x3d\x0f\x00\x18\xa0\x5f\xa2\x00\xae\x9e\x9f\x37\x03\xd5\xbf\x33\x03\xd5\xdf\x3f\x03\xd5\x21\x7c\x02\x9b\x21\x7c\x00\x53\x00\x40\x21\x4b\xe1\x0b\x40\xb9\x20\x04\x81\xda\x20\x08\x02\x8b\x10\x5b\xe8\x3c" #endif #ifdef CAPSTONE_HAS_POWERPC #define PPC_CODE "\x80\x20\x00\x00\x80\x3f\x00\x00\x10\x43\x23\x0e\xd0\x44\x00\x80\x4c\x43\x22\x02\x2d\x03\x00\x80\x7c\x43\x20\x14\x7c\x43\x20\x93\x4f\x20\x00\x21\x4c\xc8\x00\x21\x40\x82\x00\x14" #endif #ifdef CAPSTONE_HAS_SPARC #define SPARC_CODE "\x80\xa0\x40\x02\x85\xc2\x60\x08\x85\xe8\x20\x01\x81\xe8\x00\x00\x90\x10\x20\x01\xd5\xf6\x10\x16\x21\x00\x00\x0a\x86\x00\x40\x02\x01\x00\x00\x00\x12\xbf\xff\xff\x10\xbf\xff\xff\xa0\x02\x00\x09\x0d\xbf\xff\xff\xd4\x20\x60\x00\xd4\x4e\x00\x16\x2a\xc2\x80\x03" #define SPARCV9_CODE "\x81\xa8\x0a\x24\x89\xa0\x10\x20\x89\xa0\x1a\x60\x89\xa0\x00\xe0" #endif #ifdef CAPSTONE_HAS_SYSZ #define SYSZ_CODE "\xed\x00\x00\x00\x00\x1a\x5a\x0f\x1f\xff\xc2\x09\x80\x00\x00\x00\x07\xf7\xeb\x2a\xff\xff\x7f\x57\xe3\x01\xff\xff\x7f\x57\xeb\x00\xf0\x00\x00\x24\xb2\x4f\x00\x78" #endif #ifdef CAPSTONE_HAS_XCORE #define XCORE_CODE "\xfe\x0f\xfe\x17\x13\x17\xc6\xfe\xec\x17\x97\xf8\xec\x4f\x1f\xfd\xec\x37\x07\xf2\x45\x5b\xf9\xfa\x02\x06\x1b\x10" #endif #ifdef CAPSTONE_HAS_M680X #define M680X_CODE "\x06\x10\x19\x1a\x55\x1e\x01\x23\xe9\x31\x06\x34\x55\xa6\x81\xa7\x89\x7f\xff\xa6\x9d\x10\x00\xa7\x91\xa6\x9f\x10\x00\x11\xac\x99\x10\x00\x39" #endif #ifdef CAPSTONE_HAS_MOS65XX #define MOS65XX_CODE "\x0d\x34\x12\x08\x09\xFF\x10\x80\x20\x00\x00\x98" #endif #define EBPF_CODE "\x97\x09\x00\x00\x37\x13\x03\x00\xdc\x02\x00\x00\x20\x00\x00\x00\x30\x00\x00\x00\x00\x00\x00\x00\xdb\x3a\x00\x01\x00\x00\x00\x00\x84\x02\x00\x00\x00\x00\x00\x00\x6d\x33\x17\x02\x00\x00\x00\x00" #ifdef CAPSTONE_HAS_RISCV #define RISCV_CODE32 "\x37\x34\x00\x00\x97\x82\x00\x00\xef\x00\x80\x00\xef\xf0\x1f\xff\xe7\x00\x45\x00\xe7\x00\xc0\xff\x63\x05\x41\x00\xe3\x9d\x61\xfe\x63\xca\x93\x00\x63\x53\xb5\x00\x63\x65\xd6\x00\x63\x76\xf7\x00\x03\x88\x18\x00\x03\x99\x49\x00\x03\xaa\x6a\x00\x03\xcb\x2b\x01\x03\xdc\x8c\x01\x23\x86\xad\x03\x23\x9a\xce\x03\x23\x8f\xef\x01\x93\x00\xe0\x00\x13\xa1\x01\x01\x13\xb2\x02\x7d\x13\xc3\x03\xdd\x13\xe4\xc4\x12\x13\xf5\x85\x0c\x13\x96\xe6\x01\x13\xd7\x97\x01\x13\xd8\xf8\x40\x33\x89\x49\x01\xb3\x0a\x7b\x41\x33\xac\xac\x01\xb3\x3d\xde\x01\x33\xd2\x62\x40\xb3\x43\x94\x00\x33\xe5\xc5\x00\xb3\x76\xf7\x00\xb3\x54\x39\x01\xb3\x50\x31\x00\x33\x9f\x0f\x00" #define RISCV_CODE64 "\x13\x04\xa8\x7a" // aaa80413 #endif struct platform platforms[] = { #ifdef CAPSTONE_HAS_X86 { CS_ARCH_X86, CS_MODE_16, (unsigned char *)X86_CODE16, sizeof(X86_CODE32) - 1, "X86 16bit (Intel syntax)" }, { CS_ARCH_X86, CS_MODE_32, (unsigned char *)X86_CODE32, sizeof(X86_CODE32) - 1, "X86 32bit (ATT syntax)", CS_OPT_SYNTAX, CS_OPT_SYNTAX_ATT, }, { CS_ARCH_X86, CS_MODE_32, (unsigned char *)X86_CODE32, sizeof(X86_CODE32) - 1, "X86 32 (Intel syntax)" }, { CS_ARCH_X86, CS_MODE_64, (unsigned char *)X86_CODE64, sizeof(X86_CODE64) - 1, "X86 64 (Intel syntax)" }, #endif #ifdef CAPSTONE_HAS_ARM { CS_ARCH_ARM, CS_MODE_ARM, (unsigned char *)ARM_CODE, sizeof(ARM_CODE) - 1, "ARM" }, { CS_ARCH_ARM, CS_MODE_THUMB, (unsigned char *)THUMB_CODE2, sizeof(THUMB_CODE2) - 1, "THUMB-2" }, { CS_ARCH_ARM, CS_MODE_ARM, (unsigned char *)ARM_CODE2, sizeof(ARM_CODE2) - 1, "ARM: Cortex-A15 + NEON" }, { CS_ARCH_ARM, CS_MODE_THUMB, (unsigned char *)THUMB_CODE, sizeof(THUMB_CODE) - 1, "THUMB" }, #endif #ifdef CAPSTONE_HAS_MIPS { CS_ARCH_MIPS, (cs_mode)(CS_MODE_MIPS32 + CS_MODE_BIG_ENDIAN), (unsigned char *)MIPS_CODE, sizeof(MIPS_CODE) - 1, "MIPS-32 (Big-endian)" }, { CS_ARCH_MIPS, (cs_mode)(CS_MODE_MIPS64 + CS_MODE_LITTLE_ENDIAN), (unsigned char *)MIPS_CODE2, sizeof(MIPS_CODE2) - 1, "MIPS-64-EL (Little-endian)" }, #endif #ifdef CAPSTONE_HAS_ARM64 { CS_ARCH_ARM64, CS_MODE_ARM, (unsigned char *)ARM64_CODE, sizeof(ARM64_CODE) - 1, "ARM-64" }, #endif #ifdef CAPSTONE_HAS_POWERPC { CS_ARCH_PPC, CS_MODE_BIG_ENDIAN, (unsigned char*)PPC_CODE, sizeof(PPC_CODE) - 1, "PPC-64" }, #endif #ifdef CAPSTONE_HAS_SPARC { CS_ARCH_SPARC, CS_MODE_BIG_ENDIAN, (unsigned char*)SPARC_CODE, sizeof(SPARC_CODE) - 1, "Sparc" }, { CS_ARCH_SPARC, (cs_mode)(CS_MODE_BIG_ENDIAN + CS_MODE_V9), (unsigned char*)SPARCV9_CODE, sizeof(SPARCV9_CODE) - 1, "SparcV9" }, #endif #ifdef CAPSTONE_HAS_SYSZ { CS_ARCH_SYSZ, (cs_mode)0, (unsigned char*)SYSZ_CODE, sizeof(SYSZ_CODE) - 1, "SystemZ" }, #endif #ifdef CAPSTONE_HAS_XCORE { CS_ARCH_XCORE, (cs_mode)0, (unsigned char*)XCORE_CODE, sizeof(XCORE_CODE) - 1, "XCore" }, #endif #ifdef CAPSTONE_HAS_M680X { CS_ARCH_M680X, (cs_mode)CS_MODE_M680X_6809, (unsigned char*)M680X_CODE, sizeof(M680X_CODE) - 1, "M680X_6809" }, #endif #ifdef CAPSTONE_HAS_MOS65XX { CS_ARCH_MOS65XX, (cs_mode)CS_MODE_LITTLE_ENDIAN, (unsigned char*)MOS65XX_CODE, sizeof(MOS65XX_CODE) - 1, "MOS65XX" }, #endif #ifdef CAPSTONE_HAS_BPF { CS_ARCH_BPF, CS_MODE_LITTLE_ENDIAN | CS_MODE_BPF_EXTENDED, (unsigned char*) EBPF_CODE, sizeof(EBPF_CODE) - 1, "eBPF" }, #endif #ifdef CAPSTONE_HAS_RISCV { CS_ARCH_RISCV, CS_MODE_RISCV32, (unsigned char *)RISCV_CODE32, sizeof(RISCV_CODE32) - 1, "RISCV32" }, { CS_ARCH_RISCV, CS_MODE_RISCV64, (unsigned char *)RISCV_CODE64, sizeof(RISCV_CODE64) - 1, "RISCV64" }, #endif }; csh handle; uint64_t address; cs_insn *insn; cs_detail *detail; int i; cs_err err; const uint8_t *code; size_t size; for (i = 0; i < sizeof(platforms)/sizeof(platforms[0]); i++) { printf("****************\n"); printf("Platform: %s\n", platforms[i].comment); err = cs_open(platforms[i].arch, platforms[i].mode, &handle); if (err) { printf("Failed on cs_open() with error returned: %u\n", err); abort(); } if (platforms[i].opt_type) cs_option(handle, platforms[i].opt_type, platforms[i].opt_value); cs_option(handle, CS_OPT_DETAIL, CS_OPT_ON); // allocate memory for the cache to be used by cs_disasm_iter() insn = cs_malloc(handle); print_string_hex(platforms[i].code, platforms[i].size); printf("Disasm:\n"); address = 0x1000; code = platforms[i].code; size = platforms[i].size; while(cs_disasm_iter(handle, &code, &size, &address, insn)) { int n; printf("0x%" PRIx64 ":\t%s\t\t%s // insn-ID: %u, insn-mnem: %s\n", insn->address, insn->mnemonic, insn->op_str, insn->id, cs_insn_name(handle, insn->id)); // print implicit registers used by this instruction detail = insn->detail; if (detail->regs_read_count > 0) { printf("\tImplicit registers read: "); for (n = 0; n < detail->regs_read_count; n++) { printf("%s ", cs_reg_name(handle, detail->regs_read[n])); } printf("\n"); } // print implicit registers modified by this instruction if (detail->regs_write_count > 0) { printf("\tImplicit registers modified: "); for (n = 0; n < detail->regs_write_count; n++) { printf("%s ", cs_reg_name(handle, detail->regs_write[n])); } printf("\n"); } // print the groups this instruction belong to if (detail->groups_count > 0) { printf("\tThis instruction belongs to groups: "); for (n = 0; n < detail->groups_count; n++) { printf("%s ", cs_group_name(handle, detail->groups[n])); } printf("\n"); } } printf("\n"); // free memory allocated by cs_malloc() cs_free(insn, 1); cs_close(&handle); } }