1
0
mirror of synced 2024-11-15 01:57:36 +01:00

CRC32-Patches

This commit is contained in:
dkeruza 2023-11-20 14:13:29 -05:00
parent f2c3b79c2d
commit a257a21e30
8 changed files with 389 additions and 100 deletions

17
src/hookcrc32/Makefile Normal file
View File

@ -0,0 +1,17 @@
CC=gcc -m32
CFLAGS = -g -O0 -fPIC -m32 -Wall -Werror -Wno-unused-variable -Wno-unused-function
LD = g++ -m32
LDFLAGS = -Wl,-z,defs -rdynamic -static-libstdc++ -static-libgcc -lc -ldl -lGL -lglut -lX11 -lm -lpthread -shared -nostdlib
BUILD = build
OBJS := $(patsubst %.c,%.o,$(wildcard *.c))
all: hookcrc32.so
hookcrc32.so: $(OBJS)
$(LD) $(OBJS) $(LDFLAGS) $(CFLAGS) -o hookcrc32.so
rm -f *.o
clean:
rm -f hookcrc32.so

95
src/hookcrc32/hookcrc32.c Normal file
View File

@ -0,0 +1,95 @@
#define _GNU_SOURCE
#include <dlfcn.h>
#include <link.h>
#include <stdio.h>
#include <stdlib.h>
static struct {
ElfW(Addr) start, end;
} *segments;
static int n;
static int (*real_main)(int argc,char **argv);
uint32_t __crc32(const char *s,size_t n) {
uint32_t crc=0xFFFFFFFF;
for(size_t i=0;i<n;i++) {
char ch=s[i];
for(size_t j=0;j<8;j++) {
uint32_t b=(ch^crc)&1;
crc>>=1;
if(b) crc=crc^0xEDB88320;
ch>>=1;
}
}
return ~crc;
}
static int callback(struct dl_phdr_info *info, size_t size, void *data) {
/*n = info->dlpi_phnum;
segments = malloc(n * sizeof *segments);
for(int i = 0; i < n; ++i) {
segments[i].start = info->dlpi_addr + info->dlpi_phdr[i].p_vaddr;
segments[i].end = info->dlpi_addr + info->dlpi_phdr[i].p_vaddr + info->dlpi_phdr[i].p_memsz;
}
char *type;
int p_type;
printf("Name: \"%s\" (%d segments)\n", info->dlpi_name, info->dlpi_phnum);
for (int j = 0; j < info->dlpi_phnum; j++) {
p_type = info->dlpi_phdr[j].p_type;
type = (p_type == PT_LOAD) ? "PT_LOAD" :
(p_type == PT_DYNAMIC) ? "PT_DYNAMIC" :
(p_type == PT_INTERP) ? "PT_INTERP" :
(p_type == PT_NOTE) ? "PT_NOTE" :
(p_type == PT_INTERP) ? "PT_INTERP" :
(p_type == PT_PHDR) ? "PT_PHDR" :
(p_type == PT_TLS) ? "PT_TLS" :
(p_type == PT_GNU_EH_FRAME) ? "PT_GNU_EH_FRAME" :
(p_type == PT_GNU_STACK) ? "PT_GNU_STACK" :
(p_type == PT_GNU_RELRO) ? "PT_GNU_RELRO" : NULL;
printf(" %2d: [%14p; memsz:0x%7x; size:0x%7x] flags: 0x%x; ", j,
(void *) (info->dlpi_addr + info->dlpi_phdr[j].p_vaddr),
info->dlpi_phdr[j].p_memsz, info->dlpi_phdr[j].p_filesz ,info->dlpi_phdr[j].p_flags);
if (type != NULL)
printf("%s\n", type);
else
printf("[other (0x%x)]\n", p_type);*/
if((info->dlpi_phnum >= 3) && (info->dlpi_phdr[2].p_type == PT_LOAD) && (info->dlpi_phdr[2].p_flags == 5))
{
// printf("Aca voy a dumpear el codigo:\n");
//FILE *file = fopen("dump.bin","w+b");
//fwrite((void *)(info->dlpi_addr + info->dlpi_phdr[2].p_vaddr)+10,128,1,file);
//fclose(file);
int crc = 0;
crc = __crc32((void *)(info->dlpi_addr + info->dlpi_phdr[2].p_vaddr+10),128);
printf("Crc32: 0x%x\n",crc);
}
//}
return 1;
}
__attribute__((__constructor__))
static void setup(void) {
dl_iterate_phdr(callback, NULL);
//real_main = dlsym(RTLD_NEXT, "main");
exit(0);
}
__attribute__((__destructor__))
static void teardown(void) {
free(segments);
}
/*
__attribute__((__noinline__))
int main(int argc,char **argv) {
ElfW(Addr) addr = (ElfW(Addr))__builtin_extract_return_addr(__builtin_return_address(0));
for(int i = 0; i < n; ++i) {
if(addr >= segments[i].start && addr < segments[i].end) {
// Do Nothing
return 0;
}
}
return real_main(argc, argv);
}*/

