3HALT_SYMBOLS = [
"report_done"]
11from subprocess
import Popen, PIPE
23 p = Popen(cmd.split(), stdin=PIPE, stdout=PIPE, stderr=PIPE)
24 output, err = p.communicate()
25 output = output.decode(
'UTF-8')
26 err = err.decode(
'UTF-8')
34 return hex(int(s, 16))
41 input_parameter_list = list()
42 functionContainingCipher = sys.argv[0]
47 for i
in range(len(argv)):
48 input_parameter_list.append(str(argv[i]))
55 RELATIVE_PATH = str(FolderName).rpartition(
"results")[0] +
"binary"
58 out,err =
run(
"arm-none-eabi-readelf -A " + RELATIVE_PATH +
"/binary.elf")
59 tmp,err =
run(
"arm-none-eabi-readelf -A " + RELATIVE_PATH +
"/binary.elf")
61 if "Tag_CPU_name:" in out:
62 out = out[out.find(
"Tag_CPU_name:"):]
63 out = out[out.find(
":")+1 : out.find(
"\n")].strip()
69 if "Tag_CPU_arch:" in tmp:
70 tmp = tmp[tmp.find(
"Tag_CPU_arch:"):]
71 tmp = tmp[tmp.find(
":")+1 : tmp.find(
"\n")].strip()
79 print(
"ERROR: {} is not an ARMv6-M, ARMv7-M or ARMv7E-M binary.".format(tmp))
82 print(
"ERROR: 'Tag_CPU_arch' is missing in the output of readelf.")
85 print(
"ERROR: 'Tag_CPU_name' is missing in the output of readelf.")
92 with open(RELATIVE_PATH +
"/binary.map",
"rt")
as file:
93 lines = file.readlines()
100 functionContainingCipher_address =
None
101 halt_addresses = list()
102 ignore_ranges = list()
103 following_function_cipher_address =
None
104 following_function_cipher_found =
False
105 ram_edata_address =
None
106 rand_section_start =
None
107 rand_section_end =
None
108 rand_size_detected =
False
109 input_parameter_addresses = dict.fromkeys(input_parameter_list)
114 if len(parts) < 2:
continue
116 if ".data" in parts
and inputs_found ==
False:
117 lines_idx = lines.index(line)
118 data_parts = lines[lines_idx].split()
120 while(
not (
"_edata" in data_parts)):
121 for input_param
in input_parameter_list:
122 if input_param
in data_parts:
123 input_parameter_addresses[input_param] = data_parts[data_parts.index(input_param)-1]
125 data_parts = lines[lines_idx].split()
128 if "_edata" in parts:
129 ram_edata_address =
num(parts[0])
130 if ".randomness" in parts
and not rand_size_detected:
131 rand_section_start = int(parts[1], 0)
132 rand_section_end = rand_section_start + int(parts[2], 0)
133 rand_size_detected =
True
134 if parts[0].upper() ==
"FLASH":
135 flash = (
num(parts[1]),
num(parts[2]))
136 end_of_flash = int(parts[1], 0) + int(parts[2],0)
137 elif parts[0].upper() ==
"RAM":
138 ram = (
num(parts[1]),
num(parts[2]))
140 if (
not following_function_cipher_found)
and (
"cipher" in parts):
141 following_function_cipher_found =
True
142 following_function_cipher_address = (lines[lines.index(line) + 1].split())[0]
147 out,err =
run(
"arm-none-eabi-objdump " + RELATIVE_PATH +
"/binary.elf -t")
148 lines = sorted([l
for l
in out.split(
"\n")])
152 if len(parts) < 3:
continue
154 if begin_ignore !=
None and parts[2] ==
"F" and not (parts[-1]
in IGNORE_SYMBOLS):
156 ignore_ranges.append((begin_ignore, hex(min(int(parts[0],16), end_of_flash))))
159 if parts[-1] == START_SYMBOL:
160 start_address =
num(parts[0])
161 elif parts[-1] == MAIN_SYMBOL:
162 main_address =
num(parts[0])
163 elif parts[-1]
in HALT_SYMBOLS:
164 halt_addresses.append((parts[-1],
num(parts[0])))
165 elif (parts[-1]
in IGNORE_SYMBOLS
or parts[2] ==
"O")
and begin_ignore ==
None:
166 begin_ignore =
num(parts[0])
168 if parts[-1] == functionContainingCipher:
169 functionContainingCipher_address = parts[0]
171 if begin_ignore !=
None:
172 ignore_ranges.append((begin_ignore, hex(end_of_flash)))
174 if flash == (0,0)
or ram == (0,0):
175 print(
"flash or ram section could not be found in map file")
178 if start_address ==
None:
179 print(
"{} symbol could not be found in map file".format(START_SYMBOL))
182 if functionContainingCipher_address ==
None:
183 print(
"Could not find {} function in map file".format(functionContainingCipher))
185 if ram_edata_address ==
None:
186 print(
"No symbol '_edata' found in linker script in data segment. This is important for placing user input in the correct memory addresses.")
189 if (rand_section_start ==
None)
or (rand_section_end ==
None):
190 print(
"No section for emulator randomness detected. If you need no randomness proceed otherwise reconfigure linker script.")
192 for key, val
in input_parameter_addresses.items():
194 print(
"No symbol {} could be found in .map file! Check in test source files if {} is declared as global variable and stored in .data section.".format(key, key))
200 out,err =
run(
"arm-none-eabi-objdump " + RELATIVE_PATH +
"/binary.elf -h")
201 lines = [l
for l
in out.split(
"\n")]
202 while len(lines) > 0:
205 if len(parts) == 7
and parts[1].startswith(
"."):
207 if "ALLOC" not in attr:
continue
208 if int(parts[2], 16) != 0:
209 sections.append((parts[1],
num(parts[3])))
211 for name, _
in sections:
212 run(
"arm-none-eabi-objcopy -O binary --only-section="+name+
" " + RELATIVE_PATH +
"/binary.elf " + RELATIVE_PATH +
"/code_section"+name)
218 with open(RELATIVE_PATH +
"/disassembled.txt",
"r")
as f:
219 lines = f.readlines()
222 sanitised_lines.append((line.replace(
"\n",
"")).replace(
"\t",
" "))
223 sanitised_lines = list(filter(
None, sanitised_lines))
225 original_cipher_list = []
228 for line
in sanitised_lines:
229 if((functionContainingCipher_address
in line)
and (
"<{}>".format(functionContainingCipher)
in line)):
230 main_list = sanitised_lines[sanitised_lines.index(line):]
233 for line
in main_list:
235 if((
not line.startswith(
" "))
and (main_list.index(line) != 0)):
236 main_list = main_list[:main_list.index(line)]
239 for line
in main_list:
240 if(
"cipher" in line):
241 cipher_list.append(line)
242 if(
"<cipher>" in line):
243 original_cipher_list.append(line)
245 if(len(original_cipher_list) == 0):
246 print(
"could not find <cipher> symbol in compiled main-function. Checking for compiler optimized modifications...")
248 if(len(cipher_list) == 0):
249 print(
"could not find <cipher> related functions in main. Please check disassembled.txt. Aborting...")
253 print(
"found in {} (order of occurrance):".format(functionContainingCipher))
254 found_cipher_elements = []
255 for line
in cipher_list:
256 elements = list(filter(
None, line.split(
" ")))
257 function_address = elements[-2]
258 function_name = elements[-1]
259 print(
"\taddress: {}\tfunction: {}\n".format(function_address, function_name))
260 found_cipher_elements.append((function_address, function_name))
261 print(
"taking {}".format(found_cipher_elements[0][1]))
262 input(
"press enter to continue with this function to test...")
263 start_address =
num(found_cipher_elements[0][0])
267 args =
"--start {}".format(start_address)
269 args +=
" --main {}".format(main_address)
271 for x
in halt_addresses:
272 args +=
" --halt {} {}".format(x[0], x[1])
273 for start, end
in ignore_ranges:
274 args +=
" --ignore {} {}".format(start, end)
276 args +=
" --flash {} {} --ram {} {}".format(flash[0], flash[1], ram[0], ram[1])
278 args +=
" --edata_used_ram {}".format(ram_edata_address)
280 args +=
" --randomness_section {} {}".format(rand_section_start, rand_section_end)
287 args +=
" --armv7e-m"
289 for name, offset
in sections:
290 args +=
" --section " + RELATIVE_PATH +
"/code_section{} {}".format(name, offset)
293 for key, val
in input_parameter_addresses.items():
294 args +=
" {} {}".format(key,val)
def extract_args(FolderName)