44 Commits

Author SHA1 Message Date
af0c685fb3 v3.1.0 2024-01-08 17:58:56 +02:00
35cd117ffc Refactored dynamically linking ntdll 2024-01-07 20:51:55 +02:00
9f011ff103 Marked buf const in utils_write_protected_memory 2024-01-07 19:02:02 +02:00
ecbab96427 Implemented experimental patching method for SR 2024-01-07 19:01:03 +02:00
2da21065a6 Refactored protected memory writes 2024-01-07 18:34:03 +02:00
f8c4c5ad82 Replaced dummy variable references with NULL in inject.c
Apparently the crashes were an artifact of a different thing, and don't actually happen under normal conditions
2023-12-29 14:14:05 +02:00
6b5e303df6 Updated documentation 2023-12-28 14:35:29 +02:00
84e2c172a3 Marked msg_err functions noreturn 2023-12-27 14:11:02 +02:00
981a78ae53 Marked SR v1.6.0 as verified 2023-12-27 11:33:21 +02:00
55324bb5a8 v3.0.12 2023-12-27 00:40:43 +02:00
211f40ae53 SR 1.6.0: mark unverified 2023-12-27 00:37:12 +02:00
deddf93d3f SR 1.6.0: bump game version 2023-12-25 16:18:10 +02:00
c37d0e92f4 SR 1.6.0: updated checksums, patch address 2023-12-25 16:16:08 +02:00
fa3a3aa9cc Marked 3rd cn v7.2.0 as verified 2023-12-23 18:55:30 +02:00
186471508f Documented Wine 8.21+ fixing video playback 2023-12-23 18:54:41 +02:00
1f0a6bc016 Mark SR v1.5.0 as verified 2023-12-17 15:39:05 +02:00
da08b565f8 Mark 3rd glb/sea/tw/kr/jp v7.1.0 as verified 2023-12-08 00:10:05 +02:00
ead6489e63 Minor file structure reorganization 2023-11-16 22:58:31 +02:00
19d6139e13 v3.0.11 2023-11-15 18:50:56 +02:00
0047d7b64f Marked SR 1.5.0 as concerning 2023-11-13 23:08:53 +02:00
264cdc2528 Documentation update 2023-11-13 22:18:26 +02:00
ab4615dfe9 SR 1.5.0: updated checksums, patch address 2023-11-13 22:13:43 +02:00
cf34ac6e01 Mark 3rd cn v7.1.0 verified 2023-11-09 16:23:48 +02:00
6c7bbabced v3.0.10 2023-10-27 08:26:18 +03:00
81ddaeeda7 Marked 3rd 7.0.0 as verified 2023-10-27 08:25:58 +03:00
b9cae22212 Removed section name workaround for 3rd 2023-10-27 08:23:50 +03:00
8201e29e26 Remove misleading remark in readme 2023-10-11 17:55:48 +00:00
71144b4cd1 Mark HSR v1.4.0 as verified 2023-10-11 17:54:44 +00:00
5af8d2463a Set v3.0.9 in metadata.json 2023-10-10 22:02:36 +00:00
ea1d2f91f2 v3.0.9 2023-10-11 00:14:36 +03:00
f0ed718cf3 Document HSR 1.4.0 support 2023-10-09 19:27:24 +03:00
bc09349b8e Update checksums for HSR 1.4.0 2023-10-09 19:22:07 +03:00
66e51c6d9a Mark HI3 cn v7.0.0 verified 2023-10-01 11:04:01 +03:00
bc7b24f4d9 v3.0.8 2023-09-26 12:06:52 +03:00
9b55d4f160 Document HI3 forward compatibility 2023-09-26 12:06:24 +03:00
57b2423a8a Implement a better workaround for different HI3 editions having different section names 2023-09-26 12:05:53 +03:00
e96bf23a30 Document unexpected lack of change in HI3 v6.9.0 2023-09-15 23:18:02 +03:00
9296e00edd Document mfplat fix being unavailable 2023-09-11 19:30:52 +00:00
d22ded3d27 v3.0.7 2023-08-30 01:06:26 +03:00
15c403b0d1 Improve invalid checksum error message 2023-08-30 01:05:53 +03:00
1cc16ecbd9 Document HSR 1.3.0 support 2023-08-28 18:21:13 +03:00
ffe75e9de7 Update checksums to HSR 1.3.0 2023-08-28 18:19:36 +03:00
243e39d04b Optimized memory allocation in core 2023-08-26 21:24:56 +03:00
daa5585527 Update game version list in the readme 2023-08-17 23:11:46 +03:00
16 changed files with 227 additions and 196 deletions

