Initial commit: Add project structure, build configuration, and core functionality
- Added .gitignore to exclude build directory - Added utils submodule for shared utilities - Configured CMake build system with dependencies - Added main executable and DLL injection logic - Included necessary headers and manifest files - Added README with build and usage instructions
This commit is contained in:
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
build/
|
||||||
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
[submodule "utils"]
|
||||||
|
path = utils
|
||||||
|
url = https://github.com/lifegpc/c-utils
|
||||||
5
.vscode/settings.json
vendored
Normal file
5
.vscode/settings.json
vendored
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"files.associations": {
|
||||||
|
"xstring": "cpp"
|
||||||
|
}
|
||||||
|
}
|
||||||
21
CMakeLists.txt
Normal file
21
CMakeLists.txt
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
cmake_minimum_required(VERSION 3.20)
|
||||||
|
|
||||||
|
project(tasokuro_patch)
|
||||||
|
|
||||||
|
if (MSVC)
|
||||||
|
add_compile_options(/utf-8)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
include_directories("${CMAKE_CURRENT_SOURCE_DIR}/include")
|
||||||
|
|
||||||
|
set(DETOURS_LIB "${CMAKE_CURRENT_SOURCE_DIR}/lib/detours.lib")
|
||||||
|
|
||||||
|
set(ENABLE_ICONV OFF CACHE BOOL "Libiconv is not needed.")
|
||||||
|
add_subdirectory(utils)
|
||||||
|
include_directories("${CMAKE_CURRENT_SOURCE_DIR}/utils")
|
||||||
|
|
||||||
|
add_library(tasokuro_patch SHARED dllmain.cpp)
|
||||||
|
target_link_libraries(tasokuro_patch "${DETOURS_LIB}")
|
||||||
|
target_link_libraries(tasokuro_patch utils)
|
||||||
|
|
||||||
|
add_executable(tasokuro-chs WIN32 main.cpp winres.rc tasokuro-chs.exe.manifest)
|
||||||
12
README.md
Normal file
12
README.md
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
# Tasokuro Chinese Patch
|
||||||
|
## How to Compile
|
||||||
|
```powershell
|
||||||
|
md build && cd build
|
||||||
|
cmake -A x64 ../
|
||||||
|
cmake --build . --config Release
|
||||||
|
```
|
||||||
|
Now you can find two files, `tasokuro_patch.dll` and `tasokuro-chs.exe`, in the `build/Release` directory.
|
||||||
|
|
||||||
|
## How to Use
|
||||||
|
Use [EVB](https://enigmaprotector.com/) to package the resource files into `tasokuro_patch.dll`.
|
||||||
|
Then copy `tasokuro_patch.dll` and `tasokuro-chs.exe` to the game directory.
|
||||||
80
dllmain.cpp
Normal file
80
dllmain.cpp
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
#include <Windows.h>
|
||||||
|
#include "detours.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
#include "wchar_util.h"
|
||||||
|
|
||||||
|
static HFONT(WINAPI *TrueCreateFontW)(int nHeight, int nWidth, int nEscapement, int nOrientation, int fnWeight, DWORD dwItalic, DWORD dwUnderline, DWORD dwStrikeOut, DWORD dwCharSet, DWORD dwOutPrecision, DWORD dwClipPrecision, DWORD dwQuality, DWORD dwPitchAndFamily, LPCWSTR lpFaceName) = CreateFontW;
|
||||||
|
static HFONT(WINAPI *TrueCreateFontA)(int nHeight, int nWidth, int nEscapement, int nOrientation, int fnWeight, DWORD dwItalic, DWORD dwUnderline, DWORD dwStrikeOut, DWORD dwCharSet, DWORD dwOutPrecision, DWORD dwClipPrecision, DWORD dwQuality, DWORD dwPitchAndFamily, LPCSTR lpFaceName) = CreateFontA;
|
||||||
|
|
||||||
|
typedef char*(*ConvertWideToMultibyte)(LPSTR result, LPCWSTR source, int cp);
|
||||||
|
|
||||||
|
ConvertWideToMultibyte GetHandle() {
|
||||||
|
HMODULE hModule = GetModuleHandleA(NULL);
|
||||||
|
return (ConvertWideToMultibyte)((char*)hModule + 0x9e9e0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static ConvertWideToMultibyte h = nullptr;
|
||||||
|
|
||||||
|
char* convert(LPSTR result, LPCWSTR source, int cp) {
|
||||||
|
if (!h) return nullptr;
|
||||||
|
return h(result, source, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
HFONT WINAPI HookedCreateFontW(int nHeight, int nWidth, int nEscapement, int nOrientation, int fnWeight, DWORD dwItalic, DWORD dwUnderline, DWORD dwStrikeOut, DWORD dwCharSet, DWORD dwOutPrecision, DWORD dwClipPrecision, DWORD dwQuality, DWORD dwPitchAndFamily, LPCWSTR lpFaceName) {
|
||||||
|
std::wstring name(lpFaceName);
|
||||||
|
if (name == L"MS Gothic" || name == L"MS ゴシック") {
|
||||||
|
lpFaceName = L"微软雅黑";
|
||||||
|
nWidth = 0;
|
||||||
|
dwCharSet = 0;
|
||||||
|
}
|
||||||
|
return TrueCreateFontW(nHeight, nWidth, nEscapement, nOrientation, fnWeight, dwItalic, dwUnderline, dwStrikeOut, dwCharSet, dwOutPrecision, dwClipPrecision, dwQuality, dwPitchAndFamily, lpFaceName);
|
||||||
|
}
|
||||||
|
|
||||||
|
HFONT WINAPI HookedCreateFontA(int nHeight, int nWidth, int nEscapement, int nOrientation, int fnWeight, DWORD dwItalic, DWORD dwUnderline, DWORD dwStrikeOut, DWORD dwCharSet, DWORD dwOutPrecision, DWORD dwClipPrecision, DWORD dwQuality, DWORD dwPitchAndFamily, LPCSTR lpFaceName) {
|
||||||
|
UINT cp[] = { CP_UTF8, CP_OEMCP, CP_ACP, 932 };
|
||||||
|
std::wstring font;
|
||||||
|
for (int i = 0; i < 4; i++) {
|
||||||
|
if (wchar_util::str_to_wstr(font, lpFaceName, cp[i])) {
|
||||||
|
if (font == L"MS Gothic" || font == L"MS ゴシック") {
|
||||||
|
font = L"微软雅黑";
|
||||||
|
}
|
||||||
|
return TrueCreateFontW(nHeight, nWidth, nEscapement, nOrientation, fnWeight, dwItalic, dwUnderline, dwStrikeOut, dwCharSet, dwOutPrecision, dwClipPrecision, dwQuality, dwPitchAndFamily, font.c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!strcmp(lpFaceName, "MS Gothic")) {
|
||||||
|
lpFaceName = "Microsoft YaHei";
|
||||||
|
}
|
||||||
|
return TrueCreateFontA(nHeight, nWidth, nEscapement, nOrientation, fnWeight, dwItalic, dwUnderline, dwStrikeOut, dwCharSet, dwOutPrecision, dwClipPrecision, dwQuality, dwPitchAndFamily, lpFaceName);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" __declspec(dllexport) void Attach() {
|
||||||
|
DetourTransactionBegin();
|
||||||
|
DetourUpdateThread(GetCurrentThread());
|
||||||
|
h = GetHandle();
|
||||||
|
DetourAttach(&h, convert);
|
||||||
|
DetourAttach(&TrueCreateFontW, HookedCreateFontW);
|
||||||
|
DetourAttach(&TrueCreateFontA, HookedCreateFontA);
|
||||||
|
DetourTransactionCommit();
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" __declspec(dllexport) void Detach() {
|
||||||
|
if (!h) return;
|
||||||
|
DetourTransactionBegin();
|
||||||
|
DetourUpdateThread(GetCurrentThread());
|
||||||
|
DetourDetach(&h, convert);
|
||||||
|
DetourDetach(&TrueCreateFontW, HookedCreateFontW);
|
||||||
|
DetourDetach(&TrueCreateFontA, HookedCreateFontA);
|
||||||
|
DetourTransactionCommit();
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL APIENTRY DllMain(HMODULE hModule, DWORD reason, LPVOID rev) {
|
||||||
|
switch (reason) {
|
||||||
|
case DLL_PROCESS_ATTACH:
|
||||||
|
Attach();
|
||||||
|
break;
|
||||||
|
case DLL_PROCESS_DETACH:
|
||||||
|
Detach();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
1233
include/detours.h
Normal file
1233
include/detours.h
Normal file
File diff suppressed because it is too large
Load Diff
27
include/detver.h
Normal file
27
include/detver.h
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Common version parameters.
|
||||||
|
//
|
||||||
|
// Microsoft Research Detours Package, Version 4.0.1
|
||||||
|
//
|
||||||
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#define _USING_V110_SDK71_ 1
|
||||||
|
#include "winver.h"
|
||||||
|
#if 0
|
||||||
|
#include <windows.h>
|
||||||
|
#include <detours.h>
|
||||||
|
#else
|
||||||
|
#ifndef DETOURS_STRINGIFY
|
||||||
|
#define DETOURS_STRINGIFY_(x) #x
|
||||||
|
#define DETOURS_STRINGIFY(x) DETOURS_STRINGIFY_(x)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define VER_FILEFLAGSMASK 0x3fL
|
||||||
|
#define VER_FILEFLAGS 0x0L
|
||||||
|
#define VER_FILEOS 0x00040004L
|
||||||
|
#define VER_FILETYPE 0x00000002L
|
||||||
|
#define VER_FILESUBTYPE 0x00000000L
|
||||||
|
#endif
|
||||||
|
#define VER_DETOURS_BITS DETOURS_STRINGIFY(DETOURS_BITS)
|
||||||
89
include/syelog.h
Normal file
89
include/syelog.h
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Detours Test Program (syelog.h of syelog.lib)
|
||||||
|
//
|
||||||
|
// Microsoft Research Detours Package
|
||||||
|
//
|
||||||
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||||
|
//
|
||||||
|
#pragma once
|
||||||
|
#ifndef _SYELOGD_H_
|
||||||
|
#define _SYELOGD_H_
|
||||||
|
#include <stdarg.h>
|
||||||
|
|
||||||
|
#pragma pack(push, 1)
|
||||||
|
#pragma warning(push)
|
||||||
|
#pragma warning(disable: 4200)
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
//
|
||||||
|
#define SYELOG_PIPE_NAMEA "\\\\.\\pipe\\syelog"
|
||||||
|
#define SYELOG_PIPE_NAMEW L"\\\\.\\pipe\\syelog"
|
||||||
|
#ifdef UNICODE
|
||||||
|
#define SYELOG_PIPE_NAME SYELOG_PIPE_NAMEW
|
||||||
|
#else
|
||||||
|
#define SYELOG_PIPE_NAME SYELOG_PIPE_NAMEA
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
#define SYELOG_MAXIMUM_MESSAGE 4086 // 4096 - sizeof(header stuff)
|
||||||
|
|
||||||
|
typedef struct _SYELOG_MESSAGE
|
||||||
|
{
|
||||||
|
USHORT nBytes;
|
||||||
|
BYTE nFacility;
|
||||||
|
BYTE nSeverity;
|
||||||
|
DWORD nProcessId;
|
||||||
|
FILETIME ftOccurance;
|
||||||
|
BOOL fTerminate;
|
||||||
|
CHAR szMessage[SYELOG_MAXIMUM_MESSAGE];
|
||||||
|
} SYELOG_MESSAGE, *PSYELOG_MESSAGE;
|
||||||
|
|
||||||
|
|
||||||
|
// Facility Codes.
|
||||||
|
//
|
||||||
|
#define SYELOG_FACILITY_KERNEL 0x10 // OS Kernel
|
||||||
|
#define SYELOG_FACILITY_SECURITY 0x20 // OS Security
|
||||||
|
#define SYELOG_FACILITY_LOGGING 0x30 // OS Logging-internal
|
||||||
|
#define SYELOG_FACILITY_SERVICE 0x40 // User-mode system daemon
|
||||||
|
#define SYELOG_FACILITY_APPLICATION 0x50 // User-mode application
|
||||||
|
#define SYELOG_FACILITY_USER 0x60 // User self-generated.
|
||||||
|
#define SYELOG_FACILITY_LOCAL0 0x70 // Locally defined.
|
||||||
|
#define SYELOG_FACILITY_LOCAL1 0x71 // Locally defined.
|
||||||
|
#define SYELOG_FACILITY_LOCAL2 0x72 // Locally defined.
|
||||||
|
#define SYELOG_FACILITY_LOCAL3 0x73 // Locally defined.
|
||||||
|
#define SYELOG_FACILITY_LOCAL4 0x74 // Locally defined.
|
||||||
|
#define SYELOG_FACILITY_LOCAL5 0x75 // Locally defined.
|
||||||
|
#define SYELOG_FACILITY_LOCAL6 0x76 // Locally defined.
|
||||||
|
#define SYELOG_FACILITY_LOCAL7 0x77 // Locally defined.
|
||||||
|
#define SYELOG_FACILITY_LOCAL8 0x78 // Locally defined.
|
||||||
|
#define SYELOG_FACILITY_LOCAL9 0x79 // Locally defined.
|
||||||
|
|
||||||
|
// Severity Codes.
|
||||||
|
//
|
||||||
|
#define SYELOG_SEVERITY_FATAL 0x00 // System is dead.
|
||||||
|
#define SYELOG_SEVERITY_ALERT 0x10 // Take action immediately.
|
||||||
|
#define SYELOG_SEVERITY_CRITICAL 0x20 // Critical condition.
|
||||||
|
#define SYELOG_SEVERITY_ERROR 0x30 // Error
|
||||||
|
#define SYELOG_SEVERITY_WARNING 0x40 // Warning
|
||||||
|
#define SYELOG_SEVERITY_NOTICE 0x50 // Significant condition.
|
||||||
|
#define SYELOG_SEVERITY_INFORMATION 0x60 // Informational
|
||||||
|
#define SYELOG_SEVERITY_AUDIT_FAIL 0x66 // Audit Failed
|
||||||
|
#define SYELOG_SEVERITY_AUDIT_PASS 0x67 // Audit Succeeeded
|
||||||
|
#define SYELOG_SEVERITY_DEBUG 0x70 // Debugging
|
||||||
|
|
||||||
|
// Logging Functions.
|
||||||
|
//
|
||||||
|
VOID SyelogOpen(PCSTR pszIdentifier, BYTE nFacility);
|
||||||
|
VOID Syelog(BYTE nSeverity, PCSTR pszMsgf, ...);
|
||||||
|
VOID SyelogV(BYTE nSeverity, PCSTR pszMsgf, va_list args);
|
||||||
|
VOID SyelogClose(BOOL fTerminate);
|
||||||
|
|
||||||
|
#pragma warning(pop)
|
||||||
|
#pragma pack(pop)
|
||||||
|
|
||||||
|
#endif // _SYELOGD_H_
|
||||||
|
//
|
||||||
|
///////////////////////////////////////////////////////////////// End of File.
|
||||||
BIN
lib/detours.lib
Normal file
BIN
lib/detours.lib
Normal file
Binary file not shown.
70
main.cpp
Normal file
70
main.cpp
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
#include <windows.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
void ShowErrorMsg(LPCWSTR text) {
|
||||||
|
wchar_t* buf[1024];
|
||||||
|
_swprintf((wchar_t *const)buf, L"%s%i", text, GetLastError());
|
||||||
|
MessageBoxW(nullptr, (LPCWSTR)buf, L"错误消息", MB_OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
|
||||||
|
// 要启动的进程名
|
||||||
|
const wchar_t* processName = L"tasokuro.exe";
|
||||||
|
// 要注入的 DLL 路径
|
||||||
|
const wchar_t* dllPath = L"tasokuro_patch.dll";
|
||||||
|
|
||||||
|
// 启动进程
|
||||||
|
STARTUPINFOW si;
|
||||||
|
PROCESS_INFORMATION pi;
|
||||||
|
ZeroMemory(&si, sizeof(si));
|
||||||
|
ZeroMemory(&pi, sizeof(pi));
|
||||||
|
|
||||||
|
si.cb = sizeof(si);
|
||||||
|
|
||||||
|
// 创建新进程
|
||||||
|
if (!CreateProcessW((LPCWSTR)processName, nullptr, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &si, &pi)) {
|
||||||
|
ShowErrorMsg(L"CreateProcessW failed: ");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t memSize = (wcslen(dllPath) + 1) * sizeof(wchar_t);
|
||||||
|
|
||||||
|
// 在新进程中分配内存以存放 DLL 路径
|
||||||
|
LPVOID pDllPath = VirtualAllocEx(pi.hProcess, NULL, memSize, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
|
||||||
|
if (!pDllPath) {
|
||||||
|
ShowErrorMsg(L"VirtualAllocEx failed: ");
|
||||||
|
CloseHandle(pi.hProcess);
|
||||||
|
CloseHandle(pi.hThread);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 将 DLL 路径写入新进程的内存
|
||||||
|
if (!WriteProcessMemory(pi.hProcess, pDllPath, (LPVOID)dllPath, memSize, NULL)) {
|
||||||
|
ShowErrorMsg(L"WriteProcessMemory failed: ");
|
||||||
|
VirtualFreeEx(pi.hProcess, pDllPath, 0, MEM_RELEASE);
|
||||||
|
CloseHandle(pi.hProcess);
|
||||||
|
CloseHandle(pi.hThread);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建远程线程以加载 DLL
|
||||||
|
HANDLE hThread = CreateRemoteThread(pi.hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)GetProcAddress(GetModuleHandleA("kernel32.dll"), "LoadLibraryW"), pDllPath, 0, NULL);
|
||||||
|
if (!hThread) {
|
||||||
|
ShowErrorMsg(L"CreateRemoteThread failed: ");
|
||||||
|
VirtualFreeEx(pi.hProcess, pDllPath, 0, MEM_RELEASE);
|
||||||
|
CloseHandle(pi.hProcess);
|
||||||
|
CloseHandle(pi.hThread);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 等待线程完成
|
||||||
|
WaitForSingleObject(hThread, INFINITE);
|
||||||
|
|
||||||
|
// 清理
|
||||||
|
VirtualFreeEx(pi.hProcess, pDllPath, 0, MEM_RELEASE);
|
||||||
|
CloseHandle(hThread);
|
||||||
|
ResumeThread(pi.hThread); // 恢复新进程的执行
|
||||||
|
CloseHandle(pi.hProcess);
|
||||||
|
CloseHandle(pi.hThread);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
20
tasokuro-chs.exe.manifest
Normal file
20
tasokuro-chs.exe.manifest
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||||
|
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
|
||||||
|
<application xmlns="urn:schemas-microsoft-com:asm.v3">
|
||||||
|
<windowsSettings>
|
||||||
|
<dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">PerMonitorV2</dpiAwareness>
|
||||||
|
</windowsSettings>
|
||||||
|
</application>
|
||||||
|
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
|
||||||
|
<application>
|
||||||
|
<!-- Windows 10 and Windows 11 -->
|
||||||
|
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>
|
||||||
|
<!-- Windows 8.1 -->
|
||||||
|
<supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>
|
||||||
|
<!-- Windows 8 -->
|
||||||
|
<supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>
|
||||||
|
<!-- Windows 7 -->
|
||||||
|
<supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>
|
||||||
|
</application>
|
||||||
|
</compatibility>
|
||||||
|
</assembly>
|
||||||
1
utils
Submodule
1
utils
Submodule
Submodule utils added at d4d0be7e7a
Reference in New Issue
Block a user