-
Notifications
You must be signed in to change notification settings - Fork 0
/
TIBasicArch.py
139 lines (97 loc) · 4.09 KB
/
TIBasicArch.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
from binaryninja.architecture import Architecture
from binaryninja.function import InstructionInfo, InstructionTextToken, RegisterInfo
from binaryninja.enums import InstructionTextTokenType, Endianness, BranchType
from binaryninja.types import *
# import all the basic commands
from .basic_commands import *
use_default_loader_settings = True
# disassembler class for the TI Basic language
class Disassembler():
# intialize the dictionary and the max key length
def __init__(self):
self.dict = basic_commands
self.max_key_len = max([len(k) for k, v in self.dict.items()])
# Get the first command in the data
def get_command(self, data, readlen):
# get the current data (from start with the length to read)
current = data[0:readlen]
# If length is nothing then return null, we shouldn't hit this
if len(current) == 0:
return "NULL", 0
# while we can keep reading (length greater than 0) and we haven't found the bytes in the dictionary
while readlen > 1 and not current in self.dict:
# decrement readlen
readlen -= 1
# read the new bytes
current = data[0:readlen]
# if the bytes are in the dictionary
if current in self.dict:
# get the associated command
command = self.dict[current]
# if \x00 (byte we add to the end of the file) return END OF FILE
elif current == b'\x00':
command = 'END OF FILE'
readlen = 1
# otherwise return error
else:
command = 'Error'
readlen = 1
# return command and length
return command, readlen
# disassemble the next set of instructions
def disassemble(self, data, addr):
# get the max read length
readlen = self.max_key_len
# set commands we are going to return
totalCommand = ''
totalLen = 0
# get the first command in the data
command = self.get_command(data, readlen)
# add the command to the return values
totalCommand += command[0]
totalLen += command[1]
# if the command isn't a new line and while we can still read more data
while command[0] != '\r\n' and totalLen < len(data):
# get the next command
command = self.get_command(data[totalLen:], readlen)
# check that the command has length greater than 0
if command[1] == 0:
break
# append the command and length to the total
totalCommand += command[0]
totalLen += command[1]
# return the commands and total length
return (totalCommand, totalLen)
# instantiate the disassembler
disasm = Disassembler()
# TI Basic architecture
class TIBASIC(Architecture):
# set name
name = 'TI-BASIC'
# set max instruction length to the max amount that we are allowed to set it to since we search for \r\n
max_instr_length = 256
# set endianness
endianness = Endianness.LittleEndian
# add SP register to appease binja
regs = {
'SP': RegisterInfo('SP', 2)
}
stack_pointer = "SP"
def get_instruction_info(self, data, addr):
(instrTxt, instrLen) = disasm.disassemble(data, addr)
result = InstructionInfo()
result.length = instrLen
# if we reached the end of file command set branch to function return so it doesn't analyze further
if instrTxt == 'END OF FILE':
result.add_branch(BranchType.FunctionReturn)
return result
def get_instruction_text(self, data, addr):
(instrTxt, instrLen) = disasm.disassemble(data, addr)
result = []
# if end of file is reached add string saying it was added by the plugin
if instrTxt == 'END OF FILE':
instrTxt += " - Added by plugin"
result.append(InstructionTextToken(InstructionTextTokenType.TextToken, instrTxt))
return result, instrLen
def get_instruction_low_level_il(self, data, addr, il):
return None