mirror of
https://github.com/spice2x/spice2x.github.io.git
synced 2026-08-02 06:40:42 -07:00
iidx, sdvx: bi2x hook fix (attempt 2) (#499)
## Link to GitHub Issue, if one exists see my previous attempt #496, which has been reverted by #500 ## Description of change Two issues: 1. the original implementation of bi2x_hook for iidx misunderstood what `aioNMgrIob2_Create` does. In the original I/O code it returns a pointer to a C++ class instance, which would also have a vptr (pointer to a vtable) in the beginning. The original author of this code of the hook in spice thought that `aioNMgrIob2_Create` returns a pointer to a pointer. This may happen to work but it's not 100% accurate, so this has been fixed by separating out the class and the vtable allocation. Without this, the game could have accessed memory outside this buffer. 2. And then the SDVX implementation blindly copy-pasted the IIDX `bi2x_hook`. Along with the issue above, they also forgot to check the I/O DLLs to see how much memory needs to be allocated and change that. Instead, they kept the same value as IIDX, which was too small. Fix that as well. ## Testing Doing some extensive testing with IIDX (27-33) and SDVX versions (EG).
This commit is contained in:
@@ -1,5 +1,7 @@
|
||||
#include "bi2x_hook.h"
|
||||
|
||||
#if SPICE64
|
||||
|
||||
#include <cstdint>
|
||||
#include "util/detour.h"
|
||||
#include "util/logging.h"
|
||||
@@ -15,7 +17,6 @@
|
||||
|
||||
namespace games::sdvx {
|
||||
constexpr bool BI2X_PASSTHROUGH = false;
|
||||
bool BI2X_INITIALIZED = false;
|
||||
|
||||
/*
|
||||
* class definitions
|
||||
@@ -26,17 +27,28 @@ namespace games::sdvx {
|
||||
uint8_t data[0x10];
|
||||
};
|
||||
|
||||
struct AIO_NMGR_IOB2 {
|
||||
uint8_t dummy0[0x50];
|
||||
struct AIO_NMGR_IOB2_VTABLE {
|
||||
// other functions here, but they never get called
|
||||
uint8_t dummy[0x50];
|
||||
void (__fastcall *pAIO_NMGR_IOB_BeginManage)(int64_t a1);
|
||||
uint8_t dummy1[0x9A0];
|
||||
};
|
||||
|
||||
struct AIO_NMGR_IOB2 {
|
||||
AIO_NMGR_IOB2_VTABLE *vptr;
|
||||
uint8_t dummy[0x9F0];
|
||||
};
|
||||
|
||||
// confirmed in EG final in aioNMgrIob2_Create
|
||||
static_assert(sizeof(AIO_NMGR_IOB2) == 0x9F8);
|
||||
|
||||
struct AIO_IOB2_BI2X_UFC {
|
||||
// who knows
|
||||
uint8_t data[0x13F8];
|
||||
uint8_t data[0x39D8];
|
||||
};
|
||||
|
||||
// confirmed in EG final in aioIob2Bi2xUFC_Create
|
||||
static_assert(sizeof(AIO_IOB2_BI2X_UFC) == 0x39D8);
|
||||
|
||||
struct AIO_IOB2_BI2X_UFC__DEVSTATUS {
|
||||
// of course you could work with variables here
|
||||
uint8_t buffer[0x19E];
|
||||
@@ -66,7 +78,7 @@ namespace games::sdvx {
|
||||
// libaio-iob.dll
|
||||
typedef AC_HNDLIF* (__fastcall *aioIob2Bi2x_OpenSciUsbCdc_t)(uint8_t device_num);
|
||||
typedef int64_t (__fastcall *aioIob2Bi2x_WriteFirmGetState_t)(int64_t a1);
|
||||
typedef AIO_NMGR_IOB2** (__fastcall *aioNMgrIob2_Create_t)(AC_HNDLIF *a1, unsigned int a2);
|
||||
typedef AIO_NMGR_IOB2* (__fastcall *aioNMgrIob2_Create_t)(AC_HNDLIF *a1, unsigned int a2);
|
||||
|
||||
/*
|
||||
* function pointers
|
||||
@@ -345,21 +357,21 @@ namespace games::sdvx {
|
||||
log_info("bi2x_hook", "AIO_NMGR_IOB::BeginManage");
|
||||
}
|
||||
|
||||
static AIO_NMGR_IOB2** __fastcall aioNMgrIob2_Create(AC_HNDLIF *a1, unsigned int a2) {
|
||||
static AIO_NMGR_IOB2* __fastcall aioNMgrIob2_Create(AC_HNDLIF *a1, unsigned int a2) {
|
||||
if (aioNmgrIob2 == nullptr) {
|
||||
aioNmgrIob2 = new AIO_NMGR_IOB2;
|
||||
memset(aioNmgrIob2, 0x0, sizeof(AIO_NMGR_IOB2));
|
||||
aioNmgrIob2->pAIO_NMGR_IOB_BeginManage = AIO_NMGR_IOB_BeginManageStub;
|
||||
aioNmgrIob2 = new AIO_NMGR_IOB2{};
|
||||
aioNmgrIob2->vptr = new AIO_NMGR_IOB2_VTABLE{};
|
||||
aioNmgrIob2->vptr->pAIO_NMGR_IOB_BeginManage = AIO_NMGR_IOB_BeginManageStub;
|
||||
}
|
||||
log_info("bi2x_hook", "aioNMgrIob2_Create");
|
||||
BI2X_INITIALIZED = true;
|
||||
log_info("bi2x_hook", "aioNMgrIob2_Create returned {}, size=0x{:x}, vptr @ {}",
|
||||
fmt::ptr(aioNmgrIob2), sizeof(*aioNmgrIob2), fmt::ptr(aioNmgrIob2->vptr));
|
||||
|
||||
// enable hack to make PIN pad work for KFC in BI2X mode
|
||||
// this explicit check in the I/O init path is necessary
|
||||
// (as opposed to just doing a check for "isValkyrieCabMode?")
|
||||
// because there are hex edits that allow you to use legacy (KFC/BIO2) IO while in Valk mode
|
||||
acioemu::ICCA_DEVICE_HACK = true;
|
||||
return &aioNmgrIob2;
|
||||
return aioNmgrIob2;
|
||||
}
|
||||
|
||||
static int64_t __fastcall aioIob2Bi2x_WriteFirmGetState(int64_t a1) {
|
||||
@@ -411,3 +423,5 @@ namespace games::sdvx {
|
||||
aioNMgrIob2_Create, &aioNMgrIob2_Create_orig);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,6 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
#if SPICE64
|
||||
|
||||
namespace games::sdvx {
|
||||
|
||||
void bi2x_hook_init();
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -20,7 +20,6 @@ namespace games::sdvx {
|
||||
extern bool NATIVETOUCH;
|
||||
extern uint8_t DIGITAL_KNOB_SENS;
|
||||
extern std::optional<std::string> ASIO_DRIVER;
|
||||
extern bool BI2X_INITIALIZED;
|
||||
extern SdvxOverlayPosition OVERLAY_POS;
|
||||
|
||||
// states
|
||||
|
||||
Reference in New Issue
Block a user