Initial commit

This commit is contained in:
mkrsym1
2023-06-06 00:23:08 +03:00
commit 72626c2c18
37 changed files with 1146 additions and 0 deletions

View File

@ -0,0 +1,8 @@
#pragma once
#include <windows.h>
void ace_fake_driver_files();
HMODULE ace_load_base_module(const char *exeName);
HMODULE ace_load_driver_module();

View File

@ -0,0 +1,24 @@
#pragma once
// Modified from https://stackoverflow.com/a/27950866
#include <stddef.h>
#include <stdint.h>
/* CRC-32C (iSCSI) polynomial in reversed bit order. */
#define __POLY 0x82f63b78
static inline uint32_t crc32c(uint32_t crc, const unsigned char *buf, size_t len) {
crc = ~crc;
while (len--) {
crc ^= *buf++;
for (int k = 0; k < 8; k++) {
crc = crc & 1 ? (crc >> 1) ^ __POLY : crc >> 1;
}
}
return ~crc;
}
#undef __POLY

View File

@ -0,0 +1,6 @@
#pragma once
#include <wchar.h>
void err_mb_a(const char *format, ...);
void err_mb_w(const wchar_t *format, ...);

View File

@ -0,0 +1,20 @@
#pragma once
#include <windows.h>
enum game_id {
GAME_INVALID,
GAME_HI3_GLB
};
struct game_data {
enum game_id id; // Temporary
const char *name;
const char *assembly_path;
const wchar_t *assembly_name_lwr;
const char *tp6_section_name; // Unused for now
const char *tvm_section_name;
};
void game_detect(struct game_data *buf);

View File

@ -0,0 +1,5 @@
#pragma once
#include <game.h>
void hi3_fill_data(struct game_data *buf);

View File

@ -0,0 +1,36 @@
#pragma once
#include <windows.h>
#include <winternl.h>
// https://learn.microsoft.com/en-us/windows/win32/devnotes/ldrdllnotification
typedef struct _LDR_DLL_LOADED_NOTIFICATION_DATA {
ULONG Flags; //Reserved.
PCUNICODE_STRING FullDllName; //The full path name of the DLL module.
PCUNICODE_STRING BaseDllName; //The base file name of the DLL module.
PVOID DllBase; //A pointer to the base address for the DLL in memory.
ULONG SizeOfImage; //The size of the DLL image, in bytes.
} LDR_DLL_LOADED_NOTIFICATION_DATA, *PLDR_DLL_LOADED_NOTIFICATION_DATA;
typedef struct _LDR_DLL_UNLOADED_NOTIFICATION_DATA {
ULONG Flags; //Reserved.
PCUNICODE_STRING FullDllName; //The full path name of the DLL module.
PCUNICODE_STRING BaseDllName; //The base file name of the DLL module.
PVOID DllBase; //A pointer to the base address for the DLL in memory.
ULONG SizeOfImage; //The size of the DLL image, in bytes.
} LDR_DLL_UNLOADED_NOTIFICATION_DATA, *PLDR_DLL_UNLOADED_NOTIFICATION_DATA;
typedef union _LDR_DLL_NOTIFICATION_DATA {
LDR_DLL_LOADED_NOTIFICATION_DATA Loaded;
LDR_DLL_UNLOADED_NOTIFICATION_DATA Unloaded;
} LDR_DLL_NOTIFICATION_DATA, *PLDR_DLL_NOTIFICATION_DATA;
typedef void (*LdrDllNotification_t)(ULONG reason, const PLDR_DLL_NOTIFICATION_DATA data, void *context);
typedef NTSTATUS (*LdrRegisterDllNotification_t)(ULONG flags, LdrDllNotification_t notificationFunction, void *context, void **cookie);
typedef NTSTATUS (*LdrUnregisterDllNotification_t)(void *cookie);
extern LdrRegisterDllNotification_t LdrRegisterDllNotification;
extern LdrUnregisterDllNotification_t LdrUnregisterDllNotification;
void ntdll_link();

View File

