class searcher:
- def reset(this, offs = 0):
+ def reset(this, offs=0):
if offs < 0 or offs > this.length:
raise Exception('Reset past end of section')
this.address = this.baseaddr + offs
raise Exception('Needle not found in haystack')
this.skip(pos - this.offset)
+ def look_for_either(this, needle1, needle2):
+ pos1 = this.data.find(needle1, this.offset)
+ pos2 = this.data.find(needle2, this.offset)
+ if pos1 < 0 and pos2 < 0:
+ raise Exception('Needle not found in haystack')
+ if pos1 < 0 or pos2 < pos1:
+ pos1 = pos2
+ this.skip(pos1 - this.offset)
+
def __init__(this, data, addr):
this.data = data
this.baseaddr = addr
def find_hex_file_lines_constructor_32(text, hex_file_lines_got, got_plt):
while True:
- text.look_for(b'\x8b\xbb') # mov offs32(%ebx),%edi
+ text.look_for_either(b'\x8b\xbb', b'\x8b\xb3') # mov offs32(%ebx),{%edi,%esi}
offs = struct.unpack('<i', text.peek(4, 2))[0]
if got_plt + offs == hex_file_lines_got:
text.skip(6)
text.skip(3)
def parse_hex_file_lines_constructor_32(text, basic_string_plt, got_plt, lines):
+ text.skip(-5)
+ esi = (text.peek(1) == b'\xb3')
+ text.skip(5)
cnt = len(lines)
while cnt > 0:
if text.peek(2) == b'\x8d\x45': # lea offs8(%ebp),%eax
text.skip(3)
elif text.peek(2) == b'\x8d\x85': # lea offs32(%ebp),%eax
text.skip(6)
- if text.peek(1) == b'\xbe': # mov $imm32,%esi
+ if text.peek(1) == (b'\xbf' if esi else b'\xbe'): # mov $imm32,%esi
text.skip(5)
- elif text.peek(2) == b'\x31\xf6': # xor %esi,%esi
+ elif text.peek(2) == (b'\x31\xff' if esi else b'\x31\xf6'): # xor %esi,%esi
text.skip(2)
if text.peek(4) == b'\x89\x44\x24\x08': # mov %eax,0x8(%esp)
text.skip(4)
text.skip(6)
straddr += got_plt
else:
- raise Exception('Expected lea offs32(%ebx),%eax @ '+
+ raise Exception('Expected lea offs32(%ebx),%eax @ ' +
('0x%x' % text.address))
if text.peek(4) == b'\x89\x44\x24\x04': # mov %eax,0x4(%esp)
text.skip(4)
- if text.peek(3) == b'\x89\x3c\x24': # mov %edi,(%esp)
+ if text.peek(3) == (b'\x89\x34\x24' if esi else b'\x89\x3c\x24'): # mov %edi,(%esp)
offs = 0
text.skip(3)
- elif text.peek(2) == b'\x8d\x47': # lea offs8(%edi),%eax
+ elif text.peek(2) == (b'\x8d\x46' if esi else b'\x8d\x47'): # lea offs8(%edi),%eax
offs = struct.unpack('<b', text.peek(1, 2))[0]
text.skip(3)
- elif text.peek(2) == b'\x8d\x87': # lea offs32(%edi),%eax
+ elif text.peek(2) == (b'\x8d\x86' if esi else b'\x8d\x87'): # lea offs32(%edi),%eax
offs = struct.unpack('<i', text.peek(4, 2))[0]
text.skip(6)
else:
- raise Exception('Expected lea offs(%edi),%eax @ '+
+ raise Exception('Expected lea offs(%e'+('s' if esi else 'd')+'i),%eax @ ' +
('0x%x' % text.address))
if offs < 0 or offs > (len(lines) << 2) or (offs & 3) != 0:
raise Exception('Invalid offset %d' % offs)
offs = struct.unpack('<i', text.peek(4, 1))[0]
text.skip(5)
if text.address + offs != basic_string_plt:
- raise Exception('Expected call ZNSsC1EPKcRKSaIcE@plt @ '+
+ raise Exception('Expected call ZNSsC1EPKcRKSaIcE@plt @ ' +
('0x%x' % text.address))
else:
- raise Exception('Expected call ZNSsC1EPKcRKSaIcE@plt @ '+
+ raise Exception('Expected call ZNSsC1EPKcRKSaIcE@plt @ ' +
('0x%x' % text.address))
if straddr == 0:
raise Exception('NULL pointer stored to index %d' % index)
text.skip(7)
straddr += text.address
else:
- raise Exception('Expected lea offs(%rip),%rsi @ '+
+ raise Exception('Expected lea offs(%rip),%rsi @ ' +
('0x%x' % text.address))
if text.peek(3) == b'\x48\x89\xef': # mov %rbp,%rdi
offs = 0
offs = struct.unpack('<i', text.peek(4, 3))[0]
text.skip(7)
else:
- raise Exception('Expected lea offs(%rbp),%rdi @ '+
+ raise Exception('Expected lea offs(%rbp),%rdi @ ' +
('0x%x' % text.address))
+ if text.peek(1) == b'\xbb': # mov $imm32,%ebx
+ text.skip(5)
+ elif text.peek(2) == b'\x31\xdb': # xor %ebx,%ebx
+ text.skip(2)
if offs < 0 or offs > (len(lines) << 3) or (offs & 7) != 0:
raise Exception('Invalid offset %d' % offs)
index = offs >> 3
offs = struct.unpack('<i', text.peek(4, 1))[0]
text.skip(5)
if text.address + offs != basic_string_plt:
- raise Exception('Expected callq ZNSsC1EPKcRKSaIcE@plt @ '+
+ raise Exception('Expected callq ZNSsC1EPKcRKSaIcE@plt @ ' +
('0x%x' % text.address))
else:
- raise Exception('Expected callq ZNSsC1EPKcRKSaIcE@plt @ '+
+ raise Exception('Expected callq ZNSsC1EPKcRKSaIcE@plt @ ' +
('0x%x' % text.address))
if straddr == 0:
raise Exception('NULL pointer stored to index %d' % index)
for reloc in relocs['relocs']:
if reloc['r_sym'] == symnum:
return reloc
- raise Exception('Unable to find a relocation against '+symname)
+ raise Exception('Unable to find a relocation against ' + symname)
def ihex_to_binary(lines):
chunks = {}
return blob
def extract_fx2_firmware(elf, symname, filename):
- blob = elf.load_symbol(elf.dynsym[symname+'Count'])
+ blob = elf.load_symbol(elf.dynsym[symname + 'Count'])
count = struct.unpack('<I', blob)[0]
got_plt = elf.find_section('.got.plt')['sh_addr']
- hex_file_lines_got = find_reloc(elf, symname)['r_offset'];
+ hex_file_lines_got = find_reloc(elf, symname)['r_offset']
basic_string_got = find_reloc(elf, '_ZNSsC1EPKcRKSaIcE')['r_offset']
pltsec = elf.find_section('.plt')
plt = searcher(elf.read_section(pltsec), pltsec['sh_addr'])
find_hex_file_lines_constructor_32(text, hex_file_lines_got,
got_plt)
except:
- raise Exception('Unable to find constructor for '+symname)
+ raise Exception('Unable to find constructor for ' + symname)
oldoffs = text.offset
l = [0]*count
try:
f.close()
print("saved %d bytes to %s" % (len(blob), filename))
+def extract_fx2_firmware_single(elf, symname, filename):
+ if not symname in elf.dynsym:
+ return False
+ hex = bytes.decode(elf.load_symbol(elf.dynsym[symname]))
+ if hex[-1] == '\0':
+ hex = hex[:-1]
+ blob = ihex_to_binary(hex.split(';'))
+ f = open(filename, 'wb')
+ f.write(blob)
+ f.close()
+ print("saved %d bytes to %s" % (len(blob), filename))
+ return True
+
+def extract_fx3_firmware(elf, symname, filename):
+ index = 0
+ blobs = []
+ while True:
+ sym = elf.dynsym.get(symname + '_' + str(index))
+ if not sym:
+ break
+ index += 1
+ hex = bytes.decode(elf.load_symbol(sym))
+ if hex[-1] == '\0':
+ hex = hex[:-1]
+ for part in hex.split(';'):
+ if not part:
+ continue
+ if part[0] != ':':
+ raise Exception('ihex line does not start with ":"')
+ blobs.append(bytes.fromhex(part[1:]))
+ if not blobs:
+ return
+ with open(filename, 'wb') as f:
+ for blob in blobs:
+ f.write(blob)
+ print("saved %d bytes from %d blobs to %s" % (sum(map(len, blobs)),
+ len(blobs), filename))
+
def extract_symbol(elf, symname, filename):
blob = elf.load_symbol(elf.dynsym[symname])
f = open(filename, 'wb')
f.close()
print("saved %d bytes to %s" % (len(blob), filename))
+def try_extract_symbol(elf, symname, filename):
+ if not symname in elf.dynsym:
+ return
+ extract_symbol(elf, symname, filename)
+
def extract_bitstream(elf, lv):
- extract_symbol(elf, 'gLogic16Lv'+lv+'CompressedBitstream',
- 'saleae-logic16-fpga-'+lv+'.bitstream')
+ extract_symbol(elf, 'gLogic16Lv' + lv + 'CompressedBitstream',
+ 'saleae-logic16-fpga-' + lv + '.bitstream')
def usage():
print("sigrok-fwextract-saleae-logic16 <programfile>")
elf = parseelf.elf(filename)
if elf.ehdr['e_machine'] != 3 and elf.ehdr['e_machine'] != 62:
raise Exception('Unsupported e_machine')
- extract_fx2_firmware(elf, 'gLogic16HexFileLines', 'saleae-logic16-fx2.fw')
+ if not extract_fx2_firmware_single(elf, 'Logic16FirmwareStrings', 'saleae-logic16-fx2.fw'):
+ extract_fx2_firmware(elf, 'gLogic16HexFileLines', 'saleae-logic16-fx2.fw')
extract_bitstream(elf, '18')
extract_bitstream(elf, '33')
+ extract_fx3_firmware(elf, 'LogicPro16FirmwareStrings', 'saleae-logicpro16-fx3.fw')
+ extract_fx3_firmware(elf, 'LogicPro8FirmwareStrings', 'saleae-logicpro8-fx3.fw')
+ try_extract_symbol(elf, 'gLogicPro16CompressedBitstream', 'saleae-logicpro16-fpga.bitstream')
+ try_extract_symbol(elf, 'gLogicProCompressedBitstream', 'saleae-logicpro8-fpga.bitstream')
except Exception as e:
print("Error: %s" % str(e))
-