Skip to content

Conversation

@bearlikelion
Copy link

I thought this was a super interesting project, so I took a stab at getting it to compile for Linux to read Windows Godot *.exe's without running it through Wine.

Then, I figured I'd take a shot at adding in an ELF parser.

Testing

I tested with a few free Steam games Pluto Demo, Dogwalk, and Virtual Cottage. It found the proper Godot engine version but none of these games are encrypted so no key to be found.

Architecture

The ELF implementation mirrors the existing PE architecture:

The core feature of this PR was to allow cross-platform compatibility and to be able to run without the need for WINE on Linux.

./keydot -d /mnt/Storage/SteamLibrary/steamapps/common/DOGWALK/dogwalk.x86_64

[CFG] Debug logging enabled
[IO] Detected ELF file
[IO] File size: 69688024 bytes
[IO] Mapped view @ 0x7fec37400000 size=69688024 bytes
[ELF] e_type=2 e_shoff=69685912 e_shnum=33 e_shstrndx=32
[ELF] String table at offset 69685617 size 291
[ELF] Section: .interp addr=0x400350 offset=0x350 size=0x1c
[ELF] Section: .note.gnu.property addr=0x400370 offset=0x370 size=0x30
[ELF] Section: .note.ABI-tag addr=0x4003a0 offset=0x3a0 size=0x20
[ELF] Section: .hash addr=0x4003c0 offset=0x3c0 size=0x964
[ELF] Section: .gnu.hash addr=0x400d28 offset=0xd28 size=0x4c
[ELF] Section: .dynsym addr=0x400d78 offset=0xd78 size=0x1f80
[ELF] Section: .dynstr addr=0x402cf8 offset=0x2cf8 size=0xc7c
[ELF] Section: .gnu.version addr=0x403974 offset=0x3974 size=0x2a0
[ELF] Section: .gnu.version_r addr=0x403c18 offset=0x3c18 size=0x1c0
[ELF] Section: .rela.dyn addr=0x403dd8 offset=0x3dd8 size=0xf0
[ELF] Section: .rela.plt addr=0x403ec8 offset=0x3ec8 size=0x1ed8
[ELF] Section: .init addr=0x406000 offset=0x6000 size=0x17
[ELF] Section: .plt addr=0x406020 offset=0x6020 size=0x14a0
[ELF] Section: .text addr=0x4074c0 offset=0x74c0 size=0x349404e
[ELF] Section: .fini addr=0x389b510 offset=0x349b510 size=0x9
[ELF] Section: .rodata addr=0x389c000 offset=0x349c000 size=0x82ead0
[ELF] Section: pck addr=0x40caad0 offset=0x3ccaad0 size=0x8
[ELF] Section: .eh_frame_hdr addr=0x40caad8 offset=0x3ccaad8 size=0xbaf3c
[ELF] Section: .eh_frame addr=0x4185a18 offset=0x3d85a18 size=0x4dc610
[ELF] Section: .gcc_except_table addr=0x4662028 offset=0x4262028 size=0x5a9d
[ELF] Section: .tdata addr=0x4668c30 offset=0x4267c30 size=0xd
[ELF] Section: .tbss addr=0x4668c40 offset=0x4267c3d size=0x808
[ELF] Section: .init_array addr=0x4668c40 offset=0x4267c40 size=0x50
[ELF] Section: .fini_array addr=0x4668c90 offset=0x4267c90 size=0x10
[ELF] Section: .data.rel.ro addr=0x4668ca0 offset=0x4267ca0 size=0x70c0
[ELF] Section: .dynamic addr=0x466fd60 offset=0x426ed60 size=0x230
[ELF] Section: .got addr=0x466ff90 offset=0x426ef90 size=0x40
[ELF] Section: .got.plt addr=0x466ffe8 offset=0x426efe8 size=0xa60
[ELF] Section: .data addr=0x4670a60 offset=0x426fa60 size=0x56e0
[ELF] Section: .bss addr=0x4676140 offset=0x4275140 size=0x1c8aa8
[ELF] Section: .comment addr=0x0 offset=0x4275140 size=0x31
[ELF] Section: .shstrtab addr=0x0 offset=0x4275171 size=0x123
[ELF] BaseAddress=0x400000
[ELF] Type=ET_EXEC
[ELF] Section count: 32
[SECT] .text VA=0x4074c0 size=0x349404e
[SECT] rodata (.rodata) VA=0x389c000 size=0x82ead0
[SECT] .data VA=0x4670a60 size=0x56e0
[GodotVer] Scanning .rodata for 'Godot Engine' (8579792 bytes)
[GodotVer] Occurrence 1: Godot Engine
[GodotVer] Occurrence 2: Godot Engine project
[GodotVer] Occurrence 3: Godot Engine contributors. (c) 2007-present Juan Linietsky, Ariel Manzur.
[GodotVer] Occurrence 4: Godot Engine v4.4.1.stable.official
[GodotVer] Parsed version: 4.4.1.stable.official
Godot Engine version: 4.4.1.stable.official
[ANCHOR] Searching for: 'Can't open encrypted pack directory.'
[ANCHOR] Hits: 1
[ANCHOR] VA=0x4358110
[find_lea] target_va=0x4358110
[find_lea] No matching LEA instruction found.
[LEA] Not found for anchor VA=0x4358110
[ANCHOR] Searching for: 'Can't open encrypted pack-referenced file '%s'.'
[ANCHOR] Hits: 1
[ANCHOR] VA=0x4357fa8
[find_lea] target_va=0x4357fa8
[find_lea] No matching LEA instruction found.
[LEA] Not found for anchor VA=0x4357fa8
[ANCHOR] Searching for: 'Condition "fae.is_null()" is true.'
[ANCHOR] Hits: 3
[ANCHOR] VA=0x4357fd8
[find_lea] target_va=0x4357fd8
[find_lea] No matching LEA instruction found.
[LEA] Not found for anchor VA=0x4357fd8
[ANCHOR] VA=0x4358138
[find_lea] target_va=0x4358138
[find_lea] No matching LEA instruction found.
[LEA] Not found for anchor VA=0x4358138
[ANCHOR] VA=0x437e978
[find_lea] target_va=0x437e978
[find_lea] No matching LEA instruction found.
[LEA] Not found for anchor VA=0x437e978
Failed to locate the 32-byte key blob using the provided anchors.

@Titoot
Copy link
Owner

Titoot commented Dec 20, 2025

@bearlikelion oh thanks for the contribution
one note to add that even of the key doesn't exist since the game is not encrypted the location of the key do still exists, which from the output debug log I find that it's wrong

on the test game of Dogwalk it found two hits each on Can't open encrypted pack directory. and Can't open encrypted pack-referenced file '%s'. which points to 0x4358110 and 0x4357fd8 respectively which doesn't make sense, it should point to the same address which by manual analysis for the game should be 0x3F7A540 which is obviously is set to zeros since there's no key applied

the original two hits are from these functions at 0x2D68A90 and 0x2D697F0

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants