Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for 16bit mips and little endian #18

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions serial_debuger/mips16e_asm.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#coding:utf8
import os
import binascii

def ASM16(code,endian = 1):
template = '''
.section .shellcode,"awx"
.global _start
.global __start
_start:
__start:
.set mips2
.set noreorder
%s
''' % code
f = open('1.binary.s','wb')
f.write(template)
f.close()
e = '-EL' if endian == 2 else '-EB'
os.system("mips-linux-gnu-as %s -mips16 -o 1.binary.tmp 1.binary.s" % e)
os.system('rm 1.binary.s')
os.system('mips-linux-gnu-objcopy -j .shellcode -Obinary 1.binary.tmp')
f = open('1.binary.tmp','rb')
content = f.read()
f.close()
os.system('rm 1.binary.tmp')
return content
62 changes: 39 additions & 23 deletions serial_debuger/vx5_mips_debugger.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
from vx_base_debugger import VxSerialBaseDebuger
from keystone import *
from capstone import *

from mips16e_asm import *

MIPS_REGS = [
'$0', 't0', 's0', 't8',
Expand Down Expand Up @@ -218,13 +218,17 @@ def text_update(self, update_address, update_size):
self.logger.debug("current bp_address is zero, skip text update.")
return None
flag_address = self.current_bp_info["flag_address"]
original_update_count = struct.unpack("!I", self.get_mem_dump(flag_address + 0x14, 0x04))[0]
self.write_memory_data(flag_address + 0x0c, struct.pack('!I', update_address))
self.write_memory_data(flag_address + 0x10, struct.pack('!I', update_size))
pack_parm = ">I"
if self.endian == 2:
pack_parm = "<I"

original_update_count = struct.unpack(pack_parm, self.get_mem_dump(flag_address + 0x14, 0x04))[0]
self.write_memory_data(flag_address + 0x0c, struct.pack(pack_parm, update_address))
self.write_memory_data(flag_address + 0x10, struct.pack(pack_parm, update_size))
# set update flag
self._set_dbg_flag(2)
# wait text update
current_update_count = struct.unpack("!I", self.get_mem_dump(flag_address + 0x14, 0x04))[0]
current_update_count = struct.unpack(pack_parm, self.get_mem_dump(flag_address + 0x14, 0x04))[0]
while current_update_count != original_update_count + 1:
self.logger.debug("current_update_count: %s , should be: %s" % (hex(current_update_count),
hex(original_update_count + 1)))
Expand All @@ -236,7 +240,7 @@ def text_update(self, update_address, update_size):

# set update flag
self._set_dbg_flag(2)
current_update_count = struct.unpack("!I", self.get_mem_dump(flag_address + 0x14, 0x04))[0]
current_update_count = struct.unpack(pack_parm, self.get_mem_dump(flag_address + 0x14, 0x04))[0]
time.sleep(1)
self.logger.debug('text_update succeed')
return True
Expand All @@ -263,7 +267,7 @@ def init_debugger(self, over_write_address):
reg_store_offset = 0x20
recover_original_ra_asm_code = "lw $ra, 0x04-%s($sp)" % self.dbg_stack_size
recover_original_ra_asm = self.assemble(recover_original_ra_asm_code, KS_ARCH_MIPS,
KS_MODE_MIPS32, KS_MODE_BIG_ENDIAN)[0]
KS_MODE_MIPS32,KS_MODE_BIG_ENDIAN if self.endian == 1 else KS_MODE_LITTLE_ENDIAN)[0]

##########################
# Init DBG Stack #
Expand Down Expand Up @@ -297,8 +301,10 @@ def init_debugger(self, over_write_address):
# update cacheTextUpdate execute count
asm_code += "lw $a0, 0x14($sp); addiu $a0, 0x01; sw $a0, 0x14($sp);"

j = 'jal' if self.cache_update_address & 0x1 == 0 else 'jalx' #take 16bit into considerate

# update cache
asm_code += "lw $a0, 0x0c($sp); lw $a1, 0x10($sp); jal %s;" % hex(self.cache_update_address & 0xfffffff)
asm_code += "lw $a0, 0x0c($sp); lw $a1, 0x10($sp); %s %s;" % (j,hex(self.cache_update_address & 0xffffffe))

