mirror of
https://github.com/boykopovar/AnyPS5.git
synced 2026-10-30 12:25:49 +00:00
fix(relinker): refuse branches into trapped guest GS instructions on Windows
Windows output replaced each guest GS memory instruction with UD2 and NOP fill without checking the decoded direct branch targets, so a branch past the first byte of such an instruction was converted and landed in the second UD2 byte or the NOP fill. A branch target strictly inside a trapped GS instruction is now refused with "Branch enters a guest GS instruction", the rule macOS applies since #7706 and this builder already applies to its FS rewrites. The branch targets are sorted before the trap loop, which runs before the PT_TLS early returns, so images without PT_TLS are covered; guest modules go through the same builder. A branch to the first byte still converts and reaches the UD2.
This commit is contained in:
1 parent
befe264ffb
commit
7424949b8b
2 files changed
+9
-4
No files matched your search
@@ -221,8 +221,14 @@ PeDirectory WindowsTlsBuilder::Build(const std::vector<std::uint8_t>& source, co
|
||||
}
|
||||
|
||||
report(9000);
|
||||
for (const auto& [rva, length] : gsTraps)
|
||||
std::sort(branchTargets.begin(), branchTargets.end());
|
||||
branchTargets.erase(std::unique(branchTargets.begin(), branchTargets.end()), branchTargets.end());
|
||||
for (const auto& [rva, length] : gsTraps) {
|
||||
const auto target = std::upper_bound(branchTargets.begin(), branchTargets.end(), rva);
|
||||
if (target != branchTargets.end() && *target < rva + length)
|
||||
throw Domain::RelinkerException("Branch enters a guest GS instruction", *target);
|
||||
trapInstruction(sections, rva, length);
|
||||
}
|
||||
if (tls == nullptr) {
|
||||
if (!accesses.empty())
|
||||
throw Domain::RelinkerException("Guest TLS access without PT_TLS");
|
||||
@@ -274,9 +280,6 @@ PeDirectory WindowsTlsBuilder::Build(const std::vector<std::uint8_t>& source, co
|
||||
code.PatchBranch(skipCallback, code.GetRva());
|
||||
code.Emit({0xc3});
|
||||
|
||||
std::sort(branchTargets.begin(), branchTargets.end());
|
||||
branchTargets.erase(std::unique(branchTargets.begin(), branchTargets.end()), branchTargets.end());
|
||||
|
||||
std::uint64_t patched = 0;
|
||||
for (const auto& access : accesses) {
|
||||
if (patched % 256 == 0) report(9000 + 900 * patched / accesses.size());
|
||||
|
||||
@@ -777,6 +777,8 @@ def main():
|
||||
conflicting[232:344] = unwind[232:344]
|
||||
struct.pack_into("<H", conflicting, 56, 5)
|
||||
convert("conflicting-function-extents", conflicting, "Code analysis: conflicting function ranges")
|
||||
convert("branch-into-gs", make_image("register", "unwind", body=bytes.fromhex("74 01 65 48 8b 0c 25 78 03 00 00 c3")),
|
||||
"Branch enters a guest GS instruction", error_offset=0x11243)
|
||||
|
||||
def check_gs_traps(cases):
|
||||
for name, instruction, trapped in cases:
|
||||
|
||||
Reference in new issue
Block a user