View File

@ -1,24 +1,25 @@
### Games and regions
- **3rd**: glb/sea/tw/kr/jp **v6.8.0**, **cn v6.9.0 broken**
- **SR**: os/cn **v1.2.0** (potentially unsafe, but no bans were reported since v1.1.0)
# Jadeite Autopatcher
### Current game support:
- **3rd**: glb/sea/tw/kr/jp **v7.1.0+**, cn **v7.2.0+**
- **SR**: os/cn **v1.6.0**
~~You can expect newer versions of 3rd to work immediately after release with the same jadeite binary. However, that is not the case for SR: you will have to update your jadeite binary to run newer versions.~~ 6.9.0 investigation is in progress, please wait. #25
You can expect newer versions to work immediately after release with the same jadeite binary if the version is specified with a + above.
### Information
## Information
The anticheat the games use is fundamentally incompatible with Wine in multiple ways. This tool launches the game without it (`injector`) and imitates it's behaviour (`game_payload`).
**SR-specific**: this tool disables the use of DirectX shared resources in a rather hacky way. It is required, as there is no (and most likely never will be) shared resources support in DirectX translation layers (WineD3D/DXVK). Refer to [configuration](#configuration) if you wish to run the game without the fix.
**Using third-party software (such as this tool) with the games violates their Terms of Service**. Therefore, **you may receive a ban**. No bans were ever reported with 3rd, however the legacy patch for SR did cause many. **Use at your own risk and only if you understand all the possible consequences**.
**This is not a cheating tool**. Using it with Windows is not possible, and Windows support is not planned or intended in any way. However, as it does not perform any on-disk file modifications, you may reuse the same game install for Windows if you have a dual-boot setup.
### Usage
**Refer to [third-party launchers](#third-party-launchers)** for convenient usage. If you don't want to (or can't) use third-party launchers, continue reading the section below.
## Usage
**Refer to [third-party launchers](#third-party-launchers)** for convenient usage. If you don't want to (or can't) use third-party launchers, continue reading the section below
**Wine 8.0+ is recommended**, as lower versions leak "The Wine project" as the device identifier. Not critical, but taking a precaution never hurt anyone. **DXVK is strongly recommended.**
**Wine 8.0+ is recommended**, as lower versions leak "The Wine project" as the device identifier. Not critical, but taking a precaution never hurt anyone. **DXVK is strongly recommended**
**3rd-specific**: In some cases, and if you're not using Proton GE, **a fix for Media Foundation may be required to play videos. The Game may crash without it.** You can download it from [here](https://github.com/z0z0z/mf-install). You might need to [limit the number of cores available to the game](https://github.com/z0z0z/mf-install/issues/44) if your CPU has more than 8. **IMPORTANT: do not run the mfplat fix under Proton GE. Doing so may irreparably damage your game installation!**
**3rd-specific**:
- **Wine 8.21+ or [Wine-GE-Proton](https://github.com/GloriousEggroll/wine-ge-custom) is required to play videos. The game may show a black screen or crash on lower versions.**
- You might need to [limit the number of cores available to the game](https://github.com/z0z0z/mf-install/issues/44) if your CPU has more than 8.
Manual usage instructions:
- Download the game you want to run
@ -27,40 +28,40 @@ Manual usage instructions:
- Run `./block_analytics.sh` from the archive to block the games from accessing analytics servers (you might have to do a `chmod +x block_analytics.sh` first). This will require superuser privileges
- Run `wine jadeite.exe 'Z:\wine\path\to\game.exe'`
This tool is capable of starting the games from a different process. This may be useful for spoofing the parent process (SR is known to report it). Use `wine jadeite.exe 'Z:\wine\path\to\game.exe' 'Z:\wine\path\to\launcher.exe'`. `explorer.exe` is used as the default.
Detailed command line interface reference: `jadeite.exe [game path] <launcher path> <game args...>`, where:
- `game path` - Wine path to the game (required)
- `launcher path` - Wine path to the launcher process (optional, default is `C:\Windows\explorer.exe`). The launcher process will be used to start the game. You can specify the path to the official launcher here. Specifying anything other than `explorer.exe` or the official launcher is not recommended. Specify `--` to skip this argument and use the default
- `game args...` - arguments to pass to the game process (optional)
To pass commandline arguments to the game, append them after the launcher path: `wine jadeite.exe 'Z:\wine\path\to\game.exe' 'Z:\wine\path\to\launcher.exe' -arg1 -arg2 -arg3`. To use the default launcher process, use `--`: `wine jadeite.exe 'Z:\wine\path\to\game.exe' -- -arg1 -arg2 -arg3`.
Example command: `jadeite.exe 'Z:\path\to\game.exe' -- -screen-fullscreen 1`
### Configuration
## Configuration
These environment variables can be used to configure the behaviour of the tool. Any value except empty string counts as set. `1` will be used in all examples.
- `WAIT_BEFORE_RESUME=1` - show a messagebox and wait for user input before resuming the game process. Useful on my side for debugging
**SR-exclusive**:
- `SRFIX_DISABLE=1` - disable shared resources fix. Not recommended. Doing so will most likely cause the game to not run at all
### Internals
This tool consists of three parts: the main injector (`injector/src/exe.c`), the launcher payload (`injector/src/dll.c`) and the game payload (`game_payload`).
I am very bad at explaining, so just take a look at the source code. Maybe I'll write a detailed explanation in the future.
## Internals and building
To compile jadeite, you will need meson, mingw and nasm. You can probably install all three using your repository's package manager. Once all dependencies are installed, run `./build.sh` in this directory. The compiled files will be located in `./out`.
A part of the source code is witheld (`game_payload/src/core.c`). This is a forced measure to make abuse more difficult. However, a precompiled blob is provided in the repo. `build.sh` will use it automatically.
### Guildelines
All source code except `core.c` is available in this repository. You can take look around.
## Guildelines
1. **Please don't share this project in public.** This might attract unnecessary attention from either the Game Company or the Anticheat Company
2. **Please don't abuse this project for cheating.** We're just trying to play the games through Wine
### Troubleshooting
## Troubleshooting
Please do not report any issues with the Game to the official channels. Use the issue tracker of this repository
### Third-party launchers
- Honkers Launcher &mdash; Linux launcher for 3rd ([GitHub](https://github.com/an-anime-team/honkers-launcher) | [Codeberg](https://codeberg.org/an-anime-team/honkers-launcher))
- The Honkers Railway Launcher &mdash; Linux launcher for SR ([GitHub](https://github.com/an-anime-team/the-honkers-railway-launcher) | [Codeberg](https://codeberg.org/an-anime-team/the-honkers-railway-launcher))
## Third-party launchers
- **Honkers Launcher** &mdash; Linux launcher for 3rd ([GitHub](https://github.com/an-anime-team/honkers-launcher) | [Codeberg](https://codeberg.org/an-anime-team/honkers-launcher))
- **The Honkers Railway Launcher** &mdash; Linux launcher for SR ([GitHub](https://github.com/an-anime-team/the-honkers-railway-launcher) | [Codeberg](https://codeberg.org/an-anime-team/the-honkers-railway-launcher))
### Credits
- mkrsym1 &mdash; project leader, reverse engineering
- [EternalStudentDesuKa](https://github.com/EternalStudentDesuKa) &mdash; major help with analyzing network activity
- [An Anime Team](https://github.com/an-anime-team) &mdash; Honkers Launcher and The Honkers Railway Launcher
- Some others credited in the source code
## Credits
- **mkrsym1** &mdash; project leader, reverse engineering
- **[EternalStudentDesuKa](https://github.com/EternalStudentDesuKa)** &mdash; major help with analyzing network activity
- **[An Anime Team](https://github.com/an-anime-team)** &mdash; Honkers Launcher and The Honkers Railway Launcher
- Some others (credited in the source code)
License: MIT

Binary file not shown.

View File

@ -2,8 +2,8 @@
#include <wchar.h>
void msg_err_a(const char *format, ...);
void msg_err_w(const wchar_t *format, ...);
void __attribute__((noreturn)) msg_err_a(const char *format, ...);
void __attribute__((noreturn)) msg_err_w(const wchar_t *format, ...);
void msg_warn_a(const char *format, ...);
void msg_warn_w(const wchar_t *format, ...);

View File

@ -27,10 +27,32 @@ typedef union _LDR_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);
#define DYNAMIC_FN_TYPE(ret, name, args) typedef ret (*name##_t)args
extern LdrRegisterDllNotification_t LdrRegisterDllNotification;
extern LdrUnregisterDllNotification_t LdrUnregisterDllNotification;
#ifdef NTDLL_DYNAMIC_LINK_IMPL
#define DYNAMIC_FN_VAR(name) extern name##_t name; name##_t name
#else
#define DYNAMIC_FN_VAR(name) extern name##_t name
#endif
void ntdll_link();
#define DYNAMIC_FN_DEF(ret, name, args) DYNAMIC_FN_TYPE(ret, name, args); DYNAMIC_FN_VAR(name)
DYNAMIC_FN_DEF(NTSTATUS, LdrRegisterDllNotification, (ULONG flags, LdrDllNotification_t notification, void *context, void **cookie));
DYNAMIC_FN_DEF(NTSTATUS, LdrUnregisterDllNotification, (void *cookie));
#ifdef NTDLL_DYNAMIC_LINK_IMPL
#define DYNAMIC_FN_LINK(module, name) name = (name##_t)GetProcAddress(module, #name)
static void _ntdll_link() {
HMODULE ntdll = GetModuleHandleA("ntdll.dll");
DYNAMIC_FN_LINK(ntdll, LdrRegisterDllNotification);
DYNAMIC_FN_LINK(ntdll, LdrUnregisterDllNotification);
}
#undef DYNAMIC_FN_LINK
#endif
#undef DYNAMIC_FN_TYPE
#undef DYNAMIC_FN_VAR
#undef DYNAMIC_FN_DEF

View File

@ -12,3 +12,5 @@ void utils_create_parent_dirs(const wchar_t *path);
void utils_save_to_file(const wchar_t *filePath, const void *buf, size_t length);
char utils_env_enabled(const char *env);
void utils_write_protected_memory(void *addr, const void *buf, size_t size);

View File

@ -5,15 +5,16 @@ include_dir = include_directories('include')
# Input files
sources = [
'src/main.c',
'src/ntdll.c',
'src/ace.c',
'src/pe.c',
'src/game.c',
'src/hi3.c',
'src/hsr.c',
'src/utils.c',
'src/msg.c',
'src/tx.c'
'src/tx.c',
'src/hi3/hi3.c',
'src/hsr/hsr.c'
]
if fs.exists('src/core.c')

View File

@ -1,6 +1,7 @@
#include <ntdll.h>
#include <pe.h>
#include <msg.h>
#include <utils.h>
#include <ace.h>
@ -23,14 +24,7 @@ static void _dll_notification(ULONG reason, const PLDR_DLL_NOTIFICATION_DATA dat
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);
utils_write_protected_memory(entryPoint, ENTRY_POINT_STUB, sizeof(ENTRY_POINT_STUB));
}
static void _create_driver_file(const char *path) {

View File

@ -1,30 +1,20 @@
#include <utils.h>
#include <msg.h>
#include <pe.h>
#include <main.h>
#include <game.h>
const char *HI3_TXS_SECTION_NAME_OLD = ".bh3";
const char *HI3_TXS_SECTION_NAME_NEW = ".ace";
const char *HI3_BASE_MODULE_NAME = "BH3Base.dll";
const char *HI3_ASSEMBLY_PATH = "BH3_Data\\Native\\UserAssembly.dll";
const char *HI3_TXS_SECTION_NAME = ".ace";
const char *HI3_TVM_SECTION_NAME = ".tvm0";
void hi3_fill_data(struct game_data *buf) {
// !!! TEMPORARY WORKAROUND FOR HI3 6.8.0 -> 6.9.0
const uint32_t NEW_CHECKSUM = 0x885b4c63;
uint32_t crc = utils_file_crc32c(L"UnityPlayer.dll");
if (crc == NEW_CHECKSUM) {
buf->txs_section_name = HI3_TXS_SECTION_NAME_NEW;
} else {
buf->txs_section_name = HI3_TXS_SECTION_NAME_OLD;
}
buf->base_module_name = HI3_BASE_MODULE_NAME;
buf->assembly_path = HI3_ASSEMBLY_PATH;
buf->txs_section_name = HI3_TXS_SECTION_NAME;
buf->tvm_section_name = HI3_TVM_SECTION_NAME;
buf->unityplayer_callback = NULL;

View File

@ -1,98 +0,0 @@
#include <utils.h>
#include <msg.h>
#include <main.h>
#include <game.h>
const char *HSR_BASE_MODULE_NAME = "StarRailBase.dll";
const char *HSR_ASSEMBLY_PATH = "GameAssembly.dll";
const char *HSR_TXS_SECTION_NAME = ".ace";
const char *HSR_TVM_SECTION_NAME = ".tvm0";
enum hsr_region {
HSR_INVALID,
HSR_OS,
HSR_CN
};
struct crc_region_pair {
uint32_t crc;
enum hsr_region id;
};
const struct crc_region_pair HSR_REGIONS[] = {
{ 0x9eb3084e, HSR_OS }, // os v1.2.0
{ 0x14be07e9, HSR_CN } // cn v1.2.0
};
#define JUMP_SIZE (6 + sizeof(void*))
// Temporarily hardcoded offset
// v1.2.0, same for os and cn
#define WTSUD_PATCH_OFFSET 0x16430
char wtsud_original_bytes[JUMP_SIZE];
char *wtsud_patch_addr;
static void _wtsud_stub() {
// Recover original bytes
DWORD oldProtect;
VirtualProtect(wtsud_patch_addr, JUMP_SIZE, PAGE_EXECUTE_READWRITE, &oldProtect);
memcpy(wtsud_patch_addr, wtsud_original_bytes, JUMP_SIZE);
VirtualProtect(wtsud_patch_addr, JUMP_SIZE, oldProtect, &oldProtect);
unload_ctr_dec();
}
static void _unityplayer_callback(HMODULE unityModule) {
if (utils_env_enabled("SRFIX_DISABLE")) {
msg_info_a("Shared resources fix disabled. The game may not work");
return;
}
// Remove dependency on shared resources by patching WriteTextureStatisticUserData
unload_ctr_inc();
wtsud_patch_addr = ((char*)unityModule) + WTSUD_PATCH_OFFSET;
DWORD oldProtect;
VirtualProtect(wtsud_patch_addr, JUMP_SIZE, PAGE_EXECUTE_READWRITE, &oldProtect);
// Save original bytes
memcpy(wtsud_original_bytes, wtsud_patch_addr, JUMP_SIZE);
// Write jump
const char JUMP_INST[] = { 0xFF, 0x25, 0x00, 0x00, 0x00, 0x00 }; // jmp [$ + 6]
memcpy(wtsud_patch_addr, JUMP_INST, sizeof(JUMP_INST));
// Write destination address
void *destAddr = &_wtsud_stub;
memcpy(wtsud_patch_addr + sizeof(JUMP_INST), &destAddr, sizeof(destAddr));
VirtualProtect(wtsud_patch_addr, JUMP_SIZE, oldProtect, &oldProtect);
}
void hsr_fill_data(struct game_data *buf) {
uint32_t crc = utils_file_crc32c(L"UnityPlayer.dll");
enum hsr_region id = HSR_INVALID;
for (size_t i = 0; i < UTILS_COUNT(HSR_REGIONS); i++) {
if (HSR_REGIONS[i].crc == crc) {
id = HSR_REGIONS[i].id;
break;
}
}
if (id == HSR_INVALID) {
msg_err_a("Invalid UnityPlayer.dll checksum: 0x%08x. This usually happens when the patch is outdated", crc);
}
buf->base_module_name = HSR_BASE_MODULE_NAME;
buf->assembly_path = HSR_ASSEMBLY_PATH;
buf->txs_section_name = HSR_TXS_SECTION_NAME;
buf->tvm_section_name = HSR_TVM_SECTION_NAME;
buf->unityplayer_callback = &_unityplayer_callback;
}

122
game_payload/src/hsr/hsr.c Normal file
View File

@ -0,0 +1,122 @@
#include <utils.h>
#include <msg.h>
#include <main.h>
#include <game.h>
const char *HSR_BASE_MODULE_NAME = "StarRailBase.dll";
const char *HSR_ASSEMBLY_PATH = "GameAssembly.dll";
const char *HSR_TXS_SECTION_NAME = ".ace";
const char *HSR_TVM_SECTION_NAME = ".tvm0";
#define HSR_VERSION "1.6.0"
enum hsr_region {
HSR_INVALID,
HSR_OS,
HSR_CN
};
struct crc_region_pair {
uint32_t crc;
enum hsr_region id;
};
const struct crc_region_pair HSR_REGIONS[] = {
{ 0x5741ce50, HSR_OS }, // os v1.6.0
{ 0xce891f97, HSR_CN } // cn v1.6.0
};
#define JUMP_SIZE (6 + sizeof(void*))
// Temporarily hardcoded offset
// v1.6.0, same for os and cn
#define WTSUD_PATCH_OFFSET 0x16510
char wtsud_original_bytes[JUMP_SIZE];
char *wtsud_patch_addr;
static void _wtsud_stub() {
// Recover original bytes
utils_write_protected_memory(wtsud_patch_addr, wtsud_original_bytes, JUMP_SIZE);
unload_ctr_dec();
}
static void _unityplayer_callback(HMODULE unityModule) {
if (utils_env_enabled("CHECKSUM_PATCH_DISABLE")) {
msg_info_a("DirectX library verification patch disabled. The game will not work");
return;
}
// Remove check by patching WriteTextureStatisticUserData
unload_ctr_inc();
wtsud_patch_addr = ((char*)unityModule) + WTSUD_PATCH_OFFSET;
// Save original bytes
memcpy(wtsud_original_bytes, wtsud_patch_addr, JUMP_SIZE);
// Prepare payload
char payload[JUMP_SIZE];
const char JUMP_INST[] = { 0xFF, 0x25, 0x00, 0x00, 0x00, 0x00 }; // jmp [$ + 6]
memcpy(payload, JUMP_INST, sizeof(JUMP_INST));
void *destAddr = &_wtsud_stub;
memcpy(payload + sizeof(JUMP_INST), &destAddr, sizeof(destAddr));
// Write payload
utils_write_protected_memory(wtsud_patch_addr, payload, sizeof(payload));
}
static void _break_cryptcat() {
const char STUB[] = {
0xB8, 0x01, 0x00, 0x00, 0x00, // mov eax, 1
0xC3 // ret
};
const char *STUB_FUNCTIONS[] = {
"CryptCATAdminEnumCatalogFromHash",
"CryptCATCatalogInfoFromContext",
"CryptCATAdminReleaseCatalogContext"
};
HMODULE wintrust = LoadLibraryA("wintrust.dll");
for (size_t i = 0; i < UTILS_COUNT(STUB_FUNCTIONS); i++) {
void *fn = GetProcAddress(wintrust, STUB_FUNCTIONS[i]);
utils_write_protected_memory(fn, STUB, sizeof(STUB));
}
}
void hsr_fill_data(struct game_data *buf) {
if (!utils_env_enabled("BREAK_CRYPTCAT")) {
uint32_t crc = utils_file_crc32c(L"UnityPlayer.dll");
enum hsr_region id = HSR_INVALID;
for (size_t i = 0; i < UTILS_COUNT(HSR_REGIONS); i++) {
if (HSR_REGIONS[i].crc == crc) {
id = HSR_REGIONS[i].id;
break;
}
}
if (id == HSR_INVALID) {
msg_err_a("Invalid UnityPlayer.dll checksum: 0x%08x. This patch is intended to be used with HSR v" HSR_VERSION, crc);
}
// WriteTextureStatisticUserData patch
buf->unityplayer_callback = &_unityplayer_callback;
} else {
msg_warn_a("Using experimental patching method");
_break_cryptcat();
buf->unityplayer_callback = NULL;
}
buf->base_module_name = HSR_BASE_MODULE_NAME;
buf->assembly_path = HSR_ASSEMBLY_PATH;
buf->txs_section_name = HSR_TXS_SECTION_NAME;
buf->tvm_section_name = HSR_TVM_SECTION_NAME;
}

View File

@ -1,6 +1,5 @@
#include <windows.h>
#include <ntdll.h>
#include <ace.h>
#include <game.h>
#include <core.h>
@ -8,6 +7,9 @@
#include <msg.h>
#include <tx.h>
#define NTDLL_DYNAMIC_LINK_IMPL
#include <ntdll.h>
#include <main.h>
HMODULE this_module;
@ -76,7 +78,7 @@ BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, LPVOID reserved) {
this_module = instance;
// Dynamically link functions from ntdll
ntdll_link();
_ntdll_link();
// Detect which game the user is trying to run
struct game_data game;

View File

@ -1,11 +0,0 @@
#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");
}

View File

@ -64,3 +64,12 @@ char utils_env_enabled(const char *env) {
char *envText = getenv(env);
return envText && *envText;
}
void utils_write_protected_memory(void *addr, const void *buf, size_t size) {
DWORD oldProtect;
VirtualProtect(addr, size, PAGE_READWRITE, &oldProtect);
memcpy(addr, buf, size);
VirtualProtect(addr, size, oldProtect, &oldProtect);
}

View File

@ -21,15 +21,12 @@ static inline void write_protected_process_memory(HANDLE process, void *address,
DWORD oldProtect;
VirtualProtectEx(process, address, size, PAGE_EXECUTE_READWRITE, &oldProtect);
size_t bytesWritten;
WriteProcessMemory(process, address, buf, size, &bytesWritten);
WriteProcessMemory(process, address, buf, size, NULL);
VirtualProtectEx(process, address, size, oldProtect, &oldProtect);
}
void inject(HANDLE process, const void *payload, size_t payloadSize, const wchar_t *dllPath) {
size_t _; // Contrary to the docs, {Write,Read}ProcessMemory likes to crash if the last arg is NULL
// Find the EXE header in the process
char exeHeader[1024];
IMAGE_DOS_HEADER *dosHeader = NULL;
@ -38,7 +35,7 @@ void inject(HANDLE process, const void *payload, size_t payloadSize, const wchar
MEMORY_BASIC_INFORMATION memoryInfo;
char *currentAddress = 0x0;
while (VirtualQueryEx(process, currentAddress, &memoryInfo, sizeof(memoryInfo))) {
ReadProcessMemory(process, currentAddress, exeHeader, sizeof(exeHeader), &_);
ReadProcessMemory(process, currentAddress, exeHeader, sizeof(exeHeader), NULL);
dosHeader = (IMAGE_DOS_HEADER*)exeHeader;
@ -84,8 +81,8 @@ void inject(HANDLE process, const void *payload, size_t payloadSize, const wchar
char *remoteAlloc = VirtualAllocEx(process, NULL, allocSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
// Write the assembly payload and dll path
WriteProcessMemory(process, remoteAlloc, payload, payloadSize, &_);
WriteProcessMemory(process, remoteAlloc + payloadSize, dllPath, dllPathSize, &_);
WriteProcessMemory(process, remoteAlloc, payload, payloadSize, NULL);
WriteProcessMemory(process, remoteAlloc + payloadSize, dllPath, dllPathSize, NULL);
// Modify the executable to run the assembly payload
@ -97,7 +94,7 @@ void inject(HANDLE process, const void *payload, size_t payloadSize, const wchar
// Save the original entry point address and bytes
rd.entryPointAddress = entryPoint;
ReadProcessMemory(process, rd.entryPointAddress, rd.entryPointData, sizeof(rd.entryPointData), &_);
ReadProcessMemory(process, rd.entryPointAddress, rd.entryPointData, sizeof(rd.entryPointData), NULL);
// Replace the entry point with a jump to the assembly payload
write_protected_process_memory(process, entryPoint, JUMP_INST, sizeof(JUMP_INST));
@ -110,7 +107,7 @@ void inject(HANDLE process, const void *payload, size_t payloadSize, const wchar
// Save the original descriptor address and bytes
rd.importDescriptorAddress = importDescriptors;
ReadProcessMemory(process, rd.importDescriptorAddress, &rd.importDescriptorData, sizeof(rd.importDescriptorData), &_);
ReadProcessMemory(process, rd.importDescriptorAddress, &rd.importDescriptorData, sizeof(rd.importDescriptorData), NULL);
// Overwrite with zeroes
IMAGE_IMPORT_DESCRIPTOR firstDescriptor;
@ -122,12 +119,12 @@ void inject(HANDLE process, const void *payload, size_t payloadSize, const wchar
// Save the original value
rd.sizeFieldAddress = ddAddr;
ReadProcessMemory(process, rd.sizeFieldAddress, &rd.sizeFieldData, sizeof(rd.sizeFieldData), &_);
ReadProcessMemory(process, rd.sizeFieldAddress, &rd.sizeFieldData, sizeof(rd.sizeFieldData), NULL);
// Set to 0
DWORD newSize = 0;
write_protected_process_memory(process, ddAddr, &newSize, sizeof(newSize));
// Write recovery data to the allocation
WriteProcessMemory(process, remoteAlloc + payloadSize + dllPathSize, &rd, sizeof(rd), &_);
WriteProcessMemory(process, remoteAlloc + payloadSize + dllPathSize, &rd, sizeof(rd), NULL);
}

View File

@ -1,4 +1,4 @@
project('jadeite', 'c', version: '3.0.6')
project('jadeite', 'c', version: '3.1.0')
nasm = find_program('nasm')
gen_res = find_program('gen_resources.sh')

View File

@ -1,42 +1,42 @@
{
"jadeite": {
"version": "3.0.6"
"version": "3.1.0"
},
"games": {
"hi3rd": {
"global": {
"status": "verified",
"version": "6.8.0"
"version": "7.1.0"
},
"sea": {
"status": "verified",
"version": "6.8.0"
"version": "7.1.0"
},
"china": {
"status": "verified",
"version": "6.9.0"
"version": "7.2.0"
},
"taiwan": {
"status": "verified",
"version": "6.8.0"
"version": "7.1.0"
},
"korea": {
"status": "verified",
"version": "6.8.0"
"version": "7.1.0"
},
"japan": {
"status": "verified",
"version": "6.8.0"
"version": "7.1.0"
}
},
"hsr": {
"global": {
"status": "verified",
"version": "1.2.0"
"version": "1.6.0"
},
"china": {
"status": "verified",
"version": "1.2.0"
"version": "1.6.0"
}
}
}