From 750f3d44ef7237b56ee03a00d47b591e7a3c9212 Mon Sep 17 00:00:00 2001 From: TheN00bBuilder Date: Mon, 24 Jun 2024 21:38:26 -0500 Subject: [PATCH 1/3] Added basics to support context switch - still working --- librz/arch/p/analysis/analysis_arm_cs.c | 31 +++++++++++++++++++++---- librz/include/rz_analysis.h | 4 +++- librz/main/rz-asm.c | 1 + 3 files changed, 30 insertions(+), 6 deletions(-) diff --git a/librz/arch/p/analysis/analysis_arm_cs.c b/librz/arch/p/analysis/analysis_arm_cs.c index a5cd54eacae..8cfca09fc57 100644 --- a/librz/arch/p/analysis/analysis_arm_cs.c +++ b/librz/arch/p/analysis/analysis_arm_cs.c @@ -1264,11 +1264,11 @@ inline static void set_ret(const cs_insn *insn, RZ_BORROW RzAnalysisOp *op) { } static void anop32(RzAnalysis *a, csh handle, RzAnalysisOp *op, cs_insn *insn, bool thumb, const ut8 *buf, int len) { + //fprintf(stderr, "anop32 entered\n"); AnalysisArmCSContext *ctx = (AnalysisArmCSContext *)a->plugin_data; const ut64 addr = op->addr; const int pcdelta = thumb ? 4 : 8; int i; - op->cond = cond_cs2rz_32(insn->detail->arm.cc); if (op->cond == RZ_TYPE_COND_NV) { op->type = RZ_ANALYSIS_OP_TYPE_NOP; @@ -1709,7 +1709,18 @@ jmp $$ + 4 + ( [delta] * 2 ) op->reg = cs_reg_name(handle, REGID(0)); } else { /* blx label */ - op->type = RZ_ANALYSIS_OP_TYPE_CALL; + // check immediate jump address: + // if immediate operand bit 0 is 1, then its jumping to THUMB mode + if (IMM(0) && 1 && insn->bytes[12]){ + op->type = RZ_ANALYSIS_OP_TYPE_CTX_SWITCH; + } + // Check for T2 encoding - if bit 12 is 0, must check IMM(1) instead + else if (!insn->bytes[12]) { + (IMM(1) && 1) ? op->type = RZ_ANALYSIS_OP_TYPE_CTX_SWITCH : RZ_ANALYSIS_OP_TYPE_CALL; + } + else { + op->type = RZ_ANALYSIS_OP_TYPE_CALL; + } op->jump = IMM(0) & UT32_MAX; op->fail = addr + op->size; op->hint.new_bits = (a->bits == 32) ? 16 : 32; @@ -1720,7 +1731,14 @@ jmp $$ + 4 + ( [delta] * 2 ) case ARM_INS_BL: /* bl label */ op->cycles = 4; - op->type = RZ_ANALYSIS_OP_TYPE_CALL; + // check address: if immediate operand bit 0 is 1, then its jumping to THUMB mode + // no difference in T1/T2 encoding here + if (IMM(0) && 1) { + op->type = RZ_ANALYSIS_OP_TYPE_CTX_SWITCH; + } + else { + op->type = RZ_ANALYSIS_OP_TYPE_CALL; + } op->jump = IMM(0) & UT32_MAX; op->fail = addr + op->size; op->hint.new_bits = a->bits; @@ -1760,6 +1778,7 @@ jmp $$ + 4 + ( [delta] * 2 ) case ARM_INS_BX: case ARM_INS_BXJ: /* bx reg */ + if (op->val) op->cycles = 4; op->reg = cs_reg_name(handle, REGID(0)); switch (REGID(0)) { @@ -2061,8 +2080,8 @@ static void patch_capstone_bugs(cs_insn *insn, int bits, bool big_endian) { static int analysis_op(RzAnalysis *a, RzAnalysisOp *op, ut64 addr, const ut8 *buf, int len, RzAnalysisOpMask mask) { AnalysisArmCSContext *ctx = (AnalysisArmCSContext *)a->plugin_data; - cs_insn *insn = NULL; + //op->should_be_thumb = 1; int mode = (a->bits == 16) ? CS_MODE_THUMB : CS_MODE_ARM; int n, ret; mode |= (a->big_endian) ? CS_MODE_BIG_ENDIAN : CS_MODE_LITTLE_ENDIAN; @@ -2136,9 +2155,11 @@ static int analysis_op(RzAnalysis *a, RzAnalysisOp *op, ut64 addr, const ut8 *bu } else { anop32(a, ctx->handle, op, insn, thumb, (ut8 *)buf, len); if (mask & RZ_ANALYSIS_OP_MASK_OPEX) { + fprintf(stderr, "doing opex\n"); opex(&op->opex, ctx->handle, insn); } if (mask & RZ_ANALYSIS_OP_MASK_ESIL) { + fprintf(stderr, "doing esil\n"); rz_arm_cs_analysis_op_32_esil(a, op, addr, buf, len, &ctx->handle, insn, thumb); } if (mask & RZ_ANALYSIS_OP_MASK_IL) { @@ -2572,7 +2593,6 @@ static ut8 *analysis_mask(RzAnalysis *analysis, int size, const ut8 *data, ut64 if (!data) { return NULL; } - op = rz_analysis_op_new(); ret = malloc(size); memset(ret, 0xff, size); @@ -2587,6 +2607,7 @@ static ut8 *analysis_mask(RzAnalysis *analysis, int size, const ut8 *data, ut64 } rz_analysis_op_fini(op); rz_analysis_op_init(op); + fprintf(stderr, "about to call analysisop\n"); if ((oplen = analysis_op(analysis, op, at + idx, data + idx, size - idx, RZ_ANALYSIS_OP_MASK_BASIC)) < 1) { break; } diff --git a/librz/include/rz_analysis.h b/librz/include/rz_analysis.h index 006dc555e99..a37c41bb78f 100644 --- a/librz/include/rz_analysis.h +++ b/librz/include/rz_analysis.h @@ -330,7 +330,7 @@ typedef enum { RZ_ANALYSIS_OP_TYPE_CPL = 45, /* complement */ RZ_ANALYSIS_OP_TYPE_CRYPTO = 46, RZ_ANALYSIS_OP_TYPE_SYNC = 47, -// RZ_ANALYSIS_OP_TYPE_DEBUG = 43, // monitor/trace/breakpoint + RZ_ANALYSIS_OP_TYPE_CTX_SWITCH = 48 #if 0 RZ_ANALYSIS_OP_TYPE_PRIV = 40, /* privileged instruction */ RZ_ANALYSIS_OP_TYPE_FPU = 41, /* floating point stuff */ @@ -533,6 +533,7 @@ typedef struct rz_analysis_t { RzAnalysisDebugInfo *debug_info; ///< store all debug info parsed from DWARF, etc.. ut64 cmpval; ///< last compare value for jump table. ut64 lea_jmptbl_ip; ///< jump table x86 lea ip + bool should_disas_as_thumb; ///< ARM: is processor mode THUMB? } RzAnalysis; typedef enum rz_analysis_addr_hint_type_t { @@ -899,6 +900,7 @@ typedef struct rz_analysis_op_t { bool sign; /* operates on signed values, false by default */ /* Run N instructions before executing the current one */ int delay; /* delay N slots (mips, ..)*/ + bool should_be_thumb; /* if ARM processor mode is THUMB */ ut64 jump; /* true jmp */ ut64 fail; /* false jmp */ RzAnalysisOpDirection direction; diff --git a/librz/main/rz-asm.c b/librz/main/rz-asm.c index bd2a1de98d1..d0448bb1337 100644 --- a/librz/main/rz-asm.c +++ b/librz/main/rz-asm.c @@ -140,6 +140,7 @@ static int show_analinfo(RzAsmState *as, const char *arg, ut64 offset) { for (ret = 0; ret < len;) { aop.size = 0; rz_analysis_op_init(&aop); + fprintf(stderr, "about to call rz_analysis_op\n"); if (rz_analysis_op(as->analysis, &aop, offset, buf + ret, len - ret, RZ_ANALYSIS_OP_MASK_BASIC | RZ_ANALYSIS_OP_MASK_ESIL) < 1) { eprintf("Error analyzing instruction at 0x%08" PFMT64x "\n", offset); break; From 57e0291693f868c02de046abc38b6c48ad7c036d Mon Sep 17 00:00:00 2001 From: TheN00bBuilder Date: Wed, 26 Jun 2024 21:15:21 -0500 Subject: [PATCH 2/3] First working commit - doing cleanup and DEFINEs to remove magic numbers next --- librz/arch/fcn.c | 2 ++ librz/arch/op.c | 2 ++ librz/arch/p/analysis/analysis_arm_cs.c | 32 ++++++++----------------- 3 files changed, 14 insertions(+), 22 deletions(-) diff --git a/librz/arch/fcn.c b/librz/arch/fcn.c index 21e211d55b7..9d05d125049 100644 --- a/librz/arch/fcn.c +++ b/librz/arch/fcn.c @@ -1240,6 +1240,8 @@ static RzAnalysisBBEndCause run_basic_block_analysis(RzAnalysisTaskItem *item, R gotoBeach(RZ_ANALYSIS_RET_END); } break; + case RZ_ANALYSIS_OP_TYPE_CTX_SWITCH: + analysis->bits = 16; case RZ_ANALYSIS_OP_TYPE_CCALL: case RZ_ANALYSIS_OP_TYPE_CALL: /* call dst */ diff --git a/librz/arch/op.c b/librz/arch/op.c index b6d1ba9ba32..415541b126b 100644 --- a/librz/arch/op.c +++ b/librz/arch/op.c @@ -193,6 +193,7 @@ RZ_API bool rz_analysis_op_nonlinear(int t) { switch (t) { // call case RZ_ANALYSIS_OP_TYPE_CALL: + case RZ_ANALYSIS_OP_TYPE_CTX_SWITCH: case RZ_ANALYSIS_OP_TYPE_RCALL: case RZ_ANALYSIS_OP_TYPE_ICALL: case RZ_ANALYSIS_OP_TYPE_UCALL: @@ -401,6 +402,7 @@ RZ_API char *rz_analysis_op_to_string(RzAnalysis *analysis, RzAnalysisOp *op) { case RZ_ANALYSIS_OP_TYPE_IRCALL: snprintf(ret, sizeof(ret), "%s()", r0); break; + case RZ_ANALYSIS_OP_TYPE_CTX_SWITCH: case RZ_ANALYSIS_OP_TYPE_CALL: f = rz_analysis_get_fcn_in(analysis, op->jump, RZ_ANALYSIS_FCN_TYPE_NULL); if (f) { diff --git a/librz/arch/p/analysis/analysis_arm_cs.c b/librz/arch/p/analysis/analysis_arm_cs.c index 8cfca09fc57..b680f49dacc 100644 --- a/librz/arch/p/analysis/analysis_arm_cs.c +++ b/librz/arch/p/analysis/analysis_arm_cs.c @@ -1264,7 +1264,6 @@ inline static void set_ret(const cs_insn *insn, RZ_BORROW RzAnalysisOp *op) { } static void anop32(RzAnalysis *a, csh handle, RzAnalysisOp *op, cs_insn *insn, bool thumb, const ut8 *buf, int len) { - //fprintf(stderr, "anop32 entered\n"); AnalysisArmCSContext *ctx = (AnalysisArmCSContext *)a->plugin_data; const ut64 addr = op->addr; const int pcdelta = thumb ? 4 : 8; @@ -1709,16 +1708,14 @@ jmp $$ + 4 + ( [delta] * 2 ) op->reg = cs_reg_name(handle, REGID(0)); } else { /* blx label */ - // check immediate jump address: - // if immediate operand bit 0 is 1, then its jumping to THUMB mode - if (IMM(0) && 1 && insn->bytes[12]){ + // Extract opcode from bytes + int byte_to_compare = (a->big_endian & CS_MODE_BIG_ENDIAN) ? 3 : 0; + // If 5th bit of opcode is 1, then encoding is A2. + // Only then can the mode switch! + // Compare to immediate bit 1 - if set, is a THUMB CTX switch + if (IMM(0) && 1 && (insn->bytes[byte_to_compare] && 8)) { op->type = RZ_ANALYSIS_OP_TYPE_CTX_SWITCH; - } - // Check for T2 encoding - if bit 12 is 0, must check IMM(1) instead - else if (!insn->bytes[12]) { - (IMM(1) && 1) ? op->type = RZ_ANALYSIS_OP_TYPE_CTX_SWITCH : RZ_ANALYSIS_OP_TYPE_CALL; - } - else { + } else { op->type = RZ_ANALYSIS_OP_TYPE_CALL; } op->jump = IMM(0) & UT32_MAX; @@ -1731,14 +1728,7 @@ jmp $$ + 4 + ( [delta] * 2 ) case ARM_INS_BL: /* bl label */ op->cycles = 4; - // check address: if immediate operand bit 0 is 1, then its jumping to THUMB mode - // no difference in T1/T2 encoding here - if (IMM(0) && 1) { - op->type = RZ_ANALYSIS_OP_TYPE_CTX_SWITCH; - } - else { - op->type = RZ_ANALYSIS_OP_TYPE_CALL; - } + op->type = RZ_ANALYSIS_OP_TYPE_CALL; op->jump = IMM(0) & UT32_MAX; op->fail = addr + op->size; op->hint.new_bits = a->bits; @@ -1779,7 +1769,7 @@ jmp $$ + 4 + ( [delta] * 2 ) case ARM_INS_BXJ: /* bx reg */ if (op->val) - op->cycles = 4; + op->cycles = 4; op->reg = cs_reg_name(handle, REGID(0)); switch (REGID(0)) { case ARM_REG_LR: @@ -1925,6 +1915,7 @@ static void set_opdir(RzAnalysisOp *op) { case RZ_ANALYSIS_OP_TYPE_JMP: case RZ_ANALYSIS_OP_TYPE_UJMP: case RZ_ANALYSIS_OP_TYPE_UCALL: + case RZ_ANALYSIS_OP_TYPE_CTX_SWITCH: op->direction = RZ_ANALYSIS_OP_DIR_EXEC; break; default: @@ -2081,7 +2072,6 @@ static void patch_capstone_bugs(cs_insn *insn, int bits, bool big_endian) { static int analysis_op(RzAnalysis *a, RzAnalysisOp *op, ut64 addr, const ut8 *buf, int len, RzAnalysisOpMask mask) { AnalysisArmCSContext *ctx = (AnalysisArmCSContext *)a->plugin_data; cs_insn *insn = NULL; - //op->should_be_thumb = 1; int mode = (a->bits == 16) ? CS_MODE_THUMB : CS_MODE_ARM; int n, ret; mode |= (a->big_endian) ? CS_MODE_BIG_ENDIAN : CS_MODE_LITTLE_ENDIAN; @@ -2155,11 +2145,9 @@ static int analysis_op(RzAnalysis *a, RzAnalysisOp *op, ut64 addr, const ut8 *bu } else { anop32(a, ctx->handle, op, insn, thumb, (ut8 *)buf, len); if (mask & RZ_ANALYSIS_OP_MASK_OPEX) { - fprintf(stderr, "doing opex\n"); opex(&op->opex, ctx->handle, insn); } if (mask & RZ_ANALYSIS_OP_MASK_ESIL) { - fprintf(stderr, "doing esil\n"); rz_arm_cs_analysis_op_32_esil(a, op, addr, buf, len, &ctx->handle, insn, thumb); } if (mask & RZ_ANALYSIS_OP_MASK_IL) { From 18fb5411c857de17d1c44298b84d5defe62d0b62 Mon Sep 17 00:00:00 2001 From: TheN00bBuilder Date: Wed, 26 Jun 2024 21:45:46 -0500 Subject: [PATCH 3/3] Remove pesky debug prints, add explicit fallthrough comment --- librz/arch/fcn.c | 1 + librz/arch/p/analysis/analysis_arm_cs.c | 1 - librz/include/rz_analysis.h | 2 -- librz/main/rz-asm.c | 1 - 4 files changed, 1 insertion(+), 4 deletions(-) diff --git a/librz/arch/fcn.c b/librz/arch/fcn.c index 9d05d125049..eeadc048a46 100644 --- a/librz/arch/fcn.c +++ b/librz/arch/fcn.c @@ -1242,6 +1242,7 @@ static RzAnalysisBBEndCause run_basic_block_analysis(RzAnalysisTaskItem *item, R break; case RZ_ANALYSIS_OP_TYPE_CTX_SWITCH: analysis->bits = 16; + /* fallthrough */ case RZ_ANALYSIS_OP_TYPE_CCALL: case RZ_ANALYSIS_OP_TYPE_CALL: /* call dst */ diff --git a/librz/arch/p/analysis/analysis_arm_cs.c b/librz/arch/p/analysis/analysis_arm_cs.c index b680f49dacc..3cd53a5c2d2 100644 --- a/librz/arch/p/analysis/analysis_arm_cs.c +++ b/librz/arch/p/analysis/analysis_arm_cs.c @@ -2595,7 +2595,6 @@ static ut8 *analysis_mask(RzAnalysis *analysis, int size, const ut8 *data, ut64 } rz_analysis_op_fini(op); rz_analysis_op_init(op); - fprintf(stderr, "about to call analysisop\n"); if ((oplen = analysis_op(analysis, op, at + idx, data + idx, size - idx, RZ_ANALYSIS_OP_MASK_BASIC)) < 1) { break; } diff --git a/librz/include/rz_analysis.h b/librz/include/rz_analysis.h index a37c41bb78f..1140539bc33 100644 --- a/librz/include/rz_analysis.h +++ b/librz/include/rz_analysis.h @@ -533,7 +533,6 @@ typedef struct rz_analysis_t { RzAnalysisDebugInfo *debug_info; ///< store all debug info parsed from DWARF, etc.. ut64 cmpval; ///< last compare value for jump table. ut64 lea_jmptbl_ip; ///< jump table x86 lea ip - bool should_disas_as_thumb; ///< ARM: is processor mode THUMB? } RzAnalysis; typedef enum rz_analysis_addr_hint_type_t { @@ -900,7 +899,6 @@ typedef struct rz_analysis_op_t { bool sign; /* operates on signed values, false by default */ /* Run N instructions before executing the current one */ int delay; /* delay N slots (mips, ..)*/ - bool should_be_thumb; /* if ARM processor mode is THUMB */ ut64 jump; /* true jmp */ ut64 fail; /* false jmp */ RzAnalysisOpDirection direction; diff --git a/librz/main/rz-asm.c b/librz/main/rz-asm.c index d0448bb1337..bd2a1de98d1 100644 --- a/librz/main/rz-asm.c +++ b/librz/main/rz-asm.c @@ -140,7 +140,6 @@ static int show_analinfo(RzAsmState *as, const char *arg, ut64 offset) { for (ret = 0; ret < len;) { aop.size = 0; rz_analysis_op_init(&aop); - fprintf(stderr, "about to call rz_analysis_op\n"); if (rz_analysis_op(as->analysis, &aop, offset, buf + ret, len - ret, RZ_ANALYSIS_OP_MASK_BASIC | RZ_ANALYSIS_OP_MASK_ESIL) < 1) { eprintf("Error analyzing instruction at 0x%08" PFMT64x "\n", offset); break;