@ -0,0 +1,6 @@
#pragma once
#include <windows.h>
void pe_find_section(HMODULE module, const char *section, MEMORY_BASIC_INFORMATION *buf);
void *pe_find_entry_point(HMODULE module);

View File

@ -0,0 +1,7 @@
#pragma once
#include <windows.h>
#include <game.h>
void tp6_setup_patcher(struct game_data *game, HMODULE thisModule, HMODULE baseModule);

View File

@ -0,0 +1,5 @@
#pragma once
#include <stdint.h>
uint32_t utils_file_crc32c(const char *filePath);

34
game_payload/meson.build Normal file
View File

@ -0,0 +1,34 @@
# Input files
sources = [
'src/main.c',
'src/ntdll.c',
'src/ace.c',
'src/pe.c',
'src/game.c',
'src/hi3.c',
'src/utils.c',
'src/err.c',
# File withheld to make abuse more difficult
'src/tp6.c'
]
resources = [
'res/hi3/glb/allocations.dat',
'res/hi3/glb/entries.dat'
]
# Generate resource files for ./res
res_files = custom_target(
'resources.[ho]',
output: [ 'resources.o', 'resources.h' ],
input: resources,
command: [ gen_res, meson.current_source_dir(), '@OUTPUT0@', '@OUTPUT1@', '@INPUT@' ]
)
shared_library(
'game_payload',
sources,
res_files,
include_directories: 'include',
name_prefix: ''
)

Binary file not shown.

Binary file not shown.

91
game_payload/src/ace.c Normal file
View File