Binary file not shown.

View File

@ -28,7 +28,7 @@ static char *getNextToken(char *buffer, char *seperator, char **saveptr)
return token;
}
static int detectGame()
static int detectGame(uint32_t elf_crc)
{
// For a better way of doing this, we should look for strings inside the game
@ -36,19 +36,25 @@ static int detectGame()
// strings %s | grep "RIDE TURN TEST" && strings %s | grep "PLEASE SHOOT GRID"
// shows you its hotd4S for example
if (strstr(program_invocation_name, "segaboot"))
if (elf_crc == 0x93ea7e11)
{
config.game = SEGABOOT;
config.game = SEGABOOT_2_4;
return 0;
}
if (strstr(program_invocation_name, "hod4"))
if (elf_crc == 0xbc0c9ffa)
{
config.game = THE_HOUSE_OF_THE_DEAD_4;
return 0;
}
if (strstr(program_invocation_name, "Jennifer"))
if (elf_crc == 0x7235bda8)
{
config.game = THE_HOUSE_OF_THE_DEAD_4_TEST;
return 0;
}
if (elf_crc == 0x6d055308)
{
config.game = OUTRUN;
config.emulateDriveboard = 1;
@ -56,7 +62,7 @@ static int detectGame()
return 0;
}
if (strstr(program_invocation_name, "JenTest"))
if (elf_crc == 0xffdccaaa)
{
config.game = OUTRUN_TEST;
config.emulateDriveboard = 1;
@ -64,33 +70,43 @@ static int detectGame()
return 0;
}
if (strstr(program_invocation_name, "lgj"))
if (elf_crc == 0xd4726d61)
{
config.game = LETS_GO_JUNGLE;
return 0;
}
if (strstr(program_invocation_name, "abc1080"))
if (elf_crc == 0xcc02de7d)
{
config.game = ABC;
config.game = ABC_2006;
return 0;
}
if (strstr(program_invocation_name, "drive"))
if (elf_crc == 0x152530dd)
{
config.game = ABC_2007;
return 0;
}
if (elf_crc == 0xfb096f81)
{
config.game = SRTV;
config.emulateDriveboard = 1;
config.emulateMotionboard = 1;
return 0;
}
if (strstr(program_invocation_name, "dsr"))
if (elf_crc == 0xb05d9bbe)
{
config.game = RTUNED;
config.emulateDriveboard = 1;
config.emulateMotionboard = 1;
return 0;
}
if (strstr(program_invocation_name, "vf5"))
if (elf_crc == 0xc4b7e89)
{
config.game = VF5;
config.game = VT3;
return 0;
}
@ -112,16 +128,19 @@ char *getGameName()
return "Outrun 2 SP";
case THE_HOUSE_OF_THE_DEAD_4:
return "The House of the Dead 4";
case THE_HOUSE_OF_THE_DEAD_4_TEST:
return "The House of the Dead 4 - Test Menu";
case LETS_GO_JUNGLE:
return "Let's Go Jungle! Lost on the Island of Spice";
case ABC:
case ABC_2006:
case ABC_2007:
return "After Burner Climax";
case SRTV:
return "SEGA Race TV";
case RTUNED:
return "R-Tuned Ultimate Street Racing";
case VF5:
return "Virtua Fighter 5";
case VT3:
return "Virtua Tennis 3";
default:
return "Unknown Game";
}
@ -187,7 +206,7 @@ int readConfig(FILE *configFile, EmulatorConfig *config)
return 0;
}
int initConfig()
int initConfig(uint32_t elf_crc)
{
config.emulateRideboard = 0;
config.emulateDriveboard = 0;
@ -203,17 +222,20 @@ int initConfig()
strcpy(config.rideboardPath, "none");
config.width = 1024;
config.height = 768;
if (detectGame() != 0)
if (detectGame(elf_crc) != 0)
{
printf("Warning: Unsure what game this is, using default configuration values\n");
printf("Warning: Unsure what game this is, using default configuration values.\n");
}
else
{
printf("Game Detected: %s\n", getGameName());
}
configFile = fopen(CONFIG_PATH, "r");
if (configFile == NULL)
{
printf("Warning: Cannot open %s, using default values\n", CONFIG_PATH);
printf("Warning: Cannot open %s, using default values.\n", CONFIG_PATH);
return 1;
}

View File

@ -9,13 +9,15 @@ typedef enum
SEGABOOT_2_4,
SEGABOOT_2_6,
THE_HOUSE_OF_THE_DEAD_4,
THE_HOUSE_OF_THE_DEAD_4_TEST,
OUTRUN,
OUTRUN_TEST,
LETS_GO_JUNGLE,
ABC,
ABC_2006,
ABC_2007,
SRTV,
RTUNED,
VF5
VT3
} Game;
typedef enum