# TODO: recover a0, a1
# set flag to 0x00
Expand All @@ -307,14 +313,14 @@ def init_debugger(self, over_write_address):
# if flag != 0x01 keep loop
asm_code += "lw $ra, 0x00($sp); addiu $ra, -0x01; bnez $ra, -%s;" % hex(0x08 + 0x04 + 0x10 + 0x0c + 0x10)


##########################
# Recover #
##########################

# update dbg stack cache before recover
asm_code += "move $a0, $sp; li $a1, %s; jal %s;" % (hex(self.dbg_stack_size),
hex(self.cache_update_address & 0xfffffff))

asm_code += "move $a0, $sp; li $a1, %s; %s %s;" % ((hex(self.dbg_stack_size),j,
hex(self.cache_update_address & 0xffffffe)))
# recover regs
stack_offset = reg_store_offset
for i in range(0x20):
Expand All @@ -327,8 +333,10 @@ def init_debugger(self, over_write_address):
# return to bp
asm_code += "lw $ra, 0x08($sp); addiu $ra, -%s; addiu $sp, %s; jr $ra;" % (hex(self.bp_overwrite_size),
hex(self.dbg_stack_size))
asm_code += "nop;" #Branch delay slot

self.logger.debug("asm_code: %s" % asm_code)
asm_list = self.assemble(asm_code, KS_ARCH_MIPS, KS_MODE_MIPS32, KS_MODE_BIG_ENDIAN)
asm_list = self.assemble(asm_code, KS_ARCH_MIPS, KS_MODE_MIPS32, KS_MODE_BIG_ENDIAN if self.endian == 1 else KS_MODE_LITTLE_ENDIAN)
if not asm_list:
return None
self.dbg_overwrite_size = len(asm_list * 0x04)
Expand Down Expand Up @@ -553,7 +561,7 @@ def show_task_bp_trace(self, task):
bp_address = self.current_bp_info["bp_address"]
ra_address = self.current_bp_info["original_ra"]
bp_asm_data = self.break_points[bp_address]["original_asm"][:4]
bp_asm = self.disassemble(bp_asm_data, bp_address, CS_ARCH_MIPS, CS_MODE_MIPS32, CS_MODE_BIG_ENDIAN)
bp_asm = self.disassemble(bp_asm_data, bp_address, CS_ARCH_MIPS, CS_MODE_MIPS32,CS_MODE_BIG_ENDIAN if self.endian == 1 else CS_MODE_LITTLE_ENDIAN)
trace_data_list.append(bp_asm)
# get ra asm
ra_asm_data = None
Expand All @@ -565,7 +573,7 @@ def show_task_bp_trace(self, task):
if not ra_asm_data:
ra_asm_data = self.get_mem_dump(ra_address, 0x04)
self.logger.debug("ra_asm_data: %s" % ra_asm_data.encode("hex"))
ra_asm = self.disassemble(ra_asm_data, ra_address, CS_ARCH_MIPS, CS_MODE_MIPS32, CS_MODE_BIG_ENDIAN)
ra_asm = self.disassemble(ra_asm_data, ra_address, CS_ARCH_MIPS, CS_MODE_MIPS32, CS_MODE_BIG_ENDIAN if self.endian == 1 else CS_MODE_LITTLE_ENDIAN)
self.logger.debug("ra_asm: %s" % ra_asm)
trace_data_list.append(ra_asm)
for i in range(len(trace_data_list)):
Expand All @@ -582,7 +590,7 @@ def get_temp_bp_address(self, bp_address):
try:
temp_bp_address_list = []
bp_asm_data = self.break_points[bp_address]["original_asm"]
md = Cs(CS_ARCH_MIPS, CS_MODE_MIPS32 | CS_MODE_BIG_ENDIAN)
md = Cs(CS_ARCH_MIPS, CS_MODE_MIPS32 | (CS_MODE_BIG_ENDIAN if self.endian == 1 else CS_MODE_LITTLE_ENDIAN))
md.detail = True
asm_code_data = {}
for i in md.disasm(bp_asm_data, bp_address):
Expand Down Expand Up @@ -627,7 +635,7 @@ def get_temp_bp_address(self, bp_address):
self.logger.error("ERROR: %s" % err)
return None

