Repository: yangyss/lldb-trace
Branch: script1.0.1
Commit: 1a66059419c7
Files: 7
Total size: 84.5 KB
Directory structure:
gitextract_o893_d24/
├── .gitignore
├── README.md
├── lldbTrace.py
├── main.mm
└── tools/
└── verifyAlgorithm/
├── checkDemo
├── test.py
└── wtpytracer.py
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitignore
================================================
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# C extensions
*.so
# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
pip-wheel-metadata/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
*.py,cover
.hypothesis/
.pytest_cache/
# Translations
*.mo
*.pot
# Django stuff:
*.log
local_settings.py
db.sqlite3
db.sqlite3-journal
# Flask stuff:
instance/
.webassets-cache
# Scrapy stuff:
.scrapy
# Sphinx documentation
docs/_build/
# PyBuilder
target/
# Jupyter Notebook
.ipynb_checkpoints
# IPython
profile_default/
ipython_config.py
# pyenv
.python-version
# pipenv
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
# However, in case of collaboration, if having platform-specific dependencies or dependencies
# having no cross-platform support, pipenv may install dependencies that don't work, or not
# install all needed dependencies.
#Pipfile.lock
# PEP 582; used by e.g. github.com/David-OConnor/pyflow
__pypackages__/
# Celery stuff
celerybeat-schedule
celerybeat.pid
# SageMath parsed files
*.sage.py
# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/
# Spyder project settings
.spyderproject
.spyproject
# Rope project settings
.ropeproject
# mkdocs documentation
/site
# mypy
.mypy_cache/
.dmypy.json
dmypy.json
# Pyre type checker
.pyre/
================================================
FILE: README.md
================================================
# lldbTrace
##### How to use it?
> 1.*Break at an address where you want to begin tracing.*
>
> 
>
> 2, *Import lldb python script.*
>
> 
>
> 3,*Use 'trace' command,and set end tracing addresses.Multi-address split by ";".*
>
> 
>
> 4,*Result like ...*
>
> 
> *参考:https://github.com/gm281/lldb-trace*
================================================
FILE: lldbTrace.py
================================================
#!/usr/bin/python3
# -*- encoding: utf-8 -*-
#@File : lldb-trace.py
#@Time : 2021/06/25 22:16:01
#@Author : wt
import re
import lldb
import shlex
import optparse
import threading
import ctypes
import os
log_default_path = '~/Desktop/' # 默认路径 ,
options = None
d_log_file = None # fileName : Redirect debug log in d_log_file
d_log_file_name = None
t_log_file = None # fileName : Redirect trace log in t_log_file
t_log_file_name = None
t_only_self_module = None
t_parser_msgsend_parameters = None
ASLR = None
num_for_print_progress = 500 # 进度条
def log_d(msg): # debug log
global d_log_file,options
if options.log_type == 'debug':
d_log_file.write(msg)
d_log_file.write('\n')
def log_t(msg): # trace log
global t_log_file
t_log_file.write(msg)
t_log_file.write('\n')
def log_c(msg): # console log
global options
if options.print_tracing_progress:
print(msg)
def log_flush():
global d_log_file,t_log_file
if d_log_file is not None:
d_log_file.flush()
if t_log_file is not None:
t_log_file.flush()
def dlog(msg):
print("xxxxxxxxx-> {}".format(msg))
# 调试类型
TRACE_TYPE_Instrument = 0,
TRACE_TYPE_Function = 1,
# 设备架构
DEVICE_BSD32 = 'BSD32'
DEVICE_BSD64 = 'BSD64'
DEVICE_Arm64 = 'Arm64'
DEVICE_x8664 = 'x86-64'
DEVICE_x8632 = 'x86-32'
# 调试中需要处理的 汇编指令信息
CONST_INS_call = 'call',
CONST_INS_jmp = 'jmp',
CONST_INS_condition_jmp = 'condition_jmp',
CONST_INS_syscall = 'syscall',
CONST_INS_end = 'func_end_mnemonic'
CONST_FUNC_NAME_ignore_list = 'ignore_func_name_list'
CONST_FUNC_NAME_protect_list = 'protect_func_name_list'
CONST_PRINT_obj = 'obj'
CONST_PRINT_char_star = 'char_star'
CONST_REGISTER_re = 're'
CONST_REGISTER_default_return_register = 'default_return_register'
# 断点列表里的 key
CONST_BREAKPOINT_BREAKPOINE = 'breakpoint',
CONST_BREAKPOINT_INDEX = 'index', # 引用计数
# deal_with 的 返回值
CONST_DEAL_WITH_error = 0,
CONST_DEAL_WITH_continue = 1,
CONST_DEAL_WITH_wait_breakpoint = 2,
CONST_DEAL_WITH_break = 3,
# check ins end type
CONST_CHECK_ins_default = 0
CONST_CHECK_ins_ret = 1
CONST_CHECK_ins_end_address =2
#########################################################
CONST_DEVICE_info_list = {
DEVICE_BSD64 : {
CONST_FUNC_NAME_ignore_list : ['printf','objc_unsafeClaimAutoreleasedReturnValue','objc_storeStrong'],
CONST_FUNC_NAME_protect_list : {
'objc_msgSend' : {
# if trace function,need to analyse parameters. if parser_msgsend_parameters was true, need to analyse parameters too.
CONST_PRINT_obj:['po [$x0 class]'],
CONST_PRINT_char_star:['x1']
}
},
CONST_REGISTER_re : [r'\b[xwd][0-9]{1,2}',r'\b[xwd][0-9]{1,2},',r'sp'], # r'\b[xw][0-9]{1,2}[,]{0,1}'
CONST_REGISTER_default_return_register:'x0',
CONST_INS_call : ['bl'],#,'bl',
CONST_INS_jmp : ['cb','b','tb'],#'b',
CONST_INS_condition_jmp : ['b'],
CONST_INS_syscall : ['svc'],#'svc'
CONST_INS_end : ['ret']
},
DEVICE_Arm64 : {},
DEVICE_x8664 : {},
DEVICE_x8632 : {}
}
#########################################################
# 当前设备类型
DEVICE = DEVICE_BSD64
#########################################################
class WTListeningThread(threading.Thread):
def __init__(self, wait_event, notify_event,listener,process):
super(WTListeningThread, self).__init__()
self.wait_event = wait_event
self.notify_event = notify_event
self.listener = listener
self.process = process
self.exiting = False
self.wait_timeout = False
def wait_timed_out(self):
return self.wait_timeout
def exit(self):
self.exiting = True
def run(self):
steam :lldb.SBStream = lldb.SBStream()
while True:
self.wait_event.wait()
self.wait_event.clear()
if self.exiting:
log_d('=>>>Listener thread was asked to exit, complying')
self.notify_event.set()
return
while True:
event = lldb.SBEvent()
steam.Clear()
log_d('=>>>Listener waiting for events')
wait_result = self.listener.WaitForEvent(10, event)
event.GetDescription(steam)
log_d('=>>>Listener wait exited: {}, {}'.format(str(wait_result), steam.GetData()))
if not wait_result:
log_d('=>>>Listener thread timed out waiting for notification')
self.wait_timeout = True
self.notify_event.set()
break
processState = self.process.GetState()
if processState == lldb.eStateStopped:
log_d('=>>>Listener detected process state change, but it is not stopped: {}'.format(str(processState)))
break
log_d('=>>>Process not stopped, listening for the next event')
log_d('=>>>Listener thread got event, notifying')
self.notify_event.set()
def get_c_char_star(address):
retstr = ''
curr_addr = address
while True:
p = ctypes.cast(curr_addr,ctypes.POINTER(ctypes.c_char))
value = p.contents.value
if not (value[0] == 0) :
retstr = retstr + chr(value[0])
curr_addr = curr_addr + 1
else:
break
return retstr
def handle_command(command,debugger:lldb.SBDebugger):
log_d('handle_command -> command : {}'.format(command))
interpreter:lldb.SBCommandInterpreter = debugger.GetCommandInterpreter()
re_obj:lldb.SBCommandReturnObject = lldb.SBCommandReturnObject()
interpreter.HandleCommand(command,re_obj)
result = ''
log_d('handle_command -> re_obj status : {}'.format(re_obj.GetStatus()))
if re_obj.GetStatus() == lldb.eReturnStatusSuccessFinishResult:
result = re_obj.GetOutput()
# print('|{}|'.format(result.replace('\n','')))
return result.replace('\n','')
def continue_and_wait_for_breakpoint(process, thread, listening_thread, wait_event, notify_event):
wait_event.set()
log_d("Process in state: {}".format(str(process.GetState())))
process.Continue()
log_d('Process continued, waiting for notification')
notify_event.wait()
notify_event.clear()
log_d('Got notification, process in state: {}, sanity checks follow'.format(str(process.GetState())))
if listening_thread.wait_timed_out():
log_d('Listener thread exited unexpectedly')
return False
if thread.GetStopReason() != lldb.eStopReasonBreakpoint:
log_d("Thread {} didn't stop due to a breakpoint".format(str(thread)))
return False
return True
def suspend_threads_escape_select_thread(process:lldb.SBProcess,flag:bool):
select_thread :lldb.SBThread = process.GetSelectedThread()
if flag :
for item in process:
if select_thread.GetThreadID() == item.GetThreadID():
log_d('current run thread : {}'.format(item))
else:
log_d('Suspend thread : {}'.format(item))
item.Suspend()
else:
log_d('Resume all threads.')
for item in process:
item.Resume()
def match_registers(text):
now_list = []
fileters = CONST_DEVICE_info_list[DEVICE][CONST_REGISTER_re]
for item in fileters:
find_result = re.finditer(item,text)
match : str = ''
for match in find_result:
tmpStr = '{}'.format(match.group())
if tmpStr.find(',') >= 0 :
if not(tmpStr[:-1] in now_list) :
now_list.append(tmpStr[:-1])
else:
if not(tmpStr in now_list):
now_list.append(tmpStr)
return now_list
class WTInstruction():
def __init__(self, target, thread, frame,debugger,traceType=TRACE_TYPE_Instrument,traceMsgSend=False,endAddress=None):
self.target:lldb.SBTarget = target
self.thread:lldb.SBThread = thread
self.frame:lldb.SBFrame = frame
self.debugger:lldb.SBDebugger = debugger
self.trace_type = traceType # Trace 类型
self.next_instruction:lldb.SBInstruction = None # 下一条 instruction
self.current_instruction:lldb.SBInstruction = None # 当前 instruction
self.last_instruction:lldb.SBInstruction = None # 上一条 instruction
self.begin_trace_address = None # 开始 Trace 地址
self.end_trace_address = []
for item in re.split(';',endAddress):
self.end_trace_address.append(int(item,16)) # 结束 Trace 地址
# 包含 breakpoint : 以及 引用计数 used_num :
self.breakpoint_list = {} # 所有断点 的 list
self.current_instruction_list = {} # 当前 symbol 下的 所有的 instruction 列表
self.current_instruction_end_address_list = [] # 当前 symbol 下的 所有的 end_address 列表
self.call_return_instruction_list = {} # tracing 中,所有函数返回的地址 列表
self.current_module_name:str = None # 当前模块
self.append_msg = '' # 附加消息
self.print_index = 0
self.print_text = ' '
def increase_print_index(self):
log_d('@@@@ increase print index. {} : {}'.format(self.print_index,self.print_index + 1))
self.print_index = self.print_index + 1
def check_in_call_return_instruction_list(self):
pc = self.get_current_pc()
if pc in self.call_return_instruction_list:
log_d('@@@@ {} in call_return_instruction_list'.format(hex(pc)))
return True
log_d('@@@@ {} not in call_return_instruction_list'.format(hex(pc)))
return False
def decrease_print_index(self):
log_d('@@@@ decrease print index. {} : {}'.format(self.print_index,self.print_index - 1))
self.print_index = self.print_index - 1
def check_str_in_arr(self,cur_str:str,cur_arr):
for item in cur_arr:
if cur_str.startswith(item):
return True
return False
def init_env(self):
frame :lldb.SBFrame = self.thread.GetSelectedFrame()
symbol:lldb.SBSymbol = frame.GetSymbol()
if self.current_module_name is None:
self.current_module_name:str = '{}'.format(self.frame.GetModule())
log_d('current module name : {}'.format(self.current_module_name))
instructionlist : lldb.SBInstructionList = symbol.GetInstructions(self.target)
# 清空 current_instruction_list 和 current_instruction_end_address_list
if self.current_instruction_list:
self.current_instruction_list = {}
self.current_instruction_end_address_list = []
# endaddress 加入到 end tracing 地址列表中
cur_end_address = symbol.GetEndAddress().GetLoadAddress(self.target) - 4
self.end_trace_address.append(cur_end_address)
# 把 返回指令的 地址 加入到 end tracing 地址列表中
instruction :lldb.SBInstruction = None
for instruction in instructionlist:
address :lldb.SBAddress = instruction.GetAddress()
cur_mnemonic:str = instruction.GetMnemonic(self.target)
load_address = address.GetLoadAddress(self.target)
if self.check_str_in_arr(cur_mnemonic,CONST_DEVICE_info_list[DEVICE][CONST_INS_end]):
if not load_address in self.end_trace_address:
self.end_trace_address.append(load_address)
# 获得当前 pc
def get_current_pc(self):
now_frame :lldb.SBFrame = self.thread.GetSelectedFrame()
if now_frame:
return now_frame.GetPC()
return None
# 判断当前 pc 是否在 list 中
# 不在的话,更新所有 list
def checkPCInList_transferCurrentSymbolInstrucionsToList(self,address):
# current_instruction_list 为空,或者 cur_pc(有效) 不在 current_instruction_list 里
if not self.current_instruction_list or (address and (not (address in self.current_instruction_list))) :
frame :lldb.SBFrame = self.thread.GetSelectedFrame()
symbol:lldb.SBSymbol = frame.GetSymbol()
################## 给 current_instruction_end_address_list 赋值
# 获得 当前 symbol 下的 endAddress
cur_end_address = symbol.GetEndAddress().GetLoadAddress(self.target) - 4
log_d('cur symbol end addr : {}'.format(hex(cur_end_address)))
self.current_instruction_end_address_list = []
# 把 结束地址,加入到 current_instruction_end_address_list 中
self.current_instruction_end_address_list.append(cur_end_address)
# 给 current_instruction_list 赋值
# 获得 当前 symbol 下的 instructionlist
instructionlist : lldb.SBInstructionList = symbol.GetInstructions(self.target)
# 清空 current_instruction_list
if self.current_instruction_list:
self.current_instruction_list = {}
self.current_instruction_end_address_list = {}
instruction :lldb.SBInstruction = None
# 处理 所有的 instruction,
for instruction in instructionlist:
address :lldb.SBAddress = instruction.GetAddress()
cur_mnemonic:str = instruction.GetMnemonic(self.target)
load_address = address.GetLoadAddress(self.target)
self.current_instruction_list[load_address] = instruction
return False
return True
def updata_instruction_instructionList(self):
cur_pc = self.get_current_pc()
self.checkPCInList_transferCurrentSymbolInstrucionsToList(cur_pc)
if cur_pc in self.current_instruction_list:
self.current_instruction = self.current_instruction_list[cur_pc]
else:
self.current_instruction = None
def clean_env(self):
for item in self.breakpoint_list.values():
breakpoint :lldb.SBBreakpoint = item[CONST_BREAKPOINT_BREAKPOINE]
self.target.BreakpointDelete(breakpoint.GetID())
self.breakpoint_list = {}
def deal_with(self):
return self.deal_with_ins()
def updata_last_instruction(self):
self.last_instruction = self.current_instruction
def get_current_symbol_name(self):
frame:lldb.SBFrame = self.thread.GetSelectedFrame()
sym:lldb.SBSymbol = frame.GetSymbol()
return sym.GetName()
def get_next_instruction(self):
pc = self.get_current_pc()
size = self.current_instruction.GetByteSize()
next_pc = pc + size
self.checkPCInList_transferCurrentSymbolInstrucionsToList(next_pc)
if next_pc in self.current_instruction_list:
self.next_instruction = self.current_instruction_list[next_pc]
else:
self.next_instruction = None
def print_tracing_progress(self,count):
# 当前trace的总行数 内存地址:文件地址: <函数名>
global ASLR
mem_addr = 0
file_addr = 0
if self.current_instruction:
mem_addr = self.current_instruction.GetAddress().GetLoadAddress(self.target)
if not (mem_addr == 0) :
file_addr = mem_addr - ASLR
out_str = '{: <10} {} : {} <{}>'.format(count,hex(mem_addr),hex(file_addr),self.get_current_symbol_name())
log_c(out_str)
def log_current_instruction(self,cur_pc):
cur_mnemonic:str = self.current_instruction.GetMnemonic(self.target)
cur_operands:str = self.current_instruction.GetOperands(self.target)
aligns = self.print_text * self.print_index
if self.last_instruction:
last_mnemonic:str = self.last_instruction.GetMnemonic(self.target)
if self.check_str_in_arr(last_mnemonic,CONST_DEVICE_info_list[DEVICE][CONST_INS_call]) :
frame:lldb.SBFrame = self.thread.GetSelectedFrame()
return_register = CONST_DEVICE_info_list[DEVICE][CONST_REGISTER_default_return_register]
value:lldb.SBValue = frame.FindRegister(return_register)
data_str = '{: <3} : {} '.format(return_register,value.GetValue())
log_t('{}{: <15}{: <6}{: <30}// {} {}'.format(aligns,hex(cur_pc),cur_mnemonic,cur_operands,data_str,self.append_msg))
self.append_msg = ''
return
last_operands:str = self.last_instruction.GetOperands(self.target)
register_arr = match_registers(last_operands)
data_str = ''
for now_reg in register_arr:
frame:lldb.SBFrame = self.thread.GetSelectedFrame()
value:lldb.SBValue = frame.FindRegister(now_reg)
data_str = '{}{: <3} : {} '.format(data_str,now_reg,value.GetValue())
log_t('{}{: <15}{: <6}{: <30}// {} {}'.format(aligns,hex(cur_pc),cur_mnemonic,cur_operands,data_str,self.append_msg))
self.append_msg = ''
return
log_t('{}{: <15}{: <6}{: <30} {}'.format(aligns,hex(cur_pc),cur_mnemonic,cur_operands,self.append_msg))
self.append_msg = ''
def parser_ins_symbol_name(self,last_symbole_name:str,cur_symbol_name : str):
if not cur_symbol_name or not last_symbole_name:
log_d('err : cur_symbol_name or last_symbole_name is None')
return True
if cur_symbol_name in CONST_DEVICE_info_list[DEVICE][CONST_FUNC_NAME_ignore_list]:
# 忽略的 符号名
log_d('cur_symbol_name in ignore_function_names')
return True
if cur_symbol_name in CONST_DEVICE_info_list[DEVICE][CONST_FUNC_NAME_protect_list]:
# # 设置 附加信息
# # log_t('{}<< current frame name >> : {}'.format(aligens,cur_symbol_name))
# frame :lldb.SBFrame = self.thread.GetSelectedFrame()
# for pro_key,pro_value in CONST_DEVICE_info_list[DEVICE][CONST_FUNC_NAME_protect_list].items():
# if pro_key == cur_symbol_name:
# objs = pro_value[CONST_PRINT_obj]
# char_stars = pro_value[CONST_PRINT_char_star]
# for char_star_item in char_stars:
# func_name_register:lldb.SBValue = frame.FindRegister(char_star_item)
# addr = int(func_name_register.GetValue(),16)
# self.append_msg = ' : {}{: <3} ==> {} '.format(self.append_msg,char_star_item,get_c_char_star(addr))
# for obj_item in objs:
# item_value = handle_command(obj_item,self.debugger)
# self.append_msg = '{}{: <3} ==> {} '.format(self.append_msg,obj_item,item_value)
# break
# log_d('cur_symbol_name in protect_function_names')
# return True
pass
return False
def add_next_breakpoint(self):
if self.next_instruction:
next_pc = self.next_instruction.GetAddress().GetLoadAddress(self.target)
if next_pc in self.breakpoint_list:
breakpoint = self.breakpoint_list[next_pc][CONST_BREAKPOINT_BREAKPOINE]
log_d('->>> increase index on breakpoint : {}'.format(str(breakpoint)))
self.breakpoint_list[next_pc][CONST_BREAKPOINT_INDEX] = self.breakpoint_list[next_pc][CONST_BREAKPOINT_INDEX] + 1
else:
breakpoint :lldb.SBBreakpoint = self.target.BreakpointCreateByAddress(next_pc)
breakpoint.SetThreadID(self.thread.GetThreadID())
item = {}
item[CONST_BREAKPOINT_BREAKPOINE] = breakpoint
item[CONST_BREAKPOINT_INDEX] = 1
self.breakpoint_list[next_pc] = item
log_d('->>> add address : {} breakpoint : {}'.format(hex(next_pc),str(breakpoint)))
def add_call_return_addr(self):
if self.next_instruction:
next_pc = self.next_instruction.GetAddress().GetLoadAddress(self.target)
log_d('add {} index in call_return_instruction_list.'.format(hex(next_pc)))
if next_pc in self.call_return_instruction_list:
self.call_return_instruction_list[next_pc] = self.call_return_instruction_list[next_pc] + 1
else:
self.call_return_instruction_list[next_pc] = 1
def sub_call_return_addr(self):
pc = self.get_current_pc()
if pc in self.call_return_instruction_list:
log_d('@@@@ delete call return addr : {} out of call_return_instruction_list.'.format(hex(pc)))
if self.call_return_instruction_list[pc] > 1:
tmp = self.call_return_instruction_list[pc]
self.call_return_instruction_list[pc] = tmp - 1
else:
self.call_return_instruction_list.pop(pc)
def check_need_delete_breakpoint_in_current_call_return_list_and_decrease_index(self,cur_pc):
if cur_pc in self.call_return_instruction_list:
index = self.call_return_instruction_list[cur_pc]
if index > 0 :
self.call_return_instruction_list[cur_pc] = index - 1
return True
else:
self.call_return_instruction_list.pop(cur_pc)
return False
def delete_current_breakpoint(self):
if self.current_instruction:
curr_pc = self.current_instruction.GetAddress().GetLoadAddress(self.target)
if not curr_pc in self.breakpoint_list:
log_d('->>> {} not in breakpoint_list'.format(hex(curr_pc)))
return
item = self.breakpoint_list[curr_pc]
if not item :
log_d('->>> curr address : {} not in breakpoint_list'.format(hex(curr_pc)))
return
index = item[CONST_BREAKPOINT_INDEX]
if index > 1 :
log_d('->>> increase index on breakpoint : {}'.format(str(item[CONST_BREAKPOINT_BREAKPOINE])))
self.breakpoint_list[curr_pc][CONST_BREAKPOINT_INDEX] = index - 1
elif index == 1:
delete_breakpoint :lldb.SBBreakpoint = item[CONST_BREAKPOINT_BREAKPOINE]
if not self.check_need_delete_breakpoint_in_current_call_return_list_and_decrease_index(curr_pc):
self.target.BreakpointDelete(delete_breakpoint.GetID())
log_d('**** delet breakpoint at : {}'.format(hex(self.get_current_pc())))
self.breakpoint_list.pop(curr_pc)
else:
log_c('->>> {} : breakpoint delete error'.format(hex(curr_pc)))
log_d('->>> {} : breakpoint delete error'.format(hex(curr_pc)))
def check_currentIns_is_endIns(self):
if self.current_instruction:
size = self.current_instruction.GetByteSize()
pc = self.get_current_pc()
nextpc = pc + size
if nextpc in self.current_instruction_end_address_list:
log_d('addr : {} in current_instruction_end_address_list'.format(hex(nextpc)))
return True,CONST_CHECK_ins_end_address
mnemonic:str = self.current_instruction.GetMnemonic(self.target)
for ins_end_item in CONST_DEVICE_info_list[DEVICE][CONST_INS_end]:
if mnemonic.startswith(ins_end_item):
log_d('addr : {} is CONST_INS_end'.format(hex(pc)))
return True,CONST_CHECK_ins_ret
log_d('addr : {} is default ins.'.format(hex(pc)))
return False,CONST_CHECK_ins_default
else:
log_d('warning : current ins is None.')
log_c('warning : current ins is None.')
return False,CONST_CHECK_ins_default
def check_ins_call(self,mnemonic:str,cur_symbol:lldb.SBSymbol):
for call_item in CONST_DEVICE_info_list[DEVICE][CONST_INS_call]:
if not mnemonic.startswith(call_item):
continue
pc = self.get_current_pc()
self.get_next_instruction() # 获得下一条指令
if not self.next_instruction is None:
self.add_next_breakpoint()
self.add_call_return_addr()
last_symbol_name = self.get_current_symbol_name()
self.delete_current_breakpoint()# 删除当前断点
self.thread.StepInstruction(False) # 单步进入
sym_name = self.get_current_symbol_name()
if self.parser_ins_symbol_name(last_symbol_name,sym_name) : # 解析 symbol_name
self.append_msg = sym_name + self.append_msg
self.log_current_instruction(pc)
self.increase_print_index()
log_d('####### return : check_ins_call. ignore fun or protect fun. value : CONST_DEAL_WITH_wait_breakpoint')
return True,CONST_DEAL_WITH_wait_breakpoint
self.log_current_instruction(pc) # 打印信息
if not(sym_name == last_symbol_name) :
if sym_name and (not (sym_name == '')):
log_t('{}{} : '.format(self.print_text * self.print_index,sym_name))
# 忽略的,保护的,需要 CONST_DEAL_WITH_wait_breakpoint
self.increase_print_index()
log_d('####### return : check_ins_call. value : CONST_DEAL_WITH_continue')
return True,CONST_DEAL_WITH_continue
return False,None
def check_ins_jmp(self,mnemonic:str,cur_symbol:lldb.SBSymbol):
for jmp_item in CONST_DEVICE_info_list[DEVICE][CONST_INS_jmp]:
if not mnemonic.startswith(jmp_item):
continue
pc = self.get_current_pc()
self.get_next_instruction() # 获得下一条指令
if not self.next_instruction is None:
self.add_next_breakpoint()
last_symbol_name = self.get_current_symbol_name()
self.delete_current_breakpoint()
self.thread.StepInstruction(False)
sym_name = self.get_current_symbol_name()
if sym_name and self.parser_ins_symbol_name(last_symbol_name,sym_name):
print('type : {} symName : {}'.format(type(sym_name),sym_name))
if self.append_msg == None:
self.append_msg = ''
self.append_msg = sym_name + self.append_msg
self.log_current_instruction(pc)
log_d('####### return : check_ins_jmp. ignore fun or protect fun. value : CONST_DEAL_WITH_wait_breakpoint')
return True,CONST_DEAL_WITH_wait_breakpoint
self.log_current_instruction(pc) # 打印信息
log_d('####### return : check_ins_jmp. same module. value : CONST_DEAL_WITH_continue')
return True,CONST_DEAL_WITH_continue
return False,None
def check_ins_syscall(self,mnemonic:str,cur_symbol:lldb.SBSymbol):
for syscall_item in CONST_DEVICE_info_list[DEVICE][CONST_INS_syscall]:
if not mnemonic.startswith(syscall_item):
continue
self.get_next_instruction() # 获得下一条指令
if not self.next_instruction is None:
self.add_next_breakpoint()
self.delete_current_breakpoint()
self.log_current_instruction(self.get_current_pc()) # 打印信息
log_d('####### return : check_ins_syscall. value : CONST_DEAL_WITH_wait_breakpoint')
return True,CONST_DEAL_WITH_wait_breakpoint
return False,None
def check_ins_other(self,cur_symbol:lldb.SBSymbol):
self.get_next_instruction() # 获得下一条指令
if not self.next_instruction is None:
self.add_next_breakpoint()
self.delete_current_breakpoint()
self.log_current_instruction(self.get_current_pc()) # 打印信息
def check_out_tracing(self):
# 递归函数的处理 。。。。。。。
pc = self.get_current_pc()
if pc in self.end_trace_address:
self.delete_current_breakpoint()
self.log_current_instruction(pc)
log_d('end trace addr list : {}'.format(self.end_trace_address))
log_d('cur pc : {}'.format(pc))
return True
return False
def check_end_fun(self):
# 当前在结束地址
flag,ret = self.check_currentIns_is_endIns()
if flag :
if ret == CONST_CHECK_ins_ret:
pc = self.get_current_pc()
self.delete_current_breakpoint()
self.log_current_instruction(pc)
log_d('@@@@ check_end_fun : address : {} is ret ins.'.format(hex(pc)))
return True,CONST_DEAL_WITH_wait_breakpoint
elif ret == CONST_CHECK_ins_end_address:
last_pc = self.get_current_pc()
self.thread.StepInstruction(False)
self.delete_current_breakpoint()
# 判断当前pc 是否在 instructionList中
pc = self.get_current_pc()
if pc in self.current_instruction_list:
self.log_current_instruction(last_pc)
log_d('@@@@ check_end_fun : address : {} is call end address,and in current_instruction_list.'.format(hex(last_pc)))
return True,CONST_DEAL_WITH_continue
else:
# 可以 decrease print index
self.log_current_instruction(last_pc)
log_d('@@@@ check_end_fun : address : {} is call end address,and not in current_instruction_list.'.format(hex(last_pc)))
return True,CONST_DEAL_WITH_wait_breakpoint
else:
pass
log_d('@@@@ check_end_fun : address : {} is not call end address or ret ins.'.format(hex(self.get_current_pc())))
return False,None
def check_symbol_valid(self):
now_frame :lldb.SBFrame = self.thread.GetSelectedFrame()
if now_frame:
sym:lldb.SBSymbol = now_frame.GetSymbol()
if not sym.IsValid():
log_d('####### return : check_symbol_valid not valid. value : CONST_DEAL_WITH_wait_breakpoint')
return False,CONST_DEAL_WITH_wait_breakpoint
log_d('@@@@ check_symbol_valid : valid.')
return True,None
def check_in_module(self):
frame :lldb.SBFrame = self.thread.GetSelectedFrame()
now_module_name = '{}'.format(frame.GetModule())
log_d('@@@@ current module name : {}'.format(now_module_name))
if now_module_name == self.current_module_name :
return True,None
log_d('####### return : check_in_module. is not current module. value : CONST_DEAL_WITH_wait_breakpoint')
return False,CONST_DEAL_WITH_wait_breakpoint
def deal_with_ins(self):
if self.check_in_call_return_instruction_list():
self.decrease_print_index()
self.sub_call_return_addr()
# 结束tracing
if self.check_out_tracing():
log_d('####### return : check_out_tracing value : CONST_DEAL_WITH_break')
return CONST_DEAL_WITH_break
# 函数结束的判断
flag,ret = self.check_end_fun()
if flag:
log_d('####### return : check_end_fun')
return ret
# frame.GetFunction 和 frame.GetSymbol 是否有效
flag,ret = self.check_symbol_valid()
if not flag :
return ret
global t_only_self_module
if t_only_self_module :
flag,ret = self.check_in_module()
if not flag:
return ret
instruction:lldb.SBInstruction = self.current_instruction
mnemonic = None
if instruction :
mnemonic:str = instruction.GetMnemonic(self.target)
else:
log_d('warning : instruction is None')
log_c('warning : instruction is None')
cur_frame:lldb.SBFrame = self.thread.GetFrameAtIndex(0)
cur_symbol:lldb.SBSymbol = cur_frame.GetSymbol()
flag,value = self.check_ins_call(mnemonic,cur_symbol) # call 指令 操作
if flag:
log_d('check_ins_call')
return value
flag,value = self.check_ins_jmp(mnemonic,cur_symbol) # jmp 指令 操作
if flag:
log_d('check_ins_jmp')
return value
flag,value = self.check_ins_syscall(mnemonic,cur_symbol) # syscall 指令 操作
if flag :
log_d('check_ins_syscall')
return value
self.check_ins_other(cur_symbol) # 其他指令的操作
log_d('####### return : check_ins_other. value : CONST_DEAL_WITH_wait_breakpoint')
return CONST_DEAL_WITH_wait_breakpoint
class WTFunction():
def __init__(self, *args):
pass
def deal_with_fun(self):
pass
class TraceOptionParser(optparse.OptionParser):
def __init__(self, result):
optparse.OptionParser.__init__(self)
self.result = result
self.exited = False
def get_prog_name(self):
return "trace"
def exit(self, status=0, msg=None):
if msg is not None:
# print >>self.result, msg
print(msg,file=self.result)
self.exited = True
def parse_options(command, result):
global options
command_tokens = shlex.split(command)
parser = TraceOptionParser(result)
parser.add_option("-e","--end-address",action="store",metavar="END_ADDRESS",dest="end_address",help="End addresses of trace,using to stop trace thread.More address,use ';' to split.")
parser.add_option("-o","--only-tracing-self-module",action="store_true",dest="only_tracing_self_module",default=True,help="Only tracing in current module.Default is True")
parser.add_option("-m","--mode-type",action="store",metavar="<instruction/function>",dest="mode_type",default="instruction",help='Tracing mode,contains function and instruction.Default is instruction mode.')
parser.add_option("-l","--log-type",action="store",metavar="<trace/debug>",dest="log_type",default='trace',help="Set log type for this tracing. With trace type redirect trace output file. With debug type redirect trace and debug output files.Default is trace type.")
parser.add_option("-P","--parser-msgsend-parameters",action="store_true",dest="parser_msgsend_parameters",default=False,help="Parser objc_msgsend function's parameters.Default is False")
parser.add_option("-p","--print-tracing-progress",action="store_true",dest="print_tracing_progress",default=True,help="Print tracing progress in console.Default is True")
parser.add_option("-s","--suspend-threads-except-current-thread",action="store_true",dest="suspend_threads",default=True,help="Suspend threads except current thread,to clean env.Default is True")
(options, _) = parser.parse_args(command_tokens)
return parser.exited
def check_parser_command():
global options
global t_only_self_module,t_parser_msgsend_parameters
global t_log_file,t_log_file_name,d_log_file,d_log_file_name
if options.end_address is None :
print('err : plz input an address where you want to end tracing.')
return False
log_type_arr = ['trace','debug']
if not options.log_type in log_type_arr :
print('err : plz input -l --log-type value, use "trace" or "debug".')
return False
mode_type_arr = ['function','instruction']
if not options.mode_type in mode_type_arr:
print('err : plz input -m --mode-type value, use "function" or "instruction".')
return False
if options.log_type == 'trace':
print(type(t_log_file_name))
print(t_log_file_name)
t_log_file = open(t_log_file_name,'w')
if options.log_type == 'debug':
t_log_file = open(t_log_file_name,'w')
d_log_file = open(d_log_file_name,'w')
t_only_self_module = options.only_tracing_self_module
t_parser_msgsend_parameters = options.parser_msgsend_parameters
return True
def ini_log_file(mode_name:str):
import time
global log_default_path,t_log_file_name,d_log_file_name
timeName = int(time.time())
if mode_name == 'instruction':
if log_default_path.endswith('/'):
t_log_file_name = "{}{}{}".format(log_default_path,timeName,'instrace.log')
d_log_file_name = "{}{}{}".format(log_default_path,timeName,'insdebug.log')
log_c('trace log file : {}'.format(t_log_file_name))
log_c('debug log file : {}'.format(d_log_file_name))
else:
t_log_file_name = "{}/{}{}".format(log_default_path,timeName,'instrace.log')
d_log_file_name = "{}/{}{}".format(log_default_path,timeName,'insdebug.log')
log_c('trace log file : {}'.format(t_log_file_name))
log_c('debug log file : {}'.format(d_log_file_name))
elif mode_name == 'function':
if log_default_path.endswith('/'):
t_log_file_name = "{}{}{}".format(log_default_path,timeName,'funtrace.log')
d_log_file_name = "{}{}{}".format(log_default_path,timeName,'fundebug.log')
log_c('trace log file : {}'.format(t_log_file_name))
log_c('debug log file : {}'.format(d_log_file_name))
else:
t_log_file_name = "{}/{}{}".format(log_default_path,timeName,'funtrace.log')
d_log_file_name = "{}/{}{}".format(log_default_path,timeName,'fundebug.log')
log_c('trace log file : {}'.format(t_log_file_name))
log_c('debug log file : {}'.format(d_log_file_name))
else:
print('err : trace mode err.')
def test(debugger:lldb.SBDebugger):
return False
# import sys
# import os
# print(sys.argv[0])
# print(__file__)
# current_path = os.path.abspath(__file__)
# print(current_path)
# father_path = os.path.abspath(os.path.dirname(current_path) + os.path.sep + ".")
# print(father_path)
# global options
# endAddress = options.end_address
# a = re.split(';',endAddress)
# for item in a:
# print(type(int(item,16)))
# print(int(item,16))
# print(item)
# print(a)
# target: lldb.SBTarget = debugger.GetSelectedTarget()
# process: lldb.SBProcess = target.GetProcess()
# thread: lldb.SBThread = process.GetSelectedThread()
# frame: lldb.SBFrame = thread.GetSelectedFrame()
# symbol :lldb.SBSymbol = frame.GetSymbol()
# print(frame.GetModule())
# print('frame : {}'.format(frame))
# print('symbol.Instructions : ')
# print(symbol.GetInstructions(target))
# print('symbol : {}'.format(symbol))
# print('symbol.Name : "{}"'.format(symbol.GetName()))
# print('thread : {}'.format(thread))
# print('thread name : {}'.format(thread.GetName()))
# ins:lldb.SBInstruction = None
# stream:lldb.SBStream = lldb.SBStream()
# for ins in symbol.GetInstructions(target):
# # print(ins.GetData(target))
# ins.GetDescription(stream)
# addr :lldb.SBAddress = ins.GetAddress()
# module : lldb.SBModule = addr.GetModule()
# print('module : {}'.format(module))
# sym : lldb.SBSymbol = None
# for sym in module:
# print('sym name : {}'.format(sym.GetName()))
# break
# print('symbol valid : {}'.format(symbol.IsValid()))
# print('symbol DisplayName : {}'.format(symbol.GetDisplayName()))
# print('symbol MangledName : {}'.format(symbol.GetMangledName()))
return True
def trace(debugger: lldb.SBDebugger, command: str, result: lldb.SBCommandReturnObject, internal_dict):
'''
Traces execution of the symbol in the currently selected frame.
trace -h/--help, for full help
'''
global options
if parse_options(command, result):
return
####################################################
########################测 试########################
####################################################
if test(debugger):
return
####################################################
ini_log_file(options.mode_type)
if not check_parser_command():
return
wait_event = threading.Event()
wait_event.clear()
notify_event = threading.Event()
notify_event.clear()
target: lldb.SBTarget = debugger.GetSelectedTarget()
broadcaster: lldb.SBBroadcaster = target.GetBroadcaster()
log_d("Target: {}".format(str(target)))
process: lldb.SBProcess = target.GetProcess()
log_d("Process: {}".format(str(process)))
log_d("Broadcaster: {}".format(str(broadcaster)))
if options.suspend_threads :
suspend_threads_escape_select_thread(process,True)
listener = lldb.SBListener("trace breakpoint listener")
rc = broadcaster.AddListener(listener, lldb.SBProcess.eBroadcastBitStateChanged)
my_thread = WTListeningThread(wait_event, notify_event,listener, process)
my_thread.start()
thread: lldb.SBThread = process.GetSelectedThread()
log_d("Thread: {}".format(str(thread)))
frame: lldb.SBFrame = thread.GetSelectedFrame()
module: lldb.SBModule = frame.GetModule()
if frame.GetFrameID() == 0xFFFFFFFF:
log_d("Invalid frame, has your process started?")
return
insObj = WTInstruction(target,thread,frame,debugger,TRACE_TYPE_Instrument,endAddress=options.end_address)
## 初始化 环境
insObj.init_env()
global num_for_print_progress
insCount = 0
test_index = 0
while True:
log_d('index : {}'.format(test_index))
# 打印进度
if options.print_tracing_progress :
if insCount % num_for_print_progress == 0 and insCount > 0:
insObj.print_tracing_progress(insCount)
insCount = insCount + 1
# 更新当前 instruction / instructionList
log_d("////////////////////////////////loop begin////////////////////////////////")
insObj.updata_instruction_instructionList() # 更新所有的 指令 ,更新当前 指令
# ins : 设置断点,进行有必要的 单步 调试
# fun : 设置断点
ret = insObj.deal_with() # 处理 指令
# 保存指令
insObj.updata_last_instruction()
log_d("=================== Stopped at: ====================")
log_d("Frame: {}, symbol: {}, pc: {pc:#x}".format(str(frame), str(frame.GetSymbol()), pc=frame.GetPC()))
# 判断结果
if ret == CONST_DEAL_WITH_error:
log_c('err : deal with error.')
log_d('err : deal with error.')
insObj.clean_env()
break
if ret == CONST_DEAL_WITH_continue:
continue
if ret == CONST_DEAL_WITH_break :
break
continue_and_wait_for_breakpoint(process,thread,my_thread,wait_event,notify_event)
if options.suspend_threads :
suspend_threads_escape_select_thread(process,False)
my_thread.exit()
wait_event.set()
my_thread.join()
broadcaster.RemoveListener(listener)
log_d('Listener thread exited completing')
log_flush()
############################################################################################################################################################
#######################################################################traceblock###########################################################################
############################################################################################################################################################
class WTBlock():
def __init__(self, target, thread, frame,debugger,endAddress=None):
self.target:lldb.SBTarget = target
self.thread:lldb.SBThread = thread
self.frame:lldb.SBFrame = frame
self.debugger:lldb.SBDebugger = debugger
self.current_instruction_list = {}
self.end_trace_address = []
self.block_list = {} # 存贮所有的 block
#
# {
# addr : { # 这里是断点地址
# 'index' : 0 # 这里是断点信息
# 'breakpoint' : None # 这里是 lldb.SBBreakpoint
# }
# }
self.breakpoint_list = {} # 断点列表
self.loop_flag = False
self.append_msg = ''
# log
self.last_block_msg = ''
self.last_isnts_msg = ''
self.last_reg_msg = ''
##
self.test_test_index = 0
for item in re.split(';',endAddress):
self.end_trace_address.append(int(item,16)) # 结束 Trace 地址
def initEnv(self):
cur_pc = self.get_current_pc()
self.block_add_block_to_block_list(cur_pc)
for item in self.end_trace_address :
self.block_add_breakpoint(item) # 给结束地址下断点
def block_set_loop_flag(self,flag_value):
self.loop_flag = flag_value
def block_add_append_msg(self,msg):
self.append_msg = '{}[{}]'.format(self.append_msg,msg)
def block_clear_append_msg(self):
self.append_msg = ''
def block_delete_breakpoint(self,inst_addr):
if inst_addr in self.breakpoint_list :
index_value = self.breakpoint_list[inst_addr]['index']
delete_breakpoint:lldb.SBBreakpoint = self.breakpoint_list[inst_addr]['breakpoint']
if index_value > 1 :
self.breakpoint_list[inst_addr]['index'] = index_value -1
elif index_value == 1:
log_d('delete breakpoint at : {}'.format(hex(inst_addr)))
self.target.BreakpointDelete(delete_breakpoint.GetID())
self.breakpoint_list[inst_addr]['index'] = 0
self.breakpoint_list.pop(inst_addr)
else:
log_d('err : delete breakpoint with wrong index . < index : {} >'.format(index_value))
def block_add_breakpoint(self,inst_addr):
if inst_addr in self.breakpoint_list:
# index_value = self.breakpoint_list[inst_addr]['index']
# if index_value > 0 :
# print('increase breakpoint index at : {}'.format(hex(inst_addr)))
# self.breakpoint_list[inst_addr]['index'] = index_value + 1
# else:
# print('err : add breakpoint with wrong index. < index : {} >'.format(index_value))
log_d('breakpoint at {} had been exist.'.format(hex(inst_addr)))
else:
item = {}
breakpoint :lldb.SBBreakpoint = self.target.BreakpointCreateByAddress(inst_addr)
breakpoint.SetThreadID(self.thread.GetThreadID())
item['index'] = 1
item['breakpoint'] = breakpoint
self.breakpoint_list[inst_addr] = item
log_d('add breakpoint at : {}'.format(hex(inst_addr)))
def block_add_block_to_block_list(self,block_id):
if not (block_id in self.block_list) :
log_d('>>>>>> add block : {} >>> value : None.'.format(hex(block_id)))
self.block_list[block_id] = None
# 获得当前 pc
def get_current_pc(self):
now_frame :lldb.SBFrame = self.thread.GetSelectedFrame()
if now_frame:
return now_frame.GetPC()
return None
#
def block_update_current_ins(self):
frame : lldb.SBFrame = self.thread.GetSelectedFrame()
# symbol:lldb.SBSymbol = frame.GetSymbol()
# # 给 current_instruction_list 赋值
# # 获得 当前 symbol 下的 instructionlist
# insts : lldb.SBInstructionList = symbol.GetInstructions(self.target)
cur_pc = self.get_current_pc()
if not (cur_pc in self.current_instruction_list) :
# 清空一哈
self.current_instruction_list = {}
# 更新 self.current_instruction_list
target: lldb.SBTarget = self.debugger.GetSelectedTarget()
process: lldb.SBProcess = target.GetProcess()
thread: lldb.SBThread = process.GetSelectedThread()
frame: lldb.SBFrame = thread.GetSelectedFrame()
symbol :lldb.SBSymbol = frame.GetSymbol()
insts :lldb.SBInstructionList = symbol.GetInstructions(target)
# func : lldb.SBFunction = frame.GetFunction()
# insts : lldb.SBInstructionList = func.GetInstructions(self.target)
for inst in insts :
instAddr :lldb.SBAddress = inst.GetAddress()
addr = instAddr.GetLoadAddress(self.target)
if not (addr in self.current_instruction_list) :
self.current_instruction_list[addr] = inst
return cur_pc
# 判断当前 ins 是否在 trace 的结束列表中
def block_check_current_ins_in_end_tracing_address_list(self,curIns):
if curIns in self.end_trace_address :
return True
return False
def block_update_block_data(self,block_id,block_dic):
if block_id in self.block_list:
block_data = self.block_list[block_id]
if not block_data :
self.block_list[block_id] = block_dic
else :
log_d('>> block : {} had been update'.format(hex(block_id)))
else:
log_d('err : block id dont input to block list.')
def block_update_current_block(self):
# 需要在 bl 以及 jmp 目标地址,和条件jmp的下一条指令处下断点,以及 增加对应的 block 到 blockList 中
cur_pc = self.get_current_pc()
# print(self.current_instruction_list)
inst :lldb.SBInstruction = self.current_instruction_list[cur_pc]
if (cur_pc in self.block_list) and ( self.block_list[cur_pc]) :
self.block_set_loop_flag(True)
self.block_delete_breakpoint(cur_pc)
return self.block_list[cur_pc]
use_inst = inst
block_ins_list = {}
need_break = False
log_d('update block : {} insts :'.format(hex(cur_pc)))
while True :
mnemonic: str = use_inst.GetMnemonic(self.target)
inst_addr = use_inst.GetAddress().GetLoadAddress(self.target)
next_addr = inst_addr + use_inst.GetByteSize()
operands = use_inst.GetOperands(self.target)
flag = False
for item in CONST_DEVICE_info_list[DEVICE][CONST_INS_call] :
if mnemonic.startswith(item) :
flag = True
break
if flag :
self.block_add_breakpoint(inst_addr)
block_ins_list[inst_addr] = use_inst # 代码加入到 block_ins_list
if next_addr in self.current_instruction_list :
use_inst = self.current_instruction_list[next_addr] # 更新 use_inst
else :
break
continue
flag = False
for item in CONST_DEVICE_info_list[DEVICE][CONST_INS_jmp]:
if item == mnemonic :
flag = True
need_break = True
break
if flag :
self.block_add_block_to_block_list(int(operands,16)) # 添加block 到 block_list 中
self.block_add_breakpoint(int(operands,16))# 在 int(operands,16) 处下断点
if not need_break :
flag = False
for item in CONST_DEVICE_info_list[DEVICE][CONST_INS_condition_jmp] :
if mnemonic.startswith(item):
flag = True
need_break = True
break
if flag :
if int(operands,16) > inst_addr :
self.block_add_block_to_block_list(int(operands,16))
self.block_add_breakpoint(int(operands,16)) # 在 operands 下断点
self.block_add_block_to_block_list(next_addr)
self.block_add_breakpoint(next_addr) # 在 next_addr 下断点
block_ins_list[inst_addr] = use_inst # 代码加入到 block_ins_list
if need_break :
break
if next_addr in self.current_instruction_list :
use_inst = self.current_instruction_list[next_addr] # 更新 use_inst
else :
break
# self.block_list[cur_pc] = block_ins_list
# print('block : {} \n{}:'.format(hex(cur_pc),self.block_list[cur_pc]))
return block_ins_list
def block_at_bl(self,curIns):
ins:lldb.SBInstruction = self.current_instruction_list[curIns]
mnem:str = ins.GetMnemonic(self.target)
for item in CONST_DEVICE_info_list[DEVICE][CONST_INS_call]:
if mnem.startswith(item) :
return True
return False
def block_at_header(self,curIns):
if curIns in self.block_list :
return True
return False
##############################
def block_step_into(self):
self.thread.StepInstruction(False)
def block_get_data_about_function_and_symbol(self,curIns):
target: lldb.SBTarget = self.debugger.GetSelectedTarget()
process: lldb.SBProcess = target.GetProcess()
thread: lldb.SBThread = process.GetSelectedThread()
frame: lldb.SBFrame = thread.GetSelectedFrame()
symbol :lldb.SBSymbol = frame.GetSymbol()
func : lldb.SBFunction = frame.GetFunction()
# insts:lldb.SBInstructionList = func.GetInstructions(target)
# inst:lldb.SBInstruction = None
# block_delete_breakpoint
self.block_delete_breakpoint(curIns)
if func.IsValid():
return True,symbol.GetName()
return False,symbol.GetName()
def block_get_reg_msg(self):
reg_msg = ''
target: lldb.SBTarget = self.debugger.GetSelectedTarget()
process: lldb.SBProcess = target.GetProcess()
thread: lldb.SBThread = process.GetSelectedThread()
frame: lldb.SBFrame = thread.GetSelectedFrame()
registerSet :lldb.SBValueList = frame.GetRegisters()
regs:lldb.SBValue = registerSet.GetValueAtIndex(0)
for reg in regs :
if reg_msg == "" :
reg_msg = '{}:{}'.format(reg.name,reg.value)
else:
reg_msg = '{}|{}:{}'.format(reg_msg,reg.name,reg.value)
if reg.name == 'pc' :
break
return reg_msg
def block_get_current_insts_msg(self,block_id):
global ASLR
target: lldb.SBTarget = self.debugger.GetSelectedTarget()
isnts_msg = ''
if not self.loop_flag :
# isnts_msg = '0x12345 mov x0,1'
if block_id in self.block_list:
cur_block = self.block_list[block_id]
inst:lldb.SBInstruction = None
if cur_block :
for key,inst in cur_block.items():
inst_msg = '{: <5} {}'.format(inst.GetMnemonic(target),inst.GetOperands(target))
if isnts_msg == "" :
isnts_msg = '{: <10} {}'.format(hex(key - ASLR),inst_msg)
else:
isnts_msg = '{}\n\t{: <10} {}'.format(isnts_msg,hex(key - ASLR),inst_msg)
return isnts_msg
################################
# log 输出 格式
# block_id :
# {
# addr : inst
# ...
# }<函数名|函数名|..>[x0:value|x1:value|....]
# block_id :
# {}<函数名|函数名|..>[x0:value|x1:value|....]
#
# out_msg = "%s\n{\n\t%s\n}<%s>[%s]" % ('block id : 0x1233333','0x12345 mov x0,1','malloc|strlen','x0:0x1234|x1:0x222222')
def block_log_msg(self,block_id):
global ASLR
self.test_test_index = self.test_test_index + 1
block_msg = "{} =>> block id : {}".format(self.test_test_index,hex(block_id-ASLR))
isnts_msg = self.block_get_current_insts_msg(block_id)
reg_msg = self.block_get_reg_msg()
if not (self.last_block_msg == '' and self.last_isnts_msg == '' and self.last_reg_msg == '') :
out_msg = "%s\n{\n\t%s\n}<%s>[%s]" % (self.last_block_msg,self.last_isnts_msg,self.append_msg,self.last_reg_msg)
log_t(out_msg)
self.last_block_msg = block_msg
self.last_isnts_msg = isnts_msg
self.last_reg_msg = reg_msg
# 清空 append_msg
self.append_msg = ''
def block_log_end_msg(self):
if not (self.last_block_msg == '' and self.last_isnts_msg == '' and self.last_reg_msg == '') :
out_msg = "%s\n{\n\t%s\n}<%s>[%s]" % (self.last_block_msg,self.last_isnts_msg,self.append_msg,self.last_reg_msg)
log_t(out_msg)
self.last_block_msg = ''
self.last_isnts_msg = ''
self.last_reg_msg = ''
self.append_msg = ''
def block_get_symbol_name(self):
target: lldb.SBTarget = self.debugger.GetSelectedTarget()
process: lldb.SBProcess = target.GetProcess()
thread: lldb.SBThread = process.GetSelectedThread()
frame: lldb.SBFrame = thread.GetSelectedFrame()
symbol :lldb.SBSymbol = frame.GetSymbol()
return symbol.GetName()
def block_print_tracing_progress(self,count):
# 当前trace的总行数 内存地址:文件地址: <函数名>
global ASLR
file_addr = 0
cur_pc = self.get_current_pc()
if cur_pc == 0 :
log_c('{: <10} err .'.format(count))
else:
file_addr = cur_pc - ASLR
if cur_pc in self.current_instruction_list:
out_str = '{: <10} {} : {} <{}>'.format(count,hex(cur_pc),hex(file_addr),self.block_get_symbol_name())
log_c(out_str)
else:
out_str = '{: <10} {}'.format(count,hex(cur_pc))
log_c(out_str)
def block_get_block_id(self,block):
retaddr = 0
for addr in block.keys():
if retaddr == 0 :
retaddr = addr
else:
if retaddr > addr :
retaddr = addr
return retaddr
def block_print(self):
print('---> block_list <---')
for item in self.block_list:
print(hex(item))
print('---> breakpoint_list <---')
for item in self.breakpoint_list :
print(hex(item))
print('--------------------------')
def block_parser_options(command, result):
global options
command_tokens = shlex.split(command)
parser = TraceOptionParser(result)
parser.add_option("-e","--end-address",action="store",metavar="END_ADDRESS",dest="end_address",help="End addresses of trace,using to stop trace thread.More address,use ';' to split.")
parser.add_option("-l","--log-type",action="store",metavar="<trace/debug>",dest="log_type",default='trace',help="Set log type for this tracing. With trace type redirect trace output file. With debug type redirect trace and debug output files.Default is trace type.")
parser.add_option("-p","--print-tracing-progress",action="store_true",dest="print_tracing_progress",default=True,help="Print tracing progress in console.Default is True")
parser.add_option("-s","--suspend-threads-except-current-thread",action="store_true",dest="suspend_threads",default=True,help="Suspend threads except current thread,to clean env.Default is True")
(options, _) = parser.parse_args(command_tokens)
return parser.exited
def block_ini_log_file():
import time
global log_default_path,t_log_file_name,d_log_file_name
timeName = int(time.time())
if log_default_path.endswith('/'):
t_log_file_name = "{}{}{}".format(log_default_path,timeName,'blocktrace.log')
d_log_file_name = "{}{}{}".format(log_default_path,timeName,'blockdebug.log')
log_c('trace log file : {}'.format(t_log_file_name))
log_c('debug log file : {}'.format(d_log_file_name))
else:
t_log_file_name = "{}/{}{}".format(log_default_path,timeName,'blocktrace.log')
d_log_file_name = "{}/{}{}".format(log_default_path,timeName,'blockdebug.log')
log_c('trace log file : {}'.format(t_log_file_name))
log_c('debug log file : {}'.format(d_log_file_name))
def block_check_parser_command():
global options
global t_log_file,t_log_file_name,d_log_file,d_log_file_name
if options.end_address is None :
print('err : plz input an address where you want to end tracing.')
return False
log_type_arr = ['trace','debug']
if not options.log_type in log_type_arr :
print('err : plz input -l --log-type value, use "trace" or "debug".')
return False
if options.log_type == 'trace':
print(type(t_log_file_name))
print(t_log_file_name)
t_log_file = open(t_log_file_name,'w')
if options.log_type == 'debug':
t_log_file = open(t_log_file_name,'w')
d_log_file = open(d_log_file_name,'w')
return True
def test_block(debugger:lldb.SBDebugger):
return False
target: lldb.SBTarget = debugger.GetSelectedTarget()
process: lldb.SBProcess = target.GetProcess()
thread: lldb.SBThread = process.GetSelectedThread()
frame: lldb.SBFrame = thread.GetSelectedFrame()
symbol :lldb.SBSymbol = frame.GetSymbol()
func : lldb.SBFunction = frame.GetFunction()
# out_msg = "%s\n{\n\t%s\n}<%s>[%s]" % ('block id : 0x1233333','0x12345 mov x0,1','malloc|strlen','x0:0x1234|x1:0x222222')
# print(out_msg)
# registerSet :lldb.SBValueList = frame.GetRegisters()
# regs:lldb.SBValue = registerSet.GetValueAtIndex(0)
# print('num is : {}'.format(regs.GetNumChildren()))
# for reg in regs :
# print('{} : {}'.format(reg.name,reg.value))
# if reg.name == 'pc' :
# break
# print(symbol.GetInstructions(target))
# # symbol 可执行文件里有,链接库里有
# # func 可执行文件里有,但是 链接库里 没有
# if func.IsValid() :
# # insts:lldb.SBInstructionList = func.GetInstructions(target)
# # inst:lldb.SBInstruction = None
# # print('isnts : ')
# # print(insts)
# print('func : {}'.format(func))
# print('func name : {}'.format(func.GetName()))
# # print('symbol : {}'.format(symbol))
# # print('symbol DisplayName : {}'.format(symbol.GetDisplayName()))
# # print('symbol MangledName : {}'.format(symbol.GetMangledName()))
# print('symbol name : {}'.format(symbol.GetName()))
# for inst in insts :
# print('|{}|-----|{}|'.format(inst.GetMnemonic(target),inst.GetOperands(target)))
# pass
cur_block_ins_list = None # 直接更新
blockObj = WTBlock(target,thread,frame,debugger)
blockObj.initEnv()
cur_ins = blockObj.block_update_current_ins()
print('cur ins : {}'.format(hex(cur_ins)))
if not cur_block_ins_list :
cur_block_ins_list = blockObj.block_update_current_block()
# if not (cur_ins in cur_block_ins_list) :
# cur_block_ins_list = blockObj.block_update_current_block()
print('--> block_ins_list <---')
item : lldb.SBInstruction = None
for _,item in cur_block_ins_list.items() :
print('{} {} {}'.format(hex(item.GetAddress().GetLoadAddress(target)),item.GetMnemonic(target),item.GetOperands(target)))
blockObj.block_print()
def trace_block(debugger: lldb.SBDebugger, command: str, result: lldb.SBCommandReturnObject, internal_dict):
global options
if block_parser_options(command, result):
return
####################################################
########################测 试########################
####################################################
if test_block(debugger):
return
####################################################
block_ini_log_file()
if not block_check_parser_command():
return
wait_event = threading.Event()
wait_event.clear()
notify_event = threading.Event()
notify_event.clear()
target: lldb.SBTarget = debugger.GetSelectedTarget()
broadcaster: lldb.SBBroadcaster = target.GetBroadcaster()
print("Target: {}".format(str(target)))
process: lldb.SBProcess = target.GetProcess()
print("Process: {}".format(str(process)))
print("Broadcaster: {}".format(str(broadcaster)))
if options.suspend_threads :
suspend_threads_escape_select_thread(process,True)
listener = lldb.SBListener("trace breakpoint listener")
rc = broadcaster.AddListener(listener, lldb.SBProcess.eBroadcastBitStateChanged)
my_thread = WTListeningThread(wait_event, notify_event,listener, process)
my_thread.start()
thread: lldb.SBThread = process.GetSelectedThread()
print("Thread: {}".format(str(thread)))
frame: lldb.SBFrame = thread.GetSelectedFrame()
module: lldb.SBModule = frame.GetModule()
if frame.GetFrameID() == 0xFFFFFFFF:
print("Invalid frame, has your process started?")
return
blockObj = WTBlock(target,thread,frame,debugger,endAddress=options.end_address)
blockObj.initEnv()
cur_block = None # 直接更新
blockCount = 0
while True :
# 打印进度
if options.print_tracing_progress :
if blockCount % num_for_print_progress == 0 and blockCount > 0:
blockObj.block_print_tracing_progress(blockCount)
blockCount = blockCount + 1
log_d("=================== Stopped at: ====================")
log_d("Frame: {}, symbol: {}, pc: {pc:#x}".format(str(frame), str(frame.GetSymbol()), pc=frame.GetPC()))
cur_ins = blockObj.block_update_current_ins()
if blockObj.block_check_current_ins_in_end_tracing_address_list(cur_ins):
print('end tracing....... at : {}'.format(hex(cur_ins)))
blockObj.block_log_end_msg()
log_d('end tracing....... at : {}'.format(hex(cur_ins)))
# blockObj.block_print()
break
if (not cur_block ) or not (cur_ins in cur_block):
cur_block = blockObj.block_update_current_block() # 需要在 bl 以及 jmp 目标地址,和条件jmp的下一条指令处下断点,以及 增加对应的 block 到 blockList 中
blockObj.block_update_block_data(cur_ins,cur_block)
at_bl_flag = blockObj.block_at_bl(cur_ins)
at_header_flag = blockObj.block_at_header(cur_ins)
if at_bl_flag and at_header_flag :
# 当前指令 是 bl 而且是 block 头
# 输出 信息
blockObj.block_log_msg(cur_ins)
blockObj.block_set_loop_flag(False)
# 单步进入,然后获得 symble name 和 function name
blockObj.block_step_into()
_,symbol_name = blockObj.block_get_data_about_function_and_symbol(cur_ins)
blockObj.block_add_append_msg('') # blockObj.block_add_append_msg(msg) # 把信息 加入 到
elif at_bl_flag and (not at_header_flag):
# 当前指令 仅仅是 bl
# 单步进入,然后获得 symble name 和 function name
blockObj.block_step_into()
_,symbol_name = blockObj.block_get_data_about_function_and_symbol(cur_ins)
blockObj.block_add_append_msg(symbol_name) # blockObj.block_add_append_msg(msg) # 把信息 加入 到
elif at_header_flag and (not at_bl_flag):
# 当前指令 仅仅是 block 头,在进来的时候,已经搞定
# 输出 信息
blockObj.block_log_msg(cur_ins)
blockObj.block_set_loop_flag(False)
else:
log_d('err : ins out of control.')
print('err : ins out of control.')
break
# 10分钟 刷新一次缓存,把缓存 写入到 block list 文件中 xxxxx_block_list.txt
# 清空 blockObj.block_list
continue_and_wait_for_breakpoint(process,thread,my_thread,wait_event,notify_event)
if options.suspend_threads :
suspend_threads_escape_select_thread(process,False)
my_thread.exit()
wait_event.set()
my_thread.join()
broadcaster.RemoveListener(listener)
print('Listener thread exited completing')
log_flush()
def init_ASLR(debugger:lldb.SBDebugger):
global ASLR
interpreter:lldb.SBCommandInterpreter = debugger.GetCommandInterpreter()
returnObject = lldb.SBCommandReturnObject()
interpreter.HandleCommand('image list -o', returnObject)
output = returnObject.GetOutput()
match = re.match(r'.+(0x[0-9a-fA-F]+)', output)
if match:
ASLRHexStr:str = match.group(1)
ASLR = int(ASLRHexStr,16)
print('ALSR : {}'.format(ASLRHexStr))
return ASLRHexStr
else:
ASLR = ''
print('err : ALSR is None')
return None
def setDefaultPath(debugger: lldb.SBDebugger, command: str, result: lldb.SBCommandReturnObject, internal_dict):
global log_default_path
log_default_path = command
# 还需要判断这个 路径存在否
print(command)
def defaultPath(debugger: lldb.SBDebugger, command: str, result: lldb.SBCommandReturnObject, internal_dict):
global log_default_path
print(log_default_path)
def __lldb_init_module(debugger:lldb.SBDebugger, internal_dict):
global log_default_path
init_ASLR(debugger)
log_default_path = os.path.abspath(os.path.dirname(os.path.abspath(__file__)) + os.path.sep + ".")
debugger.HandleCommand('command script add -f lldbTrace.trace trace')
debugger.HandleCommand('command script add -f lldbTrace.setDefaultPath setlogpath')
debugger.HandleCommand('command script add -f lldbTrace.defaultPath logpath')
print('WT::The "trace" python command has been installed and is ready for use.')
print('WT::Default path =>>>> {}'.format(log_default_path))
print(' use : logpath command to look up logfile default path.')
print(' use : setlogpath <PATH> command to reset logfile default path.')
debugger.HandleCommand('command script add -f lldbTrace.trace_block trace_b')
print('WT::The "trace_b" python command has been installed and is ready for use.')
================================================
FILE: main.mm
================================================
//
// main.m
// checkDemo
//
// Created by wt on 2021/4/21.
//
#import <Foundation/Foundation.h>
#import <CommonCrypto/CommonCrypto.h>
#import <CommonCrypto/CommonCryptor.h>
#import <CoreLocation/CoreLocation.h>
#include <sys/stat.h>
#import <objc/runtime.h>
#import <Foundation/NSObject.h>
#import "WTAes.hpp"
int test(int a,int b,int c){
int tmp = 2 * c;
return a + b + tmp;
}
int test_fun(){
NSString * a = @"{\"b1\":\"\",\"b2\":1,\"b3\":\"AAAAAAAAAAAAAMnu601KCPF0Mj3cObiE77iT8YWCbhK1vSgWHJ3uNlYTdmODBjMGMyZGMn-JGVHeeVP_WmIdd2TFi6Si0TpSJ8_Q\",\"b4\":\"\",\"b5\":1,\"b6\":{\"c1\":\"com.meituan.imeituan\",\"c2\":\"56226DD0E7DEB85C417DD793041E5CC9\",\"c3\":\"11.7.202\",\"c4\":117202,\"c5\":-2}}";
NSLog(@"%ld",[a length]);
unsigned char arr[] = {
0xc2,0x55,0xe9,0x74,0xb0,0xd6,0x39,0xb2,
0xf3,0x0e,0x85,0x98,0x6b,0xd0,0xb8,0xc9,
0x35,0x50,0x56,0xe0,0xef,0xe7,0x1d,0x2c,
0x5a,0x0e,0x76,0x76,0xd8,0x6f,0xda,0xee,
0xf5,0xfe,0x78,0x0f,0x08,0x3d,0x47,0xe2,
0x51,0xf3,0xc1,0x75,0xf5,0xf1,0x40,0x10,
0x74,0xd6,0x62,0x5e,0xe7,0x51,0xce,0xd7,
0x8b,0x4d,0x66,0x95,0x34,0x33,0xda,0x3b,
0x0f,0xe7,0x55,0x27,0x5b,0xe8,0x11,0x2c,
0xcd,0xc5,0xfa,0x76,0x97,0x8c,0x4c,0xcc,
0x33,0x1e,0xe5,0xf2,0x5e,0xba,0xca,0xae,
0x6c,0x32,0x21,0x18,0x1e,0x5e,0x32,0x69,
0x00,0x3c,0xfa,0x14,0xea,0x62,0xed,0x81,
0x59,0xad,0x70,0x7b,0x56,0xa7,0x1d,0x40,
0x44,0x23,0x69,0x3e,0xda,0x14,0xb8,0x42,
0x67,0x9f,0xc7,0x07,0xe4,0x92,0xd3,0xff,
0x5b,0x6d,0x0d,0xd6,0x3c,0x0d,0xcb,0x33,
0x95,0x4f,0x8c,0xbe,0xd1,0xbf,0x87,0x8e,
0x24,0x03,0x8b,0xc4,0xfa,0xfd,0x25,0x7d,
0xe9,0x40,0xda,0xe8,0xc0,0xf4,0xd5,0x12,
0x6f,0xf0,0x3d,0x3e,0xca,0x96,0x63,0x72,
0x9d,0x2c,0x72,0xbb,0xef,0x73,0xac,0xaa,
0xfd,0xd1,0x4c,0x2d,0x38,0x9c,0xd2,0x19,
0x54,0x43,0x1b,0xd5,0x9d,0xa5,0x15,0x7d,
0xf2,0x27,0x7a,0x1d,0xee,0x91,0xfc,0xf2,
0xca,0x9b,0xee,0x14,0x5c,0xe5,0x6d,0x5c,
0x31,0xe6,0x47,0x45,0xf2,0x68,0xb8,0x32,
0x85,0x08,0x68,0x4e,0x57,0x80,0x82,0xc9,
0x8f,0xe2,0x7c,0xff,0x79,0xd6,0xc7,0xba,
0x68,0xf7,0x9a,0x13,0xbf,0x99,0x01,0xe8,
0x98,0x7a,0xd6,0xab,0xb8,0xae,0x0c,0x3f,
0xe7,0xb0};
NSData * data = [[NSData alloc] initWithBytes:arr length:0xfd];
NSData *base64Data = [data base64EncodedDataWithOptions:0];
NSString *base64 = [[NSString alloc] initWithData:base64Data encoding:NSUTF8StringEncoding];
NSLog(@"%@",base64);
int value = test(2, 3, 5);
NSString * str = [NSString stringWithFormat:@"%d",value];
[str stringByAppendingString:@"abc"];
// @"wlXpdLDWObLzDoWYa9C4yTVQVuDv5x0sWg52dthv2u71/ngPCD1H4lHzwXX18UAQdNZiXudRzteLTWaVNDPaOw/nVSdb6BEszcX6dpeMTMwzHuXyXrrKrmwyIRgeXjJpADz6FOpi7YFZrXB7VqcdQEQjaT7aFLhCZ5/HB+SS0/9bbQ3WPA3LM5VPjL7Rv4eOJAOLxPr9JX3pQNrowPTVEm/wPT7KlmNynSxyu+9zrKr90UwtOJzSGVRDG9WdpRV98id6He6R/PLKm+4UXOVtXDHmR0XyaLgyhQhoTleAgsmP4nz/edbHumj3mhO/mQHomHrWq7iuDD/nsA==";
// @"wlXpdLDWObLzDoWYa9C4yTVQVuDv5x0sWg52dthv2u71/ngPCD1H4lHzwXX18UAQdNZiXudRzteLTWaVNDPaOw/nVSdb6BEszcX6dpeMTMwzHuXyXrrKrmwyIRgeXjJpADz6FOpi7YFZrXB7VqcdQEQjaT7aFLhCZ5/HB+SS0/9bbQ3WPA3LM5VPjL7Rv4eOJAOLxPr9JX3pQNrowPTVEm/wPT7KlmNynSxyu+9zrKr90UwtOJzSGVRDG9WdpRV98id6He6R/PLKm+4UXOVtXDHmR0XyaLgyhQhoTleAgsmP4nz/edbHumj3mhO/mQHomHrWq7iuDD/nsCgAMA==";
// wlXpdLDWObLzDoWYa9C4yTVQVuDv5x0sWg52dthv2u71/ngPCD1H4lHzwXX18UAQdNZiXudRzteLTWaVNDPaOw/nVSdb6BEszcX6dpeMTMwzHuXyXrrKrmwyIRgeXjJpADz6FOpi7YFZrXB7VqcdQEQjaT7aFLhCZ5/HB+SS0/9bbQ3WPA3LM5VPjL7Rv4eOJAOLxPr9JX3pQNrowPTVEm/wPT7KlmNynSxyu+9zrKr90UwtOJzSGVRDG9WdpRV98id6He6R/PLKm+4UXOVtXDHmR0XyaLgyhQhoTleAgsmP4nz/edbHumj3mhO/mQHomHrWq7iuDD/nsA==
// struct stat a;
// const char * path = '/Users/wt/pro';
// stat(path, &a);
// int abc = sizeof(a);
//
// CLAuthorizationStatus status = [CLLocationManager authorizationStatus];
// NSLog(@"%f",[[NSDate date]timeIntervalSince1970]);
//
//
// [NSKeyedUnarchiver unarchiveObjectWithData:nil];
//
// CCCrypt(kCCDecrypt, kCCAlgorithmAES128, kCCOptionPKCS7Padding|kCCOptionECBMode,)
return 0;
}
void test_aes(){
AES aes;
byte enc[16];
byte buf[16]="this is a test";
byte ret[16];
aes.encrypt(buf,enc);
aes.decrypt(enc,ret);
printf("%s",ret);
}
void test_folly()
{
}
void b(void)
{
usleep(200 * 1000);
}
void a(void)
{
for(int i=0; i<3; i++)
{
b();
}
NSString * sour = @"abc";
NSString * str = [[NSString alloc] initWithString:sour];
printf("Cycle\n");
NSLog(@"%@",str);
}
void c(int i);
void d(int i)
{
c(i-1);
}
void c(int i)
{
if (i > 0) {
d(i);
}
}
void breakpoint(void)
{
a();
c(1);
}
int test()
{
while(true) {
breakpoint();
}
return 0;
}
int main(int argc, const char * argv[]) {
sleep(1);
test();
// test_fun();
// test_aes();
return 0;
}
================================================
FILE: tools/verifyAlgorithm/test.py
================================================
#!/usr/bin/python3
# -*- encoding: utf-8 -*-
#@File : test.py
#@Time : 2021/07/29 15:15:38
#@Author : wt
from wtpytracer import *
####################
## command :
## python3 test.py ~/Desktop/1627533881instrace.log
## 定义需要检测的 变量 : flag + '_' + 地址 + '_' + 寄存器
Check_0x10000393c_w8 = 'Check_0x10000393c_w8'
### 翻译的测试代码
def f(x):
ret = 0
for index in range(x):
ret = ret + index
check_value(ret,Check_0x10000393c_w8) # check ret 和 0x10000393c 的 w8 的寄存器值
return ret + x
if __name__ == '__main__':
import sys
args_list = sys.argv
if len(args_list) != 2 :
exit()
file_name = args_list[1]
try:
set_trace_data(Check_0x10000393c_w8)
parser_trace_log_file(file_name)
enable(CheckFunctionTracer())
f(5)
finally:
disable()
================================================
FILE: tools/verifyAlgorithm/wtpytracer.py
================================================
#!/usr/bin/python3
# -*- encoding: utf-8 -*-
#@File : wtpytracer.py
#@Time : 2021/07/27 18:17:18
#@Author : wt
import re
import sys
import inspect
from collections import OrderedDict
class TracebackFancy:
def __init__(self, traceback):
self.t = traceback
def getFrame(self):
return FrameFancy(self.t.tb_frame)
def getLineNumber(self):
return self.t.tb_lineno if self.t is not None else None
def getNext(self):
return TracebackFancy(self.t.tb_next)
def __str__(self):
if self.t is None:
return ""
str_self = "%s @ %s" % (
self.getFrame().getName(), self.getLineNumber())
return str_self + "\n" + self.getNext().__str__()
class ExceptionFancy:
def __init__(self, frame):
self.etraceback = frame.f_exc_traceback
self.etype = frame.exc_type
self.evalue = frame.f_exc_value
def __init__(self, tb, ty, va):
self.etraceback = tb
self.etype = ty
self.evalue = va
def getTraceback(self):
return TracebackFancy(self.etraceback)
def __nonzero__(self):
return self.etraceback is not None or self.etype is not None or self.evalue is not None
def getType(self):
return str(self.etype)
def getValue(self):
return self.evalue
class CodeFancy:
def __init__(self, code):
self.c = code
def getArgCount(self):
return self.c.co_argcount if self.c is not None else 0
def getFilename(self):
return self.c.co_filename if self.c is not None else ""
def getVariables(self):
return self.c.co_varnames if self.c is not None else []
def getName(self):
return self.c.co_name if self.c is not None else ""
def getFileName(self):
return self.c.co_filename if self.c is not None else ""
class ArgsFancy:
def __init__(self, frame, arginfo):
self.f = frame
self.a = arginfo
def __str__(self):
args, varargs, kwargs = self.getArgs(), self.getVarArgs(), self.getKWArgs()
ret = ""
count = 0
size = len(args)
for arg in args:
ret = ret + ("%s = %s" % (arg, args[arg]))
count = count + 1
if count < size:
ret = ret + ", "
if varargs:
if size > 0:
ret = ret + " "
ret = ret + "varargs are " + str(varargs)
if kwargs:
if size > 0:
ret = ret + " "
ret = ret + "kwargs are " + str(kwargs)
return ret
def getNumArgs(wantVarargs=False, wantKWArgs=False):
args, varargs, keywords, values = self.a
size = len(args)
if varargs and wantVarargs:
size = size + len(self.getVarArgs())
if keywords and wantKWArgs:
size = size + len(self.getKWArgs())
return size
def getArgs(self):
args, _, _, values = self.a
argWValues = OrderedDict()
for arg in args:
argWValues[arg] = values[arg]
return argWValues
def getVarArgs(self):
_, vargs, _, _ = self.a
if vargs:
return self.f.f_locals[vargs]
return ()
def getKWArgs(self):
_, _, kwargs, _ = self.a
if kwargs:
return self.f.f_locals[kwargs]
return {}
class FrameFancy:
def __init__(self, frame):
self.f = frame
def getCaller(self):
return FrameFancy(self.f.f_back)
def getLineNumber(self):
return self.f.f_lineno if self.f is not None else 0
def getCodeInformation(self):
return CodeFancy(self.f.f_code) if self.f is not None else None
def getExceptionInfo(self):
return ExceptionFancy(self.f) if self.f is not None else None
def getName(self):
return self.getCodeInformation().getName() if self.f is not None else ""
def getFileName(self):
return self.getCodeInformation().getFileName() if self.f is not None else ""
def getLocals(self):
return self.f.f_locals if self.f is not None else {}
def getArgumentInfo(self):
return ArgsFancy(
self.f, inspect.getargvalues(
self.f)) if self.f is not None else None
class TracerClass:
def callEvent(self, frame):
pass
def lineEvent(self, frame):
pass
def returnEvent(self, frame, retval):
pass
def exceptionEvent(self, frame, exception, value, traceback):
pass
def cCallEvent(self, frame, cfunct):
pass
def cReturnEvent(self, frame, cfunct):
pass
def cExceptionEvent(self, frame, cfunct):
pass
tracer_impl = TracerClass()
data_dic = {}
old_trace_func = None
def parser_flag(flag):
import re
aa = re.split(r'_',flag)
if len(aa) != 3 :
return None,None
return aa[1],aa[2]
class CheckFunctionTracer():
def callEvent(self, frame):
if 'check_value' == frame.getName():
flag = frame.getArgumentInfo().getArgs()['check_flag']
value = frame.getArgumentInfo().getArgs()['value']
addr,register = parser_flag(flag)
if addr in data_dic and register in data_dic[addr]:
run_index = data_dic[addr][register]['run_index']
data_len = len(data_dic[addr][register]['data'])
if run_index >= data_len:
print('*** err : at address : {} . run_index : {} out of rang'.format(addr,run_index))
return
if value == data_dic[addr][register]['data']['{}'.format(run_index + 1)] :
print('check : {} at {} times,match.'.format(addr,run_index + 1))
data_dic[addr][register]['run_index'] = run_index + 1
# print("->>LoggingTracer : call " + frame.getName() + " from " + frame.getCaller().getName() + " @ " + str(frame.getCaller().getLineNumber()) + " args are " + str(frame.getArgumentInfo()))
# @ check_flag 为 携带了地址,和寄存器名称
# @ value 为当前需要 check 的值
# 在 sys.settracer设置的回调中,只接管此函数
def check_value(value,check_flag):
pass
def set_trace_data(check_flag):
global data_dic
addr,register = parser_flag(check_flag)
if not addr or not register :
print('err : check_flag is wrong.')
return
if addr in data_dic:
data_dic[addr][register] = {
'data':{},
'run_index':0
}
else:
addr_dic = {
register:{
'data':{},
'run_index':0
}
}
data_dic[addr] = addr_dic
def add_data_in_data_dic(addr,register,value):
global data_dic
cur_reg_dic = data_dic[addr][register]
data_len = len(cur_reg_dic['data'])
data_dic[addr][register]['data']['{}'.format(data_len + 1)] = value
def parser_trace_log_file(fileName):
global data_dic
file = open(fileName)
while True:
lines = file.readlines(100000)
if not lines:
break
for line in lines:
matchObj = re.match(r'\s*(\S+)\s+',line,re.M|re.I)
if matchObj:
addr = str(matchObj.group()).replace(' ','')
if addr in data_dic:
reg = data_dic[addr]
for register in data_dic[addr].keys():
register_out = re.findall(register +r' : (\S+)',line)
if register_out:
register_value = int(register_out[0],16)
add_data_in_data_dic(addr,register,register_value)
file.close()
# {'1234':{'1':0,"2":1}} # flag : {...} address:{'x0':{data:{},run_index:0},'x1':{data:{},run_index:0}}
def the_tracer_check_data(frame, event, args = None):
global data_dic
global tracer_impl
code = frame.f_code
func_name = code.co_name
line_no = frame.f_lineno
if tracer_impl is None:
print('@@@ tracer_impl : None.')
return None
if event == 'call':
tracer_impl.callEvent(FrameFancy(frame))
return the_tracer_check_data
def enable(tracer_implementation=None):
global tracer_impl,old_trace_func
if tracer_implementation:
tracer_impl = tracer_implementation # 传递 工厂实力的对象
old_trace_func = sys.gettrace()
sys.settrace(the_tracer_check_data) # 注册回调到系统中
def check_run_ok():
global data_dic
for addr,addr_dic in data_dic.items():
for _,reg_dic in addr_dic.items():
if reg_dic['run_index'] == len(reg_dic['data']):
print('->>> at {} check value is perfect.'.format(addr))
else:
print('*** err : at {} check {} times.'.format(addr,reg_dic['run_index']))
def disable():
check_run_ok()
global old_trace_func
sys.settrace(old_trace_func)
gitextract_o893_d24/
├── .gitignore
├── README.md
├── lldbTrace.py
├── main.mm
└── tools/
└── verifyAlgorithm/
├── checkDemo
├── test.py
└── wtpytracer.py
SYMBOL INDEX (152 symbols across 3 files)
FILE: lldbTrace.py
function log_d (line 29) | def log_d(msg): # debug log
function log_t (line 35) | def log_t(msg): # trace log
function log_c (line 40) | def log_c(msg): # console log
function log_flush (line 45) | def log_flush():
function dlog (line 52) | def dlog(msg):
class WTListeningThread (line 123) | class WTListeningThread(threading.Thread):
method __init__ (line 124) | def __init__(self, wait_event, notify_event,listener,process):
method wait_timed_out (line 133) | def wait_timed_out(self):
method exit (line 136) | def exit(self):
method run (line 139) | def run(self):
function get_c_char_star (line 169) | def get_c_char_star(address):
function handle_command (line 182) | def handle_command(command,debugger:lldb.SBDebugger):
function continue_and_wait_for_breakpoint (line 194) | def continue_and_wait_for_breakpoint(process, thread, listening_thread, ...
function suspend_threads_escape_select_thread (line 210) | def suspend_threads_escape_select_thread(process:lldb.SBProcess,flag:bool):
function match_registers (line 226) | def match_registers(text):
class WTInstruction (line 242) | class WTInstruction():
method __init__ (line 243) | def __init__(self, target, thread, frame,debugger,traceType=TRACE_TYPE...
method increase_print_index (line 274) | def increase_print_index(self):
method check_in_call_return_instruction_list (line 279) | def check_in_call_return_instruction_list(self):
method decrease_print_index (line 287) | def decrease_print_index(self):
method check_str_in_arr (line 291) | def check_str_in_arr(self,cur_str:str,cur_arr):
method init_env (line 297) | def init_env(self):
method get_current_pc (line 329) | def get_current_pc(self):
method checkPCInList_transferCurrentSymbolInstrucionsToList (line 337) | def checkPCInList_transferCurrentSymbolInstrucionsToList(self,address):
method updata_instruction_instructionList (line 370) | def updata_instruction_instructionList(self):
method clean_env (line 380) | def clean_env(self):
method deal_with (line 387) | def deal_with(self):
method updata_last_instruction (line 390) | def updata_last_instruction(self):
method get_current_symbol_name (line 393) | def get_current_symbol_name(self):
method get_next_instruction (line 398) | def get_next_instruction(self):
method print_tracing_progress (line 408) | def print_tracing_progress(self,count):
method log_current_instruction (line 420) | def log_current_instruction(self,cur_pc):
method parser_ins_symbol_name (line 448) | def parser_ins_symbol_name(self,last_symbole_name:str,cur_symbol_name ...
method add_next_breakpoint (line 489) | def add_next_breakpoint(self):
method add_call_return_addr (line 505) | def add_call_return_addr(self):
method sub_call_return_addr (line 514) | def sub_call_return_addr(self):
method check_need_delete_breakpoint_in_current_call_return_list_and_decrease_index (line 525) | def check_need_delete_breakpoint_in_current_call_return_list_and_decre...
method delete_current_breakpoint (line 535) | def delete_current_breakpoint(self):
method check_currentIns_is_endIns (line 559) | def check_currentIns_is_endIns(self):
method check_ins_call (line 580) | def check_ins_call(self,mnemonic:str,cur_symbol:lldb.SBSymbol):
method check_ins_jmp (line 615) | def check_ins_jmp(self,mnemonic:str,cur_symbol:lldb.SBSymbol):
method check_ins_syscall (line 647) | def check_ins_syscall(self,mnemonic:str,cur_symbol:lldb.SBSymbol):
method check_ins_other (line 665) | def check_ins_other(self,cur_symbol:lldb.SBSymbol):
method check_out_tracing (line 673) | def check_out_tracing(self):
method check_end_fun (line 685) | def check_end_fun(self):
method check_symbol_valid (line 715) | def check_symbol_valid(self):
method check_in_module (line 725) | def check_in_module(self):
method deal_with_ins (line 735) | def deal_with_ins(self):
class WTFunction (line 797) | class WTFunction():
method __init__ (line 798) | def __init__(self, *args):
method deal_with_fun (line 800) | def deal_with_fun(self):
class TraceOptionParser (line 804) | class TraceOptionParser(optparse.OptionParser):
method __init__ (line 805) | def __init__(self, result):
method get_prog_name (line 810) | def get_prog_name(self):
method exit (line 813) | def exit(self, status=0, msg=None):
function parse_options (line 819) | def parse_options(command, result):
function check_parser_command (line 834) | def check_parser_command():
function ini_log_file (line 866) | def ini_log_file(mode_name:str):
function test (line 898) | def test(debugger:lldb.SBDebugger):
function trace (line 950) | def trace(debugger: lldb.SBDebugger, command: str, result: lldb.SBComman...
class WTBlock (line 1058) | class WTBlock():
method __init__ (line 1059) | def __init__(self, target, thread, frame,debugger,endAddress=None):
method initEnv (line 1092) | def initEnv(self):
method block_set_loop_flag (line 1098) | def block_set_loop_flag(self,flag_value):
method block_add_append_msg (line 1101) | def block_add_append_msg(self,msg):
method block_clear_append_msg (line 1105) | def block_clear_append_msg(self):
method block_delete_breakpoint (line 1108) | def block_delete_breakpoint(self,inst_addr):
method block_add_breakpoint (line 1122) | def block_add_breakpoint(self,inst_addr):
method block_add_block_to_block_list (line 1139) | def block_add_block_to_block_list(self,block_id):
method get_current_pc (line 1145) | def get_current_pc(self):
method block_update_current_ins (line 1151) | def block_update_current_ins(self):
method block_check_current_ins_in_end_tracing_address_list (line 1183) | def block_check_current_ins_in_end_tracing_address_list(self,curIns):
method block_update_block_data (line 1188) | def block_update_block_data(self,block_id,block_dic):
method block_update_current_block (line 1198) | def block_update_current_block(self):
method block_at_bl (line 1274) | def block_at_bl(self,curIns):
method block_at_header (line 1282) | def block_at_header(self,curIns):
method block_step_into (line 1288) | def block_step_into(self):
method block_get_data_about_function_and_symbol (line 1291) | def block_get_data_about_function_and_symbol(self,curIns):
method block_get_reg_msg (line 1309) | def block_get_reg_msg(self):
method block_get_current_insts_msg (line 1329) | def block_get_current_insts_msg(self,block_id):
method block_log_msg (line 1359) | def block_log_msg(self,block_id):
method block_log_end_msg (line 1378) | def block_log_end_msg(self):
method block_get_symbol_name (line 1390) | def block_get_symbol_name(self):
method block_print_tracing_progress (line 1399) | def block_print_tracing_progress(self,count):
method block_get_block_id (line 1415) | def block_get_block_id(self,block):
method block_print (line 1427) | def block_print(self):
function block_parser_options (line 1441) | def block_parser_options(command, result):
function block_ini_log_file (line 1455) | def block_ini_log_file():
function block_check_parser_command (line 1473) | def block_check_parser_command():
function test_block (line 1498) | def test_block(debugger:lldb.SBDebugger):
function trace_block (line 1558) | def trace_block(debugger: lldb.SBDebugger, command: str, result: lldb.SB...
function init_ASLR (line 1678) | def init_ASLR(debugger:lldb.SBDebugger):
function setDefaultPath (line 1695) | def setDefaultPath(debugger: lldb.SBDebugger, command: str, result: lldb...
function defaultPath (line 1701) | def defaultPath(debugger: lldb.SBDebugger, command: str, result: lldb.SB...
function __lldb_init_module (line 1705) | def __lldb_init_module(debugger:lldb.SBDebugger, internal_dict):
FILE: tools/verifyAlgorithm/test.py
function f (line 18) | def f(x):
FILE: tools/verifyAlgorithm/wtpytracer.py
class TracebackFancy (line 12) | class TracebackFancy:
method __init__ (line 14) | def __init__(self, traceback):
method getFrame (line 17) | def getFrame(self):
method getLineNumber (line 20) | def getLineNumber(self):
method getNext (line 23) | def getNext(self):
method __str__ (line 26) | def __str__(self):
class ExceptionFancy (line 34) | class ExceptionFancy:
method __init__ (line 36) | def __init__(self, frame):
method __init__ (line 41) | def __init__(self, tb, ty, va):
method getTraceback (line 46) | def getTraceback(self):
method __nonzero__ (line 49) | def __nonzero__(self):
method getType (line 52) | def getType(self):
method getValue (line 55) | def getValue(self):
class CodeFancy (line 59) | class CodeFancy:
method __init__ (line 61) | def __init__(self, code):
method getArgCount (line 64) | def getArgCount(self):
method getFilename (line 67) | def getFilename(self):
method getVariables (line 70) | def getVariables(self):
method getName (line 73) | def getName(self):
method getFileName (line 76) | def getFileName(self):
class ArgsFancy (line 80) | class ArgsFancy:
method __init__ (line 82) | def __init__(self, frame, arginfo):
method __str__ (line 86) | def __str__(self):
method getNumArgs (line 106) | def getNumArgs(wantVarargs=False, wantKWArgs=False):
method getArgs (line 115) | def getArgs(self):
method getVarArgs (line 122) | def getVarArgs(self):
method getKWArgs (line 128) | def getKWArgs(self):
class FrameFancy (line 134) | class FrameFancy:
method __init__ (line 136) | def __init__(self, frame):
method getCaller (line 139) | def getCaller(self):
method getLineNumber (line 142) | def getLineNumber(self):
method getCodeInformation (line 145) | def getCodeInformation(self):
method getExceptionInfo (line 148) | def getExceptionInfo(self):
method getName (line 151) | def getName(self):
method getFileName (line 154) | def getFileName(self):
method getLocals (line 157) | def getLocals(self):
method getArgumentInfo (line 160) | def getArgumentInfo(self):
class TracerClass (line 165) | class TracerClass:
method callEvent (line 167) | def callEvent(self, frame):
method lineEvent (line 170) | def lineEvent(self, frame):
method returnEvent (line 173) | def returnEvent(self, frame, retval):
method exceptionEvent (line 176) | def exceptionEvent(self, frame, exception, value, traceback):
method cCallEvent (line 179) | def cCallEvent(self, frame, cfunct):
method cReturnEvent (line 182) | def cReturnEvent(self, frame, cfunct):
method cExceptionEvent (line 185) | def cExceptionEvent(self, frame, cfunct):
function parser_flag (line 192) | def parser_flag(flag):
class CheckFunctionTracer (line 199) | class CheckFunctionTracer():
method callEvent (line 200) | def callEvent(self, frame):
function check_value (line 222) | def check_value(value,check_flag):
function set_trace_data (line 226) | def set_trace_data(check_flag):
function add_data_in_data_dic (line 248) | def add_data_in_data_dic(addr,register,value):
function parser_trace_log_file (line 254) | def parser_trace_log_file(fileName):
function the_tracer_check_data (line 277) | def the_tracer_check_data(frame, event, args = None):
function enable (line 297) | def enable(tracer_implementation=None):
function check_run_ok (line 305) | def check_run_ok():
function disable (line 314) | def disable():
Condensed preview — 7 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (91K chars).
[
{
"path": ".gitignore",
"chars": 1799,
"preview": "# Byte-compiled / optimized / DLL files\n__pycache__/\n*.py[cod]\n*$py.class\n\n# C extensions\n*.so\n\n# Distribution / packagi"
},
{
"path": "README.md",
"chars": 589,
"preview": "# lldbTrace\n\n##### How to use it?\n\n> 1.*Break at an address where you want to begin tracing.*\n>\n> 
About this extraction
This page contains the full source code of the yangyss/lldb-trace GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 7 files (84.5 KB), approximately 21.7k tokens, and a symbol index with 152 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.