Online fix

This commit is contained in:
iChris4 committed 2026-09-10 03:30:03 +02:00
1 parent 8a510695dc
commit 0353b76baa
2 files changed
+73 -3

No files matched your search

+12 -3
View File
@@ -130,11 +130,20 @@ inline std::array<uint8_t, 20> Sha1(const uint8_t* data, size_t size) {
using CryptoEcdsa = CryptoPP::ECDSA<CryptoPP::EC2N, CryptoPP::SHA1>;
// ng_priv is a raw 233-bit field and the sect233r1 subgroup order is itself 233
// bits wide, so a genuine keys.bin dump can hold a scalar numerically above the
// order. IOS does not reject those, and Dolphin reduces the key with a single
// conditional subtraction before using it (Common::ec::Sign, the bn_sub_modulus
// on its kk copy), so rejecting one here refuses to build the ES device
// certificate and takes the whole online login down with it. Reduce instead.
// The certificate is unaffected: G has order n, so k*G == (k mod n)*G and the
// published public key is the same point Dolphin derives from the raw scalar.
inline CryptoEcdsa::PrivateKey MakePrivateKey(const uint8_t* key) {
CryptoPP::DL_GroupParameters_EC<CryptoPP::EC2N> parameters(CryptoPP::ASN1::sect233r1());
const CryptoPP::Integer exponent(key, 30);
if (exponent <= CryptoPP::Integer::Zero() || exponent >= parameters.GetSubgroupOrder()) {
throw std::invalid_argument("Wii ES private key is outside the sect233r1 subgroup");
CryptoPP::Integer exponent(key, 30);
exponent %= parameters.GetSubgroupOrder();
if (exponent <= CryptoPP::Integer::Zero()) {
throw std::invalid_argument("Wii ES private key is zero modulo the sect233r1 subgroup order");
}
CryptoEcdsa::PrivateKey privateKey;
+61
View File
@@ -4,6 +4,7 @@
#include "hle_stubs.h"
#include "host_context.h"
#include "runtime_log.h"
#include "system_bridge.h"
// Defined in hle/os/os_sleep.cpp; the sleep-timer table is file-local there.
@@ -13,6 +14,7 @@
#include <iostream>
#include <iomanip>
#include <sstream>
#include <string_view>
namespace Fiber {
@@ -525,6 +527,44 @@ void GuestFiberManager::ProcessTimerEvents(CpuContext* cpu) {
}
}
namespace {
// Windows cannot unwind an exception out of a fiber entry point. Past
// FiberProc there is only RtlUserFiberStart, which terminates the frame chain
// without a handler, so RtlUnwindEx fails and raises STATUS_BAD_FUNCTION_TABLE
// (0xC00000FF) - a noncontinuable exception that kills the process and reports
// the fiber's entry symbol instead of the fault that actually happened. main()
// already guards the primary guest thread with the same catch set; a guest
// OSThread runs on its own fiber and needs the boundary here rather than there.
[[noreturn]] void ReportFatalGuestThreadException(uint32_t guestThreadAddr,
uint32_t entryPoint,
const CpuContext* cpu,
std::string_view category,
std::string_view details) noexcept
{
std::ostringstream message;
message << "guest thread 0x" << std::hex << std::uppercase << guestThreadAddr
<< " (entry 0x" << entryPoint << ")" << std::dec << std::nouppercase
<< " stopped with an unhandled " << category << ".\n" << details;
const std::string text = message.str();
RT_LOG(RT_TAG_OS) << "unhandled " << category << " on guest thread 0x" << std::hex
<< std::uppercase << guestThreadAddr << " (entry 0x" << entryPoint << ")"
<< std::dec << std::nouppercase << ": " << details << std::endl;
SystemBridge::DumpCpuState(cpu);
std::cerr.flush();
// Same artifact set as main()'s handler: MarkFatalErrorReported stops the
// atexit reporter, so the crash log has to be written here.
RuntimeCrash::WriteCrashArtifacts("guest_thread_exception", text);
SetRuntimeExitCode(EXIT_FAILURE);
ShowRuntimeFatalPopup(category, text);
MarkFatalErrorReported();
std::exit(EXIT_FAILURE);
}
} // namespace
#if defined(_WIN32)
void CALLBACK GuestFiberManager::FiberProc(void* param)
#else
@@ -583,6 +623,11 @@ void GuestFiberManager::FiberProc(void* param)
// Create a CpuContextScope for this fiber
CpuContextScope scope(cpu);
// A fault anywhere in this guest thread - translated code, an HLE hook or a
// guest callback - must be reported here. See
// ReportFatalGuestThreadException: unwinding past a fiber entry is not
// representable on Windows and destroys the diagnostic.
try {
int startDeferAttempts = 0;
while (entryPoint == 0x8024373c) { // EGG::Thread::start
uint32_t vtable = 0;
@@ -662,6 +707,22 @@ void GuestFiberManager::FiberProc(void* param)
}
s_currentGuestThread = 0;
}
} catch (const Memory::AccessViolation& ex) {
std::ostringstream details;
details << "addr=0x" << std::hex << std::uppercase << ex.address()
<< " len=0x" << ex.length() << std::dec << std::nouppercase
<< " reason=" << ex.reason();
ReportFatalGuestThreadException(guestThreadAddr, entryPoint, cpu,
"a guest memory access was out of bounds",
details.str());
} catch (const std::exception& ex) {
ReportFatalGuestThreadException(guestThreadAddr, entryPoint, cpu,
"a runtime exception occurred", ex.what());
} catch (...) {
ReportFatalGuestThreadException(guestThreadAddr, entryPoint, cpu,
"a runtime exception occurred",
"the exception carried no details");
}
// Return to scheduler
HostContext::Switch(s_schedulerFiber);