Skip to content

Commit

Permalink
Add support for extended registers (r8-r15)
Browse files Browse the repository at this point in the history
  * Add tests for x86-63 and x86-16
  • Loading branch information
DMaroo committed Nov 25, 2022
1 parent 139e6e2 commit 00867c5
Show file tree
Hide file tree
Showing 3 changed files with 1,065 additions and 998 deletions.
113 changes: 90 additions & 23 deletions librz/analysis/arch/x86/x86_il.c
Original file line number Diff line number Diff line change
Expand Up @@ -374,6 +374,14 @@ static const char *x86_bound_regs_64[] = {
"rbp", /* X86_REG_RBP */
"rsi", /* X86_REG_RSI */
"rdi", /* X86_REG_RDI */
"r8", /* X86_REG_R8 */
"r9", /* X86_REG_R9 */
"r10", /* X86_REG_R10 */
"r11", /* X86_REG_R11 */
"r12", /* X86_REG_R12 */
"r13", /* X86_REG_R13 */
"r14", /* X86_REG_R14 */
"r15", /* X86_REG_R15 */
"nt", /* X86_EFLAGS_NT */
"rf", /* X86_EFLAGS_RF */
"vm", /* X86_EFLAGS_VM */
Expand Down Expand Up @@ -493,6 +501,7 @@ static RzILOpPure *x86_il_get_gpr32(X86Reg reg, int bits) {
if (bits == 32) {
return VARG(x86_registers[reg]);
}
// RZ_LOG_WARN("hhah\n")
return UNSIGNED(32, VARG(x86_registers[reg]));
}
static RzILOpPure *x86_il_get_gpr64(X86Reg reg, int bits) {
Expand Down Expand Up @@ -582,9 +591,6 @@ static const struct gpr_lookup_helper_t gpr_lookup_table[] = {
[X86_REG_DI] = { 5, x86_il_get_gpr16, x86_il_set_gpr16 },
[X86_REG_EDI] = { 5, x86_il_get_gpr32, x86_il_set_gpr32 },
[X86_REG_RDI] = { 5, x86_il_get_gpr64, x86_il_set_gpr64 },
[X86_REG_IP] = { 6, x86_il_get_gpr16, x86_il_set_gpr16 },
[X86_REG_EIP] = { 6, x86_il_get_gpr32, x86_il_set_gpr32 },
[X86_REG_RIP] = { 6, x86_il_get_gpr64, x86_il_set_gpr64 },
[X86_REG_EIZ] = { 7, x86_il_get_gpr32, x86_il_set_gpr32 },
[X86_REG_RIZ] = { 7, x86_il_get_gpr64, x86_il_set_gpr64 },
[X86_REG_SIL] = { 8, x86_il_get_gprl, x86_il_set_gprl },
Expand All @@ -597,26 +603,87 @@ static const struct gpr_lookup_helper_t gpr_lookup_table[] = {
[X86_REG_RSP] = { 9, x86_il_get_gpr64, x86_il_set_gpr64 }
};

static RzILOpPure *x86_il_get_reg_bits(X86Reg reg, int bits) {
if (!x86_il_is_gpr(reg)) {
return VARG(x86_registers[reg]);
bool is_pc_reg(X86Reg reg) {
return (reg == X86_REG_IP || reg == X86_REG_EIP || reg == X86_REG_RIP);
}

struct extreg_lookup_helper_t {
X86Reg curr_reg;
X86Reg base_reg;
RzILOpPure *(*get_handler)(X86Reg, int);
RzILOpEffect *(*set_handler)(X86Reg, RzILOpPure *, int);
};

#define extreg_lookup(suff, getter, setter) \
{ X86_REG_R8##suff, X86_REG_R8, getter, setter }, \
{ X86_REG_R9##suff, X86_REG_R9, getter, setter }, \
{ X86_REG_R10##suff, X86_REG_R10, getter, setter }, \
{ X86_REG_R11##suff, X86_REG_R11, getter, setter }, \
{ X86_REG_R12##suff, X86_REG_R12, getter, setter }, \
{ X86_REG_R13##suff, X86_REG_R13, getter, setter }, \
{ X86_REG_R14##suff, X86_REG_R14, getter, setter }, \
{ X86_REG_R15##suff, X86_REG_R15, getter, setter },

static const struct extreg_lookup_helper_t extreg_lookup_table[] = {
// 64-bit wide
extreg_lookup(, x86_il_get_gpr64, x86_il_set_gpr64)

// 8-bit wide (byte)
extreg_lookup(B, x86_il_get_gprl, x86_il_set_gprl)

// 16-bit wide (word)
extreg_lookup(W, x86_il_get_gpr16, x86_il_set_gpr16)

// 32-bit wide (dword)
extreg_lookup(D, x86_il_get_gpr32, x86_il_set_gpr32)
};

int get_extreg_ind(X86Reg reg) {
for (unsigned int i = 0; i < 8 * 4 /* size of extreg_lookup_table */; i++) {
if (extreg_lookup_table[i].curr_reg == reg) {
return i;
}
}
struct gpr_lookup_helper_t entry = gpr_lookup_table[reg];
/* Need to use `get_bitness_reg` because not all registers
are available in the IL in any particular bitness
(For example, "rax" is not a valid IL variable in 32-bit mode)
So, we need to use the max width register available */
return entry.get_handler(get_bitness_reg(entry.index, bits), bits);

return -1;
}

#define x86_il_get_reg(reg) x86_il_get_reg_bits(reg, analysis->bits)
static RzILOpPure *x86_il_get_reg_bits(X86Reg reg, int bits, uint64_t pc) {
if (is_pc_reg(reg)) {
return UN(bits, pc);
}

int ind = -1;

if (x86_il_is_gpr(reg)) {
struct gpr_lookup_helper_t entry = gpr_lookup_table[reg];
/* Need to use `get_bitness_reg` because not all registers
are available in the IL in any particular bitness
(For example, "rax" is not a valid IL variable in 32-bit mode)
So, we need to use the max width register available */
return entry.get_handler(get_bitness_reg(entry.index, bits), bits);
} else if ((ind = get_extreg_ind(reg)) != -1 && bits == 64) {
struct extreg_lookup_helper_t entry = extreg_lookup_table[ind];
return entry.get_handler(entry.base_reg, bits);
}

return VARG(x86_registers[reg]);
}

#define x86_il_get_reg(reg) x86_il_get_reg_bits(reg, analysis->bits, pc)

static RzILOpEffect *x86_il_set_reg_bits(X86Reg reg, RzILOpPure *val, int bits) {
if (!x86_il_is_gpr(reg)) {
return SETG(x86_registers[reg], val);
int ind = -1;

if (x86_il_is_gpr(reg)) {
struct gpr_lookup_helper_t entry = gpr_lookup_table[reg];
return entry.set_handler(get_bitness_reg(entry.index, bits), val, bits);
} else if ((ind = get_extreg_ind(reg)) != -1 && bits == 64) {
struct extreg_lookup_helper_t entry = extreg_lookup_table[ind];
return entry.set_handler(entry.base_reg, val, bits);
}
struct gpr_lookup_helper_t entry = gpr_lookup_table[reg];
return entry.set_handler(get_bitness_reg(entry.index, bits), val, bits);

return SETG(x86_registers[reg], val);
}

#define x86_il_set_reg(reg, val) x86_il_set_reg_bits(reg, val, analysis->bits)
Expand All @@ -625,14 +692,14 @@ static RzILOpPure *x86_il_get_memaddr_segment_bits(X86Mem mem, X86Reg segment, i
RzILOpPure *offset = NULL;
if (mem.base != X86_REG_INVALID) {
if (!offset) {
offset = x86_il_get_reg_bits(mem.base, bits);
offset = x86_il_get_reg_bits(mem.base, bits, 0);
if (x86_il_get_reg_size(mem.base) != bits) {
offset = UNSIGNED(bits, offset);
}
}
}
if (mem.index != X86_REG_INVALID) {
RzILOpPure *reg = x86_il_get_reg_bits(mem.index, bits);
RzILOpPure *reg = x86_il_get_reg_bits(mem.index, bits, 0);
if (x86_il_get_reg_size(mem.index) != bits) {
reg = UNSIGNED(bits, reg);
}
Expand All @@ -655,7 +722,7 @@ static RzILOpPure *x86_il_get_memaddr_segment_bits(X86Mem mem, X86Reg segment, i
Address = Segment * 0x10 + Offset */

/* Assuming real mode */
offset = ADD(offset, SHIFTL0(UNSIGNED(32, x86_il_get_reg_bits(segment, bits)), U8(4)));
offset = ADD(offset, SHIFTL0(UNSIGNED(bits, x86_il_get_reg_bits(segment, bits, 0)), U8(4)));
}

return offset;
Expand All @@ -682,7 +749,7 @@ static RzILOpPure *x86_il_get_operand_bits(X86Op op, int analysis_bits) {
RZ_LOG_ERROR("x86: RzIL: Invalid param type encountered\n");
break;
case X86_OP_REG:
ret = x86_il_get_reg_bits(op.reg, analysis_bits);
ret = x86_il_get_reg_bits(op.reg, analysis_bits, 0);
break;
case X86_OP_IMM:
ret = SN(op.size * BITS_PER_BYTE, op.imm);
Expand Down Expand Up @@ -2379,7 +2446,7 @@ PopHelper x86_pop_helper_bits(unsigned int op_size, unsigned int bitness) {
PopHelper ret;

ret.val = LOADW(op_size * BITS_PER_BYTE, x86_il_get_memaddr_bits(stack_mem, bitness));
ret.eff = x86_il_set_reg_bits(X86_REG_RSP, ADD(x86_il_get_reg_bits(X86_REG_RSP, bitness), UN(bitness, op_size)), bitness);
ret.eff = x86_il_set_reg_bits(X86_REG_RSP, ADD(x86_il_get_reg_bits(X86_REG_RSP, bitness, 0), UN(bitness, op_size)), bitness);

return ret;
}
Expand Down Expand Up @@ -2474,7 +2541,7 @@ RzILOpEffect *x86_push_helper_impl(RzILOpPure *val, unsigned int user_op_size, u
}

RzILOpEffect *ret = STOREW(x86_il_get_memaddr_bits(stack_mem, bitness), UNSIGNED(op_size * BITS_PER_BYTE, val));
ret = SEQ2(x86_il_set_reg_bits(X86_REG_RSP, SUB(x86_il_get_reg_bits(X86_REG_RSP, bitness), UN(bitness, stack_size)), bitness), ret);
ret = SEQ2(x86_il_set_reg_bits(X86_REG_RSP, SUB(x86_il_get_reg_bits(X86_REG_RSP, bitness, 0), UN(bitness, stack_size)), bitness), ret);

return ret;
}
Expand Down
26 changes: 13 additions & 13 deletions test/db/asm/x86_16
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,19 @@ ad "aam" d40a 0x0 (seq (set temp_al (cast 8 false (var ax))) (set ax (| (& (var
ad "aam 0x42" d442 0x0 (seq (set temp_al (cast 8 false (var ax))) (set ax (| (& (var ax) (~ (bv 16 0xff00))) (<< (cast 16 false (div (var temp_al) (bv 8 0x42))) (bv 8 0x8) false))) (set adjusted (mod (var temp_al) (bv 8 0x42))) (set ax (| (& (var ax) (~ (bv 16 0xff))) (cast 16 false (var adjusted)))) (set _result (var adjusted)) (set _popcnt (bv 8 0x0)) (set _val (cast 8 false (var _result))) (repeat (is_zero (var _val)) (seq (set _popcnt (+ (var _popcnt) (ite (lsb (var _val)) (bv 8 0x1) (bv 8 0x0)))) (set _val (>> (var _val) (bv 8 0x1) false)))) (set pf (is_zero (mod (var _popcnt) (bv 8 0x2)))) (set zf (is_zero (var _result))) (set sf (msb (var _result))))
ad "aas" 3f 0x0 (seq (branch (|| (! (ule (& (cast 8 false (var ax)) (bv 8 0xf)) (bv 8 0x9))) (var af)) (seq (set ax (- (var ax) (bv 16 0x6))) (set ax (| (& (var ax) (~ (bv 16 0xff00))) (<< (cast 16 false (- (cast 8 false (>> (var ax) (bv 8 0x8) false)) (bv 8 0x1))) (bv 8 0x8) false))) (set af true) (set cf true)) (seq (set af false) (set cf false))) (set ax (| (& (var ax) (~ (bv 16 0xff))) (cast 16 false (& (cast 8 false (var ax)) (bv 8 0xf))))))
adB "cbw" 98
d "call 0" e8fdff
a "jmp 0x0" ebfe
a "jmp 0x10" eb0e
a "jmp 0x34" eb32
a "jne 0x14" 7512
a "jnz 0x94" 660f858d000000
a "jnz -0x94" 660f8565ffffff
a "jno -0x34" 71ca
d "call 0" e8fdff 0x0 (seq (set _cs (cast 16 false (var cs))) (set sp (- (var sp) (bv 16 0x2))) (storew 0 (+ (+ (cast 16 false (var sp)) (bv 16 0x0)) (<< (cast 16 false (var ss)) (bv 8 0x4) false)) (cast 16 false (var _cs))) (set _pc (bv 16 0x0)) (set sp (- (var sp) (bv 16 0x2))) (storew 0 (+ (+ (cast 16 false (var sp)) (bv 16 0x0)) (<< (cast 16 false (var ss)) (bv 8 0x4) false)) (cast 16 false (var _pc))))
a "jmp 0x0" ebfe 0x0 (jmp (+ (bv 16 0x0) (bv 16 0x0)))
a "jmp 0x10" eb0e 0x0 (jmp (+ (bv 16 0x0) (bv 16 0x10)))
a "jmp 0x34" eb32 0x0 (jmp (+ (bv 16 0x0) (bv 16 0x34)))
a "jne 0x14" 7512 0x0 (branch (! (var zf)) (jmp (+ (bv 16 0x0) (bv 16 0x14))) nop)
a "jnz 0x94" 660f858d000000 0x0 (branch (! (var zf)) (jmp (+ (bv 16 0x0) (bv 16 0x94))) nop)
a "jnz -0x94" 660f8565ffffff 0x0 (branch (! (var zf)) (jmp (+ (bv 16 0x0) (bv 16 0xff6c))) nop)
a "jno -0x34" 71ca 0x0 (branch (! (var of)) (jmp (+ (bv 16 0x0) (bv 16 0xffcc))) nop)
dB "jmp 0xfec50" e95bec
d "jmp 0x1fec50" e95bec 0x001ffff2
a "mov al, [0xbeef]" a0efbe
a "mov ax, [0xbeef]" a1efbe
a "test bl, 0x12" f6c312
a "test bx, 0x1234" f7c33412
d "jmp 0x1fec50" e95bec 0x1ffff2 (jmp (+ (bv 16 0xfff2) (bv 16 0xec50)))
a "mov al, [0xbeef]" a0efbe 0x0 (set ax (| (& (var ax) (~ (bv 16 0xff))) (cast 16 false (loadw 0 8 (bv 16 0xbeef)))))
a "mov ax, [0xbeef]" a1efbe 0x0 (set ax (loadw 0 16 (bv 16 0xbeef)))
a "test bl, 0x12" f6c312 0x0 (seq (set _res (& (cast 8 false (var bx)) (bv 8 0x12))) (set bx (| (& (var bx) (~ (bv 16 0xff))) (cast 16 false (var _res)))) (set _result (var _res)) (set _popcnt (bv 8 0x0)) (set _val (cast 8 false (var _result))) (repeat (is_zero (var _val)) (seq (set _popcnt (+ (var _popcnt) (ite (lsb (var _val)) (bv 8 0x1) (bv 8 0x0)))) (set _val (>> (var _val) (bv 8 0x1) false)))) (set pf (is_zero (mod (var _popcnt) (bv 8 0x2)))) (set zf (is_zero (var _result))) (set sf (msb (var _result))) (set cf false) (set of false))
a "test bx, 0x1234" f7c33412 0x0 (seq (set _res (& (var bx) (bv 16 0x1234))) (set bx (var _res)) (set _result (var _res)) (set _popcnt (bv 8 0x0)) (set _val (cast 8 false (var _result))) (repeat (is_zero (var _val)) (seq (set _popcnt (+ (var _popcnt) (ite (lsb (var _val)) (bv 8 0x1) (bv 8 0x0)))) (set _val (>> (var _val) (bv 8 0x1) false)))) (set pf (is_zero (mod (var _popcnt) (bv 8 0x2)))) (set zf (is_zero (var _result))) (set sf (msb (var _result))) (set cf false) (set of false))
aB "test byte [bx], 0x12" f60712
aB "test word [bx], 0x1234" f7073412
Loading

0 comments on commit 00867c5

Please sign in to comment.