View File

@ -1,3 +1,5 @@
#define _GNU_SOURCE
#include <link.h>
#include <dlfcn.h>
#include <errno.h>
#include <linux/sockios.h>
@ -13,6 +15,7 @@
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <cpuid.h>
#include "hook.h"
@ -38,19 +41,33 @@
int hooks[5] = {-1, -1, -1, -1};
FILE *fileHooks[2] = {NULL, NULL};
int fileRead[2] = {0, 0};
uint32_t elf_crc = 0;
cpuvendor cpu_vendor = {0};
static int callback(struct dl_phdr_info *info, size_t size, void *data);
uint16_t basePortAddress = 0xFFFF;
/**
* Signal handler for the SIGSEGV signal, which is triggered when a process tries to access an illegal memory location.
* @param signal
* @param info
* @param ptr
*/
static void handleSegfault(int signal, siginfo_t *info, void *ptr)
{
ucontext_t *ctx = ptr;
// Get the address of the instruction causing the segfault
uint8_t *code = (uint8_t *)ctx->uc_mcontext.gregs[REG_EIP];
printf("Code: 0x%08x - Port: 0x%08x\n", *code, (ctx->uc_mcontext.gregs[REG_EDX] & 0xFFFF));
switch (*code)
{
case 0xED:
{
// Get the port number from the EDX register
uint16_t port = ctx->uc_mcontext.gregs[REG_EDX] & 0xFFFF;
// The first port called is usually random, but everything after that
@ -60,9 +77,11 @@ static void handleSegfault(int signal, siginfo_t *info, void *ptr)
if (basePortAddress == 0xFFFF)
basePortAddress = port;
// Adjust the port number if necessary
if (port > 0x38)
port = port - basePortAddress;
// Call the security board input function with the port number and data
securityBoardIn(port, (uint32_t *)&(ctx->uc_mcontext.gregs[REG_EAX]));
ctx->uc_mcontext.gregs[REG_EIP]++;
@ -70,15 +89,17 @@ static void handleSegfault(int signal, siginfo_t *info, void *ptr)
}
break;
case 0xE7: // OUT IMMIDIATE
case 0xE7: // OUT IMMEDIATE
{
// Increment the instruction pointer by two to skip over this instruction
ctx->uc_mcontext.gregs[REG_EIP] += 2;
return;
}
break;
case 0xE6: // OUT IMMIDIATE
case 0xE6: // OUT IMMEDIATE
{
// Increment the instruction pointer by two to skip over this instruction
ctx->uc_mcontext.gregs[REG_EIP] += 2;
return;
}
@ -108,9 +129,14 @@ static void handleSegfault(int signal, siginfo_t *info, void *ptr)
}
}
void __attribute__((constructor)) hook_init()
{
printf("SEGA Lindbergh Loader\nRobert Dilley 2022\nNot for public consumption\n\n");
// Get offsets of the Game's ELF and calculate CRC32.
dl_iterate_phdr(callback, NULL);
// Get CPU ID
getCPUID();
// Implement SIGSEGV handler
struct sigaction act;
@ -118,9 +144,9 @@ void __attribute__((constructor)) hook_init()
act.sa_flags = SA_SIGINFO;
sigaction(SIGSEGV, &act, NULL);
initConfig();
initConfig(elf_crc);
if (initPatch() != 0)
if(initPatch() != 0)
exit(1);
if (initEeprom() != 0)
@ -206,18 +232,30 @@ int open64(const char *pathname, int flags)
return open(pathname, flags);
}
FILE *fopen(const char *restrict pathname, const char *restrict mode)
{
FILE *(*_fopen)(const char *restrict pathname, const char *restrict mode) = dlsym(RTLD_NEXT, "fopen");
// printf("fopen %s\n", pathname);
if (strcmp(pathname, "/root/lindbergrc") == 0)
{
return _fopen("lindbergrc", mode);
}
if (strcmp(pathname, "/usr/lib/boot/logo.tga") == 0)
{
return _fopen("logo.tga", mode);
}
if (strcmp(pathname, "/usr/lib/boot/LucidaConsole_12.tga") == 0)
{
return _fopen("LucidaConsole_12.tga", mode);
}
if (strcmp(pathname, "/usr/lib/boot/LucidaConsole_12.abc") == 0)
{
return _fopen("LucidaConsole_12.abc", mode);
}
if (strcmp(pathname, "/proc/cpuinfo") == 0)
{
fileRead[CPUINFO] = 0;
@ -242,6 +280,25 @@ FILE *fopen64(const char *pathname, const char *mode)
return fileHooks[OSRELEASE];
}
if (strcmp(pathname, "/usr/lib/boot/logo_red.tga") == 0)
{
return _fopen64("logo_red.tga", mode);
}
if (strcmp(pathname, "/usr/lib/boot/logo.tga") == 0)
{
return _fopen64("logo.tga", mode);
}
if (strcmp(pathname, "/usr/lib/boot/SEGA_KakuGothic-DB-Roman_12.tga") == 0)
{
return _fopen64("SEGA_KakuGothic-DB-Roman_12.tga", mode);
}
if (strcmp(pathname, "/usr/lib/boot/SEGA_KakuGothic-DB-Roman_12.abc") == 0)
{
return _fopen64("SEGA_KakuGothic-DB-Roman_12.abc", mode);
}
return _fopen64(pathname, mode);
}
@ -465,7 +522,7 @@ float powf(float base, float exponent)
return (float)pow((double)base, (double)exponent);
}
/** This might be required for some games
/*
int sem_wait(sem_t *sem)
{
int (*original_sem_wait)(sem_t * sem) = dlsym(RTLD_NEXT, "sem_wait");
@ -476,6 +533,10 @@ int sem_wait(sem_t *sem)
/**
* Hook function used by Harley Davidson to change IPs to localhost
* Currently does nothing.
* @param sockfd
* @param addr
* @param addrlen
* @return
*/
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen)
{
@ -491,6 +552,45 @@ int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen)
return _connect(sockfd, addr, addrlen);
}
/**
* Function to calculate CRC32 checksum in memory.
*/
uint32_t get_crc32(const char *s,size_t n)
{
uint32_t crc=0xFFFFFFFF;
for(size_t i=0;i<n;i++) {
char ch=s[i];
for(size_t j=0;j<8;j++) {
uint32_t b=(ch^crc)&1;
crc>>=1;
if(b) crc=crc^0xEDB88320;
ch>>=1;
}
}
return ~crc;
}
/**
* Callback function to get the offset and size of the execution program in memory of the ELF we hook to.
*/
static int callback(struct dl_phdr_info *info, size_t size, void *data)
{
if((info->dlpi_phnum >= 3) && (info->dlpi_phdr[2].p_type == PT_LOAD) && (info->dlpi_phdr[2].p_flags == 5))
{
elf_crc = get_crc32((void *)(info->dlpi_addr + info->dlpi_phdr[2].p_vaddr+10),128);
}
return 1;
}
void getCPUID()
{
unsigned eax;
eax = 0;
__get_cpuid(0, &eax, &cpu_vendor.ebx, &cpu_vendor.ecx, &cpu_vendor.edx);
printf("CPU Vendor: %.4s%.4s%.4s\n", (const char*)&cpu_vendor.ebx,(const char*)&cpu_vendor.edx,(const char*)&cpu_vendor.ecx);
}
/**
* Stop the game changing the DISPLAY environment variable
*/

