mirror of
https://github.com/HIllya51/LunaTranslator.git
synced 2024-12-25 22:54:12 +08:00
refactor (#1139)
This commit is contained in:
parent
9feedfd38e
commit
743eb8f36e
40
.github/workflows/build.yml
vendored
40
.github/workflows/build.yml
vendored
@ -2,11 +2,33 @@ name: build
|
||||
|
||||
on:
|
||||
push:
|
||||
paths: [ '.github/workflows/build.yml','src/**']
|
||||
paths: [ '.github/workflows/build.yml','py/**']
|
||||
pull_request:
|
||||
paths: [ '.github/workflows/build.yml','src/**']
|
||||
paths: [ '.github/workflows/build.yml','py/**']
|
||||
|
||||
jobs:
|
||||
hook:
|
||||
runs-on: windows-latest
|
||||
strategy:
|
||||
matrix:
|
||||
bits: [32, 64]
|
||||
permissions:
|
||||
id-token: write
|
||||
attestations: write
|
||||
contents: write
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
- uses: GuillaumeFalourd/setup-windows10-sdk-action@v2
|
||||
with:
|
||||
sdk-version: 22621
|
||||
- run: python cpp/LunaHook/build.py build English ${{matrix.bits}}
|
||||
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: hook_${{matrix.bits}}
|
||||
path: cpp/LunaHook/builds/Release_English
|
||||
pyrt:
|
||||
runs-on: windows-latest
|
||||
strategy:
|
||||
@ -19,11 +41,11 @@ jobs:
|
||||
python-version: '3.7.9'
|
||||
architecture: ${{ matrix.architecture }}
|
||||
|
||||
- run: python src/build.py pyrt ${{ matrix.architecture }} 3.7.9
|
||||
- run: python py/build.py pyrt ${{ matrix.architecture }} 3.7.9
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: pyrt_${{ matrix.architecture }}
|
||||
path: src/pyrt
|
||||
path: py/pyrt
|
||||
build_cpp:
|
||||
runs-on: windows-latest
|
||||
strategy:
|
||||
@ -37,16 +59,16 @@ jobs:
|
||||
with:
|
||||
sdk-version: 22621
|
||||
|
||||
- run: python src/build.py cpp ${{ matrix.architecture }}
|
||||
- run: python py/build.py cpp ${{ matrix.architecture }}
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: cpp_${{ matrix.architecture }}
|
||||
path: src/plugins/builds
|
||||
path: cpp/builds
|
||||
|
||||
|
||||
release:
|
||||
runs-on: windows-latest
|
||||
needs: [pyrt,build_cpp]
|
||||
needs: [pyrt,build_cpp,hook]
|
||||
strategy:
|
||||
matrix:
|
||||
include:
|
||||
@ -59,8 +81,8 @@ jobs:
|
||||
- uses: actions/download-artifact@v4
|
||||
with:
|
||||
path: build
|
||||
- run: python src/build.py merge ${{ matrix.architecture }}
|
||||
- run: python py/build.py merge ${{ matrix.architecture }}
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ${{ matrix.fname }}
|
||||
path: src/build/${{matrix.fname}}.zip
|
||||
path: py/build/${{matrix.fname}}.zip
|
41
.github/workflows/release.yml
vendored
41
.github/workflows/release.yml
vendored
@ -11,8 +11,29 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- id: loadversion
|
||||
run: python src/build.py loadversion | Out-File -FilePath $Env:GITHUB_OUTPUT -Encoding utf8 -Append
|
||||
|
||||
run: python py/build.py loadversion | Out-File -FilePath $Env:GITHUB_OUTPUT -Encoding utf8 -Append
|
||||
hook:
|
||||
runs-on: windows-latest
|
||||
strategy:
|
||||
matrix:
|
||||
bits: [32, 64]
|
||||
permissions:
|
||||
id-token: write
|
||||
attestations: write
|
||||
contents: write
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
- uses: GuillaumeFalourd/setup-windows10-sdk-action@v2
|
||||
with:
|
||||
sdk-version: 22621
|
||||
- run: python cpp/LunaHook/build.py build English ${{matrix.bits}}
|
||||
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: hook_${{matrix.bits}}
|
||||
path: cpp/LunaHook/builds/Release_English
|
||||
pyrt:
|
||||
runs-on: windows-latest
|
||||
strategy:
|
||||
@ -25,11 +46,11 @@ jobs:
|
||||
python-version: '3.7.9'
|
||||
architecture: ${{ matrix.architecture }}
|
||||
|
||||
- run: python src/build.py pyrt ${{ matrix.architecture }} 3.7.9
|
||||
- run: python py/build.py pyrt ${{ matrix.architecture }} 3.7.9
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: pyrt_${{ matrix.architecture }}
|
||||
path: src/pyrt
|
||||
path: py/pyrt
|
||||
build_cpp:
|
||||
runs-on: windows-latest
|
||||
strategy:
|
||||
@ -43,16 +64,16 @@ jobs:
|
||||
with:
|
||||
sdk-version: 22621
|
||||
|
||||
- run: python src/build.py cpp ${{ matrix.architecture }}
|
||||
- run: python py/build.py cpp ${{ matrix.architecture }}
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: cpp_${{ matrix.architecture }}
|
||||
path: src/plugins/builds
|
||||
path: cpp/builds
|
||||
|
||||
|
||||
release:
|
||||
runs-on: windows-latest
|
||||
needs: [pyrt,build_cpp,loadversion]
|
||||
needs: [pyrt,build_cpp,loadversion,hook]
|
||||
strategy:
|
||||
matrix:
|
||||
include:
|
||||
@ -65,15 +86,15 @@ jobs:
|
||||
- uses: actions/download-artifact@v4
|
||||
with:
|
||||
path: build
|
||||
- run: python src/build.py merge ${{ matrix.architecture }}
|
||||
- run: python py/build.py merge ${{ matrix.architecture }}
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ${{ matrix.fname }}
|
||||
path: src/build/${{matrix.fname}}.zip
|
||||
path: py/build/${{matrix.fname}}.zip
|
||||
- uses: softprops/action-gh-release@v2
|
||||
with:
|
||||
tag_name: ${{ needs.loadversion.outputs.version }}
|
||||
files: |
|
||||
src/build/${{matrix.fname}}.zip
|
||||
py/build/${{matrix.fname}}.zip
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
40
.gitignore
vendored
40
.gitignore
vendored
@ -23,22 +23,24 @@ temp/
|
||||
|
||||
.vscode/settings.json
|
||||
|
||||
src/userconfig
|
||||
src/cache
|
||||
src/chrome_cache
|
||||
src/files/ocr
|
||||
src/files/plugins
|
||||
src/files/themes
|
||||
src/run37.bat
|
||||
src/run3732.bat
|
||||
src/plugins/builds
|
||||
src/plugins/libs/webview2
|
||||
src/plugins/.vscode/settings.json
|
||||
src/plugins/libs/opencv-static/windows-x86
|
||||
src/plugins/libs/opencv-static/windows-x64
|
||||
src/plugins/libs/onnxruntime-static/windows-x86
|
||||
src/plugins/libs/onnxruntime-static/windows-x64
|
||||
src/plugins/libs/opencv-static.zip
|
||||
src/plugins/libs/onnxruntime-static.zip
|
||||
src/plugins/libs/onnxruntime-static/onnxruntime-static.7z
|
||||
src/plugins/libs/opencv-static/opencv-static.7z
|
||||
py/userconfig
|
||||
py/cache
|
||||
py/chrome_cache
|
||||
py/files/ocr
|
||||
py/files/plugins
|
||||
py/files/themes
|
||||
py/run37.bat
|
||||
py/run3732.bat
|
||||
cpp/LunaHook/build
|
||||
cpp/LunaHook/builds
|
||||
cpp/builds
|
||||
cpp/libs/webview2
|
||||
cpp/.vscode/settings.json
|
||||
cpp/libs/opencv-static/windows-x86
|
||||
cpp/libs/opencv-static/windows-x64
|
||||
cpp/libs/onnxruntime-static/windows-x86
|
||||
cpp/libs/onnxruntime-static/windows-x64
|
||||
cpp/libs/opencv-static.zip
|
||||
cpp/libs/onnxruntime-static.zip
|
||||
cpp/libs/onnxruntime-static/onnxruntime-static.7z
|
||||
cpp/libs/opencv-static/opencv-static.7z
|
||||
|
15
.gitmodules
vendored
15
.gitmodules
vendored
@ -1,18 +1,21 @@
|
||||
[submodule "src/plugins/libs/wil"]
|
||||
path = src/plugins/libs/wil
|
||||
path = cpp/libs/wil
|
||||
url = https://github.com/microsoft/wil.git
|
||||
[submodule "src/plugins/libs/rapidfuzz-cpp"]
|
||||
path = src/plugins/libs/rapidfuzz-cpp
|
||||
path = cpp/libs/rapidfuzz-cpp
|
||||
url = https://github.com/rapidfuzz/rapidfuzz-cpp
|
||||
[submodule "src/plugins/libs/wechat-ocr"]
|
||||
path = src/plugins/libs/wechat-ocr
|
||||
path = cpp/libs/wechat-ocr
|
||||
url = https://github.com/swigger/wechat-ocr
|
||||
[submodule "src/plugins/libs/tinymp3"]
|
||||
path = src/plugins/libs/tinymp3
|
||||
path = cpp/libs/tinymp3
|
||||
url = https://github.com/HIllya51/tinymp3
|
||||
[submodule "src/plugins/libs/Detours"]
|
||||
path = src/plugins/libs/Detours
|
||||
path = cpp/libs/Detours
|
||||
url = https://github.com/microsoft/Detours
|
||||
[submodule "src/plugins/libs/Clipper2"]
|
||||
path = src/plugins/libs/Clipper2
|
||||
path = cpp/libs/Clipper2
|
||||
url = https://github.com/AngusJohnson/Clipper2
|
||||
[submodule "src/plugins/libs/minhook"]
|
||||
path = cpp/libs/minhook
|
||||
url = https://github.com/TsudaKageyu/minhook
|
||||
|
@ -22,12 +22,7 @@ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY $<1:${CMAKE_FINAL_OUTPUT_DIRECTORY}>)
|
||||
|
||||
include(libs/libs.cmake)
|
||||
|
||||
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_SOURCE_DIR}/version)
|
||||
include(generate_product_version)
|
||||
|
||||
set(VERSION_MAJOR 5)
|
||||
set(VERSION_MINOR 55)
|
||||
set(VERSION_PATCH 5)
|
||||
include(${CMAKE_SOURCE_DIR}/version/version.cmake)
|
||||
|
||||
add_library(pch pch.cpp)
|
||||
target_precompile_headers(pch PUBLIC pch.h)
|
65
cpp/LunaHook/CMakeLists.txt
Normal file
65
cpp/LunaHook/CMakeLists.txt
Normal file
@ -0,0 +1,65 @@
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
project(LunaHook)
|
||||
|
||||
set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
|
||||
|
||||
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/cmake)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
add_definitions(-DUNICODE -D_UNICODE)
|
||||
add_compile_options(
|
||||
/MP
|
||||
/wd4018
|
||||
/wd4819
|
||||
/wd4244
|
||||
/wd4267
|
||||
/wd4340
|
||||
/wd4369
|
||||
/wd4573
|
||||
)
|
||||
|
||||
if(NOT CMAKE_BUILD_TYPE)
|
||||
set(CMAKE_BUILD_TYPE Release)
|
||||
endif()
|
||||
|
||||
if(${CMAKE_SIZEOF_VOID_P} EQUAL 8)
|
||||
set(bitappendix "64")
|
||||
else()
|
||||
set(bitappendix "32")
|
||||
endif()
|
||||
|
||||
if(NOT DEFINED LANGUAGE)
|
||||
set(LANGUAGE English)
|
||||
endif()
|
||||
option(BUILD_PLUGIN "BUILD_PLUGIN" OFF)
|
||||
option(BUILD_GUI "BUILD_GUI" OFF)
|
||||
option(BUILD_CLI "BUILD_CLI" OFF)
|
||||
option(WINXP "WINXP" OFF)
|
||||
|
||||
if(WINXP)
|
||||
set(WINXPAPP "_winxp")
|
||||
else()
|
||||
set(WINXPAPP "")
|
||||
endif()
|
||||
|
||||
add_definitions(-DLANGUAGE=${LANGUAGE})
|
||||
|
||||
set(CMAKE_FINAL_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/builds/${CMAKE_BUILD_TYPE}_x${bitappendix}_${LANGUAGE}${WINXPAPP})
|
||||
set(binary_out_putpath ${CMAKE_SOURCE_DIR}/builds/${CMAKE_BUILD_TYPE}_${LANGUAGE}${WINXPAPP})
|
||||
#set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY $<1:${CMAKE_FINAL_OUTPUT_DIRECTORY}>)
|
||||
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY $<1:${binary_out_putpath}>)
|
||||
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY $<1:${binary_out_putpath}>)
|
||||
|
||||
include_directories(.)
|
||||
option(USE_VCLTL "USE_VCLTL" OFF)
|
||||
option(IS_LUNAHOOK "IS_LUNAHOOK" ON)
|
||||
include(${CMAKE_SOURCE_DIR}/../libs/libs.cmake)
|
||||
|
||||
include_directories(include)
|
||||
|
||||
include(${CMAKE_SOURCE_DIR}/../version/version.cmake)
|
||||
|
||||
add_subdirectory(include)
|
||||
add_subdirectory(LunaHook)
|
||||
add_subdirectory(LunaHost)
|
22
cpp/LunaHook/Lang/Lang.h
Normal file
22
cpp/LunaHook/Lang/Lang.h
Normal file
@ -0,0 +1,22 @@
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable: 4005)
|
||||
|
||||
#define English 0
|
||||
#define Chinese 1
|
||||
#define Russian 2
|
||||
#define TradChinese 3
|
||||
|
||||
#include"en.h"
|
||||
|
||||
#if (LANGUAGE == Chinese)
|
||||
#include"zh.h"
|
||||
#endif
|
||||
#if (LANGUAGE == Russian)
|
||||
#include"ru.h"
|
||||
#endif
|
||||
#if (LANGUAGE == TradChinese)
|
||||
#include"cht.h"
|
||||
#endif
|
||||
|
||||
|
||||
#pragma warning(pop)
|
101
cpp/LunaHook/Lang/cht.h
Normal file
101
cpp/LunaHook/Lang/cht.h
Normal file
@ -0,0 +1,101 @@
|
||||
|
||||
#define ALREADY_INJECTED L"已經注入"
|
||||
#define NEED_32_BIT L"架構不匹配:請嘗試使用 32 位元注入此處理程序"
|
||||
#define NEED_64_BIT L"架構不匹配:請嘗試使用 64 位元注入此處理程序"
|
||||
#define INJECT_FAILED L"注入失敗"
|
||||
#define INVALID_CODEPAGE L"無法轉換文字(無效的字碼頁?)"
|
||||
#define PIPE_CONNECTED u8"管道已連接"
|
||||
#define INSERTING_HOOK u8"注入勾點:%s %p"
|
||||
#define REMOVING_HOOK u8"移除勾點:%s"
|
||||
#define TOO_MANY_HOOKS u8"勾點數量已達上限:無法注入"
|
||||
#define HOOK_SEARCH_STARTING u8"開始搜尋勾點"
|
||||
#define HOOK_SEARCH_INITIALIZING u8"初始化勾點搜尋(%f%%)"
|
||||
#define NOT_ENOUGH_TEXT u8"文字長度不足,無法精確搜尋"
|
||||
#define HOOK_SEARCH_INITIALIZED u8"搜尋初始化完成,建立了 %zd 個勾點"
|
||||
#define MAKE_GAME_PROCESS_TEXT u8"請點擊遊戲區域,在接下來的 %d 秒內使遊戲強制處理文字"
|
||||
#define HOOK_SEARCH_FINISHED u8"勾點搜尋完畢,找到了 %d 條結果"
|
||||
#define OUT_OF_RECORDS_RETRY u8"搜尋結果已達上限,如果結果不理想,請重試(預設最大紀錄數增加)"
|
||||
#define FUNC_MISSING u8"函式不存在"
|
||||
#define MODULE_MISSING u8"模組不存在"
|
||||
#define GARBAGE_MEMORY u8"記憶體一直在改變,無法有效讀取"
|
||||
#define SEND_ERROR u8"Sender 錯誤(可能是由於錯誤或不穩定的 H-code):%s"
|
||||
#define READ_ERROR u8"Reader 錯誤(可能是由於錯誤或不穩定的 R-code):%s"
|
||||
#define SearchForHooks_ERROR u8"搜尋勾點錯誤:記憶體移除,嘗試重新分配 %d"
|
||||
#define ResultsNum u8"%d 個結果被找到"
|
||||
#define HIJACK_ERROR u8"Hijack 錯誤"
|
||||
#define COULD_NOT_FIND u8"無法找到文字"
|
||||
#define CONSOLE L"控制台"
|
||||
#define InvalidLength u8"可能存在錯誤(無效的文字長度 %d 出現 %s)"
|
||||
#define InsertHookFailed u8"勾點注入失敗 %s"
|
||||
#define Match_Error u8"匹配 %s 引擎時發生錯誤"
|
||||
#define Attach_Error u8"連接到 %s 引擎時發生錯誤"
|
||||
#define MatchedEngine u8"匹配到 %s 引擎"
|
||||
#define ConfirmStop u8"確認是 %s 引擎,停止匹配"
|
||||
#define Attach_Stop u8"成功連接到 %s 引擎"
|
||||
#define ProcessRange u8"取得處理程序記憶體位址範圍 0x%p 到 0x%p"
|
||||
#define WarningDummy u8"警告,注入的處理程序記憶體很小,可能是無用處理程序!"
|
||||
#define WndSelectProcess L"選擇處理程序"
|
||||
#define WndLunaHostGui L"LunaHost GUI"
|
||||
#define WndSetting L"設定"
|
||||
#define WndPlugins L"外掛程式"
|
||||
#define NotifyInvalidHookCode L"特殊碼無效"
|
||||
#define BtnSelectProcess L"選擇處理程序"
|
||||
#define BtnDetach L"從遊戲分離"
|
||||
#define BtnSaveHook L"儲存勾點"
|
||||
#define BtnShowSettingWindow L"設定"
|
||||
#define BtnAttach L"注入處理程序"
|
||||
#define BtnRefresh L"重新整理"
|
||||
#define BtnToClipboard L"複製到剪貼簿"
|
||||
#define BtnReadOnly L"文字框唯讀"
|
||||
#define BtnInsertUserHook L"插入特殊碼"
|
||||
#define BtnSearchHook L"搜尋勾點"
|
||||
#define BtnPlugin L"外掛程式"
|
||||
#define LblFlushDelay L"排清延遲"
|
||||
#define LblFilterRepeat L"過濾重複文字"
|
||||
#define LblCodePage L"預設字碼頁"
|
||||
#define LblMaxBuff L"最大緩衝區長度"
|
||||
#define LblMaxHist L"最大快取文字長度"
|
||||
#define LblAutoAttach L"自動附加"
|
||||
#define LblAutoAttach_savedonly L"自動附加(僅限儲存過配置的遊戲)"
|
||||
#define MenuCopyHookCode L"複製特殊碼"
|
||||
#define MenuRemoveHook L"移除勾點"
|
||||
#define MenuDetachProcess L"離開處理程序"
|
||||
#define MenuRemeberSelect L"記住選擇的勾點"
|
||||
#define MenuForgetSelect L"忘掉選擇的勾點"
|
||||
#define MenuAddPlugin L"新增外掛程式"
|
||||
#define MenuRemovePlugin L"移除外掛程式"
|
||||
#define MenuPluginRankUp L"上移"
|
||||
#define MenuPluginRankDown L"下移"
|
||||
#define MenuPluginEnable L"使用"
|
||||
#define MenuPluginVisSetting L"顯示設定"
|
||||
#define DefaultFont L"Microsoft JhengHei"
|
||||
#define CantLoadQtLoader L"無法載入 QtLoader.dll"
|
||||
#define InvalidPlugin L"外掛程式無效!"
|
||||
#define InvalidDll L"DLL 無效!"
|
||||
#define InvalidDump L"重複!"
|
||||
#define MsgError L"錯誤"
|
||||
#define SEARCH_CJK L"搜尋中文 / 日文 / 韓文"
|
||||
#define HS_SETTINGS L"設定"
|
||||
#define BtnOk L"確定"
|
||||
#define HS_START_HOOK_SEARCH L"開始搜尋勾點"
|
||||
#define HS_SEARCH_PATTERN L"搜尋匹配特徵(Hex Byte Array)"
|
||||
#define HS_SEARCH_DURATION L"搜尋持續時間(ms)"
|
||||
#define HS_SEARCH_MODULE L"搜尋指定模組"
|
||||
#define HS_PATTERN_OFFSET L"相對於特徵位址的偏移值"
|
||||
#define HS_MAX_HOOK_SEARCH_RECORDS L"搜尋結果達到上限"
|
||||
#define HS_MIN_ADDRESS L"起始位址(hex)"
|
||||
#define HS_MAX_ADDRESS L"結束位址(hex)"
|
||||
#define HS_STRING_OFFSET L"字串偏移值(hex)"
|
||||
#define HS_HOOK_SEARCH_FILTER L"結果必須匹配的正則表達式"
|
||||
#define HS_TEXT L"文字"
|
||||
#define HS_CODEPAGE L"字碼頁"
|
||||
#define HS_SEARCH_FOR_TEXT L"搜尋指定文字"
|
||||
#define VersionLatest L"最新版本"
|
||||
#define VersionCurrent L"目前版本"
|
||||
#define ProjectHomePage L"GitHub:https://github.com/HIllya51/LunaHook\n專案首頁:https://lunatranslator.org\nPatreon:https://patreon.com/HIllya51\nDiscord:https://discord.com/invite/ErtDwVeAbB\n\n本程式是 LunaTranslator 的核心子模組,並完全整合在 LunaTranslator 中。本程式僅包含一些簡單功能,如果您需要更多功能,請使用 LunaTranslator。\n如果你發現有不支援的遊戲,請提交 Issue"
|
||||
#define LIST_HOOK L"Hook"
|
||||
#define LIST_TEXT L"文字"
|
||||
#define PROC_CONN L"處理程序已連接 %d"
|
||||
#define PROC_DISCONN L"處理程序已中斷連接 %d"
|
||||
#define COPYSELECTION L"自動將文字框中選取的文字複製到剪貼簿"
|
||||
#define FONTSELECT L"選擇字體"
|
101
cpp/LunaHook/Lang/en.h
Normal file
101
cpp/LunaHook/Lang/en.h
Normal file
@ -0,0 +1,101 @@
|
||||
|
||||
#define ALREADY_INJECTED L"already injected"
|
||||
#define NEED_32_BIT L"architecture mismatch: only x86 can inject this process"
|
||||
#define NEED_64_BIT L"architecture mismatch: only x64 can inject this process"
|
||||
#define INJECT_FAILED L"couldn't inject"
|
||||
#define INVALID_CODEPAGE L"couldn't convert text (invalid codepage?)"
|
||||
#define PIPE_CONNECTED u8"pipe connected"
|
||||
#define INSERTING_HOOK u8"inserting hook: %s %p"
|
||||
#define REMOVING_HOOK u8"removing hook: %s"
|
||||
#define TOO_MANY_HOOKS u8"too many hooks: can't insert"
|
||||
#define HOOK_SEARCH_STARTING u8"starting hook search"
|
||||
#define HOOK_SEARCH_INITIALIZING u8"initializing hook search (%f%%)"
|
||||
#define NOT_ENOUGH_TEXT u8"not enough text to search accurately"
|
||||
#define HOOK_SEARCH_INITIALIZED u8"initialized hook search with %zd hooks"
|
||||
#define MAKE_GAME_PROCESS_TEXT u8"please click around in the game to force it to process text during the next %d seconds"
|
||||
#define HOOK_SEARCH_FINISHED u8"hook search finished, %d results found"
|
||||
#define OUT_OF_RECORDS_RETRY u8"out of search records, please retry if results are poor (default record count increased)"
|
||||
#define FUNC_MISSING u8"function not present"
|
||||
#define MODULE_MISSING u8"module not present"
|
||||
#define GARBAGE_MEMORY u8"memory inline constantly changing, useless to read"
|
||||
#define SEND_ERROR u8"Send ERROR (likely an unstable/incorrect H-code) in %s"
|
||||
#define READ_ERROR u8"Reader ERROR (likely an incorrect R-code) in %s"
|
||||
#define SearchForHooks_ERROR u8"SearchForHooks ERROR: out of memory, retrying to allocate %d"
|
||||
#define ResultsNum u8"%d results processed"
|
||||
#define HIJACK_ERROR u8"Hijack ERROR"
|
||||
#define COULD_NOT_FIND u8"could not find text"
|
||||
#define CONSOLE L"Console"
|
||||
#define InvalidLength u8"something went very wrong (invalid length %d in %s)"
|
||||
#define InsertHookFailed u8"failed to insert hook %s"
|
||||
#define Match_Error u8"ERROR happened when matching engine %s "
|
||||
#define Attach_Error u8"ERROR happened when attaching engine %s ERROR"
|
||||
#define MatchedEngine u8"Matched engine %s"
|
||||
#define ConfirmStop "Confirmed engine %s, stop checking"
|
||||
#define Attach_Stop "Attach engine %s success and stop"
|
||||
#define ProcessRange "hijacking process located from 0x%p to 0x%p"
|
||||
#define WarningDummy "WARNING injected process is very small, possibly a dummy!"
|
||||
#define WndSelectProcess L"SelectProcess"
|
||||
#define WndLunaHostGui L"LunaHost GUI"
|
||||
#define WndSetting L"Setting"
|
||||
#define WndPlugins L"Plugins"
|
||||
#define NotifyInvalidHookCode L"Invalid HookCode"
|
||||
#define BtnSelectProcess L"Select Process"
|
||||
#define BtnDetach L"Detach"
|
||||
#define BtnSaveHook L"Save hook"
|
||||
#define BtnShowSettingWindow L"Settings"
|
||||
#define BtnAttach L"Attach"
|
||||
#define BtnRefresh L"Refresh"
|
||||
#define BtnToClipboard L"Copy To Clipboard"
|
||||
#define BtnReadOnly L"Text box Read only"
|
||||
#define BtnInsertUserHook L"Insert UserHook"
|
||||
#define BtnSearchHook L"Search for hooks"
|
||||
#define BtnPlugin L"Plugins"
|
||||
#define LblFlushDelay L"Flush delay"
|
||||
#define LblFilterRepeat L"Filter repetition"
|
||||
#define LblCodePage L"Default codepage"
|
||||
#define LblMaxBuff L"Max buffer size"
|
||||
#define LblMaxHist L"Max history size"
|
||||
#define LblAutoAttach L"Auto attach"
|
||||
#define LblAutoAttach_savedonly L"Auto attach (saved only)"
|
||||
#define MenuCopyHookCode L"CopyHookCode"
|
||||
#define MenuRemoveHook L"RemoveHook"
|
||||
#define MenuDetachProcess L"DetachProcess"
|
||||
#define MenuRemeberSelect L"Remeber Hook Selection"
|
||||
#define MenuForgetSelect L"Forget Hook Selection"
|
||||
#define MenuAddPlugin L"Add Plugin"
|
||||
#define MenuRemovePlugin L"Remove Plugin"
|
||||
#define MenuPluginRankUp L"Up"
|
||||
#define MenuPluginRankDown L"Down"
|
||||
#define MenuPluginEnable L"Enable"
|
||||
#define MenuPluginVisSetting L"Show Setting"
|
||||
#define DefaultFont L"Arial"
|
||||
#define CantLoadQtLoader L"Can't Load QtLoader.dll"
|
||||
#define InvalidPlugin L"Invalid Plugin!"
|
||||
#define InvalidDll L"Invalid Dll!"
|
||||
#define InvalidDump L"Dumplicated!"
|
||||
#define MsgError L"Error"
|
||||
#define SEARCH_CJK L"Search for Chinese/Japanese/Korean"
|
||||
#define HS_SETTINGS L"Settings"
|
||||
#define BtnOk L"OK"
|
||||
#define HS_START_HOOK_SEARCH L"Start hook search"
|
||||
#define HS_SEARCH_PATTERN L"Search pattern (hex byte array)"
|
||||
#define HS_SEARCH_DURATION L"Search duration (ms)"
|
||||
#define HS_SEARCH_MODULE L"Search within module"
|
||||
#define HS_PATTERN_OFFSET L"Offset from pattern start"
|
||||
#define HS_MAX_HOOK_SEARCH_RECORDS L"Search result cap"
|
||||
#define HS_MIN_ADDRESS L"Minimum address (hex)"
|
||||
#define HS_MAX_ADDRESS L"Maximum address (hex)"
|
||||
#define HS_STRING_OFFSET L"String offset (hex)"
|
||||
#define HS_HOOK_SEARCH_FILTER L"Results must match this regex"
|
||||
#define HS_TEXT L"Text"
|
||||
#define HS_CODEPAGE L"Codepage"
|
||||
#define HS_SEARCH_FOR_TEXT L"Search for specific text"
|
||||
#define VersionLatest L"Latest version"
|
||||
#define VersionCurrent L"Current version"
|
||||
#define ProjectHomePage L"Github: https://github.com/HIllya51/LunaHook\nHomepage: https://lunatranslator.org\npatreon: https://patreon.com/HIllya51\n\nThis program is a core submodule of LunaTranslator and is fully integrated in Lunatranslator. This program contains only some simple functions, if you need more functions, please use LunaTranslator.\nIf you find unsupported games, please submit an issue"
|
||||
#define LIST_HOOK L"Hook"
|
||||
#define LIST_TEXT L"Text"
|
||||
#define PROC_CONN L"process connected %d"
|
||||
#define PROC_DISCONN L"process disconnected %d"
|
||||
#define COPYSELECTION L"auto send selected text in textbox to clipboard"
|
||||
#define FONTSELECT L"Select Font"
|
101
cpp/LunaHook/Lang/ru.h
Normal file
101
cpp/LunaHook/Lang/ru.h
Normal file
@ -0,0 +1,101 @@
|
||||
|
||||
#define ALREADY_INJECTED L"Уже внедрено"
|
||||
#define NEED_32_BIT L"Неверная архетектура: тут нужно x86"
|
||||
#define NEED_64_BIT L"Неверная архетектура: тут нужно x64"
|
||||
#define INJECT_FAILED L"Не удалось внедрить"
|
||||
#define INVALID_CODEPAGE L"Не удалось преобразовать текст (неверная кодовая страница?)"
|
||||
#define PIPE_CONNECTED u8"Канал подключен"
|
||||
#define INSERTING_HOOK u8"установка хука: %s %p"
|
||||
#define REMOVING_HOOK u8"Удаление хука: %s"
|
||||
#define TOO_MANY_HOOKS u8"Слишком много хуков: невозможно добавить"
|
||||
#define HOOK_SEARCH_STARTING u8"Запущен поиск хуков"
|
||||
#define HOOK_SEARCH_INITIALIZING u8"Инициализация поиска хуков (%f%%)"
|
||||
#define NOT_ENOUGH_TEXT u8"Недостаточно текста для точного поиска"
|
||||
#define HOOK_SEARCH_INITIALIZED u8"Поиск хуков инициализирован, найдено %zd хуков"
|
||||
#define MAKE_GAME_PROCESS_TEXT u8"Пожалуйста, пощелкайте в игре, чтобы заставить ее обработать текст в течение следующих %d секунд"
|
||||
#define HOOK_SEARCH_FINISHED u8"Поиск хуков завершен, найдено %d результатов"
|
||||
#define OUT_OF_RECORDS_RETRY u8"Закончились записи поиска, попробуйте еще раз, если результаты неудовлетворительны (количество записей по умолчанию увеличено)"
|
||||
#define FUNC_MISSING u8"Функция не найдена"
|
||||
#define MODULE_MISSING u8"Модуль не найден"
|
||||
#define GARBAGE_MEMORY u8"Данные в памяти постоянно меняются, чтение бесполезно"
|
||||
#define SEND_ERROR u8"Ошибка отправки (возможен нестабильный/неверный H-код) в %s"
|
||||
#define READ_ERROR u8"Ошибка чтения (возможен неверный R-код) в %s"
|
||||
#define SearchForHooks_ERROR u8"Ошибка SearchForHooks: недостаточно памяти, повторная попытка выделения %d"
|
||||
#define ResultsNum u8"Обработано %d результатов"
|
||||
#define HIJACK_ERROR u8"Ошибка перехвата"
|
||||
#define COULD_NOT_FIND u8"Не удалось найти текст"
|
||||
#define CONSOLE L"Консоль"
|
||||
#define InvalidLength u8"Произошла критическая ошибка (неверная длина %d в %s)"
|
||||
#define InsertHookFailed u8"Не удалось установить хук %s"
|
||||
#define Match_Error u8"Ошибка при сопоставлении с движком %s"
|
||||
#define Attach_Error u8"Ошибка при подключении к движку %s"
|
||||
#define MatchedEngine u8"Сопоставлен движок %s"
|
||||
#define ConfirmStop u8"Подтвержден движок %s, поиск остановлен"
|
||||
#define Attach_Stop u8"Движок %s успешно подключен, поиск остановлен"
|
||||
#define ProcessRange u8"Перехват процесса в диапазоне адресов с 0x%p по 0x%p"
|
||||
#define WarningDummy u8"ПРЕДУПРЕЖДЕНИЕ: внедренный процесс очень мал, возможно, это пустышка!"
|
||||
#define WndSelectProcess L"Выбор процесса"
|
||||
#define WndLunaHostGui L"LunaHost - GUI"
|
||||
#define WndSetting L"Настройки"
|
||||
#define WndPlugins L"Плагины"
|
||||
#define NotifyInvalidHookCode L"Неверный код хука"
|
||||
#define BtnSelectProcess L"Выбрать процесс"
|
||||
#define BtnDetach L"Отключить"
|
||||
#define BtnSaveHook L"Сохранить хук"
|
||||
#define BtnShowSettingWindow L"Настройки"
|
||||
#define BtnAttach L"Подключить"
|
||||
#define BtnRefresh L"Обновить"
|
||||
#define BtnToClipboard L"Скопировать в буфер обмена"
|
||||
#define BtnReadOnly L"Текстовое поле доступно только для чтения"
|
||||
#define BtnInsertUserHook L"Добавить польз. хук"
|
||||
#define BtnSearchHook L"Найти хуки"
|
||||
#define BtnPlugin L"Плагины"
|
||||
#define LblFlushDelay L"Задержка сброса"
|
||||
#define LblFilterRepeat L"Фильтр повторов"
|
||||
#define LblCodePage L"Кодовая страница по умолчанию"
|
||||
#define LblMaxBuff L"Максимальный размер буфера"
|
||||
#define LblMaxHist L"Максимальный размер истории"
|
||||
#define LblAutoAttach L"Автоподключение"
|
||||
#define LblAutoAttach_savedonly L"Автоподключение (только сохраненные)"
|
||||
#define MenuCopyHookCode L"Скопировать код хука"
|
||||
#define MenuRemoveHook L"Удалить хук"
|
||||
#define MenuDetachProcess L"Отключиться от процесса"
|
||||
#define MenuRemeberSelect L"Запомнить выбранный хук"
|
||||
#define MenuForgetSelect L"Забыть выбранный хук"
|
||||
#define MenuAddPlugin L"Добавить плагин"
|
||||
#define MenuRemovePlugin L"Удалить плагин"
|
||||
#define MenuPluginRankUp L"Вверх"
|
||||
#define MenuPluginRankDown L"Вниз"
|
||||
#define MenuPluginEnable L"Включить"
|
||||
#define MenuPluginVisSetting L"Показать настройки"
|
||||
#define DefaultFont L"Arial"
|
||||
#define CantLoadQtLoader L"Не удалось загрузить QtLoader.dll"
|
||||
#define InvalidPlugin L"Неверный плагин!"
|
||||
#define InvalidDll L"Неверная DLL!"
|
||||
#define InvalidDump L"Дубликат!"
|
||||
#define MsgError L"Ошибка"
|
||||
#define SEARCH_CJK L"Искать китайские/японские/корейские символы"
|
||||
#define HS_SETTINGS L"Настройки"
|
||||
#define BtnOk L"OK"
|
||||
#define HS_START_HOOK_SEARCH L"Начать поиск хуков"
|
||||
#define HS_SEARCH_PATTERN L"Шаблон поиска (массив шестнадцатеричных байтов)"
|
||||
#define HS_SEARCH_DURATION L"Длительность поиска (мс)"
|
||||
#define HS_SEARCH_MODULE L"Искать внутри модуля"
|
||||
#define HS_PATTERN_OFFSET L"Смещение от начала шаблона"
|
||||
#define HS_MAX_HOOK_SEARCH_RECORDS L"Максимальное количество результатов поиска"
|
||||
#define HS_MIN_ADDRESS L"Минимальный адрес (шестнадцатеричный)"
|
||||
#define HS_MAX_ADDRESS L"Максимальный адрес (шестнадцатеричный)"
|
||||
#define HS_STRING_OFFSET L"Смещение строки (шестнадцатеричное)"
|
||||
#define HS_HOOK_SEARCH_FILTER L"Результаты должны соответствовать этому регулярному выражению"
|
||||
#define HS_TEXT L"Текст"
|
||||
#define HS_CODEPAGE L"Кодовая страница"
|
||||
#define HS_SEARCH_FOR_TEXT L"Искать определенный текст"
|
||||
#define VersionLatest L"Последняя версия"
|
||||
#define VersionCurrent L"Текущая версия"
|
||||
#define ProjectHomePage L"Github: https://github.com/HIllya51/LunaHook\nСтраница проекта: https://lunatranslator.org\npatreon: https://patreon.com/HIllya51\nDiscord: https://discord.com/invite/ErtDwVeAbB\n\nЭта программа является основным подмодулем LunaTranslator и полностью интегрирована в Lunatranslator. Эта программа содержит только некоторые простые функции. Если вам нужны дополнительные функции, используйте LunaTranslator.\nЕсли вы обнаружите какие-либо неподдерживаемые игры, сообщите о проблеме."
|
||||
#define LIST_HOOK L"Хук"
|
||||
#define LIST_TEXT L"Текст"
|
||||
#define PROC_CONN L"Процесс подключен %d"
|
||||
#define PROC_DISCONN L"Процесс отключен %d"
|
||||
#define COPYSELECTION L"Автоматически копировать выделенный текст в буфер обмена"
|
||||
#define FONTSELECT L"Выбрать шрифт"
|
101
cpp/LunaHook/Lang/zh.h
Normal file
101
cpp/LunaHook/Lang/zh.h
Normal file
@ -0,0 +1,101 @@
|
||||
|
||||
#define ALREADY_INJECTED L"已经注入"
|
||||
#define NEED_32_BIT L"架构不匹配: 请尝试使用32位注入此进程"
|
||||
#define NEED_64_BIT L"架构不匹配: 请尝试使用64位注入此进程"
|
||||
#define INJECT_FAILED L"注入失败"
|
||||
#define INVALID_CODEPAGE L"无法转换文本 (无效的代码页?)"
|
||||
#define PIPE_CONNECTED u8"管道已连接"
|
||||
#define INSERTING_HOOK u8"注入钩子: %s %p"
|
||||
#define REMOVING_HOOK u8"移除钩子: %s"
|
||||
#define TOO_MANY_HOOKS u8"钩子数量已达上限: 无法注入"
|
||||
#define HOOK_SEARCH_STARTING u8"开始搜索钩子"
|
||||
#define HOOK_SEARCH_INITIALIZING u8"初始化钩子搜索 (%f%%)"
|
||||
#define NOT_ENOUGH_TEXT u8"文本长度不足, 无法精确搜索"
|
||||
#define HOOK_SEARCH_INITIALIZED u8"搜索初始化完成, 创建了 %zd 个钩子"
|
||||
#define MAKE_GAME_PROCESS_TEXT u8"请点击游戏区域, 在接下来的 %d 秒内使游戏强制处理文本"
|
||||
#define HOOK_SEARCH_FINISHED u8"钩子搜索完毕, 找到了 %d 条结果"
|
||||
#define OUT_OF_RECORDS_RETRY u8"搜索结果已达上限, 如果结果不理想, 请重试(默认最大记录数增加)"
|
||||
#define FUNC_MISSING u8"函数不存在"
|
||||
#define MODULE_MISSING u8"模块不存在"
|
||||
#define GARBAGE_MEMORY u8"内存一直在改变,无法有效读取"
|
||||
#define SEND_ERROR u8"Sender 错误 (可能是由于错误或不稳定的 H-code) : %s"
|
||||
#define READ_ERROR u8"Reader 错误 (可能是由于错误或不稳定的 R-code) : %s"
|
||||
#define SearchForHooks_ERROR u8"搜索钩子错误 : 内存移除,尝试重新分配 %d"
|
||||
#define ResultsNum u8"%d 个结果被找到"
|
||||
#define HIJACK_ERROR u8"Hijack 错误"
|
||||
#define COULD_NOT_FIND u8"无法找到文本"
|
||||
#define CONSOLE L"控制台"
|
||||
#define InvalidLength u8"可能存在错误 (无效的文本长度 %d 出现 %s)"
|
||||
#define InsertHookFailed u8"钩子注入失败 %s"
|
||||
#define Match_Error u8"匹配 %s 引擎时发生错误"
|
||||
#define Attach_Error u8"连接到 %s 引擎时发送错误"
|
||||
#define MatchedEngine u8"匹配到 %s 引擎"
|
||||
#define ConfirmStop u8"确认是 %s 引擎, 停止匹配"
|
||||
#define Attach_Stop u8"成功连接到 %s 引擎"
|
||||
#define ProcessRange u8"获取到进程内存地址范围 0x%p 到 0x%p"
|
||||
#define WarningDummy u8"警告,注入的进程内存很小,可能是无用进程!"
|
||||
#define WndSelectProcess L"选择进程"
|
||||
#define WndLunaHostGui L"LunaHost GUI"
|
||||
#define WndSetting L"设置"
|
||||
#define WndPlugins L"插件"
|
||||
#define NotifyInvalidHookCode L"特殊码无效"
|
||||
#define BtnSelectProcess L"选择进程"
|
||||
#define BtnDetach L"从游戏分离"
|
||||
#define BtnSaveHook L"保存钩子"
|
||||
#define BtnShowSettingWindow L"设置"
|
||||
#define BtnAttach L"注入进程"
|
||||
#define BtnRefresh L"刷新"
|
||||
#define BtnToClipboard L"复制到剪贴板"
|
||||
#define BtnReadOnly L"文本框只读"
|
||||
#define BtnInsertUserHook L"插入特殊码"
|
||||
#define BtnSearchHook L"搜索钩子"
|
||||
#define BtnPlugin L"插件"
|
||||
#define LblFlushDelay L"刷新延迟"
|
||||
#define LblFilterRepeat L"过滤重复文本"
|
||||
#define LblCodePage L"默认代码页"
|
||||
#define LblMaxBuff L"最大缓冲区长度"
|
||||
#define LblMaxHist L"最大缓存文本长度"
|
||||
#define LblAutoAttach L"自动附加"
|
||||
#define LblAutoAttach_savedonly L"自动附加 (仅限保存过配置的游戏)"
|
||||
#define MenuCopyHookCode L"复制特殊码"
|
||||
#define MenuRemoveHook L"移除钩子"
|
||||
#define MenuDetachProcess L"离开进程"
|
||||
#define MenuRemeberSelect L"记住选择的钩子"
|
||||
#define MenuForgetSelect L"忘掉选择的钩子"
|
||||
#define MenuAddPlugin L"添加插件"
|
||||
#define MenuRemovePlugin L"移除插件"
|
||||
#define MenuPluginRankUp L"上移"
|
||||
#define MenuPluginRankDown L"下移"
|
||||
#define MenuPluginEnable L"使用"
|
||||
#define MenuPluginVisSetting L"显示设置"
|
||||
#define DefaultFont L"微软雅黑"
|
||||
#define CantLoadQtLoader L"无法加载QtLoader.dll"
|
||||
#define InvalidPlugin L"插件无效!"
|
||||
#define InvalidDll L"Dll无效!"
|
||||
#define InvalidDump L"重复!"
|
||||
#define MsgError L"错误"
|
||||
#define SEARCH_CJK L"搜索中文/日文/韩文"
|
||||
#define HS_SETTINGS L"设置"
|
||||
#define BtnOk L"确定"
|
||||
#define HS_START_HOOK_SEARCH L"开始搜索钩子"
|
||||
#define HS_SEARCH_PATTERN L"搜索匹配特征 (hex byte array)"
|
||||
#define HS_SEARCH_DURATION L"搜索持续时间 (ms)"
|
||||
#define HS_SEARCH_MODULE L"搜索指定模块"
|
||||
#define HS_PATTERN_OFFSET L"相对于特征地址的偏移值"
|
||||
#define HS_MAX_HOOK_SEARCH_RECORDS L"搜索结果达到上限"
|
||||
#define HS_MIN_ADDRESS L"起始地址 (hex)"
|
||||
#define HS_MAX_ADDRESS L"结束地址 (hex)"
|
||||
#define HS_STRING_OFFSET L"字符串偏移值 (hex)"
|
||||
#define HS_HOOK_SEARCH_FILTER L"结果必须匹配的正则表达式"
|
||||
#define HS_TEXT L"文本"
|
||||
#define HS_CODEPAGE L"代码页"
|
||||
#define HS_SEARCH_FOR_TEXT L"搜索指定文本"
|
||||
#define VersionLatest L"最新版本"
|
||||
#define VersionCurrent L"当前版本"
|
||||
#define ProjectHomePage L"Github: https://github.com/HIllya51/LunaHook\n项目主页: https://lunatranslator.org\npatreon:https://patreon.com/HIllya51\nDiscord:https://discord.com/invite/ErtDwVeAbB\n\n本程序是LunaTranslator 的核心子模块,并完全集成在Lunatranslator中。本程序仅包含一些简单功能,如果您需要更多功能,请使用 LunaTranslator。\n如果你发现有不支持的游戏,请提交issue"
|
||||
#define LIST_HOOK L"Hook"
|
||||
#define LIST_TEXT L"文本"
|
||||
#define PROC_CONN L"进程已连接 %d"
|
||||
#define PROC_DISCONN L"进程已断开连接 %d"
|
||||
#define COPYSELECTION L"自动将文本框中选取的文本复制到剪贴板"
|
||||
#define FONTSELECT L"选择字体"
|
54
cpp/LunaHook/LunaHook/CMakeLists.txt
Normal file
54
cpp/LunaHook/LunaHook/CMakeLists.txt
Normal file
@ -0,0 +1,54 @@
|
||||
include_directories(. util engines)
|
||||
if(${CMAKE_SIZEOF_VOID_P} EQUAL 8)
|
||||
set(enginessrc MKXPZ Ryujinx livecaptions Kincaid vita3k rpcs3 yuzu TYPEMOON UnrealEngine AGES7 mono Godot 5pb lucasystem LightVN V8 pchooks Artemis KiriKiri YOX PPSSPP CMVS Suika2 )
|
||||
set(enginepath "engine64")
|
||||
set(collector "enginecollection64.cpp")
|
||||
else()
|
||||
set(enginessrc Cage AGE_System AksysGames RPGMaker Stronger TACTICS Onscripter Sceplay DISCOVERY Erogos godot A98SYS GuruGuruSMF4 TeethingRing Fizz CoffeeMaker VALKYRIA mirage CisLugI tamasoft FrontWing solfasys Diskdream splushwave ransel akatombo GASTRO GSX Aksys ScrPlayer SYSD KISS IGScript Jellyfish BKEngine Overflow SRPGStudio Suika2 FVP LCScript Ohgetsu RPGMakerRGSS3 ONScripterru OVERDRIVE HXP Palette Purple Ruf RUNE Tarte Tomato Sakuradog Troy VitaminSoft UnknownEngine TSSystem Xbangbang Anisetta Nijyuei Interheart LovaGame Giga Jisatu101 EntisGLS Ciel ACTGS TerraLunar PPSSPP jukujojidai PCSX2 VanillawareGC cef V8 mono pchooks PONScripter Bishop sakanagl Lightvn KiriKiri SideB BGI Bootup morning shyakunage Regista NNNConfig Eushully Majiro littlecheese Elf Silkys CMVS Wolf Circus1 Circus2 Cotopha Artemis CatSystem Atelier Tenco QLIE Pal AIL2 NeXAS LunaSoft Unicorn Rejet Interlude AdobeAir Retouch Malie Live Nexton Lucifen Waffle TinkerBell SystemAoi Yuris Nitroplus2 Bruns EME RRE Candy Speed ApricoT Triangle AB2Try MBLMED GameMaker DxLib CodeX Minori Sprite RpgmXP Eagls Debonosu C4 WillPlus Tanuki GXP AOS Mink YukaSystem2 sakusesu Exp Syuntada Pensil Anim hibiki Nitroplus Reallive Siglus Taskforce2 RUGP IronGameSystem Anex86 ShinyDaysGame MarineHeart ShinaRio CaramelBox UnisonShift Escude Ryokucha Alice Footy2 utawarerumono System4x Abalone Abel 5pb HorkEye XUSE Leaf Nekopack AXL AGS AdobeFlash10 FocasLens Tamamo Ages3ResT)
|
||||
set(enginepath "engine32")
|
||||
set(collector "enginecollection32.cpp")
|
||||
endif()
|
||||
string(REPLACE ";" ".cpp;${enginepath}/" enginessrc "${enginessrc}")
|
||||
#message("${enginessrc}")
|
||||
set(enginessrc "${enginepath}/${enginessrc}.cpp")
|
||||
message("${enginessrc}")
|
||||
set_source_files_properties(${enginessrc} PROPERTIES SOURCE_ENCODING "UTF-8")
|
||||
|
||||
set(texthook_src
|
||||
main.cc
|
||||
texthook.cc
|
||||
hookfinder.cc
|
||||
${enginessrc}
|
||||
${collector}
|
||||
enginecontrol.cpp
|
||||
embed_util.cc
|
||||
hijackfuns.cc
|
||||
veh_hook.cpp
|
||||
)
|
||||
|
||||
|
||||
add_library(pchhook pchhook.cpp)
|
||||
target_precompile_headers(pchhook PUBLIC pchhook.h)
|
||||
|
||||
|
||||
add_subdirectory(util)
|
||||
add_subdirectory(engines)
|
||||
|
||||
generate_product_version(
|
||||
versioninfohook
|
||||
NAME "LunaHook"
|
||||
COMPANY_COPYRIGHT "HIllya51 (C) 2024"
|
||||
ICON ${PATH_TO_APPLICATION_ICON}
|
||||
VERSION_MAJOR ${VERSION_MAJOR}
|
||||
VERSION_MINOR ${VERSION_MINOR}
|
||||
VERSION_PATCH ${VERSION_PATCH}
|
||||
VERSION_REVISION ${VERSION_REVISION}
|
||||
)
|
||||
|
||||
add_library(LunaHook MODULE ${texthook_src} resource.rc ${versioninfohook})
|
||||
|
||||
target_precompile_headers(LunaHook REUSE_FROM pchhook)
|
||||
|
||||
set_target_properties(LunaHook PROPERTIES OUTPUT_NAME "LunaHook${bitappendix}")
|
||||
|
||||
target_link_libraries(LunaHook Version httpapi ws2_32 Shlwapi pch minhook commonengine utils ${YY_Thunks_for_WinXP})
|
143
cpp/LunaHook/LunaHook/NoEngine.h
Normal file
143
cpp/LunaHook/LunaHook/NoEngine.h
Normal file
@ -0,0 +1,143 @@
|
||||
class NoEngine : public ENGINE
|
||||
{
|
||||
public:
|
||||
bool attach_function()
|
||||
{
|
||||
ConsoleOutput("IGNORE %s", getenginename());
|
||||
// ConsoleOutput("IGNORE engine");
|
||||
return true;
|
||||
}
|
||||
};
|
||||
class oldSystem40ini : public NoEngine
|
||||
{
|
||||
public:
|
||||
oldSystem40ini()
|
||||
{
|
||||
// jichi 1/19/2015: Disable inserting Lstr for System40
|
||||
// See: http://sakuradite.com/topic/618
|
||||
|
||||
check_by = CHECK_BY::FILE;
|
||||
check_by_target = L"System40.ini";
|
||||
};
|
||||
};
|
||||
// class RPGMakerRGSS3:public NoEngine{
|
||||
// public:
|
||||
// RPGMakerRGSS3(){
|
||||
// // jichi 6/7/2015: RPGMaker v3
|
||||
|
||||
// check_by=CHECK_BY::FILE;
|
||||
// check_by_target=L"*.rgss3a";
|
||||
// };
|
||||
// };
|
||||
|
||||
// class FVP:public NoEngine{
|
||||
// public:
|
||||
// FVP(){
|
||||
// // 7/28/2015 jichi: Favorite games
|
||||
|
||||
// check_by=CHECK_BY::FILE;
|
||||
// check_by_target=L"*.hcb";
|
||||
// };
|
||||
// };
|
||||
|
||||
class AdvPlayerHD : public NoEngine
|
||||
{
|
||||
public:
|
||||
AdvPlayerHD()
|
||||
{
|
||||
// supposed to be WillPlus
|
||||
|
||||
check_by = CHECK_BY::FILE_ANY;
|
||||
check_by_target = check_by_list{L"AdvHD.exe", L"AdvHD.dll"};
|
||||
};
|
||||
};
|
||||
|
||||
class DPM : public NoEngine
|
||||
{
|
||||
public:
|
||||
DPM()
|
||||
{
|
||||
// jichi 4/30/2015: Skip games made from らすこう, such as とある人妻のネトラレ事情
|
||||
// It has garbage from lstrlenW. Correct text is supposed to be in TabbedTextOutA.
|
||||
|
||||
check_by = CHECK_BY::FILE;
|
||||
check_by_target = L"data_cg.dpm";
|
||||
};
|
||||
};
|
||||
|
||||
class Escude_ignore : public NoEngine
|
||||
{
|
||||
public:
|
||||
Escude_ignore()
|
||||
{
|
||||
// jichi 3/19/2014: Escude game
|
||||
// Example: bgm.bin gfx.bin maou.bin script.bin snd.bin voc.bin
|
||||
|
||||
check_by = CHECK_BY::FILE_ANY;
|
||||
check_by_target = check_by_list{L"gfx.bin", L"snd.bin", L"voc.bin"};
|
||||
};
|
||||
};
|
||||
|
||||
class Chartreux : public NoEngine
|
||||
{
|
||||
public:
|
||||
Chartreux()
|
||||
{
|
||||
|
||||
// jichi 12/28/2014: "Chartreux Inc." in Copyright.
|
||||
// Sublimary brands include Rosebleu, MORE, etc.
|
||||
// GetGlyphOutlineA already works.
|
||||
|
||||
check_by = CHECK_BY::RESOURCE_STR;
|
||||
check_by_target = L"Chartreux";
|
||||
};
|
||||
};
|
||||
class lcsebody : public NoEngine
|
||||
{
|
||||
public:
|
||||
lcsebody()
|
||||
{
|
||||
|
||||
check_by = CHECK_BY::CUSTOM;
|
||||
// jichi 3/19/2014: LC-ScriptEngine, GetGlyphOutlineA
|
||||
check_by_target = []()
|
||||
{
|
||||
return (wcsstr(processName, L"lcsebody") || !wcsncmp(processName, L"lcsebo~", 7) || Util::CheckFile(L"lcsebody*"));
|
||||
};
|
||||
};
|
||||
};
|
||||
// class FVP2:public NoEngine{
|
||||
// public:
|
||||
// FVP2(){
|
||||
|
||||
// check_by=CHECK_BY::CUSTOM;
|
||||
// // jichi 3/19/2014: LC-ScriptEngine, GetGlyphOutlineA
|
||||
// check_by_target=[](){
|
||||
|
||||
// wchar_t str[MAX_PATH];
|
||||
// DWORD i;
|
||||
// for (i = 0; processName[i]; i++) {
|
||||
// str[i] = processName[i];
|
||||
// if (processName[i] == L'.')
|
||||
// break;
|
||||
// }
|
||||
// *(DWORD *)(str + i + 1) = 0x630068; //.hcb
|
||||
// *(DWORD *)(str + i + 3) = 0x62;
|
||||
// // jichi 10/3/2013: such like アトリエかぐや
|
||||
// return (Util::CheckFile(str));
|
||||
// };
|
||||
// };
|
||||
// };
|
||||
|
||||
// if (Util::CheckFile(L"AGERC.DLL")) { // jichi 3/17/2014: Eushully, AGE.EXE
|
||||
// ConsoleOutput("IGNORE Eushully");
|
||||
// return true;
|
||||
// }
|
||||
// if (Util::CheckFile(L"*\\Managed\\UnityEngine.dll")) { // jichi 12/3/2013: Unity (BALDRSKY ZERO)
|
||||
// ConsoleOutput("IGNORE Unity");
|
||||
// return true;
|
||||
// }
|
||||
// if (Util::CheckFile(L"bsz_Data\\Managed\\UnityEngine.dll") || Util::CheckFile(L"bsz2_Data\\Managed\\UnityEngine.dll")) {
|
||||
// ConsoleOutput("IGNORE Unity");
|
||||
// return true;
|
||||
// }
|
278
cpp/LunaHook/LunaHook/embed_util.cc
Normal file
278
cpp/LunaHook/LunaHook/embed_util.cc
Normal file
@ -0,0 +1,278 @@
|
||||
#include "MinHook.h"
|
||||
|
||||
DynamicShiftJISCodec *dynamiccodec = new DynamicShiftJISCodec(932);
|
||||
|
||||
void cast_back(const HookParam &hp, TextBuffer*buff, const std::wstring &trans, bool normal)
|
||||
{
|
||||
|
||||
if ((hp.type & EMBED_CODEC_UTF16) || (hp.type & CODEC_UTF16))
|
||||
{ // renpy
|
||||
buff->from(trans);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::string astr;
|
||||
if (hp.type & EMBED_DYNA_SJIS && !normal)
|
||||
{
|
||||
astr = dynamiccodec->encodeSTD(trans, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
astr = WideStringToString(trans, hp.codepage ? hp.codepage : ((hp.type & CODEC_UTF8) ? CP_UTF8 : commonsharedmem->codepage));
|
||||
}
|
||||
buff->from(astr);
|
||||
}
|
||||
}
|
||||
|
||||
struct FunctionInfo
|
||||
{
|
||||
const char *name; // for debugging purpose
|
||||
uintptr_t *oldFunction,
|
||||
newFunction;
|
||||
bool attached;
|
||||
uintptr_t addr;
|
||||
explicit FunctionInfo(const uintptr_t _addr = 0, const char *name = "", uintptr_t *oldFunction = nullptr, uintptr_t newFunction = 0,
|
||||
bool attached = false)
|
||||
: name(name), oldFunction(oldFunction), newFunction(newFunction), attached(attached), addr(_addr)
|
||||
{
|
||||
}
|
||||
};
|
||||
std::unordered_map<uintptr_t, FunctionInfo> funcs; // attached functions
|
||||
std::vector<uintptr_t> replacedfuns; // attached functions
|
||||
bool _1f()
|
||||
{
|
||||
#define ADD_FUN(_f) funcs[F_##_f] = FunctionInfo((uintptr_t)_f, #_f, (uintptr_t *)&Hijack::old##_f, (uintptr_t)Hijack::new##_f);
|
||||
ADD_FUN(CreateFontA)
|
||||
ADD_FUN(CreateFontW)
|
||||
ADD_FUN(CreateFontIndirectA)
|
||||
ADD_FUN(CreateFontIndirectW)
|
||||
ADD_FUN(GetGlyphOutlineA)
|
||||
ADD_FUN(GetGlyphOutlineW)
|
||||
ADD_FUN(GetTextExtentPoint32A)
|
||||
ADD_FUN(GetTextExtentPoint32W)
|
||||
ADD_FUN(GetTextExtentExPointA)
|
||||
ADD_FUN(GetTextExtentExPointW)
|
||||
// ADD_FUN(GetCharABCWidthsA)
|
||||
// ADD_FUN(GetCharABCWidthsW)
|
||||
ADD_FUN(TextOutA)
|
||||
ADD_FUN(TextOutW)
|
||||
ADD_FUN(ExtTextOutA)
|
||||
ADD_FUN(ExtTextOutW)
|
||||
ADD_FUN(DrawTextA)
|
||||
ADD_FUN(DrawTextW)
|
||||
ADD_FUN(DrawTextExA)
|
||||
ADD_FUN(DrawTextExW)
|
||||
ADD_FUN(CharNextA)
|
||||
// ADD_FUN(CharNextW)
|
||||
// ADD_FUN(CharNextExA)
|
||||
// ADD_FUN(CharNextExW)
|
||||
ADD_FUN(CharPrevA)
|
||||
// ADD_FUN(CharPrevW)
|
||||
ADD_FUN(MultiByteToWideChar)
|
||||
ADD_FUN(WideCharToMultiByte)
|
||||
#undef ADD_FUN
|
||||
return 0;
|
||||
}
|
||||
bool _1 = _1f();
|
||||
bool ReplaceFunction(PVOID oldf, PVOID newf, PVOID *pOrigin)
|
||||
{
|
||||
PVOID oldx;
|
||||
if (!pOrigin)
|
||||
pOrigin = &oldx;
|
||||
RemoveHook((uintptr_t)oldf);
|
||||
if (MH_OK == MH_CreateHook(oldf, newf, pOrigin))
|
||||
return MH_OK == MH_EnableHook(oldf);
|
||||
else
|
||||
{
|
||||
MH_RemoveHook(oldf);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
void attachFunction(uintptr_t _hook_font_flag)
|
||||
{
|
||||
for (auto &_func : funcs)
|
||||
{
|
||||
if (_func.first & _hook_font_flag)
|
||||
{
|
||||
if (_func.second.attached)
|
||||
continue;
|
||||
|
||||
if (ReplaceFunction((PVOID)_func.second.addr, (PVOID)_func.second.newFunction, (PVOID *)_func.second.oldFunction))
|
||||
{
|
||||
_func.second.attached = true;
|
||||
replacedfuns.push_back(_func.first);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
void detachall()
|
||||
{
|
||||
for (auto _flag : replacedfuns)
|
||||
{
|
||||
auto info = funcs.at(_flag);
|
||||
if (MH_OK == MH_DisableHook((LPVOID)info.addr))
|
||||
MH_RemoveHook((LPVOID)info.addr);
|
||||
}
|
||||
}
|
||||
void solvefont(HookParam hp)
|
||||
{
|
||||
if (hp.hook_font)
|
||||
{
|
||||
attachFunction(hp.hook_font);
|
||||
}
|
||||
if (hp.hook_font & F_MultiByteToWideChar)
|
||||
disable_mbwc = true;
|
||||
if (hp.hook_font & F_WideCharToMultiByte)
|
||||
disable_wcmb = true;
|
||||
|
||||
if (auto current_patch_fun = patch_fun.exchange(nullptr))
|
||||
{
|
||||
current_patch_fun();
|
||||
dont_detach = true;
|
||||
}
|
||||
}
|
||||
static std::wstring alwaysInsertSpacesSTD(const std::wstring &text)
|
||||
{
|
||||
std::wstring ret;
|
||||
for (auto c : text)
|
||||
{
|
||||
ret.push_back(c);
|
||||
if (c >= 32) // ignore non-printable characters
|
||||
ret.push_back(L' '); // or insert \u3000 if needed
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
bool charEncodableSTD(const wchar_t &ch, UINT codepage)
|
||||
{
|
||||
|
||||
if (ch <= 127) // ignore ascii characters
|
||||
return true;
|
||||
std::wstring s;
|
||||
s.push_back(ch);
|
||||
return StringToWideString(WideStringToString(s, codepage), codepage).value() == s;
|
||||
}
|
||||
static std::wstring insertSpacesAfterUnencodableSTD(const std::wstring &text, HookParam hp)
|
||||
{
|
||||
|
||||
std::wstring ret;
|
||||
for (const wchar_t &c : text)
|
||||
{
|
||||
ret.push_back(c);
|
||||
if (!charEncodableSTD(c, hp.codepage ? hp.codepage : commonsharedmem->codepage))
|
||||
ret.push_back(L' ');
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
std::wstring adjustSpacesSTD(const std::wstring &text, HookParam hp)
|
||||
{
|
||||
if (hp.type & EMBED_INSERT_SPACE_ALWAYS)
|
||||
return alwaysInsertSpacesSTD(text);
|
||||
else if (hp.type & EMBED_INSERT_SPACE_AFTER_UNENCODABLE)
|
||||
return insertSpacesAfterUnencodableSTD(text, hp);
|
||||
return text;
|
||||
}
|
||||
bool isPauseKeyPressed()
|
||||
{
|
||||
return WinKey::isKeyControlPressed() || WinKey::isKeyShiftPressed() && !WinKey::isKeyReturnPressed();
|
||||
}
|
||||
std::unordered_map<UINT64, std::wstring> translatecache;
|
||||
bool check_is_thread_selected(const ThreadParam &tp)
|
||||
{
|
||||
for (int i = 0; i < ARRAYSIZE(commonsharedmem->embedtps); i++)
|
||||
{
|
||||
if (commonsharedmem->embedtps[i].use && (commonsharedmem->embedtps[i].tp == tp))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
bool check_embed_able(const ThreadParam &tp)
|
||||
{
|
||||
return host_connected && check_is_thread_selected(tp) && ((isPauseKeyPressed() == false) ? true : !commonsharedmem->fastskipignore);
|
||||
}
|
||||
bool waitforevent(UINT32 timems, const ThreadParam &tp, const std::wstring &origin)
|
||||
{
|
||||
char eventname[1000];
|
||||
sprintf(eventname, LUNA_EMBED_notify_event, GetCurrentProcessId(), simplehash::djb2_n2((const unsigned char *)(origin.c_str()), origin.size() * 2));
|
||||
auto event = win_event(eventname);
|
||||
while (timems)
|
||||
{
|
||||
if (check_embed_able(tp) == false)
|
||||
return false;
|
||||
auto sleepstep = min(100, timems);
|
||||
if (event.wait(sleepstep))
|
||||
return true;
|
||||
timems -= sleepstep;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void TextHook::parsenewlineseperator(TextBuffer*buff)
|
||||
{
|
||||
if (!(hp.newlineseperator))
|
||||
return;
|
||||
|
||||
if (hp.type & CODEC_UTF16)
|
||||
{
|
||||
StringCharReplacer((wchar_t *)buff->buff, buff->lpsize, hp.newlineseperator, wcslen(hp.newlineseperator), L'\n');
|
||||
}
|
||||
else if (hp.type & CODEC_UTF32)
|
||||
return;
|
||||
else
|
||||
{
|
||||
// ansi/utf8,newlineseperator都是简单字符
|
||||
std::string newlineseperatorA;
|
||||
for (int i = 0; i < wcslen(hp.newlineseperator); i++)
|
||||
newlineseperatorA += (char)hp.newlineseperator[i];
|
||||
StringCharReplacer((char *)buff->buff, buff->lpsize, newlineseperatorA.c_str(), newlineseperatorA.size(), '\n');
|
||||
}
|
||||
}
|
||||
UINT64 texthash(void *data, size_t len)
|
||||
{
|
||||
UINT64 sum = 0;
|
||||
auto u8data = (UINT8 *)data;
|
||||
for (int i = 0; i < len; i++)
|
||||
{
|
||||
sum += u8data[i];
|
||||
sum = sum << 1;
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
bool checktranslatedok(void *data, size_t len)
|
||||
{
|
||||
ZeroMemory(commonsharedmem->text, sizeof(commonsharedmem->text)); // clear trans before call
|
||||
if (len > 1000)
|
||||
return true;
|
||||
return (translatecache.find(texthash(data, len)) != translatecache.end());
|
||||
}
|
||||
bool TextHook::waitfornotify(TextBuffer*buff, ThreadParam tp)
|
||||
{
|
||||
std::wstring origin;
|
||||
if (auto t = commonparsestring(buff->buff, *buff->lpsize, &hp, commonsharedmem->codepage))
|
||||
origin = t.value();
|
||||
else
|
||||
return false;
|
||||
|
||||
std::wstring translate;
|
||||
auto hash = texthash(buff->buff, *buff->lpsize);
|
||||
if (translatecache.find(hash) != translatecache.end())
|
||||
{
|
||||
translate = translatecache.at(hash);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (waitforevent(commonsharedmem->waittime, tp, origin) == false)
|
||||
return false;
|
||||
translate = commonsharedmem->text;
|
||||
if ((translate.size() == 0))
|
||||
return false;
|
||||
translatecache.insert(std::make_pair(hash, translate));
|
||||
}
|
||||
if (hp.newlineseperator)
|
||||
strReplace(translate, L"\n", hp.newlineseperator);
|
||||
translate = adjustSpacesSTD(translate, hp);
|
||||
if (commonsharedmem->keeprawtext)
|
||||
translate = origin + L" " + translate;
|
||||
solvefont(hp);
|
||||
cast_back(hp, buff, translate, false);
|
||||
return true;
|
||||
}
|
34
cpp/LunaHook/LunaHook/embed_util.h
Normal file
34
cpp/LunaHook/LunaHook/embed_util.h
Normal file
@ -0,0 +1,34 @@
|
||||
#ifndef __LUNA_EMBED_ENGINE_H
|
||||
#define __LUNA_EMBED_ENGINE_H
|
||||
|
||||
extern CommonSharedMem *commonsharedmem;
|
||||
extern DynamicShiftJISCodec *dynamiccodec;
|
||||
|
||||
namespace WinKey
|
||||
{
|
||||
inline bool isKeyPressed(int vk) { return ::GetKeyState(vk) & 0xf0; }
|
||||
inline bool isKeyToggled(int vk) { return ::GetKeyState(vk) & 0x0f; }
|
||||
|
||||
inline bool isKeyReturnPressed() { return isKeyPressed(VK_RETURN); }
|
||||
inline bool isKeyControlPressed() { return isKeyPressed(VK_CONTROL); }
|
||||
inline bool isKeyShiftPressed() { return isKeyPressed(VK_SHIFT); }
|
||||
inline bool isKeyAltPressed() { return isKeyPressed(VK_MENU); }
|
||||
}
|
||||
namespace Engine
|
||||
{
|
||||
enum TextRole
|
||||
{
|
||||
UnknownRole = 0,
|
||||
ScenarioRole,
|
||||
NameRole,
|
||||
OtherRole,
|
||||
ChoiceRole = OtherRole,
|
||||
HistoryRole = OtherRole,
|
||||
RoleCount
|
||||
};
|
||||
}
|
||||
inline std::atomic<void (*)()> patch_fun = nullptr;
|
||||
bool ReplaceFunction(PVOID oldf, PVOID newf, PVOID *pOrigin = nullptr);
|
||||
bool check_embed_able(const ThreadParam &tp);
|
||||
bool checktranslatedok(void *data, size_t len);
|
||||
#endif
|
44
cpp/LunaHook/LunaHook/engine.h
Normal file
44
cpp/LunaHook/LunaHook/engine.h
Normal file
@ -0,0 +1,44 @@
|
||||
#ifndef __LUNA_ENGINE_H
|
||||
#define __LUNA_ENGINE_H
|
||||
|
||||
extern WCHAR *processName, processPath[MAX_PATH], processName_lower[MAX_PATH]; // cached
|
||||
extern uintptr_t processStartAddress, processStopAddress;
|
||||
extern uintptr_t processStartAddress, processStopAddress;
|
||||
|
||||
class ENGINE
|
||||
{
|
||||
public:
|
||||
const char *enginename;
|
||||
bool dontstop; // dont stop even if attached a engine
|
||||
bool is_engine_certain; // stop when match a engine ,even if not attached
|
||||
|
||||
enum class CHECK_BY
|
||||
{
|
||||
ALL_TRUE,
|
||||
FILE,
|
||||
FILE_ALL,
|
||||
FILE_ANY,
|
||||
RESOURCE_STR,
|
||||
CUSTOM,
|
||||
};
|
||||
CHECK_BY check_by;
|
||||
// const wchar_t* check_by_single;
|
||||
// std::vector<const wchar_t*>check_by_list;
|
||||
// std::function<bool()>check_by_custom_function;
|
||||
typedef std::function<bool()> check_by_custom_function;
|
||||
typedef std::vector<const wchar_t *> check_by_list;
|
||||
typedef const wchar_t *check_by_single;
|
||||
std::variant<check_by_single, check_by_list, check_by_custom_function> check_by_target;
|
||||
// virtual bool check_by_target(){return false;};
|
||||
virtual bool attach_function() = 0;
|
||||
virtual const char *getenginename()
|
||||
{
|
||||
if (enginename)
|
||||
return enginename;
|
||||
return typeid(*this).name() + 6;
|
||||
}
|
||||
ENGINE() : enginename(nullptr), dontstop(false), is_engine_certain(true), check_by(CHECK_BY::ALL_TRUE){};
|
||||
bool check_function();
|
||||
};
|
||||
|
||||
#endif
|
729
cpp/LunaHook/LunaHook/engine32/5pb.cpp
Normal file
729
cpp/LunaHook/LunaHook/engine32/5pb.cpp
Normal file
@ -0,0 +1,729 @@
|
||||
#include "5pb.h"
|
||||
#include "mages/mages.h"
|
||||
/** jichi 12/2/2014 5pb
|
||||
*
|
||||
* Sample game: [140924] CROSS<EFBFBD>CHANNEL 〜FINAL COMPLETE<EFBFBD> * See: http://sakuradite.com/topic/528
|
||||
*
|
||||
* Debugging method: insert breakpoint.
|
||||
* The first matched function cannot extract prelude text.
|
||||
* The second matched function can extract anything but contains garbage.
|
||||
*
|
||||
* Function for scenario:
|
||||
* 0016d90e cc int3
|
||||
* 0016d90f cc int3
|
||||
* 0016d910 8b15 782b6e06 mov edx,dword ptr ds:[0x66e2b78] ; .00b43bfe
|
||||
* 0016d916 8a0a mov cl,byte ptr ds:[edx] ; jichi: hook here
|
||||
* 0016d918 33c0 xor eax,eax
|
||||
* 0016d91a 84c9 test cl,cl
|
||||
* 0016d91c 74 41 je short .0016d95f
|
||||
* 0016d91e 8bff mov edi,edi
|
||||
* 0016d920 80f9 25 cmp cl,0x25
|
||||
* 0016d923 75 11 jnz short .0016d936
|
||||
* 0016d925 8a4a 01 mov cl,byte ptr ds:[edx+0x1]
|
||||
* 0016d928 42 inc edx
|
||||
* 0016d929 80f9 4e cmp cl,0x4e
|
||||
* 0016d92c 74 05 je short .0016d933
|
||||
* 0016d92e 80f9 6e cmp cl,0x6e
|
||||
* 0016d931 75 26 jnz short .0016d959
|
||||
* 0016d933 42 inc edx
|
||||
* 0016d934 eb 23 jmp short .0016d959
|
||||
* 0016d936 80f9 81 cmp cl,0x81
|
||||
* 0016d939 72 05 jb short .0016d940
|
||||
* 0016d93b 80f9 9f cmp cl,0x9f
|
||||
* 0016d93e 76 0a jbe short .0016d94a
|
||||
* 0016d940 80f9 e0 cmp cl,0xe0
|
||||
* 0016d943 72 0c jb short .0016d951
|
||||
* 0016d945 80f9 fc cmp cl,0xfc
|
||||
* 0016d948 77 07 ja short .0016d951
|
||||
* 0016d94a b9 02000000 mov ecx,0x2
|
||||
* 0016d94f eb 05 jmp short .0016d956
|
||||
* 0016d951 b9 01000000 mov ecx,0x1
|
||||
* 0016d956 40 inc eax
|
||||
* 0016d957 03d1 add edx,ecx
|
||||
* 0016d959 8a0a mov cl,byte ptr ds:[edx]
|
||||
* 0016d95b 84c9 test cl,cl
|
||||
* 0016d95d ^75 c1 jnz short .0016d920
|
||||
* 0016d95f c3 retn
|
||||
*
|
||||
* Function for everything:
|
||||
* 001e9a76 8bff mov edi,edi
|
||||
* 001e9a78 55 push ebp
|
||||
* 001e9a79 8bec mov ebp,esp
|
||||
* 001e9a7b 51 push ecx
|
||||
* 001e9a7c 8365 fc 00 and dword ptr ss:[ebp-0x4],0x0
|
||||
* 001e9a80 53 push ebx
|
||||
* 001e9a81 8b5d 10 mov ebx,dword ptr ss:[ebp+0x10]
|
||||
* 001e9a84 85db test ebx,ebx
|
||||
* 001e9a86 75 07 jnz short .001e9a8f
|
||||
* 001e9a88 33c0 xor eax,eax
|
||||
* 001e9a8a e9 9a000000 jmp .001e9b29
|
||||
* 001e9a8f 56 push esi
|
||||
* 001e9a90 83fb 04 cmp ebx,0x4
|
||||
* 001e9a93 72 75 jb short .001e9b0a
|
||||
* 001e9a95 8d73 fc lea esi,dword ptr ds:[ebx-0x4]
|
||||
* 001e9a98 85f6 test esi,esi
|
||||
* 001e9a9a 74 6e je short .001e9b0a
|
||||
* 001e9a9c 8b4d 0c mov ecx,dword ptr ss:[ebp+0xc]
|
||||
* 001e9a9f 8b45 08 mov eax,dword ptr ss:[ebp+0x8]
|
||||
* 001e9aa2 8a10 mov dl,byte ptr ds:[eax]
|
||||
* 001e9aa4 83c0 04 add eax,0x4
|
||||
* 001e9aa7 83c1 04 add ecx,0x4
|
||||
* 001e9aaa 84d2 test dl,dl
|
||||
* 001e9aac 74 52 je short .001e9b00
|
||||
* 001e9aae 3a51 fc cmp dl,byte ptr ds:[ecx-0x4]
|
||||
* 001e9ab1 75 4d jnz short .001e9b00
|
||||
* 001e9ab3 8a50 fd mov dl,byte ptr ds:[eax-0x3]
|
||||
* 001e9ab6 84d2 test dl,dl
|
||||
* 001e9ab8 74 3c je short .001e9af6
|
||||
* 001e9aba 3a51 fd cmp dl,byte ptr ds:[ecx-0x3]
|
||||
* 001e9abd 75 37 jnz short .001e9af6
|
||||
* 001e9abf 8a50 fe mov dl,byte ptr ds:[eax-0x2]
|
||||
* 001e9ac2 84d2 test dl,dl
|
||||
* 001e9ac4 74 26 je short .001e9aec
|
||||
* 001e9ac6 3a51 fe cmp dl,byte ptr ds:[ecx-0x2]
|
||||
* 001e9ac9 75 21 jnz short .001e9aec
|
||||
* 001e9acb 8a50 ff mov dl,byte ptr ds:[eax-0x1]
|
||||
* 001e9ace 84d2 test dl,dl
|
||||
* 001e9ad0 74 10 je short .001e9ae2
|
||||
* 001e9ad2 3a51 ff cmp dl,byte ptr ds:[ecx-0x1]
|
||||
* 001e9ad5 75 0b jnz short .001e9ae2
|
||||
* 001e9ad7 8345 fc 04 add dword ptr ss:[ebp-0x4],0x4
|
||||
* 001e9adb 3975 fc cmp dword ptr ss:[ebp-0x4],esi
|
||||
* 001e9ade ^72 c2 jb short .001e9aa2
|
||||
* 001e9ae0 eb 2e jmp short .001e9b10
|
||||
* 001e9ae2 0fb640 ff movzx eax,byte ptr ds:[eax-0x1]
|
||||
* 001e9ae6 0fb649 ff movzx ecx,byte ptr ds:[ecx-0x1]
|
||||
* 001e9aea eb 46 jmp short .001e9b32
|
||||
* 001e9aec 0fb640 fe movzx eax,byte ptr ds:[eax-0x2]
|
||||
* 001e9af0 0fb649 fe movzx ecx,byte ptr ds:[ecx-0x2]
|
||||
* 001e9af4 eb 3c jmp short .001e9b32
|
||||
* 001e9af6 0fb640 fd movzx eax,byte ptr ds:[eax-0x3]
|
||||
* 001e9afa 0fb649 fd movzx ecx,byte ptr ds:[ecx-0x3]
|
||||
* 001e9afe eb 32 jmp short .001e9b32
|
||||
* 001e9b00 0fb640 fc movzx eax,byte ptr ds:[eax-0x4]
|
||||
* 001e9b04 0fb649 fc movzx ecx,byte ptr ds:[ecx-0x4]
|
||||
* 001e9b08 eb 28 jmp short .001e9b32
|
||||
* 001e9b0a 8b4d 0c mov ecx,dword ptr ss:[ebp+0xc]
|
||||
* 001e9b0d 8b45 08 mov eax,dword ptr ss:[ebp+0x8]
|
||||
* 001e9b10 8b75 fc mov esi,dword ptr ss:[ebp-0x4]
|
||||
* 001e9b13 eb 0d jmp short .001e9b22
|
||||
* 001e9b15 8a10 mov dl,byte ptr ds:[eax] ; jichi: here, word by word
|
||||
* 001e9b17 84d2 test dl,dl
|
||||
* 001e9b19 74 11 je short .001e9b2c
|
||||
* 001e9b1b 3a11 cmp dl,byte ptr ds:[ecx]
|
||||
* 001e9b1d 75 0d jnz short .001e9b2c
|
||||
* 001e9b1f 40 inc eax
|
||||
* 001e9b20 46 inc esi
|
||||
* 001e9b21 41 inc ecx
|
||||
* 001e9b22 3bf3 cmp esi,ebx
|
||||
* 001e9b24 ^72 ef jb short .001e9b15
|
||||
* 001e9b26 33c0 xor eax,eax
|
||||
* 001e9b28 5e pop esi
|
||||
* 001e9b29 5b pop ebx
|
||||
* 001e9b2a c9 leave
|
||||
* 001e9b2b c3 retn
|
||||
*/
|
||||
namespace
|
||||
{ // unnamed
|
||||
|
||||
// Characters to ignore: [%0-9A-Z]
|
||||
bool Insert5pbHook1()
|
||||
{
|
||||
const BYTE bytes[] = {
|
||||
0xcc, // 0016d90e cc int3
|
||||
0xcc, // 0016d90f cc int3
|
||||
0x8b, 0x15, XX4, // 0016d910 8b15 782b6e06 mov edx,dword ptr ds:[0x66e2b78] ; .00b43bfe
|
||||
0x8a, 0x0a, // 0016d916 8a0a mov cl,byte ptr ds:[edx] ; jichi: hook here
|
||||
0x33, 0xc0, // 0016d918 33c0 xor eax,eax
|
||||
0x84, 0xc9 // 0016d91a 84c9 test cl,cl
|
||||
};
|
||||
enum
|
||||
{
|
||||
addr_offset = 0x0016d916 - 0x0016d90e
|
||||
};
|
||||
|
||||
ULONG addr = MemDbg::findBytes(bytes, sizeof(bytes), processStartAddress, processStopAddress);
|
||||
// GROWL_DWORD3(addr+addr_offset, processStartAddress,processStopAddress);
|
||||
if (!addr)
|
||||
{
|
||||
ConsoleOutput("5pb1: pattern not found");
|
||||
return false;
|
||||
}
|
||||
|
||||
HookParam hp;
|
||||
hp.address = addr + addr_offset;
|
||||
hp.offset = get_reg(regs::edx);
|
||||
hp.type = USING_STRING;
|
||||
ConsoleOutput("INSERT 5pb1");
|
||||
|
||||
// GDI functions are not used by 5pb games anyway.
|
||||
// ConsoleOutput("5pb: disable GDI hooks");
|
||||
//
|
||||
return NewHook(hp, "5pb1");
|
||||
}
|
||||
|
||||
// Characters to ignore: [%@A-z]
|
||||
inline bool _5pb2garbage_ch(char c)
|
||||
{
|
||||
return c == '%' || c == '@' || c >= 'A' && c <= 'z';
|
||||
}
|
||||
|
||||
// 001e9b15 8a10 mov dl,byte ptr ds:[eax] ; jichi: here, word by word
|
||||
void SpecialHook5pb2(hook_stack *stack, HookParam *hp, TextBuffer *buffer, uintptr_t *split)
|
||||
{
|
||||
static DWORD lasttext;
|
||||
DWORD text = stack->eax;
|
||||
if (lasttext == text)
|
||||
return;
|
||||
BYTE c = *(BYTE *)text;
|
||||
if (!c)
|
||||
return;
|
||||
BYTE size = ::LeadByteTable[c]; // 1, 2, or 3
|
||||
if (size == 1 && _5pb2garbage_ch(*(LPCSTR)text))
|
||||
return;
|
||||
lasttext = text;
|
||||
buffer->from(text, size);
|
||||
}
|
||||
|
||||
bool Insert5pbHook2()
|
||||
{
|
||||
const BYTE bytes[] = {
|
||||
0x8a, 0x10, // 001e9b15 8a10 mov dl,byte ptr ds:[eax] ; jichi: here, word by word
|
||||
0x84, 0xd2, // 001e9b17 84d2 test dl,dl
|
||||
0x74, 0x11 // 001e9b19 74 11 je short .001e9b2c
|
||||
};
|
||||
ULONG addr = MemDbg::findBytes(bytes, sizeof(bytes), processStartAddress, processStopAddress);
|
||||
// GROWL_DWORD3(addr, processStartAddress,processStopAddress);
|
||||
if (!addr)
|
||||
{
|
||||
ConsoleOutput("5pb2: pattern not found");
|
||||
return false;
|
||||
}
|
||||
|
||||
HookParam hp;
|
||||
hp.address = addr;
|
||||
hp.type = USING_STRING;
|
||||
hp.text_fun = SpecialHook5pb2;
|
||||
ConsoleOutput("INSERT 5pb2");
|
||||
|
||||
// GDI functions are not used by 5pb games anyway.
|
||||
// ConsoleOutput("5pb: disable GDI hooks");
|
||||
//
|
||||
return NewHook(hp, "5pb2");
|
||||
}
|
||||
|
||||
/** jichi 2/2/2015: New 5pb hook
|
||||
* Sample game: Hyperdimension.Neptunia.ReBirth1
|
||||
*
|
||||
* Debugging method: hardware breakpoint and find function in msvc110
|
||||
* Then, backtrack the function stack to find proper function.
|
||||
*
|
||||
* Hooked function: 558BEC56FF750C8BF1FF75088D460850
|
||||
*
|
||||
* 0025A12E CC INT3
|
||||
* 0025A12F CC INT3
|
||||
* 0025A130 55 PUSH EBP
|
||||
* 0025A131 8BEC MOV EBP,ESP
|
||||
* 0025A133 56 PUSH ESI
|
||||
* 0025A134 FF75 0C PUSH DWORD PTR SS:[EBP+0xC]
|
||||
* 0025A137 8BF1 MOV ESI,ECX
|
||||
* 0025A139 FF75 08 PUSH DWORD PTR SS:[EBP+0x8]
|
||||
* 0025A13C 8D46 08 LEA EAX,DWORD PTR DS:[ESI+0x8]
|
||||
* 0025A13F 50 PUSH EAX
|
||||
* 0025A140 E8 DB100100 CALL .0026B220
|
||||
* 0025A145 8B8E 988D0000 MOV ECX,DWORD PTR DS:[ESI+0x8D98]
|
||||
* 0025A14B 8988 80020000 MOV DWORD PTR DS:[EAX+0x280],ECX
|
||||
* 0025A151 8B8E A08D0000 MOV ECX,DWORD PTR DS:[ESI+0x8DA0]
|
||||
* 0025A157 8988 88020000 MOV DWORD PTR DS:[EAX+0x288],ECX
|
||||
* 0025A15D 8B8E A88D0000 MOV ECX,DWORD PTR DS:[ESI+0x8DA8]
|
||||
* 0025A163 8988 90020000 MOV DWORD PTR DS:[EAX+0x290],ECX
|
||||
* 0025A169 8B8E B08D0000 MOV ECX,DWORD PTR DS:[ESI+0x8DB0]
|
||||
* 0025A16F 8988 98020000 MOV DWORD PTR DS:[EAX+0x298],ECX
|
||||
* 0025A175 83C4 0C ADD ESP,0xC
|
||||
* 0025A178 8D8E 188B0000 LEA ECX,DWORD PTR DS:[ESI+0x8B18]
|
||||
* 0025A17E E8 DDD8FEFF CALL .00247A60
|
||||
* 0025A183 5E POP ESI
|
||||
* 0025A184 5D POP EBP
|
||||
* 0025A185 C2 0800 RETN 0x8
|
||||
* 0025A188 CC INT3
|
||||
* 0025A189 CC INT3
|
||||
*
|
||||
* Runtime stack, text in arg1, and name in arg2:
|
||||
*
|
||||
* 0015F93C 00252330 RETURN to .00252330 from .0025A130
|
||||
* 0015F940 181D0D4C ASCII "That's my line! I won't let any of you
|
||||
* take the title of True Goddess!"
|
||||
* 0015F944 0B8B4D20 ASCII " White Heart "
|
||||
* 0015F948 0B8B5528
|
||||
* 0015F94C 0B8B5524
|
||||
* 0015F950 /0015F980
|
||||
* 0015F954 |0026000F RETURN to .0026000F from .002521D0
|
||||
*
|
||||
*
|
||||
* Another candidate funciton for backup usage.
|
||||
* Previous text in arg1.
|
||||
* Current text in arg2.
|
||||
* Current name in arg3.
|
||||
*
|
||||
* 0026B21C CC INT3
|
||||
* 0026B21D CC INT3
|
||||
* 0026B21E CC INT3
|
||||
* 0026B21F CC INT3
|
||||
* 0026B220 55 PUSH EBP
|
||||
* 0026B221 8BEC MOV EBP,ESP
|
||||
* 0026B223 81EC A0020000 SUB ESP,0x2A0
|
||||
* 0026B229 BA A0020000 MOV EDX,0x2A0
|
||||
* 0026B22E 53 PUSH EBX
|
||||
* 0026B22F 8B5D 08 MOV EBX,DWORD PTR SS:[EBP+0x8]
|
||||
* 0026B232 56 PUSH ESI
|
||||
* 0026B233 57 PUSH EDI
|
||||
* 0026B234 8D041A LEA EAX,DWORD PTR DS:[EDX+EBX]
|
||||
* 0026B237 B9 A8000000 MOV ECX,0xA8
|
||||
* 0026B23C 8BF3 MOV ESI,EBX
|
||||
* 0026B23E 8DBD 60FDFFFF LEA EDI,DWORD PTR SS:[EBP-0x2A0]
|
||||
* 0026B244 F3:A5 REP MOVS DWORD PTR ES:[EDI],DWORD PTR DS>
|
||||
* 0026B246 B9 A8000000 MOV ECX,0xA8
|
||||
* 0026B24B 8BF0 MOV ESI,EAX
|
||||
* 0026B24D 8BFB MOV EDI,EBX
|
||||
* 0026B24F F3:A5 REP MOVS DWORD PTR ES:[EDI],DWORD PTR DS>
|
||||
* 0026B251 81C2 A0020000 ADD EDX,0x2A0
|
||||
* 0026B257 B9 A8000000 MOV ECX,0xA8
|
||||
* 0026B25C 8DB5 60FDFFFF LEA ESI,DWORD PTR SS:[EBP-0x2A0]
|
||||
* 0026B262 8BF8 MOV EDI,EAX
|
||||
* 0026B264 F3:A5 REP MOVS DWORD PTR ES:[EDI],DWORD PTR DS>
|
||||
* 0026B266 81FA 40830000 CMP EDX,0x8340
|
||||
* 0026B26C ^7C C6 JL SHORT .0026B234
|
||||
* 0026B26E 8BCB MOV ECX,EBX
|
||||
* 0026B270 E8 EBC7FDFF CALL .00247A60
|
||||
* 0026B275 FF75 0C PUSH DWORD PTR SS:[EBP+0xC]
|
||||
* 0026B278 8B35 D8525000 MOV ESI,DWORD PTR DS:[0x5052D8] ; msvcr110.sprintf
|
||||
* 0026B27E 68 805C5000 PUSH .00505C80 ; ASCII "%s"
|
||||
* 0026B283 53 PUSH EBX
|
||||
* 0026B284 FFD6 CALL ESI
|
||||
* 0026B286 FF75 10 PUSH DWORD PTR SS:[EBP+0x10]
|
||||
* 0026B289 8D83 00020000 LEA EAX,DWORD PTR DS:[EBX+0x200]
|
||||
* 0026B28F 68 805C5000 PUSH .00505C80 ; ASCII "%s"
|
||||
* 0026B294 50 PUSH EAX
|
||||
* 0026B295 FFD6 CALL ESI
|
||||
* 0026B297 83C4 18 ADD ESP,0x18
|
||||
* 0026B29A 8BC3 MOV EAX,EBX
|
||||
* 0026B29C 5F POP EDI
|
||||
* 0026B29D 5E POP ESI
|
||||
* 0026B29E 5B POP EBX
|
||||
* 0026B29F 8BE5 MOV ESP,EBP
|
||||
* 0026B2A1 5D POP EBP
|
||||
* 0026B2A2 C3 RETN
|
||||
* 0026B2A3 CC INT3
|
||||
* 0026B2A4 CC INT3
|
||||
* 0026B2A5 CC INT3
|
||||
* 0026B2A6 CC INT3
|
||||
*/
|
||||
void SpecialHook5pb3(hook_stack *stack, HookParam *hp, TextBuffer *buffer, uintptr_t *split)
|
||||
{
|
||||
int index = 0;
|
||||
// Text in arg1, name in arg2
|
||||
if (LPCSTR text = (LPCSTR)stack->stack[index + 1])
|
||||
if (*text)
|
||||
{
|
||||
if (index) // trim spaces in character name
|
||||
while (*text == ' ')
|
||||
text++;
|
||||
size_t sz = ::strlen(text);
|
||||
if (index)
|
||||
while (sz && text[sz - 1] == ' ')
|
||||
sz--;
|
||||
*split = FIXED_SPLIT_VALUE << index;
|
||||
buffer->from(text, sz);
|
||||
}
|
||||
}
|
||||
bool Insert5pbHook3()
|
||||
{
|
||||
const BYTE bytes[] = {
|
||||
// function starts
|
||||
0x55, // 0025A130 55 PUSH EBP
|
||||
0x8b, 0xec, // 0025A131 8BEC MOV EBP,ESP
|
||||
0x56, // 0025A133 56 PUSH ESI
|
||||
0xff, 0x75, 0x0c, // 0025A134 FF75 0C PUSH DWORD PTR SS:[EBP+0xC]
|
||||
0x8b, 0xf1, // 0025A137 8BF1 MOV ESI,ECX
|
||||
0xff, 0x75, 0x08, // 0025A139 FF75 08 PUSH DWORD PTR SS:[EBP+0x8]
|
||||
0x8d, 0x46, 0x08, // 0025A13C 8D46 08 LEA EAX,DWORD PTR DS:[ESI+0x8]
|
||||
0x50, // 0025A13F 50 PUSH EAX
|
||||
0xe8 // 0025A140 E8 DB100100 CALL .0026B220
|
||||
};
|
||||
ULONG addr = MemDbg::findBytes(bytes, sizeof(bytes), processStartAddress, processStopAddress);
|
||||
// GROWL_DWORD3(addr, processStartAddress,processStopAddress);
|
||||
if (!addr)
|
||||
{
|
||||
ConsoleOutput("5pb2: pattern not found");
|
||||
return false;
|
||||
}
|
||||
|
||||
HookParam hp;
|
||||
hp.address = addr;
|
||||
hp.type = USING_STRING | NO_CONTEXT;
|
||||
hp.text_fun = SpecialHook5pb3;
|
||||
hp.filter_fun = NewLineCharToSpaceFilterA; // replace '\n' by ' '
|
||||
ConsoleOutput("INSERT 5pb3");
|
||||
|
||||
// GDI functions are not used by 5pb games anyway.
|
||||
// ConsoleOutput("5pb: disable GDI hooks");
|
||||
//
|
||||
return NewHook(hp, "5pb3");
|
||||
}
|
||||
} // unnamed namespace
|
||||
|
||||
bool Insert5pbHook()
|
||||
{
|
||||
bool ok = Insert5pbHook1();
|
||||
ok = Insert5pbHook2() || ok;
|
||||
ok = Insert5pbHook3() || ok;
|
||||
return ok;
|
||||
}
|
||||
bool Insert5pbHookex()
|
||||
{
|
||||
// 祝姬
|
||||
const BYTE bytes[] = {
|
||||
0x0F, 0xB6, 0xC2, 0x35, 0xC5, 0x9D, 0x1C, 0x81};
|
||||
auto addr = MemDbg::findBytes(bytes, sizeof(bytes), processStartAddress, processStopAddress);
|
||||
if (addr == 0)
|
||||
return false;
|
||||
const BYTE start[] = {
|
||||
0x55, 0x8b, 0xec, 0x83, 0xe4};
|
||||
addr = reverseFindBytes(start, sizeof(start), addr - 0x40, addr);
|
||||
if (addr == 0)
|
||||
return false;
|
||||
HookParam hp;
|
||||
hp.address = addr;
|
||||
hp.offset = get_reg(regs::ecx);
|
||||
hp.type = CODEC_UTF16;
|
||||
|
||||
return NewHook(hp, "5pb");
|
||||
}
|
||||
|
||||
bool InsertStuffScriptHook()
|
||||
{
|
||||
// BOOL GetTextExtentPoint32(
|
||||
// _In_ HDC hdc,
|
||||
// _In_ LPCTSTR lpString,
|
||||
// _In_ int c,
|
||||
// _Out_ LPSIZE lpSize
|
||||
// );
|
||||
HookParam hp;
|
||||
hp.address = (DWORD)::GetTextExtentPoint32A;
|
||||
hp.offset = get_stack(2); // arg2 lpString
|
||||
hp.split = get_reg(regs::esp);
|
||||
hp.type = USING_STRING | USING_SPLIT;
|
||||
ConsoleOutput("INSERT StuffScriptEngine");
|
||||
return NewHook(hp, "StuffScriptEngine");
|
||||
// RegisterEngine(ENGINE_STUFFSCRIPT);
|
||||
}
|
||||
bool StuffScript2Filter(LPVOID data, size_t *size, HookParam *)
|
||||
{
|
||||
auto text = reinterpret_cast<LPSTR>(data);
|
||||
auto len = reinterpret_cast<size_t *>(size);
|
||||
|
||||
if (text[0] == '-')
|
||||
{
|
||||
StringFilter(text, len, "-/-", 3);
|
||||
StringFilterBetween(text, len, "-", 1, "-", 1);
|
||||
}
|
||||
StringCharReplacer(text, len, "_n_r", 4, '\n');
|
||||
StringCharReplacer(text, len, "_r", 2, ' ');
|
||||
StringFilter(text, len, "\\n", 2);
|
||||
StringFilter(text, len, "_n", 2);
|
||||
|
||||
return true;
|
||||
}
|
||||
bool InsertStuffScript2Hook()
|
||||
{
|
||||
|
||||
/*
|
||||
* Sample games:
|
||||
* https://vndb.org/r41537
|
||||
* https://vndb.org/r41539
|
||||
*/
|
||||
const BYTE bytes[] = {
|
||||
0x0F, XX, XX4, // jne tokyobabel.exe+3D4E8
|
||||
0xB9, XX4, // mov ecx,tokyobabel.exe+54EAC
|
||||
0x8D, 0x85, XX4, // lea eax,[ebp+tokyobabel.exe+59B968]
|
||||
0x8A, 0x10, // mov dl,[eax] <-- hook here
|
||||
0x3A, 0x11, // cmp dl,[ecx]
|
||||
0x75, 0x1A, // jne tokyobabel.exe+3D1D7
|
||||
0x84, 0xD2, // test dl,dl
|
||||
0x74, 0x12, // je tokyobabel.exe+3D1D3
|
||||
0x8A, 0x50, 0x01, // mov dl,[eax+01]
|
||||
0x3A, 0x51, 0x01, // cmp dl,[ecx+01]
|
||||
0x75, 0x0E, // jne tokyobabel.exe+3D1D7
|
||||
0x83, 0xC0, 0x02, // add eax,02
|
||||
0x83, 0xC1, 0x02, // add ecx,02
|
||||
0x84, 0xD2, // test dl,dl
|
||||
0x75, 0xE4, // jne Agreement.exe+4F538
|
||||
0x33, 0xC0, // xor eax,eax
|
||||
0xEB, 0x05, // jmp Agreement.exe+4F55D
|
||||
0x1B, 0xC0, // sbb eax,eax
|
||||
0x83, 0xD8, 0xFF, // sbb eax,-01
|
||||
XX2, // cmp eax,edi
|
||||
0x0F, 0x84, XX4 // je tokyobabel.exe+3D4E8
|
||||
};
|
||||
ULONG range = min(processStopAddress - processStartAddress, MAX_REL_ADDR);
|
||||
ULONG addr = MemDbg::findBytes(bytes, sizeof(bytes), processStartAddress, processStartAddress + range);
|
||||
if (!addr)
|
||||
return false;
|
||||
|
||||
HookParam hp;
|
||||
hp.address = addr + 0x11;
|
||||
hp.offset = get_reg(regs::eax);
|
||||
hp.index = 0;
|
||||
hp.type = USING_STRING | NO_CONTEXT;
|
||||
hp.filter_fun = StuffScript2Filter;
|
||||
ConsoleOutput("INSERT StuffScript2");
|
||||
return NewHook(hp, "StuffScript2");
|
||||
}
|
||||
bool StuffScript3Filter(LPVOID data, size_t *size, HookParam *)
|
||||
{
|
||||
auto text = reinterpret_cast<LPSTR>(data);
|
||||
auto len = reinterpret_cast<size_t *>(size);
|
||||
|
||||
if (text[0] == '\x81' && text[1] == '\x40')
|
||||
{ // removes space at the beginning of the sentence
|
||||
*len -= 2;
|
||||
::memmove(text, text + 2, *len);
|
||||
}
|
||||
|
||||
StringFilterBetween(text, len, "/\x81\x79", 3, "\x81\x7A", 2); // remove hidden name
|
||||
StringFilterBetween(text, len, "[", 1, "]", 1); // garbage
|
||||
|
||||
// ruby
|
||||
CharFilter(text, len, '<');
|
||||
StringFilterBetween(text, len, ",", 1, ">", 1);
|
||||
|
||||
StringCharReplacer(text, len, "_r\x81\x40", 4, ' ');
|
||||
StringCharReplacer(text, len, "_r", 2, ' ');
|
||||
|
||||
return true;
|
||||
}
|
||||
bool InsertStuffScript3Hook()
|
||||
{
|
||||
/*
|
||||
* Sample games:
|
||||
* https://vndb.org/v3111
|
||||
*/
|
||||
const BYTE bytes[] = {
|
||||
0xCC, // int 3
|
||||
0x81, 0xEC, XX4, // sub esp,00000140 <-- hook here
|
||||
0xA1, XX4, // mov eax,[EVOLIMIT.exe+8C1F0]
|
||||
0x33, 0xC4, // xor eax,esp
|
||||
0x89, 0x84, 0x24, XX4, // mov [esp+0000013C],eax
|
||||
0x53, // push ebx
|
||||
0x55, // push ebp
|
||||
0x8B, 0xAC, 0x24, XX4, // mov ebp,[esp+0000014C]
|
||||
0x8B, 0x45, 0x2C // mov eax,[ebp+2C]
|
||||
};
|
||||
ULONG range = min(processStopAddress - processStartAddress, MAX_REL_ADDR);
|
||||
ULONG addr = MemDbg::findBytes(bytes, sizeof(bytes), processStartAddress, processStartAddress + range);
|
||||
if (!addr)
|
||||
return false;
|
||||
|
||||
HookParam hp = {};
|
||||
hp.address = addr + 1;
|
||||
hp.offset = get_reg(regs::ecx);
|
||||
hp.type = USING_STRING | NO_CONTEXT;
|
||||
hp.filter_fun = StuffScript3Filter;
|
||||
NewHook(hp, "StuffScript3");
|
||||
return true;
|
||||
}
|
||||
bool StuffScript_attach_function()
|
||||
{
|
||||
auto _ = InsertStuffScriptHook();
|
||||
_ |= InsertStuffScript2Hook();
|
||||
_ |= InsertStuffScript3Hook();
|
||||
return _;
|
||||
}
|
||||
bool _5pb::attach_function()
|
||||
{
|
||||
bool b1 = Insert5pbHook();
|
||||
bool b2 = Insert5pbHookex();
|
||||
bool b3 = hookmages::MAGES();
|
||||
bool sf = StuffScript_attach_function();
|
||||
return b1 || b2 || b3 || sf;
|
||||
}
|
||||
|
||||
bool KaleidoFilter(LPVOID data, size_t *size, HookParam *)
|
||||
{
|
||||
auto text = reinterpret_cast<LPSTR>(data);
|
||||
auto len = reinterpret_cast<size_t *>(size);
|
||||
|
||||
// Unofficial eng TL with garbage newline spaces
|
||||
StringCharReplacer(text, len, " \\n ", 4, ' ');
|
||||
StringCharReplacer(text, len, " \\n", 3, ' ');
|
||||
StringCharReplacer(text, len, "\\n", 2, ' ');
|
||||
StringCharReplacer(text, len, "\xEF\xBC\x9F", 3, '?');
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool InsertKaleidoHook()
|
||||
{
|
||||
|
||||
/*
|
||||
* Sample games:
|
||||
* https://vndb.org/v29889
|
||||
*/
|
||||
const BYTE bytes[] = {
|
||||
0xFF, 0x75, 0xD4, // push [ebp-2C]
|
||||
0xE8, XX4, // call 5toubun.exe+1DD0
|
||||
0x83, 0xC4, 0x0C, // add esp,0C
|
||||
0x8A, 0xC3, // mov al,bl
|
||||
0x8B, 0x4D, 0xF4, // mov ecx,[ebp-0C]
|
||||
0x64, 0x89, 0x0D, XX4, // mov fs:[00000000],ecx
|
||||
0x59 // pop ecx << hook here
|
||||
};
|
||||
enum
|
||||
{
|
||||
addr_offset = sizeof(bytes) - 1
|
||||
};
|
||||
|
||||
ULONG range = min(processStopAddress - processStartAddress, MAX_REL_ADDR);
|
||||
ULONG addr = MemDbg::findBytes(bytes, sizeof(bytes), processStartAddress, processStartAddress + range);
|
||||
if (!addr)
|
||||
return false;
|
||||
|
||||
HookParam hp;
|
||||
hp.address = addr + addr_offset;
|
||||
hp.offset = get_reg(regs::esi);
|
||||
hp.index = 0;
|
||||
hp.split = get_stack(3);
|
||||
hp.split_index = 0;
|
||||
hp.type = USING_STRING | USING_SPLIT;
|
||||
hp.filter_fun = KaleidoFilter;
|
||||
ConsoleOutput(" INSERT Kaleido");
|
||||
|
||||
return NewHook(hp, "Kaleido");
|
||||
}
|
||||
namespace
|
||||
{ // ANONYMOUS;CODE 官中
|
||||
bool __1()
|
||||
{
|
||||
BYTE bytes[] = {
|
||||
0x8d, 0x45, 0xf4, 0x64, 0xA3, 0x00, 0x00, 0x00, 0x00, 0x8b, 0xf1, 0x8a, 0x46, 0x2c, 0x8b, 0x55, 0x08, 0x84, 0xc0, 0x74, 0x04, 0x32, 0xc0};
|
||||
ULONG addr = MemDbg::findBytes(bytes, sizeof(bytes), processStartAddress, processStopAddress);
|
||||
if (!addr)
|
||||
return false;
|
||||
addr = MemDbg::findEnclosingAlignedFunction(addr);
|
||||
if (addr == 0)
|
||||
return false;
|
||||
HookParam hp;
|
||||
hp.address = addr;
|
||||
hp.offset = get_stack(1);
|
||||
hp.type = USING_STRING | CODEC_UTF8 | EMBED_ABLE | EMBED_AFTER_NEW;
|
||||
hp.newlineseperator = L"\\n";
|
||||
return NewHook(hp, "5bp");
|
||||
}
|
||||
bool __()
|
||||
{
|
||||
BYTE sig1[] = {
|
||||
0x81, 0xFE, 0xF0, 0x00, 0x00, 0x00};
|
||||
BYTE sig2[] = {
|
||||
0x81, 0xFE, 0xF8, 0x00, 0x00, 0x00};
|
||||
BYTE sig3[] = {
|
||||
0x81, 0xFE, 0xFC, 0x00, 0x00, 0x00};
|
||||
BYTE sig4[] = {
|
||||
0x81, 0xFE, 0xFE, 0x00, 0x00, 0x00};
|
||||
BYTE sig5[] = {
|
||||
0x81, 0xFE, 0x80, 0x00, 0x00, 0x00};
|
||||
BYTE sig6[] = {
|
||||
0x81, 0xFE, 0xE0, 0x00, 0x00, 0x00};
|
||||
std::unordered_map<uintptr_t, int> addr_hit;
|
||||
for (auto sigsz : std::vector<std::pair<BYTE *, int>>{{sig1, sizeof(sig1)}, {sig2, sizeof(sig2)}, {sig3, sizeof(sig3)}, {sig4, sizeof(sig4)}, {sig5, sizeof(sig5)}, {sig6, sizeof(sig6)}})
|
||||
{
|
||||
for (auto addr : Util::SearchMemory(sigsz.first, sigsz.second, PAGE_EXECUTE, processStartAddress, processStopAddress))
|
||||
{
|
||||
addr = MemDbg::findEnclosingAlignedFunction(addr);
|
||||
if (addr == 0)
|
||||
continue;
|
||||
if (addr_hit.find(addr) == addr_hit.end())
|
||||
{
|
||||
addr_hit[addr] = 1;
|
||||
}
|
||||
else
|
||||
addr_hit[addr] += 1;
|
||||
}
|
||||
}
|
||||
DWORD addr = 0;
|
||||
int m = 0;
|
||||
for (auto _ : addr_hit)
|
||||
{
|
||||
if (_.second > m)
|
||||
{
|
||||
m = _.second;
|
||||
addr = _.first;
|
||||
}
|
||||
}
|
||||
if (!addr)
|
||||
return false;
|
||||
|
||||
HookParam hp;
|
||||
hp.address = addr;
|
||||
hp.offset = get_stack(1);
|
||||
hp.type = USING_STRING | CODEC_UTF8;
|
||||
hp.filter_fun = [](LPVOID data, size_t *size, HookParam *)
|
||||
{
|
||||
auto text = reinterpret_cast<LPSTR>(data);
|
||||
auto len = reinterpret_cast<size_t *>(size);
|
||||
StringCharReplacer(text, len, "\\n", 2, '\n');
|
||||
return true;
|
||||
};
|
||||
return NewHook(hp, "5bp");
|
||||
}
|
||||
} // namespace name
|
||||
namespace
|
||||
{
|
||||
bool __2()
|
||||
{
|
||||
// レヱル・ロマネスク origin 多国語版
|
||||
// https://vndb.org/r119877
|
||||
// char __thiscall sub_426B70(float *this, int a2, int a3, int a4, int a5, char a6, char a7)
|
||||
BYTE bytes[] = {
|
||||
0x0f, 0xb7, 0x04, 0x72,
|
||||
0x46,
|
||||
0x89, 0x85, XX4,
|
||||
0x0f, 0xb7, 0xc0,
|
||||
0x83, 0xc0, 0xf6,
|
||||
0x83, 0xf8, 0x52,
|
||||
0x0f, 0x87};
|
||||
auto addr = MemDbg::findBytes(bytes, sizeof(bytes), processStartAddress, processStopAddress);
|
||||
if (!addr)
|
||||
return false;
|
||||
addr = MemDbg::findEnclosingAlignedFunction_strict(addr);
|
||||
if (!addr)
|
||||
return false;
|
||||
HookParam hp;
|
||||
hp.address = addr;
|
||||
hp.offset = get_stack(1);
|
||||
hp.split = get_stack(2);
|
||||
hp.type = USING_SPLIT | USING_STRING | FULL_STRING | CODEC_UTF16 | EMBED_ABLE | EMBED_AFTER_NEW; // 中文显示不出来
|
||||
hp.filter_fun = [](LPVOID data, size_t *size, HookParam *)
|
||||
{
|
||||
// そうして、[おひとよ,2]御一夜――\n眼下に広がるこの町も、僕を間違いなく救ってくれた。
|
||||
// 「行政に関しての最大の変化は、市長です。\n現在の市長には[ひない,1]雛衣・ポーレットが就任しています」
|
||||
// 「なるほど。それゆえ、御一夜は衰退し、\n\x%lエアクラ;#00ffc040;エアクラ%l;#;工場の誘致話が持ち上がったわけか?」
|
||||
// 「ナビ。お前も\x%lエアクラ;#00ffc040;エアクラ%l;#;の仲間だったな。\n気を悪くしたか?」
|
||||
auto text = reinterpret_cast<LPWSTR>(data);
|
||||
auto len = reinterpret_cast<size_t *>(size);
|
||||
auto xx = std::wstring(text, *len / 2);
|
||||
xx = std::regex_replace(xx, std::wregex(L"\\[(.*?),\\d\\]"), L"$1");
|
||||
xx = std::regex_replace(xx, std::wregex(L"\\\\x%l(.*?);(.*?);(.*?);#;"), L"$1");
|
||||
return write_string_overwrite(data, size, xx);
|
||||
};
|
||||
hp.newlineseperator = L"\\n";
|
||||
return NewHook(hp, "5bp");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool _5pb_2::attach_function()
|
||||
{
|
||||
bool ___1 = __1() || __();
|
||||
___1 |= __2();
|
||||
return InsertKaleidoHook() || ___1;
|
||||
}
|
26
cpp/LunaHook/LunaHook/engine32/5pb.h
Normal file
26
cpp/LunaHook/LunaHook/engine32/5pb.h
Normal file
@ -0,0 +1,26 @@
|
||||
|
||||
|
||||
class _5pb : public ENGINE
|
||||
{
|
||||
public:
|
||||
_5pb()
|
||||
{
|
||||
is_engine_certain = false;
|
||||
check_by = CHECK_BY::FILE_ANY;
|
||||
check_by_target = check_by_list{L"data\\*.cpk", L"*.cpk", L"*.mpk", L"USRDIR\\*.mpk"};
|
||||
};
|
||||
bool attach_function();
|
||||
};
|
||||
|
||||
class _5pb_2 : public ENGINE
|
||||
{
|
||||
public:
|
||||
_5pb_2()
|
||||
{
|
||||
|
||||
check_by = CHECK_BY::FILE;
|
||||
check_by_target = L"windata/script_body.bin";
|
||||
is_engine_certain = false;
|
||||
};
|
||||
bool attach_function();
|
||||
};
|
29
cpp/LunaHook/LunaHook/engine32/A98SYS.cpp
Normal file
29
cpp/LunaHook/LunaHook/engine32/A98SYS.cpp
Normal file
@ -0,0 +1,29 @@
|
||||
#include "A98SYS.h"
|
||||
|
||||
bool A98SYS::attach_function()
|
||||
{
|
||||
// https://vndb.org/v6447
|
||||
// Rainy Blue ~6月の雨~
|
||||
|
||||
auto addrs = findiatcallormov_all((DWORD)::ExtTextOutA, processStartAddress, processStartAddress, processStopAddress, PAGE_EXECUTE);
|
||||
if (addrs.size() != 2)
|
||||
return false;
|
||||
auto addr = addrs[1];
|
||||
addr = MemDbg::findEnclosingAlignedFunction(addr);
|
||||
if (!addr)
|
||||
return false;
|
||||
auto addrs1 = findxref_reverse_checkcallop(addr, processStartAddress, processStopAddress, 0xe8);
|
||||
if (!addrs1.size())
|
||||
return false;
|
||||
addr = addrs1[0];
|
||||
addr = MemDbg::findEnclosingAlignedFunction(addr);
|
||||
if (!addr)
|
||||
return false;
|
||||
HookParam hp;
|
||||
hp.address = addr;
|
||||
hp.offset = get_stack(1);
|
||||
hp.type = USING_STRING | EMBED_ABLE | EMBED_AFTER_NEW | EMBED_DYNA_SJIS;
|
||||
hp.hook_font = F_ExtTextOutA;
|
||||
|
||||
return NewHook(hp, "A98SYS");
|
||||
}
|
13
cpp/LunaHook/LunaHook/engine32/A98SYS.h
Normal file
13
cpp/LunaHook/LunaHook/engine32/A98SYS.h
Normal file
@ -0,0 +1,13 @@
|
||||
|
||||
|
||||
class A98SYS : public ENGINE
|
||||
{
|
||||
public:
|
||||
A98SYS()
|
||||
{
|
||||
|
||||
check_by = CHECK_BY::FILE;
|
||||
check_by_target = L"A98SYS.PAK"; // STREAM.PAK
|
||||
};
|
||||
bool attach_function();
|
||||
};
|
74
cpp/LunaHook/LunaHook/engine32/AB2Try.cpp
Normal file
74
cpp/LunaHook/LunaHook/engine32/AB2Try.cpp
Normal file
@ -0,0 +1,74 @@
|
||||
#include "AB2Try.h"
|
||||
|
||||
/********************************************************************************************
|
||||
AkabeiSoft2Try hook:
|
||||
Game folder contains YaneSDK.dll. Maybe we should call the engine Yane(屋<EFBFBD> = roof)?
|
||||
This engine is based on .NET framework. This really makes it troublesome to locate a
|
||||
valid hook address. The problem is that the engine file merely contains bytecode for
|
||||
the CLR. Real meaningful object code is generated dynamically and the address is randomized.
|
||||
Therefore the easiest method is to brute force search whole address space. While it's not necessary
|
||||
to completely search the whole address space, since non-executable pages can be excluded first.
|
||||
The generated code sections do not belong to any module(exe/dll), hence they do not have
|
||||
a section name. So we can also exclude executable pages from all modules. At last, the code
|
||||
section should be long(>0x2000). The remain address space should be several MBs in size and
|
||||
can be examined in reasonable time(less than 0.1s for P8400 Win7x64).
|
||||
Characteristic sequence is 0F B7 44 50 0C, stands for movzx eax, word ptr [edx*2 + eax + C].
|
||||
Obviously this instruction extracts one unicode character from a string.
|
||||
A main shortcoming is that the code is not generated if it hasn't been used yet.
|
||||
So if you are in title screen this approach will fail.
|
||||
|
||||
********************************************************************************************/
|
||||
namespace
|
||||
{ // unnamed
|
||||
|
||||
typedef struct _NSTRING
|
||||
{
|
||||
PVOID vfTable;
|
||||
DWORD lenWithNull;
|
||||
DWORD lenWithoutNull;
|
||||
WCHAR str[1];
|
||||
} NSTRING;
|
||||
|
||||
// qsort correctly identifies overflow.
|
||||
int cmp(const void *a, const void *b)
|
||||
{
|
||||
return *(int *)a - *(int *)b;
|
||||
}
|
||||
|
||||
void SpecialHookAB2Try(hook_stack *stack, HookParam *hp, TextBuffer *buffer, uintptr_t *split)
|
||||
{
|
||||
// DWORD test = *(DWORD*)(esp_base - 0x10);
|
||||
DWORD edx = stack->edx;
|
||||
if (edx != 0)
|
||||
return;
|
||||
|
||||
// NSTRING *s = *(NSTRING **)(esp_base - 8);
|
||||
if (const NSTRING *s = (NSTRING *)stack->eax)
|
||||
{
|
||||
buffer->from(s->str, s->lenWithoutNull << 1);
|
||||
//*split = 0;
|
||||
*split = FIXED_SPLIT_VALUE; // 8/3/2014 jichi: change to single threads
|
||||
}
|
||||
}
|
||||
|
||||
bool FindCharacteristInstruction()
|
||||
{
|
||||
const BYTE bytes[] = {0x0F, 0xB7, 0x44, 0x50, 0x0C, 0x89};
|
||||
for (auto addr : Util::SearchMemory(bytes, sizeof(bytes), PAGE_EXECUTE_READWRITE))
|
||||
{
|
||||
// GROWL_DWORD(addr);
|
||||
HookParam hp;
|
||||
hp.address = addr;
|
||||
hp.text_fun = SpecialHookAB2Try;
|
||||
hp.type = USING_STRING | NO_CONTEXT | CODEC_UTF16;
|
||||
// ConsoleOutput("Please adjust text speed to fastest/immediate.");
|
||||
// RegisterEngineType(ENGINE_AB2T);
|
||||
return NewHook(hp, "AB2Try");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
} // unnamed namespace
|
||||
bool AB2Try::attach_function()
|
||||
{
|
||||
return FindCharacteristInstruction();
|
||||
}
|
13
cpp/LunaHook/LunaHook/engine32/AB2Try.h
Normal file
13
cpp/LunaHook/LunaHook/engine32/AB2Try.h
Normal file
@ -0,0 +1,13 @@
|
||||
|
||||
|
||||
class AB2Try : public ENGINE
|
||||
{
|
||||
public:
|
||||
AB2Try()
|
||||
{
|
||||
|
||||
check_by = CHECK_BY::FILE;
|
||||
check_by_target = L"Yanesdk.dll";
|
||||
};
|
||||
bool attach_function();
|
||||
};
|
28
cpp/LunaHook/LunaHook/engine32/ACTGS.cpp
Normal file
28
cpp/LunaHook/LunaHook/engine32/ACTGS.cpp
Normal file
@ -0,0 +1,28 @@
|
||||
#include "ACTGS.h"
|
||||
|
||||
bool ACTGS::attach_function()
|
||||
{
|
||||
const BYTE bytes[] = {
|
||||
0x0F, 0xBE, 0xD0,
|
||||
0x83, 0xFA, 0x20,
|
||||
0x74, XX,
|
||||
0x83, 0xfa, 0x09,
|
||||
0x75, XX
|
||||
|
||||
};
|
||||
ULONG range = min(processStopAddress - processStartAddress, MAX_REL_ADDR);
|
||||
ULONG addr = MemDbg::findBytes(bytes, sizeof(bytes), processStartAddress, processStartAddress + range);
|
||||
if (!addr)
|
||||
return false;
|
||||
|
||||
addr = findfuncstart(addr);
|
||||
if (!addr)
|
||||
return false;
|
||||
HookParam hp;
|
||||
hp.address = addr;
|
||||
hp.offset = get_stack(2);
|
||||
hp.type = USING_STRING;
|
||||
hp.filter_fun = all_ascii_Filter;
|
||||
|
||||
return NewHook(hp, "ACTGS");
|
||||
}
|
13
cpp/LunaHook/LunaHook/engine32/ACTGS.h
Normal file
13
cpp/LunaHook/LunaHook/engine32/ACTGS.h
Normal file
@ -0,0 +1,13 @@
|
||||
|
||||
|
||||
class ACTGS : public ENGINE
|
||||
{
|
||||
public:
|
||||
ACTGS()
|
||||
{
|
||||
|
||||
check_by = CHECK_BY::RESOURCE_STR;
|
||||
check_by_target = L"ACTRESS Game System";
|
||||
};
|
||||
bool attach_function();
|
||||
};
|
57
cpp/LunaHook/LunaHook/engine32/AGE_System.cpp
Normal file
57
cpp/LunaHook/LunaHook/engine32/AGE_System.cpp
Normal file
@ -0,0 +1,57 @@
|
||||
#include "AGE_System.h"
|
||||
namespace
|
||||
{
|
||||
|
||||
DWORD findx()
|
||||
{
|
||||
// 已破解
|
||||
auto addr = findiatcallormov((DWORD)GetGlyphOutlineA, processStartAddress, processStartAddress, processStopAddress, true, 0x1d); // mov ebx, ds:GetGlyphOutlineA
|
||||
if (addr)
|
||||
return addr;
|
||||
// 未破解
|
||||
// v8 = _mbsnextc(String);
|
||||
BYTE sig[] = {
|
||||
0x8b, 0x4c, 0x24, 0x04,
|
||||
0x33, 0xd2,
|
||||
0x0f, 0xb6, 0x01,
|
||||
0xf6, 0x80, XX4, 0x04,
|
||||
0x74, 0x06,
|
||||
0xc1, 0xe0, 0x08,
|
||||
0x8b, 0xd0,
|
||||
0x41,
|
||||
0x0f, 0xb6, 0x01,
|
||||
0x03, 0xc2,
|
||||
0xc3};
|
||||
addr = MemDbg::findBytes(sig, sizeof(sig), processStartAddress, processStopAddress);
|
||||
if (!addr)
|
||||
return 0;
|
||||
auto addr2 = findxref_reverse_checkcallop(addr, processStartAddress, processStopAddress, 0xe8);
|
||||
if (addr2.size() != 2)
|
||||
return 0;
|
||||
return addr2[1];
|
||||
}
|
||||
}
|
||||
bool AGE_System::attach_function()
|
||||
{
|
||||
//(18禁ゲーム) [170331] [ルネ] ようこそ! スケベエルフの森へ パッケージ版
|
||||
auto addr = findx();
|
||||
if (!addr)
|
||||
return false;
|
||||
addr = MemDbg::findEnclosingAlignedFunction(addr);
|
||||
if (!addr)
|
||||
return false;
|
||||
auto addr2 = findxref_reverse_checkcallop(addr, addr - 0x1000, addr + 0x1000, 0xe8);
|
||||
if (addr2.size() != 1)
|
||||
return false;
|
||||
|
||||
auto addr21 = MemDbg::findEnclosingAlignedFunction(addr2[0]);
|
||||
if (!addr21)
|
||||
return false;
|
||||
|
||||
HookParam hp;
|
||||
hp.address = addr21;
|
||||
hp.offset = get_stack(3);
|
||||
hp.type = USING_STRING | EMBED_ABLE | EMBED_DYNA_SJIS | EMBED_AFTER_NEW;
|
||||
hp.hook_font = F_GetGlyphOutlineA;
|
||||
return NewHook(hp, "AGE_System");
|
||||
}
|
53
cpp/LunaHook/LunaHook/engine32/AGE_System.h
Normal file
53
cpp/LunaHook/LunaHook/engine32/AGE_System.h
Normal file
@ -0,0 +1,53 @@
|
||||
|
||||
/*
|
||||
FILEVERSION 1,0,0,1
|
||||
PRODUCTVERSION 1,0,0,1
|
||||
FILEFLAGSMASK 0x3F
|
||||
FILEFLAGS 0x0
|
||||
FILEOS VOS_NT_WINDOWS32
|
||||
FILETYPE VFT_APP
|
||||
FILESUBTYPE 0x0
|
||||
{
|
||||
BLOCK "StringFileInfo"
|
||||
{
|
||||
BLOCK "041104b0"
|
||||
{
|
||||
VALUE "Comments"
|
||||
VALUE "CompanyName", " "
|
||||
VALUE "FileDescription", "AGE_System"
|
||||
VALUE "FileVersion", "1, 0, 0, 1"
|
||||
VALUE "InternalName", "AGE_System"
|
||||
VALUE "LegalCopyright", "Copyright (C) 2012"
|
||||
VALUE "LegalTrademarks"
|
||||
VALUE "OriginalFilename", "AGE_System.exe"
|
||||
VALUE "PrivateBuild"
|
||||
VALUE "ProductName", "AGE_System"
|
||||
VALUE "ProductVersion", "1, 0, 0, 1"
|
||||
VALUE "SpecialBuild"
|
||||
}
|
||||
}
|
||||
BLOCK "VarFileInfo"
|
||||
{
|
||||
VALUE "Translation", 0x411, 1200
|
||||
}
|
||||
}
|
||||
|
||||
*/
|
||||
//(18禁ゲーム) [170331] [ルネ] ようこそ! スケベエルフの森へ パッケージ版
|
||||
class AGE_System : public ENGINE
|
||||
{
|
||||
public:
|
||||
AGE_System()
|
||||
{
|
||||
|
||||
check_by = CHECK_BY::CUSTOM;
|
||||
check_by_target = []()
|
||||
{
|
||||
auto s = check_by_list{L"Agrd.pac", L"vic.pac", L"se.pac", L"mus.pac"};
|
||||
return Util::SearchResourceString(L"AGE_System") // 已破解
|
||||
|| std::all_of(s.begin(), s.end(), [](auto f)
|
||||
{ return Util::CheckFile_exits(f, true); }); // 未破解
|
||||
};
|
||||
};
|
||||
bool attach_function();
|
||||
};
|
91
cpp/LunaHook/LunaHook/engine32/AGS.cpp
Normal file
91
cpp/LunaHook/LunaHook/engine32/AGS.cpp
Normal file
@ -0,0 +1,91 @@
|
||||
#include "AGS.h"
|
||||
|
||||
bool InsertAGSHook()
|
||||
{
|
||||
|
||||
const BYTE bytes1[] = {
|
||||
/*.text:0043E3A0 55 push ebp
|
||||
.text : 0043E3A1 8B EC mov ebp, esp
|
||||
.text : 0043E3A3 83 EC 38 sub esp, 38h
|
||||
.text : 0043E3A6 53 push ebx
|
||||
.text : 0043E3A7 56 push esi
|
||||
.text : 0043E3A8 8B F1 mov esi, ecx*/
|
||||
0x55,
|
||||
0x8b, 0xec,
|
||||
0x83, 0xec, 0x38, 0x53, 0x56, 0x8b, 0xf1};
|
||||
|
||||
ULONG addr = MemDbg::findBytes(bytes1, sizeof(bytes1), processStartAddress, processStopAddress);
|
||||
if (!addr)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
const BYTE bytes2[] = {
|
||||
/* .text:0043E95E FF 75 08 push[ebp + arg_0]
|
||||
.text:0043E961 8B CE mov ecx, esi
|
||||
.text : 0043E963 E8 38 FA FF FF call sub_43E3A0*/
|
||||
0xff, 0x75, 0x08,
|
||||
0x8b, 0xce};
|
||||
bool ok = false;
|
||||
|
||||
auto addrs = findrelativecall(bytes2, sizeof(bytes2), addr, processStartAddress, processStopAddress);
|
||||
|
||||
for (auto addr : addrs)
|
||||
{
|
||||
addr = findfuncstart(addr);
|
||||
if (!addr)
|
||||
continue;
|
||||
HookParam hp;
|
||||
hp.address = addr;
|
||||
hp.offset = get_reg(regs::eax);
|
||||
hp.type = USING_STRING;
|
||||
ConsoleOutput("INSERT HOOK_AGS %p", addr);
|
||||
|
||||
ok |= NewHook(hp, "HOOK_AGS");
|
||||
}
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
bool hook2()
|
||||
{
|
||||
// 誘惑女教師~熟れた蜜の味~
|
||||
for (auto addr : findiatcallormov_all((DWORD)TextOutA, processStartAddress, processStartAddress, processStopAddress, PAGE_EXECUTE))
|
||||
{
|
||||
|
||||
auto funcaddr = findfuncstart(addr, 0x1000);
|
||||
ConsoleOutput("funcaddr %p", funcaddr);
|
||||
if (!funcaddr)
|
||||
continue;
|
||||
BYTE sig1[] = {0x68, 0x00, 0x80, 0x00, 0x00, 0x6a, 0x00};
|
||||
BYTE sig2[] = {0x2D, 0xC0, 0x00, 0x00, 0x00, 0xC1, 0xE0, 0x08};
|
||||
BYTE sig3[] = {0x83, 0xC0, 0x80, 0xC1, 0xE0, 0x08};
|
||||
BYTE sig4[] = {0x3C, 0xA0, 0x0F, 0xB6, 0xC0};
|
||||
int found = 0;
|
||||
for (auto sigsz : std::vector<std::pair<BYTE *, int>>{{sig1, sizeof(sig1)}, {sig2, sizeof(sig2)}, {sig3, sizeof(sig3)}, {sig4, sizeof(sig4)}})
|
||||
{
|
||||
auto fd = MemDbg::findBytes(sigsz.first, sigsz.second, funcaddr, addr);
|
||||
ConsoleOutput("%p", fd);
|
||||
if (fd)
|
||||
found += 1;
|
||||
}
|
||||
if (found == 4)
|
||||
{
|
||||
HookParam hp;
|
||||
hp.address = funcaddr;
|
||||
hp.type = DATA_INDIRECT;
|
||||
hp.offset = get_stack(1);
|
||||
hp.index = 0;
|
||||
return NewHook(hp, "AGS");
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool AGS::attach_function()
|
||||
{
|
||||
|
||||
return InsertAGSHook() || hook2();
|
||||
}
|
14
cpp/LunaHook/LunaHook/engine32/AGS.h
Normal file
14
cpp/LunaHook/LunaHook/engine32/AGS.h
Normal file
@ -0,0 +1,14 @@
|
||||
|
||||
|
||||
class AGS : public ENGINE
|
||||
{
|
||||
public:
|
||||
AGS()
|
||||
{
|
||||
|
||||
check_by = CHECK_BY::FILE_ANY;
|
||||
check_by_target = check_by_list{L"voice/*.pk", L"sound/*.pk", L"misc/*.pk"};
|
||||
is_engine_certain = false;
|
||||
};
|
||||
bool attach_function();
|
||||
};
|
63
cpp/LunaHook/LunaHook/engine32/AIL2.cpp
Normal file
63
cpp/LunaHook/LunaHook/engine32/AIL2.cpp
Normal file
@ -0,0 +1,63 @@
|
||||
#include "AIL2.h"
|
||||
bool InsertAIL2Hook()
|
||||
{
|
||||
auto findalign = [](uintptr_t addr1)
|
||||
{
|
||||
const BYTE pattern[] = {0x90, 0x90, 0x83, 0xec};
|
||||
return reverseFindBytes(pattern, sizeof(pattern), processStartAddress, addr1) + 2;
|
||||
};
|
||||
bool succ = false;
|
||||
BYTE bytes1[] = {
|
||||
// .text:0042E5DF 3C 66 cmp al, 66h; 'f'
|
||||
//.text:0042E5E1 74 57 jz short loc_42E63A
|
||||
//.text : 0042E5E1
|
||||
//.text : 0042E5E3 3C 70 cmp al, 70h; 'p'
|
||||
//.text:0042E5E5 74 4C jz short loc_42E633
|
||||
//.text : 0042E5E5
|
||||
//.text : 0042E5E7 3C 73 cmp al, 73h; 's'
|
||||
//.text:0042E5E9 74 37 jz short loc_42E622
|
||||
0x3c, 0x66,
|
||||
0x74, XX,
|
||||
0x3c, 0x70,
|
||||
0x74, XX,
|
||||
0x3c, 0x73,
|
||||
0x74, XX};
|
||||
auto addr1 = MemDbg::findBytes(bytes1, sizeof(bytes1), processStartAddress, processStopAddress);
|
||||
if (addr1 == 0)
|
||||
return false;
|
||||
addr1 = findalign(addr1);
|
||||
if (addr1 == 0)
|
||||
return false;
|
||||
ConsoleOutput("AIL1 %p", addr1);
|
||||
HookParam hp;
|
||||
hp.address = addr1;
|
||||
hp.codepage = 932;
|
||||
hp.offset = get_stack(3);
|
||||
hp.type = USING_STRING;
|
||||
succ |= NewHook(hp, "AIL1");
|
||||
|
||||
BYTE bytes[] = {// if ( v12 != 32 && v12 != 33088 )
|
||||
0x3d, 0x40, 0x81, 0x00, 0x00, 0x0f};
|
||||
|
||||
addr1 = MemDbg::findBytes(bytes, sizeof(bytes), processStartAddress, processStopAddress);
|
||||
if (addr1 == 0)
|
||||
return succ;
|
||||
addr1 = MemDbg::findEnclosingAlignedFunction(addr1);
|
||||
if (addr1 == 0)
|
||||
return succ;
|
||||
hp = {};
|
||||
hp.address = addr1;
|
||||
hp.codepage = 932;
|
||||
hp.offset = get_stack(4);
|
||||
hp.type = USING_STRING | USING_SPLIT;
|
||||
hp.split_index = 0;
|
||||
succ |= NewHook(hp, "AIL2");
|
||||
|
||||
return succ;
|
||||
}
|
||||
bool AIL2::attach_function()
|
||||
{
|
||||
// アイル
|
||||
|
||||
return InsertAIL2Hook();
|
||||
}
|
13
cpp/LunaHook/LunaHook/engine32/AIL2.h
Normal file
13
cpp/LunaHook/LunaHook/engine32/AIL2.h
Normal file
@ -0,0 +1,13 @@
|
||||
|
||||
|
||||
class AIL2 : public ENGINE
|
||||
{
|
||||
public:
|
||||
AIL2()
|
||||
{
|
||||
|
||||
check_by = CHECK_BY::FILE;
|
||||
check_by_target = L"Gall*.dat";
|
||||
};
|
||||
bool attach_function();
|
||||
};
|
307
cpp/LunaHook/LunaHook/engine32/AOS.cpp
Normal file
307
cpp/LunaHook/LunaHook/engine32/AOS.cpp
Normal file
@ -0,0 +1,307 @@
|
||||
#include "AOS.h"
|
||||
|
||||
/**
|
||||
* jichi 4/1/2014: Insert AOS hook
|
||||
* About 彩斤<EFBFBD>: http://erogetrailers.com/brand/165
|
||||
* About AOS: http://asmodean.reverse.net/pages/exaos.html
|
||||
*
|
||||
* Sample games:
|
||||
*
|
||||
* [140228] [Sugar Pot] 恋する少女と想<EFBFBD>キセキ V1.00 H-CODE by <EFBFBD>쿿
|
||||
* - /HB8*0@3C2F0:恋する少女と想<EFBFBD>キセキ.exe
|
||||
* - /HBC*0@3C190:恋する少女と想<EFBFBD>キセキ.exe
|
||||
*
|
||||
* [120224] [Sugar Pot] ヂ<EFBFBD>モノツキ
|
||||
*
|
||||
* LiLiM games
|
||||
*
|
||||
* /HB8*0@3C2F0:恋する少女と想<EFBFBD>キセ
|
||||
* - addr: 246512 = 0x3c2f0
|
||||
* - length_offset: 1
|
||||
* - module: 1814017450
|
||||
* - off: 8
|
||||
* - type: 72 = 0x48
|
||||
*
|
||||
* 00e3c2ed cc int3
|
||||
* 00e3c2ee cc int3
|
||||
* 00e3c2ef cc int3
|
||||
* 00e3c2f0 /$ 51 push ecx ; jichi: hook here, function starts
|
||||
* 00e3c2f1 |. a1 0c64eb00 mov eax,dword ptr ds:[0xeb640c]
|
||||
* 00e3c2f6 |. 8b0d 7846eb00 mov ecx,dword ptr ds:[0xeb4678]
|
||||
* 00e3c2fc |. 53 push ebx
|
||||
* 00e3c2fd |. 55 push ebp
|
||||
* 00e3c2fe |. 8b6c24 10 mov ebp,dword ptr ss:[esp+0x10]
|
||||
* 00e3c302 |. 56 push esi
|
||||
* 00e3c303 |. 8b35 c446eb00 mov esi,dword ptr ds:[0xeb46c4]
|
||||
* 00e3c309 |. 57 push edi
|
||||
* 00e3c30a |. 0fb63d c746eb00 movzx edi,byte ptr ds:[0xeb46c7]
|
||||
* 00e3c311 |. 81e6 ffffff00 and esi,0xffffff
|
||||
* 00e3c317 |. 894424 18 mov dword ptr ss:[esp+0x18],eax
|
||||
* 00e3c31b |. 85ff test edi,edi
|
||||
* 00e3c31d |. 74 6b je short 恋する<EFBFBD>00e3c38a
|
||||
* 00e3c31f |. 8bd9 mov ebx,ecx
|
||||
* 00e3c321 |. 85db test ebx,ebx
|
||||
* 00e3c323 |. 74 17 je short 恋する<EFBFBD>00e3c33c
|
||||
* 00e3c325 |. 8b4b 28 mov ecx,dword ptr ds:[ebx+0x28]
|
||||
* 00e3c328 |. 56 push esi ; /color
|
||||
* 00e3c329 |. 51 push ecx ; |hdc
|
||||
* 00e3c32a |. ff15 3c40e800 call dword ptr ds:[<&gdi32.SetTextColor>>; \settextcolor
|
||||
* 00e3c330 |. 89b3 c8000000 mov dword ptr ds:[ebx+0xc8],esi
|
||||
* 00e3c336 |. 8b0d 7846eb00 mov ecx,dword ptr ds:[0xeb4678]
|
||||
* 00e3c33c |> 0fbf55 1c movsx edx,word ptr ss:[ebp+0x1c]
|
||||
* 00e3c340 |. 0fbf45 0a movsx eax,word ptr ss:[ebp+0xa]
|
||||
* 00e3c344 |. 0fbf75 1a movsx esi,word ptr ss:[ebp+0x1a]
|
||||
* 00e3c348 |. 03d7 add edx,edi
|
||||
* 00e3c34a |. 03c2 add eax,edx
|
||||
* 00e3c34c |. 0fbf55 08 movsx edx,word ptr ss:[ebp+0x8]
|
||||
* 00e3c350 |. 03f7 add esi,edi
|
||||
* 00e3c352 |. 03d6 add edx,esi
|
||||
* 00e3c354 |. 85c9 test ecx,ecx
|
||||
* 00e3c356 |. 74 32 je short 恋する<EFBFBD>00e3c38a
|
||||
*/
|
||||
|
||||
bool InsertAOS1Hook()
|
||||
{
|
||||
// jichi 4/2/2014: The starting of this function is different from ヂ<>モノツキ
|
||||
// So, use a pattern in the middle of the function instead.
|
||||
//
|
||||
// const BYTE bytes[] = {
|
||||
// 0x51, // 00e3c2f0 /$ 51 push ecx ; jichi: hook here, function begins
|
||||
// 0xa1, 0x0c,0x64,0xeb,0x00, // 00e3c2f1 |. a1 0c64eb00 mov eax,dword ptr ds:[0xeb640c]
|
||||
// 0x8b,0x0d, 0x78,0x46,0xeb,0x00, // 00e3c2f6 |. 8b0d 7846eb00 mov ecx,dword ptr ds:[0xeb4678]
|
||||
// 0x53, // 00e3c2fc |. 53 push ebx
|
||||
// 0x55, // 00e3c2fd |. 55 push ebp
|
||||
// 0x8b,0x6c,0x24, 0x10, // 00e3c2fe |. 8b6c24 10 mov ebp,dword ptr ss:[esp+0x10]
|
||||
// 0x56, // 00e3c302 |. 56 push esi
|
||||
// 0x8b,0x35, 0xc4,0x46,0xeb,0x00, // 00e3c303 |. 8b35 c446eb00 mov esi,dword ptr ds:[0xeb46c4]
|
||||
// 0x57, // 00e3c309 |. 57 push edi
|
||||
// 0x0f,0xb6,0x3d, 0xc7,0x46,0xeb,0x00, // 00e3c30a |. 0fb63d c746eb00 movzx edi,byte ptr ds:[0xeb46c7]
|
||||
// 0x81,0xe6, 0xff,0xff,0xff,0x00 // 00e3c311 |. 81e6 ffffff00 and esi,0xffffff
|
||||
//};
|
||||
// enum { addr_offset = 0 };
|
||||
|
||||
const BYTE bytes[] = {
|
||||
0x0f, 0xbf, 0x55, 0x1c, // 00e3c33c |> 0fbf55 1c movsx edx,word ptr ss:[ebp+0x1c]
|
||||
0x0f, 0xbf, 0x45, 0x0a, // 00e3c340 |. 0fbf45 0a movsx eax,word ptr ss:[ebp+0xa]
|
||||
0x0f, 0xbf, 0x75, 0x1a, // 00e3c344 |. 0fbf75 1a movsx esi,word ptr ss:[ebp+0x1a]
|
||||
0x03, 0xd7, // 00e3c348 |. 03d7 add edx,edi
|
||||
0x03, 0xc2, // 00e3c34a |. 03c2 add eax,edx
|
||||
0x0f, 0xbf, 0x55, 0x08, // 00e3c34c |. 0fbf55 08 movsx edx,word ptr ss:[ebp+0x8]
|
||||
0x03, 0xf7, // 00e3c350 |. 03f7 add esi,edi
|
||||
0x03, 0xd6, // 00e3c352 |. 03d6 add edx,esi
|
||||
0x85, 0xc9 // 00e3c354 |. 85c9 test ecx,ecx
|
||||
};
|
||||
enum
|
||||
{
|
||||
addr_offset = 0x00e3c2f0 - 0x00e3c33c
|
||||
}; // distance to the beginning of the function, which is 0x51 (push ecx)
|
||||
ULONG range = min(processStopAddress - processStartAddress, MAX_REL_ADDR);
|
||||
ULONG addr = MemDbg::findBytes(bytes, sizeof(bytes), processStartAddress, processStartAddress + range);
|
||||
// GROWL(reladdr);
|
||||
if (!addr)
|
||||
{
|
||||
ConsoleOutput("AOS1: pattern not found");
|
||||
return false;
|
||||
}
|
||||
addr += addr_offset;
|
||||
// GROWL(addr);
|
||||
enum
|
||||
{
|
||||
push_ecx = 0x51
|
||||
}; // beginning of the function
|
||||
if (*(BYTE *)addr != push_ecx)
|
||||
{
|
||||
ConsoleOutput("AOS1: beginning of the function not found");
|
||||
return false;
|
||||
}
|
||||
|
||||
HookParam hp;
|
||||
hp.address = addr;
|
||||
hp.offset = get_stack(2);
|
||||
hp.type = DATA_INDIRECT;
|
||||
|
||||
ConsoleOutput("INSERT AOS1");
|
||||
|
||||
return NewHook(hp, "AOS1");
|
||||
}
|
||||
|
||||
bool InsertAOS2Hook()
|
||||
{
|
||||
const BYTE bytes[] = {
|
||||
0x51, // 00C4E7E0 /$ 51 PUSH ECX ; mireado: hook here, function begins
|
||||
0x33, 0xc0, // 00C4E7E1 |. 33C0 XOR EAX,EAX
|
||||
0x53, // 00C4E7E3 |. 53 PUSH EBX
|
||||
0x55, // 00C4E7E4 |. 55 PUSH EBP
|
||||
0x8b, 0x2d //, XX4, // 00C4E7E5 |. 8B2D 40A3CF00 MOV EBP,DWORD PTR DS:[0CFA340] ; mireado: some time changing 40A3CF00 => 40A3C000
|
||||
// 0x89,0x07, // 00C4E7EB |. 8907 MOV DWORD PTR DS:[EDI],EAX
|
||||
// 0x89,0x47, 0x04 // 00C4E7ED |. 8947 04 MOV DWORD PTR DS:[EDI+4],EAX
|
||||
// 0x56, // 00C4E7F0 |. 56 PUSH ESI
|
||||
// 0x8b,0x75, 0x44 // 00C4E7F1 |. 8B75 44 MOV ESI,DWORD PTR SS:[EBP+44]
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
addr_offset = 0
|
||||
}; // distance to the beginning of the function, which is 0x51 (push ecx)
|
||||
ULONG range = min(processStopAddress - processStartAddress, MAX_REL_ADDR);
|
||||
ULONG addr = MemDbg::findBytes(bytes, sizeof(bytes), processStartAddress, processStartAddress + range);
|
||||
// GROWL(reladdr);
|
||||
if (!addr)
|
||||
{
|
||||
ConsoleOutput("AOS2: pattern not found");
|
||||
return false;
|
||||
}
|
||||
addr += addr_offset;
|
||||
// GROWL(addr);
|
||||
enum
|
||||
{
|
||||
push_ecx = 0x51
|
||||
}; // beginning of the function
|
||||
if (*(BYTE *)addr != push_ecx)
|
||||
{
|
||||
ConsoleOutput("AOS2: beginning of the function not found");
|
||||
return false;
|
||||
}
|
||||
|
||||
HookParam hp;
|
||||
hp.address = addr;
|
||||
hp.offset = get_stack(2);
|
||||
hp.type = DATA_INDIRECT;
|
||||
|
||||
ConsoleOutput("INSERT AOS2");
|
||||
|
||||
return NewHook(hp, "AOS2");
|
||||
}
|
||||
|
||||
bool InsertAOSHook()
|
||||
{
|
||||
return InsertAOS1Hook() || InsertAOS2Hook();
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
DWORD calladdr(DWORD addr)
|
||||
{
|
||||
if (addr == 0)
|
||||
return 0;
|
||||
BYTE callop[] = {0xe8};
|
||||
addr = reverseFindBytes(callop, sizeof(callop), addr - 0x20, addr);
|
||||
if (addr == 0)
|
||||
return 0;
|
||||
auto calladdr = *(int *)((char *)addr + 1);
|
||||
ConsoleOutput("calladdr %p", calladdr);
|
||||
addr = calladdr + addr + 5;
|
||||
ConsoleOutput("funcaddr %p", addr);
|
||||
if (*(BYTE *)((BYTE *)addr - 1) != 0xcc)
|
||||
return 0;
|
||||
return addr;
|
||||
}
|
||||
DWORD lastcall()
|
||||
{
|
||||
auto addr = findiatcallormov((DWORD)TextOutA, processStartAddress, processStartAddress, processStopAddress, true);
|
||||
if (addr == 0)
|
||||
return 0;
|
||||
addr = MemDbg::findEnclosingAlignedFunction(addr);
|
||||
return addr;
|
||||
}
|
||||
}
|
||||
regs mov_reg_ebpoffset(int reg)
|
||||
{
|
||||
switch (reg)
|
||||
{
|
||||
case 0x4B:
|
||||
return regs::ebx;
|
||||
case 0x48:
|
||||
return regs::eax;
|
||||
case 0x49:
|
||||
return regs::ecx;
|
||||
case 0x4a:
|
||||
return regs::edx;
|
||||
case 0x4c:
|
||||
return regs::ebp;
|
||||
case 0x4d:
|
||||
return regs::esp;
|
||||
case 0x4e:
|
||||
return regs::esi;
|
||||
case 0x4f:
|
||||
return regs::edi;
|
||||
default:
|
||||
return regs::invalid;
|
||||
}
|
||||
}
|
||||
bool AOS_EX()
|
||||
{
|
||||
BYTE aos_shared_bytes1[] = {
|
||||
0x3c, XX,
|
||||
0x74, XX,
|
||||
0x3c, XX,
|
||||
0x74, XX,
|
||||
0x3c, XX,
|
||||
0x74, XX,
|
||||
0x3c, XX,
|
||||
0x74, XX,
|
||||
0x3c, XX,
|
||||
0x74, XX};
|
||||
BYTE aos_shared_bytes2[] = {
|
||||
|
||||
0x80, 0xfb, XX,
|
||||
0x74, XX,
|
||||
0x80, 0xfb, XX,
|
||||
0x74, XX,
|
||||
0x80, 0xfb, XX,
|
||||
0x74, XX,
|
||||
0x80, 0xfb, XX,
|
||||
0x74, XX};
|
||||
std::vector<DWORD> addrs;
|
||||
addrs.push_back(calladdr(MemDbg::findBytes(aos_shared_bytes1, sizeof(aos_shared_bytes1), processStartAddress, processStopAddress)));
|
||||
addrs.push_back(calladdr(MemDbg::findBytes(aos_shared_bytes2, sizeof(aos_shared_bytes2), processStartAddress, processStopAddress)));
|
||||
addrs.push_back(lastcall());
|
||||
for (auto addr : addrs)
|
||||
{
|
||||
if (addr == 0)
|
||||
continue;
|
||||
auto reg = mov_reg_ebpoffset(*(BYTE *)((BYTE *)addr + 5));
|
||||
int off;
|
||||
if (reg != regs::invalid)
|
||||
{
|
||||
// usercall
|
||||
off = get_reg(reg);
|
||||
}
|
||||
else if (((*(WORD *)addr)) == 0xec83)
|
||||
{
|
||||
// 姫様LOVEライフ!
|
||||
// 也是usercall,但是第二个参数是栈上。
|
||||
off = get_stack(1);
|
||||
}
|
||||
else
|
||||
{
|
||||
// 螺旋遡行のディストピア -The infinite set of alternative version- 官方中文
|
||||
BYTE sig[] = {0x89, 0x55, 0xFC};
|
||||
if (MemDbg::findBytes(sig, sizeof(sig), addr, addr + 0x20))
|
||||
{
|
||||
off = get_reg(regs::edx);
|
||||
}
|
||||
else
|
||||
{
|
||||
// cdecl;
|
||||
off = get_stack(2);
|
||||
}
|
||||
}
|
||||
HookParam hp;
|
||||
hp.address = addr;
|
||||
hp.offset = off;
|
||||
hp.type = NO_CONTEXT | DATA_INDIRECT;
|
||||
hp.index = 0;
|
||||
|
||||
return NewHook(hp, "AOS_EX");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool AOS::attach_function()
|
||||
{
|
||||
bool b1 = InsertAOSHook();
|
||||
bool b3 = AOS_EX();
|
||||
return b1 || b3;
|
||||
}
|
13
cpp/LunaHook/LunaHook/engine32/AOS.h
Normal file
13
cpp/LunaHook/LunaHook/engine32/AOS.h
Normal file
@ -0,0 +1,13 @@
|
||||
|
||||
|
||||
class AOS : public ENGINE
|
||||
{
|
||||
public:
|
||||
AOS()
|
||||
{
|
||||
|
||||
check_by = CHECK_BY::FILE;
|
||||
check_by_target = L"*.aos";
|
||||
};
|
||||
bool attach_function();
|
||||
};
|
50
cpp/LunaHook/LunaHook/engine32/AXL.cpp
Normal file
50
cpp/LunaHook/LunaHook/engine32/AXL.cpp
Normal file
@ -0,0 +1,50 @@
|
||||
#include "AXL.h"
|
||||
bool InsertAXLHook()
|
||||
{
|
||||
// キミの声がきこえる
|
||||
|
||||
BYTE bytes[] = {
|
||||
0x0f, 0x95, 0xc2, 0x33, 0xc0, 0xB9, 0x41, 0x00, 0x00, 0x00};
|
||||
auto addr = MemDbg::findBytes(bytes, sizeof(bytes), processStartAddress, processStopAddress);
|
||||
if (addr == 0)
|
||||
return false;
|
||||
|
||||
addr = findfuncstart(addr, 0x1000);
|
||||
if (addr == 0)
|
||||
return false;
|
||||
HookParam hp;
|
||||
hp.address = addr;
|
||||
hp.offset = get_stack(4);
|
||||
hp.type = USING_STRING;
|
||||
|
||||
return NewHook(hp, "AXL");
|
||||
}
|
||||
namespace
|
||||
{
|
||||
bool hook2()
|
||||
{
|
||||
// 剣乙女ノア
|
||||
// Maria~天使のキスと悪魔の花嫁~
|
||||
BYTE bytes[] = {
|
||||
0x55, 0x8b, 0xec,
|
||||
0x56,
|
||||
0x8b, 0xf0,
|
||||
0x3b, 0x9e, 0x8c, 0xf8, 0x00, 0x00,
|
||||
0x57};
|
||||
auto addr = MemDbg::findBytes(bytes, sizeof(bytes), processStartAddress, processStopAddress);
|
||||
if (addr == 0)
|
||||
return false;
|
||||
HookParam hp;
|
||||
hp.address = addr;
|
||||
hp.offset = get_stack(1);
|
||||
hp.split = get_reg(regs::eax);
|
||||
hp.type = USING_SPLIT;
|
||||
|
||||
return NewHook(hp, "TAILWIND");
|
||||
}
|
||||
}
|
||||
bool AXL::attach_function()
|
||||
{
|
||||
|
||||
return InsertAXLHook() || hook2();
|
||||
}
|
14
cpp/LunaHook/LunaHook/engine32/AXL.h
Normal file
14
cpp/LunaHook/LunaHook/engine32/AXL.h
Normal file
@ -0,0 +1,14 @@
|
||||
|
||||
|
||||
class AXL : public ENGINE
|
||||
{
|
||||
public:
|
||||
AXL()
|
||||
{
|
||||
|
||||
check_by = CHECK_BY::FILE;
|
||||
check_by_target = L"script.arc";
|
||||
is_engine_certain = false;
|
||||
};
|
||||
bool attach_function();
|
||||
};
|
23
cpp/LunaHook/LunaHook/engine32/Abalone.cpp
Normal file
23
cpp/LunaHook/LunaHook/engine32/Abalone.cpp
Normal file
@ -0,0 +1,23 @@
|
||||
#include "Abalone.h"
|
||||
|
||||
bool AbaloneHook()
|
||||
{
|
||||
BYTE bytes[] = {
|
||||
0x8B, 0x44, 0x24, XX,
|
||||
0x80, 0x38, 0x00,
|
||||
0x74};
|
||||
auto addr = MemDbg::findBytes(bytes, sizeof(bytes), processStartAddress, processStopAddress);
|
||||
ConsoleOutput("AbaloneHook %p", addr);
|
||||
if (addr == 0)
|
||||
return false;
|
||||
HookParam hp;
|
||||
hp.address = addr + 4;
|
||||
hp.offset = get_reg(regs::eax);
|
||||
hp.type = DATA_INDIRECT;
|
||||
hp.index = 0;
|
||||
return NewHook(hp, "AbaloneHook");
|
||||
}
|
||||
bool Abalone::attach_function()
|
||||
{
|
||||
return AbaloneHook();
|
||||
}
|
14
cpp/LunaHook/LunaHook/engine32/Abalone.h
Normal file
14
cpp/LunaHook/LunaHook/engine32/Abalone.h
Normal file
@ -0,0 +1,14 @@
|
||||
|
||||
|
||||
class Abalone : public ENGINE
|
||||
{
|
||||
public:
|
||||
Abalone()
|
||||
{
|
||||
|
||||
check_by = CHECK_BY::FILE;
|
||||
check_by_target = L"Archive.dat";
|
||||
is_engine_certain = false;
|
||||
};
|
||||
bool attach_function();
|
||||
};
|
423
cpp/LunaHook/LunaHook/engine32/Abel.cpp
Normal file
423
cpp/LunaHook/LunaHook/engine32/Abel.cpp
Normal file
@ -0,0 +1,423 @@
|
||||
#include "Abel.h"
|
||||
|
||||
/********************************************************************************************
|
||||
AbelSoftware hook:
|
||||
The game folder usually is made up many no extended name files(file name doesn't have '.').
|
||||
And these files have common prefix which is the game name, and 2 digit in order.
|
||||
|
||||
|
||||
********************************************************************************************/
|
||||
/** 7/31/2015
|
||||
* Sample game オタカ<EFBFBD> * Hooked address: 0x4413b0
|
||||
*
|
||||
* GDI functions are cached: TextOutA and GetTextExtentPoint32A
|
||||
*
|
||||
* 004413AB 90 NOP
|
||||
* 004413AC 90 NOP
|
||||
* 004413AD 90 NOP
|
||||
* 004413AE 90 NOP
|
||||
* 004413AF 90 NOP
|
||||
* 004413B0 6A FF PUSH -0x1 ; jichi: text in arg1, but text painted character by character
|
||||
* 004413B2 68 D0714900 PUSH .004971D0
|
||||
* 004413B7 64:A1 00000000 MOV EAX,DWORD PTR FS:[0]
|
||||
* 004413BD 50 PUSH EAX
|
||||
* 004413BE 64:8925 00000000 MOV DWORD PTR FS:[0],ESP
|
||||
* 004413C5 83EC 4C SUB ESP,0x4C
|
||||
* 004413C8 A1 C00B4B00 MOV EAX,DWORD PTR DS:[0x4B0BC0]
|
||||
* 004413CD 53 PUSH EBX
|
||||
* 004413CE 55 PUSH EBP
|
||||
* 004413CF 56 PUSH ESI
|
||||
* 004413D0 57 PUSH EDI
|
||||
* 004413D1 8BF1 MOV ESI,ECX
|
||||
* 004413D3 894424 48 MOV DWORD PTR SS:[ESP+0x48],EAX
|
||||
* 004413D7 894424 4C MOV DWORD PTR SS:[ESP+0x4C],EAX
|
||||
* 004413DB 894424 58 MOV DWORD PTR SS:[ESP+0x58],EAX
|
||||
* 004413DF 8B4424 6C MOV EAX,DWORD PTR SS:[ESP+0x6C]
|
||||
* 004413E3 33DB XOR EBX,EBX
|
||||
* 004413E5 50 PUSH EAX
|
||||
* 004413E6 8D4C24 4C LEA ECX,DWORD PTR SS:[ESP+0x4C]
|
||||
* 004413EA 895C24 68 MOV DWORD PTR SS:[ESP+0x68],EBX
|
||||
* 004413EE E8 74520400 CALL .00486667
|
||||
* 004413F3 8B4C24 78 MOV ECX,DWORD PTR SS:[ESP+0x78]
|
||||
* 004413F7 51 PUSH ECX
|
||||
* 004413F8 8D4C24 50 LEA ECX,DWORD PTR SS:[ESP+0x50]
|
||||
* 004413FC E8 66520400 CALL .00486667
|
||||
* 00441401 8B5424 7C MOV EDX,DWORD PTR SS:[ESP+0x7C]
|
||||
* 00441405 8D4C24 58 LEA ECX,DWORD PTR SS:[ESP+0x58]
|
||||
* 00441409 52 PUSH EDX
|
||||
* 0044140A E8 58520400 CALL .00486667
|
||||
* 0044140F 8B4424 70 MOV EAX,DWORD PTR SS:[ESP+0x70]
|
||||
* 00441413 894424 50 MOV DWORD PTR SS:[ESP+0x50],EAX
|
||||
* 00441417 8B4424 74 MOV EAX,DWORD PTR SS:[ESP+0x74]
|
||||
* 0044141B 83F8 FF CMP EAX,-0x1
|
||||
* 0044141E 75 06 JNZ SHORT .00441426
|
||||
* 00441420 895C24 54 MOV DWORD PTR SS:[ESP+0x54],EBX
|
||||
* 00441424 EB 2E JMP SHORT .00441454
|
||||
* 00441426 8BC8 MOV ECX,EAX
|
||||
* 00441428 33D2 XOR EDX,EDX
|
||||
* 0044142A 81E1 FF000000 AND ECX,0xFF
|
||||
* 00441430 8AD4 MOV DL,AH
|
||||
* 00441432 81C9 00FFFFFF OR ECX,0xFFFFFF00
|
||||
* 00441438 81E2 FF000000 AND EDX,0xFF
|
||||
* 0044143E C1E1 08 SHL ECX,0x8
|
||||
* 00441441 0BCA OR ECX,EDX
|
||||
* 00441443 C1E8 10 SHR EAX,0x10
|
||||
* 00441446 C1E1 08 SHL ECX,0x8
|
||||
* 00441449 25 FF000000 AND EAX,0xFF
|
||||
* 0044144E 0BC8 OR ECX,EAX
|
||||
* 00441450 894C24 54 MOV DWORD PTR SS:[ESP+0x54],ECX
|
||||
* 00441454 8B4424 48 MOV EAX,DWORD PTR SS:[ESP+0x48]
|
||||
* 00441458 3958 F8 CMP DWORD PTR DS:[EAX-0x8],EBX
|
||||
* 0044145B 0F84 7A030000 JE .004417DB
|
||||
* 00441461 8B8E 08020000 MOV ECX,DWORD PTR DS:[ESI+0x208]
|
||||
* 00441467 83F9 20 CMP ECX,0x20
|
||||
* 0044146A 0F8D 35030000 JGE .004417A5
|
||||
* 00441470 0FBE00 MOVSX EAX,BYTE PTR DS:[EAX]
|
||||
* 00441473 83E8 09 SUB EAX,0x9
|
||||
* 00441476 0F84 29030000 JE .004417A5
|
||||
* 0044147C 48 DEC EAX
|
||||
* 0044147D 0F84 0A030000 JE .0044178D
|
||||
* 00441483 83E8 03 SUB EAX,0x3
|
||||
* 00441486 0F84 19030000 JE .004417A5
|
||||
* 0044148C 8BBE 38010000 MOV EDI,DWORD PTR DS:[ESI+0x138]
|
||||
* 00441492 68 80C84A00 PUSH .004AC880
|
||||
* 00441497 8BCF MOV ECX,EDI
|
||||
* 00441499 E8 E2E9FDFF CALL .0041FE80
|
||||
* 0044149E 3BC3 CMP EAX,EBX
|
||||
* 004414A0 7D 0F JGE SHORT .004414B1
|
||||
* 004414A2 53 PUSH EBX
|
||||
* 004414A3 53 PUSH EBX
|
||||
* 004414A4 53 PUSH EBX
|
||||
* 004414A5 53 PUSH EBX
|
||||
* 004414A6 8D4C24 48 LEA ECX,DWORD PTR SS:[ESP+0x48]
|
||||
* 004414AA E8 916DFDFF CALL .00418240
|
||||
* 004414AF EB 06 JMP SHORT .004414B7
|
||||
* 004414B1 8B4F 24 MOV ECX,DWORD PTR DS:[EDI+0x24]
|
||||
* 004414B4 8B0481 MOV EAX,DWORD PTR DS:[ECX+EAX*4]
|
||||
* 004414B7 8B48 04 MOV ECX,DWORD PTR DS:[EAX+0x4]
|
||||
* 004414BA 8B10 MOV EDX,DWORD PTR DS:[EAX]
|
||||
* 004414BC 894C24 24 MOV DWORD PTR SS:[ESP+0x24],ECX
|
||||
* 004414C0 895424 20 MOV DWORD PTR SS:[ESP+0x20],EDX
|
||||
* 004414C4 8B50 08 MOV EDX,DWORD PTR DS:[EAX+0x8]
|
||||
* 004414C7 8B40 0C MOV EAX,DWORD PTR DS:[EAX+0xC]
|
||||
* 004414CA 8D4C24 10 LEA ECX,DWORD PTR SS:[ESP+0x10]
|
||||
* 004414CE 895424 28 MOV DWORD PTR SS:[ESP+0x28],EDX
|
||||
* 004414D2 51 PUSH ECX
|
||||
* 004414D3 8BCE MOV ECX,ESI
|
||||
* 004414D5 894424 30 MOV DWORD PTR SS:[ESP+0x30],EAX
|
||||
* 004414D9 E8 52F3FFFF CALL .00440830
|
||||
* 004414DE 8B5424 50 MOV EDX,DWORD PTR SS:[ESP+0x50]
|
||||
* 004414E2 33C9 XOR ECX,ECX
|
||||
* 004414E4 894C24 78 MOV DWORD PTR SS:[ESP+0x78],ECX
|
||||
* 004414E8 B8 B0B64900 MOV EAX,.0049B6B0
|
||||
* 004414ED 3B10 CMP EDX,DWORD PTR DS:[EAX]
|
||||
* 004414EF 7E 0B JLE SHORT .004414FC
|
||||
* 004414F1 83C0 04 ADD EAX,0x4
|
||||
* 004414F4 41 INC ECX
|
||||
* 004414F5 3D C0B64900 CMP EAX,.0049B6C0
|
||||
* 004414FA ^72 F1 JB SHORT .004414ED
|
||||
* 004414FC 8B5424 48 MOV EDX,DWORD PTR SS:[ESP+0x48]
|
||||
* 00441500 8D4424 18 LEA EAX,DWORD PTR SS:[ESP+0x18]
|
||||
* 00441504 894C24 78 MOV DWORD PTR SS:[ESP+0x78],ECX
|
||||
* 00441508 8B4C8E 3C MOV ECX,DWORD PTR DS:[ESI+ECX*4+0x3C]
|
||||
* 0044150C 52 PUSH EDX
|
||||
* 0044150D 50 PUSH EAX
|
||||
* 0044150E E8 3D34FCFF CALL .00404950
|
||||
* 00441513 8B46 38 MOV EAX,DWORD PTR DS:[ESI+0x38]
|
||||
* 00441516 895C24 70 MOV DWORD PTR SS:[ESP+0x70],EBX
|
||||
* 0044151A 3BC3 CMP EAX,EBX
|
||||
* 0044151C 0F84 F9000000 JE .0044161B
|
||||
* 00441522 8B50 08 MOV EDX,DWORD PTR DS:[EAX+0x8]
|
||||
* 00441525 8B4E 78 MOV ECX,DWORD PTR DS:[ESI+0x78]
|
||||
* 00441528 3BCA CMP ECX,EDX
|
||||
* 0044152A 0F8D EB000000 JGE .0044161B
|
||||
* 00441530 8B50 04 MOV EDX,DWORD PTR DS:[EAX+0x4]
|
||||
* 00441533 8B4424 10 MOV EAX,DWORD PTR SS:[ESP+0x10]
|
||||
* 00441537 8B7E 74 MOV EDI,DWORD PTR DS:[ESI+0x74]
|
||||
* 0044153A 8B2C8A MOV EBP,DWORD PTR DS:[EDX+ECX*4]
|
||||
* 0044153D 8B4C24 18 MOV ECX,DWORD PTR SS:[ESP+0x18]
|
||||
* 00441541 897C24 7C MOV DWORD PTR SS:[ESP+0x7C],EDI
|
||||
* 00441545 8B55 00 MOV EDX,DWORD PTR SS:[EBP]
|
||||
* 00441548 8D1C01 LEA EBX,DWORD PTR DS:[ECX+EAX]
|
||||
* 0044154B 8BCD MOV ECX,EBP
|
||||
* 0044154D FF52 08 CALL DWORD PTR DS:[EDX+0x8]
|
||||
* 00441550 3BF8 CMP EDI,EAX
|
||||
* 00441552 0F8D C3000000 JGE .0044161B
|
||||
* 00441558 EB 04 JMP SHORT .0044155E
|
||||
* 0044155A 8B7C24 7C MOV EDI,DWORD PTR SS:[ESP+0x7C]
|
||||
* 0044155E 8B45 00 MOV EAX,DWORD PTR SS:[EBP]
|
||||
* 00441561 57 PUSH EDI
|
||||
* 00441562 8BCD MOV ECX,EBP
|
||||
* 00441564 FF50 04 CALL DWORD PTR DS:[EAX+0x4]
|
||||
* 00441567 8BF8 MOV EDI,EAX
|
||||
* 00441569 8BCF MOV ECX,EDI
|
||||
* 0044156B 8B17 MOV EDX,DWORD PTR DS:[EDI]
|
||||
* 0044156D FF52 0C CALL DWORD PTR DS:[EDX+0xC]
|
||||
* 00441570 85C0 TEST EAX,EAX
|
||||
* 00441572 0F84 A3000000 JE .0044161B
|
||||
* 00441578 8B07 MOV EAX,DWORD PTR DS:[EDI]
|
||||
* 0044157A 8D4C24 6C LEA ECX,DWORD PTR SS:[ESP+0x6C]
|
||||
* 0044157E 51 PUSH ECX
|
||||
* 0044157F 8BCF MOV ECX,EDI
|
||||
* 00441581 FF50 10 CALL DWORD PTR DS:[EAX+0x10]
|
||||
* 00441584 8B5424 6C MOV EDX,DWORD PTR SS:[ESP+0x6C]
|
||||
* 00441588 8B4C24 78 MOV ECX,DWORD PTR SS:[ESP+0x78]
|
||||
* 0044158C 8D4424 30 LEA EAX,DWORD PTR SS:[ESP+0x30]
|
||||
* 00441590 52 PUSH EDX
|
||||
* 00441591 8B4C8E 3C MOV ECX,DWORD PTR DS:[ESI+ECX*4+0x3C]
|
||||
* 00441595 50 PUSH EAX
|
||||
* 00441596 C64424 6C 01 MOV BYTE PTR SS:[ESP+0x6C],0x1
|
||||
* 0044159B E8 B033FCFF CALL .00404950
|
||||
* 004415A0 8B10 MOV EDX,DWORD PTR DS:[EAX]
|
||||
* 004415A2 8B86 E4030000 MOV EAX,DWORD PTR DS:[ESI+0x3E4]
|
||||
* 004415A8 03DA ADD EBX,EDX
|
||||
* 004415AA 8B5424 6C MOV EDX,DWORD PTR SS:[ESP+0x6C]
|
||||
* 004415AE 52 PUSH EDX
|
||||
* 004415AF 50 PUSH EAX
|
||||
* 004415B0 E8 BB020000 CALL .00441870
|
||||
* 004415B5 83C4 08 ADD ESP,0x8
|
||||
* 004415B8 85C0 TEST EAX,EAX
|
||||
* 004415BA 74 08 JE SHORT .004415C4
|
||||
* 004415BC 3B5C24 28 CMP EBX,DWORD PTR SS:[ESP+0x28]
|
||||
* 004415C0 7F 43 JG SHORT .00441605
|
||||
* 004415C2 EB 18 JMP SHORT .004415DC
|
||||
* 004415C4 8B4C24 6C MOV ECX,DWORD PTR SS:[ESP+0x6C]
|
||||
* 004415C8 8B86 E0030000 MOV EAX,DWORD PTR DS:[ESI+0x3E0]
|
||||
* 004415CE 51 PUSH ECX
|
||||
* 004415CF 50 PUSH EAX
|
||||
* 004415D0 E8 9B020000 CALL .00441870
|
||||
* 004415D5 83C4 08 ADD ESP,0x8
|
||||
* 004415D8 85C0 TEST EAX,EAX
|
||||
* 004415DA 74 31 JE SHORT .0044160D
|
||||
* 004415DC 8D4C24 6C LEA ECX,DWORD PTR SS:[ESP+0x6C]
|
||||
* 004415E0 C64424 64 00 MOV BYTE PTR SS:[ESP+0x64],0x0
|
||||
* 004415E5 E8 404F0400 CALL .0048652A
|
||||
* 004415EA 8B7C24 7C MOV EDI,DWORD PTR SS:[ESP+0x7C]
|
||||
* 004415EE 8B55 00 MOV EDX,DWORD PTR SS:[EBP]
|
||||
* 004415F1 47 INC EDI
|
||||
* 004415F2 8BCD MOV ECX,EBP
|
||||
* 004415F4 897C24 7C MOV DWORD PTR SS:[ESP+0x7C],EDI
|
||||
* 004415F8 FF52 08 CALL DWORD PTR DS:[EDX+0x8]
|
||||
* 004415FB 3BF8 CMP EDI,EAX
|
||||
* 004415FD ^0F8C 57FFFFFF JL .0044155A
|
||||
* 00441603 EB 16 JMP SHORT .0044161B
|
||||
* 00441605 C74424 70 010000>MOV DWORD PTR SS:[ESP+0x70],0x1
|
||||
* 0044160D 8D4C24 6C LEA ECX,DWORD PTR SS:[ESP+0x6C]
|
||||
* 00441611 C64424 64 00 MOV BYTE PTR SS:[ESP+0x64],0x0
|
||||
* 00441616 E8 0F4F0400 CALL .0048652A
|
||||
* 0044161B 8B4424 10 MOV EAX,DWORD PTR SS:[ESP+0x10]
|
||||
* 0044161F 8B4C24 18 MOV ECX,DWORD PTR SS:[ESP+0x18]
|
||||
* 00441623 03C8 ADD ECX,EAX
|
||||
* 00441625 8B4424 28 MOV EAX,DWORD PTR SS:[ESP+0x28]
|
||||
* 00441629 3BC8 CMP ECX,EAX
|
||||
* 0044162B 7E 18 JLE SHORT .00441645
|
||||
* 0044162D 8B5424 48 MOV EDX,DWORD PTR SS:[ESP+0x48]
|
||||
* 00441631 8B86 E0030000 MOV EAX,DWORD PTR DS:[ESI+0x3E0]
|
||||
* 00441637 52 PUSH EDX
|
||||
* 00441638 50 PUSH EAX
|
||||
* 00441639 E8 32020000 CALL .00441870
|
||||
* 0044163E 83C4 08 ADD ESP,0x8
|
||||
* 00441641 85C0 TEST EAX,EAX
|
||||
* 00441643 74 08 JE SHORT .0044164D
|
||||
* 00441645 8B4424 70 MOV EAX,DWORD PTR SS:[ESP+0x70]
|
||||
* 00441649 85C0 TEST EAX,EAX
|
||||
* 0044164B 74 3F JE SHORT .0044168C
|
||||
* 0044164D 8B8E 08020000 MOV ECX,DWORD PTR DS:[ESI+0x208]
|
||||
* 00441653 41 INC ECX
|
||||
* 00441654 8BC1 MOV EAX,ECX
|
||||
* 00441656 898E 08020000 MOV DWORD PTR DS:[ESI+0x208],ECX
|
||||
* 0044165C 83F8 20 CMP EAX,0x20
|
||||
* 0044165F 0F8D 40010000 JGE .004417A5
|
||||
* 00441665 83EC 10 SUB ESP,0x10
|
||||
* 00441668 8B15 D0B04A00 MOV EDX,DWORD PTR DS:[0x4AB0D0]
|
||||
* 0044166E 8BDC MOV EBX,ESP
|
||||
* 00441670 33C0 XOR EAX,EAX
|
||||
* 00441672 8B3D D4B04A00 MOV EDI,DWORD PTR DS:[0x4AB0D4]
|
||||
* 00441678 33C9 XOR ECX,ECX
|
||||
* 0044167A 8903 MOV DWORD PTR DS:[EBX],EAX
|
||||
* 0044167C 894B 04 MOV DWORD PTR DS:[EBX+0x4],ECX
|
||||
* 0044167F 8BCE MOV ECX,ESI
|
||||
* 00441681 8953 08 MOV DWORD PTR DS:[EBX+0x8],EDX
|
||||
* 00441684 897B 0C MOV DWORD PTR DS:[EBX+0xC],EDI
|
||||
* 00441687 E8 7418FCFF CALL .00402F00
|
||||
* 0044168C 8B86 08020000 MOV EAX,DWORD PTR DS:[ESI+0x208]
|
||||
* 00441692 6A 00 PUSH 0x0
|
||||
* 00441694 8D0CC5 00000000 LEA ECX,DWORD PTR DS:[EAX*8]
|
||||
* 0044169B 2BC8 SUB ECX,EAX
|
||||
* 0044169D 8B948E 78040000 MOV EDX,DWORD PTR DS:[ESI+ECX*4+0x478]
|
||||
* 004416A4 8DAC8E 70040000 LEA EBP,DWORD PTR DS:[ESI+ECX*4+0x470]
|
||||
* 004416AB 52 PUSH EDX
|
||||
* 004416AC 8BCD MOV ECX,EBP
|
||||
* 004416AE E8 7D8A0000 CALL .0044A130
|
||||
* 004416B3 8BD8 MOV EBX,EAX
|
||||
* 004416B5 8D4424 48 LEA EAX,DWORD PTR SS:[ESP+0x48]
|
||||
* 004416B9 50 PUSH EAX
|
||||
* 004416BA 8D7B 08 LEA EDI,DWORD PTR DS:[EBX+0x8]
|
||||
* 004416BD 8BCF MOV ECX,EDI
|
||||
* 004416BF E8 534F0400 CALL .00486617
|
||||
* 004416C4 8D4C24 4C LEA ECX,DWORD PTR SS:[ESP+0x4C]
|
||||
* 004416C8 51 PUSH ECX
|
||||
* 004416C9 8D4F 04 LEA ECX,DWORD PTR DS:[EDI+0x4]
|
||||
* 004416CC E8 464F0400 CALL .00486617
|
||||
* 004416D1 8B5424 50 MOV EDX,DWORD PTR SS:[ESP+0x50]
|
||||
* 004416D5 8D4C24 58 LEA ECX,DWORD PTR SS:[ESP+0x58]
|
||||
* 004416D9 8957 08 MOV DWORD PTR DS:[EDI+0x8],EDX
|
||||
* 004416DC 8B4424 54 MOV EAX,DWORD PTR SS:[ESP+0x54]
|
||||
* 004416E0 51 PUSH ECX
|
||||
* 004416E1 8D4F 10 LEA ECX,DWORD PTR DS:[EDI+0x10]
|
||||
* 004416E4 8947 0C MOV DWORD PTR DS:[EDI+0xC],EAX
|
||||
* 004416E7 E8 2B4F0400 CALL .00486617
|
||||
* 004416EC 8B45 08 MOV EAX,DWORD PTR SS:[EBP+0x8]
|
||||
* 004416EF 85C0 TEST EAX,EAX
|
||||
* 004416F1 74 04 JE SHORT .004416F7
|
||||
* 004416F3 8918 MOV DWORD PTR DS:[EAX],EBX
|
||||
* 004416F5 EB 03 JMP SHORT .004416FA
|
||||
* 004416F7 895D 04 MOV DWORD PTR SS:[EBP+0x4],EBX
|
||||
* 004416FA 83EC 10 SUB ESP,0x10
|
||||
* 004416FD 895D 08 MOV DWORD PTR SS:[EBP+0x8],EBX
|
||||
* 00441700 8B4424 20 MOV EAX,DWORD PTR SS:[ESP+0x20]
|
||||
* 00441704 8B5424 28 MOV EDX,DWORD PTR SS:[ESP+0x28]
|
||||
* 00441708 8B7C24 2C MOV EDI,DWORD PTR SS:[ESP+0x2C]
|
||||
* 0044170C 8BDC MOV EBX,ESP
|
||||
* 0044170E 8D4C02 02 LEA ECX,DWORD PTR DS:[EDX+EAX+0x2]
|
||||
* 00441712 8B5424 24 MOV EDX,DWORD PTR SS:[ESP+0x24]
|
||||
* 00441716 8903 MOV DWORD PTR DS:[EBX],EAX
|
||||
* 00441718 8D7C3A 02 LEA EDI,DWORD PTR DS:[EDX+EDI+0x2]
|
||||
* 0044171C 8953 04 MOV DWORD PTR DS:[EBX+0x4],EDX
|
||||
* 0044171F 894B 08 MOV DWORD PTR DS:[EBX+0x8],ECX
|
||||
* 00441722 8BCE MOV ECX,ESI
|
||||
* 00441724 897B 0C MOV DWORD PTR DS:[EBX+0xC],EDI
|
||||
* 00441727 E8 D417FCFF CALL .00402F00
|
||||
* 0044172C 8B4424 4C MOV EAX,DWORD PTR SS:[ESP+0x4C]
|
||||
* 00441730 8B48 F8 MOV ECX,DWORD PTR DS:[EAX-0x8]
|
||||
* 00441733 85C9 TEST ECX,ECX
|
||||
* 00441735 74 6E JE SHORT .004417A5
|
||||
* 00441737 8B4E 3C MOV ECX,DWORD PTR DS:[ESI+0x3C]
|
||||
* 0044173A 50 PUSH EAX
|
||||
* 0044173B 8D4424 24 LEA EAX,DWORD PTR SS:[ESP+0x24]
|
||||
* 0044173F 50 PUSH EAX
|
||||
* 00441740 E8 0B32FCFF CALL .00404950
|
||||
* 00441745 8B5C24 20 MOV EBX,DWORD PTR SS:[ESP+0x20]
|
||||
* 00441749 8B4C24 18 MOV ECX,DWORD PTR SS:[ESP+0x18]
|
||||
* 0044174D 8B7C24 24 MOV EDI,DWORD PTR SS:[ESP+0x24]
|
||||
* 00441751 8BC3 MOV EAX,EBX
|
||||
* 00441753 2BC1 SUB EAX,ECX
|
||||
* 00441755 8BCF MOV ECX,EDI
|
||||
* 00441757 99 CDQ
|
||||
* 00441758 2BC2 SUB EAX,EDX
|
||||
* 0044175A 8B5424 14 MOV EDX,DWORD PTR SS:[ESP+0x14]
|
||||
* 0044175E F7D9 NEG ECX
|
||||
* 00441760 D1F8 SAR EAX,1
|
||||
* 00441762 03CA ADD ECX,EDX
|
||||
* 00441764 8B5424 10 MOV EDX,DWORD PTR SS:[ESP+0x10]
|
||||
* 00441768 F7D8 NEG EAX
|
||||
* 0044176A 03C2 ADD EAX,EDX
|
||||
* 0044176C 83EC 10 SUB ESP,0x10
|
||||
* 0044176F 8D7C39 02 LEA EDI,DWORD PTR DS:[ECX+EDI+0x2]
|
||||
* 00441773 8D5418 02 LEA EDX,DWORD PTR DS:[EAX+EBX+0x2]
|
||||
* 00441777 8BDC MOV EBX,ESP
|
||||
* 00441779 8903 MOV DWORD PTR DS:[EBX],EAX
|
||||
* 0044177B 894B 04 MOV DWORD PTR DS:[EBX+0x4],ECX
|
||||
* 0044177E 8BCE MOV ECX,ESI
|
||||
* 00441780 8953 08 MOV DWORD PTR DS:[EBX+0x8],EDX
|
||||
* 00441783 897B 0C MOV DWORD PTR DS:[EBX+0xC],EDI
|
||||
* 00441786 E8 7517FCFF CALL .00402F00
|
||||
* 0044178B EB 18 JMP SHORT .004417A5
|
||||
* 0044178D 8D41 29 LEA EAX,DWORD PTR DS:[ECX+0x29]
|
||||
* 00441790 8D14C5 00000000 LEA EDX,DWORD PTR DS:[EAX*8]
|
||||
* 00441797 2BD0 SUB EDX,EAX
|
||||
* 00441799 391C96 CMP DWORD PTR DS:[ESI+EDX*4],EBX
|
||||
* 0044179C 74 07 JE SHORT .004417A5
|
||||
* 0044179E 41 INC ECX
|
||||
* 0044179F 898E 08020000 MOV DWORD PTR DS:[ESI+0x208],ECX
|
||||
* 004417A5 8B86 E8020000 MOV EAX,DWORD PTR DS:[ESI+0x2E8]
|
||||
* 004417AB 33DB XOR EBX,EBX
|
||||
* 004417AD 3BC3 CMP EAX,EBX
|
||||
* 004417AF 74 2A JE SHORT .004417DB
|
||||
* 004417B1 399E C8030000 CMP DWORD PTR DS:[ESI+0x3C8],EBX
|
||||
* 004417B7 75 22 JNZ SHORT .004417DB
|
||||
* 004417B9 8B86 C4030000 MOV EAX,DWORD PTR DS:[ESI+0x3C4]
|
||||
* 004417BF 8BCE MOV ECX,ESI
|
||||
* 004417C1 50 PUSH EAX
|
||||
* 004417C2 E8 89040000 CALL .00441C50
|
||||
* 004417C7 3B86 3C020000 CMP EAX,DWORD PTR DS:[ESI+0x23C]
|
||||
* 004417CD 74 06 JE SHORT .004417D5
|
||||
* 004417CF 8986 38020000 MOV DWORD PTR DS:[ESI+0x238],EAX
|
||||
* 004417D5 8986 3C020000 MOV DWORD PTR DS:[ESI+0x23C],EAX
|
||||
* 004417DB 399E 30020000 CMP DWORD PTR DS:[ESI+0x230],EBX
|
||||
* 004417E1 75 3C JNZ SHORT .0044181F
|
||||
* 004417E3 8BCE MOV ECX,ESI
|
||||
* 004417E5 E8 C6040000 CALL .00441CB0
|
||||
* 004417EA 85C0 TEST EAX,EAX
|
||||
* 004417EC 75 31 JNZ SHORT .0044181F
|
||||
* 004417EE 399E 18020000 CMP DWORD PTR DS:[ESI+0x218],EBX
|
||||
* 004417F4 74 29 JE SHORT .0044181F
|
||||
* 004417F6 83BE C4020000 64 CMP DWORD PTR DS:[ESI+0x2C4],0x64
|
||||
* 004417FD 74 20 JE SHORT .0044181F
|
||||
* 004417FF 8B86 08020000 MOV EAX,DWORD PTR DS:[ESI+0x208]
|
||||
* 00441805 83F8 20 CMP EAX,0x20
|
||||
* 00441808 7D 1D JGE SHORT .00441827
|
||||
* 0044180A 83C0 29 ADD EAX,0x29
|
||||
* 0044180D 8D0CC5 00000000 LEA ECX,DWORD PTR DS:[EAX*8]
|
||||
* 00441814 2BC8 SUB ECX,EAX
|
||||
* 00441816 391C8E CMP DWORD PTR DS:[ESI+ECX*4],EBX
|
||||
* 00441819 74 0C JE SHORT .00441827
|
||||
* 0044181B 6A 01 PUSH 0x1
|
||||
* 0044181D EB 01 JMP SHORT .00441820
|
||||
* 0044181F 53 PUSH EBX
|
||||
* 00441820 8BCE MOV ECX,ESI
|
||||
* 00441822 E8 49C5FEFF CALL .0042DD70
|
||||
* 00441827 8D4C24 58 LEA ECX,DWORD PTR SS:[ESP+0x58]
|
||||
* 0044182B C74424 64 030000>MOV DWORD PTR SS:[ESP+0x64],0x3
|
||||
* 00441833 E8 F24C0400 CALL .0048652A
|
||||
* 00441838 8D4C24 4C LEA ECX,DWORD PTR SS:[ESP+0x4C]
|
||||
* 0044183C C64424 64 02 MOV BYTE PTR SS:[ESP+0x64],0x2
|
||||
* 00441841 E8 E44C0400 CALL .0048652A
|
||||
* 00441846 8D4C24 48 LEA ECX,DWORD PTR SS:[ESP+0x48]
|
||||
* 0044184A C74424 64 FFFFFF>MOV DWORD PTR SS:[ESP+0x64],-0x1
|
||||
* 00441852 E8 D34C0400 CALL .0048652A
|
||||
* 00441857 8B4C24 5C MOV ECX,DWORD PTR SS:[ESP+0x5C]
|
||||
* 0044185B 5F POP EDI
|
||||
* 0044185C 5E POP ESI
|
||||
* 0044185D 5D POP EBP
|
||||
* 0044185E 64:890D 00000000 MOV DWORD PTR FS:[0],ECX
|
||||
* 00441865 5B POP EBX
|
||||
* 00441866 83C4 58 ADD ESP,0x58
|
||||
* 00441869 C2 1400 RETN 0x14
|
||||
* 0044186C 90 NOP
|
||||
* 0044186D 90 NOP
|
||||
* 0044186E 90 NOP
|
||||
* 0044186F 90 NOP
|
||||
*
|
||||
* Another sample game: 不条琸<EFBFBD>界の探偵令嬢
|
||||
*/
|
||||
bool InsertAbelHook()
|
||||
{
|
||||
// jichi: If this pattern failed again, try the following pattern instead:
|
||||
// 004413D3 894424 48 MOV DWORD PTR SS:[ESP+0x48],EAX
|
||||
// 004413D7 894424 4C MOV DWORD PTR SS:[ESP+0x4C],EAX
|
||||
// 004413DB 894424 58 MOV DWORD PTR SS:[ESP+0x58],EAX
|
||||
|
||||
const DWORD character[] = {0xc981d48a, 0xffffff00};
|
||||
if (DWORD j = SearchPattern(processStartAddress, processStopAddress - processStartAddress, character, sizeof(character)))
|
||||
{
|
||||
j += processStartAddress;
|
||||
for (DWORD i = j - 0x100; j > i; j--)
|
||||
if (*(WORD *)j == 0xff6a)
|
||||
{
|
||||
HookParam hp;
|
||||
hp.address = j;
|
||||
hp.offset = get_stack(1);
|
||||
hp.type = USING_STRING | NO_CONTEXT;
|
||||
return NewHook(hp, "Abel");
|
||||
}
|
||||
}
|
||||
ConsoleOutput("Abel: failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Abel::attach_function()
|
||||
{
|
||||
|
||||
return InsertAbelHook();
|
||||
}
|
55
cpp/LunaHook/LunaHook/engine32/Abel.h
Normal file
55
cpp/LunaHook/LunaHook/engine32/Abel.h
Normal file
@ -0,0 +1,55 @@
|
||||
|
||||
|
||||
class Abel : public ENGINE
|
||||
{
|
||||
public:
|
||||
Abel()
|
||||
{
|
||||
|
||||
check_by = CHECK_BY::CUSTOM;
|
||||
check_by_target = []()
|
||||
{
|
||||
// jichi 8/24/2013: Move into functions
|
||||
// Artikash 6/15/2018: Removed this detection for Abel Software games. IthGetFileInfo no longer works correctly
|
||||
// static BYTE static_file_info[0x1000];
|
||||
// if (IthGetFileInfo(L"*01", static_file_info))
|
||||
// if (*(DWORD*)static_file_info == 0) {
|
||||
// STATUS_INFO_LENGTH_MISMATCH;
|
||||
// static WCHAR static_search_name[MAX_PATH];
|
||||
// LPWSTR name=(LPWSTR)(static_file_info+0x5E);
|
||||
// int len = wcslen(name);
|
||||
// name[len-2] = L'.';
|
||||
// name[len-1] = L'e';
|
||||
// name[len] = L'x';
|
||||
// name[len+1] = L'e';
|
||||
// name[len+2] = 0;
|
||||
// if (Util::CheckFile(name)) {
|
||||
// sizeof(FILE_BOTH_DIR_INFORMATION);
|
||||
// name[len-2] = L'*';
|
||||
// name[len-1] = 0;
|
||||
// wcscpy(static_search_name,name);
|
||||
// IthGetFileInfo(static_search_name,static_file_info);
|
||||
// union {
|
||||
// FILE_BOTH_DIR_INFORMATION *both_info;
|
||||
// DWORD addr;
|
||||
// };
|
||||
// both_info = (FILE_BOTH_DIR_INFORMATION *)static_file_info;
|
||||
// //BYTE* ptr=static_file_info;
|
||||
// len=0;
|
||||
// while (both_info->NextEntryOffset) {
|
||||
// addr += both_info->NextEntryOffset;
|
||||
// len++;
|
||||
// }
|
||||
// if (len > 3) {
|
||||
// InsertAbelHook();
|
||||
// return true;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
return (Util::CheckFile(L"system") && Util::CheckFile(L"system.dat")) || Util::CheckFile(L"*01");
|
||||
};
|
||||
|
||||
is_engine_certain = false;
|
||||
};
|
||||
bool attach_function();
|
||||
};
|
244
cpp/LunaHook/LunaHook/engine32/AdobeAir.cpp
Normal file
244
cpp/LunaHook/LunaHook/engine32/AdobeAir.cpp
Normal file
@ -0,0 +1,244 @@
|
||||
#include "AdobeAir.h"
|
||||
|
||||
/**
|
||||
* jichi 4/15/2014: Insert Adobe AIR hook
|
||||
* Sample games:
|
||||
* 華アワセ 蛟編: /HW-C*0:D8@4D04B5:Adobe AIR.dll
|
||||
* 華アワセ 姫空木編: /HW-C*0:d8@4E69A7:Adobe AIR.dll
|
||||
*
|
||||
* Issue: The game will hang if the hook is injected before loading
|
||||
*
|
||||
* /HW-C*0:D8@4D04B5:ADOBE AIR.DLL
|
||||
* - addr: 5047477 = 0x4d04b5
|
||||
* -length_offset: 1
|
||||
* - module: 3506957663 = 0xd107ed5f
|
||||
* - off: 4294967280 = 0xfffffff0 = -0x10
|
||||
* - split: 216 = 0xd8
|
||||
* - type: 90 = 0x5a
|
||||
*
|
||||
* 0f8f0497 |. eb 69 jmp short adobe_ai.0f8f0502
|
||||
* 0f8f0499 |> 83c8 ff or eax,0xffffffff
|
||||
* 0f8f049c |. eb 67 jmp short adobe_ai.0f8f0505
|
||||
* 0f8f049e |> 8b7d 0c mov edi,dword ptr ss:[ebp+0xc]
|
||||
* 0f8f04a1 |. 85ff test edi,edi
|
||||
* 0f8f04a3 |. 7e 5d jle short adobe_ai.0f8f0502
|
||||
* 0f8f04a5 |. 8b55 08 mov edx,dword ptr ss:[ebp+0x8]
|
||||
* 0f8f04a8 |. b8 80000000 mov eax,0x80
|
||||
* 0f8f04ad |. be ff030000 mov esi,0x3ff
|
||||
* 0f8f04b2 |> 0fb70a /movzx ecx,word ptr ds:[edx]
|
||||
* 0f8f04b5 |. 8bd8 |mov ebx,eax ; jichi: hook here
|
||||
* 0f8f04b7 |. 4f |dec edi
|
||||
* 0f8f04b8 |. 66:3bcb |cmp cx,bx
|
||||
* 0f8f04bb |. 73 05 |jnb short adobe_ai.0f8f04c2
|
||||
* 0f8f04bd |. ff45 fc |inc dword ptr ss:[ebp-0x4]
|
||||
* 0f8f04c0 |. eb 3a |jmp short adobe_ai.0f8f04fc
|
||||
* 0f8f04c2 |> bb 00080000 |mov ebx,0x800
|
||||
* 0f8f04c7 |. 66:3bcb |cmp cx,bx
|
||||
* 0f8f04ca |. 73 06 |jnb short adobe_ai.0f8f04d2
|
||||
* 0f8f04cc |. 8345 fc 02 |add dword ptr ss:[ebp-0x4],0x2
|
||||
* 0f8f04d0 |. eb 2a |jmp short adobe_ai.0f8f04fc
|
||||
* 0f8f04d2 |> 81c1 00280000 |add ecx,0x2800
|
||||
* 0f8f04d8 |. 8bde |mov ebx,esi
|
||||
* 0f8f04da |. 66:3bcb |cmp cx,bx
|
||||
* 0f8f04dd |. 77 19 |ja short adobe_ai.0f8f04f8
|
||||
* 0f8f04df |. 4f |dec edi
|
||||
* 0f8f04e0 |.^78 b7 |js short adobe_ai.0f8f0499
|
||||
* 0f8f04e2 |. 42 |inc edx
|
||||
* 0f8f04e3 |. 42 |inc edx
|
||||
* 0f8f04e4 |. 0fb70a |movzx ecx,word ptr ds:[edx]
|
||||
* 0f8f04e7 |. 81c1 00240000 |add ecx,0x2400
|
||||
* 0f8f04ed |. 66:3bcb |cmp cx,bx
|
||||
* 0f8f04f0 |. 77 06 |ja short adobe_ai.0f8f04f8
|
||||
* 0f8f04f2 |. 8345 fc 04 |add dword ptr ss:[ebp-0x4],0x4
|
||||
* 0f8f04f6 |. eb 04 |jmp short adobe_ai.0f8f04fc
|
||||
* 0f8f04f8 |> 8345 fc 03 |add dword ptr ss:[ebp-0x4],0x3
|
||||
* 0f8f04fc |> 42 |inc edx
|
||||
* 0f8f04fd |. 42 |inc edx
|
||||
* 0f8f04fe |. 85ff |test edi,edi
|
||||
* 0f8f0500 |.^7f b0 \jg short adobe_ai.0f8f04b2
|
||||
* 0f8f0502 |> 8b45 fc mov eax,dword ptr ss:[ebp-0x4]
|
||||
* 0f8f0505 |> 5f pop edi
|
||||
* 0f8f0506 |. 5e pop esi
|
||||
* 0f8f0507 |. 5b pop ebx
|
||||
* 0f8f0508 |. c9 leave
|
||||
* 0f8f0509 \. c3 retn
|
||||
*/
|
||||
bool InsertAdobeAirHook()
|
||||
{
|
||||
DWORD base = (DWORD)GetModuleHandleW(L"Adobe AIR.dll");
|
||||
if (!base)
|
||||
{
|
||||
ConsoleOutput("Adobe AIR: module not found");
|
||||
return false;
|
||||
}
|
||||
|
||||
// ULONG processStartAddress, processStopAddress;
|
||||
// if (!NtInspect::getModuleMemoryRange(L"Adobe AIR.dll", &startAddress, &stopAddress)) {
|
||||
// ConsoleOutput("Adobe AIR: module not found");
|
||||
// return false;
|
||||
// }
|
||||
|
||||
const BYTE bytes[] = {
|
||||
0x0f, 0xb7, 0x0a, // 0f8f04b2 |> 0fb70a /movzx ecx,word ptr ds:[edx]
|
||||
0x8b, 0xd8, // 0f8f04b5 |. 8bd8 |mov ebx,eax ; jichi: hook here
|
||||
0x4f, // 0f8f04b7 |. 4f |dec edi
|
||||
0x66, 0x3b, 0xcb, // 0f8f04b8 |. 66:3bcb |cmp cx,bx
|
||||
0x73, 0x05, // 0f8f04bb |. 73 05 |jnb short adobe_ai.0f8f04c2
|
||||
0xff, 0x45, 0xfc, // 0f8f04bd |. ff45 fc |inc dword ptr ss:[ebp-0x4]
|
||||
0xeb, 0x3a // 0f8f04c0 |. eb 3a |jmp short adobe_ai.0f8f04fc
|
||||
};
|
||||
enum
|
||||
{
|
||||
addr_offset = 0x0f8f04b5 - 0x0f8f04b2
|
||||
}; // = 3. 0 also works.
|
||||
enum
|
||||
{
|
||||
range = 0x600000
|
||||
}; // larger than relative addresses
|
||||
ULONG addr = MemDbg::findBytes(bytes, sizeof(bytes), base, base + range);
|
||||
// GROWL(reladdr);
|
||||
if (!addr)
|
||||
{
|
||||
ConsoleOutput("Adobe AIR: pattern not found");
|
||||
return false;
|
||||
}
|
||||
|
||||
HookParam hp;
|
||||
hp.address = addr + addr_offset;
|
||||
// hp.module = module;
|
||||
hp.offset = get_reg(regs::edx);
|
||||
hp.split = 0xd8;
|
||||
// hp.type = USING_SPLIT|MODULE_OFFSET|CODEC_UTF16|DATA_INDIRECT; // 0x5a;
|
||||
hp.type = USING_SPLIT | CODEC_UTF16 | DATA_INDIRECT;
|
||||
|
||||
ConsoleOutput("INSERT Adobe AIR");
|
||||
|
||||
return NewHook(hp, "Adobe AIR");
|
||||
}
|
||||
|
||||
bool AdobeAIRhook2()
|
||||
{
|
||||
auto hmodule = (DWORD)GetModuleHandle(L"Adobe AIR.dll");
|
||||
if (hmodule == 0)
|
||||
return false;
|
||||
enum
|
||||
{
|
||||
range = 0x600000
|
||||
}; // larger than relative addresses
|
||||
|
||||
auto [minAddress, maxAddress] = std::make_pair(hmodule, hmodule + range);
|
||||
const BYTE bs[] = {
|
||||
// トリック・オア・アリス
|
||||
0x66, 0x83, 0xF8, 0x19,
|
||||
0x77, XX,
|
||||
0x81, 0xC7, 0xE0, 0xFF, 0x00, 0x00};
|
||||
auto addr = MemDbg::findBytes(bs, sizeof(bs), minAddress, maxAddress);
|
||||
ConsoleOutput("%p", addr);
|
||||
if (addr == 0)
|
||||
return false;
|
||||
const BYTE start[] = {0xC2, 0x10, 0x00}; // retn 10h,+3
|
||||
addr = reverseFindBytes(start, 3, addr - 0x1000, addr);
|
||||
ConsoleOutput("%p", addr);
|
||||
if (addr == 0)
|
||||
return false;
|
||||
HookParam hp;
|
||||
hp.address = addr + 3;
|
||||
hp.offset = get_stack(1);
|
||||
hp.type = USING_STRING | CODEC_UTF16;
|
||||
|
||||
return NewHook(hp, "AdobeAIR");
|
||||
}
|
||||
|
||||
/**
|
||||
* Artikash 12/8/2018: Update AIRNovel hook for version 31.0.0.96
|
||||
* Sample game: https://vndb.org/v22252: /HQ4*8:4*4@12FF9A:Adobe AIR.dll
|
||||
* This function is called from Adobe AIR.FREGetObjectAsUTF8+5A
|
||||
* First function parameter points to a struct containing a pointer to the text along with info about the type of text
|
||||
* wchar_t* at offset 8
|
||||
*/
|
||||
bool InsertAIRNovelHook()
|
||||
{
|
||||
wcscpy_s(spDefault.boundaryModule, L"Adobe AIR.dll");
|
||||
if (DWORD FREGetObjectAsUTF8 = (DWORD)GetProcAddress(GetModuleHandleW(L"Adobe AIR.dll"), "FREGetObjectAsUTF8"))
|
||||
{
|
||||
DWORD func = FREGetObjectAsUTF8 + 0x5a + 5 + *(int *)(FREGetObjectAsUTF8 + 0x5b);
|
||||
HookParam hp;
|
||||
hp.address = func;
|
||||
hp.type = CODEC_UTF16 | USING_STRING /*|USING_SPLIT|SPLIT_INDIRECT*/ | DATA_INDIRECT; // Artikash 12/14/2018: doesn't seem to be a good split anymore
|
||||
hp.offset = get_stack(1);
|
||||
hp.split = get_stack(1);
|
||||
hp.index = 0x8;
|
||||
hp.split_index = 0x4;
|
||||
// hp.filter_fun = [](void* str, DWORD* len, HookParam* hp, BYTE index) // removes some of the garbage threads
|
||||
//{
|
||||
// return *len < 4 &&
|
||||
// *(char*)str != '[' &&
|
||||
// *(char*)str != ';' &&
|
||||
// *(char*)str != '&' &&
|
||||
// *(char*)str != '*' &&
|
||||
// *(char*)str != '\n' &&
|
||||
// *(char*)str != '\t' &&
|
||||
// memcmp((char*)str, "app:/", 5);
|
||||
// };
|
||||
|
||||
ConsoleOutput("INSERT AIRNovel");
|
||||
|
||||
return NewHook(hp, "AIRNovel");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
bool adobelair3()
|
||||
{
|
||||
// 虚構英雄ジンガイアVol3
|
||||
DWORD base = (DWORD)GetModuleHandleW(L"Adobe AIR.dll");
|
||||
if (!base)
|
||||
return false;
|
||||
BYTE sig[] = {
|
||||
0x8b, 0x85, XX4,
|
||||
0x8B, 0x4E, 0x04,
|
||||
0x85, 0xC9,
|
||||
0x0F, 0x85, XX4,
|
||||
0xFF, 0x70, 0x14,
|
||||
0x8B, 0x78, 0x0c,
|
||||
0x8b, 0xcf,
|
||||
0x68, 0xb8, 0x00, 0x00, 0x00,
|
||||
0xff, 0x15, XX4,
|
||||
0xff, 0xd7,
|
||||
0x8b, 0xc8,
|
||||
0x83, 0xc4, 0x08,
|
||||
0x85, 0xc9,
|
||||
0x0f, 0x85, XX4};
|
||||
enum
|
||||
{
|
||||
range = 0x600000
|
||||
}; // larger than relative addresses
|
||||
auto [minAddress, maxAddress] = std::make_pair(base, base + range);
|
||||
auto addr = MemDbg::findBytes(sig, sizeof(sig), minAddress, maxAddress);
|
||||
HookParam hp;
|
||||
hp.address = addr;
|
||||
hp.type = CODEC_UTF8 | USING_STRING | NO_CONTEXT;
|
||||
hp.offset = get_stack(1);
|
||||
hp.filter_fun = [](void *data, size_t *len, HookParam *hp)
|
||||
{
|
||||
// 若当前还有5个字符,则这个句子会显示5次,然后substr(1,len-1),直到结束,总共显示5+4+3+2+1次
|
||||
auto ws = StringToWideString(std::string((char *)data, *len));
|
||||
static int leng = 0;
|
||||
if (ws.length() <= leng)
|
||||
{
|
||||
leng = ws.length();
|
||||
return false;
|
||||
}
|
||||
leng = ws.length();
|
||||
return true;
|
||||
};
|
||||
return NewHook(hp, "AIRNovel");
|
||||
}
|
||||
bool AdobeAir::attach_function()
|
||||
{
|
||||
|
||||
bool b1 = InsertAdobeAirHook();
|
||||
b1 |= AdobeAIRhook2();
|
||||
b1 |= adobelair3();
|
||||
b1 = b1 || InsertAIRNovelHook(); // 乱码太多了这个
|
||||
return b1;
|
||||
}
|
16
cpp/LunaHook/LunaHook/engine32/AdobeAir.h
Normal file
16
cpp/LunaHook/LunaHook/engine32/AdobeAir.h
Normal file
@ -0,0 +1,16 @@
|
||||
|
||||
|
||||
class AdobeAir : public ENGINE
|
||||
{
|
||||
public:
|
||||
AdobeAir()
|
||||
{
|
||||
|
||||
check_by = CHECK_BY::CUSTOM;
|
||||
check_by_target = []()
|
||||
{
|
||||
return Util::CheckFile(L"Adobe AIR\\Versions\\1.0\\Adobe AIR.dll") || GetModuleHandle(L"Adobe AIR.dll") || Util::CheckFile(L"*.swf");
|
||||
};
|
||||
};
|
||||
bool attach_function();
|
||||
};
|
288
cpp/LunaHook/LunaHook/engine32/AdobeFlash10.cpp
Normal file
288
cpp/LunaHook/LunaHook/engine32/AdobeFlash10.cpp
Normal file
@ -0,0 +1,288 @@
|
||||
#include "AdobeFlash10.h"
|
||||
|
||||
/** jichi 10/31/2014 Adobe Flash Player v10
|
||||
*
|
||||
* Sample game: [141031] [ヂ<EFBFBD>ンクルベル] 輪舞曲Duo
|
||||
*
|
||||
* Debug method: Hex utf16 text, then insert hw breakpoints
|
||||
* 21:51 3110% hexstr 『何よ utf16
|
||||
* 0e30554f8830
|
||||
*
|
||||
* There are also UTF-8 strings in the memory. I could not find a good place to hook
|
||||
* using hw breakpoints.
|
||||
*
|
||||
* There are lots of matches. One is selected. Then, the enclosing function is selected.
|
||||
* arg1 is the UNICODE text.
|
||||
*
|
||||
* Pattern:
|
||||
*
|
||||
* 0161293a 8bc6 mov eax,esi
|
||||
* 0161293c 5e pop esi
|
||||
* 0161293d c2 0800 retn 0x8
|
||||
*
|
||||
* Function starts
|
||||
* 01612940 8b4c24 0c mov ecx,dword ptr ss:[esp+0xc] ; jichi: hook here
|
||||
* 01612944 53 push ebx
|
||||
* 01612945 55 push ebp
|
||||
* 01612946 56 push esi
|
||||
* 01612947 57 push edi
|
||||
* 01612948 33ff xor edi,edi
|
||||
* 0161294a 85c9 test ecx,ecx
|
||||
* 0161294c 0f84 5f010000 je ron2.01612ab1
|
||||
* 01612952 397c24 18 cmp dword ptr ss:[esp+0x18],edi
|
||||
* 01612956 0f8e ba010000 jle ron2.01612b16
|
||||
* 0161295c 8b6c24 14 mov ebp,dword ptr ss:[esp+0x14]
|
||||
* 01612960 be 01000000 mov esi,0x1
|
||||
* 01612965 eb 09 jmp short ron2.01612970
|
||||
* 01612967 8da424 00000000 lea esp,dword ptr ss:[esp]
|
||||
* 0161296e 8bff mov edi,edi
|
||||
* 01612970 0fb755 00 movzx edx,word ptr ss:[ebp]
|
||||
* 01612974 297424 18 sub dword ptr ss:[esp+0x18],esi
|
||||
* 01612978 b8 80000000 mov eax,0x80
|
||||
* 0161297d 66:3bd0 cmp dx,ax
|
||||
* 01612980 73 15 jnb short ron2.01612997
|
||||
* 01612982 297424 20 sub dword ptr ss:[esp+0x20],esi
|
||||
* 01612986 0f88 1d010000 js ron2.01612aa9
|
||||
* 0161298c 8811 mov byte ptr ds:[ecx],dl
|
||||
* 0161298e 03ce add ecx,esi
|
||||
* 01612990 03fe add edi,esi
|
||||
* 01612992 e9 fd000000 jmp ron2.01612a94
|
||||
* 01612997 b8 00080000 mov eax,0x800
|
||||
* 0161299c 66:3bd0 cmp dx,ax
|
||||
* 0161299f 73 2a jnb short ron2.016129cb
|
||||
* 016129a1 836c24 20 02 sub dword ptr ss:[esp+0x20],0x2
|
||||
* 016129a6 0f88 fd000000 js ron2.01612aa9
|
||||
* 016129ac 8bc2 mov eax,edx
|
||||
* 016129ae c1e8 06 shr eax,0x6
|
||||
* 016129b1 24 1f and al,0x1f
|
||||
* 016129b3 0c c0 or al,0xc0
|
||||
* 016129b5 8801 mov byte ptr ds:[ecx],al
|
||||
* 016129b7 80e2 3f and dl,0x3f
|
||||
* 016129ba 03ce add ecx,esi
|
||||
* 016129bc 80ca 80 or dl,0x80
|
||||
* 016129bf 8811 mov byte ptr ds:[ecx],dl
|
||||
* 016129c1 03ce add ecx,esi
|
||||
* 016129c3 83c7 02 add edi,0x2
|
||||
* 016129c6 e9 c9000000 jmp ron2.01612a94
|
||||
* 016129cb 8d82 00280000 lea eax,dword ptr ds:[edx+0x2800]
|
||||
* 016129d1 bb ff030000 mov ebx,0x3ff
|
||||
* 016129d6 66:3bc3 cmp ax,bx
|
||||
* 016129d9 77 7b ja short ron2.01612a56
|
||||
* 016129db 297424 18 sub dword ptr ss:[esp+0x18],esi
|
||||
* 016129df 0f88 c4000000 js ron2.01612aa9
|
||||
* 016129e5 0fb775 02 movzx esi,word ptr ss:[ebp+0x2]
|
||||
* 016129e9 83c5 02 add ebp,0x2
|
||||
* 016129ec 8d86 00240000 lea eax,dword ptr ds:[esi+0x2400]
|
||||
* 016129f2 66:3bc3 cmp ax,bx
|
||||
* 016129f5 77 58 ja short ron2.01612a4f
|
||||
* 016129f7 0fb7d2 movzx edx,dx
|
||||
* 016129fa 81ea f7d70000 sub edx,0xd7f7
|
||||
* 01612a00 0fb7c6 movzx eax,si
|
||||
* 01612a03 c1e2 0a shl edx,0xa
|
||||
* 01612a06 03d0 add edx,eax
|
||||
* 01612a08 836c24 20 04 sub dword ptr ss:[esp+0x20],0x4
|
||||
* 01612a0d 0f88 96000000 js ron2.01612aa9
|
||||
* 01612a13 8bc2 mov eax,edx
|
||||
* 01612a15 c1e8 12 shr eax,0x12
|
||||
* 01612a18 24 07 and al,0x7
|
||||
* 01612a1a 0c f0 or al,0xf0
|
||||
* 01612a1c 8801 mov byte ptr ds:[ecx],al
|
||||
* 01612a1e 8bc2 mov eax,edx
|
||||
* 01612a20 c1e8 0c shr eax,0xc
|
||||
* 01612a23 24 3f and al,0x3f
|
||||
* 01612a25 be 01000000 mov esi,0x1
|
||||
* 01612a2a 0c 80 or al,0x80
|
||||
* 01612a2c 880431 mov byte ptr ds:[ecx+esi],al
|
||||
* 01612a2f 03ce add ecx,esi
|
||||
* 01612a31 8bc2 mov eax,edx
|
||||
* 01612a33 c1e8 06 shr eax,0x6
|
||||
* 01612a36 03ce add ecx,esi
|
||||
* 01612a38 24 3f and al,0x3f
|
||||
* 01612a3a 0c 80 or al,0x80
|
||||
* 01612a3c 8801 mov byte ptr ds:[ecx],al
|
||||
* 01612a3e 80e2 3f and dl,0x3f
|
||||
* 01612a41 03ce add ecx,esi
|
||||
* 01612a43 80ca 80 or dl,0x80
|
||||
* 01612a46 8811 mov byte ptr ds:[ecx],dl
|
||||
* 01612a48 03ce add ecx,esi
|
||||
* 01612a4a 83c7 04 add edi,0x4
|
||||
* 01612a4d eb 45 jmp short ron2.01612a94
|
||||
* 01612a4f be 01000000 mov esi,0x1
|
||||
* 01612a54 eb 0b jmp short ron2.01612a61
|
||||
* 01612a56 8d82 00240000 lea eax,dword ptr ds:[edx+0x2400]
|
||||
* 01612a5c 66:3bc3 cmp ax,bx
|
||||
* 01612a5f 77 05 ja short ron2.01612a66
|
||||
* 01612a61 ba fdff0000 mov edx,0xfffd
|
||||
* 01612a66 836c24 20 03 sub dword ptr ss:[esp+0x20],0x3
|
||||
* 01612a6b 78 3c js short ron2.01612aa9
|
||||
* 01612a6d 8bc2 mov eax,edx
|
||||
* 01612a6f c1e8 0c shr eax,0xc
|
||||
* 01612a72 24 0f and al,0xf
|
||||
* 01612a74 0c e0 or al,0xe0
|
||||
* 01612a76 8801 mov byte ptr ds:[ecx],al
|
||||
* 01612a78 8bc2 mov eax,edx
|
||||
* 01612a7a c1e8 06 shr eax,0x6
|
||||
* 01612a7d 03ce add ecx,esi
|
||||
* 01612a7f 24 3f and al,0x3f
|
||||
* 01612a81 0c 80 or al,0x80
|
||||
* 01612a83 8801 mov byte ptr ds:[ecx],al
|
||||
* 01612a85 80e2 3f and dl,0x3f
|
||||
* 01612a88 03ce add ecx,esi
|
||||
* 01612a8a 80ca 80 or dl,0x80
|
||||
* 01612a8d 8811 mov byte ptr ds:[ecx],dl
|
||||
* 01612a8f 03ce add ecx,esi
|
||||
* 01612a91 83c7 03 add edi,0x3
|
||||
* 01612a94 83c5 02 add ebp,0x2
|
||||
* 01612a97 837c24 18 00 cmp dword ptr ss:[esp+0x18],0x0
|
||||
* 01612a9c ^0f8f cefeffff jg ron2.01612970
|
||||
* 01612aa2 8bc7 mov eax,edi
|
||||
* 01612aa4 5f pop edi
|
||||
* 01612aa5 5e pop esi
|
||||
* 01612aa6 5d pop ebp
|
||||
* 01612aa7 5b pop ebx
|
||||
* 01612aa8 c3 retn
|
||||
* 01612aa9 5f pop edi
|
||||
* 01612aaa 5e pop esi
|
||||
* 01612aab 5d pop ebp
|
||||
* 01612aac 83c8 ff or eax,0xffffffff
|
||||
* 01612aaf 5b pop ebx
|
||||
* 01612ab0 c3 retn
|
||||
* 01612ab1 8b4424 18 mov eax,dword ptr ss:[esp+0x18]
|
||||
* 01612ab5 85c0 test eax,eax
|
||||
* 01612ab7 7e 5d jle short ron2.01612b16
|
||||
* 01612ab9 8b5424 14 mov edx,dword ptr ss:[esp+0x14]
|
||||
* 01612abd 8d49 00 lea ecx,dword ptr ds:[ecx]
|
||||
* 01612ac0 0fb70a movzx ecx,word ptr ds:[edx] ; jichi: this is where the text is accessed
|
||||
* 01612ac3 be 80000000 mov esi,0x80
|
||||
* 01612ac8 48 dec eax
|
||||
* 01612ac9 66:3bce cmp cx,si
|
||||
* 01612acc 73 03 jnb short ron2.01612ad1
|
||||
* 01612ace 47 inc edi
|
||||
* 01612acf eb 3e jmp short ron2.01612b0f
|
||||
* 01612ad1 be 00080000 mov esi,0x800
|
||||
* 01612ad6 66:3bce cmp cx,si
|
||||
* 01612ad9 73 05 jnb short ron2.01612ae0
|
||||
* 01612adb 83c7 02 add edi,0x2
|
||||
* 01612ade eb 2f jmp short ron2.01612b0f
|
||||
* 01612ae0 81c1 00280000 add ecx,0x2800
|
||||
* 01612ae6 be ff030000 mov esi,0x3ff
|
||||
* 01612aeb 66:3bce cmp cx,si
|
||||
* 01612aee 77 1c ja short ron2.01612b0c
|
||||
* 01612af0 83e8 01 sub eax,0x1
|
||||
* 01612af3 ^78 b4 js short ron2.01612aa9
|
||||
* 01612af5 0fb74a 02 movzx ecx,word ptr ds:[edx+0x2]
|
||||
* 01612af9 83c2 02 add edx,0x2
|
||||
* 01612afc 81c1 00240000 add ecx,0x2400
|
||||
* 01612b02 66:3bce cmp cx,si
|
||||
* 01612b05 77 05 ja short ron2.01612b0c
|
||||
* 01612b07 83c7 04 add edi,0x4
|
||||
* 01612b0a eb 03 jmp short ron2.01612b0f
|
||||
* 01612b0c 83c7 03 add edi,0x3
|
||||
* 01612b0f 83c2 02 add edx,0x2
|
||||
* 01612b12 85c0 test eax,eax
|
||||
* 01612b14 ^7f aa jg short ron2.01612ac0
|
||||
* 01612b16 8bc7 mov eax,edi
|
||||
* 01612b18 5f pop edi
|
||||
* 01612b19 5e pop esi
|
||||
* 01612b1a 5d pop ebp
|
||||
* 01612b1b 5b pop ebx
|
||||
* 01612b1c c3 retn
|
||||
* 01612b1d cc int3
|
||||
* 01612b1e cc int3
|
||||
* 01612b1f cc int3
|
||||
*
|
||||
* Runtime stack:
|
||||
* 0019e974 0161640e return to Ron2.0161640e from Ron2.01612940
|
||||
* 0019e978 1216c180 UNICODE "Dat/Chr/HAL_061.swf"
|
||||
* 0019e97c 00000013
|
||||
* 0019e980 12522838
|
||||
* 0019e984 00000013
|
||||
* 0019e988 0210da80
|
||||
* 0019e98c 0019ecb0
|
||||
* 0019e990 0019e9e0
|
||||
* 0019e994 0019ea24
|
||||
* 0019e998 0019e9cc
|
||||
*
|
||||
* Runtime registers:
|
||||
* EAX 12522838
|
||||
* ECX 1216C180 UNICODE "Dat/Chr/HAL_061.swf"
|
||||
* EDX 0C5E9898
|
||||
* EBX 12532838
|
||||
* ESP 0019E974
|
||||
* EBP 00000013
|
||||
* ESI 00000013
|
||||
* EDI 0019E9CC
|
||||
* EIP 01612940 Ron2.01612940
|
||||
*/
|
||||
// Skip ASCII garbage such as: Dat/Chr/HAL_061.swf
|
||||
static bool AdobeFlashFilter(LPVOID data, size_t *size, HookParam *)
|
||||
{
|
||||
// TODO: Remove [0-9a-zA-Z./]{4,} as garbage
|
||||
LPCWSTR p = reinterpret_cast<LPCWSTR>(data);
|
||||
size_t len = *size / 2;
|
||||
for (size_t i = 0; i < len; i++)
|
||||
if (p[i] & 0xff00)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
bool InsertAdobeFlash10Hook()
|
||||
{
|
||||
const BYTE bytes[] = {
|
||||
0x8b, 0x4c, 0x24, 0x0c, // 01612940 8b4c24 0c mov ecx,dword ptr ss:[esp+0xc] ; jichi: hook here
|
||||
0x53, // 01612944 53 push ebx
|
||||
0x55, // 01612945 55 push ebp
|
||||
0x56, // 01612946 56 push esi
|
||||
0x57, // 01612947 57 push edi
|
||||
0x33, 0xff, // 01612948 33ff xor edi,edi
|
||||
0x85, 0xc9, // 0161294a 85c9 test ecx,ecx
|
||||
0x0f, 0x84 //, 5f010000 // 0161294c 0f84 5f010000 je ron2.01612ab1
|
||||
};
|
||||
ULONG addr = MemDbg::findBytes(bytes, sizeof(bytes), processStartAddress, processStopAddress);
|
||||
// addr = 0x01612940;
|
||||
// addr = 0x01612AC0;
|
||||
if (!addr)
|
||||
{
|
||||
ConsoleOutput("AdobeFlash10: pattern not found");
|
||||
return false;
|
||||
}
|
||||
|
||||
HookParam hp;
|
||||
hp.address = addr;
|
||||
hp.offset = get_stack(1);
|
||||
// hp.length_offset = 2 * 4; // arg2 might be the length
|
||||
hp.type = CODEC_UTF16 | USING_STRING;
|
||||
hp.filter_fun = AdobeFlashFilter;
|
||||
ConsoleOutput("INSERT Adobe Flash 10");
|
||||
|
||||
ConsoleOutput("AdobeFlash10: disable GDI hooks");
|
||||
|
||||
return NewHook(hp, "Adobe Flash 10");
|
||||
}
|
||||
namespace
|
||||
{
|
||||
bool __()
|
||||
{
|
||||
//[yosino] ANCIENT
|
||||
// https://ci-en.dlsite.com/creator/5059/
|
||||
const BYTE bytes[] = {
|
||||
0x55, 0x8b, 0xec,
|
||||
0x51, 0x51, 0x8b, 0x45, 0x10,
|
||||
0x53, 0x8b, 0xd9, 0x89, 0x43, 0x08,
|
||||
0x8a, 0x45, 0x0c};
|
||||
ULONG addr = MemDbg::findBytes(bytes, sizeof(bytes), processStartAddress, processStopAddress);
|
||||
|
||||
if (!addr)
|
||||
return false;
|
||||
|
||||
HookParam hp;
|
||||
hp.address = addr;
|
||||
hp.offset = get_stack(4);
|
||||
hp.type = CODEC_UTF16 | USING_STRING;
|
||||
return NewHook(hp, "Adobe Flash 11");
|
||||
}
|
||||
}
|
||||
bool AdobeFlash10::attach_function()
|
||||
{
|
||||
|
||||
return InsertAdobeFlash10Hook() | __();
|
||||
}
|
13
cpp/LunaHook/LunaHook/engine32/AdobeFlash10.h
Normal file
13
cpp/LunaHook/LunaHook/engine32/AdobeFlash10.h
Normal file
@ -0,0 +1,13 @@
|
||||
|
||||
|
||||
class AdobeFlash10 : public ENGINE
|
||||
{
|
||||
public:
|
||||
AdobeFlash10()
|
||||
{
|
||||
|
||||
check_by = CHECK_BY::RESOURCE_STR;
|
||||
check_by_target = L"Adobe Flash Player 10";
|
||||
};
|
||||
bool attach_function();
|
||||
};
|
41
cpp/LunaHook/LunaHook/engine32/Ages3ResT.cpp
Normal file
41
cpp/LunaHook/LunaHook/engine32/Ages3ResT.cpp
Normal file
@ -0,0 +1,41 @@
|
||||
#include "Ages3ResT.h"
|
||||
|
||||
bool Ages3ResTHook()
|
||||
{
|
||||
const BYTE bytes[] = {
|
||||
0x8d, 0x4f, XX,
|
||||
0xff, 0x15, XX4,
|
||||
XX,
|
||||
0x8d, 0x8f, XX4,
|
||||
0xff, 0x15, XX4,
|
||||
0x8d, XX, XX4,
|
||||
XX,
|
||||
0x8d, 0x8f, XX4,
|
||||
0xff, 0x15, XX4,
|
||||
0x8b, XX,
|
||||
0xff, 0x15, XX4};
|
||||
|
||||
auto addrs = Util::SearchMemory(bytes, sizeof(bytes), PAGE_EXECUTE, processStartAddress, processStopAddress);
|
||||
bool succ = false;
|
||||
for (auto addr : addrs)
|
||||
{
|
||||
ConsoleOutput("Ages3ResT %p", addr);
|
||||
if (addr == 0)
|
||||
return false;
|
||||
addr = findfuncstart(addr);
|
||||
ConsoleOutput("Ages3ResT %p", addr);
|
||||
if (addr == 0)
|
||||
return false;
|
||||
HookParam hp;
|
||||
hp.address = addr;
|
||||
hp.offset = get_stack(3);
|
||||
hp.type = CODEC_UTF16 | USING_STRING;
|
||||
succ |= NewHook(hp, "Ages3ResT");
|
||||
}
|
||||
return succ;
|
||||
}
|
||||
|
||||
bool Ages3ResT::attach_function()
|
||||
{
|
||||
return Ages3ResTHook();
|
||||
}
|
13
cpp/LunaHook/LunaHook/engine32/Ages3ResT.h
Normal file
13
cpp/LunaHook/LunaHook/engine32/Ages3ResT.h
Normal file
@ -0,0 +1,13 @@
|
||||
|
||||
|
||||
class Ages3ResT : public ENGINE
|
||||
{
|
||||
public:
|
||||
Ages3ResT()
|
||||
{
|
||||
|
||||
check_by = CHECK_BY::FILE;
|
||||
check_by_target = L"Ages3ResT.dll";
|
||||
};
|
||||
bool attach_function();
|
||||
};
|
66
cpp/LunaHook/LunaHook/engine32/Aksys.cpp
Normal file
66
cpp/LunaHook/LunaHook/engine32/Aksys.cpp
Normal file
@ -0,0 +1,66 @@
|
||||
#include "Aksys.h"
|
||||
namespace
|
||||
{
|
||||
bool _Aksys()
|
||||
{
|
||||
// https://vndb.org/v25385
|
||||
// Spirit Hunter: NG
|
||||
/*
|
||||
int __usercall sub_4CDD70@<eax>(const char *a1@<edx>, int a2, _DWORD *a3, int *a4)
|
||||
{
|
||||
int result; // eax
|
||||
const char *v6; // [esp+Ch] [ebp-8h] BYREF
|
||||
|
||||
*a3 = strlen(a1);
|
||||
if ( *a1 && a2 )
|
||||
{
|
||||
v6 = a1;
|
||||
if ( (unsigned __int8)sub_4CAEB0(&v6) )
|
||||
{
|
||||
*a4 = sub_4CAF70(0, 0, 0x3A4u, (const unsigned __int16 *)a1, 0xFDE9u);
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
return -2141454316;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
result = 0;
|
||||
*a4 = 0;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
*/
|
||||
BYTE bytes[] = {
|
||||
0x68, 0xe9, 0xfd, 0, 0,
|
||||
0x56,
|
||||
0x68, 0xa4, 0x03, 0, 0,
|
||||
0x33, XX,
|
||||
0x33, XX,
|
||||
0xe8};
|
||||
auto addr = MemDbg::findBytes(bytes, sizeof(bytes), processStartAddress, processStopAddress);
|
||||
if (!addr)
|
||||
return false;
|
||||
addr = findfuncstart(addr);
|
||||
if (!addr)
|
||||
return false;
|
||||
HookParam hp;
|
||||
hp.address = addr;
|
||||
hp.offset = get_reg(regs::edx);
|
||||
hp.split = get_reg(regs::edx);
|
||||
hp.type = USING_STRING | USING_SPLIT;
|
||||
hp.filter_fun = [](LPVOID data, size_t *size, HookParam *)
|
||||
{
|
||||
StringFilter((char *)data, size, "@1r", 3);
|
||||
StringFilter((char *)data, size, "@-1r", 4);
|
||||
return (StringToWideString(std::string((char *)data, *size), 932).has_value());
|
||||
};
|
||||
return NewHook(hp, "Aksys");
|
||||
}
|
||||
}
|
||||
bool Aksys::attach_function()
|
||||
{
|
||||
return _Aksys();
|
||||
}
|
14
cpp/LunaHook/LunaHook/engine32/Aksys.h
Normal file
14
cpp/LunaHook/LunaHook/engine32/Aksys.h
Normal file
@ -0,0 +1,14 @@
|
||||
|
||||
|
||||
class Aksys : public ENGINE
|
||||
{
|
||||
public:
|
||||
Aksys()
|
||||
{
|
||||
|
||||
check_by = CHECK_BY::FILE;
|
||||
check_by_target = L"System.bra";
|
||||
is_engine_certain = false;
|
||||
};
|
||||
bool attach_function();
|
||||
};
|
74
cpp/LunaHook/LunaHook/engine32/AksysGames.cpp
Normal file
74
cpp/LunaHook/LunaHook/engine32/AksysGames.cpp
Normal file
@ -0,0 +1,74 @@
|
||||
#include "AksysGames.h"
|
||||
|
||||
bool AksysGames::attach_function()
|
||||
{
|
||||
|
||||
const BYTE bytes[] = {
|
||||
/*
|
||||
v8 = *v2;
|
||||
if ( *v2 == (char)0x80 )
|
||||
{
|
||||
++v2;
|
||||
++v5;
|
||||
goto LABEL_26;
|
||||
}
|
||||
v9 = 0;
|
||||
v17 = v7;
|
||||
v15 = v2;
|
||||
v10 = v6;
|
||||
if ( (unsigned __int8)v8 >= 0x81u && (unsigned __int8)v8 <= 0x9Fu
|
||||
|| (unsigned __int8)v8 >= 0xE0u && (unsigned __int8)v8 <= 0xFCu )
|
||||
{
|
||||
*/
|
||||
/*
|
||||
.text:004BCB70 mov cl, [eax]
|
||||
.text:004BCB72 cmp cl, 80h ; '€'
|
||||
.text:004BCB75 jz loc_4BCC76
|
||||
.text:004BCB7B xor esi, esi
|
||||
.text:004BCB7D mov [ebp+var_20C], edi
|
||||
.text:004BCB83 mov [ebp+var_214], eax
|
||||
.text:004BCB89 mov ebx, edx
|
||||
.text:004BCB8B test edi, edi
|
||||
.text:004BCB8D jz short loc_4BCBE3
|
||||
.text:004BCB8F cmp cl, 81h
|
||||
.text:004BCB92 jb short loc_4BCB99
|
||||
.text:004BCB94 cmp cl, 9Fh
|
||||
.text:004BCB97 jbe short loc_4BCBA3
|
||||
.text:004BCB99
|
||||
.text:004BCB99 loc_4BCB99: ; CODE XREF: sub_4BCB20+72↑j
|
||||
.text:004BCB99 cmp cl, 0E0h
|
||||
.text:004BCB9C jb short loc_4BCBC3
|
||||
.text:004BCB9E cmp cl, 0FCh
|
||||
.text:004BCBA1 ja short loc_4BCBC3
|
||||
*/
|
||||
0x8a, 0x08,
|
||||
0x80, 0xf9, 0x80,
|
||||
0x0f, 0x84, XX4,
|
||||
0x33, 0xf6,
|
||||
0x89, XX, XX4,
|
||||
0x89, XX, XX4,
|
||||
0x8b, 0xda,
|
||||
0x85, 0xff,
|
||||
0x74, XX,
|
||||
0x80, 0xf9, 0x81,
|
||||
0x72, XX,
|
||||
0x80, 0xf9, 0x9f,
|
||||
0x76, XX,
|
||||
0x80, 0xf9, 0xe0,
|
||||
0x72, XX,
|
||||
0x80, 0xf9, 0xfc,
|
||||
0x77, XX};
|
||||
|
||||
ULONG range = min(processStopAddress - processStartAddress, MAX_REL_ADDR);
|
||||
ULONG addr = MemDbg::findBytes(bytes, sizeof(bytes), processStartAddress, processStartAddress + range);
|
||||
if (!addr)
|
||||
return false;
|
||||
addr = findfuncstart(addr, 0x100, true);
|
||||
if (!addr)
|
||||
return false;
|
||||
HookParam hp;
|
||||
hp.address = addr;
|
||||
hp.offset = get_stack(1);
|
||||
hp.type = USING_STRING;
|
||||
return NewHook(hp, "AksysGames");
|
||||
}
|
42
cpp/LunaHook/LunaHook/engine32/AksysGames.h
Normal file
42
cpp/LunaHook/LunaHook/engine32/AksysGames.h
Normal file
@ -0,0 +1,42 @@
|
||||
// https://store.steampowered.com/app/828380/Death_Mark_Vol1/
|
||||
// Death Mark Vol.1 - 死印之迷雾
|
||||
/*
|
||||
FILEVERSION 1,0,0,0
|
||||
PRODUCTVERSION 1,0,0,0
|
||||
FILEFLAGSMASK 0x3F
|
||||
FILEFLAGS 0x0
|
||||
FILEOS VOS_NT_WINDOWS32
|
||||
FILETYPE VFT_APP
|
||||
FILESUBTYPE 0x0
|
||||
{
|
||||
BLOCK "StringFileInfo"
|
||||
{
|
||||
BLOCK "041104b0"
|
||||
{
|
||||
VALUE "FileVersion", "1.0.0.0"
|
||||
VALUE "InternalName", "Death Mark.exe"
|
||||
VALUE "LegalCopyright", "©EXPERIENCE. Licensed to and published by Aksys Games."
|
||||
VALUE "OriginalFilename", "Death Mark.exe"
|
||||
VALUE "ProductName", "Death Mark"
|
||||
VALUE "ProductVersion", "1.0.0.0"
|
||||
}
|
||||
}
|
||||
BLOCK "VarFileInfo"
|
||||
{
|
||||
VALUE "Translation", 0x411, 1200
|
||||
}
|
||||
}
|
||||
|
||||
*/
|
||||
class AksysGames : public ENGINE
|
||||
{
|
||||
public:
|
||||
AksysGames()
|
||||
{
|
||||
|
||||
check_by = CHECK_BY::RESOURCE_STR;
|
||||
check_by_target = L"Aksys Games";
|
||||
is_engine_certain = false;
|
||||
};
|
||||
bool attach_function();
|
||||
};
|
108
cpp/LunaHook/LunaHook/engine32/Alice.cpp
Normal file
108
cpp/LunaHook/LunaHook/engine32/Alice.cpp
Normal file
@ -0,0 +1,108 @@
|
||||
#include "Alice.h"
|
||||
|
||||
/********************************************************************************************
|
||||
System40 hook:
|
||||
System40 is a game engine developed by Alicesoft.
|
||||
Afaik, there are 2 very different types of System40. Each requires a particular hook.
|
||||
|
||||
Pattern 1: Either SACTDX.dll or SACT2.dll exports SP_TextDraw.
|
||||
The first relative call in this function draw text to some surface.
|
||||
Text pointer is return by last absolute indirect call before that.
|
||||
Split parameter is a little tricky. The first register pushed onto stack at the begining
|
||||
usually is used as font size later. According to instruction opcode map, push
|
||||
eax -- 50, ecx -- 51, edx -- 52, ebx --53, esp -- 54, ebp -- 55, esi -- 56, edi -- 57
|
||||
Split parameter value:
|
||||
eax - -8, ecx - -C, edx - -10, ebx - -14, esp - -18, ebp - -1C, esi - -20, edi - -24
|
||||
Just extract the low 4 bit and shift left 2 bit, then minus by -8,
|
||||
will give us the split parameter. e.g. push ebx 53->3 *4->C, -8-C=-14.
|
||||
Sometimes if split function is enabled, ITH will split text spoke by different
|
||||
character into different thread. Just open hook dialog and uncheck split parameter.
|
||||
Then click modify hook.
|
||||
|
||||
Pattern 2: *engine.dll exports SP_SetTextSprite.
|
||||
At the entry point, EAX should be a pointer to some structure, character at +0x8.
|
||||
Before calling this function, the caller put EAX onto stack, we can also find this
|
||||
value on stack. But seems parameter order varies from game release. If a future
|
||||
game breaks the EAX rule then we need to disassemble the caller code to determine
|
||||
data offset dynamically.
|
||||
********************************************************************************************/
|
||||
|
||||
static bool InsertAliceHook1(DWORD addr)
|
||||
{
|
||||
if (!addr)
|
||||
{
|
||||
ConsoleOutput("AliceHook1: failed");
|
||||
return false;
|
||||
}
|
||||
for (DWORD i = addr, s = addr; i < s + 0x100; i++)
|
||||
if (*(BYTE *)i == 0xe8)
|
||||
{ // Find the first relative call.
|
||||
DWORD j = i + 5 + *(DWORD *)(i + 1);
|
||||
while (true)
|
||||
{ // Find the first register push onto stack.
|
||||
DWORD c = ::disasm((BYTE *)s);
|
||||
if (c == 1)
|
||||
break;
|
||||
s += c;
|
||||
}
|
||||
DWORD c = *(BYTE *)s;
|
||||
HookParam hp;
|
||||
hp.address = j;
|
||||
hp.offset = get_reg(regs::eax);
|
||||
hp.split = -8 - ((c & 0xf) << 2);
|
||||
hp.type = USING_STRING | USING_SPLIT;
|
||||
// if (s>j) hp.type^=USING_SPLIT;
|
||||
ConsoleOutput("INSERT AliceHook1");
|
||||
|
||||
// RegisterEngineType(ENGINE_SYS40);
|
||||
return NewHook(hp, "System40");
|
||||
}
|
||||
ConsoleOutput("AliceHook1: failed");
|
||||
return false;
|
||||
}
|
||||
static bool InsertAliceHook2(DWORD addr)
|
||||
{
|
||||
if (!addr)
|
||||
{
|
||||
ConsoleOutput("AliceHook2: failed");
|
||||
return false;
|
||||
}
|
||||
HookParam hp;
|
||||
hp.address = addr;
|
||||
hp.offset = get_reg(regs::eax);
|
||||
hp.index = 0x8;
|
||||
hp.type = DATA_INDIRECT;
|
||||
ConsoleOutput("INSERT AliceHook2");
|
||||
return NewHook(hp, "System40");
|
||||
// RegisterEngineType(ENGINE_SYS40);
|
||||
}
|
||||
|
||||
// jichi 8/23/2013 Move here from engine.cc
|
||||
// Do not work for the latest Alice games
|
||||
// jichi 5/13/2015: Looking for function entries in StoatSpriteEngine.dll
|
||||
bool InsertAliceHook()
|
||||
{
|
||||
bool ok = false;
|
||||
if (auto addr = Util::FindFunction("SP_TextDraw"))
|
||||
{
|
||||
|
||||
ok |= InsertAliceHook1(addr);
|
||||
}
|
||||
// if (GetFunctionAddr("SP_SetTextSprite", &addr, &low, &high, 0) && addr) {
|
||||
// InsertAliceHook2(addr);
|
||||
// return true;
|
||||
//}
|
||||
if (auto addr = Util::FindFunction("SP_SetTextSprite"))
|
||||
{ // Artikash 6/27/2018 not sure if this works
|
||||
|
||||
ok |= InsertAliceHook2(addr);
|
||||
}
|
||||
// ConsoleOutput("AliceHook: failed");
|
||||
return ok;
|
||||
}
|
||||
|
||||
bool Alice::attach_function()
|
||||
{
|
||||
|
||||
return InsertAliceHook();
|
||||
}
|
12
cpp/LunaHook/LunaHook/engine32/Alice.h
Normal file
12
cpp/LunaHook/LunaHook/engine32/Alice.h
Normal file
@ -0,0 +1,12 @@
|
||||
|
||||
|
||||
class Alice : public ENGINE
|
||||
{
|
||||
public:
|
||||
Alice()
|
||||
{
|
||||
|
||||
check_by = CHECK_BY::ALL_TRUE;
|
||||
};
|
||||
bool attach_function();
|
||||
};
|
103
cpp/LunaHook/LunaHook/engine32/Anex86.cpp
Normal file
103
cpp/LunaHook/LunaHook/engine32/Anex86.cpp
Normal file
@ -0,0 +1,103 @@
|
||||
#include "Anex86.h"
|
||||
|
||||
namespace
|
||||
{ // unnamed, for Anex86
|
||||
BYTE JIS_tableH[0x80] = {
|
||||
0x00, 0x81, 0x81, 0x82, 0x82, 0x83, 0x83, 0x84,
|
||||
0x84, 0x85, 0x85, 0x86, 0x86, 0x87, 0x87, 0x88,
|
||||
0x88, 0x89, 0x89, 0x8a, 0x8a, 0x8b, 0x8b, 0x8c,
|
||||
0x8c, 0x8d, 0x8d, 0x8e, 0x8e, 0x8f, 0x8f, 0x90,
|
||||
0x90, 0x91, 0x91, 0x92, 0x92, 0x93, 0x93, 0x94,
|
||||
0x94, 0x95, 0x95, 0x96, 0x96, 0x97, 0x97, 0x98,
|
||||
0x98, 0x99, 0x99, 0x9a, 0x9a, 0x9b, 0x9b, 0x9c,
|
||||
0x9c, 0x9d, 0x9d, 0x9e, 0x9e, 0xdf, 0xdf, 0xe0,
|
||||
0xe0, 0xe1, 0xe1, 0xe2, 0xe2, 0xe3, 0xe3, 0xe4,
|
||||
0xe4, 0xe5, 0xe5, 0xe6, 0xe6, 0xe7, 0xe7, 0xe8,
|
||||
0xe8, 0xe9, 0xe9, 0xea, 0xea, 0xeb, 0xeb, 0xec,
|
||||
0xec, 0xed, 0xed, 0xee, 0xee, 0xef, 0xef, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||
|
||||
BYTE JIS_tableL[0x80] = {
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46,
|
||||
0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e,
|
||||
0x4f, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56,
|
||||
0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e,
|
||||
0x5f, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66,
|
||||
0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e,
|
||||
0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76,
|
||||
0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e,
|
||||
0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
|
||||
0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
|
||||
0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
|
||||
0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x00};
|
||||
|
||||
void SpecialHookAnex86(hook_stack *stack, HookParam *hp, TextBuffer *buffer, uintptr_t *split)
|
||||
{
|
||||
auto ecx = stack->ecx;
|
||||
if (*(BYTE *)(ecx + 0xe) != 0)
|
||||
return;
|
||||
auto lb = *(BYTE *)(ecx + 0xc);
|
||||
auto hb = *(BYTE *)(ecx + 0xd);
|
||||
if (hb == 0)
|
||||
{
|
||||
buffer->from_t<char>(1);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (hb <= 0x7e && lb <= 0x7e)
|
||||
{
|
||||
|
||||
BYTE low;
|
||||
if ((hb & 1) == 0)
|
||||
low = lb + 0x7E;
|
||||
else
|
||||
low = JIS_tableL[lb];
|
||||
auto chr = low | (JIS_tableH[hb] << 8);
|
||||
buffer->from_t(_byteswap_ushort(chr));
|
||||
}
|
||||
}
|
||||
}
|
||||
} // unnamed namespace
|
||||
bool InsertAnex86Hook()
|
||||
{
|
||||
const BYTE bytes[] = {
|
||||
0x8a, XX, 0x0c, // mov ??,[ecx+0C]
|
||||
0x8a, XX, 0x0d // mov ??,[ecx+0D]
|
||||
};
|
||||
bool found = false;
|
||||
for (auto addr : Util::SearchMemory(bytes, sizeof(bytes), PAGE_EXECUTE, processStartAddress, processStopAddress))
|
||||
{
|
||||
// const DWORD dwords[] = {0x618ac033,0x0d418a0c}; // jichi 12/25/2013: Remove static keyword
|
||||
// for (DWORD i = processStartAddress + 0x1000; i < processStopAddress - 8; i++)
|
||||
// if (*(DWORD *)i == dwords[0])
|
||||
// if (*(DWORD *)(i + 4) == dwords[1]) {
|
||||
HookParam hp;
|
||||
if (*(BYTE *)(addr - 2) == 0x33 || *(BYTE *)(addr - 2) == 0x31)
|
||||
addr = addr - 2;
|
||||
hp.address = addr;
|
||||
hp.offset = get_reg(regs::ecx);
|
||||
hp.type = USING_CHAR;
|
||||
hp.text_fun = SpecialHookAnex86;
|
||||
// hp.type = EXTERN_HOOK;
|
||||
ConsoleOutput("INSERT Anex86");
|
||||
|
||||
found |= NewHook(hp, "Anex86");
|
||||
}
|
||||
if (found)
|
||||
return true;
|
||||
ConsoleOutput("Anex86: failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Anex86::attach_function()
|
||||
{
|
||||
|
||||
return InsertAnex86Hook();
|
||||
}
|
16
cpp/LunaHook/LunaHook/engine32/Anex86.h
Normal file
16
cpp/LunaHook/LunaHook/engine32/Anex86.h
Normal file
@ -0,0 +1,16 @@
|
||||
|
||||
|
||||
class Anex86 : public ENGINE
|
||||
{
|
||||
public:
|
||||
Anex86()
|
||||
{
|
||||
|
||||
check_by = CHECK_BY::CUSTOM;
|
||||
check_by_target = []()
|
||||
{
|
||||
return (wcsstr(processName_lower, L"anex86") || Util::CheckFile(L"anex86.exe"));
|
||||
};
|
||||
};
|
||||
bool attach_function();
|
||||
};
|
113
cpp/LunaHook/LunaHook/engine32/Anim.cpp
Normal file
113
cpp/LunaHook/LunaHook/engine32/Anim.cpp
Normal file
@ -0,0 +1,113 @@
|
||||
#include "Anim.h"
|
||||
|
||||
bool InsertAnimHook()
|
||||
{
|
||||
const BYTE bytes[] = {0xC7, 0x45, 0xFC, 0x01, 0x00, 0x00, 0x00, 0x8B, 0x4D, 0x10, 0x51, 0x8D, 0x8D, 0x40, 0x7E, 0xFF, 0xFF};
|
||||
ULONG range = min(processStopAddress - processStartAddress, MAX_REL_ADDR);
|
||||
ULONG addr = MemDbg::findBytes(bytes, sizeof(bytes), processStartAddress, processStartAddress + range);
|
||||
if (!addr)
|
||||
{
|
||||
ConsoleOutput("Anim: pattern not found");
|
||||
return false;
|
||||
}
|
||||
HookParam myhp;
|
||||
myhp.address = addr + 10;
|
||||
|
||||
myhp.type = USING_STRING | NO_CONTEXT | EMBED_ABLE | EMBED_AFTER_OVERWRITE | EMBED_DYNA_SJIS; // /HQ 不使用上下文区分 把所有线程的文本都提取
|
||||
myhp.hook_font = F_GetGlyphOutlineA;
|
||||
// data_offset
|
||||
myhp.offset = get_reg(regs::ecx);
|
||||
char nameForUser[HOOK_NAME_SIZE] = "Anim";
|
||||
|
||||
return NewHook(myhp, nameForUser);
|
||||
}
|
||||
|
||||
bool InsertAnim2Hook()
|
||||
{
|
||||
const BYTE bytes[] = {0xC7, 0x45, 0xFC, 0x01, 0x00, 0x00, 0x00, 0x8B, 0x45, 0x10, 0x50, 0x8D, 0x8D, 0xAC, 0x7E, 0xFF, 0xFF};
|
||||
ULONG range = min(processStopAddress - processStartAddress, MAX_REL_ADDR);
|
||||
ULONG addr = MemDbg::findBytes(bytes, sizeof(bytes), processStartAddress, processStartAddress + range);
|
||||
if (!addr)
|
||||
{
|
||||
ConsoleOutput("Anim2: pattern not found");
|
||||
return false;
|
||||
}
|
||||
HookParam myhp;
|
||||
myhp.address = addr + 10;
|
||||
myhp.hook_font = F_GetGlyphOutlineA;
|
||||
// メスつまみ3
|
||||
// そんな俺に声をかけてきたのは、近所のスーパーで働いている主婦の、@n『@[赤羽:あかばね]@[千晶:ちあき]』さんだ。
|
||||
myhp.filter_fun = [](void *data, size_t *len, HookParam *hp)
|
||||
{
|
||||
static const std::regex rx("@\\[(.*?):(.*?)\\]", std::regex_constants::icase);
|
||||
std::string result = std::string((char *)data, *len);
|
||||
result = std::regex_replace(result, rx, "$1");
|
||||
return write_string_overwrite(data, len, result);
|
||||
};
|
||||
myhp.newlineseperator = L"@n";
|
||||
myhp.type = USING_STRING | NO_CONTEXT | EMBED_ABLE | EMBED_AFTER_OVERWRITE | EMBED_DYNA_SJIS;
|
||||
// 僕がいない間に変貌えられた妻の秘肉 ~ラブラブ新婚妻は他の男に抱かれ淫らに喘ぐ夢を見るか~ 体験版
|
||||
|
||||
// data_offset
|
||||
myhp.offset = get_reg(regs::eax);
|
||||
|
||||
return NewHook(myhp, "Anim2");
|
||||
}
|
||||
namespace
|
||||
{
|
||||
bool Anim3Filter(LPVOID data, size_t *size, HookParam *)
|
||||
{
|
||||
auto text = reinterpret_cast<LPSTR>(data);
|
||||
auto len = reinterpret_cast<size_t *>(size);
|
||||
|
||||
StringFilterBetween(text, len, "\x81\x40", 2, "@m", 2); // @r(2,はと)
|
||||
StringFilterBetween(text, len, "\x81\x40", 2, "@n", 2); // @r(2,はと)
|
||||
StringCharReplacer(text, len, "@b", 2, ' ');
|
||||
StringCharReplacer(text, len, "\x81\x42", 2, '.');
|
||||
StringCharReplacer(text, len, "\x81\x48", 2, '?');
|
||||
StringCharReplacer(text, len, "\x81\x49", 2, '!');
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool InsertAnim3Hook()
|
||||
{
|
||||
/*
|
||||
* Sample games:
|
||||
* https://vndb.org/v17427
|
||||
* https://vndb.org/v18837
|
||||
*/
|
||||
const BYTE bytes[] = {
|
||||
0xCC, // int 3
|
||||
0x55, // push ebp << hook here
|
||||
0x8B, 0xEC, // mov ebp,esp
|
||||
0x81, 0xEC, XX4, // sub esp,00000830
|
||||
0xA1, XX4, // mov eax,[musu_mama.exe+A91F0]
|
||||
0x33, 0xC5, // xor eax,ebp
|
||||
0x89, 0x45, 0xE8 // mov [ebp-18],eax
|
||||
};
|
||||
ULONG range = min(processStopAddress - processStartAddress, MAX_REL_ADDR);
|
||||
ULONG addr = MemDbg::findBytes(bytes, sizeof(bytes), processStartAddress, processStartAddress + range);
|
||||
if (!addr)
|
||||
{
|
||||
ConsoleOutput("Anim3: pattern not found");
|
||||
return false;
|
||||
}
|
||||
|
||||
HookParam hp;
|
||||
hp.address = addr + 1;
|
||||
hp.offset = get_reg(regs::edx);
|
||||
hp.type = USING_STRING;
|
||||
hp.filter_fun = Anim3Filter;
|
||||
ConsoleOutput("INSERT Anim3");
|
||||
|
||||
return NewHook(hp, "Anim3");
|
||||
}
|
||||
}
|
||||
bool Anim::attach_function()
|
||||
{
|
||||
|
||||
auto b1 = InsertAnimHook() || InsertAnim2Hook();
|
||||
b1 = InsertAnim3Hook() || b1;
|
||||
return b1;
|
||||
}
|
14
cpp/LunaHook/LunaHook/engine32/Anim.h
Normal file
14
cpp/LunaHook/LunaHook/engine32/Anim.h
Normal file
@ -0,0 +1,14 @@
|
||||
|
||||
|
||||
class Anim : public ENGINE
|
||||
{
|
||||
public:
|
||||
Anim()
|
||||
{
|
||||
|
||||
check_by = CHECK_BY::FILE;
|
||||
check_by_target = L"voice\\*.pck";
|
||||
is_engine_certain = false;
|
||||
};
|
||||
bool attach_function();
|
||||
};
|
24
cpp/LunaHook/LunaHook/engine32/Anisetta.cpp
Normal file
24
cpp/LunaHook/LunaHook/engine32/Anisetta.cpp
Normal file
@ -0,0 +1,24 @@
|
||||
#include "Anisetta.h"
|
||||
|
||||
bool Anisetta::attach_function()
|
||||
{
|
||||
// https://vndb.org/v4068
|
||||
// 12+
|
||||
const BYTE bytes[] = {
|
||||
0xF7, 0xD8,
|
||||
0x1B, 0xC0,
|
||||
0x25, 0x58, 0x02, 0x00, 0x00,
|
||||
0x05, 0x90, 0x01, 0x00, 0x00};
|
||||
auto addr = MemDbg::findBytes(bytes, sizeof(bytes), processStartAddress, processStopAddress);
|
||||
if (addr == 0)
|
||||
return false;
|
||||
addr = MemDbg::findEnclosingAlignedFunction(addr);
|
||||
if (addr == 0)
|
||||
return false;
|
||||
HookParam hp;
|
||||
hp.address = addr;
|
||||
hp.type = CODEC_ANSI_BE;
|
||||
hp.offset = get_stack(5);
|
||||
|
||||
return NewHook(hp, "Anisetta");
|
||||
}
|
14
cpp/LunaHook/LunaHook/engine32/Anisetta.h
Normal file
14
cpp/LunaHook/LunaHook/engine32/Anisetta.h
Normal file
@ -0,0 +1,14 @@
|
||||
|
||||
|
||||
class Anisetta : public ENGINE
|
||||
{
|
||||
public:
|
||||
Anisetta()
|
||||
{
|
||||
|
||||
check_by = CHECK_BY::FILE_ANY;
|
||||
check_by_target = check_by_list{L"*.pd", L".pb"};
|
||||
is_engine_certain = false;
|
||||
};
|
||||
bool attach_function();
|
||||
};
|
159
cpp/LunaHook/LunaHook/engine32/ApricoT.cpp
Normal file
159
cpp/LunaHook/LunaHook/engine32/ApricoT.cpp
Normal file
@ -0,0 +1,159 @@
|
||||
#include "ApricoT.h"
|
||||
|
||||
/********************************************************************************************
|
||||
Apricot hook:
|
||||
Game folder contains arc.a*.
|
||||
This engine is heavily based on new DirectX interfaces.
|
||||
I can't find a good place where text is clean and not repeating.
|
||||
The game processes script encoded in UTF32-like format.
|
||||
I reversed the parsing algorithm of the game and implemented it partially.
|
||||
Only name and text data is needed.
|
||||
|
||||
********************************************************************************************/
|
||||
|
||||
/** jichi 2/15/2015: ApricoT
|
||||
*
|
||||
* Sample game: イセカイ・ラヴァーズ<EFBFBD>体験版
|
||||
* Issue of the old game is that it uses esp as split, and hence has relative address
|
||||
*
|
||||
* 00978100 5b pop ebx
|
||||
* 00978101 83c4 2c add esp,0x2c
|
||||
* 00978104 c2 0400 retn 0x4
|
||||
* 00978107 33c0 xor eax,eax ; jichi: hook here
|
||||
* 00978109 bb 03000000 mov ebx,0x3
|
||||
* 0097810e 895c24 30 mov dword ptr ss:[esp+0x30],ebx
|
||||
* 00978112 894424 2c mov dword ptr ss:[esp+0x2c],eax
|
||||
* 00978116 894424 1c mov dword ptr ss:[esp+0x1c],eax
|
||||
* 0097811a 8b4e 34 mov ecx,dword ptr ds:[esi+0x34]
|
||||
* 0097811d 3b4e 3c cmp ecx,dword ptr ds:[esi+0x3c]
|
||||
* 00978120 894424 3c mov dword ptr ss:[esp+0x3c],eax
|
||||
* 00978124 7e 3b jle short .00978161
|
||||
* 00978126 8b7e 3c mov edi,dword ptr ds:[esi+0x3c]
|
||||
* 00978129 3b7e 34 cmp edi,dword ptr ds:[esi+0x34]
|
||||
* 0097812c 76 05 jbe short .00978133
|
||||
* 0097812e e8 01db1500 call .00ad5c34
|
||||
* 00978133 837e 38 04 cmp dword ptr ds:[esi+0x38],0x4
|
||||
* 00978137 72 05 jb short .0097813e
|
||||
* 00978139 8b46 24 mov eax,dword ptr ds:[esi+0x24]
|
||||
* 0097813c eb 03 jmp short .00978141
|
||||
* 0097813e 8d46 24 lea eax,dword ptr ds:[esi+0x24]
|
||||
* 00978141 8b3cb8 mov edi,dword ptr ds:[eax+edi*4]
|
||||
* 00978144 016e 3c add dword ptr ds:[esi+0x3c],ebp
|
||||
* 00978147 57 push edi
|
||||
* 00978148 55 push ebp
|
||||
* 00978149 8d4c24 20 lea ecx,dword ptr ss:[esp+0x20]
|
||||
* 0097814d e8 de05feff call .00958730
|
||||
*
|
||||
* Sample stack: baseaddr = 0c90000
|
||||
* 001aec2c ede50fbb
|
||||
* 001aec30 0886064c
|
||||
* 001aec34 08860bd0
|
||||
* 001aec38 08860620
|
||||
* 001aec3c 00000000
|
||||
* 001aec40 00000000
|
||||
* 001aec44 08860bd0
|
||||
* 001aec48 001aee18
|
||||
* 001aec4c 08860620
|
||||
* 001aec50 00000000
|
||||
* 001aec54 00cb4408 return to .00cb4408 from .00c973e0
|
||||
* 001aec58 08860bd8
|
||||
* 001aec5c 00000000
|
||||
* 001aec60 001aefd8 pointer to next seh record
|
||||
* 001aec64 00e47d88 se handler
|
||||
* 001aec68 ffffffff
|
||||
* 001aec6c 00cb9f40 return to .00cb9f40 from .00cc8030 ; jichi: split here
|
||||
*/
|
||||
static void SpecialHookApricoT(hook_stack *stack, HookParam *hp, TextBuffer *buffer, uintptr_t *split)
|
||||
{
|
||||
DWORD reg_esi = stack->esi;
|
||||
DWORD base = *(DWORD *)(reg_esi + 0x24);
|
||||
DWORD index = *(DWORD *)(reg_esi + 0x3c);
|
||||
DWORD *script = (DWORD *)(base + index * 4);
|
||||
// jichi 2/14/2015
|
||||
// Change reg_esp to the return address
|
||||
// DWORD reg_esp = regof(esp, esp_base);
|
||||
//*split = reg_esp;
|
||||
//*split = regof(esp, esp_base);
|
||||
DWORD arg = stack->stack[16]; // return address
|
||||
*split = arg > processStartAddress ? arg - processStartAddress : arg; // use relative split value
|
||||
//*split = argof(1, esp_base);
|
||||
if (script[0] == L'<')
|
||||
{
|
||||
DWORD *end;
|
||||
for (end = script; *end != L'>'; end++)
|
||||
; // jichi 2/14/2015: i.e. = ::wcschr(script) or script
|
||||
switch (script[1])
|
||||
{
|
||||
case L'N':
|
||||
if (script[2] == L'a' && script[3] == L'm' && script[4] == L'e')
|
||||
{
|
||||
buffer_index = 0;
|
||||
for (script += 5; script < end; script++)
|
||||
if (*script > 0x20)
|
||||
wc_buffer[buffer_index++] = *script & 0xFFFF;
|
||||
buffer->from(wc_buffer, buffer_index << 1);
|
||||
// jichi 1/4/2014: The way I save subconext is not able to distinguish the split value
|
||||
// Change to shift 16
|
||||
//*split |= 1 << 31;
|
||||
*split |= 1 << 16; // jichi: differentiate name and text script
|
||||
}
|
||||
break;
|
||||
case L'T':
|
||||
if (script[2] == L'e' && script[3] == L'x' && script[4] == L't')
|
||||
{
|
||||
buffer_index = 0;
|
||||
for (script += 5; script < end; script++)
|
||||
{
|
||||
if (*script > 0x40)
|
||||
{
|
||||
while (*script == L'{')
|
||||
{
|
||||
script++;
|
||||
while (*script != L'\\')
|
||||
{
|
||||
wc_buffer[buffer_index++] = *script & 0xffff;
|
||||
script++;
|
||||
}
|
||||
while (*script++ != L'}')
|
||||
;
|
||||
}
|
||||
wc_buffer[buffer_index++] = *script & 0xffff;
|
||||
}
|
||||
}
|
||||
buffer->from(wc_buffer, buffer_index << 1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool InsertApricoTHook()
|
||||
{
|
||||
for (DWORD i = processStartAddress + 0x1000; i < processStopAddress - 4; i++)
|
||||
if ((*(DWORD *)i & 0xfff8fc) == 0x3cf880) // cmp reg,0x3c
|
||||
for (DWORD j = i + 3, k = i + 0x100; j < k; j++)
|
||||
if ((*(DWORD *)j & 0xffffff) == 0x4c2)
|
||||
{ // retn 4
|
||||
HookParam hp;
|
||||
hp.address = j + 3;
|
||||
hp.text_fun = SpecialHookApricoT;
|
||||
hp.type = USING_STRING | NO_CONTEXT | CODEC_UTF16;
|
||||
ConsoleOutput("INSERT ApricoT");
|
||||
// GROWL_DWORD3(hp.address, processStartAddress, processStopAddress);
|
||||
|
||||
// RegisterEngineType(ENGINE_APRICOT);
|
||||
// jichi 2/14/2015: disable cached GDI functions
|
||||
ConsoleOutput("ApRicoT: disable GDI hooks");
|
||||
|
||||
return NewHook(hp, "ApRicoT");
|
||||
}
|
||||
|
||||
ConsoleOutput("ApricoT: failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ApricoT::attach_function()
|
||||
{
|
||||
|
||||
return InsertApricoTHook();
|
||||
}
|
25
cpp/LunaHook/LunaHook/engine32/ApricoT.h
Normal file
25
cpp/LunaHook/LunaHook/engine32/ApricoT.h
Normal file
@ -0,0 +1,25 @@
|
||||
|
||||
|
||||
class ApricoT : public ENGINE
|
||||
{
|
||||
public:
|
||||
ApricoT()
|
||||
{
|
||||
|
||||
check_by = CHECK_BY::FILE;
|
||||
check_by_target = L"arc.a*";
|
||||
};
|
||||
bool attach_function();
|
||||
};
|
||||
|
||||
class ApricoTlast : public ApricoT
|
||||
{
|
||||
public:
|
||||
ApricoTlast()
|
||||
{
|
||||
|
||||
check_by = CHECK_BY::FILE;
|
||||
check_by_target = L"arc.dat";
|
||||
is_engine_certain = false;
|
||||
};
|
||||
};
|
270
cpp/LunaHook/LunaHook/engine32/Artemis.cpp
Normal file
270
cpp/LunaHook/LunaHook/engine32/Artemis.cpp
Normal file
@ -0,0 +1,270 @@
|
||||
#include "Artemis.h"
|
||||
|
||||
/**
|
||||
* jichi 10/1/2013: Artemis Engine
|
||||
* See: http://www.ies-net.com/
|
||||
* See (CaoNiMaGeBi): http://tieba.baidu.com/p/2625537737
|
||||
* Pattern:
|
||||
* 650a2f 83c4 0c add esp,0xc ; hook here
|
||||
* 650a32 0fb6c0 movzx eax,al
|
||||
* 650a35 85c0 test eax,eax
|
||||
* 0fb6c0 75 0e jnz short tsugokaz.0065a47
|
||||
*
|
||||
* Wrong: 0x400000 + 0x7c574
|
||||
*
|
||||
* //Example: [130927]妹スパイラル /HBN-8*0:14@65589F
|
||||
* Example: ヂ<EFBFBD>ウノイイ家<EFBFBD>Trial /HBN-8*0:14@650A2F
|
||||
* Note: 0x650a2f > 40000(base) + 20000(limit)
|
||||
* - addr: 0x650a2f
|
||||
* - text_fun: 0x0
|
||||
* - function: 0
|
||||
* - hook_len: 0
|
||||
* - ind: 0
|
||||
* - length_offset: 1
|
||||
* - module: 0
|
||||
* - off: 4294967284 = 0xfffffff4 = -0xc
|
||||
* - recover_len: 0
|
||||
* - split: 20 = 0x14
|
||||
* - split_ind: 0
|
||||
* - type: 1048 = 0x418
|
||||
*
|
||||
* @CaoNiMaGeBi:
|
||||
* RECENT GAMES:
|
||||
* [130927]妹スパイラル /HBN-8*0:14@65589F
|
||||
* [130927]サ<EFBFBD>ライホルモン
|
||||
* [131025]ヂ<EFBFBD>ウノイイ家<EFBFBD>/HBN-8*0:14@650A2F (for trial version)
|
||||
* CLIENT ORGANIZAIONS:
|
||||
* CROWD
|
||||
* D:drive.
|
||||
* Hands-Aid Corporation
|
||||
* iMel株式会社
|
||||
* SHANNON
|
||||
* SkyFish
|
||||
* SNACK-FACTORY
|
||||
* team flap
|
||||
* Zodiac
|
||||
* くらむちめ<EFBFBD><EFBFBD> * まかろんソフト
|
||||
* アイヂ<EFBFBD>アファクトリー株式会社
|
||||
* カラクリズ<EFBFBD>
|
||||
* 合赼<EFBFBD>社ファーストリー<EFBFBD>
|
||||
* 有限会社ウルクスへブン
|
||||
* 有限会社ロータス
|
||||
* 株式会社CUCURI
|
||||
* 株式会社アバン
|
||||
* 株式会社インタラクヂ<EFBFBD>ブブレインズ
|
||||
* 株式会社ウィンヂ<EFBFBD>ール
|
||||
* 株式会社エヴァンジェ
|
||||
* 株式会社ポニーキャニオン
|
||||
* 株式会社大福エンターヂ<EFBFBD>ンメン<EFBFBD> */
|
||||
bool InsertArtemis1Hook()
|
||||
{
|
||||
const BYTE bytes[] = {
|
||||
0x83, 0xc4, 0x0c, // add esp,0xc ; hook here
|
||||
0x0f, 0xb6, 0xc0, // movzx eax,al
|
||||
0x85, 0xc0, // test eax,eax
|
||||
0x75, 0x0e // jnz XXOO ; it must be 0xe, or there will be duplication
|
||||
};
|
||||
// enum { addr_offset = 0 };
|
||||
ULONG range = min(processStopAddress - processStartAddress, MAX_REL_ADDR);
|
||||
ULONG addr = MemDbg::findBytes(bytes, sizeof(bytes), processStartAddress, processStartAddress + range);
|
||||
// GROWL_DWORD3(reladdr, processStartAddress, range);
|
||||
if (!addr)
|
||||
{
|
||||
ConsoleOutput("Artemis1: pattern not exist");
|
||||
return false;
|
||||
}
|
||||
|
||||
HookParam hp;
|
||||
hp.address = addr;
|
||||
hp.offset = get_reg(regs::ecx);
|
||||
hp.split = get_stack(5);
|
||||
hp.type = NO_CONTEXT | DATA_INDIRECT | USING_SPLIT; // 0x418
|
||||
|
||||
// hp.address = 0x650a2f;
|
||||
// GROWL_DWORD(hp.address);
|
||||
|
||||
ConsoleOutput("INSERT Artemis1");
|
||||
|
||||
// ConsoleOutput("Artemis1");
|
||||
return NewHook(hp, "Artemis1");
|
||||
}
|
||||
|
||||
bool InsertArtemis2Hook()
|
||||
{
|
||||
const BYTE bytes[] = {
|
||||
// 0054461F | CC | int3 |
|
||||
0x55, // 00544620 | 55 | push ebp |
|
||||
0x8B, 0xEC, // 00544621 | 8B EC | mov ebp,esp |
|
||||
0x83, 0xE4, 0xF8, // 00544623 | 83 E4 F8 | and esp,FFFFFFF8 |
|
||||
0x6A, 0xFF, // 00544626 | 6A FF | push FFFFFFFF |
|
||||
0x68, XX4, // 00544628 | 68 68 7C 6A 00 | push 空のつくりかた体験版_ver3.0.6A7C68 |
|
||||
0x64, 0xA1, 0x00, 0x00, 0x00, 0x00, // 0054462D | 64 A1 00 00 00 00 | mov eax,dword ptr fs:[0] |
|
||||
0x50, // 00544633 | 50 | push eax |
|
||||
0x83, 0xEC, XX, // 00544634 | 83 EC 28 | sub esp,28 |
|
||||
0xA1, XX4, // 00544637 | A1 F0 57 81 00 | mov eax,dword ptr ds:[8157F0] |
|
||||
0x33, 0xC4, // 0054463C | 33 C4 | xor eax,esp |
|
||||
0x89, 0x44, 0x24, XX, // 0054463E | 89 44 24 20 | mov dword ptr ss:[esp+20],eax |
|
||||
0x53, // 00544642 | 53 | push ebx |
|
||||
0x56, // 00544643 | 56 | push esi |
|
||||
0x57, // 00544644 | 57 | push edi |
|
||||
0xA1, XX4, // 00544645 | A1 F0 57 81 00 | mov eax,dword ptr ds:[8157F0] |
|
||||
0x33, 0xC4, // 0054464A | 33 C4 | xor eax,esp |
|
||||
0x50, // 0054464C | 50 | push eax |
|
||||
0x8D, 0x44, 0x24, XX, // 0054464D | 8D 44 24 38 | lea eax,dword ptr ss:[esp+38] | [esp+38]:BaseThreadInitThunk
|
||||
0x64, 0xA3, 0x00, 0x00, 0x00, 0x00, // 00544651 | 64 A3 00 00 00 00 | mov dword ptr fs:[0],eax |
|
||||
0x8B, 0xF1, // 00544657 | 8B F1 | mov esi,ecx |
|
||||
0x8B, 0x5D, 0x08, // 00544659 | 8B 5D 08 | mov ebx,dword ptr ss:[ebp+8] |
|
||||
0x8B, 0x4D, 0x0C // 0054465C | 8B 4D 0C | mov ecx,dword ptr ss:[ebp+C] | ecx:DbgUiRemoteBreakin, [ebp+C]:BaseThreadInitThunk
|
||||
};
|
||||
enum
|
||||
{
|
||||
addr_offset = 0
|
||||
}; // distance to the beginning of the function, which is 0x55 (push ebp)
|
||||
ULONG range = min(processStopAddress - processStartAddress, MAX_REL_ADDR);
|
||||
ULONG addr = MemDbg::findBytes(bytes, sizeof(bytes), processStartAddress, processStartAddress + range);
|
||||
if (!addr)
|
||||
{
|
||||
ConsoleOutput("Artemis2: pattern not found");
|
||||
return false;
|
||||
}
|
||||
addr += addr_offset;
|
||||
enum
|
||||
{
|
||||
push_ebp = 0x55
|
||||
}; // beginning of the function
|
||||
if (*(BYTE *)addr != push_ebp)
|
||||
{
|
||||
ConsoleOutput("Artemis2: beginning of the function not found");
|
||||
return false;
|
||||
}
|
||||
|
||||
HookParam hp;
|
||||
hp.address = addr;
|
||||
hp.offset = get_stack(1);
|
||||
hp.type = USING_STRING | NO_CONTEXT;
|
||||
|
||||
ConsoleOutput("INSERT Artemis2");
|
||||
bool succ = NewHook(hp, "Artemis2");
|
||||
|
||||
// Artikash 1/1/2019: Recent games seem to use utf8 encoding instead, other than that the hook is identical.
|
||||
// Not sure how to differentiate which games are sjis/utf8 so insert both
|
||||
hp.address = addr + 6;
|
||||
hp.offset = get_reg(regs::ebp);
|
||||
hp.index = 8; // ebp was also pushed
|
||||
hp.type = CODEC_UTF8 | USING_STRING | DATA_INDIRECT;
|
||||
succ |= NewHook(hp, "Artemis2");
|
||||
// ConsoleOutput("Artemis2");
|
||||
return succ;
|
||||
}
|
||||
|
||||
bool InsertArtemis3Hook()
|
||||
{
|
||||
const BYTE bytes[] = {
|
||||
0x55, // 005FD780 | 55 | push ebp |
|
||||
0x8B, 0xEC, // 005FD781 | 8BEC | mov ebp,esp |
|
||||
0x83, 0xE4, 0xF8, // 005FD783 | 83E4 F8 | and esp,FFFFFFF8 |
|
||||
0x83, 0xEC, 0x3C, // 005FD786 | 83EC 3C | sub esp,3C |
|
||||
0xA1, XX4, // 005FD789 | A1 6C908600 | mov eax,dword ptr ds:[86906C] |
|
||||
0x33, 0xC4, // 005FD78E | 33C4 | xor eax,esp |
|
||||
0x89, 0x44, 0x24, 0x38, // 005FD790 | 894424 38 | mov dword ptr ss:[esp+38],eax |
|
||||
0x53, // 005FD794 | 53 | push ebx |
|
||||
0x56, // 005FD795 | 56 | push esi |
|
||||
0x8B, 0xC1, // 005FD796 | 8BC1 | mov eax,ecx |
|
||||
0xC7, 0x44, 0x24, 0x14, 0x00, 0x00, 0x00, 0x00, // 005FD798 | C74424 14 00000000 | mov dword ptr ss:[esp+14],0 |
|
||||
0x8B, 0x4D, 0x0C, // 005FD7A0 | 8B4D 0C | mov ecx,dword ptr ss:[ebp+C] |
|
||||
0x33, 0xF6, // 005FD7A3 | 33F6 | xor esi,esi |
|
||||
0x57, // 005FD7A5 | 57 | push edi |
|
||||
0x8B, 0x7D, 0x08, // 005FD7A6 | 8B7D 08 | mov edi,dword ptr ss:[ebp+8] |
|
||||
0x89, 0x44, 0x24, 0x14, // 005FD7A9 | 894424 14 | mov dword ptr ss:[esp+14],eax |
|
||||
0x89, 0x4C, 0x24, 0x28, // 005FD7AD | 894C24 28 | mov dword ptr ss:[esp+28],ecx |
|
||||
0x80, 0x3F, 0x00, // 005FD7B1 | 803F 00 | cmp byte ptr ds:[edi],0 |
|
||||
0x0F, 0x84, XX4, // 005FD7B4 | 0F84 88040000 | je ヘンタイ・プリズンsplit 1.5FDC42 |
|
||||
0x83, 0xB8, XX4, 0x00, // 005FD7BA | 83B8 74030000 00 | cmp dword ptr ds:[eax+374],0 |
|
||||
0x8B, 0xDF, // 005FD7C1 | 8BDF | mov ebx,edi |
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
addr_offset = 0
|
||||
}; // distance to the beginning of the function, which is 0x55 (push ebp)
|
||||
ULONG range = min(processStopAddress - processStartAddress, MAX_REL_ADDR);
|
||||
ULONG addr = MemDbg::findBytes(bytes, sizeof(bytes), processStartAddress, processStartAddress + range);
|
||||
if (!addr)
|
||||
{
|
||||
ConsoleOutput("Artemis3: pattern not found");
|
||||
return false;
|
||||
}
|
||||
addr += addr_offset;
|
||||
enum
|
||||
{
|
||||
push_ebp = 0x55
|
||||
}; // beginning of the function
|
||||
if (*(BYTE *)addr != push_ebp)
|
||||
{
|
||||
ConsoleOutput("Artemis3: beginning of the function not found");
|
||||
return false;
|
||||
}
|
||||
|
||||
HookParam hp;
|
||||
hp.address = addr;
|
||||
hp.offset = get_stack(1);
|
||||
hp.type = USING_STRING | EMBED_ABLE | CODEC_UTF8 | EMBED_AFTER_NEW;
|
||||
|
||||
return NewHook(hp, "EmbedArtemis");
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
bool a4()
|
||||
{
|
||||
// 高慢な奥さんは好きですか?~傲慢人妻教師の堕とし方~
|
||||
std::vector<uint64_t> addrs;
|
||||
for (DWORD func : {(DWORD)GetGlyphOutlineA, (DWORD)GetGlyphOutlineW})
|
||||
{
|
||||
auto addrs_ = findiatcallormov_all(func, processStartAddress, processStartAddress, processStopAddress, PAGE_EXECUTE);
|
||||
addrs.insert(addrs.end(), addrs_.begin(), addrs_.end());
|
||||
}
|
||||
bool ok = false;
|
||||
for (auto addr : addrs)
|
||||
{
|
||||
auto funcaddr = MemDbg::findEnclosingAlignedFunction(addr);
|
||||
if (!funcaddr)
|
||||
continue;
|
||||
BYTE sig1[] = {0x81, XX, 0x00, 0x00, 0x10, 0x00};
|
||||
BYTE sig2[] = {0x68, 0x00, 0x02, 0x00, 0x00, 0x68, 0x00, 0x02, 0x00, 0x00};
|
||||
BYTE sig3[] = {XX, 0x80, 0x00, 0x00, 0x00, 0x0f, 0x95, 0xc1};
|
||||
BYTE sig4[] = {0xC1, XX, 0x18};
|
||||
int found = 0;
|
||||
for (auto sigsz : std::vector<std::pair<BYTE *, int>>{{sig1, sizeof(sig1)}, {sig2, sizeof(sig2)}, {sig3, sizeof(sig3)}, {sig4, sizeof(sig4)}})
|
||||
{
|
||||
auto fd = MemDbg::findBytes(sigsz.first, sigsz.second, funcaddr, addr);
|
||||
if (fd)
|
||||
found += 1;
|
||||
}
|
||||
if (found == 4)
|
||||
{
|
||||
{
|
||||
HookParam hp;
|
||||
hp.address = funcaddr;
|
||||
hp.type = CODEC_ANSI_BE;
|
||||
hp.offset = get_stack(2);
|
||||
ok |= NewHook(hp, "Artemis4A");
|
||||
}
|
||||
{
|
||||
HookParam hp;
|
||||
hp.address = funcaddr + 5;
|
||||
hp.type = CODEC_UTF16;
|
||||
hp.offset = get_stack(2);
|
||||
ok |= NewHook(hp, "Artemis4W");
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
bool Artemis::attach_function()
|
||||
{
|
||||
|
||||
return InsertArtemis1Hook() || InsertArtemis2Hook() || InsertArtemis3Hook() || a4();
|
||||
}
|
13
cpp/LunaHook/LunaHook/engine32/Artemis.h
Normal file
13
cpp/LunaHook/LunaHook/engine32/Artemis.h
Normal file
@ -0,0 +1,13 @@
|
||||
|
||||
|
||||
class Artemis : public ENGINE
|
||||
{
|
||||
public:
|
||||
Artemis()
|
||||
{
|
||||
|
||||
check_by = CHECK_BY::FILE;
|
||||
check_by_target = L"*.pfs";
|
||||
};
|
||||
bool attach_function();
|
||||
};
|
265
cpp/LunaHook/LunaHook/engine32/Atelier.cpp
Normal file
265
cpp/LunaHook/LunaHook/engine32/Atelier.cpp
Normal file
@ -0,0 +1,265 @@
|
||||
#include "Atelier.h"
|
||||
/********************************************************************************************
|
||||
AtelierKaguya hook:
|
||||
Game folder contains message.dat. Used by AtelierKaguya games.
|
||||
Usually has font caching issue with TextOutA.
|
||||
Game engine uses EBP to set up stack frame so we can easily trace back.
|
||||
Keep step out until it's in main game module. We notice that either register or
|
||||
stack contains string pointer before call instruction. But it's not quite stable.
|
||||
In-depth analysis of the called function indicates that there's a loop traverses
|
||||
the string one character by one. We can set a hook there.
|
||||
This search process is too complex so I just make use of some characteristic
|
||||
instruction(add esi,0x40) to locate the right point.
|
||||
********************************************************************************************/
|
||||
bool InsertAtelierHook()
|
||||
{
|
||||
PcHooks::hookOtherPcFunctions(); // lstrlenA gives good hook too
|
||||
// SafeFillRange(processName, &base, &size);
|
||||
// size=size-base;
|
||||
// DWORD sig = 0x40c683; // add esi,0x40
|
||||
// i=processStartAddress+SearchPattern(processStartAddress,processStopAddress-processStartAddress,&sig,3);
|
||||
DWORD i;
|
||||
for (i = processStartAddress; i < processStopAddress - 4; i++)
|
||||
{
|
||||
DWORD sig = *(DWORD *)i & 0xffffff;
|
||||
if (0x40c683 == sig) // add esi,0x40
|
||||
break;
|
||||
}
|
||||
if (i < processStopAddress - 4)
|
||||
for (DWORD j = i - 0x200; i > j; i--)
|
||||
if (*(DWORD *)i == 0xff6acccc)
|
||||
{ // find the function entry
|
||||
HookParam hp;
|
||||
hp.address = i + 2;
|
||||
hp.offset = get_stack(2);
|
||||
hp.split = get_reg(regs::esp);
|
||||
hp.type = USING_SPLIT;
|
||||
ConsoleOutput("INSERT Aterlier KAGUYA");
|
||||
|
||||
// RegisterEngineType(ENGINE_ATELIER);
|
||||
return NewHook(hp, "Atelier KAGUYA");
|
||||
}
|
||||
|
||||
ConsoleOutput("Aterlier: failed");
|
||||
return false;
|
||||
// ConsoleOutput("Unknown Atelier KAGUYA engine.");
|
||||
}
|
||||
|
||||
bool InsertAtelierKaguya2Hook()
|
||||
{
|
||||
|
||||
/*
|
||||
* Sample games:
|
||||
* https://vndb.org/v22713
|
||||
* https://vndb.org/v31685
|
||||
* https://vndb.org/v37081
|
||||
*/
|
||||
const BYTE bytes[] = {
|
||||
0x51, // push ecx << hook here
|
||||
0x50, // push eax
|
||||
0xE8, XX4, // call Start.exe+114307
|
||||
0x83, 0xC4, 0x08, // add esp,08
|
||||
0x85, 0xC0, // test eax,eax
|
||||
0x78, 0xA1 // js Start.exe+48947
|
||||
};
|
||||
|
||||
ULONG range = min(processStopAddress - processStartAddress, MAX_REL_ADDR);
|
||||
ULONG addr = MemDbg::findBytes(bytes, sizeof(bytes), processStartAddress, processStartAddress + range);
|
||||
if (!addr)
|
||||
{
|
||||
ConsoleOutput("Atelier KAGUYA2: pattern not found");
|
||||
return false;
|
||||
}
|
||||
|
||||
HookParam hp;
|
||||
hp.address = addr;
|
||||
hp.offset = get_reg(regs::eax);
|
||||
hp.type = USING_STRING | EMBED_AFTER_OVERWRITE | EMBED_ABLE | EMBED_DYNA_SJIS;
|
||||
hp.hook_font = F_TextOutA;
|
||||
hp.filter_fun = NewLineCharToSpaceFilterA;
|
||||
ConsoleOutput("INSERT Atelier KAGUYA2");
|
||||
|
||||
return NewHook(hp, "Atelier KAGUYA2");
|
||||
}
|
||||
|
||||
bool InsertAtelierKaguya3Hook()
|
||||
{
|
||||
|
||||
/*
|
||||
* Sample games:
|
||||
* https://vndb.org/v10082
|
||||
*/
|
||||
const BYTE bytes[] = {
|
||||
0x55, // push ebp << hook here
|
||||
0x8B, 0xEC, // mov ebp,esp
|
||||
0x6A, 0xFF, // push -01
|
||||
0x68, 0x80, 0xB9, 0x4D, 0x00, // push Start.exe+DB980
|
||||
0x64, 0xA1, XX4, // mov eax,fs:[00000000]
|
||||
0x50, // push eax
|
||||
0x51, // push ecx
|
||||
0x81, 0xEC, 0xAC, 0x00, 0x00, 0x00 // sub esp,000000AC
|
||||
};
|
||||
|
||||
ULONG range = min(processStopAddress - processStartAddress, MAX_REL_ADDR);
|
||||
ULONG addr = MemDbg::findBytes(bytes, sizeof(bytes), processStartAddress, processStartAddress + range);
|
||||
if (!addr)
|
||||
{
|
||||
ConsoleOutput("Atelier KAGUYA3: pattern not found");
|
||||
return false;
|
||||
}
|
||||
|
||||
HookParam hp;
|
||||
hp.address = addr;
|
||||
hp.offset = get_reg(regs::eax);
|
||||
hp.type = USING_STRING;
|
||||
hp.filter_fun = NewLineCharToSpaceFilterA;
|
||||
ConsoleOutput("INSERT Atelier KAGUYA3");
|
||||
|
||||
return NewHook(hp, "Atelier KAGUYA3");
|
||||
}
|
||||
|
||||
bool InsertAtelierKaguya4Hook()
|
||||
{
|
||||
|
||||
/*
|
||||
* Sample games:
|
||||
* https://vndb.org/v14705
|
||||
*/
|
||||
const BYTE bytes[] = {
|
||||
0xE8, 0x90, 0xA8, 0xFF, 0xFF, // call Start.exe+18380
|
||||
0x89, 0x45, 0xF8, // mov [ebp-08],eax
|
||||
0x8B, 0x4D, 0x10, // mov ecx,[ebp+10]
|
||||
0x51, // push ecx
|
||||
0x8B, 0x55, 0x0C, // mov edx,[ebp+0C]
|
||||
0x52, // push edx
|
||||
0x8B, 0x45, 0x08, // mov eax,[ebp+08]
|
||||
0x50 // push eax << hook here
|
||||
};
|
||||
enum
|
||||
{
|
||||
addr_offset = sizeof(bytes) - 1
|
||||
};
|
||||
|
||||
ULONG range = min(processStopAddress - processStartAddress, MAX_REL_ADDR);
|
||||
ULONG addr = MemDbg::findBytes(bytes, sizeof(bytes), processStartAddress, processStartAddress + range);
|
||||
if (!addr)
|
||||
{
|
||||
ConsoleOutput("Atelier KAGUYA4: pattern not found");
|
||||
return false;
|
||||
}
|
||||
|
||||
HookParam hp;
|
||||
hp.address = addr + addr_offset;
|
||||
hp.offset = get_reg(regs::eax);
|
||||
hp.type = USING_STRING;
|
||||
hp.filter_fun = NewLineCharToSpaceFilterA;
|
||||
ConsoleOutput("INSERT Atelier KAGUYA4");
|
||||
|
||||
return NewHook(hp, "Atelier KAGUYA4");
|
||||
}
|
||||
|
||||
bool InsertAtelierKaguya5Hook()
|
||||
{
|
||||
|
||||
/*
|
||||
* Sample games:
|
||||
* https://vndb.org/v11224
|
||||
*/
|
||||
const BYTE bytes[] = {
|
||||
0xC2, 0x04, 0x00, // ret 0004
|
||||
0x55, // push ebp << hook here
|
||||
0x8B, 0xEC, // mov ebp,esp
|
||||
0x6A, 0xFF, // push -01
|
||||
0x68, XX4, // push Start.exe+DA680
|
||||
0x64, 0xA1, 0x00, 0x00, 0x00, 0x00, // mov eax,fs:[00000000]
|
||||
0x50, // push eax
|
||||
0x51, // push ecx
|
||||
};
|
||||
ULONG range = min(processStopAddress - processStartAddress, MAX_REL_ADDR);
|
||||
ULONG addr = MemDbg::findBytes(bytes, sizeof(bytes), processStartAddress, processStartAddress + range);
|
||||
if (!addr)
|
||||
{
|
||||
ConsoleOutput("Atelier KAGUYA5: pattern not found");
|
||||
return false;
|
||||
}
|
||||
|
||||
HookParam hp;
|
||||
hp.address = addr + 3;
|
||||
hp.offset = get_reg(regs::eax);
|
||||
hp.type = USING_STRING;
|
||||
hp.filter_fun = NewLineCharToSpaceFilterA;
|
||||
ConsoleOutput("INSERT Atelier KAGUYA5");
|
||||
|
||||
return NewHook(hp, "Atelier KAGUYA5");
|
||||
}
|
||||
bool InsertAtelierKaguyaX()
|
||||
{
|
||||
// エロティ課 誘惑研修はじまるよ~ しごいちゃうから覚悟なさい!
|
||||
const BYTE bytes[] = {
|
||||
0x3D, 0xF0, 0x41, 0x00, 0x00,
|
||||
0x75};
|
||||
|
||||
ULONG range = min(processStopAddress - processStartAddress, MAX_REL_ADDR);
|
||||
ULONG addr = MemDbg::findBytes(bytes, sizeof(bytes), processStartAddress, processStartAddress + range);
|
||||
if (!addr)
|
||||
return false;
|
||||
|
||||
addr = findfuncstart(addr, 0x1000);
|
||||
if (!addr)
|
||||
return false;
|
||||
HookParam hp;
|
||||
hp.address = addr;
|
||||
hp.offset = get_stack(1);
|
||||
hp.type = USING_STRING;
|
||||
|
||||
return NewHook(hp, "Atelier KAGUYA3");
|
||||
}
|
||||
bool Atelier::attach_function()
|
||||
{
|
||||
|
||||
return InsertAtelierHook() || InsertAtelierKaguya2Hook() || InsertAtelierKaguyaX() || InsertAtelierKaguya3Hook() || InsertAtelierKaguya4Hook() || InsertAtelierKaguya5Hook();
|
||||
}
|
||||
|
||||
bool Atelier2attach_function()
|
||||
{
|
||||
// https://vndb.org/v304
|
||||
// ダンジョンクルセイダーズ~TALES OF DEMON EATER~
|
||||
const BYTE bytes[] = {
|
||||
0x83, 0xFE, 0x34,
|
||||
0xF6, XX,
|
||||
0x88, XX, 0x24, 0x29,
|
||||
0x7D};
|
||||
|
||||
ULONG range = min(processStopAddress - processStartAddress, MAX_REL_ADDR);
|
||||
ULONG addr = MemDbg::findBytes(bytes, sizeof(bytes), processStartAddress, processStartAddress + range);
|
||||
if (!addr)
|
||||
return false;
|
||||
|
||||
HookParam hp;
|
||||
hp.address = addr + sizeof(bytes) - 1;
|
||||
hp.offset = get_stack(10);
|
||||
hp.type = USING_CHAR | NO_CONTEXT;
|
||||
// NO_CONTEXT:
|
||||
// 牝奴隷 ~犯された放課後~
|
||||
// https://vndb.org/v4351会把每行单独分开。
|
||||
return NewHook(hp, "Atelier KAGUYA3");
|
||||
}
|
||||
|
||||
bool Atelier2attach_function2()
|
||||
{
|
||||
// https://vndb.org/v7264
|
||||
// 禁断の病棟 特殊精神科医 遊佐惣介の診察記録
|
||||
auto addr = MemDbg::findCallerAddressAfterInt3((ULONG)TextOutA, processStartAddress, processStopAddress);
|
||||
if (addr == 0)
|
||||
return 0;
|
||||
HookParam hp;
|
||||
hp.address = addr;
|
||||
hp.offset = get_stack(3);
|
||||
hp.type = USING_STRING | DATA_INDIRECT;
|
||||
|
||||
return NewHook(hp, "Atelier KAGUYA");
|
||||
}
|
||||
bool Atelier2::attach_function()
|
||||
{
|
||||
return Atelier2attach_function() || Atelier2attach_function2();
|
||||
}
|
29
cpp/LunaHook/LunaHook/engine32/Atelier.h
Normal file
29
cpp/LunaHook/LunaHook/engine32/Atelier.h
Normal file
@ -0,0 +1,29 @@
|
||||
|
||||
|
||||
class Atelier : public ENGINE
|
||||
{
|
||||
public:
|
||||
Atelier()
|
||||
{
|
||||
|
||||
check_by = CHECK_BY::FILE;
|
||||
check_by_target = L"message.dat";
|
||||
};
|
||||
bool attach_function();
|
||||
};
|
||||
|
||||
class Atelier2 : public ENGINE
|
||||
{
|
||||
public:
|
||||
Atelier2()
|
||||
{
|
||||
|
||||
check_by = CHECK_BY::CUSTOM;
|
||||
check_by_target = []()
|
||||
{
|
||||
return (Util::CheckFile(L"*.ARC") && Util::CheckFile(L"*.ARI")) ||
|
||||
(Util::CheckFile(L"ARC\\*.ARC") && Util::CheckFile(L"ARC\\*.ARI"));
|
||||
};
|
||||
};
|
||||
bool attach_function();
|
||||
};
|
1710
cpp/LunaHook/LunaHook/engine32/BGI.cpp
Normal file
1710
cpp/LunaHook/LunaHook/engine32/BGI.cpp
Normal file
File diff suppressed because it is too large
Load Diff
11
cpp/LunaHook/LunaHook/engine32/BGI.h
Normal file
11
cpp/LunaHook/LunaHook/engine32/BGI.h
Normal file
@ -0,0 +1,11 @@
|
||||
|
||||
|
||||
class BGI:public ENGINE{
|
||||
public:
|
||||
BGI(){
|
||||
|
||||
check_by=CHECK_BY::FILE_ANY;
|
||||
check_by_target=check_by_list{L"bgi.*",L"sysgrp.arc"};
|
||||
};
|
||||
bool attach_function();
|
||||
};
|
59
cpp/LunaHook/LunaHook/engine32/BKEngine.cpp
Normal file
59
cpp/LunaHook/LunaHook/engine32/BKEngine.cpp
Normal file
@ -0,0 +1,59 @@
|
||||
#include"BKEngine.h"
|
||||
//https://bke.bakery.moe/download.html
|
||||
namespace{
|
||||
bool _1(){
|
||||
BYTE sig[]={0x64,0xa3,0x00,0x00,0x00,0x00,0x8b,0xf1,0x8b,0x45,0x08,0x0f,0x57,0xc0,0xc7,0x06,0x02,0x00,0x00,0x00};
|
||||
auto addr=MemDbg::findBytes(sig, sizeof(sig), processStartAddress, processStopAddress);
|
||||
if(addr==0)return 0;
|
||||
addr=MemDbg::findEnclosingAlignedFunction(addr);
|
||||
if(addr==0)return 0;
|
||||
HookParam hp;
|
||||
hp.address = addr;
|
||||
hp.type = CODEC_UTF16|DATA_INDIRECT;
|
||||
hp.index=0;
|
||||
hp.offset=get_stack(1);
|
||||
|
||||
return NewHook(hp, "BKEngine1");
|
||||
}
|
||||
bool _2(){
|
||||
BYTE sig[]={0xb8,0xff,0x00,0x00,0x00,0x66,0x3b,0x06,0x1b,0xc0,0xf7,0xd8,0x40};
|
||||
auto addr=MemDbg::findBytes(sig, sizeof(sig), processStartAddress, processStopAddress);
|
||||
if(addr==0)return 0;
|
||||
addr=MemDbg::findEnclosingAlignedFunction(addr);
|
||||
if(addr==0)return 0;
|
||||
HookParam hp;
|
||||
hp.address = addr;
|
||||
hp.type = CODEC_UTF16|DATA_INDIRECT|NO_CONTEXT;
|
||||
hp.index=0;
|
||||
hp.offset=get_stack(1);
|
||||
|
||||
return NewHook(hp, "BKEngine2");
|
||||
}
|
||||
bool _3(){
|
||||
BYTE sig[]={0x6a,0xff,0x6a,0x00,0x56};
|
||||
std::unordered_map<DWORD,int>mp;
|
||||
DWORD maxaddr=0;int maxi=0;
|
||||
for(auto addr:Util::SearchMemory(sig, sizeof(sig),PAGE_EXECUTE, processStartAddress, processStopAddress)){
|
||||
addr=MemDbg::findEnclosingAlignedFunction(addr);
|
||||
if(addr==0)continue;
|
||||
if(mp.find(addr)==mp.end())mp[addr]=0;
|
||||
mp[addr]+=1;
|
||||
if(mp[addr]>maxi){maxi=mp[addr];maxaddr=addr;}
|
||||
}
|
||||
if(maxaddr==0)return 0;
|
||||
|
||||
HookParam hp;
|
||||
hp.address = maxaddr;
|
||||
hp.type = CODEC_UTF16|USING_STRING;
|
||||
hp.offset=get_reg(regs::edx);
|
||||
|
||||
return NewHook(hp, "BKEngine3");
|
||||
}
|
||||
}
|
||||
bool BKEngine::attach_function() {
|
||||
|
||||
bool ok= _1();
|
||||
ok=_2()||ok;
|
||||
ok=_3()||ok;
|
||||
return ok;
|
||||
}
|
11
cpp/LunaHook/LunaHook/engine32/BKEngine.h
Normal file
11
cpp/LunaHook/LunaHook/engine32/BKEngine.h
Normal file
@ -0,0 +1,11 @@
|
||||
|
||||
|
||||
class BKEngine:public ENGINE{
|
||||
public:
|
||||
BKEngine(){
|
||||
is_engine_certain=false;
|
||||
check_by=CHECK_BY::FILE;
|
||||
check_by_target=L"*.bkarc";
|
||||
};
|
||||
bool attach_function();
|
||||
};
|
67
cpp/LunaHook/LunaHook/engine32/Bishop.cpp
Normal file
67
cpp/LunaHook/LunaHook/engine32/Bishop.cpp
Normal file
@ -0,0 +1,67 @@
|
||||
#include"Bishop.h"
|
||||
|
||||
bool bishopmbcjmstojis()
|
||||
{
|
||||
//特別授業
|
||||
const BYTE bytes[] = {
|
||||
//unsigned int __cdecl _mbcjmstojis(unsigned int C)
|
||||
0x55,0x8b,0xec,
|
||||
0x8b,0x45,0x08, //mov eax, [ebp+C]
|
||||
0x81, 0x3D,XX4, 0xA4 ,0x03 ,0x00 ,0x00, //cmp dword_4A1F0C, 3A4h //if ( dword_4A1F0C == 932 )
|
||||
XX2,
|
||||
0xa9,0x00,0x00,0xff,0xff //if ( (C & 0xFFFF0000) != 0 )
|
||||
};
|
||||
|
||||
auto addr = MemDbg::findBytes(bytes, sizeof(bytes), processStartAddress, processStopAddress);
|
||||
|
||||
if (!addr) return false;
|
||||
|
||||
HookParam hp;
|
||||
hp.address = addr ;
|
||||
hp.offset=get_stack(2);
|
||||
hp.type = USING_SPLIT|USING_STRING;
|
||||
|
||||
return NewHook(hp, "bishop");
|
||||
}
|
||||
bool Bishop::attach_function() {
|
||||
|
||||
return bishopmbcjmstojis();
|
||||
}
|
||||
|
||||
bool Bishop2::attach_function(){
|
||||
|
||||
//三射面談~連鎖する恥辱・調教の学園~
|
||||
//特別授業3SLG
|
||||
auto entry=Util::FindImportEntry(processStartAddress,(DWORD)GetGlyphOutlineW);
|
||||
if(entry==0)return false;
|
||||
bool ok=false;
|
||||
for(auto addr:Util::SearchMemory(&entry, 4, PAGE_EXECUTE, processStartAddress, processStopAddress)){
|
||||
addr = MemDbg::findEnclosingAlignedFunction(addr);
|
||||
if (!addr) continue;
|
||||
auto xrefs=findxref_reverse_checkcallop(addr,max(processStartAddress,addr-0x100000),min(processStopAddress,addr+0x100000),0xe8);
|
||||
for(auto addrx:xrefs){
|
||||
//ConsoleOutput("xref %p",addrx);
|
||||
const BYTE aligned [] = {0xCC,0xCC};
|
||||
auto addrx1 = reverseFindBytes(aligned, sizeof(aligned), addrx-0x200, addrx);
|
||||
//ConsoleOutput("Aligned %p",addrx1);
|
||||
if (!addrx1) continue;
|
||||
addrx1+=2;
|
||||
BYTE __1[]={0xDC,0x0D,XX,XX,XX,0x00};
|
||||
auto _1 = MemDbg::findBytes(__1, 6, addrx-0x30, addrx);
|
||||
//ConsoleOutput("sig %p",_1);
|
||||
if(_1==0 )continue;
|
||||
BYTE checkthiscall[]={0x8B,0xF9};//mov edi, ecx
|
||||
auto _3 = MemDbg::findBytes(checkthiscall,2, addrx1, addrx);
|
||||
HookParam hp;
|
||||
hp.address = addrx1;
|
||||
if(_3)
|
||||
hp.offset=get_stack(3);
|
||||
else
|
||||
hp.offset=get_stack(4);
|
||||
hp.type = CODEC_UTF16;
|
||||
|
||||
ok=NewHook(hp, "Bishop2");
|
||||
}
|
||||
}
|
||||
return ok;
|
||||
}
|
24
cpp/LunaHook/LunaHook/engine32/Bishop.h
Normal file
24
cpp/LunaHook/LunaHook/engine32/Bishop.h
Normal file
@ -0,0 +1,24 @@
|
||||
|
||||
|
||||
class Bishop:public ENGINE{
|
||||
public:
|
||||
Bishop(){
|
||||
|
||||
check_by=CHECK_BY::FILE;
|
||||
check_by_target=L"GRAPHICS\\PACK.PK";
|
||||
is_engine_certain=false;
|
||||
};
|
||||
bool attach_function();
|
||||
};
|
||||
|
||||
|
||||
class Bishop2:public ENGINE{
|
||||
public:
|
||||
Bishop2(){
|
||||
|
||||
check_by=CHECK_BY::FILE;
|
||||
check_by_target=L"*.bsa";
|
||||
is_engine_certain=false;
|
||||
};
|
||||
bool attach_function();
|
||||
};
|
260
cpp/LunaHook/LunaHook/engine32/Bootup.cpp
Normal file
260
cpp/LunaHook/LunaHook/engine32/Bootup.cpp
Normal file
@ -0,0 +1,260 @@
|
||||
#include"Bootup.h"
|
||||
|
||||
/**
|
||||
* jichi 5/22/2015: Insert Bootup hook
|
||||
* Sample games:
|
||||
* - [090709] [PIL] 仏蘭西少女
|
||||
* - [110318] [Daisy2] 三国恋戦<EFBFBD> * - [110329] [PIL/SLASH] 神学校
|
||||
* - [150527] [Daisy2] 絶対階級学<EFBFBD> *
|
||||
* Properties
|
||||
* - There is Bootup.dat existing in the game folder.
|
||||
* - lstrlenW can find text repeating once
|
||||
* - GetCharABCWidthsW and TextOutW can find cached text that missing characters
|
||||
* GetCharABCWidthsA and TextOutA for old games.
|
||||
* - There is only one TextOut (W for new and A for old).
|
||||
*
|
||||
* Logic:
|
||||
* + GDI hook
|
||||
* - Hook to the caller of TextOut
|
||||
* + Lstr hook
|
||||
* - Find last (second) caller of the first GetCharABCWidths after int3
|
||||
* - Find the lstrlen function in this caller, and hook to it
|
||||
*
|
||||
* Full text is in arg1, shifted one by one.
|
||||
* Character to paint is also in arg3
|
||||
*
|
||||
* All Bootup games are slightly different
|
||||
* - 三国恋戦<EFBFBD>仏蘭西少女: text in both lstrlenA and caller of TextOutA
|
||||
* But I didn't find correct lstrlenA to hook. BootupLstrA find nothing for 仏蘭西少女 and name for 三国恋戦<EFBFBD>
|
||||
* - 神学校: text in both lstrlenW and TextOutW, but lstrlenW has repetition
|
||||
* Caller of TextOutW the same as that of TextOutA
|
||||
* - 絶対階級学<EFBFBD> text in both lstrlenW and TextOutW. But TextOutW's name has repetition
|
||||
* Caller of TextOutW different 神学校
|
||||
*
|
||||
* Here's the beginning of caller of TextOutW in 絶対階級学<EFBFBD>
|
||||
* 00B61ADD CC INT3
|
||||
* 00B61ADE CC INT3
|
||||
* 00B61ADF CC INT3
|
||||
* 00B61AE0 55 PUSH EBP
|
||||
* 00B61AE1 8BEC MOV EBP,ESP
|
||||
* 00B61AE3 81EC 98000000 SUB ESP,0x98
|
||||
* 00B61AE9 53 PUSH EBX
|
||||
* 00B61AEA 56 PUSH ESI
|
||||
* 00B61AEB 57 PUSH EDI
|
||||
* 00B61AEC 8BF2 MOV ESI,EDX
|
||||
* 00B61AEE 8BF9 MOV EDI,ECX
|
||||
* 00B61AF0 8975 D8 MOV DWORD PTR SS:[EBP-0x28],ESI
|
||||
* 00B61AF3 897D E0 MOV DWORD PTR SS:[EBP-0x20],EDI
|
||||
* 00B61AF6 E8 A5FEFFFF CALL .00B619A0
|
||||
* 00B61AFB 8BD8 MOV EBX,EAX
|
||||
* 00B61AFD 895D CC MOV DWORD PTR SS:[EBP-0x34],EBX
|
||||
* 00B61B00 66:833B 00 CMP WORD PTR DS:[EBX],0x0
|
||||
* 00B61B04 0F85 0B020000 JNZ .00B61D15
|
||||
* 00B61B0A B8 00010000 MOV EAX,0x100
|
||||
* 00B61B0F 66:8933 MOV WORD PTR DS:[EBX],SI
|
||||
* 00B61B12 66:3BF0 CMP SI,AX
|
||||
* 00B61B15 72 26 JB SHORT .00B61B3D
|
||||
* 00B61B17 8B47 3C MOV EAX,DWORD PTR DS:[EDI+0x3C]
|
||||
* 00B61B1A 85C0 TEST EAX,EAX
|
||||
* 00B61B1C 74 1F JE SHORT .00B61B3D
|
||||
* 00B61B1E 8B57 44 MOV EDX,DWORD PTR DS:[EDI+0x44]
|
||||
* 00B61B21 85D2 TEST EDX,EDX
|
||||
* 00B61B23 7E 18 JLE SHORT .00B61B3D
|
||||
* 00B61B25 33C9 XOR ECX,ECX
|
||||
* 00B61B27 85D2 TEST EDX,EDX
|
||||
* 00B61B29 7E 12 JLE SHORT .00B61B3D
|
||||
* 00B61B2B 8B47 40 MOV EAX,DWORD PTR DS:[EDI+0x40]
|
||||
* 00B61B2E 8BFF MOV EDI,EDI
|
||||
* 00B61B30 66:3930 CMP WORD PTR DS:[EAX],SI
|
||||
* 00B61B33 74 6F JE SHORT .00B61BA4
|
||||
* 00B61B35 41 INC ECX
|
||||
* 00B61B36 83C0 02 ADD EAX,0x2
|
||||
* 00B61B39 3BCA CMP ECX,EDX
|
||||
* 00B61B3B ^7C F3 JL SHORT .00B61B30
|
||||
* 00B61B3D 33C0 XOR EAX,EAX
|
||||
* 00B61B3F 66:8945 9E MOV WORD PTR SS:[EBP-0x62],AX
|
||||
* 00B61B43 8B47 04 MOV EAX,DWORD PTR DS:[EDI+0x4]
|
||||
* 00B61B46 0FAF47 1C IMUL EAX,DWORD PTR DS:[EDI+0x1C]
|
||||
* 00B61B4A 0FAF47 1C IMUL EAX,DWORD PTR DS:[EDI+0x1C]
|
||||
* 00B61B4E 0FAF47 18 IMUL EAX,DWORD PTR DS:[EDI+0x18]
|
||||
* 00B61B52 50 PUSH EAX
|
||||
* 00B61B53 6A 00 PUSH 0x0
|
||||
* 00B61B55 FF77 14 PUSH DWORD PTR DS:[EDI+0x14]
|
||||
* 00B61B58 66:8975 9C MOV WORD PTR SS:[EBP-0x64],SI
|
||||
* 00B61B5C E8 2FC20200 CALL .00B8DD90
|
||||
* 00B61B61 83C4 0C ADD ESP,0xC
|
||||
* 00B61B64 8D45 9C LEA EAX,DWORD PTR SS:[EBP-0x64]
|
||||
* 00B61B67 6A 01 PUSH 0x1
|
||||
* 00B61B69 50 PUSH EAX
|
||||
* 00B61B6A 6A 00 PUSH 0x0
|
||||
* 00B61B6C 6A 00 PUSH 0x0
|
||||
* 00B61B6E FF77 10 PUSH DWORD PTR DS:[EDI+0x10]
|
||||
* 00B61B71 FF15 8820BB00 CALL DWORD PTR DS:[0xBB2088] ; gdi32.TextOutW
|
||||
* 00B61B77 8B47 1C MOV EAX,DWORD PTR DS:[EDI+0x1C]
|
||||
* 00B61B7A 8B57 14 MOV EDX,DWORD PTR DS:[EDI+0x14]
|
||||
* 00B61B7D 8B7F 04 MOV EDI,DWORD PTR DS:[EDI+0x4]
|
||||
* 00B61B80 8B73 0C MOV ESI,DWORD PTR DS:[EBX+0xC]
|
||||
* 00B61B83 0FAFF8 IMUL EDI,EAX
|
||||
* 00B61B86 48 DEC EAX
|
||||
* 00B61B87 8975 C4 MOV DWORD PTR SS:[EBP-0x3C],ESI
|
||||
* 00B61B8A 897D C8 MOV DWORD PTR SS:[EBP-0x38],EDI
|
||||
*
|
||||
* TextOutW's caller for 神学校
|
||||
* 0113183E CC INT3
|
||||
* 0113183F CC INT3
|
||||
* 01131840 55 PUSH EBP
|
||||
* 01131841 8BEC MOV EBP,ESP
|
||||
* 01131843 83EC 74 SUB ESP,0x74
|
||||
* 01131846 53 PUSH EBX
|
||||
* 01131847 56 PUSH ESI
|
||||
* 01131848 8B75 08 MOV ESI,DWORD PTR SS:[EBP+0x8]
|
||||
* 0113184B 57 PUSH EDI
|
||||
* 0113184C 8B7D 0C MOV EDI,DWORD PTR SS:[EBP+0xC]
|
||||
* 0113184F 8BCF MOV ECX,EDI
|
||||
* 01131851 8BD6 MOV EDX,ESI
|
||||
* 01131853 E8 A8FEFFFF CALL .01131700
|
||||
* 01131858 8BD8 MOV EBX,EAX
|
||||
* 0113185A 66:833B 00 CMP WORD PTR DS:[EBX],0x0
|
||||
* 0113185E 895D 90 MOV DWORD PTR SS:[EBP-0x70],EBX
|
||||
* 01131861 0F85 700F0000 JNZ .011327D7
|
||||
* 01131867 B8 00010000 MOV EAX,0x100
|
||||
* 0113186C 66:893B MOV WORD PTR DS:[EBX],DI
|
||||
* 0113186F 66:3BF8 CMP DI,AX
|
||||
* 01131872 72 2E JB SHORT .011318A2
|
||||
* 01131874 8B56 3C MOV EDX,DWORD PTR DS:[ESI+0x3C]
|
||||
* 01131877 85D2 TEST EDX,EDX
|
||||
* 01131879 74 27 JE SHORT .011318A2
|
||||
* 0113187B 8B46 44 MOV EAX,DWORD PTR DS:[ESI+0x44]
|
||||
* 0113187E 85C0 TEST EAX,EAX
|
||||
* 01131880 7E 20 JLE SHORT .011318A2
|
||||
* 01131882 33FF XOR EDI,EDI
|
||||
* 01131884 85C0 TEST EAX,EAX
|
||||
* 01131886 7E 1A JLE SHORT .011318A2
|
||||
* 01131888 8B46 40 MOV EAX,DWORD PTR DS:[ESI+0x40]
|
||||
* 0113188B EB 03 JMP SHORT .01131890
|
||||
* 0113188D 8D49 00 LEA ECX,DWORD PTR DS:[ECX]
|
||||
* 01131890 66:8B4D 0C MOV CX,WORD PTR SS:[EBP+0xC]
|
||||
* 01131894 66:3908 CMP WORD PTR DS:[EAX],CX
|
||||
* 01131897 74 74 JE SHORT .0113190D
|
||||
* 01131899 47 INC EDI
|
||||
* 0113189A 83C0 02 ADD EAX,0x2
|
||||
* 0113189D 3B7E 44 CMP EDI,DWORD PTR DS:[ESI+0x44]
|
||||
* 011318A0 ^7C EE JL SHORT .01131890
|
||||
* 011318A2 66:8B45 0C MOV AX,WORD PTR SS:[EBP+0xC]
|
||||
* 011318A6 66:8945 8C MOV WORD PTR SS:[EBP-0x74],AX
|
||||
* 011318AA 8B46 1C MOV EAX,DWORD PTR DS:[ESI+0x1C]
|
||||
* 011318AD 0FAFC0 IMUL EAX,EAX
|
||||
* 011318B0 0FAF46 18 IMUL EAX,DWORD PTR DS:[ESI+0x18]
|
||||
* 011318B4 0FAF46 04 IMUL EAX,DWORD PTR DS:[ESI+0x4]
|
||||
* 011318B8 8B56 14 MOV EDX,DWORD PTR DS:[ESI+0x14]
|
||||
* 011318BB 33C9 XOR ECX,ECX
|
||||
* 011318BD 50 PUSH EAX
|
||||
* 011318BE 51 PUSH ECX
|
||||
* 011318BF 52 PUSH EDX
|
||||
* 011318C0 66:894D 8E MOV WORD PTR SS:[EBP-0x72],CX
|
||||
* 011318C4 E8 87060200 CALL .01151F50
|
||||
* 011318C9 8B4E 10 MOV ECX,DWORD PTR DS:[ESI+0x10]
|
||||
* 011318CC 83C4 0C ADD ESP,0xC
|
||||
* 011318CF 6A 01 PUSH 0x1
|
||||
* 011318D1 8D45 8C LEA EAX,DWORD PTR SS:[EBP-0x74]
|
||||
* 011318D4 50 PUSH EAX
|
||||
* 011318D5 6A 00 PUSH 0x0
|
||||
* 011318D7 6A 00 PUSH 0x0
|
||||
* 011318D9 51 PUSH ECX
|
||||
* 011318DA FF15 38101701 CALL DWORD PTR DS:[0x1171038] ; gdi32.TextOutW
|
||||
* 011318E0 8B4E 1C MOV ECX,DWORD PTR DS:[ESI+0x1C]
|
||||
* 011318E3 8B46 04 MOV EAX,DWORD PTR DS:[ESI+0x4]
|
||||
* 011318E6 8B56 14 MOV EDX,DWORD PTR DS:[ESI+0x14]
|
||||
* 011318E9 0FAFC1 IMUL EAX,ECX
|
||||
* 011318EC 8B7B 0C MOV EDI,DWORD PTR DS:[EBX+0xC]
|
||||
*/
|
||||
namespace { // unnamed
|
||||
|
||||
bool InsertBootupGDIHook()
|
||||
{
|
||||
bool widechar = true;
|
||||
ULONG addr = MemDbg::findCallerAddressAfterInt3((ULONG)TextOutW, processStartAddress, processStopAddress);
|
||||
if (!addr) {
|
||||
addr = MemDbg::findCallerAddressAfterInt3((ULONG)TextOutA, processStartAddress, processStopAddress);
|
||||
widechar = false;
|
||||
}
|
||||
if (!addr) {
|
||||
ConsoleOutput("BootupGDI: failed to find TextOut");
|
||||
return false;
|
||||
}
|
||||
|
||||
HookParam hp;
|
||||
hp.address = addr;
|
||||
hp.type = USING_SPLIT|NO_CONTEXT|USING_CHAR; // use NO_CONTEXT to get rid of floating reladdr
|
||||
hp.type |= widechar ? CODEC_UTF16 : CODEC_ANSI_BE; // use context as split is sufficient, but will produce floating split
|
||||
|
||||
|
||||
hp.offset=get_stack(2); // arg2, character in arg2, could be modified by hook
|
||||
if (widechar)
|
||||
hp.split = get_reg(regs::edx);
|
||||
else
|
||||
hp.split = get_stack(1);
|
||||
hp.text_fun =
|
||||
[](hook_stack* stack, HookParam* hp, TextBuffer *buffer, uintptr_t *split)
|
||||
{
|
||||
DWORD arg2 = stack->stack[2];
|
||||
if ((arg2 & 0xffff0000)) { // if arg2 high bits are there, this is new Bootup game
|
||||
hp->type |= DATA_INDIRECT;
|
||||
hp->offset = get_stack(3);
|
||||
hp->split = get_reg(regs::ebx);
|
||||
}
|
||||
hp->text_fun=nullptr;
|
||||
};
|
||||
|
||||
ConsoleOutput("INSERT BootupGDI");
|
||||
|
||||
|
||||
ConsoleOutput("BootupGDI: disable GDI hooks");
|
||||
|
||||
return NewHook(hp, widechar ? "BootupW" : "BootupA");
|
||||
}
|
||||
bool InsertBootupLstrHook() // for character name
|
||||
{
|
||||
bool widechar = true;
|
||||
ULONG addr = MemDbg::findLastCallerAddressAfterInt3((ULONG)GetCharABCWidthsW, processStartAddress, processStopAddress);
|
||||
if (!addr) {
|
||||
// Do not hook to lstrlenA, which causes text extraction to stop
|
||||
//addr = MemDbg::findLastCallerAddressAfterInt3((ULONG)GetCharABCWidthsA, processStartAddress, processStopAddress);
|
||||
//widechar = false;
|
||||
}
|
||||
if (!addr) {
|
||||
ConsoleOutput("BootupLstr: failed to find GetCharABCWidths");
|
||||
return false;
|
||||
}
|
||||
//GROWL_DWORD2(addr, processStartAddress);
|
||||
//enum { range = 0x200 }; // 0x012A2CCB - 0x12A2CB0 = 0x1b
|
||||
addr = MemDbg::findCallAddress(widechar ? (ULONG)::lstrlenW : (ULONG)::lstrlenA,
|
||||
processStartAddress, processStopAddress,
|
||||
addr - processStartAddress); //, range); // no range
|
||||
if (!addr) {
|
||||
ConsoleOutput("BootupLstr: failed to find lstrlen");
|
||||
return false;
|
||||
}
|
||||
|
||||
HookParam hp;
|
||||
hp.address = addr;
|
||||
hp.type = widechar ? (USING_STRING|CODEC_UTF16) : USING_STRING; // use context as split is sufficient, but will produce floating split
|
||||
//hp.type = CODEC_UTF16|NO_CONTEXT|USING_SPLIT; // use text address as split
|
||||
//hp.split = 0;
|
||||
|
||||
ConsoleOutput("INSERT BootupLstr");
|
||||
|
||||
return NewHook(hp, widechar ? "BootupLstrW" : "BootupLstrA");
|
||||
}
|
||||
} // unnamed namespace
|
||||
bool InsertBootupHook()
|
||||
{
|
||||
bool ret = InsertBootupGDIHook();
|
||||
InsertBootupLstrHook();
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool Bootup::attach_function() {
|
||||
|
||||
return InsertBootupHook();
|
||||
}
|
13
cpp/LunaHook/LunaHook/engine32/Bootup.h
Normal file
13
cpp/LunaHook/LunaHook/engine32/Bootup.h
Normal file
@ -0,0 +1,13 @@
|
||||
|
||||
|
||||
class Bootup:public ENGINE{
|
||||
public:
|
||||
Bootup(){
|
||||
|
||||
check_by=CHECK_BY::FILE;
|
||||
check_by_target=L"Bootup.dat";
|
||||
is_engine_certain=false;
|
||||
// lstrlenW can also find text with repetition though
|
||||
};
|
||||
bool attach_function();
|
||||
};
|
80
cpp/LunaHook/LunaHook/engine32/Bruns.cpp
Normal file
80
cpp/LunaHook/LunaHook/engine32/Bruns.cpp
Normal file
@ -0,0 +1,80 @@
|
||||
#include"Bruns.h"
|
||||
|
||||
bool InsertBrunsHook()
|
||||
{
|
||||
bool success=false;
|
||||
if (Util::CheckFile(L"libscr.dll")) {
|
||||
HookParam hp;
|
||||
hp.offset=get_stack(1);
|
||||
hp.type = CODEC_UTF16;
|
||||
//?push_back@?$basic_string@GU?$char_traits@G@std@@V?$allocator@G@2@@std@@QAEXG@Z
|
||||
if (Util::CheckFile(L"msvcp90.dll"))
|
||||
hp.address = (DWORD)GetProcAddress(GetModuleHandleW(L"msvcp90.dll"), "?push_back@?$basic_string@GU?$char_traits@G@std@@V?$allocator@G@2@@std@@QAEXG@Z");
|
||||
else if (Util::CheckFile(L"msvcp80.dll"))
|
||||
hp.address = (DWORD)GetProcAddress(GetModuleHandleW(L"msvcp80.dll"), "?push_back@?$basic_string@GU?$char_traits@G@std@@V?$allocator@G@2@@std@@QAEXG@Z");
|
||||
else if (Util::CheckFile(L"msvcp100.dll")) // jichi 8/17/2013: MSVCRT 10.0 and 11.0
|
||||
hp.address = (DWORD)GetProcAddress(GetModuleHandleW(L"msvcp100.dll"), "?push_back@?$basic_string@GU?$char_traits@G@std@@V?$allocator@G@2@@std@@QAEXG@Z");
|
||||
else if (Util::CheckFile(L"msvcp110.dll"))
|
||||
hp.address = (DWORD)GetProcAddress(GetModuleHandleW(L"msvcp110.dll"), "?push_back@?$basic_string@GU?$char_traits@G@std@@V?$allocator@G@2@@std@@QAEXG@Z");
|
||||
if (hp.address) {
|
||||
ConsoleOutput("INSERT Brus#1");
|
||||
success|=NewHook(hp, "Bruns");
|
||||
}
|
||||
}
|
||||
//else
|
||||
// jichi 12/21/2013: Keep both bruns hooks
|
||||
// The first one does not work for games like 「オーク・キングダマモン娘繁殖<E7B981>豚人王~<E78E8B>anymore.
|
||||
{
|
||||
union {
|
||||
DWORD i;
|
||||
DWORD *id;
|
||||
WORD *iw;
|
||||
BYTE *ib;
|
||||
};
|
||||
DWORD k = processStopAddress - 4;
|
||||
for (i = processStartAddress + 0x1000; i < k; i++) {
|
||||
if (*id != 0xff) //cmp reg,0xff
|
||||
continue;
|
||||
i += 4;
|
||||
if (*iw != 0x8f0f)
|
||||
continue;//jg
|
||||
i += 2;
|
||||
i += *id + 4;
|
||||
for (DWORD j = i + 0x40; i < j; i++) {
|
||||
if (*ib != 0xe8)
|
||||
continue;
|
||||
i++;
|
||||
DWORD t = i + 4 + *id;
|
||||
if (t > processStartAddress && t <processStopAddress) {
|
||||
i = t;
|
||||
for (j = i + 0x80; i < j; i++) {
|
||||
if (*ib != 0xe8)
|
||||
continue;
|
||||
i++;
|
||||
t = i + 4 + *id;
|
||||
if (t > processStartAddress && t <processStopAddress) {
|
||||
|
||||
HookParam hp;
|
||||
hp.address = t;
|
||||
hp.offset=get_stack(1);
|
||||
hp.type = CODEC_UTF16|DATA_INDIRECT;
|
||||
ConsoleOutput("INSERT Brus#2");
|
||||
|
||||
return NewHook(hp, "Bruns2");
|
||||
}
|
||||
}
|
||||
k = i; //Terminate outer loop.
|
||||
break; //Terminate inner loop.
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//ConsoleOutput("Unknown Bruns engine.");
|
||||
ConsoleOutput("Brus: failed");
|
||||
return success;
|
||||
}
|
||||
|
||||
bool Bruns::attach_function() {
|
||||
|
||||
return InsertBrunsHook();
|
||||
}
|
29
cpp/LunaHook/LunaHook/engine32/Bruns.h
Normal file
29
cpp/LunaHook/LunaHook/engine32/Bruns.h
Normal file
@ -0,0 +1,29 @@
|
||||
|
||||
|
||||
class Bruns:public ENGINE{
|
||||
public:
|
||||
Bruns(){
|
||||
|
||||
check_by=CHECK_BY::CUSTOM;
|
||||
is_engine_certain=false;
|
||||
check_by_target=[](){
|
||||
return Util::CheckFile(L"args.txt")||(wcsstr(processName_lower, L"bruns") || Util::CheckFile(L"bruns.exe"));
|
||||
|
||||
};
|
||||
//check_by=CHECK_BY::FILE;
|
||||
//check_by_target=L"args.txt";
|
||||
//if (Util::CheckFile(L"libscr.dll")) { // already checked
|
||||
// InsertBrunsHook();
|
||||
// return true;
|
||||
//}
|
||||
|
||||
// jichi 10/12/2013: Sample args.txt:
|
||||
// See: http://tieba.baidu.com/p/2631413816
|
||||
// -workdir
|
||||
// .
|
||||
// -loadpath
|
||||
// .
|
||||
// am.cfg
|
||||
};
|
||||
bool attach_function();
|
||||
};
|
29
cpp/LunaHook/LunaHook/engine32/C4.cpp
Normal file
29
cpp/LunaHook/LunaHook/engine32/C4.cpp
Normal file
@ -0,0 +1,29 @@
|
||||
#include"C4.h"
|
||||
|
||||
/********************************************************************************************
|
||||
C4 hook: (Contributed by Stomp)
|
||||
Game folder contains C4.EXE or XEX.EXE.
|
||||
********************************************************************************************/
|
||||
bool InsertC4Hook()
|
||||
{
|
||||
const BYTE bytes[] = { 0x8a, 0x10, 0x40, 0x80, 0xfa, 0x5f, 0x88, 0x15 };
|
||||
//enum { addr_offset = 0 };
|
||||
ULONG addr = MemDbg::findBytes(bytes, sizeof(bytes), processStartAddress, processStopAddress);
|
||||
if (!addr) {
|
||||
ConsoleOutput("C4: pattern not found");
|
||||
return false;
|
||||
}
|
||||
HookParam hp;
|
||||
hp.address = addr;
|
||||
hp.offset=get_reg(regs::eax);
|
||||
hp.type = DATA_INDIRECT|NO_CONTEXT;
|
||||
ConsoleOutput("INSERT C4");
|
||||
|
||||
//RegisterEngineType(ENGINE_C4);
|
||||
return NewHook(hp, "C4");
|
||||
}
|
||||
|
||||
bool C4::attach_function() {
|
||||
|
||||
return InsertC4Hook();
|
||||
}
|
11
cpp/LunaHook/LunaHook/engine32/C4.h
Normal file
11
cpp/LunaHook/LunaHook/engine32/C4.h
Normal file
@ -0,0 +1,11 @@
|
||||
|
||||
|
||||
class C4:public ENGINE{
|
||||
public:
|
||||
C4(){
|
||||
|
||||
check_by=CHECK_BY::FILE_ANY;
|
||||
check_by_target=check_by_list{L"C4.EXE",L"XEX.EXE"};
|
||||
};
|
||||
bool attach_function();
|
||||
};
|
1519
cpp/LunaHook/LunaHook/engine32/CMVS.cpp
Normal file
1519
cpp/LunaHook/LunaHook/engine32/CMVS.cpp
Normal file
File diff suppressed because it is too large
Load Diff
18
cpp/LunaHook/LunaHook/engine32/CMVS.h
Normal file
18
cpp/LunaHook/LunaHook/engine32/CMVS.h
Normal file
@ -0,0 +1,18 @@
|
||||
|
||||
|
||||
class CMVS:public ENGINE{
|
||||
public:
|
||||
CMVS(){
|
||||
|
||||
check_by=CHECK_BY::FILE;
|
||||
check_by_target=L"data\\pack\\*.cpz";
|
||||
|
||||
|
||||
// jichi 8/19/2013: DO NOT WORK for games like「ハピメア」
|
||||
//if (wcsstr(str,L"cmvs32") || wcsstr(str,L"cmvs64")) {
|
||||
// InsertCMVSHook();
|
||||
// return true;
|
||||
//}
|
||||
};
|
||||
bool attach_function();
|
||||
};
|
75
cpp/LunaHook/LunaHook/engine32/Cage.cpp
Normal file
75
cpp/LunaHook/LunaHook/engine32/Cage.cpp
Normal file
@ -0,0 +1,75 @@
|
||||
#include "Cage.h"
|
||||
|
||||
bool Cage::attach_function()
|
||||
{
|
||||
// https://vndb.org/v8381
|
||||
// 夢姿 ~ゆめのすがた~
|
||||
/*
|
||||
size_t __cdecl _mbslen(const unsigned __int8 *String)
|
||||
{
|
||||
const unsigned __int8 *v2; // eax
|
||||
size_t i; // esi
|
||||
|
||||
if ( !dword_476AFC )
|
||||
return strlen((const char *)String);
|
||||
_lock(25);
|
||||
v2 = String;
|
||||
for ( i = 0; *v2; ++i )
|
||||
{
|
||||
if ( (byte_476C01[*v2] & 4) != 0 && !*++v2 )
|
||||
break;
|
||||
++v2;
|
||||
}
|
||||
_unlock(25);
|
||||
return i;
|
||||
}
|
||||
*/
|
||||
/*
|
||||
.text:00451B0C mov eax, [esp+8+String]
|
||||
.text:00451B10 pop ecx
|
||||
.text:00451B11 xor esi, esi
|
||||
.text:00451B13
|
||||
.text:00451B13 loc_451B13: ; CODE XREF: __mbslen+3D↓j
|
||||
.text:00451B13 mov cl, [eax]
|
||||
.text:00451B15 test cl, cl
|
||||
.text:00451B17 jz short loc_451B2F
|
||||
.text:00451B19 movzx ecx, cl
|
||||
.text:00451B1C test byte_476C01[ecx], 4
|
||||
.text:00451B23 jz short loc_451B2B
|
||||
.text:00451B25 inc eax
|
||||
.text:00451B26 cmp byte ptr [eax], 0
|
||||
.text:00451B29 jz short loc_451B2F
|
||||
.text:00451B2B
|
||||
.text:00451B2B loc_451B2B: ; CODE XREF: __mbslen+33↑j
|
||||
.text:00451B2B inc esi
|
||||
.text:00451B2C inc eax
|
||||
.text:00451B2D jmp short loc_451B13
|
||||
*/
|
||||
BYTE check[] = {
|
||||
0x8B, 0x44, 0x24, 0x0C,
|
||||
0x59,
|
||||
0x33, 0xF6,
|
||||
0x8A, 0x08,
|
||||
0x84, 0xC9,
|
||||
0x74, 0x16,
|
||||
0x0F, 0xB6, 0xC9,
|
||||
0xF6, 0x81, XX4, 0x04,
|
||||
0x74, 0x06,
|
||||
0x40,
|
||||
0x80, 0x38, 0x00,
|
||||
0x74, 0x04,
|
||||
0x46,
|
||||
0x40,
|
||||
0xEB, 0xE4};
|
||||
auto addrx = MemDbg::findBytes(check, sizeof(check), processStartAddress, processStopAddress);
|
||||
if (!addrx)
|
||||
return false;
|
||||
addrx = MemDbg::findEnclosingAlignedFunction(addrx);
|
||||
if (!addrx)
|
||||
return 0;
|
||||
HookParam hp;
|
||||
hp.address = addrx;
|
||||
hp.type = USING_STRING;
|
||||
hp.offset = get_stack(1);
|
||||
return NewHook(hp, "Cage");
|
||||
}
|
14
cpp/LunaHook/LunaHook/engine32/Cage.h
Normal file
14
cpp/LunaHook/LunaHook/engine32/Cage.h
Normal file
@ -0,0 +1,14 @@
|
||||
|
||||
|
||||
class Cage : public ENGINE
|
||||
{
|
||||
public:
|
||||
Cage()
|
||||
{
|
||||
// https://vndb.org/v8381
|
||||
// 夢姿 ~ゆめのすがた~
|
||||
check_by = CHECK_BY::FILE_ALL;
|
||||
check_by_target = check_by_list{L"script.msb", L"data*.ym"};
|
||||
};
|
||||
bool attach_function();
|
||||
};
|
362
cpp/LunaHook/LunaHook/engine32/Candy.cpp
Normal file
362
cpp/LunaHook/LunaHook/engine32/Candy.cpp
Normal file
@ -0,0 +1,362 @@
|
||||
#include "Candy.h"
|
||||
|
||||
/********************************************************************************************
|
||||
CandySoft hook:
|
||||
Game folder contains many *.fpk. Engine name is SystemC.
|
||||
I haven't seen this engine in other company/brand.
|
||||
|
||||
AGTH /X3 will hook lstrlenA. One thread is the exactly result we want.
|
||||
But the function call is difficult to located programmatically.
|
||||
I find a equivalent points which is more easy to search.
|
||||
The script processing function needs to find 0x5B'[',
|
||||
so there should a instruction like cmp reg,5B
|
||||
Find this position and navigate to function entry.
|
||||
The first parameter is the string pointer.
|
||||
This approach works fine with game later than つよきす2学<EFBFBD>
|
||||
|
||||
But the original つよき<EFBFBD>is quite different. I handle this case separately.
|
||||
|
||||
********************************************************************************************/
|
||||
namespace
|
||||
{
|
||||
// https://vndb.org/v23666
|
||||
//(18禁ゲーム) [180928] [INTERHEART glossy] はらかつ!3 ~子作りビジネス廃業の危機!?~ (iso+mds+rr3)
|
||||
// https://vndb.org/v47957
|
||||
//[240222][1261652][DESSERT Soft] 二股野郎とパパ活姉妹 パッケージ版 (mdf+mds)
|
||||
// https://vndb.org/v20368
|
||||
//[170224] [Sweet HEART] アイドル★クリニック 恋の薬でHな処方 (iso+mds+rr3)
|
||||
bool filter(LPVOID data, size_t *size, HookParam *)
|
||||
{
|
||||
StringFilter((char *)data, size, "$L", 2);
|
||||
StringFilter((char *)data, size, "$M", 2);
|
||||
StringFilter((char *)data, size, "$S", 2);
|
||||
StringFilterBetween((char *)data, size, "[", 1, "]", 1);
|
||||
StringFilterBetween((char *)data, size, "&", 1, ";", 1);
|
||||
return true;
|
||||
// else
|
||||
// {
|
||||
// v18 = *v16++;
|
||||
// switch ( v18 )
|
||||
// {
|
||||
// case '$':
|
||||
// switch ( *v16 )
|
||||
// {
|
||||
// case 0:
|
||||
// goto LABEL_44;
|
||||
// case 76:
|
||||
// v15 = 3;
|
||||
// break;
|
||||
// case 77:
|
||||
// if ( v15 < 2 )
|
||||
// v15 = 2;
|
||||
// break;
|
||||
// default:
|
||||
// if ( *v16 == 83 && !v15 )
|
||||
// v15 = 1;
|
||||
// break;
|
||||
// }
|
||||
// break;
|
||||
// case '[':
|
||||
// for ( i = *v16; i; i = *++v16 )
|
||||
// {
|
||||
// if ( i == 93 )
|
||||
// break;
|
||||
// }
|
||||
// break;
|
||||
// case '&':
|
||||
// for ( j = *v16; j; j = *++v16 )
|
||||
// {
|
||||
// if ( j == 59 )
|
||||
// break;
|
||||
// }
|
||||
// break;
|
||||
// default:
|
||||
// goto LABEL_43;
|
||||
// }
|
||||
// ++v16;
|
||||
// }
|
||||
}
|
||||
uintptr_t hh()
|
||||
{
|
||||
// void __usercall sub_425580(char *a1@<edx>, int a2@<ecx>, int a3)
|
||||
BYTE bytes[] = {
|
||||
0x3c, 0x24,
|
||||
0x75, XX,
|
||||
0x80, 0x7e, 0x01, 0x00,
|
||||
0x74, XX,
|
||||
0x83, XX, 0x02,
|
||||
0x83, XX, 0x02};
|
||||
auto addr = MemDbg::findBytes(bytes, sizeof(bytes), processStartAddress, processStopAddress);
|
||||
if (!addr)
|
||||
return 0;
|
||||
addr = findfuncstart(addr, 0x400);
|
||||
return addr;
|
||||
}
|
||||
}
|
||||
|
||||
namespace
|
||||
{ // unnamed Candy
|
||||
|
||||
// jichi 8/23/2013: split into two different engines
|
||||
// if (_wcsicmp(processName, L"systemc.exe")==0)
|
||||
// Process name is "SystemC.exe"
|
||||
bool InsertCandyHook1()
|
||||
{
|
||||
for (DWORD i = processStartAddress + 0x1000; i < processStopAddress - 4; i++)
|
||||
if ((*(DWORD *)i & 0xffffff) == 0x24f980) // cmp cl,24
|
||||
for (DWORD j = i, k = i - 0x100; j > k; j--)
|
||||
if (*(DWORD *)j == 0xc0330a8a)
|
||||
{ // mov cl,[edx]; xor eax,eax
|
||||
HookParam hp;
|
||||
hp.address = j;
|
||||
hp.offset = get_reg(regs::edx);
|
||||
hp.type = USING_STRING;
|
||||
ConsoleOutput("INSERT SystemC#1");
|
||||
|
||||
// RegisterEngineType(ENGINE_CANDY);
|
||||
return NewHook(hp, "SystemC");
|
||||
}
|
||||
ConsoleOutput("CandyHook1: failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
uintptr_t __InsertCandyHook2()
|
||||
{
|
||||
for (DWORD i = processStartAddress + 0x1000; i < processStopAddress - 4; i++)
|
||||
if (*(WORD *)i == 0x5b3c || // cmp al,0x5b
|
||||
(*(DWORD *)i & 0xfff8fc) == 0x5bf880) // cmp reg,0x5B
|
||||
for (DWORD j = i, k = i - 0x100; j > k; j--)
|
||||
if ((*(DWORD *)j & 0xffff) == 0x8b55)
|
||||
{ // push ebp, mov ebp,esp, sub esp,*
|
||||
return j;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
// jichi 8/23/2013: Process name is NOT "SystemC.exe"
|
||||
bool InsertCandyHook2()
|
||||
{
|
||||
auto addr1 = hh(); // 新版本的candy,但是有时会和旧版在同一个地址。当是同一个地址时,避让5个字节
|
||||
auto addr2 = __InsertCandyHook2();
|
||||
HookParam hp;
|
||||
hp.type = USING_STRING;
|
||||
hp.filter_fun = filter;
|
||||
if (addr2 == 0 && addr1 == 0)
|
||||
return false;
|
||||
else if (addr2 == 0 && addr1 != 0)
|
||||
{
|
||||
hp.address = addr1;
|
||||
hp.offset = get_reg(regs::edx);
|
||||
return NewHook(hp, "SystemC");
|
||||
}
|
||||
else if (addr2 != 0 && addr1 == 0)
|
||||
{
|
||||
hp.address = addr2;
|
||||
hp.offset = get_stack(1); // jichi: text in arg1
|
||||
return NewHook(hp, "SystemC");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (addr1 == addr2)
|
||||
{
|
||||
addr1 += 5;
|
||||
}
|
||||
hp.address = addr1;
|
||||
hp.offset = get_reg(regs::edx);
|
||||
auto succ = NewHook(hp, "SystemC");
|
||||
hp.address = addr2;
|
||||
hp.offset = get_stack(1);
|
||||
succ |= NewHook(hp, "SystemC");
|
||||
return succ;
|
||||
}
|
||||
}
|
||||
|
||||
/** jichi 10/2/2013: CHECKPOINT
|
||||
*
|
||||
* [5/31/2013] 恋もHもお勉強も、おまかせ<EFBFBD>お姉ちも<EFBFBD>部
|
||||
* base = 0xf20000
|
||||
* + シナリオ: /HSN-4@104A48:ANEBU.EXE
|
||||
* - off: 4294967288 = 0xfffffff8 = -8
|
||||
, - type: 1025 = 0x401
|
||||
* + 選択肢: /HSN-4@104FDD:ANEBU.EXE
|
||||
* - off: 4294967288 = 0xfffffff8 = -8
|
||||
* - type: 1089 = 0x441
|
||||
*/
|
||||
// bool InsertCandyHook3()
|
||||
//{
|
||||
// return false; // CHECKPOINT
|
||||
// const BYTE ins[] = {
|
||||
// 0x83,0xc4, 0x0c, // add esp,0xc ; hook here
|
||||
// 0x0f,0xb6,0xc0, // movzx eax,al
|
||||
// 0x85,0xc0, // test eax,eax
|
||||
// 0x75, 0x0e // jnz XXOO ; it must be 0xe, or there will be duplication
|
||||
// };
|
||||
// enum { addr_offset = 0 };
|
||||
// ULONG range = min(processStopAddress - processStartAddress, MAX_REL_ADDR);
|
||||
// ULONG reladdr = SearchPattern(processStartAddress, range, ins, sizeof(ins));
|
||||
// reladdr = 0x104a48;
|
||||
// GROWL_DWORD(processStartAddress);
|
||||
// //GROWL_DWORD3(reladdr, processStartAddress, range);
|
||||
// if (!reladdr)
|
||||
// return false;
|
||||
//
|
||||
// HookParam hp;
|
||||
// hp.address = processStartAddress + reladdr + addr_offset;
|
||||
// hp.offset=get_reg(regs::eax);
|
||||
// hp.type = USING_STRING|NO_CONTEXT;
|
||||
// NewHook(hp, "Candy");
|
||||
// return true;
|
||||
// }
|
||||
|
||||
} // unnamed Candy
|
||||
|
||||
namespace
|
||||
{
|
||||
bool candy3()
|
||||
{
|
||||
// お母さんは俺専用!~あなたの初めてを…母さんが貰ってア・ゲ・ル~
|
||||
// 茉莉子さん家の性事情 ~伯母さんは僕のモノ~
|
||||
const BYTE bytes[] = {
|
||||
0x24, // XX||XX2
|
||||
0x75};
|
||||
for (auto addr : Util::SearchMemory(bytes, sizeof(bytes), PAGE_EXECUTE))
|
||||
{
|
||||
ConsoleOutput("%x", addr);
|
||||
if ((*(BYTE *)(addr - 1) == 0x3c) || ((*(BYTE *)(addr - 2) == 0x83) && (*(BYTE *)(addr - 1) == 0xf9)))
|
||||
{
|
||||
addr = MemDbg::findEnclosingAlignedFunction(addr);
|
||||
if (addr == 0)
|
||||
continue;
|
||||
ConsoleOutput("!%x", addr);
|
||||
HookParam hp;
|
||||
hp.type = USING_STRING;
|
||||
if (*(BYTE *)addr == 0x55)
|
||||
hp.offset = get_stack(1);
|
||||
else if (*(BYTE *)addr == 0x56)
|
||||
hp.offset = get_reg(regs::eax);
|
||||
else
|
||||
continue;
|
||||
hp.address = addr;
|
||||
|
||||
return NewHook(hp, "candy3");
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
bool InsertCandyHook3()
|
||||
{
|
||||
|
||||
/*
|
||||
* Sample games:
|
||||
* https://vndb.org/v24878
|
||||
*/
|
||||
const BYTE bytes[] = {
|
||||
0xCC, // int 3
|
||||
0x55, // push ebp << hook here
|
||||
0x8B, 0xEC, // mov ebp,esp
|
||||
0x6A, 0xFF, // push -01
|
||||
0x68, XX4, // push iinari-omnibus.exe+C4366
|
||||
0x64, 0xA1, 0x00, 0x00, 0x00, 0x00, // mov eax,fs:[00000000]
|
||||
0x50, // push eax
|
||||
0x83, 0xEC, 0x74, // sub esp,74
|
||||
0x53, // push ebx
|
||||
0x56, // push esi
|
||||
0x57 // push edi
|
||||
};
|
||||
|
||||
ULONG range = min(processStopAddress - processStartAddress, MAX_REL_ADDR);
|
||||
ULONG addr = MemDbg::findBytes(bytes, sizeof(bytes), processStartAddress, processStartAddress + range);
|
||||
if (!addr)
|
||||
return false;
|
||||
HookParam hp;
|
||||
hp.address = addr + 1;
|
||||
hp.offset = get_stack(4);
|
||||
hp.type = USING_STRING | CODEC_UTF16;
|
||||
ConsoleOutput("INSERT SystemC#3");
|
||||
|
||||
return NewHook(hp, "SystemC#3");
|
||||
}
|
||||
}
|
||||
// jichi 10/2/2013: Add new candy hook
|
||||
bool InsertCandyHook()
|
||||
{
|
||||
|
||||
// if (0 == _wcsicmp(processName, L"systemc.exe"))
|
||||
if (Util::CheckFile(L"SystemC.exe"))
|
||||
return InsertCandyHook1() || candy3();
|
||||
else
|
||||
{
|
||||
// return InsertCandyHook2();
|
||||
bool b2 = InsertCandyHook2();
|
||||
b2 |= InsertCandyHook3();
|
||||
return b2;
|
||||
}
|
||||
}
|
||||
namespace
|
||||
{
|
||||
bool willowsoft()
|
||||
{
|
||||
const BYTE bytes[] = {
|
||||
// https://vndb.org/v5761
|
||||
// まません
|
||||
|
||||
0xA1, XX4,
|
||||
0x89, 0x45, 0xF8,
|
||||
0x83, 0x7D, 0xF8, 0x10,
|
||||
0x74, XX,
|
||||
0x83, 0x7D, 0xF8, 0x18,
|
||||
0x74, XX,
|
||||
0x83, 0x7D, 0xF8, 0x20,
|
||||
0x74, XX};
|
||||
auto addr = MemDbg::findBytes(bytes, sizeof(bytes), processStartAddress, processStopAddress);
|
||||
if (addr == 0)
|
||||
return false;
|
||||
addr = MemDbg::findEnclosingAlignedFunction(addr, 0x20);
|
||||
if (addr == 0)
|
||||
return false;
|
||||
HookParam hp;
|
||||
hp.type = USING_STRING;
|
||||
hp.offset = get_stack(2);
|
||||
hp.type = USING_STRING;
|
||||
hp.address = addr;
|
||||
return NewHook(hp, "WillowSoft");
|
||||
}
|
||||
}
|
||||
bool Candy::attach_function()
|
||||
{
|
||||
|
||||
auto b1 = InsertCandyHook();
|
||||
if (b1)
|
||||
PcHooks::hookOtherPcFunctions();
|
||||
else
|
||||
{
|
||||
b1 = b1 || willowsoft();
|
||||
if (!b1)
|
||||
PcHooks::hookOtherPcFunctions();
|
||||
}
|
||||
return b1;
|
||||
}
|
||||
|
||||
bool WillowSoft::attach_function()
|
||||
{
|
||||
// お母さんがいっぱい!!限定ママBOX
|
||||
const BYTE bytes[] = {
|
||||
0xF7, 0xC2, 0x00, 0x00, 0xFF, 0x00,
|
||||
XX2,
|
||||
0xF7, 0xC2, 0x00, 0x00, 0x00, 0xFF,
|
||||
XX2};
|
||||
auto addr = MemDbg::findBytes(bytes, sizeof(bytes), processStartAddress, processStopAddress);
|
||||
if (addr == 0)
|
||||
return false;
|
||||
addr = MemDbg::findEnclosingAlignedFunction(addr);
|
||||
if (addr == 0)
|
||||
return false;
|
||||
|
||||
HookParam hp;
|
||||
hp.type = USING_STRING;
|
||||
hp.offset = get_stack(2);
|
||||
hp.type |= DATA_INDIRECT;
|
||||
hp.index = 0;
|
||||
hp.address = addr;
|
||||
|
||||
return NewHook(hp, "WillowSoft");
|
||||
}
|
27
cpp/LunaHook/LunaHook/engine32/Candy.h
Normal file
27
cpp/LunaHook/LunaHook/engine32/Candy.h
Normal file
@ -0,0 +1,27 @@
|
||||
|
||||
|
||||
class Candy : public ENGINE
|
||||
{
|
||||
public:
|
||||
Candy()
|
||||
{
|
||||
|
||||
check_by = CHECK_BY::FILE_ANY;
|
||||
check_by_target = check_by_list{L"*.fpk", L"data\\*.fpk"};
|
||||
is_engine_certain = false;
|
||||
};
|
||||
bool attach_function();
|
||||
};
|
||||
|
||||
class WillowSoft : public ENGINE
|
||||
{
|
||||
public:
|
||||
WillowSoft()
|
||||
{
|
||||
|
||||
check_by = CHECK_BY::FILE;
|
||||
check_by_target = L"Selene.dll";
|
||||
is_engine_certain = false;
|
||||
};
|
||||
bool attach_function();
|
||||
};
|
139
cpp/LunaHook/LunaHook/engine32/CaramelBox.cpp
Normal file
139
cpp/LunaHook/LunaHook/engine32/CaramelBox.cpp
Normal file
@ -0,0 +1,139 @@
|
||||
#include"CaramelBox.h"
|
||||
|
||||
|
||||
static void SpecialHookCaramelBox(hook_stack *stack, HookParam *hp, TextBuffer *buffer, uintptr_t *split)
|
||||
{
|
||||
DWORD reg_ecx = *(DWORD*)(stack->base + hp->offset);
|
||||
BYTE *ptr = (BYTE *)reg_ecx;
|
||||
buffer_index = 0;
|
||||
while (ptr[0])
|
||||
if (ptr[0] == 0x28) { // Furigana format: (Kanji,Furi)
|
||||
ptr++;
|
||||
while (ptr[0]!=0x2c) //Copy Kanji
|
||||
text_buffer[buffer_index++] = *ptr++;
|
||||
while (ptr[0]!=0x29) // Skip Furi
|
||||
ptr++;
|
||||
ptr++;
|
||||
} else if (ptr[0] == 0x5c)
|
||||
ptr +=2;
|
||||
else {
|
||||
text_buffer[buffer_index++] = ptr[0];
|
||||
if (LeadByteTable[ptr[0]] == 2) {
|
||||
ptr++;
|
||||
text_buffer[buffer_index++] = ptr[0];
|
||||
}
|
||||
ptr++;
|
||||
}
|
||||
buffer->from(text_buffer, buffer_index);
|
||||
*split = 0; // 8/3/2014 jichi: use return address as split
|
||||
}
|
||||
// jichi 10/1/2013: Change return type to bool
|
||||
bool InsertCaramelBoxHook()
|
||||
{
|
||||
union { DWORD i; BYTE* pb; WORD* pw; DWORD *pd; };
|
||||
DWORD reg = -1;
|
||||
for (i = processStartAddress + 0x1000; i < processStopAddress - 4; i++) {
|
||||
if (*pd == 0x7ff3d) // cmp eax, 7ff
|
||||
reg = 0;
|
||||
else if ((*pd & 0xfffff8fc) == 0x07fff880) // cmp reg, 7ff
|
||||
reg = pb[1] & 0x7;
|
||||
|
||||
if (reg == -1)
|
||||
continue;
|
||||
|
||||
DWORD flag = 0;
|
||||
if (*(pb - 6) == 3) { //add reg, [ebp+$disp_32]
|
||||
if (*(pb - 5) == (0x85 | (reg << 3)))
|
||||
flag = 1;
|
||||
} else if (*(pb - 3) == 3) { // add reg, [ebp+$disp_8]
|
||||
if (*(pb - 2) == (0x45 | (reg << 3)))
|
||||
flag = 1;
|
||||
} else if (*(pb - 2) == 3) { // add reg, reg
|
||||
if (((*(pb - 1) >> 3) & 7)== reg)
|
||||
flag = 1;
|
||||
}
|
||||
reg = -1;
|
||||
if (flag) {
|
||||
for (DWORD j = i, k = i - 0x100; j > k; j--) {
|
||||
if ((*(DWORD *)j & 0xffff00ff) == 0x1000b8) { // mov eax,10??
|
||||
HookParam hp;
|
||||
hp.address = j & ~0xf;
|
||||
hp.text_fun = SpecialHookCaramelBox;
|
||||
hp.type = USING_STRING;
|
||||
for (i &= ~0xffff; i < processStopAddress - 4; i++)
|
||||
if (pb[0] == 0xe8) {
|
||||
pb++;
|
||||
if (pd[0] + i + 4 == hp.address) {
|
||||
pb += 4;
|
||||
if ((pd[0] & 0xffffff) == 0x04c483)
|
||||
hp.offset=get_stack(1);
|
||||
else hp.offset=get_reg(regs::ecx);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (hp.offset == 0) {
|
||||
ConsoleOutput("CaramelBox: failed, zero off");
|
||||
return false;
|
||||
}
|
||||
ConsoleOutput("INSERT CaramelBox");
|
||||
|
||||
//RegisterEngineType(ENGINE_CARAMEL);
|
||||
return NewHook(hp, "CaramelBox");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ConsoleOutput("CaramelBox: failed");
|
||||
return false;
|
||||
//_unknown_engine:
|
||||
//ConsoleOutput("Unknown CarmelBox engine.");
|
||||
}
|
||||
|
||||
|
||||
bool CaramelBox::attach_function() {
|
||||
|
||||
return InsertCaramelBoxHook();
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool CaramelBoxMilkAji::attach_function(){
|
||||
//雨芳恋歌
|
||||
//https://vndb.org/v6663
|
||||
BYTE bytes[] = {
|
||||
0x33,0xD2,
|
||||
0xB9,0x8A,0x02,0x00,0x00,
|
||||
0xF7,0xF1,
|
||||
0x6B,0xC0,0x44,
|
||||
0x6B,0xC0,0x03
|
||||
};
|
||||
auto addr=MemDbg::findBytes(bytes, sizeof(bytes), processStartAddress, processStopAddress);
|
||||
if(addr==0)return false;
|
||||
addr=MemDbg::findEnclosingAlignedFunction(addr);
|
||||
if(addr==0)return false;
|
||||
HookParam hp;
|
||||
hp.address = addr;
|
||||
hp.type = USING_STRING;
|
||||
hp.offset=get_stack(1);
|
||||
|
||||
return NewHook(hp, "CaramelBox");
|
||||
}
|
||||
bool CaramelBox2::attach_function(){
|
||||
//https://vndb.org/r19777
|
||||
//Otoboku - Maidens Are Falling for Me! - Download Edition
|
||||
trigger_fun=[](LPVOID addr1, hook_stack* stack){
|
||||
if(addr1!=TextOutA&& addr1!=GetTextExtentPoint32A)return false;
|
||||
auto addr=stack->retaddr;
|
||||
addr = MemDbg::findEnclosingAlignedFunction(addr);
|
||||
if (addr == 0)return false;
|
||||
HookParam hp;
|
||||
hp.address = addr;
|
||||
hp.type = USING_STRING|USING_SPLIT;
|
||||
hp.offset=get_stack(2);
|
||||
hp.split=get_stack(2);
|
||||
NewHook(hp, "CaramelBox");
|
||||
return true;
|
||||
};
|
||||
return true;
|
||||
}
|
51
cpp/LunaHook/LunaHook/engine32/CaramelBox.h
Normal file
51
cpp/LunaHook/LunaHook/engine32/CaramelBox.h
Normal file
@ -0,0 +1,51 @@
|
||||
|
||||
|
||||
class CaramelBox:public ENGINE{
|
||||
public:
|
||||
CaramelBox(){
|
||||
|
||||
check_by=CHECK_BY::CUSTOM;
|
||||
check_by_target=[](){
|
||||
auto str=std::wstring( processName_lower);
|
||||
DWORD len = str.size();
|
||||
|
||||
// jichi 8/10/2013: Since *.bin is common, move CaramelBox to the end
|
||||
str[len - 3] = L'b';
|
||||
str[len - 2] = L'i';
|
||||
str[len - 1] = L'n';
|
||||
str[len] = 0;
|
||||
return (Util::CheckFile(str.c_str()) || Util::CheckFile(L"trial.bin"));
|
||||
};
|
||||
is_engine_certain=false;
|
||||
|
||||
};
|
||||
bool attach_function();
|
||||
};
|
||||
|
||||
|
||||
class CaramelBoxMilkAji:public ENGINE{
|
||||
public:
|
||||
CaramelBoxMilkAji(){
|
||||
|
||||
check_by=CHECK_BY::FILE;
|
||||
check_by_target=L"SdActiRc.dll";
|
||||
is_engine_certain=false;
|
||||
|
||||
};
|
||||
bool attach_function();
|
||||
};
|
||||
|
||||
class CaramelBox2:public ENGINE{
|
||||
public:
|
||||
CaramelBox2(){
|
||||
|
||||
check_by=CHECK_BY::CUSTOM;
|
||||
check_by_target=[](){
|
||||
if(!Util::CheckFile(L"*.mpg"))return false;
|
||||
char copyright[]="OTOBOKU-CaramelBox";//OTOBOKU-CaramelBox //Software\Caramel-Box\OTOMEHABOKUNIKOISHITERU
|
||||
return 0!=MemDbg::findBytes(copyright,sizeof(copyright),processStartAddress,min(processStopAddress,processStartAddress+0x200000));
|
||||
};
|
||||
|
||||
};
|
||||
bool attach_function();
|
||||
};
|
877
cpp/LunaHook/LunaHook/engine32/CatSystem.cpp
Normal file
877
cpp/LunaHook/LunaHook/engine32/CatSystem.cpp
Normal file
@ -0,0 +1,877 @@
|
||||
#include "CatSystem.h"
|
||||
// jichi 5/10/2014
|
||||
// See also: http://bbs.sumisora.org/read.php?tid=11044704&fpage=2
|
||||
//
|
||||
// Old engine: グリザイアの迷宮
|
||||
// 0053cc4e cc int3
|
||||
// 0053cc4f cc int3
|
||||
// 0053cc50 6a ff push -0x1 ; jichi: hook here
|
||||
// 0053cc52 68 6b486000 push .0060486b
|
||||
// 0053cc57 64:a1 00000000 mov eax,dword ptr fs:[0]
|
||||
// 0053cc5d 50 push eax
|
||||
// 0053cc5e 81ec 24020000 sub esp,0x224
|
||||
// 0053cc64 a1 f8647600 mov eax,dword ptr ds:[0x7664f8]
|
||||
// 0053cc69 33c4 xor eax,esp
|
||||
// 0053cc6b 898424 20020000 mov dword ptr ss:[esp+0x220],eax
|
||||
// 0053cc72 53 push ebx
|
||||
// 0053cc73 55 push ebp
|
||||
// 0053cc74 56 push esi
|
||||
// 0053cc75 57 push edi
|
||||
//
|
||||
// Stack:
|
||||
// 0544e974 0053d593 return to .0053d593 from .0053cc50
|
||||
// 0544e978 045cc820
|
||||
// 0544e97c 00008dc5 : jichi: text
|
||||
// 0544e980 00000016
|
||||
// 0544e984 0452f2e4
|
||||
// 0544e988 00000000
|
||||
// 0544e98c 00000001
|
||||
// 0544e990 0544ea94
|
||||
// 0544e994 04513840
|
||||
// 0544e998 0452f2b8
|
||||
// 0544e99c 04577638
|
||||
// 0544e9a0 04620450
|
||||
// 0544e9a4 00000080
|
||||
// 0544e9a8 00000080
|
||||
// 0544e9ac 004914f3 return to .004914f3 from .0055c692
|
||||
//
|
||||
// Registers:
|
||||
// edx 0
|
||||
// ebx 00000016
|
||||
//
|
||||
//
|
||||
// New engine: イノセントガール
|
||||
// Stack:
|
||||
// 051ae508 0054e9d1 return to .0054e9d1 from .0054e310
|
||||
// 051ae50c 04361650
|
||||
// 051ae510 00008ca9 ; jichi: text
|
||||
// 051ae514 0000001a
|
||||
// 051ae518 04343864
|
||||
// 051ae51c 00000000
|
||||
// 051ae520 00000001
|
||||
// 051ae524 051ae62c
|
||||
// 051ae528 041edc20
|
||||
// 051ae52c 04343830
|
||||
// 051ae530 0434a8b0
|
||||
// 051ae534 0434a7f0
|
||||
// 051ae538 00000080
|
||||
// 051ae53c 00000080
|
||||
// 051ae540 3f560000
|
||||
// 051ae544 437f8000
|
||||
// 051ae548 4433e000
|
||||
// 051ae54c 16f60c00
|
||||
// 051ae550 051ae650
|
||||
// 051ae554 042c4c20
|
||||
// 051ae558 0000002c
|
||||
// 051ae55c 00439bc5 return to .00439bc5 from .0043af60
|
||||
//
|
||||
// Registers & stack:
|
||||
// Scenario:
|
||||
// eax 04361650
|
||||
// ecx 04357640
|
||||
// edx 04343864
|
||||
// ebx 0000001a
|
||||
// esp 051ae508
|
||||
// ebp 00008169
|
||||
// esi 04357640
|
||||
// edi 051ae62c
|
||||
// eip 0054e310 .0054e310
|
||||
//
|
||||
// 051ae508 0054e9d1 return to .0054e9d1 from .0054e310
|
||||
// 051ae50c 04361650
|
||||
// 051ae510 00008169
|
||||
// 051ae514 0000001a
|
||||
// 051ae518 04343864
|
||||
// 051ae51c 00000000
|
||||
// 051ae520 00000001
|
||||
// 051ae524 051ae62c
|
||||
// 051ae528 041edc20
|
||||
// 051ae52c 04343830
|
||||
// 051ae530 0434a8b0
|
||||
// 051ae534 0434a7f0
|
||||
// 051ae538 00000080
|
||||
// 051ae53c 00000080
|
||||
// 051ae540 3f560000
|
||||
// 051ae544 437f8000
|
||||
// 051ae548 4433e000
|
||||
// 051ae54c 16f60c00
|
||||
// 051ae550 051ae650
|
||||
// 051ae554 042c4c20
|
||||
// 051ae558 0000002c
|
||||
//
|
||||
// Name:
|
||||
//
|
||||
// eax 04362430
|
||||
// ecx 17025230
|
||||
// edx 0430b6e4
|
||||
// ebx 0000001a
|
||||
// esp 051ae508
|
||||
// ebp 00008179
|
||||
// esi 17025230
|
||||
// edi 051ae62c
|
||||
// eip 0054e310 .0054e310
|
||||
//
|
||||
// 051ae508 0054e9d1 return to .0054e9d1 from .0054e310
|
||||
// 051ae50c 04362430
|
||||
// 051ae510 00008179
|
||||
// 051ae514 0000001a
|
||||
// 051ae518 0430b6e4
|
||||
// 051ae51c 00000000
|
||||
// 051ae520 00000001
|
||||
// 051ae524 051ae62c
|
||||
// 051ae528 041edae0
|
||||
// 051ae52c 0430b6b0
|
||||
// 051ae530 0434a790
|
||||
// 051ae534 0434a910
|
||||
// 051ae538 00000080
|
||||
// 051ae53c 00000080
|
||||
// 051ae540 3efa0000
|
||||
// 051ae544 4483f000
|
||||
// 051ae548 44322000
|
||||
// 051ae54c 16f60aa0
|
||||
// 051ae550 051ae650
|
||||
// 051ae554 042c4c20
|
||||
// 051ae558 0000002c
|
||||
|
||||
static void SpecialHookCatSystem3(hook_stack *stack, HookParam *, uintptr_t *data, uintptr_t *split, size_t *len)
|
||||
{
|
||||
// DWORD ch = *data = *(DWORD *)(esp_base + hp->offset); // arg2
|
||||
DWORD ch = *data = stack->stack[2];
|
||||
*len = LeadByteTable[(ch >> 8) & 0xff]; // CODEC_ANSI_BE
|
||||
*split = stack->edx >> 16;
|
||||
}
|
||||
|
||||
bool InsertCatSystemHook()
|
||||
{
|
||||
// DWORD search=0x95EB60F;
|
||||
// DWORD j,i=SearchPattern(processStartAddress,processStopAddress-processStartAddress,&search,4);
|
||||
// if (i==0) return;
|
||||
// i+=processStartAddress;
|
||||
// for (j=i-0x100;i>j;i--)
|
||||
// if (*(DWORD*)i==0xcccccccc) break;
|
||||
// if (i==j) return;
|
||||
// hp.address=i+4;
|
||||
// hp.offset=get_reg(regs::eax);
|
||||
// hp.index=4;
|
||||
// hp.type =CODEC_ANSI_BE|DATA_INDIRECT|USING_SPLIT|SPLIT_INDIRECT;
|
||||
// hp.length_offset=1;
|
||||
|
||||
enum
|
||||
{
|
||||
beg = 0xff6acccc
|
||||
}; // jichi 7/12/2014: beginning of the function
|
||||
enum
|
||||
{
|
||||
addr_offset = 2
|
||||
}; // skip two leading 0xcc
|
||||
ULONG addr = MemDbg::findCallerAddress((ULONG)::GetTextMetricsA, beg, processStartAddress, processStopAddress);
|
||||
if (!addr)
|
||||
{
|
||||
ConsoleOutput("CatSystem2: pattern not exist");
|
||||
return false;
|
||||
}
|
||||
|
||||
HookParam hp;
|
||||
hp.address = addr + addr_offset; // skip 1 push?
|
||||
hp.offset = get_stack(2); // text character is in arg2
|
||||
|
||||
// jichi 12/23/2014: Modify split for new catsystem
|
||||
bool newEngine = Util::CheckFile(L"cs2conf.dll");
|
||||
if (newEngine)
|
||||
{
|
||||
// hp.text_fun = SpecialHookCatSystem3; // type not needed
|
||||
// NewHook(hp, "CatSystem3");
|
||||
// ConsoleOutput("INSERT CatSystem3");
|
||||
hp.type = CODEC_ANSI_BE | USING_SPLIT;
|
||||
hp.split = get_reg(regs::esi);
|
||||
ConsoleOutput("INSERT CatSystem3new");
|
||||
return NewHook(hp, "CatSystem3new");
|
||||
}
|
||||
else
|
||||
{
|
||||
BYTE check[] = {0x66, 0x83, 0xff, 0x20, // 0x20
|
||||
0x0f, 0x84, XX4,
|
||||
0xb8, 0x40, 0x81, 0x00, 0x00, // 0x8140
|
||||
0x66, 0x3b, 0xf8};
|
||||
if (MemDbg::findBytes(check, sizeof(check), addr, addr + 0x100))
|
||||
{
|
||||
hp.split = get_stack(1);
|
||||
hp.offset = get_reg(regs::edx);
|
||||
}
|
||||
else
|
||||
{
|
||||
hp.split = get_reg(regs::edx);
|
||||
}
|
||||
hp.type = CODEC_ANSI_BE | USING_SPLIT;
|
||||
ConsoleOutput("INSERT CatSystem2");
|
||||
return NewHook(hp, "CatSystem2");
|
||||
}
|
||||
}
|
||||
bool InsertCatSystem2Hook()
|
||||
{
|
||||
|
||||
/*
|
||||
* Sample games:
|
||||
* https://vndb.org/v26987
|
||||
*/
|
||||
const BYTE bytes[] = {
|
||||
0x38, 0x08, // cmp [eax],cl
|
||||
0x0F, 0x84, XX4, // je cs2.exe+23E490
|
||||
0x66, 0x66, 0x0F, 0x1F, 0x84, 0x00, XX4, // nop word ptr [eax+eax+00000000]
|
||||
0x4F, // dec edi
|
||||
0xC7, 0x85, XX4, XX4, // mov [ebp-000005A0],00000000
|
||||
0x33, 0xF6, // xor esi,esi
|
||||
0xC7, 0x85, XX4, XX4, // mov [ebp-0000057C],00000000
|
||||
0x85, 0xFF // test edi,edi
|
||||
};
|
||||
|
||||
ULONG range = min(processStopAddress - processStartAddress, MAX_REL_ADDR);
|
||||
ULONG addr = MemDbg::findBytes(bytes, sizeof(bytes), processStartAddress, processStartAddress + range);
|
||||
if (!addr)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
HookParam hp;
|
||||
hp.address = addr;
|
||||
hp.offset = get_reg(regs::eax);
|
||||
hp.type = USING_STRING | CODEC_UTF8;
|
||||
hp.filter_fun = [](void *data, size_t *len, HookParam *hp)
|
||||
{
|
||||
static std::regex rx(R"(\[(.+?)/.+\])");
|
||||
auto _ = std::regex_replace(std::string((char *)data, *len), rx, "$1");
|
||||
return write_string_overwrite(data, len, _);
|
||||
};
|
||||
return NewHook(hp, "CatSystem2new");
|
||||
}
|
||||
namespace
|
||||
{ // unnamed
|
||||
namespace Patch
|
||||
{
|
||||
|
||||
namespace Private
|
||||
{
|
||||
// String in ecx
|
||||
// bool __fastcall isLeadByteChar(const char *s, DWORD edx)
|
||||
// bool isLeadByteChar(hook_stack*s,void* data, size_t* len,uintptr_t*role)
|
||||
// {
|
||||
// auto pc=(CHAR*)s->ecx;
|
||||
|
||||
// s->eax=(bool)((pc)&&dynsjis::isleadbyte(*pc));
|
||||
// return false;
|
||||
|
||||
// //return dynsjis::isleadstr(s); // no idea why this will cause Grisaia3 to hang
|
||||
// //return ::IsDBCSLeadByte(HIBYTE(testChar));
|
||||
// }
|
||||
bool isLeadByteChar(char *s)
|
||||
{
|
||||
return s && dynsjis::isleadchar(*s);
|
||||
|
||||
// return dynsjis::isleadstr(s); // no idea why this will cause Grisaia3 to hang
|
||||
// return ::IsDBCSLeadByte(HIBYTE(testChar));
|
||||
}
|
||||
__declspec(naked) bool thiscallisLeadByteChar()
|
||||
{
|
||||
__asm {
|
||||
push ecx
|
||||
call isLeadByteChar
|
||||
pop ecx
|
||||
ret
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Private
|
||||
|
||||
/**
|
||||
* Sample game: ゆきこいめると
|
||||
*
|
||||
* This function is found by searching the following instruction:
|
||||
* 00511C8E 3C 81 CMP AL,0x81
|
||||
*
|
||||
* This function is very similar to that in LC-ScriptEngine.
|
||||
*
|
||||
* Return 1 if the first byte in arg1 is leading byte else 0.
|
||||
*
|
||||
* 00511C7C CC INT3
|
||||
* 00511C7D CC INT3
|
||||
* 00511C7E CC INT3
|
||||
* 00511C7F CC INT3
|
||||
* 00511C80 8B4C24 04 MOV ECX,DWORD PTR SS:[ESP+0x4]
|
||||
* 00511C84 85C9 TEST ECX,ECX
|
||||
* 00511C86 74 2F JE SHORT .00511CB7
|
||||
* 00511C88 8A01 MOV AL,BYTE PTR DS:[ECX]
|
||||
* 00511C8A 84C0 TEST AL,AL
|
||||
* 00511C8C 74 29 JE SHORT .00511CB7
|
||||
* 00511C8E 3C 81 CMP AL,0x81
|
||||
* 00511C90 72 04 JB SHORT .00511C96
|
||||
* 00511C92 3C 9F CMP AL,0x9F
|
||||
* 00511C94 76 08 JBE SHORT .00511C9E
|
||||
* 00511C96 3C E0 CMP AL,0xE0
|
||||
* 00511C98 72 1D JB SHORT .00511CB7
|
||||
* 00511C9A 3C EF CMP AL,0xEF
|
||||
* 00511C9C 77 19 JA SHORT .00511CB7
|
||||
* 00511C9E 8A41 01 MOV AL,BYTE PTR DS:[ECX+0x1]
|
||||
* 00511CA1 3C 40 CMP AL,0x40
|
||||
* 00511CA3 72 04 JB SHORT .00511CA9
|
||||
* 00511CA5 3C 7E CMP AL,0x7E
|
||||
* 00511CA7 76 08 JBE SHORT .00511CB1
|
||||
* 00511CA9 3C 80 CMP AL,0x80
|
||||
* 00511CAB 72 0A JB SHORT .00511CB7
|
||||
* 00511CAD 3C FC CMP AL,0xFC
|
||||
* 00511CAF 77 06 JA SHORT .00511CB7
|
||||
* 00511CB1 B8 01000000 MOV EAX,0x1
|
||||
* 00511CB6 C3 RETN
|
||||
* 00511CB7 33C0 XOR EAX,EAX
|
||||
* 00511CB9 C3 RETN
|
||||
* 00511CBA CC INT3
|
||||
* 00511CBB CC INT3
|
||||
* 00511CBC CC INT3
|
||||
* 00511CBD CC INT3
|
||||
*
|
||||
* Sample game: Grisaia3 グリザイアの楽園
|
||||
* 0050747F CC INT3
|
||||
* 00507480 8B4C24 04 MOV ECX,DWORD PTR SS:[ESP+0x4] ; jichi: text in arg1
|
||||
* 00507484 85C9 TEST ECX,ECX
|
||||
* 00507486 74 2F JE SHORT .005074B7
|
||||
* 00507488 8A01 MOV AL,BYTE PTR DS:[ECX]
|
||||
* 0050748A 84C0 TEST AL,AL
|
||||
* 0050748C 74 29 JE SHORT .005074B7
|
||||
* 0050748E 3C 81 CMP AL,0x81
|
||||
* 00507490 72 04 JB SHORT .00507496
|
||||
* 00507492 3C 9F CMP AL,0x9F
|
||||
* 00507494 76 08 JBE SHORT .0050749E
|
||||
* 00507496 3C E0 CMP AL,0xE0
|
||||
* 00507498 72 1D JB SHORT .005074B7
|
||||
* 0050749A 3C EF CMP AL,0xEF
|
||||
* 0050749C 77 19 JA SHORT .005074B7
|
||||
* 0050749E 8A41 01 MOV AL,BYTE PTR DS:[ECX+0x1]
|
||||
* 005074A1 3C 40 CMP AL,0x40
|
||||
* 005074A3 72 04 JB SHORT .005074A9
|
||||
* 005074A5 3C 7E CMP AL,0x7E
|
||||
* 005074A7 76 08 JBE SHORT .005074B1
|
||||
* 005074A9 3C 80 CMP AL,0x80
|
||||
* 005074AB 72 0A JB SHORT .005074B7
|
||||
* 005074AD 3C FC CMP AL,0xFC
|
||||
* 005074AF 77 06 JA SHORT .005074B7
|
||||
* 005074B1 B8 01000000 MOV EAX,0x1
|
||||
* 005074B6 C3 RETN
|
||||
* 005074B7 33C0 XOR EAX,EAX
|
||||
* 005074B9 C3 RETN
|
||||
* 005074BA CC INT3
|
||||
* 005074BB CC INT3
|
||||
* 005074BC CC INT3
|
||||
* 005074BD CC INT3
|
||||
*
|
||||
* Sample game: Grisaia1 グリザイアの果実
|
||||
* 0041488A CC INT3
|
||||
* 0041488B CC INT3
|
||||
* 0041488C CC INT3
|
||||
* 0041488D CC INT3
|
||||
* 0041488E CC INT3
|
||||
* 0041488F CC INT3
|
||||
* 00414890 85C9 TEST ECX,ECX ; jichi: text in ecx
|
||||
* 00414892 74 2F JE SHORT Grisaia.004148C3
|
||||
* 00414894 8A01 MOV AL,BYTE PTR DS:[ECX]
|
||||
* 00414896 84C0 TEST AL,AL
|
||||
* 00414898 74 29 JE SHORT Grisaia.004148C3
|
||||
* 0041489A 3C 81 CMP AL,0x81
|
||||
* 0041489C 72 04 JB SHORT Grisaia.004148A2
|
||||
* 0041489E 3C 9F CMP AL,0x9F
|
||||
* 004148A0 76 08 JBE SHORT Grisaia.004148AA
|
||||
* 004148A2 3C E0 CMP AL,0xE0
|
||||
* 004148A4 72 1D JB SHORT Grisaia.004148C3
|
||||
* 004148A6 3C EF CMP AL,0xEF
|
||||
* 004148A8 77 19 JA SHORT Grisaia.004148C3
|
||||
* 004148AA 8A41 01 MOV AL,BYTE PTR DS:[ECX+0x1]
|
||||
* 004148AD 3C 40 CMP AL,0x40
|
||||
* 004148AF 72 04 JB SHORT Grisaia.004148B5
|
||||
* 004148B1 3C 7E CMP AL,0x7E
|
||||
* 004148B3 76 08 JBE SHORT Grisaia.004148BD
|
||||
* 004148B5 3C 80 CMP AL,0x80
|
||||
* 004148B7 72 0A JB SHORT Grisaia.004148C3
|
||||
* 004148B9 3C FC CMP AL,0xFC
|
||||
* 004148BB 77 06 JA SHORT Grisaia.004148C3
|
||||
* 004148BD B8 01000000 MOV EAX,0x1
|
||||
* 004148C2 C3 RETN
|
||||
* 004148C3 33C0 XOR EAX,EAX
|
||||
* 004148C5 C3 RETN
|
||||
* 004148C6 CC INT3
|
||||
* 004148C7 CC INT3
|
||||
* 004148C8 CC INT3
|
||||
*/
|
||||
|
||||
ULONG patchEncoding(ULONG startAddress, ULONG stopAddress)
|
||||
{
|
||||
const uint8_t bytes[] = {
|
||||
0x74, 0x29, // 00511c8c 74 29 je short .00511cb7
|
||||
0x3c, 0x81 // 00511c8e 3c 81 cmp al,0x81
|
||||
};
|
||||
ULONG addr = MemDbg::findBytes(bytes, sizeof(bytes), startAddress, stopAddress);
|
||||
if (!addr)
|
||||
return false;
|
||||
addr = MemDbg::findEnclosingAlignedFunction(addr);
|
||||
if (!addr)
|
||||
return false;
|
||||
for (auto p = addr; p - addr < 20; p += ::disasm((LPCVOID)p))
|
||||
if (*(WORD *)p == 0xc985) // 00414890 85C9 TEST ECX,ECX ; jichi: text in ecx
|
||||
return addr; // winhook::replace_fun(p, (ULONG)Private::isLeadByteChar);
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // namespace Patch
|
||||
|
||||
/**
|
||||
* Sample game: ゆきこいめると
|
||||
*
|
||||
* Example prefix to skip:
|
||||
* 03751294 81 40 5C 70 63 81 75 83 7B 83 4E 82 CC 8E AF 82 \pc「ボクの識・
|
||||
*
|
||||
* 033CF370 5C 6E 81 40 5C 70 63 8C 4A 82 E8 95 D4 82 BB 82 \n \pc繰り返そ・
|
||||
* 033CF380 A4 81 41 96 7B 93 96 82 C9 81 41 82 B1 82 CC 8B 、、本当に、この・
|
||||
* 033CF390 47 90 DF 82 CD 81 41 83 8D 83 4E 82 C8 82 B1 82 G節は、ロクなこ・
|
||||
* 033CF3A0 C6 82 AA 82 C8 82 A2 81 42 00 AA 82 C8 82 A2 81 ニがない。.ェない・
|
||||
* 033CF3B0 42 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 B...............
|
||||
* 033CF3C0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
|
||||
* 033CF3D0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
|
||||
* 033CF3E0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
|
||||
* 033CF3F0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
|
||||
* 033CF400 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
|
||||
*
|
||||
* Sample choice texts:
|
||||
*
|
||||
* str 155 選択肢
|
||||
*
|
||||
* 0 op01 最初から始める
|
||||
*
|
||||
* 1 select_go_tar たるひ初キスシーンを見る
|
||||
*/
|
||||
template <typename strT>
|
||||
strT ltrim(strT text)
|
||||
{
|
||||
strT lastText = nullptr;
|
||||
while (*text && text != lastText)
|
||||
{
|
||||
lastText = text;
|
||||
if (text[0] == 0x20)
|
||||
text++;
|
||||
if ((UINT8)text[0] == 0x81 && (UINT8)text[1] == 0x40) // skip space \u3000 (0x8140 in sjis)
|
||||
text += 2;
|
||||
if (text[0] == '\\')
|
||||
{
|
||||
text++;
|
||||
while (::islower(text[0]) || text[0] == '@')
|
||||
text++;
|
||||
}
|
||||
}
|
||||
while ((signed char)text[0] > 0 && text[0] != '[') // skip all leading ascii characters except "[" needed for ruby
|
||||
text++;
|
||||
return text;
|
||||
}
|
||||
|
||||
// Remove trailing '\@'
|
||||
size_t rtrim(LPCSTR text)
|
||||
{
|
||||
size_t size = ::strlen(text);
|
||||
while (size >= 2 && text[size - 2] == '\\' && (UINT8)text[size - 1] <= 127)
|
||||
size -= 2;
|
||||
return size;
|
||||
}
|
||||
|
||||
namespace ScenarioHook
|
||||
{
|
||||
namespace Private
|
||||
{
|
||||
|
||||
bool isOtherText(LPCSTR text)
|
||||
{
|
||||
/* Sample game: ゆきこいめると */
|
||||
return ::strcmp(text, "\x91\x49\x91\xf0\x8e\x88") == 0; /* 選択肢 */
|
||||
}
|
||||
|
||||
/**
|
||||
* Sample game: 果つることなき未来ヨリ
|
||||
*
|
||||
* Sample ecx:
|
||||
*
|
||||
* 03283A88 24 00 CD 02 76 16 02 00 24 00 CD 02 58 00 CD 02 $.ヘv.$.ヘX.ヘ
|
||||
* 03283A98 BD 2D 01 00 1C 1C 49 03 14 65 06 00 14 65 06 00 ス-.Ie.e.
|
||||
* this is ID, this is the same ID: 0x066514
|
||||
* 03283AA8 80 64 06 00 20 8C 06 00 24 00 6C 0D 00 00 10 00 d. ・.$.l....
|
||||
* this is ID: 0x066480
|
||||
* 03283AB8 C8 F1 C2 00 21 00 00 00 48 A9 75 00 E8 A9 96 00 ネ.!...Hゥu.隧・
|
||||
* 03283AC8 00 00 00 00 48 80 4F 03 00 00 00 00 CC CC CC CC ....HO....フフフフ
|
||||
* 03283AD8 CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC フフフフフフフフフフフフフフフフ
|
||||
*/
|
||||
// struct ClassArgument // for ecx
|
||||
//{
|
||||
// DWORD unknown[7],
|
||||
// split1, // 0x20 - 9
|
||||
// split2; // 0x20
|
||||
// // split1 - split2 is always 0x94
|
||||
// DWORD split() const { return split1 - split2; } //
|
||||
// };
|
||||
|
||||
static bool containsNamePunct_(const char *text)
|
||||
{
|
||||
static const char *puncts[] = {
|
||||
"\x81\x41" /* 、 */
|
||||
,
|
||||
"\x81\x43" /* , */
|
||||
,
|
||||
"\x81\x42" /* 。 */
|
||||
//, "\x81\x48" /* ? */
|
||||
,
|
||||
"\x81\x49" /* ! */
|
||||
,
|
||||
"\x81\x63" /* … */
|
||||
,
|
||||
"\x81\x64" /* ‥ */
|
||||
|
||||
//, "\x81\x79" /* 【 */
|
||||
//, "\x81\x7a" /* 】 */
|
||||
,
|
||||
"\x81\x75" /* 「 */
|
||||
,
|
||||
"\x81\x76" /* 」 */
|
||||
,
|
||||
"\x81\x77" /* 『 */
|
||||
,
|
||||
"\x81\x78" /* 』 */
|
||||
//, "\x81\x69" /* ( */
|
||||
//, "\x81\x6a" /* ) */
|
||||
//, "\x81\x6f" /* { */
|
||||
//, "\x81\x70" /* } */
|
||||
//, "\x81\x71" /* 〈 */
|
||||
//, "\x81\x72" /* 〉 */
|
||||
,
|
||||
"\x81\x6d" /* [ */
|
||||
,
|
||||
"\x81\x6e" /* ] */
|
||||
//, "\x81\x83", /* < */
|
||||
//, "\x81\x84", /* > */
|
||||
,
|
||||
"\x81\x65" /* ‘ */
|
||||
,
|
||||
"\x81\x66" /* ’ */
|
||||
,
|
||||
"\x81\x67" /* “ */
|
||||
,
|
||||
"\x81\x68" /* ” */
|
||||
};
|
||||
for (size_t i = 0; i < sizeof(puncts) / sizeof(*puncts); i++)
|
||||
if (::strstr(text, puncts[i]))
|
||||
return true;
|
||||
|
||||
if (::strstr(text, "\x81\x48") /* ? */
|
||||
&& !::strstr(text, "\x81\x48\x81\x48\x81\x48")) /* ??? */
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
bool guessIsNameText(const char *text, size_t size)
|
||||
{
|
||||
enum
|
||||
{
|
||||
MaximumNameSize = 0x10
|
||||
};
|
||||
if (!size)
|
||||
size = ::strlen(text);
|
||||
return size < MaximumNameSize && !containsNamePunct_(text);
|
||||
}
|
||||
LPSTR trimmedText;
|
||||
size_t trimmedSize;
|
||||
void hookBefore(hook_stack *s, HookParam *hp, TextBuffer *buffer, uintptr_t *role)
|
||||
{
|
||||
// static std::unordered_set<uint64_t> hashes_;
|
||||
auto text = (LPSTR)s->eax; // arg1
|
||||
if (!text || !*text || all_ascii(text))
|
||||
return ;
|
||||
// Alternatively, if do not skip ascii chars, edx is always 0x4ef74 for Japanese texts
|
||||
// if (s->edx != 0x4ef74)
|
||||
// return true;
|
||||
trimmedText = ltrim(text);
|
||||
if (!trimmedText || !*trimmedText)
|
||||
return ;
|
||||
trimmedSize = rtrim(trimmedText);
|
||||
*role = Engine::OtherRole;
|
||||
// DOUT(QString::fromLocal8Bit((LPCSTR)s->esi));
|
||||
// auto splitText = (LPCSTR)s->esi;
|
||||
// if (::strcmp(splitText, "MES_SETNAME")) // This is for scenario text with voice
|
||||
// if (::strcmp(splitText, "MES_SETFACE"))
|
||||
// if (::strcmp(splitText, "pcm")) // first scenario or history without text
|
||||
// return true;
|
||||
// auto retaddr = s->stack[1]; // caller
|
||||
// auto retaddr = s->stack[13]; // parent caller
|
||||
// auto split = *(DWORD *)s->esi;
|
||||
// auto split = s->esi - s->eax;
|
||||
// DOUT(split);
|
||||
// auto self = (ClassArgument *)s->ecx;
|
||||
// auto split = self->split();
|
||||
// enum { sig = 0 };
|
||||
auto self = s->ecx;
|
||||
if (!Engine::isAddressWritable(self)) // old cs2 game such as Grisaia
|
||||
self = s->stack[2]; // arg1
|
||||
ULONG groupId = self;
|
||||
if (Engine::isAddressWritable(self))
|
||||
groupId = *(DWORD *)(self + 0x20);
|
||||
{
|
||||
static ULONG minimumGroupId_ = -1; // I assume scenario thread to have minimum groupId
|
||||
|
||||
// if (session_.addText(groupId, Engine::hashCharArray(text))) {
|
||||
if (groupId <= minimumGroupId_)
|
||||
{
|
||||
minimumGroupId_ = groupId;
|
||||
|
||||
*role = Engine::ScenarioRole;
|
||||
if (isOtherText(text))
|
||||
*role = Engine::OtherRole;
|
||||
else if (::isdigit(text[0]))
|
||||
*role = Engine::ChoiceRole;
|
||||
else if (trimmedText == text && !trimmedText[trimmedSize] // no prefix and suffix
|
||||
&& guessIsNameText(trimmedText, trimmedSize))
|
||||
*role = Engine::NameRole;
|
||||
}
|
||||
}
|
||||
|
||||
std::string oldData(trimmedText, trimmedSize);
|
||||
strReplace(oldData, "\\n", "\n");
|
||||
buffer->from(oldData);
|
||||
}
|
||||
void hookafter(hook_stack *s, void *data, size_t len)
|
||||
{
|
||||
auto newData = std::string((char *)data, len);
|
||||
strReplace(newData, "\n", "\\n");
|
||||
if (trimmedText[trimmedSize])
|
||||
newData.append(trimmedText + trimmedSize);
|
||||
::strcpy(trimmedText, newData.c_str());
|
||||
}
|
||||
} // namespace Private
|
||||
|
||||
/**
|
||||
* Sample game: 果つることなき未来ヨリ
|
||||
*
|
||||
* Debugging message:
|
||||
* - Hook to GetGlyphOutlineA
|
||||
* - Find "MES_SHOW" address on the stack
|
||||
* Alternatively, find the address of "fes.int/flow.fes" immediately after the game is launched
|
||||
* - Use hardware breakpoint to find out when "MES_SHOW" is overridden
|
||||
* Only stop when text is written by valid scenario text.
|
||||
*
|
||||
* 00503ADE CC INT3
|
||||
* 00503ADF CC INT3
|
||||
* 00503AE0 8B4424 0C MOV EAX,DWORD PTR SS:[ESP+0xC]
|
||||
* 00503AE4 8B4C24 04 MOV ECX,DWORD PTR SS:[ESP+0x4]
|
||||
* 00503AE8 56 PUSH ESI
|
||||
* 00503AE9 FF30 PUSH DWORD PTR DS:[EAX]
|
||||
* 00503AEB E8 102F1600 CALL Hatsumir.00666A00 ; jichi: text in eax after this call
|
||||
* 00503AF0 BE 18058900 MOV ESI,Hatsumir.00890518 ; ASCII "fes.int/flow.fes"
|
||||
* 00503AF5 8BC8 MOV ECX,EAX ; jichi: esi is the target location
|
||||
* 00503AF7 2BF0 SUB ESI,EAX
|
||||
* 00503AF9 8DA424 00000000 LEA ESP,DWORD PTR SS:[ESP]
|
||||
* 00503B00 8A11 MOV DL,BYTE PTR DS:[ECX]
|
||||
* 00503B02 8D49 01 LEA ECX,DWORD PTR DS:[ECX+0x1]
|
||||
* 00503B05 88540E FF MOV BYTE PTR DS:[ESI+ECX-0x1],DL ; jichi: target location modified here
|
||||
* 00503B09 84D2 TEST DL,DL
|
||||
* 00503B0B ^75 F3 JNZ SHORT Hatsumir.00503B00
|
||||
* 00503B0D 8B4C24 0C MOV ECX,DWORD PTR SS:[ESP+0xC]
|
||||
* 00503B11 50 PUSH EAX
|
||||
* 00503B12 68 18058900 PUSH Hatsumir.00890518 ; ASCII "fes.int/flow.fes"
|
||||
* 00503B17 8B89 B4000000 MOV ECX,DWORD PTR DS:[ECX+0xB4]
|
||||
* 00503B1D E8 EE030B00 CALL Hatsumir.005B3F10
|
||||
* 00503B22 B8 02000000 MOV EAX,0x2
|
||||
* 00503B27 5E POP ESI
|
||||
* 00503B28 C2 1000 RETN 0x10
|
||||
* 00503B2B CC INT3
|
||||
* 00503B2C CC INT3
|
||||
* 00503B2D CC INT3
|
||||
* 00503B2E CC INT3
|
||||
*
|
||||
* EAX 0353B1A0 ; jichi: text here
|
||||
* ECX 00D86D08
|
||||
* EDX 0004EF74
|
||||
* EBX 00012DB2
|
||||
* ESP 0525EBAC
|
||||
* EBP 0525ED6C
|
||||
* ESI 00D86D08
|
||||
* EDI 00000000
|
||||
* EIP 00503AF0 Hatsumir.00503AF0
|
||||
*
|
||||
* 0525EBAC 00D86D08
|
||||
* 0525EBB0 0066998E RETURN to Hatsumir.0066998E
|
||||
* 0525EBB4 00D86D08
|
||||
* 0525EBB8 00B16188
|
||||
* 0525EBBC 035527D8
|
||||
* 0525EBC0 0525EBE4
|
||||
* 0525EBC4 00B16188
|
||||
* 0525EBC8 00D86D08
|
||||
* 0525EBCC 0525F62B ASCII "ript.kcs"
|
||||
* 0525EBD0 00000004
|
||||
* 0525EBD4 00000116
|
||||
* 0525EBD8 00000003
|
||||
* 0525EBDC 00000003
|
||||
* 0525EBE0 00665C08 RETURN to Hatsumir.00665C08
|
||||
* 0525EBE4 CCCCCCCC
|
||||
* 0525EBE8 0525F620 ASCII "kcs.int/sscript.kcs"
|
||||
* 0525EBEC 00694D94 Hatsumir.00694D94
|
||||
* 0525EBF0 004B278F RETURN to Hatsumir.004B278F from Hatsumir.00666CA0
|
||||
* 0525EBF4 B3307379
|
||||
* 0525EBF8 0525ED04
|
||||
* 0525EBFC 00B16188
|
||||
* 0525EC00 0525ED04
|
||||
* 0525EC04 00B16188
|
||||
* 0525EC08 00CC5440
|
||||
* 0525EC0C 02368938
|
||||
* 0525EC10 0069448C ASCII "%s/%s"
|
||||
* 0525EC14 00B45B18 ASCII "kcs.int"
|
||||
* 0525EC18 00000001
|
||||
* 0525EC1C 023741E0
|
||||
* 0525EC20 0000000A
|
||||
* 0525EC24 0049DBB3 RETURN to Hatsumir.0049DBB3 from Hatsumir.00605A84
|
||||
* 0525EC28 72637373
|
||||
* 0525EC2C 2E747069
|
||||
* 0525EC30 0073636B Hatsumir.0073636B
|
||||
* 0525EC34 0525ED04
|
||||
* 0525EC38 0053ECDE RETURN to Hatsumir.0053ECDE from Hatsumir.004970C0
|
||||
* 0525EC3C 0525EC80
|
||||
* 0525EC40 023D9FB8
|
||||
*
|
||||
* Alternative ruby hook:
|
||||
* It will hook to the beginning of the Ruby processing function, which is not better than the current approach.
|
||||
* http://lab.aralgood.com/index.php?mid=board_lecture&search_target=title_content&search_keyword=CS&document_srl=1993027
|
||||
*
|
||||
* Sample game: Grisaia3 グリザイアの楽園
|
||||
*
|
||||
* 004B00CB CC INT3
|
||||
* 004B00CC CC INT3
|
||||
* 004B00CD CC INT3
|
||||
* 004B00CE CC INT3
|
||||
* 004B00CF CC INT3
|
||||
* 004B00D0 8B4424 0C MOV EAX,DWORD PTR SS:[ESP+0xC]
|
||||
* 004B00D4 8B08 MOV ECX,DWORD PTR DS:[EAX]
|
||||
* 004B00D6 56 PUSH ESI
|
||||
* 004B00D7 51 PUSH ECX
|
||||
* 004B00D8 8B4C24 0C MOV ECX,DWORD PTR SS:[ESP+0xC]
|
||||
* 004B00DC E8 7F191300 CALL .005E1A60
|
||||
* 004B00E1 BE D0E87B00 MOV ESI,.007BE8D0
|
||||
* 004B00E6 8BC8 MOV ECX,EAX
|
||||
* 004B00E8 2BF0 SUB ESI,EAX
|
||||
* 004B00EA 8D9B 00000000 LEA EBX,DWORD PTR DS:[EBX]
|
||||
* 004B00F0 8A11 MOV DL,BYTE PTR DS:[ECX]
|
||||
* 004B00F2 88140E MOV BYTE PTR DS:[ESI+ECX],DL
|
||||
* 004B00F5 41 INC ECX
|
||||
* 004B00F6 84D2 TEST DL,DL
|
||||
* 004B00F8 ^75 F6 JNZ SHORT .004B00F0
|
||||
* 004B00FA 8B5424 0C MOV EDX,DWORD PTR SS:[ESP+0xC]
|
||||
* 004B00FE 8B8A B4000000 MOV ECX,DWORD PTR DS:[EDX+0xB4]
|
||||
* 004B0104 50 PUSH EAX
|
||||
* 004B0105 68 D0E87B00 PUSH .007BE8D0
|
||||
* 004B010A E8 818D0600 CALL .00518E90
|
||||
* 004B010F B8 02000000 MOV EAX,0x2
|
||||
* 004B0114 5E POP ESI
|
||||
* 004B0115 C2 1000 RETN 0x10
|
||||
* 004B0118 CC INT3
|
||||
* 004B0119 CC INT3
|
||||
* 004B011A CC INT3
|
||||
* 004B011B CC INT3
|
||||
* 004B011C CC INT3
|
||||
*
|
||||
* Sample game: Grisaia1 グリザイアの果実
|
||||
* 00498579 CC INT3
|
||||
* 0049857A CC INT3
|
||||
* 0049857B CC INT3
|
||||
* 0049857C CC INT3
|
||||
* 0049857D CC INT3
|
||||
* 0049857E CC INT3
|
||||
* 0049857F CC INT3
|
||||
* 00498580 8B4424 0C MOV EAX,DWORD PTR SS:[ESP+0xC]
|
||||
* 00498584 8B08 MOV ECX,DWORD PTR DS:[EAX] ; jichi: ecx is no longer a pointer
|
||||
* 00498586 8B4424 04 MOV EAX,DWORD PTR SS:[ESP+0x4]
|
||||
* 0049858A 56 PUSH ESI
|
||||
* 0049858B E8 10920500 CALL Grisaia.004F17A0
|
||||
* 00498590 BE D89C7600 MOV ESI,Grisaia.00769CD8 ; ASCII "bgm01"
|
||||
* 00498595 8BC8 MOV ECX,EAX
|
||||
* 00498597 2BF0 SUB ESI,EAX
|
||||
* 00498599 8DA424 00000000 LEA ESP,DWORD PTR SS:[ESP]
|
||||
* 004985A0 8A11 MOV DL,BYTE PTR DS:[ECX]
|
||||
* 004985A2 88140E MOV BYTE PTR DS:[ESI+ECX],DL
|
||||
* 004985A5 41 INC ECX
|
||||
* 004985A6 84D2 TEST DL,DL
|
||||
* 004985A8 ^75 F6 JNZ SHORT Grisaia.004985A0
|
||||
* 004985AA 8B4C24 0C MOV ECX,DWORD PTR SS:[ESP+0xC]
|
||||
* 004985AE 8B91 B4000000 MOV EDX,DWORD PTR DS:[ECX+0xB4]
|
||||
* 004985B4 50 PUSH EAX
|
||||
* 004985B5 68 D89C7600 PUSH Grisaia.00769CD8 ; ASCII "bgm01"
|
||||
* 004985BA 52 PUSH EDX
|
||||
* 004985BB E8 701C0600 CALL Grisaia.004FA230
|
||||
* 004985C0 B8 02000000 MOV EAX,0x2
|
||||
* 004985C5 5E POP ESI
|
||||
* 004985C6 C2 1000 RETN 0x10
|
||||
* 004985C9 CC INT3
|
||||
* 004985CA CC INT3
|
||||
* 004985CB CC INT3
|
||||
* 004985CC CC INT3
|
||||
* 004985CD CC INT3
|
||||
*/
|
||||
bool attach(ULONG startAddress, ULONG stopAddress, HookParamType code)
|
||||
{
|
||||
const uint8_t bytes[] = {
|
||||
0xe8, XX4, // 004b00dc e8 7f191300 call .005e1a60 ; jichi: hook after here
|
||||
0xbe, XX4, // 004b00e1 be d0e87b00 mov esi,.007be8d0
|
||||
0x8b, 0xc8, // 004b00e6 8bc8 mov ecx,eax
|
||||
0x2b, 0xf0 // 004b00e8 2bf0 sub esi,eax
|
||||
// XX2, XX, 0x00,0x00,0x00 // 004b00ea 8d9b 00000000 lea ebx,dword ptr ds:[ebx]
|
||||
};
|
||||
ULONG addr = MemDbg::findBytes(bytes, sizeof(bytes), startAddress, stopAddress);
|
||||
if (addr == 0)
|
||||
return false;
|
||||
HookParam hp;
|
||||
hp.address = addr + 5;
|
||||
hp.type = USING_STRING | EMBED_ABLE|NO_CONTEXT;
|
||||
if (code)
|
||||
hp.type |= code;
|
||||
else
|
||||
hp.type |= EMBED_DYNA_SJIS;
|
||||
hp.text_fun = Private::hookBefore;
|
||||
hp.hook_after = Private::hookafter;
|
||||
hp.hook_font = F_GetGlyphOutlineA;
|
||||
hp.filter_fun = [](void *data, size_t *len, HookParam *hp)
|
||||
{
|
||||
static std::regex rx(R"(\[(.+?)/.+\])");
|
||||
auto _ = std::regex_replace(std::string((char *)data, *len), rx, "$1");
|
||||
return write_string_overwrite(data, len, _);
|
||||
};
|
||||
|
||||
static ULONG p;
|
||||
p = Patch::patchEncoding(startAddress, stopAddress);
|
||||
if (p)
|
||||
{
|
||||
hp.type |= EMBED_DYNA_SJIS;
|
||||
hp.hook_font = F_GetGlyphOutlineA;
|
||||
patch_fun = []()
|
||||
{
|
||||
if (*(WORD *)p == 0xc985)
|
||||
{ // test ecx,ecx , thiscall
|
||||
ReplaceFunction((PVOID)p, (PVOID)(ULONG)Patch::Private::thiscallisLeadByteChar);
|
||||
}
|
||||
else
|
||||
ReplaceFunction((PVOID)p, (PVOID)(ULONG)Patch::Private::isLeadByteChar);
|
||||
};
|
||||
}
|
||||
|
||||
return NewHook(hp, "EmbedCS2");
|
||||
}
|
||||
}
|
||||
} // namespace ScenarioHook
|
||||
bool CatSystem::attach_function()
|
||||
{
|
||||
HookParamType code = CODEC_ANSI_LE;
|
||||
auto b1 = InsertCatSystemHook();
|
||||
if (!b1)
|
||||
{
|
||||
b1 |= InsertCatSystem2Hook();
|
||||
code = CODEC_UTF8;
|
||||
}
|
||||
auto embed = ScenarioHook::attach(processStartAddress, processStopAddress, code);
|
||||
|
||||
b1 |= embed;
|
||||
return b1;
|
||||
}
|
12
cpp/LunaHook/LunaHook/engine32/CatSystem.h
Normal file
12
cpp/LunaHook/LunaHook/engine32/CatSystem.h
Normal file
@ -0,0 +1,12 @@
|
||||
|
||||
|
||||
class CatSystem:public ENGINE{
|
||||
public:
|
||||
CatSystem(){
|
||||
|
||||
check_by=CHECK_BY::FILE;
|
||||
check_by_target=L"*.int";
|
||||
is_engine_certain=false;
|
||||
};
|
||||
bool attach_function();
|
||||
};
|
49
cpp/LunaHook/LunaHook/engine32/Ciel.cpp
Normal file
49
cpp/LunaHook/LunaHook/engine32/Ciel.cpp
Normal file
@ -0,0 +1,49 @@
|
||||
#include"Ciel.h"
|
||||
|
||||
bool CielFilter(LPVOID data, size_t *size, HookParam *)
|
||||
{
|
||||
auto text = reinterpret_cast<LPSTR>(data);
|
||||
auto len = reinterpret_cast<size_t *>(size);
|
||||
|
||||
if (*len == 1) return false;
|
||||
|
||||
//StringCharReplacer(text, len, "^n", 2, ' ');
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool InsertCielHook()
|
||||
{
|
||||
|
||||
/*
|
||||
* Sample games:
|
||||
* https://vndb.org/r26480
|
||||
* https://vndb.org/v1648
|
||||
* https://vndb.org/v10392
|
||||
*/
|
||||
const BYTE bytes[] = {
|
||||
0x50, // push eax << hook here
|
||||
0xE8, XX4, // call FaultA.exe+81032
|
||||
0x83, 0xC4, 0x04, // add esp,04
|
||||
0x85, 0xC0, // test eax,eax
|
||||
0x74, 0x32, // je FaultA.exe+41FA6
|
||||
0x81, 0x7C, 0x24, 0x10, XX4 // cmp [esp+10],000003FE
|
||||
};
|
||||
|
||||
ULONG range = min(processStopAddress - processStartAddress, MAX_REL_ADDR);
|
||||
ULONG addr = MemDbg::findBytes(bytes, sizeof(bytes), processStartAddress, processStartAddress + range);
|
||||
if (!addr) return false;
|
||||
|
||||
HookParam hp;
|
||||
hp.address = addr;
|
||||
hp.offset=get_reg(regs::edi);
|
||||
hp.index = 0;
|
||||
hp.type = DATA_INDIRECT;
|
||||
hp.filter_fun = CielFilter;
|
||||
|
||||
return NewHook(hp, "Ciel");
|
||||
}
|
||||
bool Ciel::attach_function() {
|
||||
|
||||
return InsertCielHook();
|
||||
}
|
11
cpp/LunaHook/LunaHook/engine32/Ciel.h
Normal file
11
cpp/LunaHook/LunaHook/engine32/Ciel.h
Normal file
@ -0,0 +1,11 @@
|
||||
|
||||
|
||||
class Ciel:public ENGINE{
|
||||
public:
|
||||
Ciel(){
|
||||
|
||||
check_by=CHECK_BY::FILE;
|
||||
check_by_target=L"sys/kidoku.dat";
|
||||
};
|
||||
bool attach_function();
|
||||
};
|
82
cpp/LunaHook/LunaHook/engine32/Circus1.cpp
Normal file
82
cpp/LunaHook/LunaHook/engine32/Circus1.cpp
Normal file
@ -0,0 +1,82 @@
|
||||
#include"Circus1.h"
|
||||
/********************************************************************************************
|
||||
CIRCUS hook:
|
||||
Game folder contains advdata folder. Used by CIRCUS games.
|
||||
Usually has font caching issues. But trace back from GetGlyphOutline gives a hook
|
||||
which generate repetition.
|
||||
If we study circus engine follow Freaka's video, we can easily discover that
|
||||
in the game main module there is a static buffer, which is filled by new text before
|
||||
it's drawing to screen. By setting a hardware breakpoint there we can locate the
|
||||
function filling the buffer. But we don't have to set hardware breakpoint to search
|
||||
the hook address if we know some characteristic instruction(cmp al,0x24) around there.
|
||||
********************************************************************************************/
|
||||
bool InsertCircusHook1() // jichi 10/2/2013: Change return type to bool
|
||||
{
|
||||
for (DWORD i = processStartAddress + 0x1000; i < processStopAddress - 4; i++)
|
||||
if (*(WORD *)i == 0xa3c) //cmp al, 0xA; je
|
||||
for (DWORD j = i; j < i + 0x100; j++) {
|
||||
BYTE c = *(BYTE *)j;
|
||||
if (c == 0xc3)
|
||||
break;
|
||||
if (c == 0xe8) {
|
||||
DWORD k = *(DWORD *)(j+1)+j+5;
|
||||
if (k > processStartAddress && k < processStopAddress) {
|
||||
HookParam hp;
|
||||
hp.address = k;
|
||||
hp.offset=get_stack(3);
|
||||
hp.split =get_reg(regs::esp);
|
||||
hp.type = DATA_INDIRECT|USING_SPLIT;
|
||||
ConsoleOutput("INSERT CIRCUS#1");
|
||||
|
||||
//RegisterEngineType(ENGINE_CIRCUS);
|
||||
return NewHook(hp, "Circus1");
|
||||
}
|
||||
}
|
||||
}
|
||||
//break;
|
||||
//ConsoleOutput("Unknown CIRCUS engine");
|
||||
ConsoleOutput("CIRCUS1: failed");
|
||||
return false;
|
||||
}
|
||||
namespace{
|
||||
//C.D.C.D.2~シーディーシーディー2~
|
||||
//https://vndb.org/v947
|
||||
bool circus12()
|
||||
{
|
||||
BYTE sig[]={
|
||||
0x3C,0x24,
|
||||
0x0F,0x85,XX4,
|
||||
0x8A,0x47,0x01,
|
||||
0x47,
|
||||
0x3C,0x6E,
|
||||
0x75,XX,
|
||||
0xA0,XX4,
|
||||
0xB9,XX4,
|
||||
0x84,0xC0,
|
||||
0x0F,0x84,XX4,
|
||||
0x88,0x06,
|
||||
0x8A,0x41,0x01,
|
||||
0x46,
|
||||
0x41,
|
||||
0x84,0xC0,
|
||||
0x75,XX,
|
||||
0xE9,XX4,
|
||||
0x3C,0x66,
|
||||
0x75,XX
|
||||
};
|
||||
auto addr=MemDbg::findBytes(sig,sizeof(sig),processStartAddress,processStopAddress);
|
||||
if(!addr)return false;
|
||||
addr=MemDbg::findEnclosingAlignedFunction(addr,0x40);
|
||||
if(!addr)return false;
|
||||
HookParam hp;
|
||||
hp.address =addr;
|
||||
hp.offset=get_stack(2);
|
||||
hp.type = USING_STRING|EMBED_ABLE|EMBED_AFTER_NEW|EMBED_DYNA_SJIS;
|
||||
hp.hook_font=F_GetGlyphOutlineA;
|
||||
return NewHook(hp, "Circus1");
|
||||
}
|
||||
}
|
||||
bool Circus1::attach_function() {
|
||||
|
||||
return InsertCircusHook1()|circus12();
|
||||
}
|
11
cpp/LunaHook/LunaHook/engine32/Circus1.h
Normal file
11
cpp/LunaHook/LunaHook/engine32/Circus1.h
Normal file
@ -0,0 +1,11 @@
|
||||
|
||||
|
||||
class Circus1:public ENGINE{
|
||||
public:
|
||||
Circus1(){
|
||||
|
||||
check_by=CHECK_BY::FILE;
|
||||
check_by_target=L"AdvData\\DAT\\NAMES.DAT";
|
||||
};
|
||||
bool attach_function();
|
||||
};
|
393
cpp/LunaHook/LunaHook/engine32/Circus2.cpp
Normal file
393
cpp/LunaHook/LunaHook/engine32/Circus2.cpp
Normal file
@ -0,0 +1,393 @@
|
||||
#include"Circus2.h"
|
||||
namespace{
|
||||
bool filter(void* data, size_t* len, HookParam* hp){
|
||||
if (strstr((char*)data,"@i")||strstr((char*)data,"@y"))return false;
|
||||
//{てんきゅう/天穹}
|
||||
if(strstr((char*)data,"\x81\x6f")&&strstr((char*)data,"\x81\x5e")&&strstr((char*)data,"\x81\x70")){
|
||||
StringFilter((char*)data, len, "\x81\x70", 2);
|
||||
StringFilterBetween((char*)data,len, "\x81\x6f", 2, "\x81\x5e", 2);
|
||||
}
|
||||
return true;
|
||||
};
|
||||
}
|
||||
/**
|
||||
* jichi 6/5/2014: Sample function from DC3 at 0x4201d0
|
||||
* 004201ce cc int3
|
||||
* 004201cf cc int3
|
||||
* 004201d0 /$ 8b4c24 08 mov ecx,dword ptr ss:[esp+0x8]
|
||||
* 004201d4 |. 8a01 mov al,byte ptr ds:[ecx]
|
||||
* 004201d6 |. 84c0 test al,al
|
||||
* 004201d8 |. 74 1c je short dc3.004201f6
|
||||
* 004201da |. 8b5424 04 mov edx,dword ptr ss:[esp+0x4]
|
||||
* 004201de |. 8bff mov edi,edi
|
||||
* 004201e0 |> 3c 24 /cmp al,0x24
|
||||
* 004201e2 |. 75 05 |jnz short dc3.004201e9
|
||||
* 004201e4 |. 83c1 02 |add ecx,0x2
|
||||
* 004201e7 |. eb 04 |jmp short dc3.004201ed
|
||||
* 004201e9 |> 8802 |mov byte ptr ds:[edx],al
|
||||
* 004201eb |. 42 |inc edx
|
||||
* 004201ec |. 41 |inc ecx
|
||||
* 004201ed |> 8a01 |mov al,byte ptr ds:[ecx]
|
||||
* 004201ef |. 84c0 |test al,al
|
||||
* 004201f1 |.^75 ed \jnz short dc3.004201e0
|
||||
* 004201f3 |. 8802 mov byte ptr ds:[edx],al
|
||||
* 004201f5 |. c3 retn
|
||||
* 004201f6 |> 8b4424 04 mov eax,dword ptr ss:[esp+0x4]
|
||||
* 004201fa |. c600 00 mov byte ptr ds:[eax],0x0
|
||||
* 004201fd \. c3 retn
|
||||
*/
|
||||
bool InsertCircusHook2() // jichi 10/2/2013: Change return type to bool
|
||||
{
|
||||
for (DWORD i = processStartAddress + 0x1000; i < processStopAddress -4; i++)
|
||||
if ((*(DWORD *)i & 0xffffff) == 0x75243c) { // cmp al, 24; je
|
||||
if (DWORD j = SafeFindEnclosingAlignedFunction(i, 0x80)) {
|
||||
HookParam hp;
|
||||
hp.address = j;
|
||||
hp.offset=get_stack(2);
|
||||
//hp.filter_fun = CharNewLineFilter; // \n\s* is used to remove new line
|
||||
hp.type = USING_STRING;
|
||||
//GROWL_DWORD(hp.address); // jichi 6/5/2014: 0x4201d0 for DC3
|
||||
|
||||
//RegisterEngineType(ENGINE_CIRCUS);
|
||||
return NewHook(hp, "Circus");
|
||||
}
|
||||
break;
|
||||
}
|
||||
//ConsoleOutput("Unknown CIRCUS engine.");
|
||||
ConsoleOutput("CIRCUS: failed");
|
||||
return false;
|
||||
}
|
||||
namespace{
|
||||
bool c2(){
|
||||
//D.C.III Dream Days~ダ・カーポIII~ドリームデイズ
|
||||
auto entry=Util::FindImportEntry(processStartAddress,(DWORD)GetGlyphOutlineA);
|
||||
DWORD funcaddr=0;
|
||||
if(entry==0)return false;
|
||||
for (auto addr : Util::SearchMemory(&entry, 4, PAGE_EXECUTE, processStartAddress, processStopAddress) ) {
|
||||
DWORD _=0xCCCCCCCC;
|
||||
funcaddr=reverseFindBytes((BYTE*)&_,4,addr-0x1000,addr);
|
||||
//funcaddr=MemDbg::findEnclosingAlignedFunction(addr,0x1000);ConsoleOutput("%p",funcaddr);
|
||||
}
|
||||
if(funcaddr==0)return false;
|
||||
funcaddr+=4;
|
||||
HookParam hp;
|
||||
hp.address = funcaddr;
|
||||
hp.offset=get_stack(2);
|
||||
hp.type = USING_STRING;//|EMBED_ABLE|EMBED_AFTER_NEW|EMBED_DYNA_SJIS;
|
||||
//hp.hook_font=F_GetGlyphOutlineA;
|
||||
//it will split a long to many lines
|
||||
hp.filter_fun=filter;
|
||||
|
||||
return NewHook(hp, "Circus2");
|
||||
}
|
||||
}
|
||||
|
||||
namespace { // unnamed
|
||||
|
||||
// Skip leading tags such as @K and @c5
|
||||
template <typename strT>
|
||||
strT ltrim(strT s)
|
||||
{
|
||||
if (s && *s == '@')
|
||||
while ((signed char)*++s > 0);
|
||||
return s;
|
||||
}
|
||||
|
||||
namespace ScenarioHook {
|
||||
namespace Private {
|
||||
|
||||
DWORD nameReturnAddress_,
|
||||
scenarioReturnAddress_;
|
||||
|
||||
/**
|
||||
* Sample game: DC3, function: 0x4201d0
|
||||
*
|
||||
* IDA: sub_4201D0 proc near
|
||||
* - arg_0 = dword ptr 4
|
||||
* - arg_4 = dword ptr 8
|
||||
*
|
||||
* Observations:
|
||||
* - arg1: LPVOID, pointed to unknown object
|
||||
* - arg2: LPCSTR, the actual text
|
||||
*
|
||||
* Example runtime stack:
|
||||
* 0012F15C 0040C208 RETURN to .0040C208 from .00420460
|
||||
* 0012F160 0012F7CC ; jichi: unknown stck
|
||||
* 0012F164 0012F174 ; jichi: text
|
||||
* 0012F168 0012F6CC
|
||||
* 0012F16C 0012F7CC
|
||||
* 0012F170 0012F7CC
|
||||
*/
|
||||
void hookafter(hook_stack*s,void* data, size_t len){
|
||||
|
||||
auto newData =std::string((char*)data,len);
|
||||
LPCSTR text = (LPCSTR)s->stack[2], // arg2
|
||||
trimmedText = ltrim(text);
|
||||
if (trimmedText != text)
|
||||
newData.insert(0,std::string(text, trimmedText - text));
|
||||
s->stack[2]=(DWORD)allocateString(newData);
|
||||
}
|
||||
void hookBefore(hook_stack *s, HookParam *hp, TextBuffer *buffer, uintptr_t *role)
|
||||
{
|
||||
|
||||
LPCSTR text = (LPCSTR)s->stack[2], // arg2
|
||||
trimmedText = ltrim(text);
|
||||
if (!trimmedText || !*trimmedText)
|
||||
return ;
|
||||
auto retaddr = s->stack[0]; // retaddr
|
||||
* role = retaddr == scenarioReturnAddress_ ? Engine::ScenarioRole :
|
||||
retaddr == nameReturnAddress_ ? Engine::NameRole :
|
||||
Engine::OtherRole;
|
||||
//s->ebx? Engine::OtherRole : // other threads ebx is not zero
|
||||
//// 004201e4 |. 83c1 02 |add ecx,0x2
|
||||
//// 004201e7 |. eb 04 |jmp short dc3.004201ed
|
||||
//*(BYTE *)(retaddr + 3) == 0xe9 // old name
|
||||
//? Engine::NameRole : // retaddr+3 is jmp
|
||||
//Engine::ScenarioRole;
|
||||
buffer->from_cs(trimmedText);
|
||||
}
|
||||
|
||||
// Alternatively, using the following pattern bytes also works:
|
||||
//
|
||||
// 3c24750583c102eb0488024241
|
||||
//
|
||||
// 004201e0 |> 3c 24 /cmp al,0x24
|
||||
// 004201e2 |. 75 05 |jnz short dc3.004201e9
|
||||
// 004201e4 |. 83c1 02 |add ecx,0x2
|
||||
// 004201e7 |. eb 04 |jmp short dc3.004201ed
|
||||
// 004201e9 |> 8802 |mov byte ptr ds:[edx],al
|
||||
// 004201eb |. 42 |inc edx
|
||||
// 004201ec |. 41 |inc ecx
|
||||
ULONG findFunctionAddress(ULONG startAddress, ULONG stopAddress) // find the function to hook
|
||||
{
|
||||
//return 0x4201d0; // DC3 function address
|
||||
for (ULONG i = startAddress + 0x1000; i < stopAddress -4; i++)
|
||||
// * 004201e0 |> 3c 24 /cmp al,0x24
|
||||
// * 004201e2 |. 75 05 |jnz short dc3.004201e9
|
||||
if ((*(ULONG *)i & 0xffffff) == 0x75243c) { // cmp al, 24; je
|
||||
enum { range = 0x80 }; // the range is small, since it is a small function
|
||||
if (ULONG addr = MemDbg::findEnclosingAlignedFunction(i, range))
|
||||
return addr;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // namespace Private
|
||||
|
||||
/**
|
||||
* jichi 6/5/2014: Sample function from DC3 at 0x4201d0
|
||||
*
|
||||
* Sample game: DC3PP
|
||||
* 0042CE1E 68 E0F0B700 PUSH .00B7F0E0
|
||||
* 0042CE23 A3 0C824800 MOV DWORD PTR DS:[0x48820C],EAX
|
||||
* 0042CE28 E8 A352FFFF CALL .004220D0 ; jichi: name thread
|
||||
* 0042CE2D C705 08024D00 01>MOV DWORD PTR DS:[0x4D0208],0x1
|
||||
* 0042CE37 EB 52 JMP SHORT .0042CE8B
|
||||
* 0042CE39 392D 08024D00 CMP DWORD PTR DS:[0x4D0208],EBP
|
||||
* 0042CE3F 74 08 JE SHORT .0042CE49
|
||||
* 0042CE41 392D 205BB900 CMP DWORD PTR DS:[0xB95B20],EBP
|
||||
* 0042CE47 74 07 JE SHORT .0042CE50
|
||||
* 0042CE49 C605 E0F0B700 00 MOV BYTE PTR DS:[0xB7F0E0],0x0
|
||||
* 0042CE50 8D5424 40 LEA EDX,DWORD PTR SS:[ESP+0x40]
|
||||
* 0042CE54 52 PUSH EDX
|
||||
* 0042CE55 68 30B5BA00 PUSH .00BAB530
|
||||
* 0042CE5A 892D 08024D00 MOV DWORD PTR DS:[0x4D0208],EBP
|
||||
* 0042CE60 E8 6B52FFFF CALL .004220D0 ; jichi: scenario thread
|
||||
* 0042CE65 C705 A0814800 FF>MOV DWORD PTR DS:[0x4881A0],-0x1
|
||||
* 0042CE6F 892D 2C824800 MOV DWORD PTR DS:[0x48822C],EBP
|
||||
*
|
||||
* Sample game: 水夏弐律
|
||||
*
|
||||
* 004201ce cc int3
|
||||
* 004201cf cc int3
|
||||
* 004201d0 /$ 8b4c24 08 mov ecx,dword ptr ss:[esp+0x8]
|
||||
* 004201d4 |. 8a01 mov al,byte ptr ds:[ecx]
|
||||
* 004201d6 |. 84c0 test al,al
|
||||
* 004201d8 |. 74 1c je short dc3.004201f6
|
||||
* 004201da |. 8b5424 04 mov edx,dword ptr ss:[esp+0x4]
|
||||
* 004201de |. 8bff mov edi,edi
|
||||
* 004201e0 |> 3c 24 /cmp al,0x24
|
||||
* 004201e2 |. 75 05 |jnz short dc3.004201e9
|
||||
* 004201e4 |. 83c1 02 |add ecx,0x2
|
||||
* 004201e7 |. eb 04 |jmp short dc3.004201ed
|
||||
* 004201e9 |> 8802 |mov byte ptr ds:[edx],al
|
||||
* 004201eb |. 42 |inc edx
|
||||
* 004201ec |. 41 |inc ecx
|
||||
* 004201ed |> 8a01 |mov al,byte ptr ds:[ecx]
|
||||
* 004201ef |. 84c0 |test al,al
|
||||
* 004201f1 |.^75 ed \jnz short dc3.004201e0
|
||||
* 004201f3 |. 8802 mov byte ptr ds:[edx],al
|
||||
* 004201f5 |. c3 retn
|
||||
* 004201f6 |> 8b4424 04 mov eax,dword ptr ss:[esp+0x4]
|
||||
* 004201fa |. c600 00 mov byte ptr ds:[eax],0x0
|
||||
* 004201fd \. c3 retn
|
||||
*
|
||||
* Sample registers:
|
||||
* EAX 0012F998
|
||||
* ECX 000000DB
|
||||
* EDX 00000059
|
||||
* EBX 00000000 ; ebx is zero for name/scenario thread
|
||||
* ESP 0012F96C
|
||||
* EBP 00000003
|
||||
* ESI 00000025
|
||||
* EDI 000000DB
|
||||
* EIP 022C0000
|
||||
*
|
||||
* EAX 0012F174
|
||||
* ECX 0012F7CC
|
||||
* EDX FDFBF80C
|
||||
* EBX 0012F6CC
|
||||
* ESP 0012F15C
|
||||
* EBP 0012F5CC
|
||||
* ESI 800000DB
|
||||
* EDI 00000001
|
||||
* EIP 00420460 .00420460
|
||||
*
|
||||
* EAX 0012F174
|
||||
* ECX 0012F7CC
|
||||
* EDX FDFBF7DF
|
||||
* EBX 0012F6CC
|
||||
* ESP 0012F15C
|
||||
* EBP 0012F5CC
|
||||
* ESI 00000108
|
||||
* EDI 00000001
|
||||
* EIP 00420460 .00420460
|
||||
*
|
||||
* 0042DC5D 52 PUSH EDX
|
||||
* 0042DC5E 68 E038AC00 PUSH .00AC38E0 ; ASCII "Ami"
|
||||
* 0042DC63 E8 F827FFFF CALL .00420460 ; jichi: name thread
|
||||
* 0042DC68 83C4 08 ADD ESP,0x8
|
||||
* 0042DC6B E9 48000000 JMP .0042DCB8
|
||||
* 0042DC70 83FD 58 CMP EBP,0x58
|
||||
* 0042DC73 74 07 JE SHORT .0042DC7C
|
||||
* 0042DC75 C605 E038AC00 00 MOV BYTE PTR DS:[0xAC38E0],0x0
|
||||
* 0042DC7C 8D4424 20 LEA EAX,DWORD PTR SS:[ESP+0x20]
|
||||
* 0042DC80 50 PUSH EAX
|
||||
* 0042DC81 68 0808AF00 PUSH .00AF0808
|
||||
* 0042DC86 E8 D527FFFF CALL .00420460 ; jichi: scenario thread
|
||||
* 0042DC8B 83C4 08 ADD ESP,0x8
|
||||
* 0042DC8E 33C0 XOR EAX,EAX
|
||||
* 0042DC90 C705 D0DF4700 FF>MOV DWORD PTR DS:[0x47DFD0],-0x1
|
||||
* 0042DC9A A3 0CE04700 MOV DWORD PTR DS:[0x47E00C],EAX
|
||||
* 0042DC9F A3 940EB200 MOV DWORD PTR DS:[0xB20E94],EAX
|
||||
* 0042DCA4 A3 2C65AC00 MOV DWORD PTR DS:[0xAC652C],EAX
|
||||
* 0042DCA9 C705 50F9AC00 59>MOV DWORD PTR DS:[0xACF950],0x59
|
||||
* 0042DCB3 A3 3C70AE00 MOV DWORD PTR DS:[0xAE703C],EAX
|
||||
*/
|
||||
bool attach(ULONG startAddress, ULONG stopAddress)
|
||||
{
|
||||
ULONG addr = Private::findFunctionAddress(startAddress, stopAddress);
|
||||
if (!addr)
|
||||
return false;
|
||||
// Find the nearest two callers (distance within 100)
|
||||
ULONG lastCall = 0;
|
||||
auto fun = [&lastCall](ULONG call) -> bool {
|
||||
// scenario: 0x42b78c
|
||||
// name: 0x42b754
|
||||
if (call - lastCall < 100) {
|
||||
Private::scenarioReturnAddress_ = call + 5;
|
||||
Private::nameReturnAddress_ = lastCall + 5;
|
||||
return false; // found target
|
||||
}
|
||||
lastCall = call;
|
||||
return true; // replace all functions
|
||||
};
|
||||
MemDbg::iterNearCallAddress(fun, addr, startAddress, stopAddress);
|
||||
if (!Private::scenarioReturnAddress_ && lastCall) {
|
||||
Private::scenarioReturnAddress_ = lastCall + 5;
|
||||
}
|
||||
HookParam hp;
|
||||
hp.address=addr;
|
||||
hp.filter_fun=filter;
|
||||
hp.text_fun=Private::hookBefore;
|
||||
hp.hook_after=Private::hookafter;
|
||||
hp.hook_font=F_GetGlyphOutlineA;
|
||||
hp.type=USING_STRING|EMBED_ABLE|NO_CONTEXT|EMBED_DYNA_SJIS;
|
||||
|
||||
|
||||
return NewHook(hp,"EmbedCircus");
|
||||
}
|
||||
|
||||
} // namespace ScenarioHook
|
||||
|
||||
} // unnamed namespace
|
||||
bool InsertCircusHook3()
|
||||
{
|
||||
/*
|
||||
* Sample games:
|
||||
* https://vndb.org/v20218
|
||||
*/
|
||||
const BYTE bytes[] = {
|
||||
0xCC, // int 3
|
||||
0x81, 0xEC, XX4, // sub esp,000004E0 << hook here
|
||||
0xA1, XX4, // mov eax,[DSIF.EXE+AD288]
|
||||
0x33, 0xC4, // xor eax,esp
|
||||
0x89, 0x84, 0x24, XX4, // mov [esp+000004DC],eax
|
||||
0x8B, 0x84, 0x24, XX4, // mov eax,[esp+000004E4]
|
||||
0x53, // push ebx
|
||||
0x55, // push ebp
|
||||
0x56, // push esi
|
||||
0x8B, 0xB4, 0x24, XX4 // mov esi,[esp+000004F4]
|
||||
};
|
||||
ULONG range = min(processStopAddress - processStartAddress, MAX_REL_ADDR);
|
||||
ULONG addr = MemDbg::findBytes(bytes, sizeof(bytes), processStartAddress, processStartAddress + range);
|
||||
if (!addr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
HookParam hp;
|
||||
hp.address = addr + 1;
|
||||
hp.offset=get_reg(regs::esi);
|
||||
hp.split = get_reg(regs::ecx);
|
||||
hp.type = USING_STRING | USING_SPLIT;
|
||||
return NewHook(hp, "Circus3");
|
||||
}
|
||||
|
||||
bool CircusFilter(LPVOID data, size_t *size, HookParam *)
|
||||
{
|
||||
auto text = reinterpret_cast<LPSTR>(data);
|
||||
auto len = reinterpret_cast<size_t *>(size);
|
||||
|
||||
//ConsoleOutput("debug:Circus: -%.*s-", *len, text);
|
||||
if (*len <= 1 || cpp_strnstr(text, "\\", *len) || (text[0] == '&' && text[1] == 'n'))
|
||||
return false;
|
||||
|
||||
CharReplacer(text, len, '\n', ' ');
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool InsertCircusHook4()
|
||||
{
|
||||
/*
|
||||
* Sample games:
|
||||
* https://vndb.org/r46909
|
||||
*/
|
||||
const BYTE bytes[] = {
|
||||
0x83, 0xF8, 0xFF, // cmp eax,-01 << hook here
|
||||
0x0F, 0x84, XX4, // je DST.exe+1BCF0
|
||||
0x8B, 0x0D, XX4 // mov ecx,[DST.exe+A41F0]
|
||||
};
|
||||
ULONG range = min(processStopAddress - processStartAddress, MAX_REL_ADDR);
|
||||
ULONG addr = MemDbg::findBytes(bytes, sizeof(bytes), processStartAddress, processStartAddress + range);
|
||||
if (!addr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
HookParam hp;
|
||||
hp.address = addr;
|
||||
hp.offset=get_reg(regs::edx);
|
||||
hp.split =get_stack(4); //arg4
|
||||
hp.padding = 0x40;
|
||||
hp.type = USING_STRING | USING_SPLIT;
|
||||
hp.filter_fun = CircusFilter;
|
||||
|
||||
return NewHook(hp, "Circus4");
|
||||
}
|
||||
bool Circus2::attach_function() {
|
||||
bool ch2=InsertCircusHook2();
|
||||
bool _1= ch2||c2();
|
||||
bool _2=ch2|| InsertCircusHook3() || InsertCircusHook4();
|
||||
bool embed=ScenarioHook::attach(processStartAddress,processStopAddress);
|
||||
return _1||embed||_2;
|
||||
}
|
11
cpp/LunaHook/LunaHook/engine32/Circus2.h
Normal file
11
cpp/LunaHook/LunaHook/engine32/Circus2.h
Normal file
@ -0,0 +1,11 @@
|
||||
|
||||
|
||||
class Circus2:public ENGINE{
|
||||
public:
|
||||
Circus2(){
|
||||
|
||||
check_by=CHECK_BY::FILE;
|
||||
check_by_target=L"AdvData\\GRP\\NAMES.DAT";
|
||||
};
|
||||
bool attach_function();
|
||||
};
|
67
cpp/LunaHook/LunaHook/engine32/CisLugI.cpp
Normal file
67
cpp/LunaHook/LunaHook/engine32/CisLugI.cpp
Normal file
@ -0,0 +1,67 @@
|
||||
#include "CisLugI.h"
|
||||
|
||||
bool CisLugI::attach_function()
|
||||
{
|
||||
// int __cdecl common_tcsncpy_s<char>(_BYTE *a1, int a2, int a3, int a4)
|
||||
// errno_t __cdecl strncpy_s(char *Destination, rsize_t SizeInBytes, const char *Source, rsize_t MaxCount)
|
||||
// {
|
||||
// return common_tcsncpy_s<char>(Destination, SizeInBytes, (int)Source, MaxCount);
|
||||
// }
|
||||
BYTE sig[] = {
|
||||
0x8b,
|
||||
0xff,
|
||||
0x55,
|
||||
0x8b,
|
||||
0xec,
|
||||
0x51,
|
||||
0x8b,
|
||||
XX,
|
||||
0x14,
|
||||
0x8b,
|
||||
XX,
|
||||
0x08,
|
||||
0x56,
|
||||
0x85,
|
||||
XX,
|
||||
0x75,
|
||||
XX,
|
||||
0x85,
|
||||
XX,
|
||||
0x75,
|
||||
XX,
|
||||
0x39,
|
||||
XX,
|
||||
0x0c,
|
||||
0x75,
|
||||
XX,
|
||||
0x33,
|
||||
0xc0,
|
||||
0xeb,
|
||||
XX,
|
||||
0x85,
|
||||
XX,
|
||||
0x74,
|
||||
XX,
|
||||
0x8b,
|
||||
XX,
|
||||
0x0c,
|
||||
0x85,
|
||||
XX,
|
||||
0x74,
|
||||
XX,
|
||||
0x85,
|
||||
XX,
|
||||
0x75,
|
||||
XX,
|
||||
|
||||
};
|
||||
auto addr = MemDbg::findBytes(sig, sizeof(sig), processStartAddress, processStopAddress);
|
||||
if (!addr)
|
||||
return false;
|
||||
HookParam hp;
|
||||
hp.address = addr;
|
||||
hp.type = USING_STRING;
|
||||
hp.offset = get_stack(3);
|
||||
|
||||
return NewHook(hp, "CisLugI");
|
||||
}
|
14
cpp/LunaHook/LunaHook/engine32/CisLugI.h
Normal file
14
cpp/LunaHook/LunaHook/engine32/CisLugI.h
Normal file
@ -0,0 +1,14 @@
|
||||
#include "engine.h"
|
||||
|
||||
class CisLugI : public ENGINE
|
||||
{
|
||||
public:
|
||||
CisLugI()
|
||||
{
|
||||
// CisLugI-シスラギ-
|
||||
// https://vndb.org/v23679
|
||||
check_by = CHECK_BY::FILE_ALL;
|
||||
check_by_target = check_by_list{L"chara.rvk5", L"back.rvk5", L"bgm.rvk5", L"container*.rvk5", L"script/*.rvk5", L"Sgr/*.rvk5"};
|
||||
};
|
||||
bool attach_function();
|
||||
};
|
147
cpp/LunaHook/LunaHook/engine32/CodeX.cpp
Normal file
147
cpp/LunaHook/LunaHook/engine32/CodeX.cpp
Normal file
@ -0,0 +1,147 @@
|
||||
#include "CodeX.h"
|
||||
|
||||
bool CodeXFilter(LPVOID data, size_t *size, HookParam *)
|
||||
{
|
||||
std::string result = std::string((char *)data, *size);
|
||||
strReplace(result, "^n", "\n");
|
||||
if (startWith(result, "\n"))
|
||||
result = result.substr(1);
|
||||
|
||||
//|晒[さら]
|
||||
result = std::regex_replace(result, std::regex("\\|(.+?)\\[(.+?)\\]"), "$1");
|
||||
|
||||
return write_string_overwrite(data, size, result);
|
||||
}
|
||||
|
||||
bool InsertCodeXHook()
|
||||
{
|
||||
|
||||
/*
|
||||
* Sample games:
|
||||
* https://vndb.org/v41664
|
||||
* https://vndb.org/v36122
|
||||
*/
|
||||
const BYTE bytes[] = {
|
||||
0x83, 0xC4, 0x08, // add esp,08 << hook here
|
||||
0x8D, 0x85, XX4, // lea eax,[ebp-00000218]
|
||||
0x50, // push eax
|
||||
0x68, XX4, // push ???????????!.exe+10A76C
|
||||
0x85, 0xF6, // test esi,esi
|
||||
0x74, 0x4F, // je ???????????!.exe+2A95B
|
||||
0xFF, 0x15, XX4, // call dword ptr [???????????!.exe+C8140]
|
||||
0x8B, 0x85, XX4 // mov eax,[ebp-00000220] << alternative hook here
|
||||
};
|
||||
|
||||
ULONG range = min(processStopAddress - processStartAddress, MAX_REL_ADDR);
|
||||
ULONG addr = MemDbg::findBytes(bytes, sizeof(bytes), processStartAddress, processStartAddress + range);
|
||||
if (!addr)
|
||||
{
|
||||
ConsoleOutput("CodeX: pattern not found");
|
||||
return false;
|
||||
}
|
||||
|
||||
HookParam hp;
|
||||
hp.address = addr;
|
||||
hp.offset = get_reg(regs::eax);
|
||||
hp.index = 0;
|
||||
hp.type = USING_STRING | EMBED_ABLE | EMBED_AFTER_OVERWRITE | NO_CONTEXT; // 无法解决中文乱码
|
||||
hp.hook_font = F_GetGlyphOutlineA;
|
||||
hp.filter_fun = CodeXFilter;
|
||||
ConsoleOutput("INSERT CodeX");
|
||||
|
||||
return NewHook(hp, "CodeX");
|
||||
}
|
||||
namespace
|
||||
{
|
||||
bool hook()
|
||||
{
|
||||
// 霞外籠逗留記
|
||||
BYTE _[] = {0x90, 0x90, 0x68, 0x64, 0x7B, 0x4C, 0x00}; // aHdL db 'hd{L',0
|
||||
ULONG addr = MemDbg::findBytes(_, sizeof(_), processStartAddress, processStopAddress);
|
||||
if (addr == 0)
|
||||
return false;
|
||||
addr += 2;
|
||||
BYTE bytes[] = {0x68, XX4};
|
||||
memcpy(bytes + 1, &addr, 4);
|
||||
auto addrs = Util::SearchMemory(bytes, sizeof(bytes), PAGE_EXECUTE, processStartAddress, processStopAddress);
|
||||
bool succ = false;
|
||||
for (auto adr : addrs)
|
||||
{
|
||||
adr = MemDbg::findEnclosingAlignedFunction(adr);
|
||||
if (adr == 0)
|
||||
continue;
|
||||
HookParam hp;
|
||||
hp.address = adr;
|
||||
hp.offset = get_stack(1);
|
||||
hp.type = CODEC_ANSI_BE;
|
||||
succ |= NewHook(hp, "CodeX");
|
||||
}
|
||||
return succ;
|
||||
}
|
||||
}
|
||||
namespace
|
||||
{
|
||||
// https://vndb.org/v598
|
||||
// ANGEL BULLET
|
||||
bool hook2()
|
||||
{
|
||||
BYTE _[] = {
|
||||
0x8b, 0x44, 0x24, 0x04,
|
||||
0x81, 0xec, XX4,
|
||||
0x25, 0xff, 0xff, 0, 0,
|
||||
0x8d, 0x54, 0x24, 0,
|
||||
0x56,
|
||||
0x8b, 0xf1,
|
||||
0x50,
|
||||
0x8d, 0x4e, XX,
|
||||
0x51,
|
||||
0x68, XX4, //%s%03d
|
||||
0x52,
|
||||
0xff, 0x15, XX4, // wprintfA
|
||||
};
|
||||
ULONG addr = MemDbg::findBytes(_, sizeof(_), processStartAddress, processStopAddress);
|
||||
if (addr == 0)
|
||||
return false;
|
||||
HookParam hp;
|
||||
hp.address = addr;
|
||||
hp.offset = get_reg(regs::edx);
|
||||
hp.type = USING_STRING;
|
||||
hp.filter_fun = CodeXFilter;
|
||||
return NewHook(hp, "CodeX");
|
||||
}
|
||||
}
|
||||
namespace
|
||||
{
|
||||
bool hook3()
|
||||
{
|
||||
BYTE _[] = {
|
||||
// if ( *(_WORD *)v38 == 8511 || (_WORD)v5 == 16161 || (_WORD)v5 == 8481 )
|
||||
0xB9, 0x3F, 0x21, 0x00, 0x00, // mov ecx, 213Fh
|
||||
0x0F, 0xB7, 0x02, // movzx eax, word ptr [edx]
|
||||
0x66, 0x3B, 0xC1, // cmp ax, cx
|
||||
0x0F, 0x84, XX4, // jz loc_458294
|
||||
0xb9, 0x21, 0x3f, 0x00, 0x00, // mov ecx, 3F21h
|
||||
0x66, 0x3B, 0xC1,
|
||||
0x0F, 0x84, XX4,
|
||||
0xb9, 0x21, 0x21, 0x00, 0x00, // mov ecx, 2121h
|
||||
0x66, 0x3B, 0xC1,
|
||||
0x0F, 0x84, XX4};
|
||||
ULONG addr = MemDbg::findBytes(_, sizeof(_), processStartAddress, processStopAddress);
|
||||
if (addr == 0)
|
||||
return false;
|
||||
addr = MemDbg::findEnclosingAlignedFunction(addr);
|
||||
if (addr == 0)
|
||||
return false;
|
||||
HookParam hp;
|
||||
hp.address = addr;
|
||||
hp.offset = get_stack(1);
|
||||
hp.type = USING_STRING | FULL_STRING | NO_CONTEXT;
|
||||
// 这个可以提取到人名,但是会把一堆字体名给hook进去,所以不要内嵌
|
||||
hp.filter_fun = CodeXFilter;
|
||||
return NewHook(hp, "CodeX2");
|
||||
}
|
||||
}
|
||||
bool CodeX::attach_function()
|
||||
{
|
||||
return (hook3() | InsertCodeXHook()) || hook() || hook2();
|
||||
}
|
12
cpp/LunaHook/LunaHook/engine32/CodeX.h
Normal file
12
cpp/LunaHook/LunaHook/engine32/CodeX.h
Normal file
@ -0,0 +1,12 @@
|
||||
|
||||
|
||||
class CodeX:public ENGINE{
|
||||
public:
|
||||
CodeX(){
|
||||
|
||||
check_by=CHECK_BY::FILE;
|
||||
check_by_target=L"*.xfl";
|
||||
is_engine_certain=false;
|
||||
};
|
||||
bool attach_function();
|
||||
};
|
71
cpp/LunaHook/LunaHook/engine32/CoffeeMaker.cpp
Normal file
71
cpp/LunaHook/LunaHook/engine32/CoffeeMaker.cpp
Normal file
@ -0,0 +1,71 @@
|
||||
#include "CoffeeMaker.h"
|
||||
|
||||
bool CoffeeMaker_attach_function()
|
||||
{
|
||||
// https://vndb.org/v4025
|
||||
// こころナビ
|
||||
const BYTE bytes[] = {
|
||||
0x81,0xF9,0xD4,0x2B,0x00,0x00,
|
||||
0x7F,XX,
|
||||
0xB8,0x5D,0x41,0x4C,0xAE,
|
||||
};
|
||||
auto addr = MemDbg::findBytes(bytes, sizeof(bytes), processStartAddress, processStopAddress);
|
||||
if (!addr)
|
||||
return false;
|
||||
addr = MemDbg::findEnclosingAlignedFunction(addr, 0x10);
|
||||
if (!addr)
|
||||
return false;
|
||||
auto addrs = findxref_reverse_checkcallop(addr, addr - 0x1000, addr + 0x1000, 0xe8);
|
||||
if (addrs.size() != 1)
|
||||
return false;
|
||||
auto addr2 = addrs[0];
|
||||
addr2 = MemDbg::findEnclosingAlignedFunction(addr2, 0x40);
|
||||
if (!addr2)
|
||||
return false;
|
||||
HookParam hp;
|
||||
hp.address = addr2;
|
||||
hp.type = USING_CHAR | CODEC_ANSI_BE | NO_CONTEXT;
|
||||
hp.user_value = addr;
|
||||
hp.text_fun = [](hook_stack *stack, HookParam *hp, TextBuffer *buffer, uintptr_t *split)
|
||||
{
|
||||
auto a2 = stack->stack[1];
|
||||
if (a2 > 0x2bd4)
|
||||
return;
|
||||
auto sub_429050 = (int(__stdcall *)(signed int a1))hp->user_value;
|
||||
static int idx = 0;
|
||||
idx += 1;
|
||||
if(idx++%2)
|
||||
buffer->from_t((wchar_t)sub_429050(a2));
|
||||
};
|
||||
|
||||
return NewHook(hp, "CoffeeMaker");
|
||||
}
|
||||
|
||||
bool CoffeeMaker_attach_function2()
|
||||
{
|
||||
// https://vndb.org/v4025
|
||||
// こころナビ
|
||||
const BYTE bytes[] = {
|
||||
0x55,0x8B,0xEC,0x57,0x56,0x8B,0x75,0x0C,0x8B,0x4D,0x10,0x8B,0x7D,0x08,0x8B,0xC1,
|
||||
0x8B,0xD1,0x03,0xC6,0x3B,0xFE,0x76,0x08,0x3B,0xF8,0x0F,0x82,XX4,
|
||||
0xF7,0xC7,0x03,0x00,0x00,0x00,0x75,XX,0xC1,0xE9,0x02,0x83,0xE2,0x03,0x83,0xF9,0x08
|
||||
};
|
||||
auto addr = MemDbg::findBytes(bytes, sizeof(bytes), processStartAddress, processStopAddress);
|
||||
if (!addr)
|
||||
return false;
|
||||
HookParam hp;
|
||||
hp.address = addr;
|
||||
hp.offset=get_stack(1);//get_reg(regs::ecx);//void *__cdecl memcpy(void *a1, const void *Src, size_t Size)
|
||||
hp.type = USING_STRING;
|
||||
hp.filter_fun=[](void* data, size_t* len, HookParam* hp){
|
||||
auto s=std::string((char*)data,*len);
|
||||
strReplace(s,R"(\w\w\w)","");
|
||||
return write_string_overwrite(data,len,s);
|
||||
};
|
||||
return NewHook(hp, "CoffeeMaker");
|
||||
}
|
||||
|
||||
bool CoffeeMaker::attach_function()
|
||||
{
|
||||
return CoffeeMaker_attach_function2()||CoffeeMaker_attach_function();
|
||||
}
|
11
cpp/LunaHook/LunaHook/engine32/CoffeeMaker.h
Normal file
11
cpp/LunaHook/LunaHook/engine32/CoffeeMaker.h
Normal file
@ -0,0 +1,11 @@
|
||||
|
||||
|
||||
class CoffeeMaker:public ENGINE{
|
||||
public:
|
||||
CoffeeMaker(){
|
||||
|
||||
check_by=CHECK_BY::FILE_ALL;
|
||||
check_by_target=check_by_list{L"VIC.EPK",L"MUS.EPK",L"SE.EPK",L"CG.EPK",L"SCR.EPK"};
|
||||
};
|
||||
bool attach_function();
|
||||
};
|
795
cpp/LunaHook/LunaHook/engine32/Cotopha.cpp
Normal file
795
cpp/LunaHook/LunaHook/engine32/Cotopha.cpp
Normal file
@ -0,0 +1,795 @@
|
||||
#include "Cotopha.h"
|
||||
#define s2_mov_ecx_edi 0xcf8b
|
||||
|
||||
namespace
|
||||
{ // unnamed
|
||||
|
||||
namespace ScenarioHook
|
||||
{
|
||||
|
||||
namespace Private
|
||||
{
|
||||
|
||||
/**
|
||||
* Sample game: お兄ちゃん、右手の使用を禁止します! (old type)
|
||||
*
|
||||
* - Name
|
||||
*
|
||||
* EAX 00000000
|
||||
* ECX 04A4C058
|
||||
* EDX 00713FD8 .00713FD8
|
||||
* EBX 17F90130
|
||||
* ESP 0012EBBC
|
||||
* EBP 0020C5A8
|
||||
* ESI 04A4B678
|
||||
* EDI 04A4C058
|
||||
* EIP 005C2E20 .005C2E20
|
||||
*
|
||||
* 0012EBBC 0055D210 RETURN to .0055D210
|
||||
* 0012EBC0 17F90130
|
||||
* 0012EBC4 04A4B678
|
||||
* 0012EBC8 00000000
|
||||
* 0012EBCC 0020C5A8
|
||||
* 0012EBD0 00000000 ; jichi: used to identify name
|
||||
* 0012EBD4 00000000
|
||||
* 0012EBD8 04A4B678
|
||||
* 0012EBDC 00000000
|
||||
* 0012EBE0 0020C5A8
|
||||
* 0012EBE4 00000000
|
||||
* 0012EBE8 0055C58F RETURN to .0055C58F from .0046CD30
|
||||
* 0012EBEC 0012EC54
|
||||
* 0012EBF0 0055C5A3 RETURN to .0055C5A3 from .0055D180
|
||||
* 0012EBF4 04A4C058
|
||||
* 0012EBF8 04A4B678
|
||||
*
|
||||
* - Scenario
|
||||
*
|
||||
* EAX 00000000
|
||||
* ECX 04A4CC30
|
||||
* EDX 00713FD8 .00713FD8
|
||||
* EBX 17F90170
|
||||
* ESP 0012EBBC
|
||||
* EBP 00000015
|
||||
* ESI 04A4C250
|
||||
* EDI 04A4CC30
|
||||
* EIP 005C2E20 .005C2E20
|
||||
*
|
||||
* 0012EBBC 0055D210 RETURN to .0055D210
|
||||
* 0012EBC0 17F90170
|
||||
* 0012EBC4 04A4C250
|
||||
* 0012EBC8 0000001E ; jichi: old game arg3 is 1e
|
||||
* 0012EBCC 00000015
|
||||
* 0012EBD0 00000002
|
||||
* 0012EBD4 00000002
|
||||
* 0012EBD8 04A4C250
|
||||
* 0012EBDC 0000001E
|
||||
* 0012EBE0 00000015
|
||||
* 0012EBE4 00000000
|
||||
* 0012EBE8 0055C58F RETURN to .0055C58F from .0046CD30
|
||||
* 0012EBEC 0012EC54
|
||||
* 0012EBF0 0055C5A3 RETURN to .0055C5A3 from .0055D180
|
||||
*
|
||||
* Caller of the scenario/name thread:
|
||||
* 0055D207 8BCF MOV ECX,EDI
|
||||
* 0055D209 897C24 34 MOV DWORD PTR SS:[ESP+0x34],EDI
|
||||
* 0055D20D FF52 14 CALL DWORD PTR DS:[EDX+0x14] ; jichi: called here
|
||||
* 0055D210 8BCF MOV ECX,EDI ; jichi: retaddr is here
|
||||
* 0055D212 894424 18 MOV DWORD PTR SS:[ESP+0x18],EAX
|
||||
* 0055D216 E8 456D0600 CALL .005C3F60
|
||||
* 0055D21B 33C9 XOR ECX,ECX
|
||||
* 0055D21D 894424 14 MOV DWORD PTR SS:[ESP+0x14],EAX
|
||||
* 0055D221 3BC1 CMP EAX,ECX
|
||||
* 0055D223 76 06 JBE SHORT .0055D22B
|
||||
*
|
||||
* Sample game: キスと魔王と紅茶 (very old type)
|
||||
*
|
||||
* - Name:
|
||||
*
|
||||
* EAX 0A4106C0 ASCII "ゥa"
|
||||
* ECX 0012F594
|
||||
* EDX 0058032C ASCII "pgM"
|
||||
* EBX 00000000
|
||||
* ESP 0012F4F4
|
||||
* EBP 00000003
|
||||
* ESI 0012F618
|
||||
* EDI 0012F594
|
||||
* EIP 004D52B0 .004D52B0
|
||||
*
|
||||
* 0012F4F4 004DBFF2 RETURN to .004DBFF2
|
||||
* 0012F4F8 0A4106C0 ASCII "ゥa"
|
||||
* 0012F4FC 0012F698
|
||||
* 0012F500 0012F618
|
||||
* 0012F504 0296EA58
|
||||
* 0012F508 00000000 ; jichi: used to identify name
|
||||
* 0012F50C 0A40EC00
|
||||
* 0012F510 00000000
|
||||
* 0012F514 000000F9
|
||||
* 0012F518 00005DC8
|
||||
* 0012F51C 00580304 ASCII "PgM"
|
||||
* 0012F520 D90A0DDD
|
||||
* 0012F524 00000018
|
||||
* 0012F528 00000000
|
||||
*
|
||||
* - Scenario:
|
||||
*
|
||||
* EAX 00000000
|
||||
* ECX 01B69134
|
||||
* EDX 0058032C ASCII "pgM"
|
||||
* EBX 09E82E88
|
||||
* ESP 0012F548
|
||||
* EBP 00000016
|
||||
* ESI 01B68A70
|
||||
* EDI 01B69134
|
||||
* EIP 004D52B0 .004D52B0
|
||||
*
|
||||
* 0012F548 004B5210 RETURN to .004B5210
|
||||
* 0012F54C 09E82E88
|
||||
* 0012F550 01B68A70
|
||||
* 0012F554 00000018
|
||||
* 0012F558 00000016
|
||||
* 0012F55C 00000009
|
||||
* 0012F560 01B69134
|
||||
* 0012F564 01B68A70
|
||||
* 0012F568 00000018
|
||||
* 0012F56C 00000016
|
||||
* 0012F570 00000000
|
||||
* 0012F574 004B459F RETURN to .004B459F from .0040DE50
|
||||
* 0012F578 0012F5E0
|
||||
* 0012F57C 004B45B3 RETURN to .004B45B3 from .004B5180
|
||||
* 0012F580 09E82E88
|
||||
* 0012F584 00000000
|
||||
* 0012F588 0012FC78
|
||||
* 0012F58C 00000000
|
||||
* 0012F590 01B68A70
|
||||
* 0012F594 005655D0 .005655D0
|
||||
* 0012F598 0057BB80 .0057BB80
|
||||
* 0012F59C 0A419628
|
||||
*
|
||||
* Caller of the name/scenario thread
|
||||
*
|
||||
* 004B517D 90 NOP
|
||||
* 004B517E 90 NOP
|
||||
* 004B517F 90 NOP
|
||||
* 004B5180 83EC 1C SUB ESP,0x1C
|
||||
* 004B5183 53 PUSH EBX
|
||||
* 004B5184 55 PUSH EBP
|
||||
* 004B5185 8B5C24 28 MOV EBX,DWORD PTR SS:[ESP+0x28]
|
||||
* 004B5189 56 PUSH ESI
|
||||
* 004B518A 8BF1 MOV ESI,ECX
|
||||
* 004B518C 57 PUSH EDI
|
||||
* 004B518D 8B86 A0050000 MOV EAX,DWORD PTR DS:[ESI+0x5A0]
|
||||
* 004B5193 85C0 TEST EAX,EAX
|
||||
* 004B5195 74 63 JE SHORT .004B51FA
|
||||
* 004B5197 53 PUSH EBX
|
||||
* 004B5198 8D8E C4060000 LEA ECX,DWORD PTR DS:[ESI+0x6C4]
|
||||
* 004B519E E8 3DFD0100 CALL .004D4EE0
|
||||
* 004B51A3 8BF8 MOV EDI,EAX
|
||||
* 004B51A5 8D86 D4060000 LEA EAX,DWORD PTR DS:[ESI+0x6D4]
|
||||
* 004B51AB 8B8E EC060000 MOV ECX,DWORD PTR DS:[ESI+0x6EC]
|
||||
* 004B51B1 8BAE F0060000 MOV EBP,DWORD PTR DS:[ESI+0x6F0]
|
||||
* 004B51B7 8B10 MOV EDX,DWORD PTR DS:[EAX]
|
||||
* 004B51B9 895424 1C MOV DWORD PTR SS:[ESP+0x1C],EDX
|
||||
* 004B51BD 8B50 04 MOV EDX,DWORD PTR DS:[EAX+0x4]
|
||||
* 004B51C0 895424 20 MOV DWORD PTR SS:[ESP+0x20],EDX
|
||||
* 004B51C4 8B50 08 MOV EDX,DWORD PTR DS:[EAX+0x8]
|
||||
* 004B51C7 8B40 0C MOV EAX,DWORD PTR DS:[EAX+0xC]
|
||||
* 004B51CA 894424 28 MOV DWORD PTR SS:[ESP+0x28],EAX
|
||||
* 004B51CE 8BC2 MOV EAX,EDX
|
||||
* 004B51D0 2BC1 SUB EAX,ECX
|
||||
* 004B51D2 3BF8 CMP EDI,EAX
|
||||
* 004B51D4 7F 24 JG SHORT .004B51FA
|
||||
* 004B51D6 83BE A0050000 03 CMP DWORD PTR DS:[ESI+0x5A0],0x3
|
||||
* 004B51DD 75 0B JNZ SHORT .004B51EA
|
||||
* 004B51DF 2BC7 SUB EAX,EDI
|
||||
* 004B51E1 99 CDQ
|
||||
* 004B51E2 2BC2 SUB EAX,EDX
|
||||
* 004B51E4 D1F8 SAR EAX,1
|
||||
* 004B51E6 03C8 ADD ECX,EAX
|
||||
* 004B51E8 EB 04 JMP SHORT .004B51EE
|
||||
* 004B51EA 2BD7 SUB EDX,EDI
|
||||
* 004B51EC 8BCA MOV ECX,EDX
|
||||
* 004B51EE 898E EC060000 MOV DWORD PTR DS:[ESI+0x6EC],ECX
|
||||
* 004B51F4 89AE F0060000 MOV DWORD PTR DS:[ESI+0x6F0],EBP
|
||||
* 004B51FA 8B96 C4060000 MOV EDX,DWORD PTR DS:[ESI+0x6C4]
|
||||
* 004B5200 8DBE C4060000 LEA EDI,DWORD PTR DS:[ESI+0x6C4]
|
||||
* 004B5206 53 PUSH EBX
|
||||
* 004B5207 8BCF MOV ECX,EDI
|
||||
* 004B5209 897C24 14 MOV DWORD PTR SS:[ESP+0x14],EDI
|
||||
* 004B520D FF52 10 CALL DWORD PTR DS:[EDX+0x10] ; jichi: called here
|
||||
* 004B5210 8BCF MOV ECX,EDI ; jichi: retaddr is here
|
||||
* 004B5212 894424 18 MOV DWORD PTR SS:[ESP+0x18],EAX
|
||||
* 004B5216 E8 85120200 CALL .004D64A0
|
||||
* 004B521B 33ED XOR EBP,EBP
|
||||
* 004B521D 894424 14 MOV DWORD PTR SS:[ESP+0x14],EAX
|
||||
* 004B5221 3BC5 CMP EAX,EBP
|
||||
* 004B5223 76 06 JBE SHORT .004B522B
|
||||
* 004B5225 89AE A0050000 MOV DWORD PTR DS:[ESI+0x5A0],EBP
|
||||
* 004B522B 85C0 TEST EAX,EAX
|
||||
* 004B522D 896C24 30 MOV DWORD PTR SS:[ESP+0x30],EBP
|
||||
* 004B5231 76 68 JBE SHORT .004B529B
|
||||
* 004B5233 55 PUSH EBP
|
||||
* 004B5234 8BCF MOV ECX,EDI
|
||||
* 004B5236 E8 75120200 CALL .004D64B0
|
||||
* 004B523B 85C0 TEST EAX,EAX
|
||||
* 004B523D 74 4F JE SHORT .004B528E
|
||||
* 004B523F 50 PUSH EAX
|
||||
* 004B5240 8BCE MOV ECX,ESI
|
||||
* 004B5242 E8 69000000 CALL .004B52B0
|
||||
* 004B5247 8BD8 MOV EBX,EAX
|
||||
* 004B5249 85DB TEST EBX,EBX
|
||||
* 004B524B 74 41 JE SHORT .004B528E
|
||||
* 004B524D 8B86 C0060000 MOV EAX,DWORD PTR DS:[ESI+0x6C0]
|
||||
* 004B5253 8B8E B0060000 MOV ECX,DWORD PTR DS:[ESI+0x6B0]
|
||||
* 004B5259 8BAE 30070000 MOV EBP,DWORD PTR DS:[ESI+0x730]
|
||||
* 004B525F 8DBE 28070000 LEA EDI,DWORD PTR DS:[ESI+0x728]
|
||||
* 004B5265 03C8 ADD ECX,EAX
|
||||
* 004B5267 6A 00 PUSH 0x0
|
||||
* 004B5269 8D55 01 LEA EDX,DWORD PTR SS:[EBP+0x1]
|
||||
* 004B526C 898E C0060000 MOV DWORD PTR DS:[ESI+0x6C0],ECX
|
||||
* 004B5272 52 PUSH EDX
|
||||
* 004B5273 8BCF MOV ECX,EDI
|
||||
* 004B5275 8983 C0000000 MOV DWORD PTR DS:[EBX+0xC0],EAX
|
||||
* 004B527B E8 8003F8FF CALL .00435600
|
||||
* 004B5280 8B47 04 MOV EAX,DWORD PTR DS:[EDI+0x4]
|
||||
* 004B5283 8B7C24 10 MOV EDI,DWORD PTR SS:[ESP+0x10]
|
||||
* 004B5287 891CA8 MOV DWORD PTR DS:[EAX+EBP*4],EBX
|
||||
* 004B528A 8B6C24 30 MOV EBP,DWORD PTR SS:[ESP+0x30]
|
||||
* 004B528E 8B4424 14 MOV EAX,DWORD PTR SS:[ESP+0x14]
|
||||
* 004B5292 45 INC EBP
|
||||
* 004B5293 3BE8 CMP EBP,EAX
|
||||
* 004B5295 896C24 30 MOV DWORD PTR SS:[ESP+0x30],EBP
|
||||
* 004B5299 ^72 98 JB SHORT .004B5233
|
||||
* 004B529B 8BCF MOV ECX,EDI
|
||||
* 004B529D E8 2E120200 CALL .004D64D0
|
||||
* 004B52A2 8B4424 18 MOV EAX,DWORD PTR SS:[ESP+0x18]
|
||||
* 004B52A6 5F POP EDI
|
||||
* 004B52A7 5E POP ESI
|
||||
* 004B52A8 5D POP EBP
|
||||
* 004B52A9 5B POP EBX
|
||||
* 004B52AA 83C4 1C ADD ESP,0x1C
|
||||
* 004B52AD C2 0400 RETN 0x4
|
||||
* 004B52B0 64:A1 00000000 MOV EAX,DWORD PTR FS:[0]
|
||||
* 004B52B6 6A FF PUSH -0x1
|
||||
* 004B52B8 68 A1F15200 PUSH .0052F1A1
|
||||
* 004B52BD 50 PUSH EAX
|
||||
* 004B52BE 64:8925 00000000 MOV DWORD PTR FS:[0],ESP
|
||||
* 004B52C5 81EC CC000000 SUB ESP,0xCC
|
||||
* 004B52CB 56 PUSH ESI
|
||||
* 004B52CC 8BF1 MOV ESI,ECX
|
||||
* 004B52CE 8B8C24 E0000000 MOV ECX,DWORD PTR SS:[ESP+0xE0]
|
||||
* 004B52D5 57 PUSH EDI
|
||||
* 004B52D6 85C9 TEST ECX,ECX
|
||||
* 004B52D8 75 07 JNZ SHORT .004B52E1
|
||||
* 004B52DA 33C0 XOR EAX,EAX
|
||||
* 004B52DC E9 55060000 JMP .004B5936
|
||||
* 004B52E1 8B79 14 MOV EDI,DWORD PTR DS:[ECX+0x14]
|
||||
* 004B52E4 85FF TEST EDI,EDI
|
||||
* 004B52E6 897C24 18 MOV DWORD PTR SS:[ESP+0x18],EDI
|
||||
* 004B52EA 75 07 JNZ SHORT .004B52F3
|
||||
* 004B52EC 33C0 XOR EAX,EAX
|
||||
* 004B52EE E9 43060000 JMP .004B5936
|
||||
* 004B52F3 8A86 AA060000 MOV AL,BYTE PTR DS:[ESI+0x6AA]
|
||||
* 004B52F9 84C0 TEST AL,AL
|
||||
* 004B52FB 74 51 JE SHORT .004B534E
|
||||
* 004B52FD 8B01 MOV EAX,DWORD PTR DS:[ECX]
|
||||
* 004B52FF 8D5424 08 LEA EDX,DWORD PTR SS:[ESP+0x8]
|
||||
* 004B5303 52 PUSH EDX
|
||||
* 004B5304 FF50 34 CALL DWORD PTR DS:[EAX+0x34]
|
||||
* 004B5307 8D86 D4060000 LEA EAX,DWORD PTR DS:[ESI+0x6D4]
|
||||
* 004B530D 8B8E D4060000 MOV ECX,DWORD PTR DS:[ESI+0x6D4]
|
||||
* 004B5313 894C24 48 MOV DWORD PTR SS:[ESP+0x48],ECX
|
||||
* 004B5317 8B50 04 MOV EDX,DWORD PTR DS:[EAX+0x4]
|
||||
* 004B531A 895424 4C MOV DWORD PTR SS:[ESP+0x4C],EDX
|
||||
* 004B531E 8B48 08 MOV ECX,DWORD PTR DS:[EAX+0x8]
|
||||
* 004B5321 894C24 50 MOV DWORD PTR SS:[ESP+0x50],ECX
|
||||
* 004B5325 8A8E 14070000 MOV CL,BYTE PTR DS:[ESI+0x714]
|
||||
* 004B532B 8B40 0C MOV EAX,DWORD PTR DS:[EAX+0xC]
|
||||
* 004B532E 84C9 TEST CL,CL
|
||||
* 004B5330 75 0D JNZ SHORT .004B533F
|
||||
* 004B5332 394424 0C CMP DWORD PTR SS:[ESP+0xC],EAX
|
||||
* 004B5336 7E 16 JLE SHORT .004B534E
|
||||
* 004B5338 33C0 XOR EAX,EAX
|
||||
* 004B533A E9 F7050000 JMP .004B5936
|
||||
*
|
||||
* Sample game: プライマルハーツ (new type), 0x54bd80
|
||||
* Name:
|
||||
* 0012EB5C 004DACB0 RETURN to .004DACB0
|
||||
* 0012EB60 05067E40
|
||||
* 0012EB64 0000001E ; jichi: new game arg2 is 1e
|
||||
* 0012EB68 0012ECA8
|
||||
* 0012EB6C 008D3E48
|
||||
* 0012EB70 004512DB RETURN to .004512DB from .00450FE0
|
||||
* 0012EB74 0000001E
|
||||
* 0012EB78 00000025
|
||||
* 0012EB7C 0012ECA8
|
||||
* 0012EB80 008D3E48
|
||||
* 0012EB84 0000001E
|
||||
* 0012EB88 004DA1CB RETURN to .004DA1CB from .00451280
|
||||
* 0012EB8C 004DA1DF RETURN to .004DA1DF from .004DAC20 ; jichi: 004DAC20 is a better place to hook to
|
||||
* 0012EB90 05067E40
|
||||
* 0012EB94 5D9C7C59
|
||||
* 0012EB98 00000000
|
||||
* 0012EB9C 008D3E48
|
||||
* 0012EBA0 00000000
|
||||
* 0012EBA4 00000000
|
||||
* 0012EBA8 1600C8C8
|
||||
* 0012EBAC 006835B4 .006835B4
|
||||
* 0012EBB0 1621BBF0 UNICODE "\h:\f;MsgFont:\s:\c;E6ADFA:\v:"
|
||||
* 0012EBB4 00000025
|
||||
*
|
||||
* 0012EB5C 004DACB0 RETURN to .004DACB0
|
||||
* 0012EB60 05000420
|
||||
* 0012EB64 0000001E
|
||||
* 0012EB68 0012ECA8
|
||||
* 0012EB6C 008D3E48
|
||||
* 0012EB70 004512DB RETURN to .004512DB from .00450FE0
|
||||
* 0012EB74 0000001E
|
||||
* 0012EB78 00000022
|
||||
* 0012EB7C 0012ECA8
|
||||
* 0012EB80 008D3E48
|
||||
* 0012EB84 0000001E
|
||||
* 0012EB88 004DA1CB RETURN to .004DA1CB from .00451280
|
||||
* 0012EB8C 004DA1DF RETURN to .004DA1DF from .004DAC20
|
||||
* 0012EB90 05000420
|
||||
* 0012EB94 5D9C7C59
|
||||
* 0012EB98 00000000
|
||||
* 0012EB9C 008D3E48
|
||||
* 0012EBA0 00000000
|
||||
* 0012EBA4 00000000
|
||||
* 0012EBA8 05000C90
|
||||
* 0012EBAC 006835B4 .006835B4
|
||||
* 0012EBB0 05000F40 UNICODE "\h:\f;MsgFont:\s:\c;DAD4FF:\v:"
|
||||
* 0012EBB4 00000022
|
||||
* 0012EBB8 00000034
|
||||
* 0012EBBC 00000022
|
||||
* 0012EBC0 FFFFFFFF
|
||||
* 0012EBC4 7C00FFFF
|
||||
* 0012EBC8 78000000
|
||||
* 0012EBCC F8000001
|
||||
* 0012EBD0 00000000
|
||||
* 0012EBD4 58001384
|
||||
* 0012EBD8 28000000
|
||||
* 0012EBDC 28000000
|
||||
* 0012EBE0 00000048
|
||||
* 0012EBE4 00655A28 .00655A28
|
||||
* 0012EBE8 05000420
|
||||
* 0012EBEC 00000004
|
||||
* 0012EBF0 00000007
|
||||
* 0012EBF4 00210030
|
||||
* 0012EBF8 00000000
|
||||
* 0012EBFC 00DAD4FF
|
||||
* 0012EC00 0012EC98
|
||||
* 0012EC04 00000001
|
||||
*
|
||||
* EAX 0054BD80 .0054BD80
|
||||
* ECX 008D4848
|
||||
* EDX 0069E80C .0069E80C
|
||||
* EBX 05067E40
|
||||
* ESP 0012EB5C
|
||||
* EBP 0012ECA8
|
||||
* ESI 008D3E48
|
||||
* EDI 0000001E
|
||||
* EIP 0054BD80 .0054BD80
|
||||
*
|
||||
* 004DAC98 89AE 300A0000 MOV DWORD PTR DS:[ESI+0xA30],EBP
|
||||
* 004DAC9E 8B96 000A0000 MOV EDX,DWORD PTR DS:[ESI+0xA00]
|
||||
* 004DACA4 8B42 14 MOV EAX,DWORD PTR DS:[EDX+0x14]
|
||||
* 004DACA7 8D8E 000A0000 LEA ECX,DWORD PTR DS:[ESI+0xA00]
|
||||
* 004DACAD 53 PUSH EBX
|
||||
* 004DACAE FFD0 CALL EAX ; jichi: called here
|
||||
* 004DACB0 8B8E 100A0000 MOV ECX,DWORD PTR DS:[ESI+0xA10]
|
||||
* 004DACB6 894424 14 MOV DWORD PTR SS:[ESP+0x14],EAX
|
||||
* 004DACBA 8B41 08 MOV EAX,DWORD PTR DS:[ECX+0x8]
|
||||
* 004DACBD 33FF XOR EDI,EDI
|
||||
* 004DACBF 3BC7 CMP EAX,EDI
|
||||
* 004DACC1 894424 10 MOV DWORD PTR SS:[ESP+0x10],EAX
|
||||
*
|
||||
* ecx:
|
||||
* 01814848 0C E8 69 00 60 C7 F8 13 00 00 00 00 00 00 00 00 i읠ᏸ....
|
||||
* 01814858 28 3E 81 01 00 00 00 00 00 00 00 00 80 01 00 00 㸨Ɓ....ƀ. ; jichi: 810 is the width and 26 the height to paint
|
||||
* 01814868 26 00 00 00 FF FF FF 00 00 00 00 00 00 00 00 00 &..ÿ....
|
||||
* 01814878 00 00 00 00 26 00 00 00 00 00 00 00 00 00 00 00 ..&.....
|
||||
* 01814888 06 00 00 00 03 00 00 00 28 5A 65 00 98 3D 81 01 ..娨e㶘Ɓ
|
||||
* 01814898 2C 00 00 00 43 00 00 00 00 01 01 00 BA C1 1E 77 ,.C.Ā솺眞
|
||||
* 018148A8 35 FC 1C 77 20 FF 1C 77 90 16 38 0B 64 D5 68 00 ﰵ眜@眜ᚐସ핤h
|
||||
* 018148B8 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ........
|
||||
* 018148C8 7E 31 00 00 4C 03 00 00 00 00 00 00 00 00 00 00 ㅾ.͌.....
|
||||
* 018148D8 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ........
|
||||
* 018148E8 00 00 00 00 00 00 F0 3F 00 00 00 00 00 00 F0 3F ...㿰...㿰
|
||||
* 018148F8 00 00 00 00 00 00 00 00 94 C3 67 00 00 00 00 00 ....쎔g..
|
||||
*
|
||||
* 01814848 0C E8 69 00 58 EC E4 03 00 00 00 00 00 00 00 00 iϤ....
|
||||
* 01814858 28 3E 81 01 00 00 00 00 00 00 00 00 80 01 00 00 㸨Ɓ....ƀ.
|
||||
* 01814868 26 00 00 00 FF FF FF 00 00 00 00 00 00 00 00 00 &..ÿ....
|
||||
* 01814878 00 00 00 00 26 00 00 00 00 00 00 00 00 00 00 00 ..&.....
|
||||
* 01814888 06 00 00 00 03 00 00 00 28 5A 65 00 98 3D 81 01 ..娨e㶘Ɓ
|
||||
* 01814898 2C 00 00 00 43 00 00 00 00 01 01 00 BA C1 1E 77 ,.C.Ā솺眞
|
||||
* 018148A8 35 FC 1C 77 20 FF 1C 77 90 16 38 0B 64 D5 68 00 ﰵ眜@眜ᚐସ핤h
|
||||
* 018148B8 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ........
|
||||
* 018148C8 4B 4F 00 00 4C 03 00 00 00 00 00 00 00 00 00 00 佋.͌.....
|
||||
* 018148D8 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ........
|
||||
* 018148E8 00 00 00 00 00 00 F0 3F 00 00 00 00 00 00 F0 3F ...㿰...㿰
|
||||
* 018148F8 00 00 00 00 00 00 00 00 94 C3 67 00 00 00 00 00 ....쎔g..
|
||||
*
|
||||
* Scenario:
|
||||
* EAX 0054BD80 .0054BD80
|
||||
* ECX 008D3C50
|
||||
* EDX 0069E80C .0069E80C
|
||||
* EBX 1621C280
|
||||
* ESP 0012EB5C
|
||||
* EBP 0012ECA8
|
||||
* ESI 008D3250
|
||||
* EDI 0000001E
|
||||
* EIP 0054BD80 .0054BD80
|
||||
*
|
||||
* 0012EB5C 004DACB0 RETURN to .004DACB0
|
||||
* 0012EB60 1621C280
|
||||
* 0012EB64 0000001E
|
||||
* 0012EB68 0012ECA8
|
||||
* 0012EB6C 008D3250
|
||||
* 0012EB70 004512DB RETURN to .004512DB from .00450FE0
|
||||
* 0012EB74 0000001E
|
||||
* 0012EB78 00000041
|
||||
* 0012EB7C 0012ECA8
|
||||
* 0012EB80 008D3250
|
||||
* 0012EB84 0000001E
|
||||
* 0012EB88 004DA1CB RETURN to .004DA1CB from .00451280
|
||||
* 0012EB8C 004DA1DF RETURN to .004DA1DF from .004DAC20
|
||||
* 0012EB90 1621C280
|
||||
*
|
||||
* 0012EB5C 004DACB0 RETURN to .004DACB0
|
||||
* 0012EB60 050003B8
|
||||
* 0012EB64 0000001E
|
||||
* 0012EB68 0012ECA8
|
||||
* 0012EB6C 008D3250
|
||||
* 0012EB70 004512DB RETURN to .004512DB from .00450FE0
|
||||
* 0012EB74 0000001E
|
||||
* 0012EB78 00000034
|
||||
* 0012EB7C 0012ECA8
|
||||
* 0012EB80 008D3250
|
||||
* 0012EB84 0000001E
|
||||
* 0012EB88 004DA1CB RETURN to .004DA1CB from .00451280
|
||||
* 0012EB8C 004DA1DF RETURN to .004DA1DF from .004DAC20
|
||||
* 0012EB90 050003B8
|
||||
* 0012EB94 5D9C7C59
|
||||
* 0012EB98 00000000
|
||||
* 0012EB9C 008D3250
|
||||
* 0012EBA0 00000000
|
||||
* 0012EBA4 00000000
|
||||
* 0012EBA8 05007A68 UNICODE "38"
|
||||
* 0012EBAC 006835B4 .006835B4
|
||||
* 0012EBB0 0500E910 UNICODE "\h:\f;MsgFont:\s:\c;DAD4FF:\v:"
|
||||
* 0012EBB4 00000034
|
||||
* 0012EBB8 0000004F
|
||||
* 0012EBBC 00000034
|
||||
* 0012EBC0 FFFFFFFF
|
||||
* 0012EBC4 7C00FFFF
|
||||
* 0012EBC8 78000000
|
||||
* 0012EBCC F8000001
|
||||
* 0012EBD0 00000000
|
||||
* 0012EBD4 58001384
|
||||
* 0012EBD8 28000000
|
||||
* 0012EBDC 28000000
|
||||
* 0012EBE0 00000040
|
||||
* 0012EBE4 00655A28 .00655A28
|
||||
* 0012EBE8 050003B8
|
||||
*
|
||||
* ecx:
|
||||
* 01813C50 0C E8 69 00 80 E9 F8 13 00 00 00 00 00 00 00 00 iᏸ....
|
||||
* 01813C60 30 32 81 01 00 00 00 00 00 00 00 00 84 03 00 00 ㈰Ɓ....΄. ; jichi: 384 is the width and 76 the height to paint
|
||||
* 01813C70 76 00 00 00 FF FF FF 00 00 00 00 00 00 00 00 00 v..ÿ....
|
||||
* 01813C80 00 00 00 00 26 00 00 00 00 00 00 00 00 00 00 00 ..&.....
|
||||
* 01813C90 06 00 00 00 03 00 00 00 28 5A 65 00 A0 31 81 01 ..娨eㆠƁ
|
||||
* 01813CA0 2C 00 00 00 43 00 00 00 00 01 01 00 BA C1 1E 77 ,.C.Ā솺眞
|
||||
* 01813CB0 35 FC 1C 77 20 FF 1C 77 20 24 34 0B 64 D5 68 00 ﰵ眜@眜␠핤h
|
||||
* 01813CC0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ........
|
||||
* 01813CD0 7E 31 00 00 50 03 00 00 00 00 00 00 00 00 00 00 ㅾ.͐.....
|
||||
* 01813CE0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ........
|
||||
* 01813CF0 00 00 00 00 00 00 F0 3F 00 00 00 00 00 00 F0 3F ...㿰...㿰
|
||||
*
|
||||
* 01813C50 0C E8 69 00 10 C4 E4 03 00 00 00 00 00 00 00 00 i쐐Ϥ....
|
||||
* 01813C60 30 32 81 01 00 00 00 00 00 00 00 00 84 03 00 00 ㈰Ɓ....΄.
|
||||
* 01813C70 76 00 00 00 FF FF FF 00 00 00 00 00 00 00 00 00 v..ÿ....
|
||||
* 01813C80 00 00 00 00 26 00 00 00 00 00 00 00 00 00 00 00 ..&.....
|
||||
* 01813C90 06 00 00 00 03 00 00 00 28 5A 65 00 A0 31 81 01 ..娨eㆠƁ
|
||||
* 01813CA0 2C 00 00 00 43 00 00 00 00 01 01 00 BA C1 1E 77 ,.C.Ā솺眞
|
||||
* 01813CB0 35 FC 1C 77 20 FF 1C 77 20 24 34 0B 64 D5 68 00 ﰵ眜@眜␠핤h
|
||||
*/
|
||||
bool attachCaller(ULONG addr);
|
||||
size_t textSize_;
|
||||
void hookBefore(hook_stack *s, HookParam *hp, TextBuffer *buffer, uintptr_t *role)
|
||||
{
|
||||
static std::wstring text_; // persistent storage, which makes this function not thread-safe
|
||||
textSize_ = 0;
|
||||
auto text = (LPCWSTR)s->stack[1]; // arg1
|
||||
if (!text || !*text)
|
||||
return ;
|
||||
|
||||
if (::wcscmp(text, L"----/--/-- --:--") == 0)
|
||||
return ;
|
||||
|
||||
textSize_ = ::wcslen(text);
|
||||
if (s->stack[1] == s->stack[13]) // for new games
|
||||
attachCaller(s->stack[12]);
|
||||
else if (s->stack[1] == s->stack[14]) // for old games
|
||||
attachCaller(s->stack[13]);
|
||||
// else // very old or very new games
|
||||
|
||||
auto retaddr = s->stack[0];
|
||||
|
||||
// int textStackIndex = -1;
|
||||
|
||||
*role = Engine::OtherRole;
|
||||
if (s->stack[2] < 0x100)
|
||||
{ // new game, this value is mostly 0x1e
|
||||
// if (s->stack[1] == s->stack[13])
|
||||
// textStackIndex = 13;
|
||||
// 004DACA7 8D8E 000A0000 LEA ECX,DWORD PTR DS:[ESI+0xA00]
|
||||
// 004DACAD 53 PUSH EBX
|
||||
// 004DACAE FFD0 CALL EAX ; jichi: called here
|
||||
// 004DACB0 8B8E 100A0000 MOV ECX,DWORD PTR DS:[ESI+0xA10]
|
||||
// 004DACB6 894424 14 MOV DWORD PTR SS:[ESP+0x14],EAX
|
||||
// 004DACBA 8B41 08 MOV EAX,DWORD PTR DS:[ECX+0x8]
|
||||
// 004DACBD 33FF XOR EDI,EDI
|
||||
// if (*(WORD *)retaddr == 0x8e8b) { // 004DACB0 8B8E 100A0000 MOV ECX,DWORD PTR DS:[ESI+0xA10]
|
||||
*role = Engine::ScenarioRole;
|
||||
enum : wchar_t
|
||||
{
|
||||
w_open = 0x3010,
|
||||
w_close = 0x3011
|
||||
}; /* 【】 */
|
||||
if (text[0] == w_open && text[::wcslen(text) - 1] == w_close)
|
||||
*role = Engine::NameRole;
|
||||
}
|
||||
else if (s->stack[3] < 0x100 // for old game
|
||||
|| *(WORD *)retaddr == s2_mov_ecx_edi && *(WORD *)(retaddr - 5) == 0x52ff)
|
||||
{ // for very old game
|
||||
// Sample game: お兄ちゃん、右手の使用を禁止します! (old type)
|
||||
// 0055D207 8BCF MOV ECX,EDI
|
||||
// 0055D209 897C24 34 MOV DWORD PTR SS:[ESP+0x34],EDI
|
||||
// 0055D20D FF52 14 CALL DWORD PTR DS:[EDX+0x14] ; jichi: called here
|
||||
// 0055D210 8BCF MOV ECX,EDI ; jichi: retaddr is here
|
||||
// 0055D212 894424 18 MOV DWORD PTR SS:[ESP+0x18],EAX
|
||||
|
||||
// Sample game: キスと魔王と紅茶 (old type)
|
||||
// name:
|
||||
// 004DBFEC 50 PUSH EAX
|
||||
// 004DBFED 8BCF MOV ECX,EDI
|
||||
// 004DBFEF FF52 10 CALL DWORD PTR DS:[EDX+0x10] ; jichi: called here
|
||||
// 004DBFF2 8B7424 7C MOV ESI,DWORD PTR SS:[ESP+0x7C]
|
||||
// 004DBFF6 33DB XOR EBX,EBX
|
||||
// 004DBFF8 3BF3 CMP ESI,EBX
|
||||
// 004DBFFA 74 4B JE SHORT .004DC047
|
||||
// 004DBFFC 8BCF MOV ECX,EDI
|
||||
// 004DBFFE E8 9DA4FFFF CALL .004D64A0
|
||||
// 004DC003 8BE8 MOV EBP,EAX
|
||||
// 004DC005 891E MOV DWORD PTR DS:[ESI],EBX
|
||||
// 004DC007 85ED TEST EBP,EBP
|
||||
//
|
||||
// Scenario:
|
||||
// 004B5207 8BCF MOV ECX,EDI
|
||||
// 004B5209 897C24 14 MOV DWORD PTR SS:[ESP+0x14],EDI
|
||||
// 004B520D FF52 10 CALL DWORD PTR DS:[EDX+0x10] ; jichi: called here
|
||||
// 004B5210 8BCF MOV ECX,EDI
|
||||
// 004B5212 894424 18 MOV DWORD PTR SS:[ESP+0x18],EAX
|
||||
// 004B5216 E8 85120200 CALL .004D64A0
|
||||
// 004B521B 33ED XOR EBP,EBP
|
||||
*role = s->stack[5] == 0 ? Engine::NameRole : Engine::ScenarioRole;
|
||||
}
|
||||
buffer->from_cs(text);
|
||||
}
|
||||
|
||||
void hookAfterCaller(hook_stack *s, HookParam *hp, TextBuffer *buffer, uintptr_t *split)
|
||||
{
|
||||
if (textSize_)
|
||||
s->eax = textSize_;
|
||||
}
|
||||
bool attachCaller(ULONG addr)
|
||||
{
|
||||
static std::unordered_set<ULONG> addresses_;
|
||||
if (addresses_.find(addr) != addresses_.end())
|
||||
return false;
|
||||
addresses_.insert(addr);
|
||||
HookParam hp;
|
||||
hp.address=addr;
|
||||
hp.text_fun = hookAfterCaller;
|
||||
return NewHook(hp,"attachCaller");
|
||||
}
|
||||
|
||||
} // namespace Private
|
||||
|
||||
} // namespace ScenarioHook
|
||||
|
||||
} // unnamed namespace
|
||||
bool CotophaFilter(LPVOID data, size_t *size, HookParam *)
|
||||
{
|
||||
auto text = reinterpret_cast<LPWSTR>(data);
|
||||
auto len = reinterpret_cast<size_t *>(size);
|
||||
|
||||
if (*len <= 2 || text[0] != L'\\')
|
||||
return false;
|
||||
|
||||
size_t lenPurged = 0;
|
||||
for (size_t i = 0; i < *len / 2; i++)
|
||||
{
|
||||
if (text[i] != L'\\')
|
||||
{
|
||||
text[lenPurged++] = text[i];
|
||||
}
|
||||
else
|
||||
{
|
||||
// start command
|
||||
wchar_t cmd = text[++i];
|
||||
if (cmd == 'r')
|
||||
{ // ruby
|
||||
i++; // skip ';' char
|
||||
while (text[++i] != L':')
|
||||
{
|
||||
if (text[i] == L';') // when we reach '; ' we have the kanji part
|
||||
break;
|
||||
text[lenPurged++] = text[i];
|
||||
}
|
||||
}
|
||||
else if (cmd == L'n' && lenPurged) // newline
|
||||
text[lenPurged++] = L' '; // for Western language compatibility
|
||||
while (text[++i] != L':')
|
||||
;
|
||||
}
|
||||
}
|
||||
if (lenPurged)
|
||||
text[lenPurged++] = L' '; // for Western language compatibility
|
||||
*len = lenPurged * 2;
|
||||
return true;
|
||||
}
|
||||
bool InsertCotophaHook1()
|
||||
{
|
||||
enum : DWORD
|
||||
{
|
||||
ins = 0xec8b55
|
||||
}; // mov ebp,esp, sub esp,* ; jichi 7/12/2014
|
||||
ULONG addr = MemDbg::findCallerAddress((ULONG)::GetTextMetricsA, ins, processStartAddress, processStopAddress);
|
||||
if (!addr)
|
||||
return false;
|
||||
HookParam hp;
|
||||
hp.address = addr;
|
||||
hp.offset = get_stack(1);
|
||||
hp.split = get_reg(regs::ebp);
|
||||
hp.type = CODEC_UTF16 | USING_SPLIT | USING_STRING | EMBED_ABLE | EMBED_AFTER_NEW|NO_CONTEXT;
|
||||
hp.text_fun = ScenarioHook::Private::hookBefore;
|
||||
ConsoleOutput("INSERT Cotopha");
|
||||
|
||||
// RegisterEngineType(ENGINE_COTOPHA);
|
||||
return NewHook(hp, "Cotopha");
|
||||
}
|
||||
|
||||
bool InsertCotophaHook2()
|
||||
{
|
||||
if (void *addr = GetProcAddress(GetModuleHandleW(NULL), "eslHeapFree"))
|
||||
{
|
||||
HookParam hp;
|
||||
hp.address = (uintptr_t)addr;
|
||||
hp.offset = get_stack(2);
|
||||
hp.type = CODEC_UTF16 | USING_STRING;
|
||||
hp.filter_fun = CotophaFilter;
|
||||
return NewHook(hp, "Cotopha2");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
bool InsertCotophaHook3()
|
||||
{
|
||||
const BYTE bytes[] = {0x8B, 0x75, 0xB8, 0x8B, 0xCE, 0x50, 0xC6, 0x45, 0xFC, 0x01, 0xE8};
|
||||
ULONG range = min(processStopAddress - processStartAddress, MAX_REL_ADDR);
|
||||
ULONG addr = MemDbg::findBytes(bytes, sizeof(bytes), processStartAddress, processStartAddress + range);
|
||||
if (!addr)
|
||||
return false;
|
||||
|
||||
HookParam myhp;
|
||||
myhp.address = addr;
|
||||
myhp.type = CODEC_UTF16 | USING_STRING | EMBED_ABLE | EMBED_AFTER_NEW;
|
||||
myhp.offset = get_reg(regs::eax);
|
||||
|
||||
return NewHook(myhp, "Cotopha3_EWideString");
|
||||
}
|
||||
bool InsertCotophaHook4()
|
||||
{
|
||||
/*
|
||||
* https://vndb.org/v32624
|
||||
*/
|
||||
const BYTE bytes[] = {
|
||||
0xCC, // int 3
|
||||
0x55, // push ebp << hook here
|
||||
0x8B, 0xEC, // mov ebp,esp
|
||||
0x51, // push ecx
|
||||
0x53, // push ebx
|
||||
0x56, // push esi
|
||||
0x57, // push edi
|
||||
0x8B, 0x7D, 0x08, // mov edi,[ebp+08]
|
||||
0x33, 0xF6, // xor esi,esi
|
||||
0x8B, 0xD9, // mov ebx,ecx
|
||||
0x85, 0xFF, // test edi,edi
|
||||
0x74, 0x0D // je ststeady2.glsGetEnabledProcessorType+643F
|
||||
};
|
||||
|
||||
ULONG range = min(processStopAddress - processStartAddress, MAX_REL_ADDR);
|
||||
ULONG addr = MemDbg::findBytes(bytes, sizeof(bytes), processStartAddress, processStartAddress + range);
|
||||
if (!addr)
|
||||
return false;
|
||||
|
||||
HookParam hp = {};
|
||||
hp.address = addr + 1;
|
||||
hp.offset = get_stack(1);
|
||||
hp.type = CODEC_UTF16 | USING_STRING | NO_CONTEXT;
|
||||
hp.filter_fun = CotophaFilter;
|
||||
return NewHook(hp, "Cotopha4");
|
||||
}
|
||||
namespace
|
||||
{
|
||||
bool h5()
|
||||
{
|
||||
// 狙われた優等生 身代わりの代償
|
||||
const BYTE bytes[] = {
|
||||
// if ( v90 && ((v40 = *(_WORD *)(v94 + 28), v40 >= 0x41u && v40 <= 0x5Au) || v40 >= 0x61u && v40 <= 0x7Au) )
|
||||
|
||||
0x8b, 0x45, XX,
|
||||
0x0f, 0xb7, 0x50, XX,
|
||||
|
||||
0xb8, 0x41, 0x00, 0x00, 0x00,
|
||||
0x66, 0x3b, 0xd0,
|
||||
0x66, 0xb8, 0x5a, 0x00,
|
||||
0x1b, 0xc9,
|
||||
0x41,
|
||||
0x66, 0x3b, 0xc2,
|
||||
0x1b, 0xc0,
|
||||
0x40,
|
||||
0x85, 0xc8,
|
||||
|
||||
0x75, XX,
|
||||
|
||||
0xb8, 0x61, 0x00, 0x00, 0x00,
|
||||
0x66, 0x3b, 0xd0,
|
||||
0x66, 0xb8, 0x7a, 0x00,
|
||||
0x1b, 0xc9,
|
||||
0x41,
|
||||
0x66, 0x3b, 0xc2,
|
||||
0x1b, 0xc0,
|
||||
0x40,
|
||||
0x85, 0xc8
|
||||
|
||||
};
|
||||
|
||||
ULONG addr = MemDbg::findBytes(bytes, sizeof(bytes), processStartAddress, processStopAddress);
|
||||
if (!addr)
|
||||
return false;
|
||||
addr = MemDbg::findEnclosingAlignedFunction(addr);
|
||||
if (!addr)
|
||||
return false;
|
||||
BYTE check[] = {
|
||||
0x66, 0x90,
|
||||
0x40,
|
||||
0x66, 0x83, 0x3c, 0x42, 0x00,
|
||||
0x75, XX};
|
||||
BYTE check2[] = {0x8d, 0x45, 0xf4};
|
||||
auto addrx = MemDbg::findBytes(check, sizeof(check), addr, addr + 0x100);
|
||||
if (!addrx)
|
||||
return false;
|
||||
addrx = MemDbg::findBytes(check2, sizeof(check2), addr, addrx);
|
||||
if (!addrx)
|
||||
return false;
|
||||
HookParam hp;
|
||||
hp.address = addr;
|
||||
hp.offset = get_stack(3);
|
||||
hp.type = CODEC_UTF16 | USING_STRING | EMBED_ABLE | EMBED_AFTER_NEW ;
|
||||
hp.hook_font = F_GetGlyphOutlineW;
|
||||
return NewHook(hp, "Cotopha5");
|
||||
}
|
||||
}
|
||||
bool InsertCotophaHook()
|
||||
{
|
||||
auto _old = InsertCotophaHook1();
|
||||
return (InsertCotophaHook4() | InsertCotophaHook3()) || InsertCotophaHook2() || h5() || _old;
|
||||
}
|
||||
bool Cotopha::attach_function()
|
||||
{
|
||||
|
||||
return InsertCotophaHook();
|
||||
}
|
11
cpp/LunaHook/LunaHook/engine32/Cotopha.h
Normal file
11
cpp/LunaHook/LunaHook/engine32/Cotopha.h
Normal file
@ -0,0 +1,11 @@
|
||||
|
||||
|
||||
class Cotopha:public ENGINE{
|
||||
public:
|
||||
Cotopha(){
|
||||
|
||||
check_by=CHECK_BY::FILE_ANY;
|
||||
check_by_target=check_by_list{L"*.noa",L"data\\*.noa"};
|
||||
};
|
||||
bool attach_function();
|
||||
};
|
39
cpp/LunaHook/LunaHook/engine32/DISCOVERY.cpp
Normal file
39
cpp/LunaHook/LunaHook/engine32/DISCOVERY.cpp
Normal file
@ -0,0 +1,39 @@
|
||||
#include "DISCOVERY.h"
|
||||
namespace
|
||||
{
|
||||
bool DISCOVERY1()
|
||||
{
|
||||
// https://vndb.org/v4053
|
||||
// 小雪の朱-コユキノアカ-
|
||||
|
||||
BYTE sig[] = {
|
||||
/*
|
||||
if ( *(v6 - 2) != 23
|
||||
|| *(v6 - 3) != sub_40C130(255, 255, 255)
|
||||
|| sub_418190(*(v6 - 4), v6 - 1) != 1
|
||||
|| dword_B81054 && dword_975570 )*/
|
||||
|
||||
0x83, 0x7b, 0xf8, 0x17,
|
||||
0x75, XX,
|
||||
0x68, 0xff, 0x00, 0x00, 0x00,
|
||||
0x68, 0xff, 0x00, 0x00, 0x00,
|
||||
0x68, 0xff, 0x00, 0x00, 0x00,
|
||||
0xe8};
|
||||
auto addr = MemDbg::findBytes(sig, sizeof(sig), processStartAddress, processStopAddress);
|
||||
if (!addr)
|
||||
return false;
|
||||
HookParam hp;
|
||||
hp.address = addr;
|
||||
hp.type = USING_CHAR;
|
||||
hp.text_fun = [](hook_stack *stack, HookParam *hp, TextBuffer *buffer, uintptr_t *split)
|
||||
{
|
||||
auto v6 = (int *)stack->ebx - 4;
|
||||
buffer->from_t<WORD>(*v6);
|
||||
};
|
||||
return NewHook(hp, "DISCOVERY");
|
||||
}
|
||||
}
|
||||
bool DISCOVERY::attach_function()
|
||||
{
|
||||
return DISCOVERY1();
|
||||
}
|
14
cpp/LunaHook/LunaHook/engine32/DISCOVERY.h
Normal file
14
cpp/LunaHook/LunaHook/engine32/DISCOVERY.h
Normal file
@ -0,0 +1,14 @@
|
||||
|
||||
|
||||
class DISCOVERY : public ENGINE
|
||||
{
|
||||
public:
|
||||
DISCOVERY()
|
||||
{
|
||||
|
||||
check_by = CHECK_BY::FILE_ALL;
|
||||
check_by_target = check_by_list{L"BG.PD", L"CG.PD", L"CHIP.PD", L"SE.PB", L"STAND.PD", L"VOICE.PB", L"*.ID"};
|
||||
is_engine_certain = false;
|
||||
};
|
||||
bool attach_function();
|
||||
};
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user