def create_bp_asm(self, bp_address):
def create_bp_asm(self, bp_address,is_16bit = 0):
"""Create breakpoint asm code

:param bp_address: break point address
Expand All @@ -637,11 +645,19 @@ def create_bp_asm(self, bp_address):
asm_code = "addiu $sp, -%s;" % hex(self.dbg_stack_size)
# save original $RA value
asm_code += "sw $ra, 0x04($sp);"
# jump to dbg loop
asm_code += "jal %s;" % (hex(self.debugger_base_address & 0xffffff))
if is_16bit == 0:
# jump to dbg loop
asm_code += "jal %s;" % (hex(self.debugger_base_address & 0xffffff))
asm_code += 'nop;' # Branch delay slot
asm_list = self.assemble(str(asm_code), KS_ARCH_MIPS, KS_MODE_16,KS_MODE_BIG_ENDIAN if self.endian == 1 else KS_MODE_LITTLE_ENDIAN)
if not asm_list:
return None
asm_data = "".join(asm_list).decode("hex")
else: #16 bit mode
asm_code += 'nop;nop;nop;' #padding
# jump to dbg loop
asm_code += "jalx %s;" % (hex(self.debugger_base_address & 0xffffff))
asm_code += 'nop;' # Branch delay slot
asm_data = ASM16(asm_code,self.endian)
self.logger.debug("asm_code: %s" % asm_code)
asm_list = self.assemble(str(asm_code), KS_ARCH_MIPS, KS_MODE_MIPS32, KS_MODE_BIG_ENDIAN)
if not asm_list:
return None
asm_data = "".join(asm_list).decode("hex")
return asm_data
return asm_data
34 changes: 22 additions & 12 deletions serial_debuger/vx_base_debugger.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ def __init__(self, serial=None, serial_until='\r\n#', process_regs=MIPS_REGS, pr
self.cache_update_address = cache_update_address
self.dbg_stack_size = 0x200
self.bp_overwrite_size = 0x10 # Breakpoint overwrite size
self.dbg_overwrite_size = 0x0
self.dbg_overwrite_size = 0x1
self.process_regs = process_regs
self.process_type = process_type
self.endian = endian
Expand Down Expand Up @@ -245,7 +245,7 @@ def is_task_on_break_point(self, task):
if self.endian == 2:
pack_parm = "<I"
sp = int(self.current_task_regs[task]["sp"], 16)
break_point = struct.unpack(pack_parm, self.get_mem_dump(sp + 0x08, 0x04))[0] - self.bp_overwrite_size
break_point = (struct.unpack(pack_parm, self.get_mem_dump(sp + 0x08, 0x04))[0] - self.bp_overwrite_size) & 0xfffffffe # take 16bit in considerate
original_ra = struct.unpack(pack_parm, self.get_mem_dump(sp + 0x04, 0x04))[0]
self.current_bp_info["bp_address"] = break_point # break point address = $ra - 0x08
self.current_bp_info["flag_address"] = sp
Expand Down Expand Up @@ -282,6 +282,12 @@ def remove_all_temp_bp(self):
# cleanup list after temp break point restore
del self.break_points[bp_addr]

def remove_break_point(self,bp_addr):
self.restone_bp_asm(bp_addr)
# cleanup list after temp break point restore
del self.break_points[bp_addr]


def _is_on_break_point(self):
"""Check did any task hit break point.

Expand All @@ -292,9 +298,12 @@ def _is_on_break_point(self):
return None
# TODO: need handle multi task hit breakpoint.
for task in current_tasks_status:
if self._is_address_in_debug_loop(int(current_tasks_status[task]['pc'], 16)):
return task

self.logger.debug(current_tasks_status[task])
try:
if self._is_address_in_debug_loop(int(current_tasks_status[task]['pc'], 16)):
return task
except:
return None
return None

