Linear Equation 2
Category: Reverse
Im just dumping my solve script here. I might add a writeup later.
Please don’t judge my code too harshly, the goal was to solve quickly, not to write clean code.
Solution
Table generation
from pwn import *
import z3
filename = "./lineq2"
elf = ELF(filename)
context.binary = elf
with open(filename, "rb") as f:
elf_bytes = f.read()
elf_bytes = bytearray(elf_bytes)
GHIDRA_OFFSET = 0x100000
DATA_OFFSET_START = 0x3020
DATA_OFFSET_END = 0x296420
PART_SIZE = 0x10500
TARGET_BUFF_SIZE = 0x10000
def generate_part_starts(DATA_OFFSET_START, TARGET_BUFF_SIZE):
"""
Find all beginings of chunks of size TARGET_BUFF_SIZE composed with 0x00 or 0x01 bytes
"""
part_starts = []
current_part_start = DATA_OFFSET_START
current_part_size = 0
for i in range(DATA_OFFSET_START, DATA_OFFSET_END):
if current_part_size == TARGET_BUFF_SIZE:
part_starts.append((current_part_start))
current_part_start = i
current_part_size = 0
if elf_bytes[i] == 0x00 or elf_bytes[i] == 0x01:
current_part_size += 1
else:
current_part_start = i+1
current_part_size = 0
return part_starts
part_starts = generate_part_starts(DATA_OFFSET_START, TARGET_BUFF_SIZE)
part_sizes = []
for i in range(len(part_starts)-1):
part_sizes.append(part_starts[i+1]-part_starts[i])
part_sizes.append(DATA_OFFSET_END-part_starts[-1])
def find_part_result(part_start, part_size):
"""
Find the result of the part which is the index of the first 0x01 byte
"""
result = -1
for i in range(part_size):
if elf_bytes[part_start+i] == 0x01:
if result != -1:
print("Multiple results found !", result, i)
result = i
return result
part_results = []
for part_start in part_starts:
part_results.append(find_part_result(part_start, TARGET_BUFF_SIZE))
def generate_tables(part_starts, part_sizes):
"""
Generate tables indexed with thei addresses in the result dictionary
A part is composed of :
1 target buff of size TARGET_BUFF_SIZE
X tables of size 0x200
1 final table of size 0x100
"""
tables = {}
for part_num in range(len(part_starts)):
tables_total_size = part_sizes[part_num] - TARGET_BUFF_SIZE
table_count = tables_total_size // 0x200
for i in range(table_count):
table = []
for j in range(0x200):
table.append(elf_bytes[part_starts[part_num]+TARGET_BUFF_SIZE+i*0x200+j])
tables[part_starts[part_num]+TARGET_BUFF_SIZE+i*0x200] = table
if tables_total_size % 0x200 == 0x100:
final_table = []
for i in range(0x100):
final_table.append(elf_bytes[part_starts[part_num]+TARGET_BUFF_SIZE+table_count*0x200+i])
tables[part_starts[part_num]+TARGET_BUFF_SIZE+table_count*0x200] = final_table
return tables
tables_dict = generate_tables(part_starts, part_sizes)
Condition generation
def generate_conditions(tables_dict, inputs:list):
tables = {}
# Add GHIDRA_OFFSET to the addresses
for key in tables_dict.keys():
tables[key+GHIDRA_OFFSET] = tables_dict[key]
perm_values = {
3: inputs[36],
4: inputs[7],
5: inputs[18],
7: inputs[43],
8: inputs[26],
9: inputs[33],
10: inputs[15],
11: inputs[5],
12: inputs[31],
13: inputs[39],
14: inputs[6],
15: inputs[14],
16: inputs[32],
17: inputs[22],
18: inputs[19],
19: inputs[42],
20: inputs[25],
21: inputs[30],
22: inputs[28],
23: inputs[13],
24: inputs[23],
25: inputs[37],
26: tables[0x0021a020][inputs[28]],
27: inputs[16],
28: inputs[21],
29: inputs[35],
30: inputs[41],
31: inputs[27],
32: inputs[20],
33: inputs[9],
34: inputs[34],
35: inputs[24],
36: inputs[11],
}
perm = lambda x: perm_values[x]
inp = lambda x: inputs[x]
conditions = {
0x00103020: (((((tables[0x00113020][tables[0x00113420][perm(27)]*2]) + (tables[0x002bdc20][tables[0x00113420][perm(31)]*2])) - (tables[0x00113220][tables[0x00113420][perm(9)]*2])) - (tables[0x001b6c20][tables[0x00113420][perm(27)]*2])) - (tables[0x0023a820][tables[0x00113420][perm(22)]*2])),
0x00113520: (((((tables[0x00123520][tables[0x001f8f20][perm(16)]*2]) + (tables[0x00123920][tables[0x001f8f20][perm(15)]*2])) - (tables[0x00123720][tables[0x001f8f20][inp(12)]*2])) - (tables[0x00342620][tables[0x001f8f20][perm(7)]*2])) - (tables[0x00353320][tables[0x001f8f20][perm(25)]*2])),
0x00123b20: ((((tables[0x00133b20][tables[0x00133f20][perm(9)]*2]) - ((tables[0x00133d20][tables[0x00133f20][perm(9)]*2]) + (tables[0x00374920][tables[0x00133f20][perm(16)]*2]))) - (tables[0x00219620][tables[0x00133f20][perm(29)]*2])) - (tables[0x00363c20][tables[0x00133f20][inp(8)]*2])),
0x00134020: ((((tables[0x00144020][tables[0x00144620][perm(3)]*2]) - ((tables[0x00321620][tables[0x00144620][perm(8)]*2]) + (tables[0x00144420][tables[0x00144620][perm(17)]*2]))) - (tables[0x00144220][tables[0x00144620][perm(13)]*2])) - (tables[0x001e8320][tables[0x00144620][perm(34)]*2])),
0x00144720: (((((tables[0x00385020][tables[0x00154920][perm(17)]*2]) + (tables[0x0026b920][tables[0x00154920][perm(11)]*2])) - (tables[0x001e8920][tables[0x00154920][perm(8)]*2])) - (tables[0x00374520][tables[0x00154920][perm(22)]*2])) - (tables[0x00154720][tables[0x00154920][perm(4)]*2])),
0x00154a20: (((((tables[0x00164a20][tables[0x00165220][perm(31)]*2]) + (tables[0x00164e20][tables[0x00165220][perm(34)]*2])) - (tables[0x00165020][tables[0x00165220][perm(31)]*2])) - (tables[0x0022a520][tables[0x00165220][perm(7)]*2])) - (tables[0x00164c20][tables[0x00165220][perm(17)]*2])),
0x00165320: ((((tables[0x001a6220][tables[0x00175920][perm(7)]*2]) + (tables[0x00175720][tables[0x00175920][perm(28)]*2]) + (tables[0x00175320][tables[0x00175920][perm(34)]*2])) - (tables[0x00175520][tables[0x00175920][perm(30)]*2])) - (tables[0x00374720][tables[0x00175920][perm(20)]*2])),
0x00175a20: ((((tables[0x00342c20][tables[0x00185e20][inp(17)]*2]) + (tables[0x00185c20][tables[0x00185e20][perm(14)]*2]) + (tables[0x00185a20][tables[0x00185e20][perm(20)]*2])) - (tables[0x002ef720][tables[0x00185e20][perm(24)]*2])) - (tables[0x00374520][tables[0x00185e20][perm(15)]*2])),
0x00185f20: (((((tables[0x00195f20][tables[0x00196120][perm(24)]*2]) + (tables[0x00321a20][tables[0x00196120][perm(4)]*2])) - (tables[0x00385220][tables[0x00196120][perm(13)]*2])) - (tables[0x002df020][tables[0x00196120][perm(16)]*2])) - (tables[0x00363c20][tables[0x00196120][perm(24)]*2])),
0x00196220: (((((tables[0x001a6420][tables[0x002eff20][inp(17)]*2]) + (tables[0x001a6a20][tables[0x002eff20][perm(29)]*2])) - (tables[0x001a6820][tables[0x002eff20][perm(34)]*2])) - (tables[0x001a6620][tables[0x002eff20][perm(14)]*2])) - (tables[0x001a6220][tables[0x002eff20][perm(32)]*2])),
0x001a6c20: (((((tables[0x001b7220][tables[0x001b7420][perm(19)]*2]) + (tables[0x001b6e20][tables[0x001b7420][perm(30)]*2])) - (tables[0x002ad120][tables[0x001b7420][perm(36)]*2])) - (tables[0x001b7020][tables[0x001b7420][perm(19)]*2])) - (tables[0x001b6c20][tables[0x001b7420][inp(40)]*2])),
0x001b7520: ((((tables[0x001c7920][tables[0x001c7b20][perm(29)]*2]) + (tables[0x00352f20][tables[0x001c7b20][inp(29)]*2]) + (tables[0x0029ce20][tables[0x001c7b20][perm(7)]*2])) - (tables[0x001c7720][tables[0x001c7b20][perm(22)]*2])) - (tables[0x001c7520][tables[0x001c7b20][perm(5)]*2])),
0x001c7c20: ((((tables[0x00332120][tables[0x001d8220][perm(27)]*2]) + (tables[0x002ce520][tables[0x001d8220][perm(30)]*2]) + (tables[0x001d7e20][tables[0x001d8220][perm(28)]*2])) - (tables[0x001d8020][tables[0x001d8220][perm(22)]*2])) - (tables[0x001d7c20][tables[0x001d8220][perm(36)]*2])),
0x001d8320: ((((tables[0x001e8720][tables[0x002be220][perm(13)]*2]) + (tables[0x00321a20][tables[0x002be220][perm(10)]*2]) + (tables[0x001e8320][tables[0x002be220][perm(12)]*2])) - (tables[0x001e8920][tables[0x002be220][perm(7)]*2])) - (tables[0x001e8520][tables[0x002be220][perm(24)]*2])),
0x001e8b20: ((((tables[0x00311120][tables[0x001f8f20][inp(8)]*2]) + (tables[0x00310b20][tables[0x001f8f20][perm(10)]*2]) + (tables[0x001f8d20][tables[0x001f8f20][perm(28)]*2])) - (tables[0x00352f20][tables[0x001f8f20][perm(27)]*2])) - (tables[0x001f8b20][tables[0x001f8f20][inp(10)]*2])),
0x001f9020: (((((tables[0x00209020][tables[0x00332520][perm(29)]*2]) + (tables[0x00209420][tables[0x00332520][perm(3)]*2])) - (tables[0x00209220][tables[0x00332520][perm(5)]*2])) - (tables[0x00395f20][tables[0x00332520][perm(28)]*2])) - (tables[0x00209420][tables[0x00332520][perm(25)]*2])),
0x00209620: ((((tables[0x00219820][tables[0x0021a020][perm(8)]*2]) + (tables[0x00219e20][perm(26) * 2]) + (tables[0x00219620][tables[0x0021a020][perm(8)]*2])) - (tables[0x00219c20][perm(26) * 2])) - (tables[0x00219a20][perm(26) * 2])),
0x0021a120: (((((tables[0x0022a120][tables[0x0022a720][perm(21)]*2]) + (tables[0x0022a520][tables[0x0022a720][perm(3)]*2])) - (tables[0x0022a320][tables[0x0022a720][perm(3)]*2])) - (tables[0x00385020][tables[0x0022a720][perm(21)]*2])) - (tables[0x0028c520][tables[0x0022a720][perm(14)]*2])),
0x0022a820: ((((tables[0x0023ac20][tables[0x0023ae20][perm(18)]*2]) - ((tables[0x0023aa20][tables[0x0023ae20][perm(35)]*2]) + (tables[0x002ce520][tables[0x0023ae20][perm(17)]*2]))) - (tables[0x00300020][tables[0x0023ae20][perm(3)]*2])) - (tables[0x0023a820][tables[0x0023ae20][perm(3)]*2])),
0x0023af20: ((((tables[0x0024b120][tables[0x0024b320][perm(20)]*2]) + (tables[0x00353520][tables[0x0024b320][perm(24)]*2]) + (tables[0x002df220][tables[0x0024b320][perm(17)]*2])) - (tables[0x0024af20][tables[0x0024b320][perm(15)]*2])) - (tables[0x00300020][tables[0x0024b320][perm(27)]*2])),
0x0024b420: (((((tables[0x0028c320][tables[0x0025b620][perm(8)]*2]) + (tables[0x0025b420][tables[0x0025b620][perm(20)]*2])) - (tables[0x002efb20][tables[0x0025b620][perm(36)]*2])) - (tables[0x00310d20][tables[0x0025b620][perm(33)]*2])) - (tables[0x002ef720][tables[0x0025b620][inp(38)]*2])),
0x0025b720: ((((tables[0x00321a20][tables[0x0026bd20][perm(32)]*2]) + (tables[0x0026bb20][tables[0x0026bd20][perm(17)]*2]) + (tables[0x0026b720][tables[0x0026bd20][perm(23)]*2])) - (tables[0x0026b920][tables[0x0026bd20][perm(7)]*2])) - (tables[0x0026bb20][tables[0x0026bd20][perm(8)]*2])),
0x0026be20: (((((tables[0x00395f20][tables[0x0027c220][perm(7)]*2]) + (tables[0x0027be20][tables[0x0027c220][perm(35)]*2])) - (tables[0x0027c020][tables[0x0027c220][perm(20)]*2])) - (tables[0x002efb20][tables[0x0027c220][perm(17)]*2])) - (tables[0x00353520][tables[0x0027c220][perm(33)]*2])),
0x0027c320: ((((tables[0x002efb20][tables[0x0028c720][perm(19)]*2]) + (tables[0x0029cc20][tables[0x0028c720][perm(21)]*2]) + (tables[0x0028c320][tables[0x0028c720][perm(16)]*2])) - (tables[0x0028c520][tables[0x0028c720][perm(29)]*2])) - (tables[0x002efd20][tables[0x0028c720][perm(19)]*2])),
0x0028c820: (((((tables[0x0029c820][tables[0x0029d020][perm(31)]*2]) + (tables[0x0029ca20][tables[0x0029d020][perm(15)]*2])) - (tables[0x0029ce20][tables[0x0029d020][perm(25)]*2])) - (tables[0x0029cc20][tables[0x0029d020][perm(8)]*2])) - (tables[0x002ce720][tables[0x0029d020][perm(21)]*2])),
0x0029d120: ((((tables[0x00385620][tables[0x002ad920][perm(15)]*2]) - ((tables[0x002ad520][tables[0x002ad920][perm(12)]*2]) + (tables[0x002ad720][tables[0x002ad920][perm(23)]*2]))) - (tables[0x002ad320][tables[0x002ad920][perm(19)]*2])) - (tables[0x002ad120][tables[0x002ad920][perm(9)]*2])),
0x002ada20: (((((tables[0x002ef720][tables[0x002be220][perm(8)]*2]) + (tables[0x002be020][tables[0x002be220][perm(7)]*2])) - (tables[0x002bde20][tables[0x002be220][perm(13)]*2])) - (tables[0x002bdc20][tables[0x002be220][perm(11)]*2])) - (tables[0x002bda20][tables[0x002be220][perm(21)]*2])),
0x002be320: (((((tables[0x002ce320][tables[0x002ce920][perm(12)]*2]) + (tables[0x002ce520][tables[0x002ce920][perm(20)]*2])) - (tables[0x00374b20][tables[0x002ce920][perm(23)]*2])) - (tables[0x002ce720][tables[0x002ce920][perm(25)]*2])) - (tables[0x00374320][tables[0x002ce920][perm(25)]*2])),
0x002cea20: (((tables[0x002dee20][tables[0x002df420][perm(11)]*2]) + (tables[0x002df220][tables[0x002df420][perm(15)]*2]) + (tables[0x002dec20][tables[0x002df420][perm(18)]*2]) + (tables[0x002dea20][tables[0x002df420][perm(28)]*2])) - (tables[0x002df020][tables[0x002df420][perm(20)]*2])),
0x002df520: ((((tables[0x002ef920][tables[0x002eff20][perm(32)]*2]) + (tables[0x002efd20][tables[0x002eff20][perm(19)]*2]) + (tables[0x002ef520][tables[0x002eff20][perm(3)]*2])) - (tables[0x002efb20][tables[0x002eff20][perm(34)]*2])) - (tables[0x002ef720][tables[0x002eff20][perm(36)]*2])),
0x002f0020: ((((tables[0x00300220][tables[0x00300820][perm(3)]*2]) + (tables[0x00300620][tables[0x00300820][perm(5)]*2]) + (tables[0x00300020][tables[0x00300820][perm(13)]*2])) - (tables[0x00300420][tables[0x00300820][perm(11)]*2])) - (tables[0x00321420][tables[0x00300820][perm(36)]*2])),
0x00300920: (((((tables[0x00310b20][tables[0x00311320][perm(33)]*2]) + (tables[0x00311120][tables[0x00311320][perm(19)]*2])) - (tables[0x00310f20][tables[0x00311320][perm(36)]*2])) - (tables[0x00310d20][tables[0x00311320][perm(16)]*2])) - (tables[0x00310920][tables[0x00311320][perm(32)]*2])),
0x00311420: (((tables[0x00321a20][tables[0x00321c20][inp(10)]*2]) + (tables[0x00385420][tables[0x00321c20][perm(10)]*2]) + (tables[0x00321820][tables[0x00321c20][perm(11)]*2]) + (tables[0x00321420][tables[0x00321c20][perm(12)]*2])) - (tables[0x00321620][tables[0x00321c20][perm(29)]*2])),
0x00321d20: (((((tables[0x00331f20][tables[0x00332520][inp(40)]*2]) + (tables[0x00332320][tables[0x00332520][perm(4)]*2])) - (tables[0x00332120][tables[0x00332520][perm(32)]*2])) - (tables[0x00331d20][tables[0x00332520][perm(29)]*2])) - (tables[0x00385020][tables[0x00332520][perm(35)]*2])),
0x00332620: ((((tables[0x00352f20][tables[0x00342e20][perm(34)]*2]) + (tables[0x00342c20][tables[0x00342e20][perm(3)]*2]) + (tables[0x00342620][tables[0x00342e20][perm(35)]*2])) - (tables[0x00342a20][tables[0x00342e20][perm(8)]*2])) - (tables[0x00342820][tables[0x00342e20][perm(16)]*2])),
0x00342f20: (((((tables[0x00353120][tables[0x00353920][perm(23)]*2]) + (tables[0x00353720][tables[0x00353920][perm(23)]*2])) - (tables[0x00353520][tables[0x00353920][perm(9)]*2])) - (tables[0x00353320][tables[0x00353920][perm(28)]*2])) - (tables[0x00352f20][tables[0x00353920][perm(20)]*2])),
0x00353a20: ((((tables[0x00364020][tables[0x00364220][perm(19)]*2]) - ((tables[0x00374b20][tables[0x00364220][perm(19)]*2]) + (tables[0x00363e20][tables[0x00364220][perm(27)]*2]))) - (tables[0x00363c20][tables[0x00364220][perm(16)]*2])) - (tables[0x00363a20][tables[0x00364220][inp(4)]*2])),
0x00364320: ((((tables[0x00374520][tables[0x00374d20][perm(18)]*2]) - ((tables[0x00374920][tables[0x00374d20][perm(8)]*2]) + (tables[0x00374b20][tables[0x00374d20][perm(34)]*2]))) - (tables[0x00374720][tables[0x00374d20][perm(32)]*2])) - (tables[0x00374320][tables[0x00374d20][perm(16)]*2])),
0x00374e20: (((((tables[0x00385220][tables[0x00385820][inp(38)]*2]) + (tables[0x00385620][tables[0x00385820][perm(32)]*2])) - (tables[0x00385420][tables[0x00385820][perm(15)]*2])) - (tables[0x00385020][tables[0x00385820][perm(36)]*2])) - (tables[0x00384e20][tables[0x00385820][perm(33)]*2])),
0x00385920: ((((tables[0x00395f20][tables[0x00396320][inp(12)]*2]) + (tables[0x00396120][tables[0x00396320][perm(17)]*2]) + (tables[0x00395d20][tables[0x00396320][perm(31)]*2])) - (tables[0x00395b20][tables[0x00396320][perm(8)]*2])) - (tables[0x00395920][tables[0x00396320][perm(7)]*2]))
}
return conditions
conditions = generate_conditions(tables_dict, [0x00]*44)
# Check that all the keys correspond to the addresses of the parts
for key in conditions.keys():
if key not in [x+GHIDRA_OFFSET for x in part_starts]:
print("ERROR: ", hex(key))
Z3 solver
s = z3.Solver()
z3_tables = {}
for key in tables_dict.keys():
if len(tables_dict[key]) == 0x200:
z3_tables[key] = z3.Array("array_"+hex(key), z3.BitVecSort(16), z3.BitVecSort(8))
else:
z3_tables[key] = z3.Array("array_"+hex(key), z3.BitVecSort(8), z3.BitVecSort(16))
for key in z3_tables.keys():
for i in range(len(tables_dict[key])):
s.add(z3_tables[key][i] == tables_dict[key][i])
z3_inputs = [z3.BitVec("input_"+str(i), 8) for i in range(45)]
s.add(z3_inputs[0] == ord("E"))
s.add(z3_inputs[1] == ord("C"))
s.add(z3_inputs[2] == ord("W"))
s.add(z3_inputs[3] == ord("{"))
s.add(z3_inputs[44] == ord("}"))
for i in range(45):
s.add(z3_inputs[i] >= 0x20)
s.add(z3_inputs[i] < 0x7f)
conditions = generate_conditions(z3_tables, z3_inputs)
for key in conditions.keys():
s.add(conditions[key] == part_results[part_starts.index(key-GHIDRA_OFFSET)])
print(s.check())
m = s.model()
res = ""
for i in range(45):
res += chr(m[z3_inputs[i]].as_long())
print(res)
sat
ECW{4rR4Ys_4r3_N0_Pr0bl3m_F0r_sUp3er_h4Xx0Rs}