共计 9102 个字符,预计需要花费 23 分钟才能阅读完成。
1. 3GPP Decoder 工具调研
家喻户晓,3GPP Decoder 工具在蜂窝网络 OTA 音讯的解析上有独到的效率。比方 Qualcomm、UNISOC、MediaTek 的平台工具对于 OTA 音讯的解析格局各不相同,要比拟的时候应用 3GPP Decoder 工具能够对立格局,确保在遇到问题时能够疾速比拟等。
以后大家应用的 3GPP Decoder 工具个别是如下三个:
http://3gppdecoder.free.fr
https://www.3glteinfo.com/
https://gitee.com/konglinglon…
这三个工具没有 python 写的,python 是比拟风行的编程语言,广泛应用于自动化测试。
2. 应用 Python 构建 3GPP Decoder 工具
2.1. 须要学习的材料
2.1.1. tkinter 学习
学习 tkinter,只有学习 grid 布局就足够了,为了防止混同,倡议学习如下文档即可。
https://tkdocs.com/tutorial/i…
2.1.2. wireshark 命令
该文档具备启发性,对 dissector 的了解也是重中之重:
如何让 wireshark 解码任意层的数据:https://blog.csdn.net/peng_yw…
该文档介绍了 DLT=147 的办法:
The Wireshark Network Analyzer:https://users.cs.fiu.edu/~esj…
-o “uat:user_dlts:\”User 0 (DLT=147)\”,\”cops\”,\”0\”,\”\”,\”0\”,\”\””
2.2. 程序源码
import os
import re
import subprocess
import configparser
from tkinter import *
from tkinter import ttk
from tkinter import filedialog
from tkinter.scrolledtext import ScrolledText
class TGPPDecoder:
WiresharkPath = ''NROTAList = ("nas-5gs","nr-rrc.dl.ccch","nr-rrc.dl.dcch","nr-rrc.ul.ccch","nr-rrc.ul.dcch","nr-rrc.ul.ccch1","nr-rrc.bcch.bch","nr-rrc.bcch.dl.sch","nr-rrc.pcch","nr-rrc.rrc_reconf","nr-rrc.ue_mrdc_cap","nr-rrc.ue_nr_cap","xnap","f1ap","ngap","x2ap")
LTEOTAList = (
"lte-rrc.dl.ccch",
"lte-rrc.dl.dcch",
"lte-rrc.ul.ccch",
"lte-rrc.ul.dcch",
"lte-rrc.bcch.bch",
"lte-rrc.bcch.dl.sch",
"lte-rrc.pcch",
"lte-rrc.mcch",
"lte-rrc.ue_eutra_cap",
"nas-eps",
"nas-eps_plain",
"s1ap",
"x2ap",
"lpp",
"ulp")
LTENBOTAList = (
"nr-rrc.dl.ccch.nb",
"nr-rrc.dl.dcch.nb",
"nr-rrc.ul.ccch.nb",
"nr-rrc.ul.dcch.nb",
"s1ap",
"x2ap")
WCDMAOTAList = (
"rrc.bcch.bch",
"rrc.bcch.fach",
"rrc.dl.ccch",
"rrc.dl.dcch",
"rrc.pcch",
"rrc.ul.ccch",
"rrc.ul.dcch",
"rrc.irat.ho_to_utran_cmd",
"rrc.irat.irat_ho_info",
"rrc.si.mib",
"rrc.si.sb1",
"rrc.si.sb2",
"rrc.si.sib1",
"rrc.si.sib2",
"rrc.si.sib3",
"rrc.si.sib4",
"rrc.si.sib5",
"rrc.si.sib5bis",
"rrc.si.sib6",
"rrc.si.sib7",
"rrc.si.sib11",
"rrc.si.sib11bis",
"rrc.si.sib12",
"rrc.si.sib18",
"rrc.si.sib19",
"rrc.si.sib20",
"rrc.si.sib21",
"rrc.si.sib22")
GSMOTAList = (
"gsm_rlcmac_dl",
"gsm_rlcmac_ul",
"llcgprs",
"gsm_a_dtap",
"gsm_a_rp",
"gsm_sms",
"gsm_a_ccch",
"gsm_a_sacch")
SIMProtocolList = (
"gsm_sim",
"etsi_cat",
"gsm_sim.command",
"gsm_sim.response",)
# If it is not defined here, it cannot be used in callback function GetOTAList().
selectcb = ''inputText =''
outputText = ''TGPPDecoder =''
def __init__(self, root):
root.title('3gppdecoder v0.1')
root.minsize(760, 508)
mainframe = ttk.Frame(root, padding="3 3 3 3")
mainframe.grid(column=0, row=0, sticky=(N, W, E, S))
root.columnconfigure(0, weight=1)
root.rowconfigure(0, weight=1)
inputlf = ttk.Labelframe(mainframe, text='Input')
inputlf.grid(column=0, row=0, ipadx=5, ipady=5,padx=5, pady=5, sticky=(W, E))
self.inputText = ScrolledText(inputlf, height=8, font='TkFixedFont')
self.inputText.grid(column=0, row=0, sticky=(W, E))
inputlf.columnconfigure(0, weight=1)
protocollf = ttk.Labelframe(mainframe, text='Protocol selection')
protocollf.grid(column=0, row=1, ipadx=5, ipady=5,padx=5, pady=5, sticky=(W, E))
self.protocol = StringVar()
self.protocol.set('LTE')
nrrb = ttk.Radiobutton(protocollf, text='NR', variable=self.protocol, value='NR', command=self.GetOTAList)
lterb = ttk.Radiobutton(protocollf, text='LTE', variable=self.protocol, value='LTE', command=self.GetOTAList)
ltenbrb = ttk.Radiobutton(protocollf, text='LTE-NB', variable=self.protocol, value='LTE-NB', command=self.GetOTAList)
wcdmarb = ttk.Radiobutton(protocollf, text='WCDMA', variable=self.protocol, value='WCDMA', command=self.GetOTAList)
gsmrb = ttk.Radiobutton(protocollf, text='GSM', variable=self.protocol, value='GSM', command=self.GetOTAList)
simrb = ttk.Radiobutton(protocollf, text='SIM', variable=self.protocol, value='SIM', command=self.GetOTAList)
self.otatype = StringVar()
self.selectcb = ttk.Combobox(protocollf, width=35, value=self.LTEOTAList, textvariable=self.otatype)
nrrb.grid(column=0, row=0, padx=5, sticky=W)
lterb.grid(column=1, row=0, padx=5, sticky=W)
ltenbrb.grid(column=2, row=0, padx=5, sticky=W)
wcdmarb.grid(column=3, row=0, padx=5, sticky=W)
gsmrb.grid(column=4, row=0, padx=5, sticky=W)
simrb.grid(column=5, row=0, padx=5, sticky=W)
self.selectcb.current(0)
self.selectcb.grid(column=6, row=0, padx=15, sticky=W)
protocollf.columnconfigure(6, weight=1)
decodinglf = ttk.Labelframe(mainframe, text='Output decoding')
decodinglf.grid(column=0, row=2, ipadx=5, ipady=5,padx=5, pady=5, sticky=(W, E))
textbn = ttk.Button(decodinglf, text='Text view', command=self.TextButtonCallback)
wiresharkbn = ttk.Button(decodinglf, text='Wireshark', command=self.WiresharkButtonCallback)
wiresharkpathlb = ttk.Label(decodinglf, text='Wireshark Path:')
self.GetWiresharkPath()
self.wiresharkpathet = ttk.Entry(decodinglf, width=35)
self.wiresharkpathet.delete(0, "end")
self.wiresharkpathet.insert(0, self.WiresharkPath)
self.wiresharkpathet['state'] = 'readonly'
settingsbn = ttk.Button(decodinglf, width=5, text='...', command=self.SetWiresharkPath)
textbn.grid(column=0, row=0, padx=5, sticky=W)
wiresharkbn.grid(column=1, row=0, padx=5, sticky=W)
wiresharkpathlb.grid(column=2, row=0, sticky=E)
self.wiresharkpathet.grid(column=3, row=0, padx=5, sticky=E)
settingsbn.grid(column=4, row=0, padx=5, sticky=E)
decodinglf.columnconfigure(1, weight=1)
self.outputText = ScrolledText(mainframe, font='TkFixedFont')
self.outputText.grid(column=0, row=3, padx=5, pady=10, sticky=(N, S, E, W))
mainframe.columnconfigure(0, weight=1)
mainframe.rowconfigure(3, weight=1)
def GetOTAList(self):
p = self.protocol.get()
if p == 'NR':
self.selectcb['value'] = self.NROTAList
elif p == 'LTE':
self.selectcb['value'] = self.LTEOTAList
elif p == 'LTE-NB':
self.selectcb['value'] = self.LTENBOTAList
elif p == 'WCDMA':
self.selectcb['value'] = self.WCDMAOTAList
elif p == 'GSM':
self.selectcb['value'] = self.GSMOTAList
elif p == 'SIM':
self.selectcb['value'] = self.SIMProtocolList
else:
self.selectcb['value'] = self.LTEOTAList
self.selectcb.current(0)
def WriteASCIIHexDumpFile(self, rawStr, ASCIIHexDumpFile):
offset = 0
with open(ASCIIHexDumpFile, 'w+') as fp:
for x in rawStr.strip().split(' '):
if offset % 16 == 0:
if offset != 0:
fp.write('\n')
fp.write('%.6x' % offset)
fp.write(' ' + x)
offset = offset + 1
def CreatePcap(self, ASCIIHexDumpFile):
cmd1 = '"'+ self.WiresharkPath + r'/text2pcap.exe"-l 147 ASCII_Hex_Dump.txt fortshark.pcap'
p = subprocess.Popen(cmd1, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
#improt ctypes
#whnd = ctypes.windll.kernel32.GetConsoleWindow()
#if whnd != 0:
# ctypes.windll.user32.ShowWindow(whnd, 0)
p.wait()
def AnalyzeByTshark(self, ASCIIHexDumpFile, channelType):
self.CreatePcap(ASCIIHexDumpFile)
cmd2 = '"'+ self.WiresharkPath + r'/tshark.exe"-V -T text -o"uat:user_dlts:\"User 0 (DLT=147)\",\"cops\",\"0\",\"\",\"0\",\"\"" -r fortshark.pcap'cmd2 = cmd2.replace('cops', channelType)
p = subprocess.Popen(cmd2, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
output, err = p.communicate()
output = str(output, encoding = "utf-8")
#print(output)
flag = False
output_ = ''
for line in output.splitlines():
if flag:
output_ += line + '\n'
if 'DLT: 147' in line.strip():
flag = True
#print(output_)
return output_
def AnalyzeByWireshark(self, ASCIIHexDumpFile, channelType):
self.CreatePcap(ASCIIHexDumpFile)
cmd2 = '"'+ self.WiresharkPath + r'/Wireshark.exe"-o"uat:user_dlts:\"User 0 (DLT=147)\",\"cops\",\"0\",\"\",\"0\",\"\"" -r fortshark.pcap'cmd2 = cmd2.replace('cops', channelType)
p = subprocess.Popen(cmd2, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
output, err = p.communicate()
def GetInputRawData(self):
text = self.inputText.get('0.0','end')
strText = re.sub('\s','',text)
strCheckResult = re.search('^[0-9A-Fa-f]+$', strText)
if strCheckResult:
return True
else:
return False
def TextButtonCallback(self):
self.outputText.delete(1.0,'end')
if not os.path.isfile(self.WiresharkPath + r'/tshark.exe'):
self.outputText.insert(1.0, 'Invalid Wireshark path.')
elif self.GetInputRawData():
text = self.inputText.get('0.0','end')
strText = re.sub('\s','',text)
pattern = re.compile('.{2}')
fmtStr = ' '.join(pattern.findall(strText))
self.WriteASCIIHexDumpFile(fmtStr, 'ASCII_Hex_Dump.txt')
output = self.AnalyzeByTshark('ASCII_Hex_Dump.txt', self.otatype.get())
self.outputText.insert(1.0, output)
else:
self.outputText.insert(1.0, 'Invalid hex string.')
def WiresharkButtonCallback(self):
self.outputText.delete(1.0,'end')
self.outputText.update()
if not os.path.isfile(self.WiresharkPath + r'/tshark.exe'):
self.outputText.insert(1.0, 'Invalid Wireshark path.')
elif self.GetInputRawData():
text = self.inputText.get('0.0','end')
strText = re.sub('\s','',text)
pattern = re.compile('.{2}')
fmtStr = ' '.join(pattern.findall(strText))
self.WriteASCIIHexDumpFile(fmtStr, 'ASCII_Hex_Dump.txt')
output = self.AnalyzeByWireshark('ASCII_Hex_Dump.txt', self.otatype.get())
else:
self.outputText.insert(1.0, 'Invalid hex string.')
def GetWiresharkPath(self):
config = configparser.ConfigParser()
config.read('config.ini', encoding='utf-8')
if config.has_option('DEFAULT', 'path'):
self.WiresharkPath = config.get("DEFAULT", "path")
else:
self.WiresharkPath = ''
def SetWiresharkPath(self):
config = configparser.ConfigParser()
config.read('config.ini', encoding='utf-8')
dirname = filedialog.askdirectory()
if os.path.exists(dirname):
config.set("DEFAULT", "path", dirname)
with open("config.ini", "w+", encoding="utf-8") as f:
config.write(f)
self.wiresharkpathet['state'] = 'normal'
self.wiresharkpathet.delete(0, 'end')
self.wiresharkpathet.insert(0, dirname)
self.wiresharkpathet['state'] = 'readonly'
self.GetWiresharkPath()
if __name__ == '__main__':
root = Tk()
TGPPDecoder(root)
root.mainloop()
3. 打包办法
进入 anconda prompt,装置 pyinstaller:
pip install pyinstaller
打包.exe 文件:
pyinstaller -F -w TGPPDecoder.py