View File

@ -0,0 +1,9 @@
uint32_t get_crc32(const char *s,size_t n);
void getCPUID();
typedef struct
{
unsigned ebx;
unsigned edx;
unsigned ecx;
}cpuvendor;

View File

@ -5,6 +5,9 @@
#include "patch.h"
#include "config.h"
#include "hook.h"
extern cpuvendor cpu_vendor;
static void setVariable(uint32_t address, uint32_t value)
{
@ -14,7 +17,7 @@ static void setVariable(uint32_t address, uint32_t value)
void *toModify = (void *)(address - (address % pagesize));
int prot = mprotect(toModify, pagesize, PROT_WRITE);
int prot = mprotect(toModify, pagesize, PROT_EXEC | PROT_WRITE);
if (prot != 0)
{
printf("Error: Cannot unprotect memory region to change variable (%d)\n", prot);
@ -70,75 +73,116 @@ int initPatch()
switch (game)
{
case RTUNED:
{
detourFunction(0x08366846, amDongleInit);
detourFunction(0x08365301, amDongleIsAvailable);
detourFunction(0x08365cf7, amDongleUpdate);
}
break;
case SRTV:
{
detourFunction(0x084d5b40, amDongleInit);
detourFunction(0x084d45f9, amDongleIsAvailable);
detourFunction(0x084d4fef, amDongleUpdate);
}
break;
case ABC:
{
detourFunction(0x081e3424, amDongleInit);
detourFunction(0x081e3772, amDongleIsAvailable);
detourFunction(0x081e369e, amDongleUpdate);
}
break;
case OUTRUN:
{
setVariable(0x0893a24c, 2); // amBackupDebugLevel
setVariable(0x0893a260, 2); // amCreditDebugLevel
setVariable(0x0893a4b8, 2); // amDipswDebugLevel
setVariable(0x0893a4bc, 2); // amDongleDebugLevel
setVariable(0x0893a4c0, 2); // amEepromDebugLevel
setVariable(0x0893a4c4, 2); // amHwmonitorDebugLevel
setVariable(0x0893a4c8, 2); // amJvsDebugLevel
setVariable(0x0893a4cc, 2); // amLibDebugLevel
setVariable(0x0893a4d0, 2); // amMiscDebugLevel
setVariable(0x0893a4d4, 2); // amOsinfoDebugLevel
setVariable(0x0893a4d8, 2); // amSysDataDebugLevel
setVariable(0x0893a4e0, 2); // bcLibDebugLevel
detourFunction(0x08190e80, amDongleInit);
detourFunction(0x08191201, amDongleIsAvailable);
detourFunction(0x08191125, amDongleUpdate);
}
break;
case RTUNED:
{
detourFunction(0x08366846, amDongleInit);
detourFunction(0x08365301, amDongleIsAvailable);
detourFunction(0x08365cf7, amDongleUpdate);
}
break;
case THE_HOUSE_OF_THE_DEAD_4:
{
setVariable(0x0a737c60, 2); // amBackupDebugLevel
setVariable(0x0a737c64, 2); // amChunkDataDebugLevel
setVariable(0x0a737c80, 2); // amCreditDebugLevel
setVariable(0x0a737ed8, 2); // amDipswDebugLevel
setVariable(0x0a737edc, 2); // amDiskDebugLevel
setVariable(0x0a737ee0, 2); // amDongleDebugLevel
setVariable(0x0a737ee4, 2); // amEepromDebugLevel
setVariable(0x0a737ee8, 2); // amHmDebugLevel
setVariable(0x0a737ef0, 2); // amJvsDebugLevel
setVariable(0x0a737f14, 2); // amLibDebugLevel
setVariable(0x0a737f18, 2); // amMiscDebugLevel
setVariable(0x0a737f1c, 2); // amSysDataDebugLevel
setVariable(0x0a737f20, 2); // bcLibDebugLevel
setVariable(0x0a737f24, 0x0FFFFFFF); // s_logMask
detourFunction(0x08320178, amDongleInit);
detourFunction(0x08320459, amDongleIsAvailable);
detourFunction(0x083203c0, amDongleUpdate);
}
break;
case SRTV:
{
detourFunction(0x084d5b40, amDongleInit);
detourFunction(0x084d45f9, amDongleIsAvailable);
detourFunction(0x084d4fef, amDongleUpdate);
}
break;
case ABC_2006:
{
setVariable(0x0a0a37e4, 2); // amBackupDebugLevel
setVariable(0x0a0a3800, 2); // amCreditDebugLevel
setVariable(0x0a0a3a58, 2); // amDipswDebugLevel
setVariable(0x0a0a3a5c, 2); // amDongleDebugLevel
setVariable(0x0a0a3a60, 2); // amEepromDebugLevel
setVariable(0x0a0a3a64, 2); // amHwmonitorDebugLevel
setVariable(0x0a0a3a68, 2); // amJvsDebugLevel
setVariable(0x0a0a3a6c, 2); // amLibDebugLevel
setVariable(0x0a0a3a70, 2); // amMiscDebugLevel
setVariable(0x0a0a3a74, 2); // amOsinfoDebugLevel
setVariable(0x0a0a3a78, 2); // amSysDataDebugLevel
setVariable(0x0a0a3a80, 2); // bcLibDebugLevel
detourFunction(0x081e4980, amDongleInit);
detourFunction(0x081e4cce, amDongleIsAvailable);
detourFunction(0x081e4bfa, amDongleUpdate);
}
break;
case ABC_2007:
{
setVariable(0x0a0a0d24, 2); // amBackupDebugLevel
setVariable(0x0a0a0d40, 2); // amCreditDebugLevel
setVariable(0x0a0a0f98, 2); // amDipswDebugLevel
setVariable(0x0a0a0f9c, 2); // amDongleDebugLevel
setVariable(0x0a0a0fa0, 2); // amEepromDebugLevel
setVariable(0x0a0a0fa4, 2); // amHwmonitorDebugLevel
setVariable(0x0a0a0fa8, 2); // amJvsDebugLevel
setVariable(0x0a0a0fac, 2); // amLibDebugLevel
setVariable(0x0a0a0fb0, 2); // amMiscDebugLevel
setVariable(0x0a0a0fb4, 2); // amOsinfoDebugLevel
setVariable(0x0a0a0fb8, 2); // amSysDataDebugLevel
setVariable(0x0a0a0fc0, 2); // bcLibDebugLevel
detourFunction(0x081e3424, amDongleInit);
detourFunction(0x081e3772, amDongleIsAvailable);
detourFunction(0x081e369e, amDongleUpdate);
}
break;
case OUTRUN:
{
setVariable(0x0893a24c, 2); // amBackupDebugLevel
setVariable(0x0893a260, 2); // amCreditDebugLevel
setVariable(0x0893a4b8, 2); // amDipswDebugLevel
setVariable(0x0893a4bc, 2); // amDongleDebugLevel
setVariable(0x0893a4c0, 2); // amEepromDebugLevel
setVariable(0x0893a4c4, 2); // amHwmonitorDebugLevel
setVariable(0x0893a4c8, 2); // amJvsDebugLevel
setVariable(0x0893a4cc, 2); // amLibDebugLevel
setVariable(0x0893a4d0, 2); // amMiscDebugLevel
setVariable(0x0893a4d4, 2); // amOsinfoDebugLevel
setVariable(0x0893a4d8, 2); // amSysDataDebugLevel
setVariable(0x0893a4e0, 2); // bcLibDebugLevel
detourFunction(0x08190e80, amDongleInit);
detourFunction(0x08191201, amDongleIsAvailable);
detourFunction(0x08191125, amDongleUpdate);
}
break;
default:
// Don't do any patches for random games
case THE_HOUSE_OF_THE_DEAD_4:
{
setVariable(0x0a737c60, 2); // amBackupDebugLevel
setVariable(0x0a737c64, 2); // amChunkDataDebugLevel
setVariable(0x0a737c80, 2); // amCreditDebugLevel
setVariable(0x0a737ed8, 2); // amDipswDebugLevel
setVariable(0x0a737edc, 2); // amDiskDebugLevel
setVariable(0x0a737ee0, 2); // amDongleDebugLevel
setVariable(0x0a737ee4, 2); // amEepromDebugLevel
setVariable(0x0a737ee8, 2); // amHmDebugLevel
setVariable(0x0a737ef0, 2); // amJvsDebugLevel
setVariable(0x0a737f14, 2); // amLibDebugLevel
setVariable(0x0a737f18, 2); // amMiscDebugLevel
setVariable(0x0a737f1c, 2); // amSysDataDebugLevel
setVariable(0x0a737f20, 2); // bcLibDebugLevel
setVariable(0x0a737f24, 0x0FFFFFFF); // s_logMask
detourFunction(0x08320178, amDongleInit);
detourFunction(0x08320459, amDongleIsAvailable);
detourFunction(0x083203c0, amDongleUpdate);
setVariable(0x0837d6aa, cpu_vendor.ebx);
setVariable(0x0837d6ba, cpu_vendor.edx);
setVariable(0x0837d6c5, cpu_vendor.ecx);
}
break;
case THE_HOUSE_OF_THE_DEAD_4_TEST:
{
detourFunction(0x080677a0, amDongleInit);
detourFunction(0x08067a81, amDongleIsAvailable);
detourFunction(0x080679e8, amDongleUpdate);
setVariable(0x0807217a, cpu_vendor.ebx);
setVariable(0x0807218a, cpu_vendor.edx);
setVariable(0x08072195, cpu_vendor.ecx);
}
break;
default:
// Don't do any patches for random games
break;
}
return 0;
}
}