@ -0,0 +1,91 @@
#include <ntdll.h>
#include <pe.h>
#include <err.h>
#include <ace.h>
static void _dll_notification(ULONG reason, const PLDR_DLL_NOTIFICATION_DATA data, void *context) {
if (reason != 1) { // 1 - attach
return;
}
// context should be set to the target module name, lowercase
wchar_t *targetModuleName = (wchar_t*)context;
wchar_t lwModuleName[MAX_PATH];
wcscpy(lwModuleName, data->Loaded.BaseDllName->Buffer);
_wcslwr(lwModuleName);
if (wcscmp(targetModuleName, lwModuleName) == 0) {
// Replace entry point with a stub
void *entryPoint = pe_find_entry_point(data->Loaded.DllBase);
const char ENTRY_POINT_STUB[] = {
0xB8, 0x01, 0x00, 0x00, 0x00, // mov eax, 1
0xC3 // ret
};
DWORD oldProtect;
VirtualProtect(entryPoint, sizeof(ENTRY_POINT_STUB), PAGE_EXECUTE_READWRITE, &oldProtect);
memcpy(entryPoint, ENTRY_POINT_STUB, sizeof(ENTRY_POINT_STUB));
VirtualProtect(entryPoint, sizeof(ENTRY_POINT_STUB), oldProtect, &oldProtect);
}
}
void ace_fake_driver_files() {
// They only report presence
const char *wdDriverPath = "ACE-BASE.sys";
const char *s32DriverPath = "C:\\windows\\system32\\drivers\\ACE-BASE.sys";
HANDLE wdDriverFile = CreateFileA(wdDriverPath, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (!wdDriverFile) {
err_mb_a("Could not create driver file: %s", wdDriverPath);
}
// Just in case
HANDLE s32DriverFile = CreateFileA(s32DriverPath, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (!s32DriverFile) {
err_mb_a("Could not create driver file: %s", s32DriverPath);
}
CloseHandle(wdDriverFile);
CloseHandle(s32DriverFile);
}
HMODULE ace_load_base_module(const char *exeName) {
wchar_t baseModuleName[MAX_PATH];
swprintf(baseModuleName, MAX_PATH, L"%sbase.dll", exeName);
wcslwr(baseModuleName);
void *cookie;
LdrRegisterDllNotification(0, &_dll_notification, baseModuleName, &cookie);
HMODULE baseModule = LoadLibraryW(baseModuleName);
if (!baseModule) {
err_mb_w(L"Could not load base module: %ls", baseModuleName);
}
// LoadLibraryA is synchronous; the notification function has already finished executing
LdrUnregisterDllNotification(cookie);
return baseModule;
}
HMODULE ace_load_driver_module() {
const char *driverModulePath = "AntiCheatExpert/InGame/x64/ACE-DRV64.dll";
void *cookie;
LdrRegisterDllNotification(0, &_dll_notification, L"ace-drv64.dll", &cookie);
HMODULE driverModule = LoadLibraryA(driverModulePath);
if (!driverModule) {
err_mb_a("Could not load driver module: %s", driverModulePath);
}
// LoadLibraryA is synchronous; the notification function has already finished executing
LdrUnregisterDllNotification(cookie);
return driverModule;
}

26
game_payload/src/err.c Normal file
View File

@ -0,0 +1,26 @@
#include <windows.h>
#include <stdio.h>
#include <err.h>
#define DEF_ERROR_FN(name, type, printfn, mbfn, projname) \
void name(const type *format, ...) { \
va_list args; \
va_start(args, format); \
\
int count = printfn(NULL, 0, format, args) + 1; \
\
type *buf = malloc(count * sizeof(type)); \
printfn(buf, count, format, args); \
\
mbfn(NULL, buf, projname, MB_OK | MB_ICONERROR); \
\
va_end(args); \
\
free(buf); \
exit(1); \
}
DEF_ERROR_FN(err_mb_a, char, _vsnprintf, MessageBoxA, "Jadeite Autopatcher")
DEF_ERROR_FN(err_mb_w, wchar_t, _vsnwprintf, MessageBoxW, L"Jadeite Autopatcher")

19
game_payload/src/game.c Normal file
View File

@ -0,0 +1,19 @@
#include <err.h>
#include <hi3.h>
#include <game.h>
void game_detect(struct game_data *buf) {
wchar_t exePath[MAX_PATH];
GetModuleFileNameW(NULL, exePath, MAX_PATH);
wchar_t *exeName = wcsrchr(exePath, L'\\') + 1;
wcslwr(exeName);
// Only HI3 is supported for now
if (wcscmp(exeName, L"bh3.exe") == 0) {
hi3_fill_data(buf);
} else {
err_mb_w(L"Unknown game: %ls", exeName);
}
}

44
game_payload/src/hi3.c Normal file
View File

@ -0,0 +1,44 @@
#include <utils.h>
#include <err.h>
#include <hi3.h>
const char *HI3_NAME = "BH3";
const char *HI3_ASSEMBLY_PATH = "BH3_Data/Native/UserAssembly.dll";
const wchar_t *HI3_ASSEMBLY_NAME_LWR = L"userassembly.dll";
const char *HI3_TP6_SECTION_NAME = ".bh3";
const char *HI3_TVM_SECTION_NAME = ".tvm0";
struct crc_id_pair {
uint32_t crc;
enum game_id id;
};
const struct crc_id_pair HI3_REGIONS[] = {
// Only glb for now
// It may be possible to get rid of region-specific data altogether in the future
{ 0x34bdec99, GAME_HI3_GLB } // glb v6.6.0
};
void hi3_fill_data(struct game_data *buf) {
uint32_t crc = utils_file_crc32c("UnityPlayer.dll");
enum game_id id = GAME_INVALID;
for (size_t i = 0; i < sizeof(HI3_REGIONS) / sizeof(struct crc_id_pair); i++) {
if (HI3_REGIONS[i].crc == crc) {
id = HI3_REGIONS[i].id;
}
}
if (id == GAME_INVALID) {
err_mb_a("Invalid UnityPlayer.dll checksum: %d", crc);
}
buf->id = id;
buf->name = HI3_NAME;
buf->assembly_path = HI3_ASSEMBLY_PATH;
buf->assembly_name_lwr = HI3_ASSEMBLY_NAME_LWR;
buf->tp6_section_name = HI3_TP6_SECTION_NAME;
buf->tvm_section_name = HI3_TVM_SECTION_NAME;
}

33
game_payload/src/main.c Normal file
View File

@ -0,0 +1,33 @@
#include <windows.h>
#include <ntdll.h>
#include <ace.h>
#include <game.h>
#include <tp6.h>
#include <utils.h>
BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, LPVOID reserved) {
// Only listen to attach
if (reason != DLL_PROCESS_ATTACH) {
return TRUE;
}
// Dynamically link functions from ntdll
ntdll_link();
// Detect which game the user is trying to run
struct game_data game;
game_detect(&game);
// Create fake ACE driver files
ace_fake_driver_files();
// Load both ACE modules
HMODULE baseModule = ace_load_base_module(game.name);
ace_load_driver_module();
// ...magic
tp6_setup_patcher(&game, instance, baseModule);
return TRUE;
}

11
game_payload/src/ntdll.c Normal file
View File

@ -0,0 +1,11 @@
#include <ntdll.h>
LdrRegisterDllNotification_t LdrRegisterDllNotification;
LdrUnregisterDllNotification_t LdrUnregisterDllNotification;
void ntdll_link() {
HMODULE ntdll = GetModuleHandleA("ntdll.dll");
LdrRegisterDllNotification = (LdrRegisterDllNotification_t)GetProcAddress(ntdll, "LdrRegisterDllNotification");
LdrUnregisterDllNotification = (LdrUnregisterDllNotification_t)GetProcAddress(ntdll, "LdrUnregisterDllNotification");
}

34
game_payload/src/pe.c Normal file
View File

@ -0,0 +1,34 @@
#include <stdint.h>
#include <pe.h>
void pe_find_section(HMODULE module, const char *section, MEMORY_BASIC_INFORMATION *buf) {
char *cModule = (char*)module;
IMAGE_DOS_HEADER* dosHeader = (IMAGE_DOS_HEADER*)module;
IMAGE_NT_HEADERS64* ntHeaders = (IMAGE_NT_HEADERS64*)(cModule + dosHeader->e_lfanew);
uint16_t sectionCount = ntHeaders->FileHeader.NumberOfSections;
IMAGE_SECTION_HEADER* sectionHeader = (IMAGE_SECTION_HEADER*)(ntHeaders + 1);
void* targetAddress = 0x0;
for (uint16_t i = 0; i < sectionCount; i++) {
if (strncmp((char*)sectionHeader->Name, section, 8) == 0) {
targetAddress = (void*)(cModule + sectionHeader->VirtualAddress);
break;
}
sectionHeader++;
}
VirtualQuery(targetAddress, buf, sizeof(MEMORY_BASIC_INFORMATION));
}
void *pe_find_entry_point(HMODULE module) {
char *cModule = (char*)module;
IMAGE_DOS_HEADER* dosHeader = (IMAGE_DOS_HEADER*)module;
IMAGE_NT_HEADERS64* ntHeaders = (IMAGE_NT_HEADERS64*)(cModule + dosHeader->e_lfanew);
return cModule + ntHeaders->OptionalHeader.AddressOfEntryPoint;
}

2
game_payload/src/tp6.md Normal file
View File

@ -0,0 +1,2 @@
### 1.0.0
- First version

30
game_payload/src/utils.c Normal file
View File

@ -0,0 +1,30 @@
#include <windows.h>
#include <crc32.h>
#include <err.h>
#include <utils.h>
uint32_t utils_file_crc32c(const char *filePath) {
HANDLE file = CreateFileA(filePath, FILE_READ_ACCESS, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (!file) {
err_mb_a("Could not open file: %s", filePath);
}
LARGE_INTEGER fileSize;
GetFileSizeEx(file, &fileSize);
HANDLE hMap = CreateFileMappingA(file, NULL, PAGE_READONLY, 0, 0, NULL);
char *map = MapViewOfFile(hMap, FILE_MAP_READ, 0, 0, 0);
if (!map) {
err_mb_a("Could not create file mapping for %s", filePath);
}
uint32_t crc = crc32c(0, (unsigned char*)map, fileSize.QuadPart);
UnmapViewOfFile(map);
CloseHandle(hMap);
CloseHandle(file);
return crc;
}