对jtag调试器进行逆向工程,分析mcu的jtag协议,这是个巨大的工程,方法不对,根本做不出来。但是借助逻辑分析仪进行数据采集,用python进行数据处理,直接生产程序代码,看起来能很容易的取得调试器的协议。
msp430的jtag,官方只开源了烧写flash部分的源码和协议,至于单步调试,读写寄存器,断点设置等,都没有公开,只有几家商业公司掌握着,msp430开源社区里没这方面的任何进展。因此,我下定决心对fet430uif进行“逆向工程",完成arm板的jtag调试器,实现对msp430的gdb调试。
msp430的jtag使用的是4pin的jtag接口,TCK,TMS,TDI, TDO。使用agient logic analyzer采集jta个的时序,分别多次采集mspdebug的基本命令:读寄存器,写寄存器,单步,断点设置,运行,运行到断点等。
把采集到的数据保存好,再选着list数据(并非waveform数据)导出成cvs格式的数据格式,方便python读取分析。采集到的jtag数据量非常大,50ns的采样间隔,500ms就有160mb的数据。
msp430的jtag的基本操作只有shiftIR,shiftDR8,shiftDR16等几个,不多,用python写一个状态机,即可对这些数据进行处理。使用python对数据进行初步处理生成对应的jtag基本操作,生成一个只有几十kb的txt文本。
从采集的时序数据中初步得出了上面这些jtag基本操作的数据,这样进行分析手工编写代码,具有一定难度,工作量巨大。我再次使用python进行处理,生成C语言代码,为了方便阅读,还会自动生成一些简单的注释,生成的代码包含了宏定义。
这样,fet430uif调试器产生的时序,我都可以很方便的解释成C语言代码,分析出jtag协议,易如反掌。本来一个非常有难度的逆向工程,借助了逻辑分析仪与python就变得异常简单容易,大大减少了工作量。作为一个嵌入式工程师,学习掌握多种编程语言,对工作的帮助是不可估量。当初我学习python语言也是因为网上看到许多大牛对python的推崇,没想到却短期内给我的工作带来如此巨大的帮助。所以,尽量多学习掌握不同的语言,你永远也不知道它有多么重要,但它可能某一天帮了你一把。
附录python源码:
decode-msp430-jtag.py
import sys import os # TDO - data[0] # TDI - data[1] # TMS - data[2] # TCK - data[3] class DeShiftData: def __init__(self): self.data = ""; def finish(self): data = "" if len(self.data) == 8: data = "0x%0.2X" % int(self.data, 2) else: data = "0x%0.4X" % int(self.data, 2) self.data = "" return data def push(self, data): self.data = self.data + data class TAPState: def __init__(self): self.state="IDLE" def change(self, tms): lastState = self.state if self.state == "IDLE": if tms == "0": pass else: self.state = "selectDRScan" elif self.state == "selectDRScan": if tms == "0": self.state = "captureDR" else: self.state = "selectRIScan" elif self.state == "captureDR": if tms == "0": self.state = "shiftDR" else: self.state = "exit1DR" elif self.state == "shiftDR": if tms == "0": #loop pass else: self.state = "exit1DR" elif self.state == "exit1DR": if tms == "0": self.state = "pauseDR" else: self.state = "updateDR" elif self.state == "pauseDR": if tms == "0": #loop pass else: self.state = "exit2DR" elif self.state == "exit2DR": if tms == "0": self.state = "shiftDR" else: self.state = "updateDR" elif self.state == "updateDR": if tms == "0": self.state = "IDLE" else: self.state = "selectDRScan" #IR elif self.state == "selectRIScan": if tms == "0": self.state = "captureIR" else: self.state = "fuseCheck" elif self.state == "captureIR": if tms == "0": self.state = "shiftIR" else: self.state = "exit1IR" elif self.state == "shiftIR": if tms == "0": #loop pass else: self.state = "exit1IR" elif self.state == "exit1IR": if tms == "0": self.state = "pauseIR" else: self.state = "updateIR" elif self.state == "pauseIR": if tms == "0": #loop pass else: self.state = "exit2IR" elif self.state == "exit2IR": if tms == "0": self.state = "shiftIR" else: self.state = "updateIR" elif self.state == "updateIR": if tms == "0": self.state = "IDLE" else: self.state = "selectIRScan" return (lastState,self.state) #travel all lines in file datafile = sys.argv[1] last_data = "0110" lastTime = "0 ns" count=0 tap = TAPState() dataIR = DeShiftData() dataDR = DeShiftData() dataOUT = DeShiftData() count=0 for line in open(datafile): number,data,myTime = line.split(",") #skip first line try: data = bin(int(data, 16))[2:].zfill(4) except: print "#convererror line is: %s" % line continue #skip if last_data == data or data[0] == "\"": continue lastTime = myTime TDO = data[0] TDI = data[1] TMS = data[2] TCK = data[3] #pos edge if TCK == "1" and last_data[3] == "0": #tap lastTapState,tapState = tap.change(TMS) if lastTapState == "captureIR" or lastTapState == "captureDR": #start a shitf pass elif tapState == "shiftIR" or lastTapState == "shiftIR": #print "shiftIR " + TDI dataIR.push(TDI) if tapState == "exit1IR": irdata = dataIR.finish() print myTime.replace("\n", "") + " ShiftIR " + irdata elif tapState == "shiftDR" or lastTapState == "shiftDR": #print "shiftDR " + TDI + " " + TDO dataDR.push(TDI) dataOUT.push(TDO) if tapState == "exit1DR": drdata = dataDR.finish() outdata = dataOUT.finish() print myTime.replace("\n", "") + " ShiftDR " + drdata print myTime.replace("\n", "") + " = " + outdata if TDI != last_data[1] and tapState == "IDLE": if TDI == "0": print myTime.replace("\n", "") + " clrTCLK 0" else: print myTime.replace("\n", "") + " setTCLK 1" last_data = data
jtag-to-c.py
import sys #travel all lines in file datafile = sys.argv[1] print """/* * %s */ """ % sys.argv[1] codeDict = {"0xC8":"IR_CNTRL_SIG_16BIT", "0xc8":"IR_CNTRL_SIG_16BIT", "0x88":"IR_CNTRL_SIG_M8BIT", "0x48":"IR_CNTRL_SIG_L8BIT", "0x28":"IR_CNTRL_SIG_CAPTURE", "0xA8":"IR_CNTRL_SIG_RELEASE", "0xa8":"IR_CNTRL_SIG_RELEASE", "0x44":"IR_PREPARE_BLOW", "0x24":"IR_EX_BLOW", "0x82":"IR_DATA_16BIT", "0xC2":"IR_DATA_QUICK", "0xc2":"IR_DATA_QUICK", "0x22":"IR_DATA_PSA", "0x62":"IR_SHIFT_OUT_PSA", "0xC1":"IR_ADDR_16BIT", "0xc1":"IR_ADDR_16BIT", "0x21":"IR_ADDR_CAPTURE", "0xA1":"IR_DATA_TO_ADDR", "0xa1":"IR_DATA_TO_ADDR", "0xFF":"IR_BYPASS", "0xff":"IR_BYPASS", "0x90":"IR_CTRL_SETTING", "0x30":"IR_30_SETTING", "0x42":"IR_DATA_CAPTURE", "0xD0": "IR_D0_CHECK", "0xd0": "IR_D0_CHECK" } lastTime = "0" for line in open(datafile): #print line.strip("\n") try: myTime, sym, operation, code = line.split() except: print "//FIXME: error - line.split() %s" % line continue code = code.strip("\n") if sym != "us": interval = (float(myTime) - float(lastTime)) if interval > 0.1: print "\n//Interval %F ms" % interval print "MsDelay(%d);" % int(interval) lastTime = myTime if operation == "ShiftIR": if codeDict[code] == "IR_CNTRL_SIG_CAPTURE": print "\n//fetch" elif codeDict[code] == "IR_CTRL_SETTING": print "\n//setting" elif codeDict[code] == "IR_D0_CHECK": print "\n//check" elif codeDict[code] == "IR_CNTRL_SIG_RELEASE": print "\n//run" print "IR_Shift(" + codeDict[code] + ");" elif operation == "ShiftDR": if len(code) == 4: print "DR_Shift8(" + code + ");", else: print "DR_Shift16(" + code + ");", elif operation == "=": print "\t\t//=" + code elif operation == "clrTCLK": print "ClrTCLK();" elif operation == "setTCLK": print "SetTCLK();"