Commit Graph

224 Commits

Author SHA1 Message Date
Adrià 9e2ffe0da4
Merge pull request #1457 from drk1rd/fix/relinker-ud1-trap
fix(relinker): decode UD1 as a trap
2026-10-08 16:17:06 +02:00
Adrià 94d03f29fa
Merge pull request #1454 from mrk1987/fix/windows-internal-guest-libc
fix(relinker): resolve internal libc imports from guest libc
2026-10-08 16:07:33 +02:00
Adrià 63c57d2222
Merge pull request #1432 from ToyuAU/build/standalone-relinker
build(relinker): add a dependency-free conversion build mode
2026-10-08 15:43:51 +02:00
Adrià 033a46360d
Merge pull request #1424 from muhzain05/fix/relinker-jmprel-bounds
fix(relinker): bound the jump relocation table range
2026-10-08 15:39:32 +02:00
Adrià fd5f63a2d0
Merge pull request #1393 from xsvm/fix/relinker-rewriter-reference-sites
fix(relinker): classify rewrite reference sites with the instruction decoder
2026-10-08 15:03:48 +02:00
Adrià 2a906716f9
Merge pull request #1403 from overlordxrz-source/refactor/relinker-read-needed-once
refactor(relinker): read the executable's DT_NEEDED entries in one place
2026-10-08 15:00:52 +02:00
muhzain05 19f2fcf059 fix(relinker): bound the jump relocation table range
DT_JMPREL and DT_PLTRELSZ were never range-checked against the input
file. With DT_OS_JMPREL the offset is used raw, so an offset outside the
image reached BuildDynamicSection and CompactPlt. When DT_PLTRELSZ is
zero the per-entry loops never run, so nothing rejected the table and
the relink produced an output executable.

Validate the declared range with the subtraction-based check already
used for DT_STRTAB and DT_STRSZ, next to it and before the table is
read.
2026-10-08 05:25:08 -06:00
Gjon Gojcevic 90dcd6256c fix(relinker): tolerate unwind ranges that split an instruction
A static branch into a skipped function tail is accepted when an
instruction decodes there within its executable segment, so a range that
ends inside an instruction no longer stops code analysis.

The Windows TLS rewriter skips a non-FS segment-prefixed instruction that
starts inside an earlier collected instruction: it is an alternative
decoding from a range that begins mid-instruction, not a TLS access.
2026-10-08 13:20:32 +02:00
Dean Galvin 2096c66a91 revert: undo #1156's bundled libc lifecycle suppression
Since #1156 a title's bundled sce_module/libc.prx is loaded for its
exports but its init is suppressed, while titles still call its malloc,
which then returns NULL (#1500). On Linux, titles that bundle libc crash
at launch: one segfaults within 0.2 s, another stops with bad_alloc.

This reverts commit 2d6aff7a1e, reversing
changes made to e82e03f11e.
2026-10-08 23:49:41 +13:00
xsvm 22ebf5e608 fix(relinker): classify rewrite reference sites with the instruction decoder
ClassifyInstruction assumed a ModRM byte right after every opcode that
was not a near branch. A length-changing rewrite therefore adjusted
immediates such as MOVABS imm64 that looked like a RIP-relative ModRM,
and missed RIP-relative operands of VEX and 0F 38 / 0F 3A instructions
and the rel8 targets of LOOP and JRCXZ. Take the RIP-relative
displacement and branch target from DecodeInstruction instead.
2026-10-08 18:20:14 +08:00
Suryansh Prajapati 7a3ec9f015 fix(relinker): decode UD1 as a trap
UD1 (0F B9 /r) always raises #UD, like UD2, but DecodeInstruction
reported it as sequential. Reachability analysis then followed the
bytes after it, so an import reachable only through that fallthrough
was kept by the strict unused NID filter. UD1 keeps its ModRM, so a
RIP-relative operand is still reported.
2026-10-08 15:26:54 +05:30
Adrià 73ac9ef7f4
Merge pull request #1218 from hashaam1217/feat/relinker-rip-relative-stubs
feat(relinker): relocate RIP-relative operands into --to-intel stubs
2026-10-08 11:40:17 +02:00
Dean 1bd8f07ccd
Merge pull request #1317 from Dextroid17/fix/name-both-self-container-magics
fix(relinker): name the second SELF container magic as a SELF input
2026-10-08 22:36:28 +13:00
Dean 9e5ade70fb
Merge pull request #1381 from overlordxrz-source/fix/relinker-decoder-0f-no-modrm
fix(relinker): decode 0F A8-AA without a ModRM and MOV CR/DR without a memory operand
2026-10-08 22:35:44 +13:00
Dean a753d0de45
Merge pull request #1303 from overlordxrz-source/fix/relinker-evex-grp3-immediate
fix(relinker): do not add the F6/F7 TEST immediate to EVEX instructions
2026-10-08 22:35:39 +13:00
Adrià 0802d02713
Merge pull request #1242 from hashaam1217/fix/program-header-entry-size
fix(relinker): reject a program header entry size other than 56 bytes
2026-10-08 11:28:29 +02:00
Adrià 296d68a31d
Merge pull request #1238 from hashaam1217/fix/windows-overlapping-load-segments
fix(relinker): reject overlapping PT_LOAD segments before sizing the Windows image
2026-10-08 11:14:58 +02:00
Adrià 71a0eab968
Merge pull request #1233 from hashaam1217/feat/windows-tls-register-loads
feat(relinker): load Windows guest TLS values through register addresses
2026-10-08 11:11:10 +02:00
Hashaam Zafar a571a7f100 feat(relinker): relocate RIP-relative operands into --to-intel stubs
SHA-1 and SHA-256 instructions with a [rip+disp32] operand, and
instructions with one that a short site absorbs, now move into the
stub. The stub records each displacement as a relocation relative to
the site, and the Linux, guest and Windows placements resolve it once
the stub address is known. Indirect branches through [rip+disp32]
still fail the relink.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 11:10:38 +02:00
Adrià 2d6aff7a1e
Merge pull request #1156 from ahir061/fix/linux-bundled-libc-lifecycle
fix(relinker): suppress duplicate system library lifecycle
2026-10-08 11:03:20 +02:00
Adrià 0703d818d0
Merge pull request #1194 from ASVLCII/fix/relinker-input-validation-20261007
fix(relinker): reject incomplete RELA entries
2026-10-08 10:49:19 +02:00
Adrià 2959dc5318
Merge pull request #1168 from oguzhanozfe/fix/decoder-moffs-length
fix(relinker): decode the 64-bit address of MOV moffs instructions
2026-10-08 10:39:59 +02:00
Adrià Franch 402cd1545e test(relinker): give the lifecycle fixture a non-executable stack header
glibc 2.41+ refuses to dlopen a module without PT_GNU_STACK, so the native
part of guest_lifecycle_ownership failed on current distributions.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-08 10:27:52 +02:00
Adrià 8388121a4f
Merge pull request #1153 from ebarr24/codex/windows-gui-error-status
fix(relinker): preserve GUI startup failure status without stderr
2026-10-08 10:26:56 +02:00
Adrià 17440abe24
Merge pull request #1165 from oguzhanozfe/fix/linux-dynstr-runpath-size
fix(relinker): include the run path in the Linux DT_STRSZ
2026-10-08 10:25:19 +02:00
Adrià 61896dea23
Merge pull request #1163 from oguzhanozfe/fix/decoder-rexw-immediate-size
fix(relinker): let REX.W override 0x66 when sizing decoder immediates
2026-10-08 10:23:35 +02:00
Ahir Barman Maji b12022bb4e test(relinker): fix Windows lifecycle fixture build 2026-10-08 10:22:40 +02:00
Ahir Barman Maji 9517cc33f8 fix(relinker): suppress duplicate system library lifecycle 2026-10-08 10:22:40 +02:00
Adrià f51eeff059
Merge pull request #1117 from TideOPL/fix/relinker-tls-unreached-code
fix(relinker): find Windows guest TLS accesses in code no root reaches
2026-10-08 09:54:40 +02:00
mrk1987 2050d84595 test(relinker): isolate guest libc resolution coverage 2026-10-08 09:43:52 +02:00
mrk1987 b64bb679cc fix(relinker): resolve internal libc imports from guest libc 2026-10-08 09:23:13 +02:00
ToyuAU 2d59fffdb7 build(relinker): add a dependency-free conversion build mode 2026-10-08 18:21:30 +11:00
Adrià 66b8abd8e6
Merge pull request #1101 from eliasbruno124-dev/fix/relinker-windows-guest-filenames
fix(relinker): resolve Windows guest filename casing
2026-10-08 08:43:35 +02:00
Adrià 7a178e2276
Merge pull request #1089 from AaravMehta-07/fix/relinker-registry-json
fix(relinker): escape control characters in call registry JSON
2026-10-08 08:10:07 +02:00
Adrià Franch 4e69584edf test(relinker): pin RELA bounds check with malformed-ELF cases
Co-authored-by: Dextroid17 <noreply@github.com>
Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-08 07:52:32 +02:00
Fynn Jannis Schulz 9ff9d4325c fix(relinker): share RELA entry bounds check with extractRelative 2026-10-08 07:52:23 +02:00
Fynn Jannis Schulz cfba9c09d2 fix(relinker): overflow-safe RELA entry bounds check 2026-10-08 07:52:23 +02:00
Dean 4a435af58a
Merge pull request #1103 from ctz23/test/windows-icon-distinct-output-20261007
test(relinker): use distinct executables in Windows icon tests
2026-10-08 18:28:01 +13:00
overlordxrz-source cd51d8b1bf refactor(relinker): read the executable's DT_NEEDED entries in one place 2026-10-07 22:31:35 -04:00
overlordxrz-source e66d78c626 fix(relinker): decode 0F A8-AA without a ModRM and MOV CR/DR without a memory operand
PUSH GS, POP GS and RSM (0F A8, 0F A9, 0F AA) have no ModRM byte, but fell in the 0F A3-AB ModRM range, so the decoder read the next byte as a ModRM and sized its displacement. MOV to and from control and debug registers (0F 20-23) ignore the ModRM mod field and always name a register, but were sized and reported as memory forms, including a RIP-relative disp32 for mod 00 r/m 101.
2026-10-07 21:14:30 -04:00
Dextroid17 9fce570e95 fix(relinker): name the second SELF container magic as a SELF input
ElfReader::ReadHeader names 0x1D3D154F as a SELF container, but dumps also
carry a second container magic, 0xEEF51454 (bytes 54 14 f5 ee), which fell
through to "Invalid ELF magic number: 54 14 f5 ee". That message reads as a
corrupt input rather than an encrypted one, so a user cannot tell that
decryption is what stands between them and a relink.

Both magics now report the SELF message. Measured on two retail dumps:
PPSA03671's eboot.bin and libcohtml.Prospero.prx are 54 14 f5 ee; PPSA28997's
eboot and modules are 4f 15 3d 1d.

Tested: Linux (CachyOS, GCC, Release, BUILD_TESTING=ON), relinker rebuilt. The
new case fails on the revert of the reader change with the exact message above
and passes with it; elf_header, elf_offsets, dynamic_segment,
string_table_bounds, guest_needed_modules, guest_module_directories and
linux_load_alignment still pass.
2026-10-07 19:28:04 -04:00
overlordxrz-source f4ef1cd6ec fix(relinker): do not add the F6/F7 TEST immediate to EVEX instructions
The decoder adds the TEST immediate of opcodes F6 and F7 when ModRM.reg
is 0 or 1. The check excluded VEX and two-byte opcodes but not EVEX, so
an EVEX.0F F6 (VPSADBW) whose ModRM.reg is 0 or 1 was given an extra
imm8 and decoded one byte too long. VPSADBW has no immediate (Intel SDM
Vol. 2B, VPSADBW).
2026-10-07 18:51:05 -04:00
Hashaam Zafar 33ab7c90f9 fix(relinker): reject a program header entry size other than 56 bytes
ReadProgramHeaders stepped through the table by e_phentsize without
checking it. With 0 it read the first header e_phnum times, and with
any other size it read misaligned fields, so a damaged header failed
much later as "No PT_DYNAMIC segment found", after building up to
65535 copies of one segment. A non-empty table must now use 56-byte
entries, as the guest module reader already requires.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 12:08:14 -07:00
Hashaam Zafar a8f862b6df fix(relinker): reject overlapping PT_LOAD segments before sizing the Windows image
WindowsLoadImage sized its data and page table from the end of the last
segment and checked for overlap while copying. A segment whose memory
size reached past the last segment's end wrote page flags past the
table before its overlap was found; the relinker crashed with SIGSEGV
on such an input. Overlap is now checked in a pass before sizing.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 12:05:05 -07:00
Hashaam Zafar 71b9cf3d0d test(relinker): run the Windows TLS cases on Linux x86-64
tls_function_coverage ran its execution cases only on Windows; on
Linux it checked bytes. windows_image_runner.py maps the relinked PE,
points GS at a TEB whose TLS slot holds a block copied from the
template, runs the TLS callbacks for process attach with the Windows
argument registers and calls the guest entry. convert() uses it on
Linux x86-64 and expects 42, as on Windows.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 11:52:14 -07:00
Hashaam Zafar ace7999dce feat(relinker): load Windows guest TLS values through register addresses
mov r64 and mov r32 from fs:[mem], where mem has a base or an index
register, now relink for Windows (64 48 8b 03, mov rax, fs:[rbx], in
#217). The stub computes the offset with lea on the original address,
adds the thread pointer and loads.

These sites can be shorter than the 5-byte jump. A short site moves the
following sequential instructions into its stub and relocates
RIP-relative ones; a branch, a return or another TLS access after it
fails the relink. A TLS site shorter than a jump is now rejected instead
of overwriting the next instruction.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 11:44:34 -07:00
Nguyen Phuong Thuy 3b35a674f3 fix(relinker): reject incomplete RELA entries 2026-10-07 16:41:20 +00:00
Ethan Barr 2ed81aebe4 fix(relinker): preserve GUI startup failure status without stderr 2026-10-07 09:38:56 -07:00
Oguzhan Ozdemir e8f73a5531 fix(relinker): decode the 64-bit address of MOV moffs instructions
A0-A3 (MOV AL/eAX/rAX to and from moffs) have no ModRM byte and carry an
8-byte absolute address in 64-bit mode, or 4 bytes with a 0x67 prefix.
The decoder added nothing for the address, so the linear scanner decoded
the address bytes as code.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 19:00:37 +03:00
Oguzhan Ozdemir cf8b7315b6 fix(relinker): include the run path in the Linux DT_STRSZ
The Linux patcher appends the DT_RUNPATH string after the copied
.dynstr data but kept DT_STRSZ and the .dynstr section size at the size
of the copied data, so DT_RUNPATH pointed at the first byte past the
declared string table.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 18:58:42 +03:00