forked from Hay1tsme/segatools
APMv3: add hook (#73)
This adds support for APMv3 I/O, menus and the launcher. * Added a apm3hook dll and I/O based on the usual layout. * Added C:\Mount\Apm to vfs. * Added the relevant .dlls to unityhook. * Added a hook for apmmount.dll that uses `CreateDosDevice` to mount decrypted data to the locations the launcher and games expect files to be. This will conflict with anything that is already at W:\ and X:\, but I do not have better solutions for this. * `launch.bat` is a bit more involved as it simulates the launcher loop. It can be broken by alt+f4ing or closing the launcher with "X". * An extra export was added, so rundll32 can be used to get rid of the dosdevices after the launcher was killed. * Since all the games do everything via `X:\lib\apm.dll`, no game hooks were needed in testing, therefore, `game.bat` files can be used as is. * Path hooks are applied correctly, so you can go correctly between games, launcher, sub system test mode and game test modes. A setup guide (some stuff specific to my server) can be found here: https://gmg.hopto.org:82/gmg/wiki/index.php/All.Net_P-ras_Multi_Menu Tested with the 2 APM sample apps, Blazblue, Puyo, Guilty Gear and some weird unity puzzle game whose name I forgot.   Reviewed-on: #73 Co-authored-by: kyoubate-haruka <46010460+kyoubate-haruka@users.noreply.github.com> Co-committed-by: kyoubate-haruka <46010460+kyoubate-haruka@users.noreply.github.com>
This commit is contained in:
210
common/platform/security.c
Normal file
210
common/platform/security.c
Normal file
@ -0,0 +1,210 @@
|
||||
#include <windows.h>
|
||||
#include <bcrypt.h>
|
||||
|
||||
#define STATUS_SUCCESS ((NTSTATUS)0x00000000)
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "hook/table.h"
|
||||
|
||||
#include "platform/security.h"
|
||||
|
||||
#include "util/dprintf.h"
|
||||
#include "util/dump.h"
|
||||
|
||||
static NTSTATUS __stdcall my_BCryptDecrypt(
|
||||
BCRYPT_KEY_HANDLE hKey,
|
||||
PUCHAR pbInput,
|
||||
ULONG cbInput,
|
||||
void* pPaddingInfo,
|
||||
PUCHAR pbIV,
|
||||
ULONG cbIV,
|
||||
PUCHAR pbOutput,
|
||||
ULONG cbOutput,
|
||||
ULONG* pcbResult,
|
||||
ULONG dwFlags);
|
||||
|
||||
static NTSTATUS (__stdcall *next_BCryptDecrypt)(
|
||||
BCRYPT_KEY_HANDLE hKey,
|
||||
PUCHAR pbInput,
|
||||
ULONG cbInput,
|
||||
void* pPaddingInfo,
|
||||
PUCHAR pbIV,
|
||||
ULONG cbIV,
|
||||
PUCHAR pbOutput,
|
||||
ULONG cbOutput,
|
||||
ULONG* pcbResult,
|
||||
ULONG dwFlags);
|
||||
|
||||
static NTSTATUS __stdcall my_BCryptEncrypt(
|
||||
BCRYPT_KEY_HANDLE hKey,
|
||||
PUCHAR pbInput,
|
||||
ULONG cbInput,
|
||||
void* pPaddingInfo,
|
||||
PUCHAR pbIV,
|
||||
ULONG cbIV,
|
||||
PUCHAR pbOutput,
|
||||
ULONG cbOutput,
|
||||
ULONG* pcbResult,
|
||||
ULONG dwFlags);
|
||||
|
||||
static NTSTATUS (__stdcall *next_BCryptEncrypt)(
|
||||
BCRYPT_KEY_HANDLE hKey,
|
||||
PUCHAR pbInput,
|
||||
ULONG cbInput,
|
||||
void* pPaddingInfo,
|
||||
PUCHAR pbIV,
|
||||
ULONG cbIV,
|
||||
PUCHAR pbOutput,
|
||||
ULONG cbOutput,
|
||||
ULONG* pcbResult,
|
||||
ULONG dwFlags);
|
||||
|
||||
static const struct hook_symbol security_hook_syms[] = {
|
||||
{
|
||||
.name = "BCryptDecrypt",
|
||||
.patch = my_BCryptDecrypt,
|
||||
.link = (void **) &next_BCryptDecrypt,
|
||||
},
|
||||
{
|
||||
.name = "BCryptEncrypt",
|
||||
.patch = my_BCryptEncrypt,
|
||||
.link = (void **) &next_BCryptEncrypt,
|
||||
}
|
||||
};
|
||||
|
||||
void LogKeyProperties(BCRYPT_KEY_HANDLE hKey) {
|
||||
NTSTATUS status;
|
||||
ULONG cbData;
|
||||
|
||||
// Retrieve the algorithm name
|
||||
WCHAR algorithmName[256];
|
||||
ULONG cbAlgorithmName = sizeof(algorithmName);
|
||||
|
||||
status = BCryptGetProperty(hKey, BCRYPT_ALGORITHM_NAME, (PUCHAR) algorithmName, cbAlgorithmName * sizeof(WCHAR),
|
||||
&cbData, 0);
|
||||
if (status == STATUS_SUCCESS) {
|
||||
dprintf("Algorithm: %ls\n", algorithmName);
|
||||
} else {
|
||||
dprintf("Algorithm: failed to retrieve algorithm name (0x%08lX)\n", status);
|
||||
}
|
||||
|
||||
// Export the key value
|
||||
DWORD keyBlobSize = 0;
|
||||
status = BCryptExportKey(hKey, NULL, BCRYPT_KEY_DATA_BLOB, NULL, 0, &keyBlobSize, 0);
|
||||
if (status != STATUS_SUCCESS) {
|
||||
dprintf("KEY: failed to determine key blob size (0x%08lX)\n", status);
|
||||
return;
|
||||
}
|
||||
|
||||
PUCHAR keyBlob = (PUCHAR) malloc(keyBlobSize);
|
||||
if (!keyBlob) {
|
||||
dprintf("KEY: failed the memory allocation for key blob.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
status = BCryptExportKey(hKey, NULL, BCRYPT_KEY_DATA_BLOB, keyBlob, keyBlobSize, &keyBlobSize, 0);
|
||||
if (status == STATUS_SUCCESS) {
|
||||
int headerSize = sizeof(BCRYPT_KEY_DATA_BLOB_HEADER);
|
||||
dprintf("KEY (%lu bytes):\n", keyBlobSize - headerSize);
|
||||
dump(keyBlob + headerSize, keyBlobSize - headerSize);
|
||||
} else {
|
||||
dprintf("KEY: failed to export key value (0x%08lX)\n", status);
|
||||
}
|
||||
|
||||
free(keyBlob);
|
||||
}
|
||||
|
||||
|
||||
static NTSTATUS __stdcall my_BCryptDecrypt(
|
||||
BCRYPT_KEY_HANDLE hKey,
|
||||
PUCHAR pbInput,
|
||||
ULONG cbInput,
|
||||
void* pPaddingInfo,
|
||||
PUCHAR pbIV,
|
||||
ULONG cbIV,
|
||||
PUCHAR pbOutput,
|
||||
ULONG cbOutput,
|
||||
ULONG* pcbResult,
|
||||
ULONG dwFlags) {
|
||||
dprintf("BCrypt: Decrypt\n");
|
||||
dprintf("FLAGS: %lx\n", dwFlags);
|
||||
LogKeyProperties(hKey);
|
||||
dprintf("IV:\n");
|
||||
dump(pbIV, cbIV);
|
||||
dprintf("ENCRYPTED:\n");
|
||||
dump(pbInput, cbInput);
|
||||
NTSTATUS ret = next_BCryptDecrypt(hKey, pbInput, cbInput, pPaddingInfo, pbIV, cbIV, pbOutput, cbOutput, pcbResult,
|
||||
dwFlags);
|
||||
dprintf("Operation Result: %lx\n", ret);
|
||||
if (ret == 0) {
|
||||
dprintf("Decrypted (%ld, max buf: %ld):\n", *pcbResult, cbOutput);
|
||||
if (pbOutput != NULL) {
|
||||
dump(pbOutput, *pcbResult);
|
||||
} else {
|
||||
dprintf("pbOutput == NULL!\n");
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static NTSTATUS __stdcall my_BCryptEncrypt(
|
||||
BCRYPT_KEY_HANDLE hKey,
|
||||
PUCHAR pbInput,
|
||||
ULONG cbInput,
|
||||
void* pPaddingInfo,
|
||||
PUCHAR pbIV,
|
||||
ULONG cbIV,
|
||||
PUCHAR pbOutput,
|
||||
ULONG cbOutput,
|
||||
ULONG* pcbResult,
|
||||
ULONG dwFlags) {
|
||||
dprintf("BCrypt: Encrypt\n");
|
||||
dprintf("FLAGS: %lx\n", dwFlags);
|
||||
LogKeyProperties(hKey);
|
||||
dprintf("IV:\n");
|
||||
dump(pbIV, cbIV);
|
||||
dprintf("Input data (%ld):\n", cbInput);
|
||||
dump(pbOutput, *pcbResult);
|
||||
NTSTATUS ret = next_BCryptEncrypt(hKey, pbInput, cbInput, pPaddingInfo, pbIV, cbIV, pbOutput, cbOutput, pcbResult,
|
||||
dwFlags);
|
||||
dprintf("Operation Result: %lx\n", ret);
|
||||
if (ret == 0) {
|
||||
dprintf("First 16 bytes of encrypted data (%ld, max buf: %ld):\n", *pcbResult, cbOutput);
|
||||
if (pbOutput != NULL) {
|
||||
dump(pbOutput, min(16, *pcbResult));
|
||||
} else {
|
||||
dprintf("pbOutput == NULL!\n");
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
HRESULT security_hook_init() {
|
||||
security_hook_insert_hooks(NULL);
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
void security_hook_insert_hooks(HMODULE mod) {
|
||||
|
||||
char value[8];
|
||||
if (!GetEnvironmentVariableA("BCRYPT_DUMP_ENABLED", value, 8)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (value[0] != '1') {
|
||||
return;
|
||||
}
|
||||
|
||||
dprintf("BCrypt: dumping enabled\n");
|
||||
|
||||
hook_table_apply(
|
||||
mod,
|
||||
"BCrypt.dll",
|
||||
security_hook_syms,
|
||||
_countof(security_hook_syms));
|
||||
}
|
Reference in New Issue
Block a user