"""Unit tests for skills/exe-reverse/scripts/dart_snapshot_strings.py, the Dart AOT string reader. The input is an ELF shared object and no sample may be committed, so the container is generated by `conftest.build_synthetic_elf`: a valid ELF64 header, a `.text` of sixteen bytes, a `.rodata` with one one-byte (ASCII) literal and one two-byte (UTF-16LE) literal at known offsets, and a section-name string table. Offsets are read from the fixture's own record of where it put each literal, never hardcoded here. What the synthetic image cannot do is be a real snapshot. Literal recovery is what these tests hold: a one-byte and a two-byte literal at known offsets, a case-insensitive filter, and an offset probe that resolves anywhere a literal occupies. The instruction-level observations this file once carried are **withdrawn** -- a byte scan cannot read this format, and the reference records why -- so nothing here asserts anything about how a reference is encoded. """ import pytest pytestmark = pytest.mark.unit ONE_BYTE = "one-byte" TWO_BYTE = "two-byte" # The two idioms the observer counts, assembled here so the positive cases are built rather than # asserted from a table. `49 8B /r` is a load through r15 -- Dart's pool pointer; `48 8B 05` is a # RIP-relative load, which the docstring records as near-absent in a real image. POOL_LOAD = bytes((0x49, 0x8B, 0x87, 0x10, 0x00, 0x00, 0x00)) FILLER = bytes((0x90,)) * 8 def text_section(data, vaddr=0x1000, offset=0): return {"offset": offset, "vaddr": vaddr, "size": len(data)} def hex_bytes(*values): return bytes(values) # --- the container ----------------------------------------------------------- def test_the_fixture_is_an_elf_shared_object_the_reader_accepts(load_script, synthetic_elf): dss = load_script("dart_snapshot_strings.py") elf = dss.Elf(synthetic_elf.data, str(synthetic_elf.path)) assert elf.machine == 0x3E assert elf.etype == 3 described = elf.describe() assert described["machine"] == "x86-64" assert described["type"] == "shared-object" assert [s["name"] for s in described["sections"]] == [".text", ".rodata", ".shstrtab"] def test_the_fixture_is_the_size_the_builder_promised(synthetic_elf): assert len(synthetic_elf.data) == synthetic_elf.size assert synthetic_elf.size < 0x1000, "a virtual address above this cannot be a file offset" def test_sections_are_found_by_name(load_script, synthetic_elf): dss = load_script("dart_snapshot_strings.py") elf = dss.Elf(synthetic_elf.data) text = elf.section(".text") rodata = elf.section(".rodata") assert text["offset"] == synthetic_elf.text["offset"] assert text["vaddr"] == synthetic_elf.text["vaddr"] assert text["size"] == synthetic_elf.text["size"] assert rodata["offset"] == synthetic_elf.rodata["offset"] assert rodata["vaddr"] == synthetic_elf.rodata["vaddr"] assert rodata["size"] == synthetic_elf.rodata["size"] assert elf.section(".absent") is None @pytest.mark.parametrize("mutation,message", [ (lambda d: bytearray(b"not an elf image at all" + bytes(64)), "not an ELF image"), (lambda d: bytearray(b"\x7fELF" + d[4:]), None), # a valid image (lambda d: bytearray(d[:4] + bytes((1,)) + d[5:]), "not a 64-bit ELF"), (lambda d: bytearray(d[:5] + bytes((2,)) + d[6:]), "not little-endian"), (lambda d: bytearray(d[:0x30]), "not an ELF image"), # truncated header ]) def test_the_reader_refuses_a_container_it_cannot_read(load_script, synthetic_elf, mutation, message): """A refusal is a ValueError with a reason; the CLI turns it into the documented exit code.""" dss = load_script("dart_snapshot_strings.py") data = mutation(bytearray(synthetic_elf.data)) if message is None: assert dss.Elf(bytes(data)).etype == 3 return with pytest.raises(ValueError) as excinfo: dss.Elf(bytes(data)) assert message in str(excinfo.value) def test_the_address_maps_round_trip(load_script, synthetic_elf): dss = load_script("dart_snapshot_strings.py") elf = dss.Elf(synthetic_elf.data) for entry in synthetic_elf.literals: assert elf.vaddr_to_offset(entry["vaddr"]) == entry["offset"] assert elf.offset_to_vaddr(entry["offset"]) == entry["vaddr"] assert elf.vaddr_to_offset(0xDEADBEEF) is None assert elf.offset_to_vaddr(0xFFFFFF) is None # --- literal recovery -------------------------------------------------------- def test_every_literal_in_the_fixture_is_recovered_at_the_offset_it_was_placed( load_script, synthetic_elf): dss = load_script("dart_snapshot_strings.py") elf = dss.Elf(synthetic_elf.data) recovered = dss.recover_strings(synthetic_elf.data, elf.section(".rodata")) assert [(off, va, text, enc) for off, va, text, enc in recovered] == [ (entry["offset"], entry["vaddr"], entry["text"], entry["encoding"]) for entry in synthetic_elf.literals] def test_both_encodings_are_recovered(load_script, synthetic_elf): """A keyword search that only reads ASCII misses half of a localised application's literals.""" dss = load_script("dart_snapshot_strings.py") elf = dss.Elf(synthetic_elf.data) recovered = dss.recover_strings(synthetic_elf.data, elf.section(".rodata")) by_encoding = {} for _off, _va, text, encoding in recovered: by_encoding.setdefault(encoding, set()).add(text) assert by_encoding[ONE_BYTE] == {"premium_license", "trial_mode"} assert by_encoding[TWO_BYTE] == {"vip_pass"} def test_a_two_byte_literal_reports_byte_offsets_and_character_counts(load_script, synthetic_elf): """Pinned, because the two units differ by a factor of two for this encoding. The offsets are bytes; the text is characters. `--at` filters on `offset <= at < offset + len(text)`, so for a two-byte literal it accepts only the first half of the bytes the literal occupies. Measured here as a unit fact; the CLI layer pins the effect. """ dss = load_script("dart_snapshot_strings.py") entry = synthetic_elf.literal("vip_pass") recovered = dss.recover_strings(synthetic_elf.data, dss.Elf(synthetic_elf.data).section(".rodata")) offset, vaddr, text, encoding = [row for row in recovered if row[0] == entry["offset"]][0] assert (offset, vaddr, encoding) == (entry["offset"], entry["vaddr"], TWO_BYTE) assert text == "vip_pass" assert len(text) * 2 == 16, "sixteen bytes on disk, eight characters reported" def test_a_two_byte_run_does_not_glue_the_tail_of_one_literal_to_the_next(load_script): """A run is reported from its own first byte, never from the tail of the literal before it. This used to be a false positive. The scan accepted *any* printable byte followed by a NUL -- which is exactly the shape of the last character of an ASCII literal plus its alignment byte -- so a two-byte literal beginning right after one was reported as a literal that does not exist, at an offset inside a different one. Both directions are asserted here, because the cheap fix for the glue error (skip anything preceded by a character-shaped pair) reintroduces the opposite one: the real run then starts with its own bytes looking like an interior position. """ dss = load_script("dart_snapshot_strings.py") ascii_part = b"odd_phase_literal\x00" assert len(ascii_part) % 2 == 0, "the two-byte run needs to start at an even offset" data = ascii_part + "vip_pass".encode("utf-16-le") + b"\x00\x00" recovered = dss.recover_strings(data, {"offset": 0, "vaddr": 0x1000, "size": len(data)}) texts = [row[2] for row in recovered] assert "odd_phase_literal" in texts assert "vip_pass" in texts, texts assert "lvip_pass" not in texts, "the tail of the ASCII literal was glued onto the next run" assert texts.count("vip_pass") == 1 def test_a_two_byte_literal_landing_at_an_odd_offset_is_recovered(load_script): """A two-byte run at an odd offset is found, and the run before it does not manufacture one. Two errors lived here. The scan stepped through the two-byte form from the section base, so a run shifted to an odd offset -- which one odd-length literal is enough to do -- was never examined and was missed whole. Advancing one byte at a time fixes that, and the second half of this test guards the error it introduces: the tail of an even-length one-byte literal is a printable byte followed by alignment, which reads as the start of a two-byte run and yields a literal that does not exist. """ dss = load_script("dart_snapshot_strings.py") ascii_part = b"even_phase_liter\x00" assert len(ascii_part) % 2 == 1, "the two-byte run needs to start at an odd offset" data = ascii_part + "vip_pass".encode("utf-16-le") + b"\x00\x00" recovered = dss.recover_strings(data, {"offset": 0, "vaddr": 0x1000, "size": len(data)}) texts = [row[2] for row in recovered] assert "vip_pass" in texts, texts assert "even_phase_liter" in texts, texts # No phantom literal: a run is reported once, from its own first byte. assert texts.count("vip_pass") == 1 two_byte = [row for row in recovered if row[3] == "two-byte"] assert len(two_byte) == 1, two_byte # An even-length one-byte literal before a two-byte run must not start a phantom run. data2 = b"even_phase_lite\x00" + "vip_pass".encode("utf-16-le") + b"\x00\x00" got2 = [row[2] for row in dss.recover_strings( data2, {"offset": 0, "vaddr": 0x1000, "size": len(data2)})] assert "vip_pass" in got2, got2 assert "vip_pass"[0] not in [t for t in got2 if t != "vip_pass"], got2 def test_min_length_drops_the_shorter_literals(load_script, synthetic_elf): dss = load_script("dart_snapshot_strings.py") rodata = dss.Elf(synthetic_elf.data).section(".rodata") long_only = dss.recover_strings(synthetic_elf.data, rodata, min_length=12) assert [row[2] for row in long_only] == ["premium_license"] everything = dss.recover_strings(synthetic_elf.data, rodata, min_length=6) assert {row[2] for row in everything} == {"premium_license", "trial_mode", "vip_pass"} def test_the_limit_caps_how_many_literals_come_back(load_script, synthetic_elf): dss = load_script("dart_snapshot_strings.py") rodata = dss.Elf(synthetic_elf.data).section(".rodata") assert len(dss.recover_strings(synthetic_elf.data, rodata, limit=1)) == 1 assert len(dss.recover_strings(synthetic_elf.data, rodata, limit=2)) == 2 def test_a_section_claiming_more_bytes_than_the_file_holds_is_clamped(load_script, synthetic_elf): """A truncated image must not read past the end; the reader clamps to the data it has.""" dss = load_script("dart_snapshot_strings.py") truncated = synthetic_elf.data[:synthetic_elf.rodata["offset"] + 0x10] rodata = dict(synthetic_elf.rodata, size=synthetic_elf.rodata["size"] + 0x1000) recovered = dss.recover_strings(truncated, rodata) assert [row[2] for row in recovered] == ["premium_license"] def test_the_code_section_yields_no_literals(load_script, synthetic_elf): """The fixture's `.text` is sixteen bytes of instructions, so nothing survives the length gate.""" dss = load_script("dart_snapshot_strings.py") text = dss.Elf(synthetic_elf.data).section(".text") assert dss.recover_strings(synthetic_elf.data, text) == [] # --- pool observation --------------------------------------------------------