def wait_break(self):
Expand All @@ -306,10 +315,9 @@ def wait_break(self):
try:
# Wait for any task hit break point.
task = self._is_on_break_point()
while not task:
while task is None:
task = self._is_on_break_point()
time.sleep(0.2)

# Get break point by task
current_breakpoint = self.is_task_on_break_point(task)
while not current_breakpoint:
Expand Down Expand Up @@ -423,7 +431,7 @@ def show_task_bp_asm(self, task):
"""
bp_address = self.current_bp_info["bp_address"]
bp_asm_data = self.break_points[bp_address]["original_asm"]
bp_asm_code = self.disassemble(bp_asm_data, bp_address, CS_ARCH_MIPS, CS_MODE_MIPS32, CS_MODE_BIG_ENDIAN)
bp_asm_code = self.disassemble(bp_asm_data, bp_address, CS_ARCH_MIPS, CS_MODE_MIPS32,CS_MODE_BIG_ENDIAN if self.endian == 1 else CS_MODE_LITTLE_ENDIAN)
print(bp_asm_code)

def show_task_bp_trace(self, task):
Expand Down Expand Up @@ -523,18 +531,20 @@ def task_resume(self, task, wait=True):
if wait:
self.wait_task_break(task)

def create_bp_asm(self, bp_address):
def create_bp_asm(self, bp_address,is_16bit):
"""Create breakpoint asm code

:param bp_address: break point address
:return: Breakpoint shellcode
"""
self.not_implemented("create_bp_asm")

def add_break_point(self, bp_address, bp_type=0, condition=None):
def add_break_point(self, bp_address, is_16bit = 0,bp_type=0, condition=None):
"""Add break point

:param bp_address: Break point address you want to Add.
:param is_16bit 0 = 32 bit MIPS
1 = 16 bit MIPS
:param bp_type: 0 = normal break point should will keep
1 = temp break point, used to keep normal break point add automatically.
will be removed after hit normal break point.
Expand All @@ -547,14 +557,14 @@ def add_break_point(self, bp_address, bp_type=0, condition=None):
if bp_type == 0:
self.logger.info("Add breakpoint at %s" % hex(bp_address))
# create break point asm
asm_data = self.create_bp_asm(bp_address)
asm_data = self.create_bp_asm(bp_address,is_16bit)
if not asm_data:
self.logger.error("Can't create break point asm")
return False
asm_length = len(asm_data)
# get original_asm
original_asm = self.get_mem_dump(bp_address, asm_length)
bp_asm_code = self.disassemble(original_asm, bp_address, CS_ARCH_MIPS, CS_MODE_MIPS32, CS_MODE_BIG_ENDIAN)
bp_asm_code = self.disassemble(original_asm, bp_address, CS_ARCH_MIPS, CS_MODE_MIPS32,CS_MODE_BIG_ENDIAN if self.endian == 1 else CS_MODE_LITTLE_ENDIAN)
self.logger.debug("original_asm: %s" % original_asm)
self.bp_overwrite_size = asm_length
self.write_memory_data(bp_address, asm_data)
Expand Down
34 changes: 34 additions & 0 deletions serial_debugger_example_with16bit.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# !/usr/bin/env python2
# coding=utf-8
from serial_debuger.vx5_mips_debugger import *
from serial_debuger.serialtube import serialtube
import logging
import socket
import time


def wait_move_on(print_string):
print(print_string)
move_on = False
while move_on is False:
ans = raw_input("Y/y to move on,\n:")
if ans.upper() == "Y":
move_on = True
return

serial_port = "/dev/ttyUSB2"
debugger = Vx5MipsDebugger(endian=2,cache_update_address=0x800C9B51 #flag 1 is for 16bit
,process_type='MIPSLE')
debugger.serial = serialtube(port=serial_port,baudrate=57600)
#debugger.logger.setLevel(logging.DEBUG)
debugger.init_debugger(0x8014BA00)

#flag 1 for 16bit
debugger.add_break_point(0x800F77F0,1)

task = debugger.wait_break()
wait_move_on('success break!')

print("Resume task")
debugger.task_resume(task)