Merge pull request #1086 from ucgJhe/qdb

Qdb improvements
This commit is contained in:
kj.xwings.l
2022-02-08 08:50:38 +08:00
committed by GitHub
3 changed files with 120 additions and 31 deletions
+77 -28
View File
@@ -13,7 +13,7 @@ from qiling.const import QL_ARCH
import unicorn
from .utils import dump_regs, get_arm_flags, disasm, _parse_int, handle_bnj
from .utils import dump_regs, get_x86_eflags, get_arm_flags, disasm, _parse_int, handle_bnj
from .const import *
@@ -192,8 +192,34 @@ def context_reg(ql: Qiling, saved_states: Optional[Mapping[str, int]] = None, /,
print(lines.format(*_cur_regs.values()))
elif ql.archtype in (QL_ARCH.ARM, QL_ARCH.ARM_THUMB, QL_ARCH.CORTEX_M):
elif ql.archtype == QL_ARCH.X86:
if saved_states is not None:
_saved_states = copy.deepcopy(saved_states)
_diff = [k for k in _cur_regs if _cur_regs[k] != _saved_states[k]]
else:
_diff = None
lines = ""
for idx, r in enumerate(_cur_regs, 1):
if len(r) == 2:
line = "{}{}: 0x{{:08x}} {}\t\t".format(_colors[(idx-1) // 4], r, color.END)
else:
line = "{}{}: 0x{{:08x}} {}\t".format(_colors[(idx-1) // 4], r, color.END)
if _diff and r in _diff:
line = f"{color.UNDERLINE}{color.BOLD}{line}"
if idx % 4 == 0 and idx != 32:
line += "\n"
lines += line
print(lines.format(*_cur_regs.values()))
print(color.GREEN, "EFLAGS: [CF: {flags[CF]}, PF: {flags[PF]}, AF: {flags[AF]}, ZF: {flags[ZF]}, SF: {flags[SF]}, OF: {flags[OF]}]".format(flags=get_x86_eflags(ql.reg.ef)), color.END, sep="")
elif ql.archtype in (QL_ARCH.ARM, QL_ARCH.ARM_THUMB, QL_ARCH.CORTEX_M):
_cur_regs.update({"sl": _cur_regs.pop("r10")})
_cur_regs.update({"ip": _cur_regs.pop("r12")})
@@ -265,7 +291,10 @@ def context_reg(ql: Qiling, saved_states: Optional[Mapping[str, int]] = None, /,
def print_asm(ql: Qiling, insn: CsInsn, to_jump: Optional[bool] = None, address: int = None) -> None:
opcode = "".join(f"{b:02x}" for b in insn.bytes)
trace_line = f"0x{insn.address:08x} │ {opcode:10s} {insn.mnemonic:10} {insn.op_str:35s}"
if ql.archtype in (QL_ARCH.X86, QL_ARCH.X8664):
trace_line = f"0x{insn.address:08x} │ {opcode:20s} {insn.mnemonic:10} {insn.op_str:35s}"
else:
trace_line = f"0x{insn.address:08x} │ {opcode:10s} {insn.mnemonic:10} {insn.op_str:35s}"
cursor = " "
if ql.reg.arch_pc == insn.address:
@@ -282,39 +311,59 @@ def context_asm(ql: Qiling, address: int) -> None:
with context_printer(ql, field_name="[ DISASM ]"):
# assembly before current location
if ql.archtype in (QL_ARCH.X86, QL_ARCH.X8664):
past_list = []
past_list = []
# assembly before current location
line = disasm(ql, address-0x10)
line = disasm(ql, address)
acc_size = line.size
while line:
if line.address == address:
break
while line and len(past_list) != 10:
past_list.append(line)
next_start = address + acc_size
line = disasm(ql, next_start)
acc_size += line.size
addr = line.address + line.size
line = disasm(ql, addr)
# print four insns before current location
for line in past_list[:-1]:
print_asm(ql, line)
if not line:
break
else:
past_list.append(line)
# assembly before current location
# print four insns before current location
for line in past_list[:-1][:4]:
print_asm(ql, line)
past_list = []
# assembly for current location
line = disasm(ql, address-0x10)
cur_ins = disasm(ql, address)
to_jump, next_stop = handle_bnj(ql, address)
print_asm(ql, cur_ins, to_jump=to_jump)
while line:
if line.address == address:
break
# assembly after current location
addr = line.address + line.size
line = disasm(ql, addr)
forward_insn_size = cur_ins.size
for _ in range(5):
forward_insn = disasm(ql, address+forward_insn_size)
if forward_insn:
print_asm(ql, forward_insn)
forward_insn_size += forward_insn.size
if not line:
break
past_list.append(line)
# print four insns before current location
for line in past_list[:-1][:4]:
print_asm(ql, line)
# assembly for current location
cur_ins = disasm(ql, address)
to_jump, next_stop = handle_bnj(ql, address)
print_asm(ql, cur_ins, to_jump=to_jump)
# assembly after current location
forward_insn_size = cur_ins.size
for _ in range(5):
forward_insn = disasm(ql, address+forward_insn_size)
if forward_insn:
print_asm(ql, forward_insn)
forward_insn_size += forward_insn.size
+6 -2
View File
@@ -232,7 +232,11 @@ class QlQdb(cmd.Cmd, QlDebugger):
self.ql.count -= 1
else:
count = 1 if next_stop == self.cur_addr + 4 else 2
if self.ql.archtype in (QL_ARCH.X86, QL_ARCH.X8664):
count = 1
else:
count = 1 if next_stop == self.cur_addr + 4 else 2
self._run(count=count)
self.do_context()
@@ -323,7 +327,7 @@ class QlQdb(cmd.Cmd, QlDebugger):
"""
try:
context_asm(self.ql, _parse_int(address), self.ql.pointersize)
context_asm(self.ql, address)
except:
print(f"{color.RED}[!] something went wrong ...{color.END}")
+37 -1
View File
@@ -36,6 +36,15 @@ def dump_regs(ql: Qiling) -> Mapping[str, int]:
"r12", "sp", "lr", "pc",
)
elif ql.archtype == QL_ARCH.X86:
_reg_order = (
"eax", "ebx", "ecx", "edx",
"esp", "ebp", "esi", "edi",
"eip", "ss", "cs", "ds", "es",
"fs", "gs", "ef",
)
elif ql.archtype == QL_ARCH.CORTEX_M:
_reg_order = (
@@ -83,7 +92,7 @@ def _parse_int(s: str) -> int:
# function dectorator for parse argument as integer
def parse_int(func: Callable) -> Callable:
def wrap(qdb, s: str) -> int:
def wrap(qdb, s: str = "") -> int:
assert type(s) is str
try:
ret = _parse_int(s)
@@ -109,6 +118,7 @@ def handle_bnj(ql: Qiling, cur_addr: str) -> Callable[[Qiling, str], int]:
QL_ARCH.ARM : handle_bnj_arm,
QL_ARCH.ARM_THUMB: handle_bnj_arm,
QL_ARCH.CORTEX_M : handle_bnj_arm,
QL_ARCH.X86 : handle_bnj_x86,
}.get(ql.archtype)(ql, cur_addr)
@@ -121,6 +131,17 @@ def get_cpsr(bits: int) -> (bool, bool, bool, bool):
)
def get_x86_eflags(bits: int) -> Dict[str, bool]:
return {
"CF" : bits & 0x0001 != 0, # CF, carry flag
"PF" : bits & 0x0004 != 0, # PF, parity flag
"AF" : bits & 0x0010 != 0, # AF, adjust flag
"ZF" : bits & 0x0040 != 0, # ZF, zero flag
"SF" : bits & 0x0080 != 0, # SF, sign flag
"OF" : bits & 0x0800 != 0, # OF, overflow flag
}
def is_thumb(bits: int) -> bool:
return bits & 0x00000020 != 0
@@ -158,8 +179,23 @@ def _read_inst(ql: Qiling, addr: int) -> int:
latter_two = ql.unpack16(ql.mem.read(addr+2, 2))
result += ql.pack16(latter_two)
elif ql.archtype in (QL_ARCH.X86, QL_ARCH.X8664):
# due to the variadic lengh of x86 instructions ( 1~15 )
# always assume the maxium size for disassembler to tell
# what is it exactly.
result = ql.mem.read(addr, 15)
return result
def handle_bnj_x86(ql: Qilng, cur_addr: str) -> int:
# FIXME: NO HANDLE BRANCH AND JUMP FOR X86 FOR NOW
to_jump = False
ret_addr = None
return (to_jump, ret_addr)
def handle_bnj_arm(ql: Qiling, cur_addr: str) -> int: