Skip to content

Instantly share code, notes, and snippets.

@Alyinghood
Last active January 17, 2024 12:30
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Alyinghood/21bdb81d6f83114604082bd019482ae3 to your computer and use it in GitHub Desktop.
Save Alyinghood/21bdb81d6f83114604082bd019482ae3 to your computer and use it in GitHub Desktop.
// SPDX-License-Identifier: MIT
// See https://forums.nrvnqsr.com/showthread.php/9708-Mahoutsukai-no-Yoru-HD-PC-file-format-deciphering
#include <windows.h>
#include <string.h>
#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
#include <stdint.h>
// Dependency: https://github.com/TsudaKageyu/minhook
#include "MinHook.h"
static uint64_t work_image_base = 0x00007ff6bf390000;
static void *image_base = NULL;
int trymap(char *exe_path)
{
#if defined(_M_IX86) || defined(_M_X64) || defined(_M_AMD64)
// PE headers
PIMAGE_DOS_HEADER pidh;
PIMAGE_NT_HEADERS pinh;
PIMAGE_SECTION_HEADER pish;
// pointer to virtually allocated memory
LPVOID lpAddress = NULL;
// read executable file from storage
BYTE *data = NULL;
ULONG size = 0;
{
FILE* input_file = fopen(exe_path, "rb");
if (!input_file)
return 1;
fseek(input_file, 0, SEEK_END);
uint32_t input_file_size = ftell(input_file);
fseek(input_file, 0, SEEK_SET);
uint8_t *exe_bytes = malloc(input_file_size);
if (!exe_bytes)
return 1;
size_t input_file_bytes_read = fread(exe_bytes, 1, input_file_size, input_file);
if (input_file_bytes_read != input_file_size)
return 1;
data = exe_bytes;
size = input_file_size;
}
// check if valid DOS header
pidh = (PIMAGE_DOS_HEADER)data;
if (pidh->e_magic != IMAGE_DOS_SIGNATURE)
{
printf("DOS signature error: %x\n", GetLastError());
return 1;
}
// check if valid pe file
pinh = (PIMAGE_NT_HEADERS)((ULONG_PTR)data + pidh->e_lfanew);
if (pinh->Signature != IMAGE_NT_SIGNATURE)
{
printf("PE signature error: %x\n", GetLastError());
return 1;
}
image_base = (void *)(pinh->OptionalHeader.ImageBase);
if (pinh->OptionalHeader.SizeOfImage != 0x621db1)
{
printf("Size of image not known (was executable updated?): %x\n", pinh->OptionalHeader.SizeOfImage);
return 1;
}
// allocate virtual space for process
lpAddress = VirtualAllocEx(GetCurrentProcess(), (PVOID)pinh->OptionalHeader.ImageBase, pinh->OptionalHeader.SizeOfImage, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
if (lpAddress == NULL)
{
printf("Virtual allocation error: %x\n", GetLastError());
return 1;
}
// write headers into memory
if (WriteProcessMemory(GetCurrentProcess(), (PVOID)pinh->OptionalHeader.ImageBase, data, pinh->OptionalHeader.SizeOfHeaders, NULL) == FALSE)
{
printf("Write PE header error: %x\n", GetLastError());
return 1;
}
// write each section into memory
for (int i = 0; i < pinh->FileHeader.NumberOfSections; i++)
{
// calculate section header of each section
pish = (PIMAGE_SECTION_HEADER)((ULONG_PTR)data + pidh->e_lfanew + sizeof (IMAGE_NT_HEADERS) + sizeof (IMAGE_SECTION_HEADER) * i);
// write section data into memory
if (WriteProcessMemory(GetCurrentProcess(), (PVOID)(pinh->OptionalHeader.ImageBase + pish->VirtualAddress), (LPVOID)((ULONG_PTR)data + pish->PointerToRawData), pish->SizeOfRawData, NULL) == FALSE)
{
DWORD last_error = GetLastError();
if (last_error == 87)
{
printf("Got ERROR_INVALID_PARAMETER but continuing\n");
}
else
{
printf("Write section memory error: %x\n", last_error);
return 1;
}
}
}
return 0;
#endif
return 1;
}
struct struct_cbt_this
{
BYTE gap0[8];
struct struct_threadjob *csid;
void *element10;
DWORD jobid;
DWORD jobcount;
};
typedef void *(__fastcall *workercb)(struct struct_cbt_this *a1);
struct struct_threadjob
{
DWORD dw00[6];
workercb thread_job_worker_func;
void *thread_job_worker_func2;
struct struct_cbt_this *thread_job_worker_userdata;
};
typedef void *(__fastcall *MallocCallback)(size_t);
static MallocCallback fpMalloc = NULL;
static MallocCallback fpMalloc2 = NULL;
static void * __fastcall DetourMalloc(size_t size)
{
return malloc(size);
}
typedef void (__fastcall *FreeCallback)(void *);
static FreeCallback fpFree = NULL;
static void __fastcall DetourFree(void *ptr)
{
// stubbed
}
typedef void (__fastcall *WaitJobCallback)(struct struct_threadjob *a1);
static WaitJobCallback fpWaitJob = NULL;
static void __fastcall DetourWaitJob(struct struct_threadjob *a1)
{
if (a1->thread_job_worker_func2 != NULL)
{
fprintf(stderr, "Unsupported feature usage detected\n");
exit(1);
}
a1->thread_job_worker_userdata->jobid = 0;
a1->dw00[2] = 0;
for (int i = 0; i < a1->thread_job_worker_userdata->jobcount; i += 1)
{
a1->thread_job_worker_func(a1->thread_job_worker_userdata);
}
}
typedef void (__stdcall *FailureCallback)();
static FailureCallback fpCxxThrowException = NULL;
static FailureCallback fpAbort = NULL;
static FailureCallback fpAbort2 = NULL;
static void __stdcall DetourFailure()
{
fprintf(stderr, "Failure detected, aborting\n");
exit(1);
}
typedef struct ptr_range_lz_
{
uint8_t *dataptr;
uint32_t datasz;
uint32_t padd;
uint64_t dataszused;
} ptr_range_lz;
int main(int argc, char** argv)
{
if (argc != 4)
return 1;
if (trymap(argv[1]) != 0 || image_base == NULL)
return 2;
{
MH_Initialize();
if (MH_CreateHook(((uint8_t *)image_base) + (0x7FF6BF50D8FC - work_image_base), &DetourMalloc, (LPVOID *)&fpMalloc) != MH_OK)
{
return 3;
}
if (MH_CreateHook(((uint8_t *)image_base) + (0x7FF6BF50D60C - work_image_base), &DetourMalloc, (LPVOID *)&fpMalloc2) != MH_OK)
{
return 3;
}
if (MH_CreateHook(((uint8_t *)image_base) + (0x7FF6BF50D4C4 - work_image_base), &DetourFree, (LPVOID *)&fpFree) != MH_OK)
{
return 3;
}
if (MH_CreateHook(((uint8_t *)image_base) + (0x7FF6BF3EF7F0 - work_image_base), &DetourWaitJob, (LPVOID *)&fpWaitJob) != MH_OK)
{
return 3;
}
if (MH_CreateHook(((uint8_t *)image_base) + (0x7FF6BF52BC98 - work_image_base), &DetourFailure, (LPVOID *)&fpCxxThrowException) != MH_OK)
{
return 3;
}
if (MH_CreateHook(((uint8_t *)image_base) + (0x7FF6BF52EE8C - work_image_base), &DetourFailure, (LPVOID *)&fpAbort) != MH_OK)
{
return 3;
}
if (MH_CreateHook(((uint8_t *)image_base) + (0x7FF6BF3A4670 - work_image_base), &DetourFailure, (LPVOID *)&fpAbort2) != MH_OK)
{
return 3;
}
if (MH_EnableHook(MH_ALL_HOOKS) != MH_OK)
{
return 5;
}
}
FILE* input_file = fopen(argv[2], "rb");
if (!input_file)
return 6;
fseek(input_file, 0, SEEK_END);
uint32_t input_file_size = ftell(input_file);
fseek(input_file, 0, SEEK_SET);
uint8_t *compressed_bytes = malloc(input_file_size);
if (!compressed_bytes)
return 7;
size_t input_file_bytes_read = fread(compressed_bytes, 1, input_file_size, input_file);
if (input_file_bytes_read != input_file_size)
return 8;
fclose(input_file);
{
int64_t res;
unsigned __int8 *uncompressed_data;
unsigned int uncompressed_size;
struct struct_threadjob tj;
int64_t (__fastcall *x_sub_7FF6BF455670_extraction)(unsigned __int8 **unz_data_ptr, unsigned int *unz_data_sz, unsigned __int8 *indata, unsigned int indatasz, __int64 a5, struct struct_threadjob *a6) = (void *)(((uint8_t *)image_base) + (0x7FF6BF455670 - work_image_base));
uncompressed_data = NULL;
uncompressed_size = 0;
memset(&tj, 0, sizeof(tj));
res = x_sub_7FF6BF455670_extraction(&uncompressed_data, &uncompressed_size, compressed_bytes, input_file_bytes_read, 0, &tj);
if (res != 0)
{
fprintf(stderr, "Unusual result: %llx\n", res);
return 6;
}
if ( uncompressed_data == NULL )
{
return 6;
}
if ( uncompressed_size == 0 )
{
return 6;
}
FILE* out_file = fopen(argv[3], "wb");
if (!out_file)
return 7;
fwrite(uncompressed_data, 1, uncompressed_size, out_file);
fclose(out_file);
}
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment