├── .github └── workflows │ ├── ci.yml │ └── package.yml ├── .gitignore ├── .gitmodules ├── CMakeLists.txt ├── CMakePresets.json ├── CMakeUserPresets.json ├── LICENSE ├── OpenSpeedy_en_US.ts ├── OpenSpeedy_zh_CN.ts ├── OpenSpeedy_zh_TW.ts ├── README.md ├── aboutdialog.cpp ├── aboutdialog.h ├── aboutdialog.ui ├── bridge ├── CMakeLists.txt └── main.cpp ├── config.h ├── cpuutils.cpp ├── cpuutils.h ├── docs ├── README_cn.md └── README_ja.md ├── icons.rc ├── images ├── icon.ico ├── icon_16.ico ├── icon_32.ico ├── icon_64.ico └── logo.png ├── installer ├── config │ └── config.xml ├── create_installer.bat └── packages │ └── com.openspeedy.app │ ├── data │ └── .gitkeep │ └── meta │ ├── installscript.qs │ └── package.xml ├── main.cpp ├── mainwindow.cpp ├── mainwindow.h ├── mainwindow.ui ├── memutils.cpp ├── memutils.h ├── preferencedialog.cpp ├── preferencedialog.h ├── preferencedialog.ui ├── processmonitor.cpp ├── processmonitor.h ├── qsinglekeysequenceedit.cpp ├── qsinglekeysequenceedit.h ├── resources.qrc ├── script ├── build32.bat ├── build64.bat └── initenv.bat ├── speedpatch ├── CMakeLists.txt ├── SpeedPatch_global.h ├── speedpatch.cpp ├── speedpatch.h └── vcpkg.json ├── taskscheduler.cpp ├── taskscheduler.h ├── third_party └── minhook │ ├── .editorconfig │ ├── .github │ └── workflows │ │ └── msbuild.yml │ ├── .gitignore │ ├── AUTHORS.txt │ ├── CMakeLists.txt │ ├── LICENSE.txt │ ├── README.md │ ├── build │ └── MinGW │ │ ├── make.bat │ │ └── make.sh │ ├── cmake │ └── minhook-config.cmake.in │ ├── dll_resources │ └── MinHook.def │ ├── include │ └── MinHook.h │ └── src │ ├── buffer.c │ ├── buffer.h │ ├── hde │ ├── hde32.c │ ├── hde32.h │ ├── hde64.c │ ├── hde64.h │ ├── pstdint.h │ ├── table32.h │ └── table64.h │ ├── hook.c │ ├── trampoline.c │ └── trampoline.h ├── translations ├── OpenSpeedy_en_US.qm ├── OpenSpeedy_zh_CN.qm └── OpenSpeedy_zh_TW.qm ├── windbg.h ├── winutils.cpp └── winutils.h /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: Build OpenSpeedy 2 | 3 | on: 4 | pull_request: 5 | branches: [ master ] 6 | workflow_dispatch: 7 | 8 | jobs: 9 | build: 10 | runs-on: self-hosted 11 | outputs: 12 | artifact-id: ${{ steps.upload-unsigned-artifacts.outputs.artifact-id }} 13 | 14 | steps: 15 | - name: Checkout 16 | uses: actions/checkout@v4 17 | 18 | - name: Build 32-bit 19 | shell: cmd 20 | run: | 21 | echo Building 32-bit... 22 | call script\initenv.bat 23 | call script\build32.bat 24 | 25 | - name: Build 64-bit 26 | shell: cmd 27 | run: | 28 | echo Building 64-bit... 29 | call script\initenv.bat 30 | call script\build64.bat 31 | 32 | - name: Collect artifacts to flat directory 33 | shell: cmd 34 | run: | 35 | echo Collecting artifacts... 36 | 37 | if not exist "artifacts" mkdir "artifacts" 38 | 39 | copy "build\CMAKE-64bit-Release\OpenSpeedy.exe" "artifacts\" 40 | copy "build\CMAKE-64bit-Release\speedpatch64.dll" "artifacts\" 41 | copy "build\CMAKE-64bit-Release\bridge64.exe" "artifacts\" 42 | copy "build\CMAKE-32bit-Release\speedpatch32.dll" "artifacts\" 43 | copy "build\CMAKE-32bit-Release\bridge32.exe" "artifacts\" 44 | 45 | echo Artifacts directory contents: 46 | dir "artifacts" 47 | 48 | - name: Upload unsigned artifacts 49 | id: upload-unsigned-artifacts 50 | uses: actions/upload-artifact@v4 51 | if: success() 52 | with: 53 | name: OpenSpeedy-unsigned-artifacts 54 | path: artifacts/ 55 | if-no-files-found: warn 56 | 57 | -------------------------------------------------------------------------------- /.github/workflows/package.yml: -------------------------------------------------------------------------------- 1 | name: Package 2 | on: 3 | workflow_dispatch: 4 | inputs: 5 | build_id: 6 | description: '构建工作流ID' 7 | required: true 8 | type: string 9 | version: 10 | description: '版本号' 11 | required: true 12 | default: '1.0.0' 13 | type: string 14 | artifact_name: 15 | description: '签名的制品名称' 16 | required: true 17 | default: 'OpenSpeedy-unsigned-artifacts' 18 | type: string 19 | 20 | jobs: 21 | package: 22 | runs-on: windows-latest # GitHub-hosted runner 23 | 24 | steps: 25 | - name: Checkout 26 | uses: actions/checkout@v4 27 | 28 | - name: Download build artifact 29 | uses: actions/download-artifact@v4 30 | with: 31 | name: ${{ github.event.inputs.artifact_name }} 32 | run-id: ${{ github.event.inputs.build_id }} 33 | path: artifacts/ 34 | github-token: ${{ secrets.GITHUB_TOKEN }} 35 | 36 | - id: upload-unsigned-artifacts 37 | name: Re-upload as new artifact 38 | uses: actions/upload-artifact@v4 39 | with: 40 | name: OpenSpeedy-unsigned-artifacts 41 | path: artifacts/ 42 | retention-days: 30 43 | 44 | - name: SignPath signing 45 | uses: signpath/github-action-submit-signing-request@v1.1 46 | with: 47 | api-token: ${{ secrets.SIGNPATH_API_TOKEN }} 48 | organization-id: '58b9835d-38ea-4898-a564-76610c01cecd' 49 | project-slug: OpenSpeedy 50 | signing-policy-slug: test-signing 51 | github-artifact-id: ${{ steps.upload-unsigned-artifacts.outputs.artifact-id }} 52 | artifact-configuration-slug: initial 53 | wait-for-completion: true 54 | output-artifact-directory: signed-artifacts/ 55 | parameters: | 56 | version: ${{ toJSON(github.event.inputs.version) }} 57 | 58 | - name: Upload signed artifacts 59 | uses: actions/upload-artifact@v4 60 | with: 61 | name: OpenSpeedy-signed-artifacts 62 | path: signed-artifacts/ 63 | retention-days: 30 64 | 65 | - uses: actions/setup-python@v5 66 | with: 67 | python-version: '3.13' 68 | 69 | - name: Cache Qt Installer Framework 70 | uses: actions/cache@v4 71 | id: cache-qtifw 72 | with: 73 | path: ${{ github.workspace }}/Qt/Tools/QtInstallerFramework 74 | key: qtifw-4.7.0-${{ runner.os }} 75 | restore-keys: | 76 | qtifw-4.7.0- 77 | qtifw- 78 | 79 | - name: Install Qt Installer Framework 80 | if: steps.cache-qtifw.outputs.cache-hit != 'true' 81 | run: | 82 | pip install aqtinstall 83 | python3 -m aqt install-tool -O ${{ github.workspace }}/Qt/ windows desktop tools_ifw qt.tools.ifw.47 84 | 85 | - name: Add Qt Installer Framework to PATH 86 | run: | 87 | echo "${{ github.workspace }}/Qt/Tools/QtInstallerFramework/4.7/bin/" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append 88 | 89 | - name: Package installer 90 | run: | 91 | Copy-Item -Path "signed-artifacts/*" -Destination "installer/packages/com.openspeedy.app/data/" -Recurse -Force 92 | $version = "${{ github.event.inputs.version }}" 93 | 94 | $configXmlPath = "installer\config\config.xml" 95 | [xml]$configXml = Get-Content $configXmlPath 96 | $configXml.Installer.Version = $version 97 | $configXml.Save((Resolve-Path $configXmlPath)) 98 | 99 | $packageXmlPath = "installer\packages\com.openspeedy.app\meta\package.xml" 100 | [xml]$packageXml = Get-Content $packageXmlPath 101 | $packageXml.Package.Version = $version 102 | $packageXml.Save((Resolve-Path $packageXmlPath)) 103 | 104 | Write-Host "Updated package version to: $version" 105 | binarycreator.exe -c installer\config\config.xml -p installer\packages OpenSpeedy-installer-${{ github.event.inputs.version }}.exe 106 | 107 | - id: upload-unsigned-installer 108 | name: Upload installer 109 | uses: actions/upload-artifact@v4 110 | with: 111 | name: OpenSpeedy-unsigned-installer-${{ github.event.inputs.version }} 112 | path: OpenSpeedy-installer-${{ github.event.inputs.version }}.exe 113 | 114 | - name: SignPath signing 115 | uses: signpath/github-action-submit-signing-request@v1.1 116 | with: 117 | api-token: ${{ secrets.SIGNPATH_API_TOKEN }} 118 | organization-id: '58b9835d-38ea-4898-a564-76610c01cecd' 119 | project-slug: OpenSpeedy 120 | signing-policy-slug: test-signing 121 | github-artifact-id: ${{ steps.upload-unsigned-installer.outputs.artifact-id }} 122 | artifact-configuration-slug: installer 123 | wait-for-completion: true 124 | output-artifact-directory: signed-installer/ 125 | parameters: | 126 | version: ${{ toJSON(github.event.inputs.version) }} 127 | 128 | - name: Upload signed installer 129 | uses: actions/upload-artifact@v4 130 | with: 131 | name: OpenSpeedy-signed-installer-${{ github.event.inputs.version }} 132 | path: signed-installer/ 133 | retention-days: 30 -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # This file is used to ignore files which are generated 2 | # ---------------------------------------------------------------------------- 3 | 4 | *~ 5 | *.autosave 6 | *.a 7 | *.core 8 | *.moc 9 | *.o 10 | *.obj 11 | *.orig 12 | *.rej 13 | *.so 14 | *.so.* 15 | *_pch.h.cpp 16 | *_resource.rc 17 | *.qm 18 | .#* 19 | *.*# 20 | core 21 | !core/ 22 | tags 23 | .DS_Store 24 | .directory 25 | *.debug 26 | Makefile* 27 | *.prl 28 | *.app 29 | moc_*.cpp 30 | ui_*.h 31 | qrc_*.cpp 32 | Thumbs.db 33 | *.res 34 | *.rc 35 | /.qmake.cache 36 | /.qmake.stash 37 | 38 | # qtcreator generated files 39 | *.pro.user* 40 | *.qbs.user* 41 | CMakeLists.txt.user* 42 | 43 | # xemacs temporary files 44 | *.flc 45 | 46 | # Vim temporary files 47 | .*.swp 48 | 49 | # Visual Studio generated files 50 | *.ib_pdb_index 51 | *.idb 52 | *.ilk 53 | *.pdb 54 | *.sln 55 | *.suo 56 | *.vcproj 57 | *vcproj.*.*.user 58 | *.ncb 59 | *.sdf 60 | *.opensdf 61 | *.vcxproj 62 | *vcxproj.* 63 | 64 | # MinGW generated files 65 | *.Debug 66 | *.Release 67 | 68 | # Python byte code 69 | *.pyc 70 | 71 | # Binaries 72 | # -------- 73 | *.dll 74 | *.exe 75 | 76 | # Directories with generated files 77 | .moc/ 78 | .obj/ 79 | .pch/ 80 | .rcc/ 81 | .uic/ 82 | /build*/ 83 | .vs/ 84 | out/ -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/game1024/OpenSpeedy/b54416000c2bea56654a9f628f2641cd55038780/.gitmodules -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.16) 2 | 3 | project(OpenSpeedy VERSION 0.1 LANGUAGES CXX) 4 | 5 | set(CMAKE_AUTOUIC ON) 6 | set(CMAKE_AUTOMOC ON) 7 | set(CMAKE_AUTORCC ON) 8 | 9 | set(CMAKE_CXX_STANDARD 17) 10 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 11 | 12 | # 启用Qt静态链接 13 | set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreadedlt;lt;CONFIG:Debug>:Debug>") 14 | 15 | find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Widgets LinguistTools) 16 | find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Widgets Network WinExtras LinguistTools) 17 | set(TS_FILES 18 | OpenSpeedy_zh_CN.ts 19 | OpenSpeedy_en_US.ts 20 | OpenSpeedy_zh_TW.ts 21 | ) 22 | 23 | set(PROJECT_SOURCES 24 | main.cpp 25 | mainwindow.cpp 26 | mainwindow.h 27 | mainwindow.ui 28 | ${TS_FILES} 29 | ) 30 | 31 | if(${QT_VERSION_MAJOR} GREATER_EQUAL 6) 32 | qt_add_executable(OpenSpeedy 33 | MANUAL_FINALIZATION 34 | ${PROJECT_SOURCES} 35 | winutils.h winutils.cpp 36 | processmonitor.h processmonitor.cpp 37 | resources.qrc 38 | images/icon.ico images/logo.png 39 | icons.rc 40 | ) 41 | 42 | # Define target properties for Android with Qt 6 as: 43 | # set_property(TARGET OpenSpeedy APPEND PROPERTY QT_ANDROID_PACKAGE_SOURCE_DIR 44 | # ${CMAKE_CURRENT_SOURCE_DIR}/android) 45 | # For more information, see https://doc.qt.io/qt-6/qt-add-executable.html#target-creation 46 | 47 | qt_create_translation(QM_FILES ${CMAKE_SOURCE_DIR} ${TS_FILES}) 48 | else() 49 | qt5_create_translation(QM_FILES 50 | ${CMAKE_SOURCE_DIR} 51 | ${TS_FILES}) 52 | 53 | add_definitions("-DUNICODE -DNOMINMAX") 54 | add_executable(OpenSpeedy 55 | ${PROJECT_SOURCES} 56 | processmonitor.h processmonitor.cpp 57 | resources.qrc 58 | images/icon.ico images/logo.png 59 | icons.rc 60 | config.h 61 | windbg.h 62 | aboutdialog.ui 63 | aboutdialog.h aboutdialog.cpp aboutdialog.ui 64 | preferencedialog.h preferencedialog.cpp preferencedialog.ui 65 | qsinglekeysequenceedit.h qsinglekeysequenceedit.cpp 66 | ${QM_FILES} 67 | 68 | 69 | ) 70 | 71 | add_library(winutils 72 | winutils.h winutils.cpp 73 | cpuutils.h cpuutils.cpp 74 | memutils.h memutils.cpp 75 | taskscheduler.h 76 | taskscheduler.cpp 77 | ) 78 | 79 | target_include_directories(winutils PUBLIC 80 | ${CMAKE_CURRENT_SOURCE_DIR} 81 | ) 82 | 83 | target_link_libraries(winutils PUBLIC 84 | Qt${QT_VERSION_MAJOR}::Core 85 | pdh 86 | ole32 87 | oleaut32 88 | taskschd) 89 | endif() 90 | 91 | 92 | 93 | target_link_libraries(OpenSpeedy PRIVATE 94 | Qt${QT_VERSION_MAJOR}::Widgets 95 | Qt${QT_VERSION_MAJOR}::Network 96 | Qt${QT_VERSION_MAJOR}::WinExtras 97 | winutils 98 | ) 99 | 100 | # Qt for iOS sets MACOSX_BUNDLE_GUI_IDENTIFIER automatically since Qt 6.1. 101 | # If you are developing for iOS or macOS you should consider setting an 102 | # explicit, fixed bundle identifier manually though. 103 | if(${QT_VERSION} VERSION_LESS 6.1.0) 104 | set(BUNDLE_ID_OPTION MACOSX_BUNDLE_GUI_IDENTIFIER com.example.OpenSpeedy) 105 | endif() 106 | set_target_properties(OpenSpeedy PROPERTIES 107 | ${BUNDLE_ID_OPTION} 108 | MACOSX_BUNDLE_BUNDLE_VERSION ${PROJECT_VERSION} 109 | MACOSX_BUNDLE_SHORT_VERSION_STRING ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR} 110 | MACOSX_BUNDLE TRUE 111 | WIN32_EXECUTABLE TRUE 112 | #LINK_FLAGS "/MANIFESTUAC:\"level='requireAdministrator' uiAccess='false'\" /SUBSYSTEM:WINDOWS" 113 | ) 114 | 115 | include(GNUInstallDirs) 116 | install(TARGETS OpenSpeedy 117 | BUNDLE DESTINATION . 118 | LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} 119 | RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} 120 | ) 121 | 122 | if(QT_VERSION_MAJOR EQUAL 6) 123 | qt_finalize_executable(OpenSpeedy) 124 | endif() 125 | 126 | add_subdirectory(third_party/minhook) 127 | add_subdirectory(speedpatch) 128 | add_subdirectory(bridge) 129 | 130 | -------------------------------------------------------------------------------- /CMakePresets.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": 3, 3 | "configurePresets": [ 4 | { 5 | "hidden": true, 6 | "name": "Qt", 7 | "cacheVariables": { 8 | "CMAKE_PREFIX_PATH": "$env{QTDIR}" 9 | }, 10 | "vendor": { 11 | "qt-project.org/Qt": { 12 | "checksum": "wVa86FgEkvdCTVp1/nxvrkaemJc=" 13 | } 14 | } 15 | } 16 | ], 17 | "vendor": { 18 | "qt-project.org/Presets": { 19 | "checksum": "67SmY24ZeVbebyKD0fGfIzb/bGI=" 20 | } 21 | } 22 | } -------------------------------------------------------------------------------- /CMakeUserPresets.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": 3, 3 | "configurePresets": [ 4 | { 5 | "name": "Qt-Debug", 6 | "inherits": "Qt-Default", 7 | "binaryDir": "${sourceDir}/out/build/debug", 8 | "cacheVariables": { 9 | "CMAKE_BUILD_TYPE": "Debug", 10 | "CMAKE_CXX_FLAGS": "-DQT_QML_DEBUG" 11 | }, 12 | "environment": { 13 | "QML_DEBUG_ARGS": "-qmljsdebugger=file:{68d8eccf-89d3-401a-a51b-854d41e11c66},block" 14 | } 15 | }, 16 | { 17 | "name": "Qt-Release", 18 | "inherits": "Qt-Default", 19 | "binaryDir": "${sourceDir}/out/build/release", 20 | "cacheVariables": { 21 | "CMAKE_BUILD_TYPE": "Release" 22 | } 23 | }, 24 | { 25 | "hidden": true, 26 | "name": "Qt-Default", 27 | "inherits": "6.9.0_msvc2022_64", 28 | "vendor": { 29 | "qt-project.org/Default": { 30 | "checksum": "p2g8qSfRuZwrHdoqsydD/azGQjs=" 31 | } 32 | } 33 | }, 34 | { 35 | "hidden": true, 36 | "name": "6.9.0_msvc2022_64", 37 | "inherits": "Qt", 38 | "environment": { 39 | "QTDIR": "D:/Qt/6.9.0/msvc2022_64" 40 | }, 41 | "architecture": { 42 | "strategy": "external", 43 | "value": "x64" 44 | }, 45 | "generator": "Ninja", 46 | "vendor": { 47 | "qt-project.org/Version": { 48 | "checksum": "sBywmcWZZXChcZz0AVGlSBNHGws=" 49 | } 50 | } 51 | } 52 | ], 53 | "vendor": { 54 | "qt-project.org/Presets": { 55 | "checksum": "IQB0bB4OeX7kqF6cObd8brpl2ck=" 56 | } 57 | } 58 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | <h1 align="center"> OpenSpeedy </h1> 2 | 3 | <p align="center"> 4 | <img style="margin:0 auto" width=100 height=100 src="https://github.com/user-attachments/assets/bdbe4a60-7692-4e9c-9df4-ad1711337c57"> 5 | </img> 6 | </p> 7 | 8 | <p align="center"> 9 | OpenSpeedy is an open-source and free game speed tool that helps you break frame rate limitations and provides a smoother, silkier gaming acceleration experience. 10 | </p> 11 | 12 | <p align="center"> 13 | <img src="https://api.visitorbadge.io/api/visitors?path=game1024.openspeedy&countColor=%234ecdc4"> 14 | <br/> 15 | 16 | <a href="https://github.com/game1024/OpenSpeedy/stargazers"> 17 | <img src="https://img.shields.io/github/stars/game1024/OpenSpeedy?style=for-the-badge&color=yellow" alt="GitHub Stars"> 18 | </a> 19 | 20 | <img src="https://img.shields.io/github/forks/game1024/OpenSpeedy?style=for-the-badge&color=8a2be2" alt="GitHub Forks"> 21 | 22 | <a href="https://github.com/game1024/OpenSpeedy/issues"> 23 | <img src="https://img.shields.io/github/issues-raw/game1024/OpenSpeedy?style=for-the-badge&label=Issues&color=orange" alt="Github Issues"> 24 | </a> 25 | <br/> 26 | 27 | <a href="https://github.com/game1024/OpenSpeedy/releases"> 28 | <img src="https://img.shields.io/github/downloads/game1024/OpenSpeedy/total?style=for-the-badge" alt="Downloads"> 29 | </a> 30 | <a href="https://github.com/game1024/OpenSpeedy/releases"> 31 | <img src="https://img.shields.io/github/v/release/game1024/OpenSpeedy?style=for-the-badge&color=brightgreen" alt="Version"> 32 | </a> 33 | <a href="https://github.com/game1024/OpenSpeedy/actions"> 34 | <img src="https://img.shields.io/github/actions/workflow/status/game1024/OpenSpeedy/ci.yml?style=for-the-badge" alt="Github Action"> 35 | </a> 36 | <a href="https://github.com/game1024/OpenSpeedy"> 37 | <img src="https://img.shields.io/badge/Platform-Windows-lightblue?style=for-the-badge" alt="Platform"> 38 | </a> 39 | <br/> 40 | 41 | <a href="https://github.com/game1024/OpenSpeedy/commits"> 42 | <img src="https://img.shields.io/github/commit-activity/m/game1024/OpenSpeedy?style=for-the-badge" alt="Commit Activity"> 43 | </a> 44 | <img src="https://img.shields.io/badge/language-C/C++-blue?style=for-the-badge"> 45 | <img src="https://img.shields.io/badge/License-GPLv3-green.svg?style=for-the-badge"> 46 | <br/> 47 | 48 | <a href="https://hellogithub.com/repository/975f473c56ad4369a1c30ac9aa5819e0" target="_blank"> 49 | <img src="https://abroad.hellogithub.com/v1/widgets/recommend.svg?rid=975f473c56ad4369a1c30ac9aa5819e0&claim_uid=kmUCncHJr9SpNV7&theme=neutral" alt="Featured|HelloGitHub" style="width: 250px; height: 54px;" width="250" height="54" /> 50 | </a> 51 | </p> 52 | 53 | <p align="center"> 54 | <a href="https://github.com/game1024/OpenSpeedy/blob/master/docs/README_cn.md"> 55 | 简体中文 56 | </a> 57 | · 58 | <a href="https://github.com/game1024/OpenSpeedy/blob/master/docs/README_ja.md"> 59 | 日本語 60 | </a> 61 | · 62 | <a href="https://github.com/game1024/OpenSpeedy?tab=readme-ov-file#-openspeedy-"> 63 | English 64 | </a> 65 | </p> 66 | 67 | # 🚀 Features 68 | - Completely free and open-source 69 | - Easy-to-use interface 70 | - Customizable speed multiplier 71 | - Good compatibility with various game engines 72 | - Low system resource consumption 73 | - Supports accelerating both x86 and x64 processes 74 | - Non-invasive to the kernel: Ring3 level Hook, does not compromise the system kernel 75 | 76 | # 💾 Installation 77 | 📦 **Method1: Winget** 78 | 79 | ``` powershell 80 | # install 81 | winget install openspeedy 82 | 83 | # open a new terminal, you can run openspeedy by following command 84 | openspeedy 85 | ``` 86 | 87 | 📥 **Method2: Manual Download** 88 | 89 | Visit the [Installation Page](https://github.com/game1024/OpenSpeedy/releases) to download the latest version 90 | 91 | 92 | 93 | # 💻 System Requirements 94 | - OS: Windows 10 or later 95 | - Platform: x86 (32-bit) and x64 (64-bit) 96 | 97 | # 📝 Usage Instructions 98 | 1. Start OpenSpeedy 99 | 2. Launch the target game you want to speed up 100 | <img src="https://github.com/user-attachments/assets/648e721d-9c3a-4d82-954c-19b16355d084" width="50%"> 101 | 102 | 3. Select the game process, and adjust the speed multiplier in the OpenSpeedy interface 103 | <img src="https://github.com/user-attachments/assets/9469aae9-8be0-4e40-884d-1fbea3206e73" width="50%"> 104 | 105 | 4. The effect takes effect immediately. Compare the results below 106 | 107 | <video src="https://github.com/user-attachments/assets/74471b1f-7f95-4de8-b5aa-7edc85c9d5f0" width="70%"></video> 108 | 109 | # 🔧 Technical Principle 110 | OpenSpeedy achieves game speed adjustment by hooking the following Windows system time functions: 111 | 112 | | Function Name | Library | Description | 113 | |---------------|---------|-------------| 114 | | Sleep | user32.dll | Thread sleep | 115 | | SetTimer | user32.dll | Create message-based timer | 116 | | timeGetTime | winmm.dll | Get milliseconds elapsed since system startup | 117 | | GetTickCount | kernel32.dll | Get milliseconds elapsed since system startup | 118 | | GetTickCount64 | kernel32.dll | Get milliseconds elapsed since system startup (64-bit) | 119 | | QueryPerformanceCounter | kernel32.dll | High precision performance counter | 120 | | GetSystemTimeAsFileTime | kernel32.dll | Get system time | 121 | | GetSystemTimePreciseAsFileTime | kernel32.dll | Get high precision system time | 122 | 123 | # ⚠️ Notes 124 | - This tool is for learning and research purposes only 125 | - Some online games may have anti-cheat systems. Using this tool may result in your account being banned 126 | - Excessive speeding up may cause the game physics engine to malfunction or crash 127 | - Not recommended for use in competitive online games 128 | - Open source product does not include digital signature and may be falsely flagged by antivirus software 129 | 130 | # 🔄 Feedback 131 | If you encounter any issues during use, feel free to provide feedback via: 132 | - [FAQ](https://github.com/game1024/OpenSpeedy/wiki#faq) - You can first check the wiki to locate the issue. 133 | - [GitHub Issues](https://github.com/game1024/OpenSpeedy/issues) - Submit issue reports 134 | - WeChat Group 135 | <img width="30%" src="https://github.com/user-attachments/assets/d77cb35d-6c92-4480-89c9-40f124c4df08"> 136 | 137 | # 🎁 Sponosor 138 | If you find the OpenSpeedy project helpful, you can buy me a coffee~ ☕️ 139 | 140 | 365VPN uses dedicated lines to connect worldwide, offering speeds of up to 10Gbps. Download now to start surfing for free🏄: https://ref.365tz87989.com/?r=RWQVZD 141 | 142 | # 📜 License 143 | OpenSpeedy is licensed under the GNU v3 License. 144 | 145 | # 🙏 Acknowledgements 146 | OpenSpeedy uses source code from the following projects. Thanks to the open-source community! If OpenSpeedy helps you, please give us a Star! 147 | - [minhook](https://github.com/TsudaKageyu/minhook): For API Hooking 148 | - [Qt](https://www.qt.io/): GUI 149 | 150 | Disclaimer: OpenSpeedy is intended for educational and research purposes only. Users assume all risks and responsibilities for using this software. The author is not responsible for any loss or legal liability resulting from the use of this software. 151 | 152 | <p align="center"> 153 | <img src="https://api.star-history.com/svg?repos=game1024/openspeedy&type=Date" Alt="Star History Chart"> 154 | </p> 155 | -------------------------------------------------------------------------------- /aboutdialog.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * OpenSpeedy - Open Source Game Speed Controller 3 | * Copyright (C) 2025 Game1024 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see <https://www.gnu.org/licenses/>. 17 | */ 18 | #include "aboutdialog.h" 19 | #include "ui_aboutdialog.h" 20 | #include <QPushButton> 21 | #include <QScreen> 22 | AboutDialog::AboutDialog(QWidget* parent) 23 | : QDialog(parent) 24 | , ui(new Ui::AboutDialog) 25 | { 26 | ui->setupUi(this); 27 | ui->buttonBox->button(QDialogButtonBox::Ok)->setText(tr("确认")); 28 | ui->versionContent->setText(QString("%1").arg(OPENSPEEDY_VERSION)); 29 | connect(QGuiApplication::primaryScreen(), 30 | &QScreen::logicalDotsPerInchChanged, 31 | this, 32 | &AboutDialog::recreate); 33 | setWindowFlags(Qt::Dialog | Qt::WindowTitleHint | Qt::CustomizeWindowHint); 34 | } 35 | 36 | AboutDialog::~AboutDialog() 37 | { 38 | delete ui; 39 | } 40 | 41 | void 42 | AboutDialog::recreate() 43 | { 44 | layout()->invalidate(); 45 | layout()->activate(); 46 | adjustSize(); 47 | } 48 | -------------------------------------------------------------------------------- /aboutdialog.h: -------------------------------------------------------------------------------- 1 | /* 2 | * OpenSpeedy - Open Source Game Speed Controller 3 | * Copyright (C) 2025 Game1024 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see <https://www.gnu.org/licenses/>. 17 | */ 18 | #ifndef ABOUTDIALOG_H 19 | #define ABOUTDIALOG_H 20 | #include "config.h" 21 | #include <QDialog> 22 | 23 | namespace Ui 24 | { 25 | class AboutDialog; 26 | } 27 | 28 | class AboutDialog : public QDialog 29 | { 30 | Q_OBJECT 31 | 32 | public: 33 | explicit AboutDialog(QWidget* parent = nullptr); 34 | ~AboutDialog(); 35 | 36 | private slots: 37 | void recreate(); 38 | 39 | private: 40 | Ui::AboutDialog* ui; 41 | }; 42 | 43 | #endif // ABOUTDIALOG_H 44 | -------------------------------------------------------------------------------- /aboutdialog.ui: -------------------------------------------------------------------------------- 1 | <?xml version="1.0" encoding="UTF-8"?> 2 | <ui version="4.0"> 3 | <class>AboutDialog</class> 4 | <widget class="QDialog" name="AboutDialog"> 5 | <property name="windowModality"> 6 | <enum>Qt::ApplicationModal</enum> 7 | </property> 8 | <property name="geometry"> 9 | <rect> 10 | <x>0</x> 11 | <y>0</y> 12 | <width>440</width> 13 | <height>215</height> 14 | </rect> 15 | </property> 16 | <property name="sizePolicy"> 17 | <sizepolicy hsizetype="Maximum" vsizetype="Maximum"> 18 | <horstretch>0</horstretch> 19 | <verstretch>0</verstretch> 20 | </sizepolicy> 21 | </property> 22 | <property name="minimumSize"> 23 | <size> 24 | <width>0</width> 25 | <height>0</height> 26 | </size> 27 | </property> 28 | <property name="maximumSize"> 29 | <size> 30 | <width>16777215</width> 31 | <height>16777215</height> 32 | </size> 33 | </property> 34 | <property name="windowTitle"> 35 | <string>关于</string> 36 | </property> 37 | <property name="sizeGripEnabled"> 38 | <bool>false</bool> 39 | </property> 40 | <property name="modal"> 41 | <bool>false</bool> 42 | </property> 43 | <layout class="QVBoxLayout" name="verticalLayout"> 44 | <property name="spacing"> 45 | <number>7</number> 46 | </property> 47 | <property name="sizeConstraint"> 48 | <enum>QLayout::SetFixedSize</enum> 49 | </property> 50 | <item> 51 | <widget class="QLabel" name="appTitle"> 52 | <property name="font"> 53 | <font> 54 | <family>微软雅黑</family> 55 | <pointsize>12</pointsize> 56 | </font> 57 | </property> 58 | <property name="text"> 59 | <string>OpenSpeedy</string> 60 | </property> 61 | <property name="alignment"> 62 | <set>Qt::AlignCenter</set> 63 | </property> 64 | </widget> 65 | </item> 66 | <item> 67 | <layout class="QGridLayout" name="gridLayout"> 68 | <property name="sizeConstraint"> 69 | <enum>QLayout::SetMaximumSize</enum> 70 | </property> 71 | <property name="verticalSpacing"> 72 | <number>4</number> 73 | </property> 74 | <item row="2" column="1"> 75 | <widget class="QLabel" name="label_3"> 76 | <property name="sizePolicy"> 77 | <sizepolicy hsizetype="Minimum" vsizetype="Preferred"> 78 | <horstretch>0</horstretch> 79 | <verstretch>0</verstretch> 80 | </sizepolicy> 81 | </property> 82 | <property name="font"> 83 | <font> 84 | <family>微软雅黑</family> 85 | </font> 86 | </property> 87 | <property name="text"> 88 | <string>版本:</string> 89 | </property> 90 | <property name="scaledContents"> 91 | <bool>false</bool> 92 | </property> 93 | <property name="alignment"> 94 | <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> 95 | </property> 96 | <property name="wordWrap"> 97 | <bool>true</bool> 98 | </property> 99 | </widget> 100 | </item> 101 | <item row="0" column="0"> 102 | <widget class="QLabel" name="authorIcon"> 103 | <property name="sizePolicy"> 104 | <sizepolicy hsizetype="Maximum" vsizetype="Preferred"> 105 | <horstretch>0</horstretch> 106 | <verstretch>0</verstretch> 107 | </sizepolicy> 108 | </property> 109 | <property name="font"> 110 | <font> 111 | <family>Segoe UI Emoji</family> 112 | <pointsize>12</pointsize> 113 | </font> 114 | </property> 115 | <property name="text"> 116 | <string>😄</string> 117 | </property> 118 | </widget> 119 | </item> 120 | <item row="0" column="1"> 121 | <widget class="QLabel" name="label"> 122 | <property name="sizePolicy"> 123 | <sizepolicy hsizetype="Minimum" vsizetype="Preferred"> 124 | <horstretch>0</horstretch> 125 | <verstretch>0</verstretch> 126 | </sizepolicy> 127 | </property> 128 | <property name="font"> 129 | <font> 130 | <family>微软雅黑</family> 131 | </font> 132 | </property> 133 | <property name="text"> 134 | <string>作者:</string> 135 | </property> 136 | <property name="scaledContents"> 137 | <bool>false</bool> 138 | </property> 139 | <property name="alignment"> 140 | <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> 141 | </property> 142 | <property name="wordWrap"> 143 | <bool>true</bool> 144 | </property> 145 | </widget> 146 | </item> 147 | <item row="3" column="0"> 148 | <widget class="QLabel" name="licenseIcon"> 149 | <property name="sizePolicy"> 150 | <sizepolicy hsizetype="Maximum" vsizetype="Preferred"> 151 | <horstretch>0</horstretch> 152 | <verstretch>0</verstretch> 153 | </sizepolicy> 154 | </property> 155 | <property name="font"> 156 | <font> 157 | <family>Segoe UI Emoji</family> 158 | <pointsize>12</pointsize> 159 | </font> 160 | </property> 161 | <property name="text"> 162 | <string>📜</string> 163 | </property> 164 | </widget> 165 | </item> 166 | <item row="3" column="2"> 167 | <widget class="QLabel" name="licenseContent"> 168 | <property name="font"> 169 | <font> 170 | <family>微软雅黑</family> 171 | </font> 172 | </property> 173 | <property name="text"> 174 | <string>General Public License v3</string> 175 | </property> 176 | </widget> 177 | </item> 178 | <item row="1" column="0"> 179 | <widget class="QLabel" name="homeIcon"> 180 | <property name="sizePolicy"> 181 | <sizepolicy hsizetype="Maximum" vsizetype="Preferred"> 182 | <horstretch>0</horstretch> 183 | <verstretch>0</verstretch> 184 | </sizepolicy> 185 | </property> 186 | <property name="font"> 187 | <font> 188 | <family>Segoe UI Emoji</family> 189 | <pointsize>12</pointsize> 190 | </font> 191 | </property> 192 | <property name="text"> 193 | <string>🚀</string> 194 | </property> 195 | </widget> 196 | </item> 197 | <item row="0" column="2"> 198 | <widget class="QLabel" name="authorContent"> 199 | <property name="font"> 200 | <font> 201 | <family>微软雅黑</family> 202 | </font> 203 | </property> 204 | <property name="text"> 205 | <string><html><head/><body><p><a href="https://github.com/game1024"><span style=" text-decoration: none; color:#003e92;">game1024</span></a></p></body></html></string> 206 | </property> 207 | <property name="openExternalLinks"> 208 | <bool>true</bool> 209 | </property> 210 | </widget> 211 | </item> 212 | <item row="2" column="0"> 213 | <widget class="QLabel" name="versionIcon"> 214 | <property name="sizePolicy"> 215 | <sizepolicy hsizetype="Maximum" vsizetype="Preferred"> 216 | <horstretch>0</horstretch> 217 | <verstretch>0</verstretch> 218 | </sizepolicy> 219 | </property> 220 | <property name="font"> 221 | <font> 222 | <family>Segoe UI Emoji</family> 223 | <pointsize>12</pointsize> 224 | </font> 225 | </property> 226 | <property name="text"> 227 | <string>🌳</string> 228 | </property> 229 | </widget> 230 | </item> 231 | <item row="1" column="2"> 232 | <widget class="QLabel" name="homeContent"> 233 | <property name="font"> 234 | <font> 235 | <family>微软雅黑</family> 236 | </font> 237 | </property> 238 | <property name="text"> 239 | <string><html><head/><body><p><a href="https://github.com/game1024/OpenSpeedy"><span style=" text-decoration: none; color:#003e92;">game1024/OpenSpeedy</span></a></p></body></html></string> 240 | </property> 241 | <property name="openExternalLinks"> 242 | <bool>true</bool> 243 | </property> 244 | </widget> 245 | </item> 246 | <item row="2" column="2"> 247 | <widget class="QLabel" name="versionContent"> 248 | <property name="font"> 249 | <font> 250 | <family>微软雅黑</family> 251 | </font> 252 | </property> 253 | <property name="text"> 254 | <string>v0.0.0</string> 255 | </property> 256 | </widget> 257 | </item> 258 | <item row="3" column="1"> 259 | <widget class="QLabel" name="label_4"> 260 | <property name="sizePolicy"> 261 | <sizepolicy hsizetype="Minimum" vsizetype="Preferred"> 262 | <horstretch>0</horstretch> 263 | <verstretch>0</verstretch> 264 | </sizepolicy> 265 | </property> 266 | <property name="font"> 267 | <font> 268 | <family>微软雅黑</family> 269 | </font> 270 | </property> 271 | <property name="text"> 272 | <string>协议:</string> 273 | </property> 274 | <property name="scaledContents"> 275 | <bool>false</bool> 276 | </property> 277 | <property name="alignment"> 278 | <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> 279 | </property> 280 | <property name="wordWrap"> 281 | <bool>true</bool> 282 | </property> 283 | </widget> 284 | </item> 285 | <item row="1" column="1"> 286 | <widget class="QLabel" name="label_2"> 287 | <property name="sizePolicy"> 288 | <sizepolicy hsizetype="Minimum" vsizetype="Preferred"> 289 | <horstretch>0</horstretch> 290 | <verstretch>0</verstretch> 291 | </sizepolicy> 292 | </property> 293 | <property name="font"> 294 | <font> 295 | <family>微软雅黑</family> 296 | </font> 297 | </property> 298 | <property name="text"> 299 | <string>主页:</string> 300 | </property> 301 | <property name="scaledContents"> 302 | <bool>false</bool> 303 | </property> 304 | <property name="alignment"> 305 | <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> 306 | </property> 307 | <property name="wordWrap"> 308 | <bool>true</bool> 309 | </property> 310 | </widget> 311 | </item> 312 | </layout> 313 | </item> 314 | <item> 315 | <widget class="QDialogButtonBox" name="buttonBox"> 316 | <property name="standardButtons"> 317 | <set>QDialogButtonBox::Ok</set> 318 | </property> 319 | </widget> 320 | </item> 321 | </layout> 322 | </widget> 323 | <resources/> 324 | <connections> 325 | <connection> 326 | <sender>buttonBox</sender> 327 | <signal>accepted()</signal> 328 | <receiver>AboutDialog</receiver> 329 | <slot>accept()</slot> 330 | <hints> 331 | <hint type="sourcelabel"> 332 | <x>219</x> 333 | <y>154</y> 334 | </hint> 335 | <hint type="destinationlabel"> 336 | <x>219</x> 337 | <y>89</y> 338 | </hint> 339 | </hints> 340 | </connection> 341 | </connections> 342 | </ui> 343 | -------------------------------------------------------------------------------- /bridge/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.16) 2 | 3 | project(Bridge LANGUAGES CXX) 4 | 5 | set(CMAKE_AUTOUIC ON) 6 | set(CMAKE_AUTOMOC ON) 7 | set(CMAKE_AUTORCC ON) 8 | 9 | set(CMAKE_CXX_STANDARD 17) 10 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 11 | 12 | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ..) 13 | 14 | find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Core) 15 | find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Core) 16 | 17 | # 判断是32位还是64位 18 | if(CMAKE_SIZEOF_VOID_P EQUAL 8) 19 | set(TARGET_NAME "bridge64") 20 | set(SPEEDPATCH_LIBRARY "speedpatch64") 21 | elseif(CMAKE_SIZEOF_VOID_P EQUAL 4) 22 | set(TARGET_NAME "bridge32") 23 | set(SPEEDPATCH_LIBRARY "speedpatch32") 24 | else() 25 | set(TARGET_NAME "bridge64") 26 | set(SPEEDPATCH_LIBRARY "speedpatch") 27 | endif() 28 | 29 | add_executable(${TARGET_NAME} 30 | main.cpp 31 | ) 32 | 33 | target_link_libraries(${TARGET_NAME} Qt${QT_VERSION_MAJOR}::Core ${SPEEDPATCH_LIBRARY} winutils) 34 | 35 | include(GNUInstallDirs) 36 | install(TARGETS ${TARGET_NAME} 37 | LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} 38 | RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} 39 | ) 40 | -------------------------------------------------------------------------------- /bridge/main.cpp: -------------------------------------------------------------------------------- 1 | #include "../config.h" 2 | #include "../speedpatch/speedpatch.h" 3 | #include "../windbg.h" 4 | #include "../winutils.h" 5 | #include <QCoreApplication> 6 | #include <QDebug> 7 | #include <QDir> 8 | #include <QRegularExpression> 9 | #include <QTextStream> 10 | 11 | #ifndef _WIN64 12 | #define SPEEDPATCH_DLL SPEEDPATCH32_DLL 13 | #else 14 | #define SPEEDPATCH_DLL SPEEDPATCH64_DLL 15 | #endif 16 | 17 | void 18 | handleInject(int processId, QString dllPath) 19 | { 20 | qDebug() << "执行 inject,进程ID:" << processId; 21 | winutils::injectDll(processId, dllPath); 22 | SetProcessStatus(processId, true); 23 | } 24 | 25 | void 26 | handleUnhook(int processId, QString dllPath) 27 | { 28 | qDebug() << "执行 unhook,进程ID:" << processId; 29 | SetProcessStatus(processId, false); 30 | } 31 | 32 | void 33 | handleChange(double factor) 34 | { 35 | qDebug() << "执行 change,参数:" << factor; 36 | ChangeSpeed(factor); 37 | } 38 | 39 | int 40 | main(int argc, char* argv[]) 41 | { 42 | SetUnhandledExceptionFilter(createMiniDump); 43 | QCoreApplication a(argc, argv); 44 | if (winutils::enableAllPrivilege()) 45 | { 46 | qDebug() << "权限提升成功"; 47 | } 48 | 49 | QString dllPath = QDir::toNativeSeparators( 50 | QCoreApplication::applicationDirPath() + "/" + SPEEDPATCH_DLL); 51 | 52 | QTextStream in(stdin); 53 | QTextStream out(stdout); 54 | 55 | QRegularExpression injectRegex("^\\s*inject\\s+(\\d+)\\s*quot;, 56 | QRegularExpression::CaseInsensitiveOption); 57 | QRegularExpression unhookRegex("^\\s*unhook\\s+(\\d+)\\s*quot;, 58 | QRegularExpression::CaseInsensitiveOption); 59 | QRegularExpression changeRegex("^\\s*change\\s+([+-]?\\d*\\.?\\d+)\\s*quot;, 60 | QRegularExpression::CaseInsensitiveOption); 61 | QRegularExpression exitRegex("^\\s*exit\\s*quot;, 62 | QRegularExpression::CaseInsensitiveOption); 63 | 64 | while (true) 65 | { 66 | QString line = in.readLine(); 67 | if (line.isNull()) 68 | { 69 | // 管道关闭或输入结束 70 | break; 71 | } 72 | line = line.trimmed(); 73 | if (line.isEmpty()) 74 | continue; 75 | 76 | QRegularExpressionMatch match; 77 | if ((match = injectRegex.match(line)).hasMatch()) 78 | { 79 | int pid = match.captured(1).toInt(); 80 | handleInject(pid, dllPath); 81 | } 82 | else if ((match = unhookRegex.match(line)).hasMatch()) 83 | { 84 | int pid = match.captured(1).toInt(); 85 | handleUnhook(pid, dllPath); 86 | } 87 | else if ((match = changeRegex.match(line)).hasMatch()) 88 | { 89 | double factor = match.captured(1).toDouble(); 90 | handleChange(factor); 91 | } 92 | else if (exitRegex.match(line).hasMatch()) 93 | { 94 | qDebug() << "收到exit命令,程序即将退出。"; 95 | break; 96 | } 97 | else 98 | { 99 | qDebug() << "无效命令:" << line; 100 | } 101 | } 102 | 103 | return 0; 104 | } 105 | -------------------------------------------------------------------------------- /config.h: -------------------------------------------------------------------------------- 1 | /* 2 | * OpenSpeedy - Open Source Game Speed Controller 3 | * Copyright (C) 2025 Game1024 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see <https://www.gnu.org/licenses/>. 17 | */ 18 | #ifndef CONFIG_H 19 | #define CONFIG_H 20 | 21 | #define OPENSPEEDY_VERSION "v1.7.6" 22 | 23 | #define BRIDGE32_EXE "bridge32.exe" 24 | #define BRIDGE64_EXE "bridge64.exe" 25 | 26 | #define SPEEDPATCH32_DLL "speedpatch32.dll" 27 | #define SPEEDPATCH64_DLL "speedpatch64.dll" 28 | 29 | #define CONFIG_LANGUAGE "General/Language" 30 | 31 | // 热键ID 32 | enum HotkeyIds 33 | { 34 | HOTKEY_INCREASE_SPEED = 1001, 35 | HOTKEY_DECREASE_SPEED = 1002, 36 | HOTKEY_RESET_SPEED = 1003, 37 | HOTKEY_SHIFT1 = 1011, 38 | HOTKEY_SHIFT2 = 1012, 39 | HOTKEY_SHIFT3 = 1013, 40 | HOTKEY_SHIFT4 = 1014, 41 | HOTKEY_SHIFT5 = 1015 42 | }; 43 | 44 | #endif // CONFIG_H 45 | -------------------------------------------------------------------------------- /cpuutils.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * OpenSpeedy - Open Source Game Speed Controller 3 | * Copyright (C) 2025 Game1024 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see <https://www.gnu.org/licenses/>. 17 | */ 18 | #include "cpuutils.h" 19 | 20 | CpuUtils::CpuUtils() 21 | { 22 | } 23 | 24 | bool CpuUtils::init() 25 | { 26 | // 创建查询 27 | if (PdhOpenQuery(NULL, NULL, &hQuery) != ERROR_SUCCESS) return false; 28 | 29 | if (PdhAddEnglishCounter(hQuery, 30 | L"\\Processor(_Total)\\% Processor Time", 31 | NULL, 32 | &hCounter) != ERROR_SUCCESS) 33 | { 34 | PdhCloseQuery(hQuery); 35 | return false; 36 | } 37 | 38 | // 第一次采样 39 | PdhCollectQueryData(hQuery); 40 | initialized = true; 41 | return true; 42 | } 43 | 44 | double CpuUtils::getUsage() 45 | { 46 | if (!initialized) return -1; 47 | 48 | // 收集数据 49 | if (PdhCollectQueryData(hQuery) != ERROR_SUCCESS) return -1; 50 | 51 | PDH_FMT_COUNTERVALUE value; 52 | if (PdhGetFormattedCounterValue(hCounter, PDH_FMT_DOUBLE, NULL, &value) != 53 | ERROR_SUCCESS) 54 | return -1; 55 | 56 | return value.doubleValue; 57 | } 58 | 59 | QString CpuUtils::getModel() 60 | { 61 | int cpuInfo[4]; 62 | char cpuBrand[48 + 1] = {0}; 63 | 64 | // 获取CPU品牌字符串(需要调用3次CPUID) 65 | __cpuid(cpuInfo, 0x80000002); 66 | memcpy(cpuBrand, cpuInfo, sizeof(cpuInfo)); 67 | 68 | __cpuid(cpuInfo, 0x80000003); 69 | memcpy(cpuBrand + 16, cpuInfo, sizeof(cpuInfo)); 70 | 71 | __cpuid(cpuInfo, 0x80000004); 72 | memcpy(cpuBrand + 32, cpuInfo, sizeof(cpuInfo)); 73 | 74 | QString result(cpuBrand); 75 | 76 | return result.trimmed(); 77 | } 78 | 79 | CpuUtils::~CpuUtils() 80 | { 81 | if (hCounter) PdhRemoveCounter(hCounter); 82 | if (hQuery) PdhCloseQuery(hQuery); 83 | } 84 | -------------------------------------------------------------------------------- /cpuutils.h: -------------------------------------------------------------------------------- 1 | /* 2 | * OpenSpeedy - Open Source Game Speed Controller 3 | * Copyright (C) 2025 Game1024 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see <https://www.gnu.org/licenses/>. 17 | */ 18 | #ifndef CPUUTILS_H 19 | #define CPUUTILS_H 20 | 21 | #include <windows.h> 22 | #include <QString> 23 | #include <pdh.h> 24 | 25 | class CpuUtils 26 | { 27 | private: 28 | PDH_HQUERY hQuery = NULL; 29 | PDH_HCOUNTER hCounter = NULL; 30 | bool initialized = false; 31 | 32 | public: 33 | CpuUtils(); 34 | 35 | ~CpuUtils(); 36 | 37 | bool init(); 38 | 39 | double getUsage(); 40 | 41 | QString getModel(); 42 | }; 43 | 44 | #endif // CPUUTILS_H 45 | -------------------------------------------------------------------------------- /docs/README_cn.md: -------------------------------------------------------------------------------- 1 | <h1 align="center"> OpenSpeedy </h1> 2 | 3 | 4 | <p align="center"> 5 | <img style="margin:0 auto" width=100 height=100 src="https://github.com/user-attachments/assets/bdbe4a60-7692-4e9c-9df4-ad1711337c57"> 6 | </img> 7 | </p> 8 | 9 | <p align="center"> 10 | OpenSpeedy 是一款开源免费的游戏变速工具,让你的游戏突破帧率限制,提供更流畅丝滑的游戏加速体验。 11 | </p> 12 | 13 | <p align="center"> 14 | <img src="https://api.visitorbadge.io/api/visitors?path=game1024.openspeedy&countColor=%234ecdc4"> 15 | <br/> 16 | 17 | <a href="https://github.com/game1024/OpenSpeedy/stargazers"> 18 | <img src="https://img.shields.io/github/stars/game1024/OpenSpeedy?style=for-the-badge&color=yellow" alt="GitHub Stars"> 19 | </a> 20 | 21 | <img src="https://img.shields.io/github/forks/game1024/OpenSpeedy?style=for-the-badge&color=8a2be2" alt="GitHub Forks"> 22 | 23 | <a href="https://github.com/game1024/OpenSpeedy/issues"> 24 | <img src="https://img.shields.io/github/issues-raw/game1024/OpenSpeedy?style=for-the-badge&label=Issues&color=orange" alt="Github Issues"> 25 | </a> 26 | <br/> 27 | 28 | <a href="https://github.com/game1024/OpenSpeedy/releases"> 29 | <img src="https://img.shields.io/github/downloads/game1024/OpenSpeedy/total?style=for-the-badge" alt="Downloads"> 30 | </a> 31 | <a href="https://github.com/game1024/OpenSpeedy/releases"> 32 | <img src="https://img.shields.io/github/v/release/game1024/OpenSpeedy?style=for-the-badge&color=brightgreen" alt="Version"> 33 | </a> 34 | <a href="https://github.com/game1024/OpenSpeedy/actions"> 35 | <img src="https://img.shields.io/github/actions/workflow/status/game1024/OpenSpeedy/ci.yml?style=for-the-badge" alt="Github Action"> 36 | </a> 37 | <a href="https://github.com/game1024/OpenSpeedy"> 38 | <img src="https://img.shields.io/badge/Platform-Windows-lightblue?style=for-the-badge" alt="Platform"> 39 | </a> 40 | <br/> 41 | 42 | <a href="https://github.com/game1024/OpenSpeedy/commits"> 43 | <img src="https://img.shields.io/github/commit-activity/m/game1024/OpenSpeedy?style=for-the-badge" alt="提交活跃度"> 44 | </a> 45 | <img src="https://img.shields.io/badge/language-C/C++-blue?style=for-the-badge"> 46 | <img src="https://img.shields.io/badge/License-GPLv3-green.svg?style=for-the-badge"> 47 | <br/> 48 | 49 | <a href="https://hellogithub.com/repository/975f473c56ad4369a1c30ac9aa5819e0" target="_blank"> 50 | <img src="https://abroad.hellogithub.com/v1/widgets/recommend.svg?rid=975f473c56ad4369a1c30ac9aa5819e0&claim_uid=kmUCncHJr9SpNV7&theme=neutral" alt="Featured|HelloGitHub" style="width: 250px; height: 54px;" width="250" height="54" /> 51 | </a> 52 | </p> 53 | 54 | <p align="center"> 55 | <a href="https://github.com/game1024/OpenSpeedy/blob/master/docs/README_cn.md"> 56 | 简体中文 57 | </a> 58 | · 59 | <a href="https://github.com/game1024/OpenSpeedy/blob/master/docs/README_ja.md"> 60 | 日本語 61 | </a> 62 | · 63 | <a href="https://github.com/game1024/OpenSpeedy?tab=readme-ov-file#-openspeedy-"> 64 | English 65 | </a> 66 | </p> 67 | 68 | 69 | # 🚀 特性 70 | - 完全免费且开源 71 | - 简单易用的界面 72 | - 可自定义变速倍率 73 | - 对多种游戏引擎兼容性良好 74 | - 低系统资源占用 75 | - 同时可以加速x86和x64平台进程 76 | - 无内核侵入性,Ring3层Hook,不破坏系统内核 77 | 78 | 79 | 80 | 81 | 82 | # 💾 安装 83 | 📦 **方式1: Winget** 84 | 85 | ``` powershell 86 | # 安装命令如下 87 | winget install openspeedy 88 | 89 | # 打开一个新的终端,运行openspeedy 90 | openspeedy 91 | ``` 92 | 93 | 📥 **方式2: 手动下载** 94 | 95 | 访问 [安装页面](https://github.com/game1024/OpenSpeedy/releases) 下载最新版本 96 | 97 | 98 | # 💻 操作系统要求 99 | - OS: Windows10 以上 100 | - 平台:x86(32位) 和 x64 (64位) 101 | 102 | 103 | # 📝 使用说明 104 | 1. 启动 OpenSpeedy 105 | 2. 运行需要变速的目标游戏 106 | <img src="https://github.com/user-attachments/assets/648e721d-9c3a-4d82-954c-19b16355d084" width="50%"> 107 | 108 | 3. 勾选游戏进程,在 OpenSpeedy 界面中调整速度倍率 109 | <img src="https://github.com/user-attachments/assets/9469aae9-8be0-4e40-884d-1fbea3206e73" width="50%"> 110 | 111 | 4. 即刻生效,对比效果如下 112 | 113 | <video src="https://github.com/user-attachments/assets/74471b1f-7f95-4de8-b5aa-7edc85c9d5f0" width="70%"></video> 114 | 115 | # 🔧 技术原理 116 | OpenSpeedy 通过 Hook 以下 Windows 系统时间函数来实现游戏速度调整: 117 | 118 | |函数名 | 所属库 | 功能 | 119 | |--------|----------|------------------| 120 | |Sleep|user32.dll|线程休眠| 121 | |SetTimer|user32.dll|创建基于消息的计时器| 122 | |timeGetTime | winmm.dll | 获取系统启动后经过的毫秒数 | 123 | |GetTickCount | kernel32.dll | 获取系统启动后经过的毫秒数 | 124 | |GetTickCount64 | kernel32.dll | 获取系统启动后经过的毫秒数(64位) | 125 | |QueryPerformanceCounter | kernel32.dll | 高精度性能计数器 | 126 | |GetSystemTimeAsFileTime | kernel32.dll | 获取系统时间 | 127 | |GetSystemTimePreciseAsFileTime | kernel32.dll | 获取高精度系统时间 | 128 | 129 | # ⚠️ 注意事项 130 | - 本工具仅供学习和研究使用 131 | - 部分在线游戏可能有反作弊系统,使用本工具可能导致账号被封禁 132 | - 过度加速可能导致游戏物理引擎异常或崩溃 133 | - 不建议在竞技类在线游戏中使用 134 | - 开源产品不带数字签名,可能被杀毒软件误报 135 | 136 | # 🔄 反馈 137 | 如果在使用过程中遇到任何问题,欢迎通过以下方式反馈: 138 | - [FAQ](https://github.com/game1024/OpenSpeedy/wiki#faq) - 先查看wiki定位常见问题 139 | - [GitHub Issues](https://github.com/game1024/OpenSpeedy/issues) - 提交问题报告, 网盘类问题请勿提issue, 我不支持, 谢谢合作~🙏 140 | - 微信群聊(x盘类问题不要进群,谢谢合作~🙏) 141 | <img width="30%" src="https://github.com/user-attachments/assets/d77cb35d-6c92-4480-89c9-40f124c4df08"> 142 | 143 | 144 | # 🎁 赞助 145 | 如果觉得OpenSpeedy项目对你有帮助,可以请我喝杯咖啡~☕️ 146 | 147 | 365VPN使用专线连接全球,体验至高10Gbps/s网速。 下载立刻开始免费冲浪🏄:https://ref.365tz87989.com/?r=RWQVZD 148 | 149 | # 📜 开源协议 150 | OpenSpeedy 遵循 GNU v3 许可证。 151 | 152 | # 🙏 鸣谢 153 | OpenSpeedy使用到以下项目的源码,感谢开源社区的力量,如果OpenSpeedy对你有帮助,欢迎Star! 154 | - [minhook](https://github.com/TsudaKageyu/minhook): 用于API Hook 155 | - [Qt](https://www.qt.io/): GUI 156 | 157 | 免责声明: OpenSpeedy 仅用于教育和研究目的。用户应自行承担使用本软件的所有风险和责任。作者不对因使用本软件导致的任何损失或法律责任负责。 158 | 159 | <p align="center"> 160 | <img src="https://api.star-history.com/svg?repos=game1024/openspeedy&type=Date" Alt="Star History Chart"> 161 | </p> 162 | -------------------------------------------------------------------------------- /docs/README_ja.md: -------------------------------------------------------------------------------- 1 | <h1 align="center"> OpenSpeedy </h1> 2 | 3 | <p align="center"> 4 | <img style="margin:0 auto" width=100 height=100 src="https://github.com/user-attachments/assets/bdbe4a60-7692-4e9c-9df4-ad1711337c57"> 5 | </img> 6 | </p> 7 | 8 | <p align="center"> 9 | OpenSpeedyは、フレームレート制限を突破し、よりスムーズで快適なゲーム加速体験を提供する、オープンソースかつ無料のゲーム速度調整ツールです。 10 | </p> 11 | 12 | <p align="center"> 13 | <img src="https://api.visitorbadge.io/api/visitors?path=game1024.openspeedy&countColor=%234ecdc4"> 14 | <br/> 15 | 16 | <a href="https://github.com/game1024/OpenSpeedy/stargazers"> 17 | <img src="https://img.shields.io/github/stars/game1024/OpenSpeedy?style=for-the-badge&color=yellow" alt="GitHub Stars"> 18 | </a> 19 | 20 | <img src="https://img.shields.io/github/forks/game1024/OpenSpeedy?style=for-the-badge&color=8a2be2" alt="GitHub Forks"> 21 | 22 | <a href="https://github.com/game1024/OpenSpeedy/issues"> 23 | <img src="https://img.shields.io/github/issues-raw/game1024/OpenSpeedy?style=for-the-badge&label=Issues&color=orange" alt="Github Issues"> 24 | </a> 25 | <br/> 26 | 27 | <a href="https://github.com/game1024/OpenSpeedy/releases"> 28 | <img src="https://img.shields.io/github/downloads/game1024/OpenSpeedy/total?style=for-the-badge" alt="Downloads"> 29 | </a> 30 | <a href="https://github.com/game1024/OpenSpeedy/releases"> 31 | <img src="https://img.shields.io/github/v/release/game1024/OpenSpeedy?style=for-the-badge&color=brightgreen" alt="Version"> 32 | </a> 33 | <a href="https://github.com/game1024/OpenSpeedy/actions"> 34 | <img src="https://img.shields.io/github/actions/workflow/status/game1024/OpenSpeedy/ci.yml?style=for-the-badge" alt="Github Action"> 35 | </a> 36 | <a href="https://github.com/game1024/OpenSpeedy"> 37 | <img src="https://img.shields.io/badge/Platform-Windows-lightblue?style=for-the-badge" alt="Platform"> 38 | </a> 39 | <br/> 40 | 41 | <a href="https://github.com/game1024/OpenSpeedy/commits"> 42 | <img src="https://img.shields.io/github/commit-activity/m/game1024/OpenSpeedy?style=for-the-badge" alt="コミットアクティビティ"> 43 | </a> 44 | <img src="https://img.shields.io/badge/language-C/C++-blue?style=for-the-badge"> 45 | <img src="https://img.shields.io/badge/License-GPLv3-green.svg?style=for-the-badge"> 46 | <br/> 47 | </p> 48 | 49 | <p align="center"> 50 | <a href="https://github.com/game1024/OpenSpeedy/blob/master/docs/README_cn.md"> 51 | 简体中文 52 | </a> 53 | · 54 | <a href="https://github.com/game1024/OpenSpeedy/blob/master/docs/README_ja.md"> 55 | 日本語 56 | </a> 57 | · 58 | <a href="https://github.com/game1024/OpenSpeedy?tab=readme-ov-file#-openspeedy-"> 59 | English 60 | </a> 61 | </p> 62 | 63 | # 🚀 特徴 64 | - 完全無料・オープンソース 65 | - シンプルで使いやすいインターフェース 66 | - 速度倍率をカスタマイズ可能 67 | - 様々なゲームエンジンとの高い互換性 68 | - 低いシステムリソース消費 69 | - x86およびx64プラットフォームのプロセスを同時に加速可能 70 | - カーネル非侵入型、Ring3レベルのHook、システムカーネルを破壊しない 71 | 72 | # 📥 インストール 73 | 1. [インストールページ](https://github.com/game1024/OpenSpeedy/releases)にアクセスし、最新版をダウンロードしてください 74 | 2. ダウンロードしたファイルを任意の場所に解凍してください 75 | 3. インストール不要、「OpenSpeedy.exe」を直接実行するだけで利用できます 76 | 77 | # 💻 動作環境 78 | - OS: Windows10以降 79 | - プラットフォーム:x86(32ビット)およびx64(64ビット) 80 | 81 | # 📝 使い方 82 | 1. OpenSpeedyを起動する 83 | 2. 速度を変更したいゲームを起動する 84 | <img src="https://github.com/user-attachments/assets/648e721d-9c3a-4d82-954c-19b16355d084" width="50%"> 85 | 86 | 3. ゲームプロセスを選択し、OpenSpeedyの画面で速度倍率を調整する 87 | <img src="https://github.com/user-attachments/assets/9469aae9-8be0-4e40-884d-1fbea3206e73" width="50%"> 88 | 89 | 4. すぐに効果が反映されます。下記の比較動画をご覧ください 90 | 91 | <video src="https://github.com/user-attachments/assets/74471b1f-7f95-4de8-b5aa-7edc85c9d5f0" width="70%"></video> 92 | 93 | # 🔧 技術原理 94 | OpenSpeedyは、以下のWindowsシステム時間関数をHookすることで、ゲーム速度を調整しています: 95 | 96 | | 関数名 | 所属ライブラリ | 機能 | 97 | |--------|--------|------------------| 98 | | Sleep | user32.dll | スレッドのスリープ | 99 | | SetTimer | user32.dll | メッセージベースのタイマー作成 | 100 | | timeGetTime | winmm.dll | システム起動後の経過ミリ秒数取得 | 101 | | GetTickCount | kernel32.dll | システム起動後の経過ミリ秒数取得 | 102 | | GetTickCount64 | kernel32.dll | システム起動後の経過ミリ秒数取得 (64ビット) | 103 | | QueryPerformanceCounter | kernel32.dll | 高精度パフォーマンスカウンタ | 104 | | GetSystemTimeAsFileTime | kernel32.dll | システム時刻の取得 | 105 | | GetSystemTimePreciseAsFileTime | kernel32.dll | 高精度なシステム時刻の取得 | 106 | 107 | # ⚠️ 注意事項 108 | - 本ツールは学習および研究用途のみを目的としています 109 | - 一部オンラインゲームにはアンチチートシステムが搭載されています。本ツールの使用によりアカウントがBANされる場合があります 110 | - 過度な加速は、ゲームの物理エンジン異常やクラッシュの原因となる場合があります 111 | - 対戦型オンラインゲームでの利用は推奨しません 112 | - オープンソース製品のためデジタル署名は付与しておらず、ウイルス対策ソフトによる誤検出の可能性があります 113 | 114 | # 🔄 フィードバック 115 | 使用中に問題が発生した場合は、以下の方法でご連絡ください: 116 | - [FAQ](https://github.com/game1024/OpenSpeedy/wiki#faq) - まずはWikiを確認して問題の場所を特定できます 117 | - [GitHub Issues](https://github.com/game1024/OpenSpeedy/issues) - 不具合報告 118 | - WeChat Group 119 | <img width="30%" src="https://github.com/user-attachments/assets/d77cb35d-6c92-4480-89c9-40f124c4df08"> 120 | 121 | # 🎁 スポンサー 122 | もしOpenSpeedyプロジェクトが役に立ったと感じたら、コーヒーをご馳走していただけると嬉しいです~ ☕️ 123 | 124 | 365VPNは専用回線を利用して世界中を接続し、最大10Gbpsの速度を提供します。今すぐダウンロードして無料でサーフィンを始めましょう🏄: https://ref.365tz87989.com/?r=RWQVZD 125 | 126 | # 📜 ライセンス 127 | OpenSpeedyはGNU v3ライセンスに従っています。 128 | 129 | # 🙏 クレジット 130 | OpenSpeedyは以下のプロジェクトのソースコードを使用しています。オープンソースコミュニティに感謝します。OpenSpeedyが役立った場合はStarをお願いします! 131 | - [minhook](https://github.com/TsudaKageyu/minhook): APIフック用 132 | - [Qt](https://www.qt.io/): GUI 133 | 134 | 免責事項: OpenSpeedyは教育及び研究目的のみでご利用ください。本ソフトウェアの使用に伴うすべてのリスクと責任は利用者にあります。著者は本ソフトウェアの使用によるいかなる損害や法的責任も一切負いません。 135 | 136 | <p align="center"> 137 | <img src="https://api.star-history.com/svg?repos=game1024/openspeedy&type=Date" Alt="Star History Chart"> 138 | </p> 139 | -------------------------------------------------------------------------------- /icons.rc: -------------------------------------------------------------------------------- 1 | IDI_APP_ICON ICON DISCARDABLE "images/icon_64.ico" 2 | -------------------------------------------------------------------------------- /images/icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/game1024/OpenSpeedy/b54416000c2bea56654a9f628f2641cd55038780/images/icon.ico -------------------------------------------------------------------------------- /images/icon_16.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/game1024/OpenSpeedy/b54416000c2bea56654a9f628f2641cd55038780/images/icon_16.ico -------------------------------------------------------------------------------- /images/icon_32.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/game1024/OpenSpeedy/b54416000c2bea56654a9f628f2641cd55038780/images/icon_32.ico -------------------------------------------------------------------------------- /images/icon_64.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/game1024/OpenSpeedy/b54416000c2bea56654a9f628f2641cd55038780/images/icon_64.ico -------------------------------------------------------------------------------- /images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/game1024/OpenSpeedy/b54416000c2bea56654a9f628f2641cd55038780/images/logo.png -------------------------------------------------------------------------------- /installer/config/config.xml: -------------------------------------------------------------------------------- 1 | <?xml version="1.0" encoding="UTF-8"?> 2 | <Installer> 3 | <Name>OpenSpeedy</Name> 4 | <Version>1.0.0</Version> 5 | <Title>OpenSpeedy</Title> 6 | <Publisher>Game1024</Publisher> 7 | <StartMenuDir>OpenSpeedy</StartMenuDir> 8 | <TargetDir>@HomeDir@/OpenSpeedy</TargetDir> 9 | <WizardStyle>Modern</WizardStyle> 10 | <AllowNonAsciiCharacters>true</AllowNonAsciiCharacters> 11 | </Installer> -------------------------------------------------------------------------------- /installer/create_installer.bat: -------------------------------------------------------------------------------- 1 | set QTIFWDIR=D:\Qt\Tools\QtInstallerFramework\4.9\bin 2 | %QTIFWDIR%\binarycreator.exe -c %~dp0config\config.xml -p packages OpenSpeedy-installer.exe 3 | -------------------------------------------------------------------------------- /installer/packages/com.openspeedy.app/data/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/game1024/OpenSpeedy/b54416000c2bea56654a9f628f2641cd55038780/installer/packages/com.openspeedy.app/data/.gitkeep -------------------------------------------------------------------------------- /installer/packages/com.openspeedy.app/meta/installscript.qs: -------------------------------------------------------------------------------- 1 | function Component() 2 | { 3 | } 4 | 5 | Component.prototype.createOperations = function() 6 | { 7 | try 8 | { 9 | // call the base create operations function 10 | component.createOperations(); 11 | 12 | component.addOperation("CreateShortcut", "@TargetDir@/OpenSpeedy.exe", "@DesktopDir@/OpenSpeedy.lnk"); 13 | } 14 | catch (e) 15 | { 16 | console.log(e); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /installer/packages/com.openspeedy.app/meta/package.xml: -------------------------------------------------------------------------------- 1 | <?xml version="1.0" encoding="UTF-8"?> 2 | <Package> 3 | <DisplayName>OpenSpeedy Application</DisplayName> 4 | <Description>OpenSpeedy</Description> 5 | <Version>1.0.0</Version> 6 | <ReleaseDate>2025-06-14</ReleaseDate> 7 | <Default>true</Default> 8 | <Essential>true</Essential> 9 | </Package> -------------------------------------------------------------------------------- /main.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * OpenSpeedy - Open Source Game Speed Controller 3 | * Copyright (C) 2025 Game1024 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see <https://www.gnu.org/licenses/>. 17 | */ 18 | #include "mainwindow.h" 19 | #include "windbg.h" 20 | #include <QApplication> 21 | #include <QCommandLineParser> 22 | #include <QLocalServer> 23 | #include <QLocalSocket> 24 | #include <QLocale> 25 | #include <QTranslator> 26 | #include <ShellScalingApi.h> 27 | int 28 | main(int argc, char* argv[]) 29 | { 30 | SetUnhandledExceptionFilter(createMiniDump); 31 | SetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2); 32 | QApplication::setAttribute(Qt::AA_EnableHighDpiScaling); 33 | QApplication::setAttribute(Qt::AA_UseHighDpiPixmaps); 34 | QApplication::setAttribute(Qt::AA_UseSoftwareOpenGL); 35 | QApplication a(argc, argv); 36 | winutils::enableAllPrivilege(); 37 | 38 | // 检查是否已有实例在运行 39 | QString unique = "OpenSpeedy"; 40 | QLocalSocket socket; 41 | socket.connectToServer(unique); 42 | if (socket.waitForConnected(500)) 43 | { 44 | socket.close(); 45 | return -1; 46 | } 47 | 48 | // 使用资源文件中的图标 49 | QIcon appIcon; 50 | appIcon.addFile(":/icons/images/icon_16.ico", QSize(16, 16)); 51 | appIcon.addFile(":/icons/images/icon_32.ico", QSize(32, 32)); 52 | appIcon.addFile(":/icons/images/icon_64.ico", QSize(64, 64)); 53 | a.setWindowIcon(appIcon); 54 | 55 | QSettings settings = 56 | QSettings(QCoreApplication::applicationDirPath() + "/config.ini", 57 | QSettings::IniFormat); 58 | 59 | QTranslator translator; 60 | const QString baseName = 61 | "OpenSpeedy_" + 62 | settings.value(CONFIG_LANGUAGE, QLocale().system().name()).toString(); 63 | 64 | if (translator.load(":/i18n/translations/" + baseName)) 65 | { 66 | a.installTranslator(&translator); 67 | } 68 | 69 | // 解析命令行参数 70 | QCommandLineParser parser; 71 | parser.setApplicationDescription("OpenSpeedy"); 72 | QCommandLineOption minimizeOption( 73 | QStringList() << "m" << "minimize-to-tray", "启动时最小化到托盘"); 74 | parser.addOption(minimizeOption); 75 | parser.process(a); 76 | 77 | MainWindow w; 78 | w.resize(1024, 768); 79 | 80 | if (parser.isSet(minimizeOption)) 81 | { 82 | w.hide(); 83 | } 84 | else 85 | { 86 | w.show(); 87 | } 88 | 89 | // 创建并启动本地服务器 90 | QLocalServer server; 91 | QLocalServer::removeServer(unique); 92 | server.listen(unique); 93 | // 当用户尝试再运行一个进程时,将窗口显示到最前台 94 | QObject::connect(&server, 95 | &QLocalServer::newConnection, 96 | [&] 97 | { 98 | w.show(); 99 | w.raise(); 100 | w.showNormal(); 101 | w.activateWindow(); 102 | }); 103 | return a.exec(); 104 | } 105 | -------------------------------------------------------------------------------- /mainwindow.h: -------------------------------------------------------------------------------- 1 | /* 2 | * OpenSpeedy - Open Source Game Speed Controller 3 | * Copyright (C) 2025 Game1024 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see <https://www.gnu.org/licenses/>. 17 | */ 18 | #ifndef MAINWINDOW_H 19 | #define MAINWINDOW_H 20 | #include "aboutdialog.h" 21 | #include "config.h" 22 | #include "cpuutils.h" 23 | #include "memutils.h" 24 | #include "preferencedialog.h" 25 | #include "processmonitor.h" 26 | #include "winutils.h" 27 | #include <QAbstractNativeEventFilter> 28 | #include <QActionGroup> 29 | #include <QMainWindow> 30 | #include <QSettings> 31 | #include <QSystemTrayIcon> 32 | #define CONFIG_SLIDERVALUE_KEY "MainWindow/SliderValue" 33 | 34 | QT_BEGIN_NAMESPACE 35 | namespace Ui 36 | { 37 | class MainWindow; 38 | } 39 | QT_END_NAMESPACE 40 | 41 | class MainWindow 42 | : public QMainWindow 43 | , public QAbstractNativeEventFilter 44 | { 45 | Q_OBJECT 46 | 47 | public: 48 | MainWindow(QWidget* parent = nullptr); 49 | ~MainWindow(); 50 | 51 | private slots: 52 | void recreate(); 53 | 54 | void refresh(); 55 | 56 | void on_sliderCtrl_valueChanged(int value); 57 | 58 | void on_sliderInputSpinBox_editingFinished(); 59 | 60 | void on_processNameFilter_textChanged(const QString& text); 61 | 62 | void iconActivated(QSystemTrayIcon::ActivationReason reason); 63 | 64 | void recreateTray(); 65 | 66 | void on_sliderLabel_clicked(); 67 | 68 | void on_autoStartCheckBox_stateChanged(int arg1); 69 | 70 | private: 71 | Ui::MainWindow* ui; 72 | AboutDialog* m_aboutDlg; 73 | PreferenceDialog* m_preferenceDlg; 74 | 75 | QThread* m_thread; 76 | ProcessMonitor* m_processMonitor; 77 | QTimer* m_timer; 78 | 79 | QSystemTrayIcon* trayIcon; 80 | QMenu* trayMenu; 81 | QAction* showAction; 82 | QAction* hideAction; 83 | QAction* quitAction; 84 | 85 | CpuUtils* m_cpu; 86 | MemUtils* m_mem; 87 | 88 | QSettings* m_settings; 89 | 90 | int m_back; 91 | 92 | QActionGroup* m_languageGroup; 93 | 94 | void init(); 95 | 96 | void createTray(); 97 | 98 | double speedFactor(int sliderValue); 99 | 100 | int sliderValue(double speedFactor); 101 | 102 | protected: 103 | void closeEvent(QCloseEvent* event) override; 104 | 105 | bool nativeEventFilter(const QByteArray& eventType, 106 | void* message, 107 | long* result) override; 108 | }; 109 | #endif // MAINWINDOW_H 110 | -------------------------------------------------------------------------------- /memutils.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * OpenSpeedy - Open Source Game Speed Controller 3 | * Copyright (C) 2025 Game1024 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see <https://www.gnu.org/licenses/>. 17 | */ 18 | #include "memutils.h" 19 | 20 | MemUtils::MemUtils() 21 | { 22 | } 23 | 24 | bool MemUtils::init() 25 | { 26 | if (PdhOpenQuery(NULL, NULL, &hQuery) != ERROR_SUCCESS) return false; 27 | 28 | if (PdhAddEnglishCounter(hQuery, 29 | L"\\Memory\\Available Bytes", 30 | NULL, 31 | &hCounter) != ERROR_SUCCESS) 32 | { 33 | PdhCloseQuery(hQuery); 34 | return false; 35 | } 36 | 37 | PdhCollectQueryData(hQuery); 38 | initialized = true; 39 | return true; 40 | } 41 | 42 | double MemUtils::getTotal() 43 | { 44 | MEMORYSTATUSEX memInfo; 45 | memInfo.dwLength = sizeof(MEMORYSTATUSEX); 46 | GlobalMemoryStatusEx(&memInfo); 47 | return memInfo.ullTotalPhys / (1024.0 * 1024.0 * 1024.0); 48 | } 49 | 50 | double MemUtils::getUsage() 51 | { 52 | if (!initialized) return -1; 53 | 54 | if (PdhCollectQueryData(hQuery) != ERROR_SUCCESS) return -1; 55 | 56 | PDH_FMT_COUNTERVALUE available; 57 | if (PdhGetFormattedCounterValue(hCounter, 58 | PDH_FMT_DOUBLE, 59 | NULL, 60 | &available) != ERROR_SUCCESS) 61 | return -1; 62 | 63 | double totalMemory = getTotal() * 1024 * 1024 * 1024; 64 | double usageMemory = totalMemory - available.doubleValue; 65 | 66 | return usageMemory / (1024.0 * 1024.0 * 1024.0); 67 | } 68 | -------------------------------------------------------------------------------- /memutils.h: -------------------------------------------------------------------------------- 1 | /* 2 | * OpenSpeedy - Open Source Game Speed Controller 3 | * Copyright (C) 2025 Game1024 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see <https://www.gnu.org/licenses/>. 17 | */ 18 | #ifndef MEMUTILS_H 19 | #define MEMUTILS_H 20 | #include <windows.h> 21 | #include <pdh.h> 22 | 23 | class MemUtils 24 | { 25 | private: 26 | PDH_HQUERY hQuery = NULL; 27 | PDH_HCOUNTER hCounter = NULL; 28 | bool initialized = false; 29 | 30 | public: 31 | MemUtils(); 32 | 33 | bool init(); 34 | 35 | double getTotal(); 36 | 37 | double getUsage(); 38 | }; 39 | 40 | #endif // MEMUTILS_H 41 | -------------------------------------------------------------------------------- /preferencedialog.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * OpenSpeedy - Open Source Game Speed Controller 3 | * Copyright (C) 2025 Game1024 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see <https://www.gnu.org/licenses/>. 17 | */ 18 | #include "preferencedialog.h" 19 | #include "ui_preferencedialog.h" 20 | #include <QDebug> 21 | #include <QPushButton> 22 | #include <QScreen> 23 | PreferenceDialog::PreferenceDialog(HWND hMainWindow, 24 | QSettings* settings, 25 | QLabel* increaseSpeedLabel, 26 | QLabel* decreaseSpeedLabel, 27 | QLabel* resetSpeedLabel, 28 | QWidget* parent) 29 | : QDialog(parent) 30 | , ui(new Ui::PreferenceDialog) 31 | , m_settings(settings) 32 | , m_increaseSpeedLabel(increaseSpeedLabel) 33 | , m_decreaseSpeedLabel(decreaseSpeedLabel) 34 | , m_resetSpeedLabel(resetSpeedLabel) 35 | , m_mainwindow(hMainWindow) 36 | { 37 | ui->setupUi(this); 38 | setWindowFlags(Qt::Dialog | Qt::WindowTitleHint | Qt::CustomizeWindowHint); 39 | 40 | ui->buttonBox->button(QDialogButtonBox::Ok)->setText(tr("确认")); 41 | ui->buttonBox->button(QDialogButtonBox::Cancel)->setText(tr("取消")); 42 | 43 | loadShortcut( 44 | HOTKEY_INCREASE_SPEED, CONFIG_HOTKEY_SPEEDUP, DEFAULT_HOTKEY_SPEEDUP); 45 | loadShortcut( 46 | HOTKEY_DECREASE_SPEED, CONFIG_HOTKEY_SPEEDDOWN, DEFAULT_HOTKEY_SPEEDDOWN); 47 | loadShortcut( 48 | HOTKEY_RESET_SPEED, CONFIG_HOTKEY_RESETSPEED, DEFAULT_HOTKEY_RERSETSPEED); 49 | loadShortcut(HOTKEY_SHIFT1, CONFIG_HOTKEY_SHIFT1, DEFAULT_HOTKEY_SHIFT1); 50 | loadShortcut(HOTKEY_SHIFT2, CONFIG_HOTKEY_SHIFT2, DEFAULT_HOTKEY_SHIFT2); 51 | loadShortcut(HOTKEY_SHIFT3, CONFIG_HOTKEY_SHIFT3, DEFAULT_HOTKEY_SHIFT3); 52 | loadShortcut(HOTKEY_SHIFT4, CONFIG_HOTKEY_SHIFT4, DEFAULT_HOTKEY_SHIFT4); 53 | loadShortcut(HOTKEY_SHIFT5, CONFIG_HOTKEY_SHIFT5, DEFAULT_HOTKEY_SHIFT5); 54 | 55 | m_shift1Value = 56 | m_settings->value(CONFIG_SHIFT1_VALUE, DEFAULT_SHIFT1_VALUE).toDouble(); 57 | m_shift2Value = 58 | m_settings->value(CONFIG_SHIFT2_VALUE, DEFAULT_SHIFT2_VALUE).toDouble(); 59 | m_shift3Value = 60 | m_settings->value(CONFIG_SHIFT3_VALUE, DEFAULT_SHIFT3_VALUE).toDouble(); 61 | m_shift4Value = 62 | m_settings->value(CONFIG_SHIFT4_VALUE, DEFAULT_SHIFT4_VALUE).toDouble(); 63 | m_shift5Value = 64 | m_settings->value(CONFIG_SHIFT5_VALUE, DEFAULT_SHIFT5_VALUE).toDouble(); 65 | 66 | m_increaseStep = 67 | m_settings->value(CONFIG_INCREASE_STEP, DEFAULT_INCREASE_STEP).toInt(); 68 | m_decreaseStep = 69 | m_settings->value(CONFIG_DECREASE_STEP, DEFAULT_DECREASE_STEP).toInt(); 70 | 71 | connect(QGuiApplication::primaryScreen(), 72 | &QScreen::logicalDotsPerInchChanged, 73 | this, 74 | &PreferenceDialog::recreate); 75 | redraw(); 76 | adjustSize(); 77 | setupGlobalHotkeys(); 78 | } 79 | 80 | PreferenceDialog::~PreferenceDialog() 81 | { 82 | unregisterGlobalHotkeys(); 83 | delete ui; 84 | } 85 | 86 | int 87 | PreferenceDialog::getIncreaseStep() 88 | { 89 | return m_increaseStep; 90 | } 91 | 92 | int 93 | PreferenceDialog::getDecreaseStep() 94 | { 95 | return m_decreaseStep; 96 | } 97 | 98 | double 99 | PreferenceDialog::getShift1() 100 | { 101 | return m_shift1Value; 102 | } 103 | 104 | double 105 | PreferenceDialog::getShift2() 106 | { 107 | return m_shift2Value; 108 | } 109 | 110 | double 111 | PreferenceDialog::getShift3() 112 | { 113 | return m_shift3Value; 114 | } 115 | 116 | double 117 | PreferenceDialog::getShift4() 118 | { 119 | return m_shift4Value; 120 | } 121 | 122 | double 123 | PreferenceDialog::getShift5() 124 | { 125 | return m_shift5Value; 126 | } 127 | 128 | void 129 | PreferenceDialog::show() 130 | { 131 | unregisterGlobalHotkeys(); 132 | QDialog::show(); 133 | } 134 | 135 | void 136 | PreferenceDialog::setupGlobalHotkeys() 137 | { 138 | for (auto it = m_shortcuts.begin(); it != m_shortcuts.end(); it++) 139 | { 140 | int id = it.key(); 141 | QtCombinedKey combined = it.value(); 142 | 143 | UINT vk = QSingleKeySequenceEdit::toVK(combined.key, combined.modifier); 144 | UINT modifier = QSingleKeySequenceEdit::toModifier(combined.modifier); 145 | RegisterHotKey(m_mainwindow, id, modifier, vk); 146 | } 147 | 148 | qDebug() << "全局快捷键已注册:"; 149 | } 150 | 151 | void 152 | PreferenceDialog::unregisterGlobalHotkeys() 153 | { 154 | for (auto it = m_shortcuts.begin(); it != m_shortcuts.end(); it++) 155 | { 156 | int id = it.key(); 157 | UnregisterHotKey(m_mainwindow, id); 158 | } 159 | qDebug() << "全局快捷键已注销"; 160 | } 161 | 162 | void 163 | PreferenceDialog::loadShortcut(int id, 164 | const QString& config, 165 | const QString& defaultValue) 166 | { 167 | m_shortcuts.insert(id, 168 | QSingleKeySequenceEdit::toQtCombinedKey( 169 | m_settings->value(config, defaultValue).toString())); 170 | } 171 | 172 | void 173 | PreferenceDialog::dump() 174 | { 175 | dumpShortcut(CONFIG_HOTKEY_SPEEDUP, 176 | ui->speedUpKeySequenceEdit->getKeyText()); 177 | dumpShortcut(CONFIG_HOTKEY_SPEEDDOWN, 178 | ui->speedDownKeySequenceEdit->getKeyText()); 179 | dumpShortcut(CONFIG_HOTKEY_RESETSPEED, 180 | ui->resetSpeedKeySequenceEdit->getKeyText()); 181 | 182 | dumpShortcut(CONFIG_HOTKEY_SHIFT1, ui->shift1KeySequenceEdit->getKeyText()); 183 | dumpShortcut(CONFIG_HOTKEY_SHIFT2, ui->shift2KeySequenceEdit->getKeyText()); 184 | dumpShortcut(CONFIG_HOTKEY_SHIFT3, ui->shift3KeySequenceEdit->getKeyText()); 185 | dumpShortcut(CONFIG_HOTKEY_SHIFT4, ui->shift4KeySequenceEdit->getKeyText()); 186 | dumpShortcut(CONFIG_HOTKEY_SHIFT5, ui->shift5KeySequenceEdit->getKeyText()); 187 | m_settings->setValue(CONFIG_INCREASE_STEP, 188 | ui->increaseStepSpinBox->value()); 189 | m_settings->setValue(CONFIG_DECREASE_STEP, 190 | ui->decreaseStepSpinBox->value()); 191 | m_settings->setValue(CONFIG_SHIFT1_VALUE, ui->shift1DoubleSpinBox->value()); 192 | m_settings->setValue(CONFIG_SHIFT2_VALUE, ui->shift2DoubleSpinBox->value()); 193 | m_settings->setValue(CONFIG_SHIFT3_VALUE, ui->shift3DoubleSpinBox->value()); 194 | m_settings->setValue(CONFIG_SHIFT4_VALUE, ui->shift4DoubleSpinBox->value()); 195 | m_settings->setValue(CONFIG_SHIFT5_VALUE, ui->shift5DoubleSpinBox->value()); 196 | m_settings->sync(); 197 | } 198 | 199 | void 200 | PreferenceDialog::dumpShortcut(const QString& config, const QString& keyText) 201 | { 202 | m_settings->setValue(config, keyText); 203 | } 204 | 205 | void 206 | PreferenceDialog::updateShortcut(int id, QSingleKeySequenceEdit* keyEdit) 207 | { 208 | m_shortcuts[id] = keyEdit->getQtCombinedKey(); 209 | } 210 | 211 | void 212 | PreferenceDialog::update() 213 | { 214 | updateShortcut(HOTKEY_INCREASE_SPEED, ui->speedUpKeySequenceEdit); 215 | updateShortcut(HOTKEY_DECREASE_SPEED, ui->speedDownKeySequenceEdit); 216 | updateShortcut(HOTKEY_RESET_SPEED, ui->resetSpeedKeySequenceEdit); 217 | updateShortcut(HOTKEY_SHIFT1, ui->shift1KeySequenceEdit); 218 | updateShortcut(HOTKEY_SHIFT2, ui->shift2KeySequenceEdit); 219 | updateShortcut(HOTKEY_SHIFT3, ui->shift3KeySequenceEdit); 220 | updateShortcut(HOTKEY_SHIFT4, ui->shift4KeySequenceEdit); 221 | updateShortcut(HOTKEY_SHIFT5, ui->shift5KeySequenceEdit); 222 | 223 | m_increaseStep = ui->increaseStepSpinBox->value(); 224 | m_decreaseStep = ui->decreaseStepSpinBox->value(); 225 | m_shift1Value = ui->shift1DoubleSpinBox->value(); 226 | m_shift2Value = ui->shift2DoubleSpinBox->value(); 227 | m_shift3Value = ui->shift3DoubleSpinBox->value(); 228 | m_shift4Value = ui->shift4DoubleSpinBox->value(); 229 | m_shift5Value = ui->shift5DoubleSpinBox->value(); 230 | } 231 | 232 | void 233 | PreferenceDialog::redrawSpinBox(QSpinBox* spinbox, int value) 234 | { 235 | spinbox->setValue(value); 236 | } 237 | 238 | void 239 | PreferenceDialog::redrawSpinBox(QDoubleSpinBox* spinbox, double value) 240 | { 241 | spinbox->setValue(value); 242 | } 243 | 244 | void 245 | PreferenceDialog::redrawKeyEdit(QSingleKeySequenceEdit* keyEdit, int id) 246 | { 247 | QtCombinedKey combinedKey = m_shortcuts[id]; 248 | keyEdit->setKeySequence(combinedKey.key | combinedKey.modifier); 249 | } 250 | 251 | void 252 | PreferenceDialog::redraw() 253 | { 254 | redrawKeyEdit(ui->speedUpKeySequenceEdit, HOTKEY_INCREASE_SPEED); 255 | redrawKeyEdit(ui->speedDownKeySequenceEdit, HOTKEY_DECREASE_SPEED); 256 | redrawKeyEdit(ui->resetSpeedKeySequenceEdit, HOTKEY_RESET_SPEED); 257 | redrawKeyEdit(ui->shift1KeySequenceEdit, HOTKEY_SHIFT1); 258 | redrawKeyEdit(ui->shift2KeySequenceEdit, HOTKEY_SHIFT2); 259 | redrawKeyEdit(ui->shift3KeySequenceEdit, HOTKEY_SHIFT3); 260 | redrawKeyEdit(ui->shift4KeySequenceEdit, HOTKEY_SHIFT4); 261 | redrawKeyEdit(ui->shift5KeySequenceEdit, HOTKEY_SHIFT5); 262 | 263 | redrawSpinBox(ui->increaseStepSpinBox, m_increaseStep); 264 | redrawSpinBox(ui->decreaseStepSpinBox, m_decreaseStep); 265 | redrawSpinBox(ui->shift1DoubleSpinBox, m_shift1Value); 266 | redrawSpinBox(ui->shift2DoubleSpinBox, m_shift2Value); 267 | redrawSpinBox(ui->shift3DoubleSpinBox, m_shift3Value); 268 | redrawSpinBox(ui->shift4DoubleSpinBox, m_shift4Value); 269 | redrawSpinBox(ui->shift5DoubleSpinBox, m_shift5Value); 270 | 271 | m_increaseSpeedLabel->setText( 272 | QString(tr("%1 增加速度")) 273 | .arg(QSingleKeySequenceEdit::wrapText( 274 | ui->speedUpKeySequenceEdit->getKeyText()))); 275 | 276 | m_decreaseSpeedLabel->setText( 277 | QString(tr("%1 减少速度")) 278 | .arg(QSingleKeySequenceEdit::wrapText( 279 | ui->speedDownKeySequenceEdit->getKeyText()))); 280 | 281 | m_resetSpeedLabel->setText( 282 | QString(tr("%1 重置速度")) 283 | .arg(QSingleKeySequenceEdit::wrapText( 284 | ui->resetSpeedKeySequenceEdit->getKeyText()))); 285 | 286 | adjustSize(); 287 | } 288 | 289 | void 290 | PreferenceDialog::on_buttonBox_accepted() 291 | { 292 | update(); 293 | setupGlobalHotkeys(); 294 | redraw(); 295 | dump(); 296 | } 297 | 298 | void 299 | PreferenceDialog::on_buttonBox_rejected() 300 | { 301 | redraw(); 302 | setupGlobalHotkeys(); 303 | } 304 | 305 | void 306 | PreferenceDialog::recreate() 307 | { 308 | layout()->invalidate(); 309 | layout()->activate(); 310 | adjustSize(); 311 | } 312 | -------------------------------------------------------------------------------- /preferencedialog.h: -------------------------------------------------------------------------------- 1 | /* 2 | * OpenSpeedy - Open Source Game Speed Controller 3 | * Copyright (C) 2025 Game1024 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see <https://www.gnu.org/licenses/>. 17 | */ 18 | #ifndef PREFERENCEDIALOG_H 19 | #define PREFERENCEDIALOG_H 20 | 21 | #include <windows.h> 22 | #include "config.h" 23 | #include "qsinglekeysequenceedit.h" 24 | #include <QDialog> 25 | #include <QDoubleSpinBox> 26 | #include <QLabel> 27 | #include <QMap> 28 | #include <QSettings> 29 | #include <QSpinBox> 30 | 31 | namespace Ui 32 | { 33 | class PreferenceDialog; 34 | } 35 | 36 | #define CONFIG_HOTKEY_SPEEDUP "Hotkey/SpeedUp" 37 | #define CONFIG_HOTKEY_SPEEDDOWN "Hotkey/SpeedDown" 38 | #define CONFIG_HOTKEY_RESETSPEED "Hotkey/ResetSpeed" 39 | #define CONFIG_HOTKEY_SHIFT1 "Hotkey/Shift1" 40 | #define CONFIG_HOTKEY_SHIFT2 "Hotkey/Shift2" 41 | #define CONFIG_HOTKEY_SHIFT3 "Hotkey/Shift3" 42 | #define CONFIG_HOTKEY_SHIFT4 "Hotkey/Shift4" 43 | #define CONFIG_HOTKEY_SHIFT5 "Hotkey/Shift5" 44 | 45 | #define CONFIG_SHIFT1_VALUE "Shift/Shift1Value" 46 | #define CONFIG_SHIFT2_VALUE "Shift/Shift2Value" 47 | #define CONFIG_SHIFT3_VALUE "Shift/Shift3Value" 48 | #define CONFIG_SHIFT4_VALUE "Shift/Shift4Value" 49 | #define CONFIG_SHIFT5_VALUE "Shift/Shift5Value" 50 | #define CONFIG_INCREASE_STEP "Shift/IncreaseStep" 51 | #define CONFIG_DECREASE_STEP "Shift/DecreaseStep" 52 | 53 | #define DEFAULT_SHIFT1_VALUE 10.0 54 | #define DEFAULT_SHIFT2_VALUE 20.0 55 | #define DEFAULT_SHIFT3_VALUE 30.0 56 | #define DEFAULT_SHIFT4_VALUE 40.0 57 | #define DEFAULT_SHIFT5_VALUE 50.0 58 | #define DEFAULT_INCREASE_STEP 1 59 | #define DEFAULT_DECREASE_STEP 1 60 | 61 | #define DEFAULT_HOTKEY_SPEEDUP "Ctrl+Alt+Up" 62 | #define DEFAULT_HOTKEY_SPEEDDOWN "Ctrl+Alt+Down" 63 | #define DEFAULT_HOTKEY_RERSETSPEED "Ctrl+Alt+0" 64 | #define DEFAULT_HOTKEY_SHIFT1 "Ctrl+Alt+1" 65 | #define DEFAULT_HOTKEY_SHIFT2 "Ctrl+Alt+2" 66 | #define DEFAULT_HOTKEY_SHIFT3 "Ctrl+Alt+3" 67 | #define DEFAULT_HOTKEY_SHIFT4 "Ctrl+Alt+4" 68 | #define DEFAULT_HOTKEY_SHIFT5 "Ctrl+Alt+5" 69 | 70 | class PreferenceDialog : public QDialog 71 | { 72 | Q_OBJECT 73 | 74 | public: 75 | explicit PreferenceDialog(HWND hMainWindow, 76 | QSettings* settings, 77 | QLabel* increaseSpeedLabel, 78 | QLabel* decreaseSpeedLabel, 79 | QLabel* resetSpeedLabel, 80 | QWidget* parent = nullptr); 81 | ~PreferenceDialog(); 82 | 83 | int getIncreaseStep(); 84 | 85 | int getDecreaseStep(); 86 | 87 | double getShift1(); 88 | 89 | double getShift2(); 90 | 91 | double getShift3(); 92 | 93 | double getShift4(); 94 | 95 | double getShift5(); 96 | 97 | public slots: 98 | void show(); 99 | 100 | private slots: 101 | void on_buttonBox_accepted(); 102 | 103 | void on_buttonBox_rejected(); 104 | 105 | void recreate(); 106 | 107 | private: 108 | void setupGlobalHotkeys(); 109 | 110 | void unregisterGlobalHotkeys(); 111 | 112 | void loadShortcut(int id, 113 | const QString& config, 114 | const QString& defaultValue); 115 | 116 | void dumpShortcut(const QString& config, const QString& keyText); 117 | void dump(); 118 | 119 | void updateShortcut(int id, QSingleKeySequenceEdit* keyEdit); 120 | void update(); 121 | 122 | void redrawSpinBox(QSpinBox* spinbox, int value); 123 | void redrawSpinBox(QDoubleSpinBox* spinbox, double value); 124 | void redrawKeyEdit(QSingleKeySequenceEdit* keyEdit, int id); 125 | void redraw(); 126 | 127 | Ui::PreferenceDialog* ui; 128 | 129 | QSettings* m_settings; 130 | 131 | QLabel* m_increaseSpeedLabel; 132 | QLabel* m_decreaseSpeedLabel; 133 | QLabel* m_resetSpeedLabel; 134 | 135 | QMap<int, QtCombinedKey> m_shortcuts; 136 | 137 | double m_shift1Value; 138 | double m_shift2Value; 139 | double m_shift3Value; 140 | double m_shift4Value; 141 | double m_shift5Value; 142 | 143 | int m_increaseStep; 144 | int m_decreaseStep; 145 | 146 | HWND m_mainwindow; 147 | }; 148 | 149 | #endif // PREFERENCEDIALOG_H 150 | -------------------------------------------------------------------------------- /processmonitor.h: -------------------------------------------------------------------------------- 1 | /* 2 | * OpenSpeedy - Open Source Game Speed Controller 3 | * Copyright (C) 2025 Game1024 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see <https://www.gnu.org/licenses/>. 17 | */ 18 | #ifndef PROCESSMONITOR_H 19 | #define PROCESSMONITOR_H 20 | #include <windows.h> 21 | #include "winutils.h" 22 | #include <QLabel> 23 | #include <QMap> 24 | #include <QObject> 25 | #include <QProcess> 26 | #include <QSettings> 27 | #include <QThread> 28 | #include <QTimer> 29 | #include <QTreeWidget> 30 | #include <tlhelp32.h> 31 | 32 | #define CONFIG_TARGETNAMES_KEY "ProcessMonitor/TargetNames" 33 | 34 | class ProcessMonitor : public QObject 35 | { 36 | Q_OBJECT 37 | public: 38 | explicit ProcessMonitor(QSettings* settings, 39 | QTreeWidget* treeWidget, 40 | QLabel* treeStatusLabel, 41 | QLabel* injector32StatusLabel, 42 | QLabel* injector64StatusLabel, 43 | 44 | QObject* parent = nullptr); 45 | ~ProcessMonitor(); 46 | 47 | // 设置刷新间隔(毫秒) 48 | void setInterval(int msec); 49 | // 设置过滤 50 | void setFilter(QString processName); 51 | 52 | void changeSpeed(double factor); 53 | 54 | public slots: 55 | // 定时刷新槽函数 56 | void refresh(); 57 | 58 | void start(); 59 | 60 | private slots: 61 | void onItemChanged(QTreeWidgetItem* item, int column); 62 | 63 | private: 64 | QTreeWidget* m_treeWidget; 65 | QLabel* m_treeStatusLabel; 66 | QLabel* m_injector32StatusLabel; 67 | QLabel* m_injector64StatusLabel; 68 | QString m_filter; 69 | QTimer* m_timer = nullptr; 70 | QString m_dllPath; 71 | 72 | QProcess* m_bridge32; 73 | QProcess* m_bridge64; 74 | 75 | QSettings* m_settings; 76 | 77 | // 图标缓存 78 | QHash<QString, QIcon> m_iconCache; 79 | 80 | // 存储进程ID到TreeWidgetItem的映射 81 | QMap<DWORD, QTreeWidgetItem*> m_processItems; 82 | 83 | // 存储需要加速的进程 84 | QSet<QString> m_targetNames; 85 | 86 | void init(); 87 | 88 | void dump(); 89 | 90 | void update(const QList<ProcessInfo>& processList); 91 | 92 | void injectDll(DWORD processId, bool is64Bit); 93 | 94 | void unhookDll(DWORD processId, bool is64Bit); 95 | 96 | void startBridge32(); 97 | 98 | void startBridge64(); 99 | 100 | void healthcheckBridge(); 101 | 102 | void terminalBridge(); 103 | 104 | // 获取进程图标 105 | static QIcon getProcessIcon(QString processPath); 106 | 107 | static QIcon getDefaultIcon(const QString& processName); 108 | 109 | QIcon getProcessIconCached(DWORD proccessId); 110 | }; 111 | 112 | class SortTreeWidgetItem : public QTreeWidgetItem 113 | { 114 | public: 115 | SortTreeWidgetItem(QTreeWidget* parent = nullptr) 116 | : QTreeWidgetItem(parent) 117 | { 118 | } 119 | 120 | bool operator<(const QTreeWidgetItem& other) const override 121 | { 122 | int column = treeWidget()->sortColumn(); 123 | 124 | QVariant ldata = this->data(column, Qt::UserRole); 125 | QVariant rdata = other.data(column, Qt::UserRole); 126 | if (ldata.isValid() && rdata.isValid()) 127 | { 128 | if (ldata.type() == QVariant::UInt && rdata.type() == QVariant::UInt) 129 | { 130 | return ldata.toUInt() < rdata.toUInt(); 131 | } 132 | else 133 | { 134 | return ldata.toString() < rdata.toString(); 135 | } 136 | } 137 | else 138 | { 139 | QString ltext = this->text(column); 140 | QString rtext = other.text(column); 141 | return ltext < rtext; 142 | } 143 | } 144 | 145 | bool operator>(const QTreeWidgetItem& other) const 146 | { 147 | int column = treeWidget()->sortColumn(); 148 | 149 | QVariant ldata = this->data(column, Qt::UserRole); 150 | QVariant rdata = other.data(column, Qt::UserRole); 151 | if (ldata.isValid() && rdata.isValid()) 152 | { 153 | if (ldata.type() == QVariant::UInt && rdata.type() == QVariant::UInt) 154 | { 155 | return ldata.toUInt() > rdata.toUInt(); 156 | } 157 | else 158 | { 159 | return ldata.toString() > rdata.toString(); 160 | } 161 | } 162 | else 163 | { 164 | QString ltext = this->text(column); 165 | QString rtext = other.text(column); 166 | return ltext > rtext; 167 | } 168 | } 169 | }; 170 | 171 | #endif // PROCESSMONITOR_H 172 | -------------------------------------------------------------------------------- /qsinglekeysequenceedit.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * OpenSpeedy - Open Source Game Speed Controller 3 | * Copyright (C) 2025 Game1024 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see <https://www.gnu.org/licenses/>. 17 | */ 18 | #include "qsinglekeysequenceedit.h" 19 | #include <QDebug> 20 | 21 | QSingleKeySequenceEdit::QSingleKeySequenceEdit(QWidget* parent) 22 | : QKeySequenceEdit(parent) 23 | { 24 | setStyleSheet(":focus {" 25 | " border: 2px solid #3498db;" 26 | " background-color: #ebf3fd;" 27 | " font-weight: bold;" 28 | " outline: none;" 29 | "}"); 30 | 31 | connect(this, 32 | &QKeySequenceEdit::keySequenceChanged, 33 | this, 34 | &QSingleKeySequenceEdit::update); 35 | } 36 | 37 | UINT 38 | QSingleKeySequenceEdit::getVK() 39 | { 40 | return toVK(m_key, m_modifier); 41 | } 42 | 43 | UINT 44 | QSingleKeySequenceEdit::getModifier() 45 | { 46 | return toModifier(m_modifier); 47 | } 48 | 49 | QtCombinedKey 50 | QSingleKeySequenceEdit::getQtCombinedKey() 51 | { 52 | return QtCombinedKey{ m_key, m_modifier }; 53 | } 54 | 55 | QString 56 | QSingleKeySequenceEdit::getKeyText() 57 | { 58 | return keySequence().toString(QKeySequence::NativeText); 59 | } 60 | 61 | void 62 | QSingleKeySequenceEdit::keyPressEvent(QKeyEvent* event) 63 | { 64 | int key = event->key(); 65 | Qt::KeyboardModifiers modifiers = event->modifiers(); 66 | 67 | // 忽略单独的修饰键 68 | if (isModifierKey(key)) 69 | { 70 | return; 71 | } 72 | 73 | m_key = key; 74 | m_modifier = modifiers; 75 | 76 | // 创建单个按键序列 77 | QKeySequence singleKey(key | modifiers); 78 | setKeySequence(singleKey); 79 | 80 | // 🔚 结束编辑 81 | emit editingFinished(); 82 | clearFocus(); 83 | } 84 | 85 | void 86 | QSingleKeySequenceEdit::update() 87 | { 88 | QKeySequence sequence = keySequence(); 89 | 90 | if (sequence.isEmpty()) 91 | { 92 | m_key = 0; 93 | m_modifier = Qt::NoModifier; 94 | } 95 | else 96 | { 97 | int combinedKey = sequence[0]; 98 | m_modifier = 99 | Qt::KeyboardModifiers(combinedKey & Qt::KeyboardModifierMask); 100 | m_key = combinedKey & ~Qt::KeyboardModifierMask; 101 | } 102 | } 103 | 104 | bool 105 | QSingleKeySequenceEdit::isModifierKey(int key) const 106 | { 107 | return (key == Qt::Key_Control || key == Qt::Key_Alt || 108 | key == Qt::Key_Shift || key == Qt::Key_Meta); 109 | } 110 | 111 | UINT 112 | QSingleKeySequenceEdit::toVK(int qtKey, Qt::KeyboardModifiers qtMod) 113 | { 114 | // 🔤 字母键 A-Z 115 | if (qtKey >= Qt::Key_A && qtKey <= Qt::Key_Z) 116 | { 117 | return qtKey; // Qt 和 Windows 的 A-Z 键码相同 118 | } 119 | 120 | // 🔢 小键盘 0-9 121 | if (qtMod & Qt::KeypadModifier) 122 | { 123 | switch (qtKey) 124 | { 125 | // 数字键盘 126 | case Qt::Key_0: 127 | return VK_NUMPAD0; 128 | case Qt::Key_1: 129 | return VK_NUMPAD1; 130 | case Qt::Key_2: 131 | return VK_NUMPAD2; 132 | case Qt::Key_3: 133 | return VK_NUMPAD3; 134 | case Qt::Key_4: 135 | return VK_NUMPAD4; 136 | case Qt::Key_5: 137 | return VK_NUMPAD5; 138 | case Qt::Key_6: 139 | return VK_NUMPAD6; 140 | case Qt::Key_7: 141 | return VK_NUMPAD7; 142 | case Qt::Key_8: 143 | return VK_NUMPAD8; 144 | case Qt::Key_9: 145 | return VK_NUMPAD9; 146 | } 147 | } 148 | 149 | // 🔢 数字键 0-9 150 | if (qtKey >= Qt::Key_0 && qtKey <= Qt::Key_9) 151 | { 152 | return qtKey; // Qt 和 Windows 的 0-9 键码相同 153 | } 154 | 155 | // 🎯 功能键映射 156 | switch (qtKey) 157 | { 158 | // F1-F12 159 | case Qt::Key_F1: 160 | return VK_F1; 161 | case Qt::Key_F2: 162 | return VK_F2; 163 | case Qt::Key_F3: 164 | return VK_F3; 165 | case Qt::Key_F4: 166 | return VK_F4; 167 | case Qt::Key_F5: 168 | return VK_F5; 169 | case Qt::Key_F6: 170 | return VK_F6; 171 | case Qt::Key_F7: 172 | return VK_F7; 173 | case Qt::Key_F8: 174 | return VK_F8; 175 | case Qt::Key_F9: 176 | return VK_F9; 177 | case Qt::Key_F10: 178 | return VK_F10; 179 | case Qt::Key_F11: 180 | return VK_F11; 181 | case Qt::Key_F12: 182 | return VK_F12; 183 | 184 | // 方向键 185 | case Qt::Key_Left: 186 | return VK_LEFT; 187 | case Qt::Key_Right: 188 | return VK_RIGHT; 189 | case Qt::Key_Up: 190 | return VK_UP; 191 | case Qt::Key_Down: 192 | return VK_DOWN; 193 | 194 | // 特殊键 195 | case Qt::Key_Enter: 196 | case Qt::Key_Return: 197 | return VK_RETURN; 198 | case Qt::Key_Escape: 199 | return VK_ESCAPE; 200 | case Qt::Key_Tab: 201 | return VK_TAB; 202 | case Qt::Key_Backspace: 203 | return VK_BACK; 204 | case Qt::Key_Delete: 205 | return VK_DELETE; 206 | case Qt::Key_Insert: 207 | return VK_INSERT; 208 | case Qt::Key_Home: 209 | return VK_HOME; 210 | case Qt::Key_End: 211 | return VK_END; 212 | case Qt::Key_PageUp: 213 | return VK_PRIOR; 214 | case Qt::Key_PageDown: 215 | return VK_NEXT; 216 | case Qt::Key_Space: 217 | return VK_SPACE; 218 | 219 | // 符号键 220 | case Qt::Key_Semicolon: 221 | return VK_OEM_1; // ; 222 | case Qt::Key_Equal: 223 | return VK_OEM_PLUS; // = 224 | case Qt::Key_Comma: 225 | return VK_OEM_COMMA; // , 226 | case Qt::Key_Minus: 227 | return VK_OEM_MINUS; // - 228 | case Qt::Key_Period: 229 | return VK_OEM_PERIOD; // . 230 | case Qt::Key_Slash: 231 | return VK_OEM_2; // / 232 | case Qt::Key_QuoteLeft: 233 | return VK_OEM_3; // ` 234 | case Qt::Key_BracketLeft: 235 | return VK_OEM_4; // [ 236 | case Qt::Key_Backslash: 237 | return VK_OEM_5; // 238 | case Qt::Key_BracketRight: 239 | return VK_OEM_6; // ] 240 | case Qt::Key_Apostrophe: 241 | return VK_OEM_7; // ' 242 | 243 | // 其他常用键 244 | case Qt::Key_CapsLock: 245 | return VK_CAPITAL; 246 | case Qt::Key_NumLock: 247 | return VK_NUMLOCK; 248 | case Qt::Key_ScrollLock: 249 | return VK_SCROLL; 250 | case Qt::Key_Pause: 251 | return VK_PAUSE; 252 | case Qt::Key_Print: 253 | return VK_PRINT; 254 | 255 | default: 256 | qDebug() << "Unknown Qt key:" << qtKey; 257 | return 0; // 未知按键 258 | } 259 | } 260 | 261 | UINT 262 | QSingleKeySequenceEdit::toModifier(Qt::KeyboardModifiers qtMod) 263 | { 264 | UINT winMod = 0; 265 | 266 | if (qtMod & Qt::ControlModifier) 267 | { 268 | winMod |= MOD_CONTROL; 269 | } 270 | if (qtMod & Qt::AltModifier) 271 | { 272 | winMod |= MOD_ALT; 273 | } 274 | if (qtMod & Qt::ShiftModifier) 275 | { 276 | winMod |= MOD_SHIFT; 277 | } 278 | if (qtMod & Qt::MetaModifier) 279 | { 280 | winMod |= MOD_WIN; // Windows 键 281 | } 282 | 283 | return winMod; 284 | } 285 | 286 | QString 287 | QSingleKeySequenceEdit::wrapText(QString keyText) 288 | { 289 | return keyText.replace("Up", "⬆️") 290 | .replace("Down", "⬇️") 291 | .replace("Left", "⬅️") 292 | .replace("Right", "➡️"); 293 | } 294 | 295 | QtCombinedKey 296 | QSingleKeySequenceEdit::toQtCombinedKey(const QString& keyText) 297 | { 298 | QKeySequence sequence = QKeySequence(keyText); 299 | 300 | if (!sequence.isEmpty()) 301 | { 302 | int combinedKey = sequence[0]; 303 | Qt::KeyboardModifiers modifier = 304 | Qt::KeyboardModifiers(combinedKey & Qt::KeyboardModifierMask); 305 | int key = combinedKey & ~Qt::KeyboardModifierMask; 306 | return QtCombinedKey{ key, modifier }; 307 | } 308 | else 309 | { 310 | return QtCombinedKey{ 0, Qt::NoModifier }; 311 | } 312 | } 313 | -------------------------------------------------------------------------------- /qsinglekeysequenceedit.h: -------------------------------------------------------------------------------- 1 | /* 2 | * OpenSpeedy - Open Source Game Speed Controller 3 | * Copyright (C) 2025 Game1024 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see <https://www.gnu.org/licenses/>. 17 | */ 18 | #ifndef QSINGLEKEYSEQUENCEEDIT_H 19 | #define QSINGLEKEYSEQUENCEEDIT_H 20 | 21 | #include <windows.h> 22 | #include <QKeyEvent> 23 | #include <QKeySequenceEdit> 24 | #include <QObject> 25 | #define QKEYSEQUENCEEDIT_DEFAULT_PLACEHOLDER "点击设置热键" 26 | 27 | struct QtCombinedKey 28 | { 29 | int key; 30 | Qt::KeyboardModifiers modifier; 31 | }; 32 | 33 | class QSingleKeySequenceEdit : public QKeySequenceEdit 34 | { 35 | Q_OBJECT 36 | 37 | public: 38 | explicit QSingleKeySequenceEdit(QWidget* parent = nullptr); 39 | 40 | static UINT toVK(int qtKey, Qt::KeyboardModifiers qtMod); 41 | 42 | static UINT toModifier(Qt::KeyboardModifiers qtMod); 43 | 44 | static QtCombinedKey toQtCombinedKey(const QString& keyText); 45 | 46 | static QString wrapText(QString keyText); 47 | 48 | UINT getVK(); 49 | 50 | UINT getModifier(); 51 | 52 | QtCombinedKey getQtCombinedKey(); 53 | 54 | QString getKeyText(); 55 | 56 | protected: 57 | void keyPressEvent(QKeyEvent* event) override; 58 | 59 | private slots: 60 | void update(); 61 | 62 | private: 63 | bool isModifierKey(int key) const; 64 | 65 | int m_key; 66 | Qt::KeyboardModifiers m_modifier; 67 | }; 68 | 69 | #endif // QSINGLEKEYSEQUENCEEDIT_H 70 | -------------------------------------------------------------------------------- /resources.qrc: -------------------------------------------------------------------------------- 1 | <RCC> 2 | <qresource prefix="/icons"> 3 | <file>images/icon.ico</file> 4 | <file>images/logo.png</file> 5 | <file>images/icon_16.ico</file> 6 | <file>images/icon_32.ico</file> 7 | <file>images/icon_64.ico</file> 8 | </qresource> 9 | <qresource prefix="/i18n"> 10 | <file>translations/OpenSpeedy_en_US.qm</file> 11 | <file>translations/OpenSpeedy_zh_CN.qm</file> 12 | <file>translations/OpenSpeedy_zh_TW.qm</file> 13 | </qresource> 14 | </RCC> 15 | -------------------------------------------------------------------------------- /script/build32.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | echo ================================= 3 | echo Build 32 bit Qt5.15 static library 4 | echo ================================= 5 | 6 | if "%VCINSTALLDIR%"=="" ( 7 | echo Initializing Visual Studio 2022 32-bit environment... 8 | call %VC_TOOLS_32BIT% 9 | ) else ( 10 | echo Visual Studio environment already initialized 11 | echo VCINSTALLDIR: %VCINSTALLDIR% 12 | ) 13 | 14 | set SCRIPT_DIR=%~dp0 15 | set SOURCE_DIR=%SCRIPT_DIR%..\ 16 | set BUILD_DIR=%BUILD_DIR_32BIT% 17 | set QT_QMAKE_EXECUTABLE=%QT_QMAKE_EXECUTABLE_32BIT% 18 | 19 | REM 将命令执行结果存储在变量中 20 | for /f "delims=" %%i in ('"%QT_QMAKE_EXECUTABLE%" -query QT_INSTALL_PREFIX') do set QT_INSTALL_PREFIX=%%i 21 | echo "%QT_QMAKE_EXECUTABLE%" 22 | echo "%QT_INSTALL_PREFIX%" 23 | 24 | cmake.exe ^ 25 | -DQT_QMAKE_EXECUTABLE:FILEPATH="%QT_QMAKE_EXECUTABLE%" ^ 26 | -DCMAKE_PREFIX_PATH:PATH="%QT_INSTALL_PREFIX%" ^ 27 | -DCMAKE_BUILD_TYPE=Release ^ 28 | -S %SOURCE_DIR% ^ 29 | -B %BUILD_DIR% 30 | 31 | cmake.exe --build "%BUILD_DIR%" --config Release 32 | -------------------------------------------------------------------------------- /script/build64.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | echo ================================= 3 | echo Build 64 bit Qt5.15 static library 4 | echo ================================= 5 | 6 | if "%VCINSTALLDIR%"=="" ( 7 | echo Initializing Visual Studio 2022 64-bit environment... 8 | call %VC_TOOLS_64BIT% 9 | ) else ( 10 | echo Visual Studio environment already initialized 11 | echo VCINSTALLDIR: %VCINSTALLDIR% 12 | ) 13 | 14 | set SCRIPT_DIR=%~dp0 15 | set SOURCE_DIR=%SCRIPT_DIR%..\ 16 | set BUILD_DIR=%BUILD_DIR_64BIT% 17 | set QT_QMAKE_EXECUTABLE=%QT_QMAKE_EXECUTABLE_64BIT% 18 | 19 | REM 将命令执行结果存储在变量中 20 | for /f "delims=" %%i in ('"%QT_QMAKE_EXECUTABLE%" -query QT_INSTALL_PREFIX') do set QT_INSTALL_PREFIX=%%i 21 | echo "%QT_QMAKE_EXECUTABLE%" 22 | echo "%QT_INSTALL_PREFIX%" 23 | 24 | cmake.exe ^ 25 | -DQT_QMAKE_EXECUTABLE:FILEPATH="%QT_QMAKE_EXECUTABLE%" ^ 26 | -DCMAKE_PREFIX_PATH:PATH="%QT_INSTALL_PREFIX%" ^ 27 | -DCMAKE_BUILD_TYPE=Release ^ 28 | -S %SOURCE_DIR% ^ 29 | -B %BUILD_DIR% 30 | 31 | cmake.exe --build "%BUILD_DIR%" --config Release 32 | -------------------------------------------------------------------------------- /script/initenv.bat: -------------------------------------------------------------------------------- 1 | set VC_TOOLS_32BIT="D:\Program Files\Microsoft Visual Studio\2022\Preview\VC\Auxiliary\Build\vcvars32.bat" 2 | set VC_TOOLS_64BIT="D:\Program Files\Microsoft Visual Studio\2022\Preview\VC\Auxiliary\Build\vcvars64.bat" 3 | set BUILD_DIR_32BIT="%~dp0..\build\CMAKE-32bit-Release" 4 | set BUILD_DIR_64BIT="%~dp0..\build\CMAKE-64bit-Release" 5 | set QT_QMAKE_EXECUTABLE_32BIT="E:\source\github\vcpkg\installed\x86-windows-static\tools\qt5\bin\qmake.exe" 6 | set QT_QMAKE_EXECUTABLE_64BIT="E:\source\github\vcpkg\installed\x64-windows-static\tools\qt5\bin\qmake.exe" -------------------------------------------------------------------------------- /speedpatch/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.16) 2 | 3 | project(speedpatch LANGUAGES CXX) 4 | 5 | set(CMAKE_AUTOUIC ON) 6 | set(CMAKE_AUTOMOC ON) 7 | set(CMAKE_AUTORCC ON) 8 | set(CMAKE_CXX_STANDARD 17) 9 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 10 | 11 | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ..) 12 | 13 | # 判断是32位还是64位 14 | if(CMAKE_SIZEOF_VOID_P EQUAL 8) 15 | set(SUFFIX "64") 16 | elseif(CMAKE_SIZEOF_VOID_P EQUAL 4) 17 | set(SUFFIX "32") 18 | else() 19 | set(SUFFIX "") 20 | endif() 21 | 22 | # 设置目标名带后缀 23 | set(TARGET_NAME "speedpatch${SUFFIX}") 24 | 25 | add_library(${TARGET_NAME} SHARED 26 | speedpatch.cpp 27 | speedpatch.h 28 | vcpkg.json 29 | 30 | ) 31 | 32 | target_link_libraries(${TARGET_NAME} PRIVATE 33 | minhook 34 | ) 35 | target_compile_definitions(${TARGET_NAME} PRIVATE SPEEDPATCH_LIBRARY) 36 | -------------------------------------------------------------------------------- /speedpatch/SpeedPatch_global.h: -------------------------------------------------------------------------------- 1 | /* 2 | * OpenSpeedy - Open Source Game Speed Controller 3 | * Copyright (C) 2025 Game1024 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see <https://www.gnu.org/licenses/>. 17 | */ 18 | #ifndef SPEEDPATCH_GLOBAL_H 19 | #define SPEEDPATCH_GLOBAL_H 20 | 21 | 22 | #endif // SPEEDPATCH_GLOBAL_H 23 | -------------------------------------------------------------------------------- /speedpatch/speedpatch.h: -------------------------------------------------------------------------------- 1 | /* 2 | * OpenSpeedy - Open Source Game Speed Controller 3 | * Copyright (C) 2025 Game1024 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see <https://www.gnu.org/licenses/>. 17 | */ 18 | #ifndef SPEEDPATCH_H 19 | #define SPEEDPATCH_H 20 | #include <windows.h> 21 | #include <string> 22 | 23 | #if defined(SPEEDPATCH_LIBRARY) 24 | #define SPEEDPATCH_API __declspec(dllexport) 25 | #else 26 | #define SPEEDPATCH_API __declspec(dllimport) 27 | #endif 28 | 29 | std::wstring 30 | GetCurrentProcessName(); 31 | 32 | std::wstring 33 | GetProcessFileMapName(DWORD processId); 34 | 35 | extern "C" 36 | { 37 | SPEEDPATCH_API void Init(); 38 | SPEEDPATCH_API void Clean(); 39 | SPEEDPATCH_API BOOL GetStatus(); 40 | SPEEDPATCH_API void SetProcessStatus(DWORD processId,BOOL status); 41 | SPEEDPATCH_API void ChangeSpeed(double factor_); 42 | SPEEDPATCH_API LRESULT CALLBACK HookProc(int nCode, 43 | WPARAM wParam, 44 | LPARAM lParam 45 | ); 46 | } 47 | 48 | #endif // SPEEDPATCH_H 49 | -------------------------------------------------------------------------------- /speedpatch/vcpkg.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://raw.githubusercontent.com/microsoft/vcpkg-tool/main/docs/vcpkg.schema.json", 3 | "name": "mypackage", 4 | "version-string": "0.0.1", 5 | "dependencies": [ 6 | "minhook" 7 | ] 8 | } 9 | -------------------------------------------------------------------------------- /taskscheduler.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * OpenSpeedy - Open Source Game Speed Controller 3 | * Copyright (C) 2025 Game1024 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see <https://www.gnu.org/licenses/>. 17 | */ 18 | #include "taskscheduler.h" 19 | #include <QDebug> 20 | #include <QDir> 21 | #include <QProcess> 22 | TaskScheduler::TaskScheduler(QObject *parent) : QObject{parent} 23 | { 24 | } 25 | 26 | TaskScheduler::~TaskScheduler() 27 | { 28 | } 29 | 30 | bool TaskScheduler::createStartupTask(const QString &taskName, 31 | const QString &executablePath) 32 | { 33 | if (taskName.isEmpty() || executablePath.isEmpty()) 34 | { 35 | qWarning() << "任务名称或可执行文件路径不能为空"; 36 | return false; 37 | } 38 | 39 | if (!QFile::exists(executablePath)) 40 | { 41 | qWarning() << "可执行文件不存在" << executablePath; 42 | return false; 43 | } 44 | 45 | QStringList arguments; 46 | arguments << "/create" 47 | << "/f" 48 | << "/tn" << taskName << "/tr" 49 | << QString("\"%1\" --minimize-to-tray").arg(executablePath) 50 | << "/sc" << "onlogon" 51 | << "/delay" << "0000:10" 52 | << "/rl" << "highest"; 53 | 54 | return execute(arguments); 55 | } 56 | 57 | bool TaskScheduler::deleteTask(const QString &taskName) 58 | { 59 | if (taskName.isEmpty()) 60 | { 61 | qWarning() << "任务名称不能为空"; 62 | return false; 63 | } 64 | 65 | if (!isTaskExists(taskName)) 66 | { 67 | qWarning() << "任务不存在, 无需删除" << taskName; 68 | return true; 69 | } 70 | 71 | QStringList arguments; 72 | arguments << "/delete" 73 | << "/f" 74 | << "/tn" << taskName; 75 | 76 | return execute(arguments); 77 | } 78 | 79 | bool TaskScheduler::enableTask(const QString &taskName, bool enable) 80 | { 81 | if (!isTaskExists(taskName)) 82 | { 83 | qWarning() << "任务不存在:" << taskName; 84 | return false; 85 | } 86 | 87 | QStringList arguments; 88 | arguments << "/change" 89 | << "/tn" << taskName << (enable ? "/enable" : "/disable"); 90 | return execute(arguments); 91 | } 92 | 93 | bool TaskScheduler::isTaskExists(const QString &taskName) 94 | { 95 | QStringList arguments; 96 | arguments << "/query" << "/tn" << taskName; 97 | 98 | return execute(arguments); 99 | } 100 | 101 | bool TaskScheduler::execute(const QStringList &arguments) 102 | { 103 | QProcess process; 104 | process.setProgram("schtasks"); 105 | process.setArguments(arguments); 106 | 107 | const int timeout = 10000; 108 | process.start(); 109 | if (!process.waitForStarted(timeout)) 110 | { 111 | qWarning() << "无法运行:" << process.errorString(); 112 | return false; 113 | } 114 | 115 | if (!process.waitForFinished(timeout)) 116 | { 117 | qWarning() << "执行超时"; 118 | process.kill(); 119 | return false; 120 | } 121 | 122 | int exitcode = process.exitCode(); 123 | QString stdout_ = QString::fromLocal8Bit(process.readAllStandardOutput()); 124 | QString stderr_ = QString::fromLocal8Bit(process.readAllStandardError()); 125 | 126 | if (exitcode == 0) 127 | { 128 | qDebug() << "执行成功:" << arguments; 129 | qDebug() << "输出:" << stdout_; 130 | return true; 131 | } 132 | else 133 | { 134 | qDebug() << "执行失败:" << arguments; 135 | qDebug() << "错误输出:" << stderr_; 136 | qDebug() << "标准输出:" << stdout_; 137 | return false; 138 | } 139 | } 140 | 141 | bool TaskScheduler::createStartupShortcut(const QString &taskName, 142 | const QString &executablePath) 143 | { 144 | QString home = QDir::homePath(); 145 | QString startupDir = 146 | home + 147 | "\\AppData\\Roaming\\Microsoft\\Windows\\Start Menu\\Programs\\Startup"; 148 | QString shortcutPath = QDir(startupDir).absoluteFilePath(taskName + ".lnk"); 149 | QString arguments = "--minimize-to-tray"; 150 | 151 | QString psScript = 152 | QString("$WScriptShell = New-Object -ComObject WScript.Shell; " 153 | "$Shortcut = $WScriptShell.CreateShortcut('%1'); " 154 | "$Shortcut.TargetPath = '%2'; " 155 | "$Shortcut.Arguments = '%3'; " 156 | "$Shortcut.Description = '%4'; " 157 | "$Shortcut.Save()") 158 | .arg(shortcutPath, executablePath, arguments, 159 | QString("启动 %1").arg(QFileInfo(executablePath).baseName())); 160 | 161 | return executePs(psScript); 162 | } 163 | 164 | bool TaskScheduler::deleteStartupShortcut(const QString &taskName) 165 | { 166 | QString home = QDir::homePath(); 167 | QString startupDir = 168 | home + "\\AppData\\Roaming\\Microsoft\\Windows\\Start Menu\\Programs\\Startup"; 169 | QString shortcutPath = QDir(startupDir).absoluteFilePath(taskName + ".lnk"); 170 | 171 | QString psScript = QString("Remove-Item '%1' -Force").arg(shortcutPath); 172 | 173 | return executePs(psScript); 174 | } 175 | 176 | bool TaskScheduler::isStartupShortcutExists(const QString &taskName) 177 | { 178 | QString home = QDir::homePath(); 179 | QString startupDir = 180 | home + 181 | "\\AppData\\Roaming\\Microsoft\\Windows\\Start Menu\\Programs\\Startup"; 182 | QString shortcutPath = QDir(startupDir).absoluteFilePath(taskName + ".lnk"); 183 | 184 | return QFile::exists(shortcutPath); 185 | } 186 | 187 | bool TaskScheduler::executePs(const QString &psScript) 188 | { 189 | QProcess process; 190 | process.setProgram("powershell"); 191 | process.setArguments({"-ExecutionPolicy", "Bypass", "-Command", psScript}); 192 | 193 | process.start(); 194 | if (!process.waitForStarted(5000)) 195 | { 196 | qDebug() << "PowerShell 启动失败:" << process.errorString(); 197 | return false; 198 | } 199 | 200 | if (process.waitForFinished(5000) && process.exitCode() == 0) 201 | { 202 | qDebug() << "PowerShell 执行成功"; 203 | return true; 204 | } 205 | else 206 | { 207 | QString error = QString::fromLocal8Bit(process.readAllStandardError()); 208 | qDebug() << "PowerShell 执行失败:" << error; 209 | } 210 | 211 | return false; 212 | } 213 | -------------------------------------------------------------------------------- /taskscheduler.h: -------------------------------------------------------------------------------- 1 | /* 2 | * OpenSpeedy - Open Source Game Speed Controller 3 | * Copyright (C) 2025 Game1024 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see <https://www.gnu.org/licenses/>. 17 | */ 18 | #ifndef TASKSCHEDULER_H 19 | #define TASKSCHEDULER_H 20 | 21 | #include <windows.h> 22 | #include <QObject> 23 | #include <QString> 24 | class TaskScheduler : public QObject 25 | { 26 | Q_OBJECT 27 | public: 28 | explicit TaskScheduler(QObject *parent = nullptr); 29 | ~TaskScheduler(); 30 | 31 | bool createStartupTask(const QString &taskName, 32 | const QString &executablePath); 33 | bool deleteTask(const QString &taskName); 34 | bool enableTask(const QString &taskName, bool enable); 35 | bool isTaskExists(const QString &taskName); 36 | bool execute(const QStringList &arguments); 37 | 38 | bool createStartupShortcut(const QString &taskName, 39 | const QString &executablePath); 40 | bool deleteStartupShortcut(const QString &taskName); 41 | bool isStartupShortcutExists(const QString &taskName); 42 | bool executePs(const QString &psScript); 43 | }; 44 | 45 | #endif // TASKSCHEDULER_H 46 | -------------------------------------------------------------------------------- /third_party/minhook/.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig is awesome: http://EditorConfig.org 2 | 3 | # top-most EditorConfig file 4 | root = true 5 | 6 | # Windows-style newlines with a newline ending every file 7 | [*] 8 | end_of_line = crlf 9 | insert_final_newline = true 10 | 11 | # 4 space indentation 12 | [*.{c,h,def}] 13 | indent_style = space 14 | indent_size = 4 15 | 16 | # Trim trailing whitespaces 17 | [*.{c,h,def,txt}] 18 | trim_trailing_whitespace = true 19 | 20 | # UTF-8 with BOM 21 | [*.{c,h,def,txt}] 22 | charset=utf-8-bom 23 | 24 | # C/C++ code formatting 25 | [*.{c,h}] 26 | cpp_space_pointer_reference_alignment = right 27 | -------------------------------------------------------------------------------- /third_party/minhook/.github/workflows/msbuild.yml: -------------------------------------------------------------------------------- 1 | name: Build 2 | 3 | on: 4 | workflow_dispatch: 5 | push: 6 | branches: [ "master" ] 7 | 8 | env: 9 | # Path to the solution file relative to the root of the project. 10 | SOLUTION_FILE_PATH: build/VC17/MinHookVC17.sln 11 | 12 | # Configuration type to build. 13 | # You can convert this to a build matrix if you need coverage of multiple configuration types. 14 | # https://docs.github.com/actions/learn-github-actions/managing-complex-workflows#using-a-build-matrix 15 | BUILD_CONFIGURATION: Release 16 | 17 | jobs: 18 | build: 19 | runs-on: windows-latest 20 | 21 | steps: 22 | - uses: actions/checkout@v4 23 | 24 | - name: Add MSBuild to PATH 25 | uses: microsoft/setup-msbuild@v2 26 | 27 | - name: Build Win32 28 | # Add additional options to the MSBuild command line here (like platform or verbosity level). 29 | # See https://docs.microsoft.com/visualstudio/msbuild/msbuild-command-line-reference 30 | run: msbuild /m /p:Configuration=${{ env.BUILD_CONFIGURATION }} /p:Platform="Win32" ${{ env.SOLUTION_FILE_PATH }} 31 | 32 | - name: Build x64 33 | # Add additional options to the MSBuild command line here (like platform or verbosity level). 34 | # See https://docs.microsoft.com/visualstudio/msbuild/msbuild-command-line-reference 35 | run: msbuild /m /p:Configuration=${{ env.BUILD_CONFIGURATION }} /p:Platform="x64" ${{ env.SOLUTION_FILE_PATH }} 36 | 37 | - name: Collect artifacts 38 | shell: bash 39 | run: | 40 | mkdir "${{ runner.temp }}/artifacts" 41 | mv "build/VC17/bin/${{ env.BUILD_CONFIGURATION }}" "${{ runner.temp }}/artifacts/bin" 42 | mv "build/VC17/lib/${{ env.BUILD_CONFIGURATION }}" "${{ runner.temp }}/artifacts/lib" 43 | cp -r include "${{ runner.temp }}/artifacts/include" 44 | 45 | - name: Package bin 46 | uses: actions/upload-artifact@v4 47 | with: 48 | name: MinHook_bin 49 | path: | 50 | ${{ runner.temp }}/artifacts/bin/ 51 | ${{ runner.temp }}/artifacts/include/ 52 | 53 | - name: Package lib 54 | uses: actions/upload-artifact@v4 55 | with: 56 | name: MinHook_lib 57 | path: | 58 | ${{ runner.temp }}/artifacts/lib/ 59 | ${{ runner.temp }}/artifacts/include/ 60 | -------------------------------------------------------------------------------- /third_party/minhook/.gitignore: -------------------------------------------------------------------------------- 1 | #OS junk files 2 | [Tt]humbs.db 3 | *.DS_Store 4 | 5 | #Visual Studio files 6 | *.[Oo]bj 7 | *.user 8 | *.aps 9 | *.pch 10 | *.vspscc 11 | *.vssscc 12 | *_i.c 13 | *_p.c 14 | *.ncb 15 | *.suo 16 | *.tlb 17 | *.tlh 18 | *.bak 19 | *.[Cc]ache 20 | *.ilk 21 | *.log 22 | *.sbr 23 | *.sdf 24 | *.opensdf 25 | *.unsuccessfulbuild 26 | ipch/ 27 | obj/ 28 | [Ll]ib 29 | [Bb]in 30 | [Dd]ebug*/ 31 | [Rr]elease*/ 32 | Ankh.NoLoad 33 | *.VC.db 34 | .vs/ 35 | 36 | #GCC files 37 | *.o 38 | *.d 39 | *.res 40 | *.dll 41 | *.a 42 | 43 | #Visual Studio Code files 44 | .vscode/ 45 | -------------------------------------------------------------------------------- /third_party/minhook/AUTHORS.txt: -------------------------------------------------------------------------------- 1 | Tsuda Kageyu <tsuda.kageyu@gmail.com> 2 | Creator, maintainer 3 | 4 | Michael Maltsev <leahcimmar@gmail.com> 5 | Added "Queue" functions. A lot of bug fixes. 6 | 7 | Andrey Unis <uniskz@gmail.com> 8 | Rewrote the hook engine in plain C. 9 | -------------------------------------------------------------------------------- /third_party/minhook/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # MinHook - The Minimalistic API Hooking Library for x64/x86 2 | # Copyright (C) 2009-2017 Tsuda Kageyu. 3 | # All rights reserved. 4 | # 5 | # Redistribution and use in source and binary forms, with or without 6 | # modification, are permitted provided that the following conditions 7 | # are met: 8 | # 9 | # 1. Redistributions of source code must retain the above copyright 10 | # notice, this list of conditions and the following disclaimer. 11 | # 2. Redistributions in binary form must reproduce the above copyright 12 | # notice, this list of conditions and the following disclaimer in the 13 | # documentation and/or other materials provided with the distribution. 14 | # 15 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 16 | # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 17 | # TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 18 | # PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER 19 | # OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 20 | # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 21 | # PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 22 | # PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 23 | # LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 24 | # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 25 | # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | 27 | cmake_minimum_required(VERSION 3.0...3.5) 28 | 29 | project(minhook LANGUAGES C) 30 | 31 | include(CMakePackageConfigHelpers) 32 | 33 | set(MINHOOK_MAJOR_VERSION 1) 34 | set(MINHOOK_MINOR_VERSION 3) 35 | set(MINHOOK_PATCH_VERSION 3) 36 | set(MINHOOK_VERSION ${MINHOOK_MAJOR_VERSION}.${MINHOOK_MINOR_VERSION}.${MINHOOK_PATCH_VERSION}) 37 | 38 | ################ 39 | # BUILD # 40 | ################ 41 | 42 | option(BUILD_SHARED_LIBS "build shared version" OFF) 43 | 44 | set(SOURCES_MINHOOK 45 | "src/buffer.c" 46 | "src/hook.c" 47 | "src/trampoline.c" 48 | ) 49 | 50 | if(CMAKE_SIZEOF_VOID_P EQUAL 8) 51 | set(SOURCES_HDE "src/hde/hde64.c") 52 | else() 53 | set(SOURCES_HDE "src/hde/hde32.c") 54 | endif() 55 | 56 | if(BUILD_SHARED_LIBS) 57 | set(RESOURCES 58 | "dll_resources/MinHook.rc" 59 | "dll_resources/MinHook.def" 60 | ) 61 | endif() 62 | 63 | add_library(minhook ${SOURCES_MINHOOK} ${SOURCES_HDE} ${RESOURCES}) 64 | 65 | target_include_directories(minhook PUBLIC 66 | lt;BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include/> 67 | lt;INSTALL_INTERFACE:include> 68 | ) 69 | 70 | target_include_directories(minhook PRIVATE "src/") 71 | target_include_directories(minhook PRIVATE "src/hde/") 72 | 73 | if(WIN32) 74 | set_target_properties(minhook PROPERTIES PREFIX "") 75 | if(CMAKE_SIZEOF_VOID_P EQUAL 8) 76 | set_target_properties(minhook PROPERTIES DEBUG_POSTFIX ".x64d") 77 | set_target_properties(minhook PROPERTIES RELEASE_POSTFIX ".x64") 78 | set_target_properties(minhook PROPERTIES RELWITHDEBINFO_POSTFIX ".x64") 79 | set_target_properties(minhook PROPERTIES MINSIZEREL_POSTFIX ".x64") 80 | else() 81 | set_target_properties(minhook PROPERTIES DEBUG_POSTFIX ".x32d") 82 | set_target_properties(minhook PROPERTIES RELEASE_POSTFIX ".x32") 83 | set_target_properties(minhook PROPERTIES RELWITHDEBINFO_POSTFIX ".x32") 84 | set_target_properties(minhook PROPERTIES MINSIZEREL_POSTFIX ".x32") 85 | endif() 86 | else() 87 | set_target_properties(minhook PROPERTIES PREFIX "lib") 88 | set_target_properties(minhook PROPERTIES POSTFIX "") 89 | set_target_properties(minhook PROPERTIES DEBUG_POSTFIX "d") 90 | endif() 91 | 92 | ################ 93 | # CMAKE CONFIG # 94 | ################ 95 | 96 | configure_package_config_file( 97 | "cmake/minhook-config.cmake.in" 98 | "minhook-config.cmake" 99 | INSTALL_DESTINATION 100 | "lib/minhook" 101 | ) 102 | 103 | write_basic_package_version_file( 104 | "minhook-config-version.cmake" 105 | VERSION 106 | ${MINHOOK_VERSION} 107 | COMPATIBILITY 108 | AnyNewerVersion 109 | ) 110 | 111 | install( 112 | FILES 113 | "${CMAKE_CURRENT_BINARY_DIR}/minhook-config.cmake" 114 | "${CMAKE_CURRENT_BINARY_DIR}/minhook-config-version.cmake" 115 | DESTINATION 116 | "lib/minhook" 117 | ) 118 | 119 | ################### 120 | # INSTALL # 121 | ################### 122 | 123 | install(TARGETS minhook 124 | EXPORT minhook-targets 125 | RUNTIME DESTINATION "bin" 126 | ARCHIVE DESTINATION "lib" 127 | LIBRARY DESTINATION "lib" 128 | ) 129 | 130 | install( 131 | EXPORT 132 | minhook-targets 133 | NAMESPACE 134 | minhook:: 135 | DESTINATION 136 | "lib/minhook" 137 | ) 138 | 139 | install( 140 | DIRECTORY include DESTINATION . 141 | ) 142 | -------------------------------------------------------------------------------- /third_party/minhook/LICENSE.txt: -------------------------------------------------------------------------------- 1 | MinHook - The Minimalistic API Hooking Library for x64/x86 2 | Copyright (C) 2009-2017 Tsuda Kageyu. 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions 7 | are met: 8 | 9 | 1. Redistributions of source code must retain the above copyright 10 | notice, this list of conditions and the following disclaimer. 11 | 2. Redistributions in binary form must reproduce the above copyright 12 | notice, this list of conditions and the following disclaimer in the 13 | documentation and/or other materials provided with the distribution. 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 16 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 17 | TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 18 | PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER 19 | OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 20 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 21 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 22 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 23 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 24 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 25 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | 27 | ================================================================================ 28 | Portions of this software are Copyright (c) 2008-2009, Vyacheslav Patkov. 29 | ================================================================================ 30 | Hacker Disassembler Engine 32 C 31 | Copyright (c) 2008-2009, Vyacheslav Patkov. 32 | All rights reserved. 33 | 34 | Redistribution and use in source and binary forms, with or without 35 | modification, are permitted provided that the following conditions 36 | are met: 37 | 38 | 1. Redistributions of source code must retain the above copyright 39 | notice, this list of conditions and the following disclaimer. 40 | 2. Redistributions in binary form must reproduce the above copyright 41 | notice, this list of conditions and the following disclaimer in the 42 | documentation and/or other materials provided with the distribution. 43 | 44 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 45 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 46 | TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 47 | PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR 48 | CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 49 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 50 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 51 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 52 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 53 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 54 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 55 | 56 | ------------------------------------------------------------------------------- 57 | Hacker Disassembler Engine 64 C 58 | Copyright (c) 2008-2009, Vyacheslav Patkov. 59 | All rights reserved. 60 | 61 | Redistribution and use in source and binary forms, with or without 62 | modification, are permitted provided that the following conditions 63 | are met: 64 | 65 | 1. Redistributions of source code must retain the above copyright 66 | notice, this list of conditions and the following disclaimer. 67 | 2. Redistributions in binary form must reproduce the above copyright 68 | notice, this list of conditions and the following disclaimer in the 69 | documentation and/or other materials provided with the distribution. 70 | 71 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 72 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 73 | TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 74 | PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR 75 | CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 76 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 77 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 78 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 79 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 80 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 81 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 82 | -------------------------------------------------------------------------------- /third_party/minhook/README.md: -------------------------------------------------------------------------------- 1 | # MinHook 2 | 3 | [](https://opensource.org/licenses/BSD-2-Clause) 4 | 5 | The Minimalistic x86/x64 API Hooking Library for Windows 6 | 7 | http://www.codeproject.com/KB/winsdk/LibMinHook.aspx 8 | 9 | ### Version history 10 | 11 | - **v1.3.4 - 28 Mar 2025** 12 | * Improved error handling for enumerating and suspending threads. 13 | * Visual Studio 2022 support. 14 | * CMake support. 15 | * Fixed compilation with Clang. 16 | * Fixed compilation as C++ code. 17 | 18 | - **v1.3.3 - 8 Jan 2017** 19 | * Added a helper function ```MH_CreateHookApiEx```. (Thanks to asm256) 20 | * Support Visual Studio 2017 RC. 21 | 22 | - **v1.3.2.1 - 9 Nov 2015** (Nuget package only) 23 | * Fixed an insufficient support for Visual Studio 2015. 24 | 25 | - **v1.3.2 - 1 Nov 2015** 26 | * Support Visual Studio 2015. 27 | * Support MinGW. 28 | 29 | - **v1.3.2-beta3 - 21 Jul 2015** (Nuget package only) 30 | * Support MinGW. (Experimental) 31 | 32 | - **v1.3.2-beta2 - 18 May 2015** 33 | * Fixed some subtle bugs. (Thanks to RaMMicHaeL) 34 | * Added a helper function ```MH_StatusToString```. (Thanks to Jan Klass) 35 | 36 | - **v1.3.2-beta - 12 May 2015** 37 | * Fixed a possible thread deadlock in x64 mode. (Thanks to Aleh Kazakevich) 38 | * Reduced the footprint a little more. 39 | * Support Visual Studio 2015 RC. (Experimental) 40 | 41 | - **v1.3.1.1 - 7 Apr 2015** (Nuget package only) 42 | * Support for WDK8.0 and 8.1. 43 | 44 | - **v1.3.1 - 19 Mar 2015** 45 | * No major changes from v1.3.1-beta. 46 | 47 | - **v1.3.1-beta - 11 Mar 2015** 48 | * Added a helper function ```MH_CreateHookApi```. (Thanks to uniskz). 49 | * Fixed a false memory leak reported by some tools. 50 | * Fixed a degradated compatibility issue. 51 | 52 | - **v1.3 - 13 Sep 2014** 53 | * No major changes from v1.3-beta3. 54 | 55 | - **v1.3-beta3 - 31 Jul 2014** 56 | * Fixed some small bugs. 57 | * Improved the memory management. 58 | 59 | - **v1.3-beta2 - 21 Jul 2014** 60 | * Changed the parameters to Windows-friendly types. (void* to LPVOID) 61 | * Fixed some small bugs. 62 | * Reorganized the source files. 63 | * Reduced the footprint a little more. 64 | 65 | - **v1.3-beta - 17 Jul 2014** 66 | * Rewrote in plain C to reduce the footprint and memory usage. (suggested by Andrey Unis) 67 | * Simplified the overall code base to make it more readable and maintainable. 68 | * Changed the license from 3-clause to 2-clause BSD License. 69 | 70 | - **v1.2 - 28 Sep 2013** 71 | * Removed boost dependency ([jarredholman](https://github.com/jarredholman/minhook)). 72 | * Fixed a small bug in the GetRelativeBranchDestination function ([pillbug99](http://www.codeproject.com/Messages/4058892/Small-Bug-Found.aspx)). 73 | * Added the ```MH_RemoveHook``` function, which removes a hook created with the ```MH_CreateHook``` function. 74 | * Added the following functions to enable or disable multiple hooks in one go: ```MH_QueueEnableHook```, ```MH_QueueDisableHook```, ```MH_ApplyQueued```. This is the preferred way of handling multiple hooks as every call to `MH_EnableHook` or `MH_DisableHook` suspends and resumes all threads. 75 | * Made the functions ```MH_EnableHook``` and ```MH_DisableHook``` enable/disable all created hooks when the ```MH_ALL_HOOKS``` parameter is passed. This, too, is an efficient way of handling multiple hooks. 76 | * If the target function is too small to be patched with a jump, MinHook tries to place the jump above the function. If that fails as well, the ```MH_CreateHook``` function returns ```MH_ERROR_UNSUPPORTED_FUNCTION```. This fixes an issue of hooking the LoadLibraryExW function on Windows 7 x64 ([reported by Obble](http://www.codeproject.com/Messages/4578613/Re-Bug-LoadLibraryExW-hook-fails-on-windows-2008-r.aspx)). 77 | 78 | - **v1.1 - 26 Nov 2009** 79 | * Changed the interface to create a hook and a trampoline function in one go to prevent the detour function from being called before the trampoline function is created. ([reported by xliqz](http://www.codeproject.com/Messages/3280374/Unsafe.aspx)) 80 | * Shortened the function names from ```MinHook_*``` to ```MH_*``` to make them handier. 81 | 82 | - **v1.0 - 22 Nov 2009** 83 | * Initial release. 84 | 85 | ### Building MinHook - Using vcpkg 86 | 87 | You can download and install MinHook using the [vcpkg](https://github.com/Microsoft/vcpkg) dependency manager: 88 | 89 | git clone https://github.com/microsoft/vcpkg 90 | .\vcpkg\bootstrap-vcpkg.bat 91 | .\vcpkg\vcpkg integrate install 92 | .\vcpkg\vcpkg install minhook 93 | 94 | The MinHook port in vcpkg is kept up to date by Microsoft team members and community contributors. If the version is out of date, please [create an issue or pull request](https://github.com/Microsoft/vcpkg) on the vcpkg repository. 95 | -------------------------------------------------------------------------------- /third_party/minhook/build/MinGW/make.bat: -------------------------------------------------------------------------------- 1 | windres -i ../../dll_resources/MinHook.rc -o MinHook_rc.o && dllwrap --driver-name g++ -o MinHook.dll -masm=intel --def ../../dll_resources/MinHook.def -Wl,-enable-stdcall-fixup -Wall MinHook_rc.o ../../src/*.c ../../src/HDE/*.c -I../../include -I../../src -Werror -std=c++11 -s -static-libgcc -static-libstdc++|| pause -------------------------------------------------------------------------------- /third_party/minhook/build/MinGW/make.sh: -------------------------------------------------------------------------------- 1 | x86_64-w64-mingw32-windres -i ../../dll_resources/MinHook.rc -o MinHook_rc.o && 2 | x86_64-w64-mingw32-dllwrap -o MinHook.dll -masm=intel --def ../../dll_resources/MinHook.def -Wl,-enable-stdcall-fixup -Wall MinHook_rc.o ../../src/*.c ../../src/hde/*.c -I../../include -I../../src -Werror -s -static-libgcc -static-libstdc++ 3 | -------------------------------------------------------------------------------- /third_party/minhook/cmake/minhook-config.cmake.in: -------------------------------------------------------------------------------- 1 | # MinHook - The Minimalistic API Hooking Library for x64/x86 2 | # Copyright (C) 2009-2017 Tsuda Kageyu. 3 | # All rights reserved. 4 | # 5 | # Redistribution and use in source and binary forms, with or without 6 | # modification, are permitted provided that the following conditions 7 | # are met: 8 | # 9 | # 1. Redistributions of source code must retain the above copyright 10 | # notice, this list of conditions and the following disclaimer. 11 | # 2. Redistributions in binary form must reproduce the above copyright 12 | # notice, this list of conditions and the following disclaimer in the 13 | # documentation and/or other materials provided with the distribution. 14 | # 15 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 16 | # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 17 | # TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 18 | # PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER 19 | # OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 20 | # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 21 | # PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 22 | # PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 23 | # LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 24 | # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 25 | # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | 27 | set(MINHOOK_MAJOR_VERSION "@MINHOOK_MAJOR_VERSION@") 28 | set(MINHOOK_MINOR_VERSION "@MINHOOK_MINOR_VERSION@") 29 | set(MINHOOK_PATCH_VERSION "@MINHOOK_PATCH_VERSION@") 30 | set(MINHOOK_VERSION "@MINHOOK_VERSION@") 31 | 32 | @PACKAGE_INIT@ 33 | 34 | set(MINHOOK_FOUND ON) 35 | 36 | set_and_check(MINHOOK_INCLUDE_DIRS "${PACKAGE_PREFIX_DIR}/include/") 37 | set_and_check(MINHOOK_LIBRARY_DIRS "${PACKAGE_PREFIX_DIR}/lib") 38 | 39 | include("${PACKAGE_PREFIX_DIR}/lib/minhook/minhook-targets.cmake") 40 | -------------------------------------------------------------------------------- /third_party/minhook/dll_resources/MinHook.def: -------------------------------------------------------------------------------- 1 | EXPORTS 2 | MH_Initialize 3 | MH_Uninitialize 4 | 5 | MH_CreateHook 6 | MH_CreateHookApi 7 | MH_CreateHookApiEx 8 | MH_RemoveHook 9 | MH_EnableHook 10 | MH_DisableHook 11 | MH_QueueEnableHook 12 | MH_QueueDisableHook 13 | MH_ApplyQueued 14 | MH_StatusToString 15 | -------------------------------------------------------------------------------- /third_party/minhook/include/MinHook.h: -------------------------------------------------------------------------------- 1 | /* 2 | * MinHook - The Minimalistic API Hooking Library for x64/x86 3 | * Copyright (C) 2009-2017 Tsuda Kageyu. 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions 8 | * are met: 9 | * 10 | * 1. Redistributions of source code must retain the above copyright 11 | * notice, this list of conditions and the following disclaimer. 12 | * 2. Redistributions in binary form must reproduce the above copyright 13 | * notice, this list of conditions and the following disclaimer in the 14 | * documentation and/or other materials provided with the distribution. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 18 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 19 | * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER 20 | * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 21 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 22 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 23 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 24 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 25 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 26 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | */ 28 | 29 | #pragma once 30 | 31 | #if !(defined _M_IX86) && !(defined _M_X64) && !(defined __i386__) && !(defined __x86_64__) 32 | #error MinHook supports only x86 and x64 systems. 33 | #endif 34 | 35 | #include <windows.h> 36 | 37 | // MinHook Error Codes. 38 | typedef enum MH_STATUS 39 | { 40 | // Unknown error. Should not be returned. 41 | MH_UNKNOWN = -1, 42 | 43 | // Successful. 44 | MH_OK = 0, 45 | 46 | // MinHook is already initialized. 47 | MH_ERROR_ALREADY_INITIALIZED, 48 | 49 | // MinHook is not initialized yet, or already uninitialized. 50 | MH_ERROR_NOT_INITIALIZED, 51 | 52 | // The hook for the specified target function is already created. 53 | MH_ERROR_ALREADY_CREATED, 54 | 55 | // The hook for the specified target function is not created yet. 56 | MH_ERROR_NOT_CREATED, 57 | 58 | // The hook for the specified target function is already enabled. 59 | MH_ERROR_ENABLED, 60 | 61 | // The hook for the specified target function is not enabled yet, or already 62 | // disabled. 63 | MH_ERROR_DISABLED, 64 | 65 | // The specified pointer is invalid. It points the address of non-allocated 66 | // and/or non-executable region. 67 | MH_ERROR_NOT_EXECUTABLE, 68 | 69 | // The specified target function cannot be hooked. 70 | MH_ERROR_UNSUPPORTED_FUNCTION, 71 | 72 | // Failed to allocate memory. 73 | MH_ERROR_MEMORY_ALLOC, 74 | 75 | // Failed to change the memory protection. 76 | MH_ERROR_MEMORY_PROTECT, 77 | 78 | // The specified module is not loaded. 79 | MH_ERROR_MODULE_NOT_FOUND, 80 | 81 | // The specified function is not found. 82 | MH_ERROR_FUNCTION_NOT_FOUND 83 | } 84 | MH_STATUS; 85 | 86 | // Can be passed as a parameter to MH_EnableHook, MH_DisableHook, 87 | // MH_QueueEnableHook or MH_QueueDisableHook. 88 | #define MH_ALL_HOOKS NULL 89 | 90 | #ifdef __cplusplus 91 | extern "C" { 92 | #endif 93 | 94 | // Initialize the MinHook library. You must call this function EXACTLY ONCE 95 | // at the beginning of your program. 96 | MH_STATUS WINAPI MH_Initialize(VOID); 97 | 98 | // Uninitialize the MinHook library. You must call this function EXACTLY 99 | // ONCE at the end of your program. 100 | MH_STATUS WINAPI MH_Uninitialize(VOID); 101 | 102 | // Creates a hook for the specified target function, in disabled state. 103 | // Parameters: 104 | // pTarget [in] A pointer to the target function, which will be 105 | // overridden by the detour function. 106 | // pDetour [in] A pointer to the detour function, which will override 107 | // the target function. 108 | // ppOriginal [out] A pointer to the trampoline function, which will be 109 | // used to call the original target function. 110 | // This parameter can be NULL. 111 | MH_STATUS WINAPI MH_CreateHook(LPVOID pTarget, LPVOID pDetour, LPVOID *ppOriginal); 112 | 113 | // Creates a hook for the specified API function, in disabled state. 114 | // Parameters: 115 | // pszModule [in] A pointer to the loaded module name which contains the 116 | // target function. 117 | // pszProcName [in] A pointer to the target function name, which will be 118 | // overridden by the detour function. 119 | // pDetour [in] A pointer to the detour function, which will override 120 | // the target function. 121 | // ppOriginal [out] A pointer to the trampoline function, which will be 122 | // used to call the original target function. 123 | // This parameter can be NULL. 124 | MH_STATUS WINAPI MH_CreateHookApi( 125 | LPCWSTR pszModule, LPCSTR pszProcName, LPVOID pDetour, LPVOID *ppOriginal); 126 | 127 | // Creates a hook for the specified API function, in disabled state. 128 | // Parameters: 129 | // pszModule [in] A pointer to the loaded module name which contains the 130 | // target function. 131 | // pszProcName [in] A pointer to the target function name, which will be 132 | // overridden by the detour function. 133 | // pDetour [in] A pointer to the detour function, which will override 134 | // the target function. 135 | // ppOriginal [out] A pointer to the trampoline function, which will be 136 | // used to call the original target function. 137 | // This parameter can be NULL. 138 | // ppTarget [out] A pointer to the target function, which will be used 139 | // with other functions. 140 | // This parameter can be NULL. 141 | MH_STATUS WINAPI MH_CreateHookApiEx( 142 | LPCWSTR pszModule, LPCSTR pszProcName, LPVOID pDetour, LPVOID *ppOriginal, LPVOID *ppTarget); 143 | 144 | // Removes an already created hook. 145 | // Parameters: 146 | // pTarget [in] A pointer to the target function. 147 | MH_STATUS WINAPI MH_RemoveHook(LPVOID pTarget); 148 | 149 | // Enables an already created hook. 150 | // Parameters: 151 | // pTarget [in] A pointer to the target function. 152 | // If this parameter is MH_ALL_HOOKS, all created hooks are 153 | // enabled in one go. 154 | MH_STATUS WINAPI MH_EnableHook(LPVOID pTarget); 155 | 156 | // Disables an already created hook. 157 | // Parameters: 158 | // pTarget [in] A pointer to the target function. 159 | // If this parameter is MH_ALL_HOOKS, all created hooks are 160 | // disabled in one go. 161 | MH_STATUS WINAPI MH_DisableHook(LPVOID pTarget); 162 | 163 | // Queues to enable an already created hook. 164 | // Parameters: 165 | // pTarget [in] A pointer to the target function. 166 | // If this parameter is MH_ALL_HOOKS, all created hooks are 167 | // queued to be enabled. 168 | MH_STATUS WINAPI MH_QueueEnableHook(LPVOID pTarget); 169 | 170 | // Queues to disable an already created hook. 171 | // Parameters: 172 | // pTarget [in] A pointer to the target function. 173 | // If this parameter is MH_ALL_HOOKS, all created hooks are 174 | // queued to be disabled. 175 | MH_STATUS WINAPI MH_QueueDisableHook(LPVOID pTarget); 176 | 177 | // Applies all queued changes in one go. 178 | MH_STATUS WINAPI MH_ApplyQueued(VOID); 179 | 180 | // Translates the MH_STATUS to its name as a string. 181 | const char *WINAPI MH_StatusToString(MH_STATUS status); 182 | 183 | #ifdef __cplusplus 184 | } 185 | #endif 186 | -------------------------------------------------------------------------------- /third_party/minhook/src/buffer.c: -------------------------------------------------------------------------------- 1 | /* 2 | * MinHook - The Minimalistic API Hooking Library for x64/x86 3 | * Copyright (C) 2009-2017 Tsuda Kageyu. 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions 8 | * are met: 9 | * 10 | * 1. Redistributions of source code must retain the above copyright 11 | * notice, this list of conditions and the following disclaimer. 12 | * 2. Redistributions in binary form must reproduce the above copyright 13 | * notice, this list of conditions and the following disclaimer in the 14 | * documentation and/or other materials provided with the distribution. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 18 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 19 | * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER 20 | * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 21 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 22 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 23 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 24 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 25 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 26 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | */ 28 | 29 | #include <windows.h> 30 | #include "buffer.h" 31 | 32 | // Size of each memory block. (= page size of VirtualAlloc) 33 | #define MEMORY_BLOCK_SIZE 0x1000 34 | 35 | // Max range for seeking a memory block. (= 1024MB) 36 | #define MAX_MEMORY_RANGE 0x40000000 37 | 38 | // Memory protection flags to check the executable address. 39 | #define PAGE_EXECUTE_FLAGS \ 40 | (PAGE_EXECUTE | PAGE_EXECUTE_READ | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY) 41 | 42 | // Memory slot. 43 | typedef struct _MEMORY_SLOT 44 | { 45 | union 46 | { 47 | struct _MEMORY_SLOT *pNext; 48 | UINT8 buffer[MEMORY_SLOT_SIZE]; 49 | }; 50 | } MEMORY_SLOT, *PMEMORY_SLOT; 51 | 52 | // Memory block info. Placed at the head of each block. 53 | typedef struct _MEMORY_BLOCK 54 | { 55 | struct _MEMORY_BLOCK *pNext; 56 | PMEMORY_SLOT pFree; // First element of the free slot list. 57 | UINT usedCount; 58 | } MEMORY_BLOCK, *PMEMORY_BLOCK; 59 | 60 | //------------------------------------------------------------------------- 61 | // Global Variables: 62 | //------------------------------------------------------------------------- 63 | 64 | // First element of the memory block list. 65 | static PMEMORY_BLOCK g_pMemoryBlocks; 66 | 67 | //------------------------------------------------------------------------- 68 | VOID InitializeBuffer(VOID) 69 | { 70 | // Nothing to do for now. 71 | } 72 | 73 | //------------------------------------------------------------------------- 74 | VOID UninitializeBuffer(VOID) 75 | { 76 | PMEMORY_BLOCK pBlock = g_pMemoryBlocks; 77 | g_pMemoryBlocks = NULL; 78 | 79 | while (pBlock) 80 | { 81 | PMEMORY_BLOCK pNext = pBlock->pNext; 82 | VirtualFree(pBlock, 0, MEM_RELEASE); 83 | pBlock = pNext; 84 | } 85 | } 86 | 87 | //------------------------------------------------------------------------- 88 | #if defined(_M_X64) || defined(__x86_64__) 89 | static LPVOID FindPrevFreeRegion(LPVOID pAddress, LPVOID pMinAddr, DWORD dwAllocationGranularity) 90 | { 91 | ULONG_PTR tryAddr = (ULONG_PTR)pAddress; 92 | 93 | // Round down to the allocation granularity. 94 | tryAddr -= tryAddr % dwAllocationGranularity; 95 | 96 | // Start from the previous allocation granularity multiply. 97 | tryAddr -= dwAllocationGranularity; 98 | 99 | while (tryAddr >= (ULONG_PTR)pMinAddr) 100 | { 101 | MEMORY_BASIC_INFORMATION mbi; 102 | if (VirtualQuery((LPVOID)tryAddr, &mbi, sizeof(mbi)) == 0) 103 | break; 104 | 105 | if (mbi.State == MEM_FREE) 106 | return (LPVOID)tryAddr; 107 | 108 | if ((ULONG_PTR)mbi.AllocationBase < dwAllocationGranularity) 109 | break; 110 | 111 | tryAddr = (ULONG_PTR)mbi.AllocationBase - dwAllocationGranularity; 112 | } 113 | 114 | return NULL; 115 | } 116 | #endif 117 | 118 | //------------------------------------------------------------------------- 119 | #if defined(_M_X64) || defined(__x86_64__) 120 | static LPVOID FindNextFreeRegion(LPVOID pAddress, LPVOID pMaxAddr, DWORD dwAllocationGranularity) 121 | { 122 | ULONG_PTR tryAddr = (ULONG_PTR)pAddress; 123 | 124 | // Round down to the allocation granularity. 125 | tryAddr -= tryAddr % dwAllocationGranularity; 126 | 127 | // Start from the next allocation granularity multiply. 128 | tryAddr += dwAllocationGranularity; 129 | 130 | while (tryAddr <= (ULONG_PTR)pMaxAddr) 131 | { 132 | MEMORY_BASIC_INFORMATION mbi; 133 | if (VirtualQuery((LPVOID)tryAddr, &mbi, sizeof(mbi)) == 0) 134 | break; 135 | 136 | if (mbi.State == MEM_FREE) 137 | return (LPVOID)tryAddr; 138 | 139 | tryAddr = (ULONG_PTR)mbi.BaseAddress + mbi.RegionSize; 140 | 141 | // Round up to the next allocation granularity. 142 | tryAddr += dwAllocationGranularity - 1; 143 | tryAddr -= tryAddr % dwAllocationGranularity; 144 | } 145 | 146 | return NULL; 147 | } 148 | #endif 149 | 150 | //------------------------------------------------------------------------- 151 | static PMEMORY_BLOCK GetMemoryBlock(LPVOID pOrigin) 152 | { 153 | PMEMORY_BLOCK pBlock; 154 | #if defined(_M_X64) || defined(__x86_64__) 155 | ULONG_PTR minAddr; 156 | ULONG_PTR maxAddr; 157 | 158 | SYSTEM_INFO si; 159 | GetSystemInfo(&si); 160 | minAddr = (ULONG_PTR)si.lpMinimumApplicationAddress; 161 | maxAddr = (ULONG_PTR)si.lpMaximumApplicationAddress; 162 | 163 | // pOrigin ± 512MB 164 | if ((ULONG_PTR)pOrigin > MAX_MEMORY_RANGE && minAddr < (ULONG_PTR)pOrigin - MAX_MEMORY_RANGE) 165 | minAddr = (ULONG_PTR)pOrigin - MAX_MEMORY_RANGE; 166 | 167 | if (maxAddr > (ULONG_PTR)pOrigin + MAX_MEMORY_RANGE) 168 | maxAddr = (ULONG_PTR)pOrigin + MAX_MEMORY_RANGE; 169 | 170 | // Make room for MEMORY_BLOCK_SIZE bytes. 171 | maxAddr -= MEMORY_BLOCK_SIZE - 1; 172 | #endif 173 | 174 | // Look the registered blocks for a reachable one. 175 | for (pBlock = g_pMemoryBlocks; pBlock != NULL; pBlock = pBlock->pNext) 176 | { 177 | #if defined(_M_X64) || defined(__x86_64__) 178 | // Ignore the blocks too far. 179 | if ((ULONG_PTR)pBlock < minAddr || (ULONG_PTR)pBlock >= maxAddr) 180 | continue; 181 | #endif 182 | // The block has at least one unused slot. 183 | if (pBlock->pFree != NULL) 184 | return pBlock; 185 | } 186 | 187 | #if defined(_M_X64) || defined(__x86_64__) 188 | // Alloc a new block above if not found. 189 | { 190 | LPVOID pAlloc = pOrigin; 191 | while ((ULONG_PTR)pAlloc >= minAddr) 192 | { 193 | pAlloc = FindPrevFreeRegion(pAlloc, (LPVOID)minAddr, si.dwAllocationGranularity); 194 | if (pAlloc == NULL) 195 | break; 196 | 197 | pBlock = (PMEMORY_BLOCK)VirtualAlloc( 198 | pAlloc, MEMORY_BLOCK_SIZE, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); 199 | if (pBlock != NULL) 200 | break; 201 | } 202 | } 203 | 204 | // Alloc a new block below if not found. 205 | if (pBlock == NULL) 206 | { 207 | LPVOID pAlloc = pOrigin; 208 | while ((ULONG_PTR)pAlloc <= maxAddr) 209 | { 210 | pAlloc = FindNextFreeRegion(pAlloc, (LPVOID)maxAddr, si.dwAllocationGranularity); 211 | if (pAlloc == NULL) 212 | break; 213 | 214 | pBlock = (PMEMORY_BLOCK)VirtualAlloc( 215 | pAlloc, MEMORY_BLOCK_SIZE, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); 216 | if (pBlock != NULL) 217 | break; 218 | } 219 | } 220 | #else 221 | // In x86 mode, a memory block can be placed anywhere. 222 | pBlock = (PMEMORY_BLOCK)VirtualAlloc( 223 | NULL, MEMORY_BLOCK_SIZE, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); 224 | #endif 225 | 226 | if (pBlock != NULL) 227 | { 228 | // Build a linked list of all the slots. 229 | PMEMORY_SLOT pSlot = (PMEMORY_SLOT)pBlock + 1; 230 | pBlock->pFree = NULL; 231 | pBlock->usedCount = 0; 232 | do 233 | { 234 | pSlot->pNext = pBlock->pFree; 235 | pBlock->pFree = pSlot; 236 | pSlot++; 237 | } while ((ULONG_PTR)pSlot - (ULONG_PTR)pBlock <= MEMORY_BLOCK_SIZE - MEMORY_SLOT_SIZE); 238 | 239 | pBlock->pNext = g_pMemoryBlocks; 240 | g_pMemoryBlocks = pBlock; 241 | } 242 | 243 | return pBlock; 244 | } 245 | 246 | //------------------------------------------------------------------------- 247 | LPVOID AllocateBuffer(LPVOID pOrigin) 248 | { 249 | PMEMORY_SLOT pSlot; 250 | PMEMORY_BLOCK pBlock = GetMemoryBlock(pOrigin); 251 | if (pBlock == NULL) 252 | return NULL; 253 | 254 | // Remove an unused slot from the list. 255 | pSlot = pBlock->pFree; 256 | pBlock->pFree = pSlot->pNext; 257 | pBlock->usedCount++; 258 | #ifdef _DEBUG 259 | // Fill the slot with INT3 for debugging. 260 | memset(pSlot, 0xCC, sizeof(MEMORY_SLOT)); 261 | #endif 262 | return pSlot; 263 | } 264 | 265 | //------------------------------------------------------------------------- 266 | VOID FreeBuffer(LPVOID pBuffer) 267 | { 268 | PMEMORY_BLOCK pBlock = g_pMemoryBlocks; 269 | PMEMORY_BLOCK pPrev = NULL; 270 | ULONG_PTR pTargetBlock = ((ULONG_PTR)pBuffer / MEMORY_BLOCK_SIZE) * MEMORY_BLOCK_SIZE; 271 | 272 | while (pBlock != NULL) 273 | { 274 | if ((ULONG_PTR)pBlock == pTargetBlock) 275 | { 276 | PMEMORY_SLOT pSlot = (PMEMORY_SLOT)pBuffer; 277 | #ifdef _DEBUG 278 | // Clear the released slot for debugging. 279 | memset(pSlot, 0x00, sizeof(MEMORY_SLOT)); 280 | #endif 281 | // Restore the released slot to the list. 282 | pSlot->pNext = pBlock->pFree; 283 | pBlock->pFree = pSlot; 284 | pBlock->usedCount--; 285 | 286 | // Free if unused. 287 | if (pBlock->usedCount == 0) 288 | { 289 | if (pPrev) 290 | pPrev->pNext = pBlock->pNext; 291 | else 292 | g_pMemoryBlocks = pBlock->pNext; 293 | 294 | VirtualFree(pBlock, 0, MEM_RELEASE); 295 | } 296 | 297 | break; 298 | } 299 | 300 | pPrev = pBlock; 301 | pBlock = pBlock->pNext; 302 | } 303 | } 304 | 305 | //------------------------------------------------------------------------- 306 | BOOL IsExecutableAddress(LPVOID pAddress) 307 | { 308 | MEMORY_BASIC_INFORMATION mi; 309 | VirtualQuery(pAddress, &mi, sizeof(mi)); 310 | 311 | return (mi.State == MEM_COMMIT && (mi.Protect & PAGE_EXECUTE_FLAGS)); 312 | } 313 | -------------------------------------------------------------------------------- /third_party/minhook/src/buffer.h: -------------------------------------------------------------------------------- 1 | /* 2 | * MinHook - The Minimalistic API Hooking Library for x64/x86 3 | * Copyright (C) 2009-2017 Tsuda Kageyu. 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions 8 | * are met: 9 | * 10 | * 1. Redistributions of source code must retain the above copyright 11 | * notice, this list of conditions and the following disclaimer. 12 | * 2. Redistributions in binary form must reproduce the above copyright 13 | * notice, this list of conditions and the following disclaimer in the 14 | * documentation and/or other materials provided with the distribution. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 18 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 19 | * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER 20 | * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 21 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 22 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 23 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 24 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 25 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 26 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | */ 28 | 29 | #pragma once 30 | 31 | // Size of each memory slot. 32 | #if defined(_M_X64) || defined(__x86_64__) 33 | #define MEMORY_SLOT_SIZE 64 34 | #else 35 | #define MEMORY_SLOT_SIZE 32 36 | #endif 37 | 38 | VOID InitializeBuffer(VOID); 39 | VOID UninitializeBuffer(VOID); 40 | LPVOID AllocateBuffer(LPVOID pOrigin); 41 | VOID FreeBuffer(LPVOID pBuffer); 42 | BOOL IsExecutableAddress(LPVOID pAddress); 43 | -------------------------------------------------------------------------------- /third_party/minhook/src/hde/hde32.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Hacker Disassembler Engine 32 C 3 | * Copyright (c) 2008-2009, Vyacheslav Patkov. 4 | * All rights reserved. 5 | * 6 | */ 7 | 8 | #if defined(_M_IX86) || defined(__i386__) 9 | 10 | #include <string.h> 11 | #include "hde32.h" 12 | #include "table32.h" 13 | 14 | unsigned int hde32_disasm(const void *code, hde32s *hs) 15 | { 16 | uint8_t x, c, *p = (uint8_t *)code, cflags, opcode, pref = 0; 17 | uint8_t *ht = hde32_table, m_mod, m_reg, m_rm, disp_size = 0; 18 | 19 | memset(hs, 0, sizeof(hde32s)); 20 | 21 | for (x = 16; x; x--) 22 | switch (c = *p++) { 23 | case 0xf3: 24 | hs->p_rep = c; 25 | pref |= PRE_F3; 26 | break; 27 | case 0xf2: 28 | hs->p_rep = c; 29 | pref |= PRE_F2; 30 | break; 31 | case 0xf0: 32 | hs->p_lock = c; 33 | pref |= PRE_LOCK; 34 | break; 35 | case 0x26: case 0x2e: case 0x36: 36 | case 0x3e: case 0x64: case 0x65: 37 | hs->p_seg = c; 38 | pref |= PRE_SEG; 39 | break; 40 | case 0x66: 41 | hs->p_66 = c; 42 | pref |= PRE_66; 43 | break; 44 | case 0x67: 45 | hs->p_67 = c; 46 | pref |= PRE_67; 47 | break; 48 | default: 49 | goto pref_done; 50 | } 51 | pref_done: 52 | 53 | hs->flags = (uint32_t)pref << 23; 54 | 55 | if (!pref) 56 | pref |= PRE_NONE; 57 | 58 | if ((hs->opcode = c) == 0x0f) { 59 | hs->opcode2 = c = *p++; 60 | ht += DELTA_OPCODES; 61 | } else if (c >= 0xa0 && c <= 0xa3) { 62 | if (pref & PRE_67) 63 | pref |= PRE_66; 64 | else 65 | pref &= ~PRE_66; 66 | } 67 | 68 | opcode = c; 69 | cflags = ht[ht[opcode / 4] + (opcode % 4)]; 70 | 71 | if (cflags == C_ERROR) { 72 | hs->flags |= F_ERROR | F_ERROR_OPCODE; 73 | cflags = 0; 74 | if ((opcode & -3) == 0x24) 75 | cflags++; 76 | } 77 | 78 | x = 0; 79 | if (cflags & C_GROUP) { 80 | uint16_t t; 81 | t = *(uint16_t *)(ht + (cflags & 0x7f)); 82 | cflags = (uint8_t)t; 83 | x = (uint8_t)(t >> 8); 84 | } 85 | 86 | if (hs->opcode2) { 87 | ht = hde32_table + DELTA_PREFIXES; 88 | if (ht[ht[opcode / 4] + (opcode % 4)] & pref) 89 | hs->flags |= F_ERROR | F_ERROR_OPCODE; 90 | } 91 | 92 | if (cflags & C_MODRM) { 93 | hs->flags |= F_MODRM; 94 | hs->modrm = c = *p++; 95 | hs->modrm_mod = m_mod = c >> 6; 96 | hs->modrm_rm = m_rm = c & 7; 97 | hs->modrm_reg = m_reg = (c & 0x3f) >> 3; 98 | 99 | if (x && ((x << m_reg) & 0x80)) 100 | hs->flags |= F_ERROR | F_ERROR_OPCODE; 101 | 102 | if (!hs->opcode2 && opcode >= 0xd9 && opcode <= 0xdf) { 103 | uint8_t t = opcode - 0xd9; 104 | if (m_mod == 3) { 105 | ht = hde32_table + DELTA_FPU_MODRM + t*8; 106 | t = ht[m_reg] << m_rm; 107 | } else { 108 | ht = hde32_table + DELTA_FPU_REG; 109 | t = ht[t] << m_reg; 110 | } 111 | if (t & 0x80) 112 | hs->flags |= F_ERROR | F_ERROR_OPCODE; 113 | } 114 | 115 | if (pref & PRE_LOCK) { 116 | if (m_mod == 3) { 117 | hs->flags |= F_ERROR | F_ERROR_LOCK; 118 | } else { 119 | uint8_t *table_end, op = opcode; 120 | if (hs->opcode2) { 121 | ht = hde32_table + DELTA_OP2_LOCK_OK; 122 | table_end = ht + DELTA_OP_ONLY_MEM - DELTA_OP2_LOCK_OK; 123 | } else { 124 | ht = hde32_table + DELTA_OP_LOCK_OK; 125 | table_end = ht + DELTA_OP2_LOCK_OK - DELTA_OP_LOCK_OK; 126 | op &= -2; 127 | } 128 | for (; ht != table_end; ht++) 129 | if (*ht++ == op) { 130 | if (!((*ht << m_reg) & 0x80)) 131 | goto no_lock_error; 132 | else 133 | break; 134 | } 135 | hs->flags |= F_ERROR | F_ERROR_LOCK; 136 | no_lock_error: 137 | ; 138 | } 139 | } 140 | 141 | if (hs->opcode2) { 142 | switch (opcode) { 143 | case 0x20: case 0x22: 144 | m_mod = 3; 145 | if (m_reg > 4 || m_reg == 1) 146 | goto error_operand; 147 | else 148 | goto no_error_operand; 149 | case 0x21: case 0x23: 150 | m_mod = 3; 151 | if (m_reg == 4 || m_reg == 5) 152 | goto error_operand; 153 | else 154 | goto no_error_operand; 155 | } 156 | } else { 157 | switch (opcode) { 158 | case 0x8c: 159 | if (m_reg > 5) 160 | goto error_operand; 161 | else 162 | goto no_error_operand; 163 | case 0x8e: 164 | if (m_reg == 1 || m_reg > 5) 165 | goto error_operand; 166 | else 167 | goto no_error_operand; 168 | } 169 | } 170 | 171 | if (m_mod == 3) { 172 | uint8_t *table_end; 173 | if (hs->opcode2) { 174 | ht = hde32_table + DELTA_OP2_ONLY_MEM; 175 | table_end = ht + sizeof(hde32_table) - DELTA_OP2_ONLY_MEM; 176 | } else { 177 | ht = hde32_table + DELTA_OP_ONLY_MEM; 178 | table_end = ht + DELTA_OP2_ONLY_MEM - DELTA_OP_ONLY_MEM; 179 | } 180 | for (; ht != table_end; ht += 2) 181 | if (*ht++ == opcode) { 182 | if ((*ht++ & pref) && !((*ht << m_reg) & 0x80)) 183 | goto error_operand; 184 | else 185 | break; 186 | } 187 | goto no_error_operand; 188 | } else if (hs->opcode2) { 189 | switch (opcode) { 190 | case 0x50: case 0xd7: case 0xf7: 191 | if (pref & (PRE_NONE | PRE_66)) 192 | goto error_operand; 193 | break; 194 | case 0xd6: 195 | if (pref & (PRE_F2 | PRE_F3)) 196 | goto error_operand; 197 | break; 198 | case 0xc5: 199 | goto error_operand; 200 | } 201 | goto no_error_operand; 202 | } else 203 | goto no_error_operand; 204 | 205 | error_operand: 206 | hs->flags |= F_ERROR | F_ERROR_OPERAND; 207 | no_error_operand: 208 | 209 | c = *p++; 210 | if (m_reg <= 1) { 211 | if (opcode == 0xf6) 212 | cflags |= C_IMM8; 213 | else if (opcode == 0xf7) 214 | cflags |= C_IMM_P66; 215 | } 216 | 217 | switch (m_mod) { 218 | case 0: 219 | if (pref & PRE_67) { 220 | if (m_rm == 6) 221 | disp_size = 2; 222 | } else 223 | if (m_rm == 5) 224 | disp_size = 4; 225 | break; 226 | case 1: 227 | disp_size = 1; 228 | break; 229 | case 2: 230 | disp_size = 2; 231 | if (!(pref & PRE_67)) 232 | disp_size <<= 1; 233 | break; 234 | } 235 | 236 | if (m_mod != 3 && m_rm == 4 && !(pref & PRE_67)) { 237 | hs->flags |= F_SIB; 238 | p++; 239 | hs->sib = c; 240 | hs->sib_scale = c >> 6; 241 | hs->sib_index = (c & 0x3f) >> 3; 242 | if ((hs->sib_base = c & 7) == 5 && !(m_mod & 1)) 243 | disp_size = 4; 244 | } 245 | 246 | p--; 247 | switch (disp_size) { 248 | case 1: 249 | hs->flags |= F_DISP8; 250 | hs->disp.disp8 = *p; 251 | break; 252 | case 2: 253 | hs->flags |= F_DISP16; 254 | hs->disp.disp16 = *(uint16_t *)p; 255 | break; 256 | case 4: 257 | hs->flags |= F_DISP32; 258 | hs->disp.disp32 = *(uint32_t *)p; 259 | break; 260 | } 261 | p += disp_size; 262 | } else if (pref & PRE_LOCK) 263 | hs->flags |= F_ERROR | F_ERROR_LOCK; 264 | 265 | if (cflags & C_IMM_P66) { 266 | if (cflags & C_REL32) { 267 | if (pref & PRE_66) { 268 | hs->flags |= F_IMM16 | F_RELATIVE; 269 | hs->imm.imm16 = *(uint16_t *)p; 270 | p += 2; 271 | goto disasm_done; 272 | } 273 | goto rel32_ok; 274 | } 275 | if (pref & PRE_66) { 276 | hs->flags |= F_IMM16; 277 | hs->imm.imm16 = *(uint16_t *)p; 278 | p += 2; 279 | } else { 280 | hs->flags |= F_IMM32; 281 | hs->imm.imm32 = *(uint32_t *)p; 282 | p += 4; 283 | } 284 | } 285 | 286 | if (cflags & C_IMM16) { 287 | if (hs->flags & F_IMM32) { 288 | hs->flags |= F_IMM16; 289 | hs->disp.disp16 = *(uint16_t *)p; 290 | } else if (hs->flags & F_IMM16) { 291 | hs->flags |= F_2IMM16; 292 | hs->disp.disp16 = *(uint16_t *)p; 293 | } else { 294 | hs->flags |= F_IMM16; 295 | hs->imm.imm16 = *(uint16_t *)p; 296 | } 297 | p += 2; 298 | } 299 | if (cflags & C_IMM8) { 300 | hs->flags |= F_IMM8; 301 | hs->imm.imm8 = *p++; 302 | } 303 | 304 | if (cflags & C_REL32) { 305 | rel32_ok: 306 | hs->flags |= F_IMM32 | F_RELATIVE; 307 | hs->imm.imm32 = *(uint32_t *)p; 308 | p += 4; 309 | } else if (cflags & C_REL8) { 310 | hs->flags |= F_IMM8 | F_RELATIVE; 311 | hs->imm.imm8 = *p++; 312 | } 313 | 314 | disasm_done: 315 | 316 | if ((hs->len = (uint8_t)(p-(uint8_t *)code)) > 15) { 317 | hs->flags |= F_ERROR | F_ERROR_LENGTH; 318 | hs->len = 15; 319 | } 320 | 321 | return (unsigned int)hs->len; 322 | } 323 | 324 | #endif // defined(_M_IX86) || defined(__i386__) 325 | -------------------------------------------------------------------------------- /third_party/minhook/src/hde/hde32.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Hacker Disassembler Engine 32 3 | * Copyright (c) 2006-2009, Vyacheslav Patkov. 4 | * All rights reserved. 5 | * 6 | * hde32.h: C/C++ header file 7 | * 8 | */ 9 | 10 | #ifndef _HDE32_H_ 11 | #define _HDE32_H_ 12 | 13 | /* stdint.h - C99 standard header 14 | * http://en.wikipedia.org/wiki/stdint.h 15 | * 16 | * if your compiler doesn't contain "stdint.h" header (for 17 | * example, Microsoft Visual C++), you can download file: 18 | * http://www.azillionmonkeys.com/qed/pstdint.h 19 | * and change next line to: 20 | * #include "pstdint.h" 21 | */ 22 | #include "pstdint.h" 23 | 24 | #define F_MODRM 0x00000001 25 | #define F_SIB 0x00000002 26 | #define F_IMM8 0x00000004 27 | #define F_IMM16 0x00000008 28 | #define F_IMM32 0x00000010 29 | #define F_DISP8 0x00000020 30 | #define F_DISP16 0x00000040 31 | #define F_DISP32 0x00000080 32 | #define F_RELATIVE 0x00000100 33 | #define F_2IMM16 0x00000800 34 | #define F_ERROR 0x00001000 35 | #define F_ERROR_OPCODE 0x00002000 36 | #define F_ERROR_LENGTH 0x00004000 37 | #define F_ERROR_LOCK 0x00008000 38 | #define F_ERROR_OPERAND 0x00010000 39 | #define F_PREFIX_REPNZ 0x01000000 40 | #define F_PREFIX_REPX 0x02000000 41 | #define F_PREFIX_REP 0x03000000 42 | #define F_PREFIX_66 0x04000000 43 | #define F_PREFIX_67 0x08000000 44 | #define F_PREFIX_LOCK 0x10000000 45 | #define F_PREFIX_SEG 0x20000000 46 | #define F_PREFIX_ANY 0x3f000000 47 | 48 | #define PREFIX_SEGMENT_CS 0x2e 49 | #define PREFIX_SEGMENT_SS 0x36 50 | #define PREFIX_SEGMENT_DS 0x3e 51 | #define PREFIX_SEGMENT_ES 0x26 52 | #define PREFIX_SEGMENT_FS 0x64 53 | #define PREFIX_SEGMENT_GS 0x65 54 | #define PREFIX_LOCK 0xf0 55 | #define PREFIX_REPNZ 0xf2 56 | #define PREFIX_REPX 0xf3 57 | #define PREFIX_OPERAND_SIZE 0x66 58 | #define PREFIX_ADDRESS_SIZE 0x67 59 | 60 | #pragma pack(push,1) 61 | 62 | typedef struct { 63 | uint8_t len; 64 | uint8_t p_rep; 65 | uint8_t p_lock; 66 | uint8_t p_seg; 67 | uint8_t p_66; 68 | uint8_t p_67; 69 | uint8_t opcode; 70 | uint8_t opcode2; 71 | uint8_t modrm; 72 | uint8_t modrm_mod; 73 | uint8_t modrm_reg; 74 | uint8_t modrm_rm; 75 | uint8_t sib; 76 | uint8_t sib_scale; 77 | uint8_t sib_index; 78 | uint8_t sib_base; 79 | union { 80 | uint8_t imm8; 81 | uint16_t imm16; 82 | uint32_t imm32; 83 | } imm; 84 | union { 85 | uint8_t disp8; 86 | uint16_t disp16; 87 | uint32_t disp32; 88 | } disp; 89 | uint32_t flags; 90 | } hde32s; 91 | 92 | #pragma pack(pop) 93 | 94 | #ifdef __cplusplus 95 | extern "C" { 96 | #endif 97 | 98 | /* __cdecl */ 99 | unsigned int hde32_disasm(const void *code, hde32s *hs); 100 | 101 | #ifdef __cplusplus 102 | } 103 | #endif 104 | 105 | #endif /* _HDE32_H_ */ 106 | -------------------------------------------------------------------------------- /third_party/minhook/src/hde/hde64.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Hacker Disassembler Engine 64 C 3 | * Copyright (c) 2008-2009, Vyacheslav Patkov. 4 | * All rights reserved. 5 | * 6 | */ 7 | 8 | #if defined(_M_X64) || defined(__x86_64__) 9 | 10 | #include <string.h> 11 | #include "hde64.h" 12 | #include "table64.h" 13 | 14 | unsigned int hde64_disasm(const void *code, hde64s *hs) 15 | { 16 | uint8_t x, c, *p = (uint8_t *)code, cflags, opcode, pref = 0; 17 | uint8_t *ht = hde64_table, m_mod, m_reg, m_rm, disp_size = 0; 18 | uint8_t op64 = 0; 19 | 20 | memset(hs, 0, sizeof(hde64s)); 21 | 22 | for (x = 16; x; x--) 23 | switch (c = *p++) { 24 | case 0xf3: 25 | hs->p_rep = c; 26 | pref |= PRE_F3; 27 | break; 28 | case 0xf2: 29 | hs->p_rep = c; 30 | pref |= PRE_F2; 31 | break; 32 | case 0xf0: 33 | hs->p_lock = c; 34 | pref |= PRE_LOCK; 35 | break; 36 | case 0x26: case 0x2e: case 0x36: 37 | case 0x3e: case 0x64: case 0x65: 38 | hs->p_seg = c; 39 | pref |= PRE_SEG; 40 | break; 41 | case 0x66: 42 | hs->p_66 = c; 43 | pref |= PRE_66; 44 | break; 45 | case 0x67: 46 | hs->p_67 = c; 47 | pref |= PRE_67; 48 | break; 49 | default: 50 | goto pref_done; 51 | } 52 | pref_done: 53 | 54 | hs->flags = (uint32_t)pref << 23; 55 | 56 | if (!pref) 57 | pref |= PRE_NONE; 58 | 59 | if ((c & 0xf0) == 0x40) { 60 | hs->flags |= F_PREFIX_REX; 61 | if ((hs->rex_w = (c & 0xf) >> 3) && (*p & 0xf8) == 0xb8) 62 | op64++; 63 | hs->rex_r = (c & 7) >> 2; 64 | hs->rex_x = (c & 3) >> 1; 65 | hs->rex_b = c & 1; 66 | if (((c = *p++) & 0xf0) == 0x40) { 67 | opcode = c; 68 | goto error_opcode; 69 | } 70 | } 71 | 72 | if ((hs->opcode = c) == 0x0f) { 73 | hs->opcode2 = c = *p++; 74 | ht += DELTA_OPCODES; 75 | } else if (c >= 0xa0 && c <= 0xa3) { 76 | op64++; 77 | if (pref & PRE_67) 78 | pref |= PRE_66; 79 | else 80 | pref &= ~PRE_66; 81 | } 82 | 83 | opcode = c; 84 | cflags = ht[ht[opcode / 4] + (opcode % 4)]; 85 | 86 | if (cflags == C_ERROR) { 87 | error_opcode: 88 | hs->flags |= F_ERROR | F_ERROR_OPCODE; 89 | cflags = 0; 90 | if ((opcode & -3) == 0x24) 91 | cflags++; 92 | } 93 | 94 | x = 0; 95 | if (cflags & C_GROUP) { 96 | uint16_t t; 97 | t = *(uint16_t *)(ht + (cflags & 0x7f)); 98 | cflags = (uint8_t)t; 99 | x = (uint8_t)(t >> 8); 100 | } 101 | 102 | if (hs->opcode2) { 103 | ht = hde64_table + DELTA_PREFIXES; 104 | if (ht[ht[opcode / 4] + (opcode % 4)] & pref) 105 | hs->flags |= F_ERROR | F_ERROR_OPCODE; 106 | } 107 | 108 | if (cflags & C_MODRM) { 109 | hs->flags |= F_MODRM; 110 | hs->modrm = c = *p++; 111 | hs->modrm_mod = m_mod = c >> 6; 112 | hs->modrm_rm = m_rm = c & 7; 113 | hs->modrm_reg = m_reg = (c & 0x3f) >> 3; 114 | 115 | if (x && ((x << m_reg) & 0x80)) 116 | hs->flags |= F_ERROR | F_ERROR_OPCODE; 117 | 118 | if (!hs->opcode2 && opcode >= 0xd9 && opcode <= 0xdf) { 119 | uint8_t t = opcode - 0xd9; 120 | if (m_mod == 3) { 121 | ht = hde64_table + DELTA_FPU_MODRM + t*8; 122 | t = ht[m_reg] << m_rm; 123 | } else { 124 | ht = hde64_table + DELTA_FPU_REG; 125 | t = ht[t] << m_reg; 126 | } 127 | if (t & 0x80) 128 | hs->flags |= F_ERROR | F_ERROR_OPCODE; 129 | } 130 | 131 | if (pref & PRE_LOCK) { 132 | if (m_mod == 3) { 133 | hs->flags |= F_ERROR | F_ERROR_LOCK; 134 | } else { 135 | uint8_t *table_end, op = opcode; 136 | if (hs->opcode2) { 137 | ht = hde64_table + DELTA_OP2_LOCK_OK; 138 | table_end = ht + DELTA_OP_ONLY_MEM - DELTA_OP2_LOCK_OK; 139 | } else { 140 | ht = hde64_table + DELTA_OP_LOCK_OK; 141 | table_end = ht + DELTA_OP2_LOCK_OK - DELTA_OP_LOCK_OK; 142 | op &= -2; 143 | } 144 | for (; ht != table_end; ht++) 145 | if (*ht++ == op) { 146 | if (!((*ht << m_reg) & 0x80)) 147 | goto no_lock_error; 148 | else 149 | break; 150 | } 151 | hs->flags |= F_ERROR | F_ERROR_LOCK; 152 | no_lock_error: 153 | ; 154 | } 155 | } 156 | 157 | if (hs->opcode2) { 158 | switch (opcode) { 159 | case 0x20: case 0x22: 160 | m_mod = 3; 161 | if (m_reg > 4 || m_reg == 1) 162 | goto error_operand; 163 | else 164 | goto no_error_operand; 165 | case 0x21: case 0x23: 166 | m_mod = 3; 167 | if (m_reg == 4 || m_reg == 5) 168 | goto error_operand; 169 | else 170 | goto no_error_operand; 171 | } 172 | } else { 173 | switch (opcode) { 174 | case 0x8c: 175 | if (m_reg > 5) 176 | goto error_operand; 177 | else 178 | goto no_error_operand; 179 | case 0x8e: 180 | if (m_reg == 1 || m_reg > 5) 181 | goto error_operand; 182 | else 183 | goto no_error_operand; 184 | } 185 | } 186 | 187 | if (m_mod == 3) { 188 | uint8_t *table_end; 189 | if (hs->opcode2) { 190 | ht = hde64_table + DELTA_OP2_ONLY_MEM; 191 | table_end = ht + sizeof(hde64_table) - DELTA_OP2_ONLY_MEM; 192 | } else { 193 | ht = hde64_table + DELTA_OP_ONLY_MEM; 194 | table_end = ht + DELTA_OP2_ONLY_MEM - DELTA_OP_ONLY_MEM; 195 | } 196 | for (; ht != table_end; ht += 2) 197 | if (*ht++ == opcode) { 198 | if ((*ht++ & pref) && !((*ht << m_reg) & 0x80)) 199 | goto error_operand; 200 | else 201 | break; 202 | } 203 | goto no_error_operand; 204 | } else if (hs->opcode2) { 205 | switch (opcode) { 206 | case 0x50: case 0xd7: case 0xf7: 207 | if (pref & (PRE_NONE | PRE_66)) 208 | goto error_operand; 209 | break; 210 | case 0xd6: 211 | if (pref & (PRE_F2 | PRE_F3)) 212 | goto error_operand; 213 | break; 214 | case 0xc5: 215 | goto error_operand; 216 | } 217 | goto no_error_operand; 218 | } else 219 | goto no_error_operand; 220 | 221 | error_operand: 222 | hs->flags |= F_ERROR | F_ERROR_OPERAND; 223 | no_error_operand: 224 | 225 | c = *p++; 226 | if (m_reg <= 1) { 227 | if (opcode == 0xf6) 228 | cflags |= C_IMM8; 229 | else if (opcode == 0xf7) 230 | cflags |= C_IMM_P66; 231 | } 232 | 233 | switch (m_mod) { 234 | case 0: 235 | if (pref & PRE_67) { 236 | if (m_rm == 6) 237 | disp_size = 2; 238 | } else 239 | if (m_rm == 5) 240 | disp_size = 4; 241 | break; 242 | case 1: 243 | disp_size = 1; 244 | break; 245 | case 2: 246 | disp_size = 2; 247 | if (!(pref & PRE_67)) 248 | disp_size <<= 1; 249 | break; 250 | } 251 | 252 | if (m_mod != 3 && m_rm == 4) { 253 | hs->flags |= F_SIB; 254 | p++; 255 | hs->sib = c; 256 | hs->sib_scale = c >> 6; 257 | hs->sib_index = (c & 0x3f) >> 3; 258 | if ((hs->sib_base = c & 7) == 5 && !(m_mod & 1)) 259 | disp_size = 4; 260 | } 261 | 262 | p--; 263 | switch (disp_size) { 264 | case 1: 265 | hs->flags |= F_DISP8; 266 | hs->disp.disp8 = *p; 267 | break; 268 | case 2: 269 | hs->flags |= F_DISP16; 270 | hs->disp.disp16 = *(uint16_t *)p; 271 | break; 272 | case 4: 273 | hs->flags |= F_DISP32; 274 | hs->disp.disp32 = *(uint32_t *)p; 275 | break; 276 | } 277 | p += disp_size; 278 | } else if (pref & PRE_LOCK) 279 | hs->flags |= F_ERROR | F_ERROR_LOCK; 280 | 281 | if (cflags & C_IMM_P66) { 282 | if (cflags & C_REL32) { 283 | if (pref & PRE_66) { 284 | hs->flags |= F_IMM16 | F_RELATIVE; 285 | hs->imm.imm16 = *(uint16_t *)p; 286 | p += 2; 287 | goto disasm_done; 288 | } 289 | goto rel32_ok; 290 | } 291 | if (op64) { 292 | hs->flags |= F_IMM64; 293 | hs->imm.imm64 = *(uint64_t *)p; 294 | p += 8; 295 | } else if (!(pref & PRE_66)) { 296 | hs->flags |= F_IMM32; 297 | hs->imm.imm32 = *(uint32_t *)p; 298 | p += 4; 299 | } else 300 | goto imm16_ok; 301 | } 302 | 303 | 304 | if (cflags & C_IMM16) { 305 | imm16_ok: 306 | hs->flags |= F_IMM16; 307 | hs->imm.imm16 = *(uint16_t *)p; 308 | p += 2; 309 | } 310 | if (cflags & C_IMM8) { 311 | hs->flags |= F_IMM8; 312 | hs->imm.imm8 = *p++; 313 | } 314 | 315 | if (cflags & C_REL32) { 316 | rel32_ok: 317 | hs->flags |= F_IMM32 | F_RELATIVE; 318 | hs->imm.imm32 = *(uint32_t *)p; 319 | p += 4; 320 | } else if (cflags & C_REL8) { 321 | hs->flags |= F_IMM8 | F_RELATIVE; 322 | hs->imm.imm8 = *p++; 323 | } 324 | 325 | disasm_done: 326 | 327 | if ((hs->len = (uint8_t)(p-(uint8_t *)code)) > 15) { 328 | hs->flags |= F_ERROR | F_ERROR_LENGTH; 329 | hs->len = 15; 330 | } 331 | 332 | return (unsigned int)hs->len; 333 | } 334 | 335 | #endif // defined(_M_X64) || defined(__x86_64__) 336 | -------------------------------------------------------------------------------- /third_party/minhook/src/hde/hde64.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Hacker Disassembler Engine 64 3 | * Copyright (c) 2008-2009, Vyacheslav Patkov. 4 | * All rights reserved. 5 | * 6 | * hde64.h: C/C++ header file 7 | * 8 | */ 9 | 10 | #ifndef _HDE64_H_ 11 | #define _HDE64_H_ 12 | 13 | /* stdint.h - C99 standard header 14 | * http://en.wikipedia.org/wiki/stdint.h 15 | * 16 | * if your compiler doesn't contain "stdint.h" header (for 17 | * example, Microsoft Visual C++), you can download file: 18 | * http://www.azillionmonkeys.com/qed/pstdint.h 19 | * and change next line to: 20 | * #include "pstdint.h" 21 | */ 22 | #include "pstdint.h" 23 | 24 | #define F_MODRM 0x00000001 25 | #define F_SIB 0x00000002 26 | #define F_IMM8 0x00000004 27 | #define F_IMM16 0x00000008 28 | #define F_IMM32 0x00000010 29 | #define F_IMM64 0x00000020 30 | #define F_DISP8 0x00000040 31 | #define F_DISP16 0x00000080 32 | #define F_DISP32 0x00000100 33 | #define F_RELATIVE 0x00000200 34 | #define F_ERROR 0x00001000 35 | #define F_ERROR_OPCODE 0x00002000 36 | #define F_ERROR_LENGTH 0x00004000 37 | #define F_ERROR_LOCK 0x00008000 38 | #define F_ERROR_OPERAND 0x00010000 39 | #define F_PREFIX_REPNZ 0x01000000 40 | #define F_PREFIX_REPX 0x02000000 41 | #define F_PREFIX_REP 0x03000000 42 | #define F_PREFIX_66 0x04000000 43 | #define F_PREFIX_67 0x08000000 44 | #define F_PREFIX_LOCK 0x10000000 45 | #define F_PREFIX_SEG 0x20000000 46 | #define F_PREFIX_REX 0x40000000 47 | #define F_PREFIX_ANY 0x7f000000 48 | 49 | #define PREFIX_SEGMENT_CS 0x2e 50 | #define PREFIX_SEGMENT_SS 0x36 51 | #define PREFIX_SEGMENT_DS 0x3e 52 | #define PREFIX_SEGMENT_ES 0x26 53 | #define PREFIX_SEGMENT_FS 0x64 54 | #define PREFIX_SEGMENT_GS 0x65 55 | #define PREFIX_LOCK 0xf0 56 | #define PREFIX_REPNZ 0xf2 57 | #define PREFIX_REPX 0xf3 58 | #define PREFIX_OPERAND_SIZE 0x66 59 | #define PREFIX_ADDRESS_SIZE 0x67 60 | 61 | #pragma pack(push,1) 62 | 63 | typedef struct { 64 | uint8_t len; 65 | uint8_t p_rep; 66 | uint8_t p_lock; 67 | uint8_t p_seg; 68 | uint8_t p_66; 69 | uint8_t p_67; 70 | uint8_t rex; 71 | uint8_t rex_w; 72 | uint8_t rex_r; 73 | uint8_t rex_x; 74 | uint8_t rex_b; 75 | uint8_t opcode; 76 | uint8_t opcode2; 77 | uint8_t modrm; 78 | uint8_t modrm_mod; 79 | uint8_t modrm_reg; 80 | uint8_t modrm_rm; 81 | uint8_t sib; 82 | uint8_t sib_scale; 83 | uint8_t sib_index; 84 | uint8_t sib_base; 85 | union { 86 | uint8_t imm8; 87 | uint16_t imm16; 88 | uint32_t imm32; 89 | uint64_t imm64; 90 | } imm; 91 | union { 92 | uint8_t disp8; 93 | uint16_t disp16; 94 | uint32_t disp32; 95 | } disp; 96 | uint32_t flags; 97 | } hde64s; 98 | 99 | #pragma pack(pop) 100 | 101 | #ifdef __cplusplus 102 | extern "C" { 103 | #endif 104 | 105 | /* __cdecl */ 106 | unsigned int hde64_disasm(const void *code, hde64s *hs); 107 | 108 | #ifdef __cplusplus 109 | } 110 | #endif 111 | 112 | #endif /* _HDE64_H_ */ 113 | -------------------------------------------------------------------------------- /third_party/minhook/src/hde/pstdint.h: -------------------------------------------------------------------------------- 1 | /* 2 | * MinHook - The Minimalistic API Hooking Library for x64/x86 3 | * Copyright (C) 2009-2017 Tsuda Kageyu. All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions 7 | * are met: 8 | * 9 | * 1. Redistributions of source code must retain the above copyright 10 | * notice, this list of conditions and the following disclaimer. 11 | * 2. Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in the 13 | * documentation and/or other materials provided with the distribution. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR 16 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | #pragma once 28 | 29 | #include <windows.h> 30 | 31 | // Integer types for HDE. 32 | typedef INT8 int8_t; 33 | typedef INT16 int16_t; 34 | typedef INT32 int32_t; 35 | typedef INT64 int64_t; 36 | typedef UINT8 uint8_t; 37 | typedef UINT16 uint16_t; 38 | typedef UINT32 uint32_t; 39 | typedef UINT64 uint64_t; 40 | -------------------------------------------------------------------------------- /third_party/minhook/src/hde/table32.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Hacker Disassembler Engine 32 C 3 | * Copyright (c) 2008-2009, Vyacheslav Patkov. 4 | * All rights reserved. 5 | * 6 | */ 7 | 8 | #define C_NONE 0x00 9 | #define C_MODRM 0x01 10 | #define C_IMM8 0x02 11 | #define C_IMM16 0x04 12 | #define C_IMM_P66 0x10 13 | #define C_REL8 0x20 14 | #define C_REL32 0x40 15 | #define C_GROUP 0x80 16 | #define C_ERROR 0xff 17 | 18 | #define PRE_ANY 0x00 19 | #define PRE_NONE 0x01 20 | #define PRE_F2 0x02 21 | #define PRE_F3 0x04 22 | #define PRE_66 0x08 23 | #define PRE_67 0x10 24 | #define PRE_LOCK 0x20 25 | #define PRE_SEG 0x40 26 | #define PRE_ALL 0xff 27 | 28 | #define DELTA_OPCODES 0x4a 29 | #define DELTA_FPU_REG 0xf1 30 | #define DELTA_FPU_MODRM 0xf8 31 | #define DELTA_PREFIXES 0x130 32 | #define DELTA_OP_LOCK_OK 0x1a1 33 | #define DELTA_OP2_LOCK_OK 0x1b9 34 | #define DELTA_OP_ONLY_MEM 0x1cb 35 | #define DELTA_OP2_ONLY_MEM 0x1da 36 | 37 | unsigned char hde32_table[] = { 38 | 0xa3,0xa8,0xa3,0xa8,0xa3,0xa8,0xa3,0xa8,0xa3,0xa8,0xa3,0xa8,0xa3,0xa8,0xa3, 39 | 0xa8,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xac,0xaa,0xb2,0xaa,0x9f,0x9f, 40 | 0x9f,0x9f,0xb5,0xa3,0xa3,0xa4,0xaa,0xaa,0xba,0xaa,0x96,0xaa,0xa8,0xaa,0xc3, 41 | 0xc3,0x96,0x96,0xb7,0xae,0xd6,0xbd,0xa3,0xc5,0xa3,0xa3,0x9f,0xc3,0x9c,0xaa, 42 | 0xaa,0xac,0xaa,0xbf,0x03,0x7f,0x11,0x7f,0x01,0x7f,0x01,0x3f,0x01,0x01,0x90, 43 | 0x82,0x7d,0x97,0x59,0x59,0x59,0x59,0x59,0x7f,0x59,0x59,0x60,0x7d,0x7f,0x7f, 44 | 0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x9a,0x88,0x7d, 45 | 0x59,0x50,0x50,0x50,0x50,0x59,0x59,0x59,0x59,0x61,0x94,0x61,0x9e,0x59,0x59, 46 | 0x85,0x59,0x92,0xa3,0x60,0x60,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59, 47 | 0x59,0x59,0x9f,0x01,0x03,0x01,0x04,0x03,0xd5,0x03,0xcc,0x01,0xbc,0x03,0xf0, 48 | 0x10,0x10,0x10,0x10,0x50,0x50,0x50,0x50,0x14,0x20,0x20,0x20,0x20,0x01,0x01, 49 | 0x01,0x01,0xc4,0x02,0x10,0x00,0x00,0x00,0x00,0x01,0x01,0xc0,0xc2,0x10,0x11, 50 | 0x02,0x03,0x11,0x03,0x03,0x04,0x00,0x00,0x14,0x00,0x02,0x00,0x00,0xc6,0xc8, 51 | 0x02,0x02,0x02,0x02,0x00,0x00,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0xff,0xca, 52 | 0x01,0x01,0x01,0x00,0x06,0x00,0x04,0x00,0xc0,0xc2,0x01,0x01,0x03,0x01,0xff, 53 | 0xff,0x01,0x00,0x03,0xc4,0xc4,0xc6,0x03,0x01,0x01,0x01,0xff,0x03,0x03,0x03, 54 | 0xc8,0x40,0x00,0x0a,0x00,0x04,0x00,0x00,0x00,0x00,0x7f,0x00,0x33,0x01,0x00, 55 | 0x00,0x00,0x00,0x00,0x00,0xff,0xbf,0xff,0xff,0x00,0x00,0x00,0x00,0x07,0x00, 56 | 0x00,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 57 | 0x00,0xff,0xff,0x00,0x00,0x00,0xbf,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 58 | 0x7f,0x00,0x00,0xff,0x4a,0x4a,0x4a,0x4a,0x4b,0x52,0x4a,0x4a,0x4a,0x4a,0x4f, 59 | 0x4c,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x55,0x45,0x40,0x4a,0x4a,0x4a, 60 | 0x45,0x59,0x4d,0x46,0x4a,0x5d,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a, 61 | 0x4a,0x4a,0x4a,0x4a,0x4a,0x61,0x63,0x67,0x4e,0x4a,0x4a,0x6b,0x6d,0x4a,0x4a, 62 | 0x45,0x6d,0x4a,0x4a,0x44,0x45,0x4a,0x4a,0x00,0x00,0x00,0x02,0x0d,0x06,0x06, 63 | 0x06,0x06,0x0e,0x00,0x00,0x00,0x00,0x06,0x06,0x06,0x00,0x06,0x06,0x02,0x06, 64 | 0x00,0x0a,0x0a,0x07,0x07,0x06,0x02,0x05,0x05,0x02,0x02,0x00,0x00,0x04,0x04, 65 | 0x04,0x04,0x00,0x00,0x00,0x0e,0x05,0x06,0x06,0x06,0x01,0x06,0x00,0x00,0x08, 66 | 0x00,0x10,0x00,0x18,0x00,0x20,0x00,0x28,0x00,0x30,0x00,0x80,0x01,0x82,0x01, 67 | 0x86,0x00,0xf6,0xcf,0xfe,0x3f,0xab,0x00,0xb0,0x00,0xb1,0x00,0xb3,0x00,0xba, 68 | 0xf8,0xbb,0x00,0xc0,0x00,0xc1,0x00,0xc7,0xbf,0x62,0xff,0x00,0x8d,0xff,0x00, 69 | 0xc4,0xff,0x00,0xc5,0xff,0x00,0xff,0xff,0xeb,0x01,0xff,0x0e,0x12,0x08,0x00, 70 | 0x13,0x09,0x00,0x16,0x08,0x00,0x17,0x09,0x00,0x2b,0x09,0x00,0xae,0xff,0x07, 71 | 0xb2,0xff,0x00,0xb4,0xff,0x00,0xb5,0xff,0x00,0xc3,0x01,0x00,0xc7,0xff,0xbf, 72 | 0xe7,0x08,0x00,0xf0,0x02,0x00 73 | }; 74 | -------------------------------------------------------------------------------- /third_party/minhook/src/hde/table64.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Hacker Disassembler Engine 64 C 3 | * Copyright (c) 2008-2009, Vyacheslav Patkov. 4 | * All rights reserved. 5 | * 6 | */ 7 | 8 | #define C_NONE 0x00 9 | #define C_MODRM 0x01 10 | #define C_IMM8 0x02 11 | #define C_IMM16 0x04 12 | #define C_IMM_P66 0x10 13 | #define C_REL8 0x20 14 | #define C_REL32 0x40 15 | #define C_GROUP 0x80 16 | #define C_ERROR 0xff 17 | 18 | #define PRE_ANY 0x00 19 | #define PRE_NONE 0x01 20 | #define PRE_F2 0x02 21 | #define PRE_F3 0x04 22 | #define PRE_66 0x08 23 | #define PRE_67 0x10 24 | #define PRE_LOCK 0x20 25 | #define PRE_SEG 0x40 26 | #define PRE_ALL 0xff 27 | 28 | #define DELTA_OPCODES 0x4a 29 | #define DELTA_FPU_REG 0xfd 30 | #define DELTA_FPU_MODRM 0x104 31 | #define DELTA_PREFIXES 0x13c 32 | #define DELTA_OP_LOCK_OK 0x1ae 33 | #define DELTA_OP2_LOCK_OK 0x1c6 34 | #define DELTA_OP_ONLY_MEM 0x1d8 35 | #define DELTA_OP2_ONLY_MEM 0x1e7 36 | 37 | unsigned char hde64_table[] = { 38 | 0xa5,0xaa,0xa5,0xb8,0xa5,0xaa,0xa5,0xaa,0xa5,0xb8,0xa5,0xb8,0xa5,0xb8,0xa5, 39 | 0xb8,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xac,0xc0,0xcc,0xc0,0xa1,0xa1, 40 | 0xa1,0xa1,0xb1,0xa5,0xa5,0xa6,0xc0,0xc0,0xd7,0xda,0xe0,0xc0,0xe4,0xc0,0xea, 41 | 0xea,0xe0,0xe0,0x98,0xc8,0xee,0xf1,0xa5,0xd3,0xa5,0xa5,0xa1,0xea,0x9e,0xc0, 42 | 0xc0,0xc2,0xc0,0xe6,0x03,0x7f,0x11,0x7f,0x01,0x7f,0x01,0x3f,0x01,0x01,0xab, 43 | 0x8b,0x90,0x64,0x5b,0x5b,0x5b,0x5b,0x5b,0x92,0x5b,0x5b,0x76,0x90,0x92,0x92, 44 | 0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x6a,0x73,0x90, 45 | 0x5b,0x52,0x52,0x52,0x52,0x5b,0x5b,0x5b,0x5b,0x77,0x7c,0x77,0x85,0x5b,0x5b, 46 | 0x70,0x5b,0x7a,0xaf,0x76,0x76,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b, 47 | 0x5b,0x5b,0x86,0x01,0x03,0x01,0x04,0x03,0xd5,0x03,0xd5,0x03,0xcc,0x01,0xbc, 48 | 0x03,0xf0,0x03,0x03,0x04,0x00,0x50,0x50,0x50,0x50,0xff,0x20,0x20,0x20,0x20, 49 | 0x01,0x01,0x01,0x01,0xc4,0x02,0x10,0xff,0xff,0xff,0x01,0x00,0x03,0x11,0xff, 50 | 0x03,0xc4,0xc6,0xc8,0x02,0x10,0x00,0xff,0xcc,0x01,0x01,0x01,0x00,0x00,0x00, 51 | 0x00,0x01,0x01,0x03,0x01,0xff,0xff,0xc0,0xc2,0x10,0x11,0x02,0x03,0x01,0x01, 52 | 0x01,0xff,0xff,0xff,0x00,0x00,0x00,0xff,0x00,0x00,0xff,0xff,0xff,0xff,0x10, 53 | 0x10,0x10,0x10,0x02,0x10,0x00,0x00,0xc6,0xc8,0x02,0x02,0x02,0x02,0x06,0x00, 54 | 0x04,0x00,0x02,0xff,0x00,0xc0,0xc2,0x01,0x01,0x03,0x03,0x03,0xca,0x40,0x00, 55 | 0x0a,0x00,0x04,0x00,0x00,0x00,0x00,0x7f,0x00,0x33,0x01,0x00,0x00,0x00,0x00, 56 | 0x00,0x00,0xff,0xbf,0xff,0xff,0x00,0x00,0x00,0x00,0x07,0x00,0x00,0xff,0x00, 57 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff, 58 | 0x00,0x00,0x00,0xbf,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7f,0x00,0x00, 59 | 0xff,0x40,0x40,0x40,0x40,0x41,0x49,0x40,0x40,0x40,0x40,0x4c,0x42,0x40,0x40, 60 | 0x40,0x40,0x40,0x40,0x40,0x40,0x4f,0x44,0x53,0x40,0x40,0x40,0x44,0x57,0x43, 61 | 0x5c,0x40,0x60,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40, 62 | 0x40,0x40,0x64,0x66,0x6e,0x6b,0x40,0x40,0x6a,0x46,0x40,0x40,0x44,0x46,0x40, 63 | 0x40,0x5b,0x44,0x40,0x40,0x00,0x00,0x00,0x00,0x06,0x06,0x06,0x06,0x01,0x06, 64 | 0x06,0x02,0x06,0x06,0x00,0x06,0x00,0x0a,0x0a,0x00,0x00,0x00,0x02,0x07,0x07, 65 | 0x06,0x02,0x0d,0x06,0x06,0x06,0x0e,0x05,0x05,0x02,0x02,0x00,0x00,0x04,0x04, 66 | 0x04,0x04,0x05,0x06,0x06,0x06,0x00,0x00,0x00,0x0e,0x00,0x00,0x08,0x00,0x10, 67 | 0x00,0x18,0x00,0x20,0x00,0x28,0x00,0x30,0x00,0x80,0x01,0x82,0x01,0x86,0x00, 68 | 0xf6,0xcf,0xfe,0x3f,0xab,0x00,0xb0,0x00,0xb1,0x00,0xb3,0x00,0xba,0xf8,0xbb, 69 | 0x00,0xc0,0x00,0xc1,0x00,0xc7,0xbf,0x62,0xff,0x00,0x8d,0xff,0x00,0xc4,0xff, 70 | 0x00,0xc5,0xff,0x00,0xff,0xff,0xeb,0x01,0xff,0x0e,0x12,0x08,0x00,0x13,0x09, 71 | 0x00,0x16,0x08,0x00,0x17,0x09,0x00,0x2b,0x09,0x00,0xae,0xff,0x07,0xb2,0xff, 72 | 0x00,0xb4,0xff,0x00,0xb5,0xff,0x00,0xc3,0x01,0x00,0xc7,0xff,0xbf,0xe7,0x08, 73 | 0x00,0xf0,0x02,0x00 74 | }; 75 | -------------------------------------------------------------------------------- /third_party/minhook/src/trampoline.c: -------------------------------------------------------------------------------- 1 | /* 2 | * MinHook - The Minimalistic API Hooking Library for x64/x86 3 | * Copyright (C) 2009-2017 Tsuda Kageyu. 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions 8 | * are met: 9 | * 10 | * 1. Redistributions of source code must retain the above copyright 11 | * notice, this list of conditions and the following disclaimer. 12 | * 2. Redistributions in binary form must reproduce the above copyright 13 | * notice, this list of conditions and the following disclaimer in the 14 | * documentation and/or other materials provided with the distribution. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 18 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 19 | * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER 20 | * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 21 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 22 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 23 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 24 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 25 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 26 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | */ 28 | 29 | #include <windows.h> 30 | 31 | #if defined(_MSC_VER) && !defined(MINHOOK_DISABLE_INTRINSICS) 32 | #define ALLOW_INTRINSICS 33 | #include <intrin.h> 34 | #endif 35 | 36 | #ifndef ARRAYSIZE 37 | #define ARRAYSIZE(A) (sizeof(A)/sizeof((A)[0])) 38 | #endif 39 | 40 | #if defined(_M_X64) || defined(__x86_64__) 41 | #include "./hde/hde64.h" 42 | typedef hde64s HDE; 43 | #define HDE_DISASM(code, hs) hde64_disasm(code, hs) 44 | #else 45 | #include "./hde/hde32.h" 46 | typedef hde32s HDE; 47 | #define HDE_DISASM(code, hs) hde32_disasm(code, hs) 48 | #endif 49 | 50 | #include "trampoline.h" 51 | #include "buffer.h" 52 | 53 | // Maximum size of a trampoline function. 54 | #if defined(_M_X64) || defined(__x86_64__) 55 | #define TRAMPOLINE_MAX_SIZE (MEMORY_SLOT_SIZE - sizeof(JMP_ABS)) 56 | #else 57 | #define TRAMPOLINE_MAX_SIZE MEMORY_SLOT_SIZE 58 | #endif 59 | 60 | //------------------------------------------------------------------------- 61 | static BOOL IsCodePadding(LPBYTE pInst, UINT size) 62 | { 63 | UINT i; 64 | 65 | if (pInst[0] != 0x00 && pInst[0] != 0x90 && pInst[0] != 0xCC) 66 | return FALSE; 67 | 68 | for (i = 1; i < size; ++i) 69 | { 70 | if (pInst[i] != pInst[0]) 71 | return FALSE; 72 | } 73 | return TRUE; 74 | } 75 | 76 | //------------------------------------------------------------------------- 77 | BOOL CreateTrampolineFunction(PTRAMPOLINE ct) 78 | { 79 | #if defined(_M_X64) || defined(__x86_64__) 80 | CALL_ABS call = { 81 | 0xFF, 0x15, 0x00000002, // FF15 00000002: CALL [RIP+8] 82 | 0xEB, 0x08, // EB 08: JMP +10 83 | 0x0000000000000000ULL // Absolute destination address 84 | }; 85 | JMP_ABS jmp = { 86 | 0xFF, 0x25, 0x00000000, // FF25 00000000: JMP [RIP+6] 87 | 0x0000000000000000ULL // Absolute destination address 88 | }; 89 | JCC_ABS jcc = { 90 | 0x70, 0x0E, // 7* 0E: J** +16 91 | 0xFF, 0x25, 0x00000000, // FF25 00000000: JMP [RIP+6] 92 | 0x0000000000000000ULL // Absolute destination address 93 | }; 94 | #else 95 | CALL_REL call = { 96 | 0xE8, // E8 xxxxxxxx: CALL +5+xxxxxxxx 97 | 0x00000000 // Relative destination address 98 | }; 99 | JMP_REL jmp = { 100 | 0xE9, // E9 xxxxxxxx: JMP +5+xxxxxxxx 101 | 0x00000000 // Relative destination address 102 | }; 103 | JCC_REL jcc = { 104 | 0x0F, 0x80, // 0F8* xxxxxxxx: J** +6+xxxxxxxx 105 | 0x00000000 // Relative destination address 106 | }; 107 | #endif 108 | 109 | UINT8 oldPos = 0; 110 | UINT8 newPos = 0; 111 | ULONG_PTR jmpDest = 0; // Destination address of an internal jump. 112 | BOOL finished = FALSE; // Is the function completed? 113 | #if defined(_M_X64) || defined(__x86_64__) 114 | UINT8 instBuf[16]; 115 | #endif 116 | 117 | ct->patchAbove = FALSE; 118 | ct->nIP = 0; 119 | 120 | do 121 | { 122 | HDE hs; 123 | UINT copySize; 124 | LPVOID pCopySrc; 125 | ULONG_PTR pOldInst = (ULONG_PTR)ct->pTarget + oldPos; 126 | ULONG_PTR pNewInst = (ULONG_PTR)ct->pTrampoline + newPos; 127 | 128 | copySize = HDE_DISASM((LPVOID)pOldInst, &hs); 129 | if (hs.flags & F_ERROR) 130 | return FALSE; 131 | 132 | pCopySrc = (LPVOID)pOldInst; 133 | if (oldPos >= sizeof(JMP_REL)) 134 | { 135 | // The trampoline function is long enough. 136 | // Complete the function with the jump to the target function. 137 | #if defined(_M_X64) || defined(__x86_64__) 138 | jmp.address = pOldInst; 139 | #else 140 | jmp.operand = (UINT32)(pOldInst - (pNewInst + sizeof(jmp))); 141 | #endif 142 | pCopySrc = &jmp; 143 | copySize = sizeof(jmp); 144 | 145 | finished = TRUE; 146 | } 147 | #if defined(_M_X64) || defined(__x86_64__) 148 | else if ((hs.modrm & 0xC7) == 0x05) 149 | { 150 | // Instructions using RIP relative addressing. (ModR/M = 00???101B) 151 | 152 | // Modify the RIP relative address. 153 | PUINT32 pRelAddr; 154 | 155 | // Avoid using memcpy to reduce the footprint. 156 | #ifndef ALLOW_INTRINSICS 157 | memcpy(instBuf, (LPBYTE)pOldInst, copySize); 158 | #else 159 | __movsb(instBuf, (LPBYTE)pOldInst, copySize); 160 | #endif 161 | pCopySrc = instBuf; 162 | 163 | // Relative address is stored at (instruction length - immediate value length - 4). 164 | pRelAddr = (PUINT32)(instBuf + hs.len - ((hs.flags & 0x3C) >> 2) - 4); 165 | *pRelAddr 166 | = (UINT32)((pOldInst + hs.len + (INT32)hs.disp.disp32) - (pNewInst + hs.len)); 167 | 168 | // Complete the function if JMP (FF /4). 169 | if (hs.opcode == 0xFF && hs.modrm_reg == 4) 170 | finished = TRUE; 171 | } 172 | #endif 173 | else if (hs.opcode == 0xE8) 174 | { 175 | // Direct relative CALL 176 | ULONG_PTR dest = pOldInst + hs.len + (INT32)hs.imm.imm32; 177 | #if defined(_M_X64) || defined(__x86_64__) 178 | call.address = dest; 179 | #else 180 | call.operand = (UINT32)(dest - (pNewInst + sizeof(call))); 181 | #endif 182 | pCopySrc = &call; 183 | copySize = sizeof(call); 184 | } 185 | else if ((hs.opcode & 0xFD) == 0xE9) 186 | { 187 | // Direct relative JMP (EB or E9) 188 | ULONG_PTR dest = pOldInst + hs.len; 189 | 190 | if (hs.opcode == 0xEB) // isShort jmp 191 | dest += (INT8)hs.imm.imm8; 192 | else 193 | dest += (INT32)hs.imm.imm32; 194 | 195 | // Simply copy an internal jump. 196 | if ((ULONG_PTR)ct->pTarget <= dest 197 | && dest < ((ULONG_PTR)ct->pTarget + sizeof(JMP_REL))) 198 | { 199 | if (jmpDest < dest) 200 | jmpDest = dest; 201 | } 202 | else 203 | { 204 | #if defined(_M_X64) || defined(__x86_64__) 205 | jmp.address = dest; 206 | #else 207 | jmp.operand = (UINT32)(dest - (pNewInst + sizeof(jmp))); 208 | #endif 209 | pCopySrc = &jmp; 210 | copySize = sizeof(jmp); 211 | 212 | // Exit the function if it is not in the branch. 213 | finished = (pOldInst >= jmpDest); 214 | } 215 | } 216 | else if ((hs.opcode & 0xF0) == 0x70 217 | || (hs.opcode & 0xFC) == 0xE0 218 | || (hs.opcode2 & 0xF0) == 0x80) 219 | { 220 | // Direct relative Jcc 221 | ULONG_PTR dest = pOldInst + hs.len; 222 | 223 | if ((hs.opcode & 0xF0) == 0x70 // Jcc 224 | || (hs.opcode & 0xFC) == 0xE0) // LOOPNZ/LOOPZ/LOOP/JECXZ 225 | dest += (INT8)hs.imm.imm8; 226 | else 227 | dest += (INT32)hs.imm.imm32; 228 | 229 | // Simply copy an internal jump. 230 | if ((ULONG_PTR)ct->pTarget <= dest 231 | && dest < ((ULONG_PTR)ct->pTarget + sizeof(JMP_REL))) 232 | { 233 | if (jmpDest < dest) 234 | jmpDest = dest; 235 | } 236 | else if ((hs.opcode & 0xFC) == 0xE0) 237 | { 238 | // LOOPNZ/LOOPZ/LOOP/JCXZ/JECXZ to the outside are not supported. 239 | return FALSE; 240 | } 241 | else 242 | { 243 | UINT8 cond = ((hs.opcode != 0x0F ? hs.opcode : hs.opcode2) & 0x0F); 244 | #if defined(_M_X64) || defined(__x86_64__) 245 | // Invert the condition in x64 mode to simplify the conditional jump logic. 246 | jcc.opcode = 0x71 ^ cond; 247 | jcc.address = dest; 248 | #else 249 | jcc.opcode1 = 0x80 | cond; 250 | jcc.operand = (UINT32)(dest - (pNewInst + sizeof(jcc))); 251 | #endif 252 | pCopySrc = &jcc; 253 | copySize = sizeof(jcc); 254 | } 255 | } 256 | else if ((hs.opcode & 0xFE) == 0xC2) 257 | { 258 | // RET (C2 or C3) 259 | 260 | // Complete the function if not in a branch. 261 | finished = (pOldInst >= jmpDest); 262 | } 263 | 264 | // Can't alter the instruction length in a branch. 265 | if (pOldInst < jmpDest && copySize != hs.len) 266 | return FALSE; 267 | 268 | // Trampoline function is too large. 269 | if ((newPos + copySize) > TRAMPOLINE_MAX_SIZE) 270 | return FALSE; 271 | 272 | // Trampoline function has too many instructions. 273 | if (ct->nIP >= ARRAYSIZE(ct->oldIPs)) 274 | return FALSE; 275 | 276 | ct->oldIPs[ct->nIP] = oldPos; 277 | ct->newIPs[ct->nIP] = newPos; 278 | ct->nIP++; 279 | 280 | // Avoid using memcpy to reduce the footprint. 281 | #ifndef ALLOW_INTRINSICS 282 | memcpy((LPBYTE)ct->pTrampoline + newPos, pCopySrc, copySize); 283 | #else 284 | __movsb((LPBYTE)ct->pTrampoline + newPos, (LPBYTE)pCopySrc, copySize); 285 | #endif 286 | newPos += copySize; 287 | oldPos += hs.len; 288 | } while (!finished); 289 | 290 | // Is there enough place for a long jump? 291 | if (oldPos < sizeof(JMP_REL) 292 | && !IsCodePadding((LPBYTE)ct->pTarget + oldPos, sizeof(JMP_REL) - oldPos)) 293 | { 294 | // Is there enough place for a short jump? 295 | if (oldPos < sizeof(JMP_REL_SHORT) 296 | && !IsCodePadding((LPBYTE)ct->pTarget + oldPos, sizeof(JMP_REL_SHORT) - oldPos)) 297 | { 298 | return FALSE; 299 | } 300 | 301 | // Can we place the long jump above the function? 302 | if (!IsExecutableAddress((LPBYTE)ct->pTarget - sizeof(JMP_REL))) 303 | return FALSE; 304 | 305 | if (!IsCodePadding((LPBYTE)ct->pTarget - sizeof(JMP_REL), sizeof(JMP_REL))) 306 | return FALSE; 307 | 308 | ct->patchAbove = TRUE; 309 | } 310 | 311 | #if defined(_M_X64) || defined(__x86_64__) 312 | // Create a relay function. 313 | jmp.address = (ULONG_PTR)ct->pDetour; 314 | 315 | ct->pRelay = (LPBYTE)ct->pTrampoline + newPos; 316 | memcpy(ct->pRelay, &jmp, sizeof(jmp)); 317 | #endif 318 | 319 | return TRUE; 320 | } 321 | -------------------------------------------------------------------------------- /third_party/minhook/src/trampoline.h: -------------------------------------------------------------------------------- 1 | /* 2 | * MinHook - The Minimalistic API Hooking Library for x64/x86 3 | * Copyright (C) 2009-2017 Tsuda Kageyu. 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions 8 | * are met: 9 | * 10 | * 1. Redistributions of source code must retain the above copyright 11 | * notice, this list of conditions and the following disclaimer. 12 | * 2. Redistributions in binary form must reproduce the above copyright 13 | * notice, this list of conditions and the following disclaimer in the 14 | * documentation and/or other materials provided with the distribution. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 18 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 19 | * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER 20 | * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 21 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 22 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 23 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 24 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 25 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 26 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | */ 28 | 29 | #pragma once 30 | 31 | #pragma pack(push, 1) 32 | 33 | // Structs for writing x86/x64 instructions. 34 | 35 | // 8-bit relative jump. 36 | typedef struct _JMP_REL_SHORT 37 | { 38 | UINT8 opcode; // EB xx: JMP +2+xx 39 | UINT8 operand; 40 | } JMP_REL_SHORT, *PJMP_REL_SHORT; 41 | 42 | // 32-bit direct relative jump/call. 43 | typedef struct _JMP_REL 44 | { 45 | UINT8 opcode; // E9/E8 xxxxxxxx: JMP/CALL +5+xxxxxxxx 46 | UINT32 operand; // Relative destination address 47 | } JMP_REL, *PJMP_REL, CALL_REL; 48 | 49 | // 64-bit indirect absolute jump. 50 | typedef struct _JMP_ABS 51 | { 52 | UINT8 opcode0; // FF25 00000000: JMP [+6] 53 | UINT8 opcode1; 54 | UINT32 dummy; 55 | UINT64 address; // Absolute destination address 56 | } JMP_ABS, *PJMP_ABS; 57 | 58 | // 64-bit indirect absolute call. 59 | typedef struct _CALL_ABS 60 | { 61 | UINT8 opcode0; // FF15 00000002: CALL [+6] 62 | UINT8 opcode1; 63 | UINT32 dummy0; 64 | UINT8 dummy1; // EB 08: JMP +10 65 | UINT8 dummy2; 66 | UINT64 address; // Absolute destination address 67 | } CALL_ABS; 68 | 69 | // 32-bit direct relative conditional jumps. 70 | typedef struct _JCC_REL 71 | { 72 | UINT8 opcode0; // 0F8* xxxxxxxx: J** +6+xxxxxxxx 73 | UINT8 opcode1; 74 | UINT32 operand; // Relative destination address 75 | } JCC_REL; 76 | 77 | // 64bit indirect absolute conditional jumps that x64 lacks. 78 | typedef struct _JCC_ABS 79 | { 80 | UINT8 opcode; // 7* 0E: J** +16 81 | UINT8 dummy0; 82 | UINT8 dummy1; // FF25 00000000: JMP [+6] 83 | UINT8 dummy2; 84 | UINT32 dummy3; 85 | UINT64 address; // Absolute destination address 86 | } JCC_ABS; 87 | 88 | #pragma pack(pop) 89 | 90 | typedef struct _TRAMPOLINE 91 | { 92 | LPVOID pTarget; // [In] Address of the target function. 93 | LPVOID pDetour; // [In] Address of the detour function. 94 | LPVOID pTrampoline; // [In] Buffer address for the trampoline and relay function. 95 | 96 | #if defined(_M_X64) || defined(__x86_64__) 97 | LPVOID pRelay; // [Out] Address of the relay function. 98 | #endif 99 | BOOL patchAbove; // [Out] Should use the hot patch area? 100 | UINT nIP; // [Out] Number of the instruction boundaries. 101 | UINT8 oldIPs[8]; // [Out] Instruction boundaries of the target function. 102 | UINT8 newIPs[8]; // [Out] Instruction boundaries of the trampoline function. 103 | } TRAMPOLINE, *PTRAMPOLINE; 104 | 105 | BOOL CreateTrampolineFunction(PTRAMPOLINE ct); 106 | -------------------------------------------------------------------------------- /translations/OpenSpeedy_en_US.qm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/game1024/OpenSpeedy/b54416000c2bea56654a9f628f2641cd55038780/translations/OpenSpeedy_en_US.qm -------------------------------------------------------------------------------- /translations/OpenSpeedy_zh_CN.qm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/game1024/OpenSpeedy/b54416000c2bea56654a9f628f2641cd55038780/translations/OpenSpeedy_zh_CN.qm -------------------------------------------------------------------------------- /translations/OpenSpeedy_zh_TW.qm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/game1024/OpenSpeedy/b54416000c2bea56654a9f628f2641cd55038780/translations/OpenSpeedy_zh_TW.qm -------------------------------------------------------------------------------- /windbg.h: -------------------------------------------------------------------------------- 1 | /* 2 | * OpenSpeedy - Open Source Game Speed Controller 3 | * Copyright (C) 2025 Game1024 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see <https://www.gnu.org/licenses/>. 17 | */ 18 | #ifndef WINDBG_H 19 | #define WINDBG_H 20 | #include <windows.h> 21 | #include <QDateTime> 22 | #include <QDir> 23 | #include <dbghelp.h> 24 | // 链接dbghelp库 25 | #pragma comment(lib, "dbghelp.lib") 26 | 27 | typedef BOOL(WINAPI *MINIDUMPWRITEDUMP)( 28 | HANDLE hProcess, 29 | DWORD ProcessId, 30 | HANDLE hFile, 31 | MINIDUMP_TYPE DumpType, 32 | PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam, 33 | PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam, 34 | PMINIDUMP_CALLBACK_INFORMATION CallbackParam); 35 | 36 | // 自定义异常处理函数 37 | LONG WINAPI createMiniDump(EXCEPTION_POINTERS *exceptionPointers) 38 | { 39 | // 创建dump文件目录 40 | QDir dumpDir(QDir::currentPath() + "/dumps"); 41 | if (!dumpDir.exists()) 42 | { 43 | dumpDir.mkpath("."); 44 | } 45 | 46 | // 生成带时间戳的文件名 47 | QString dumpFileName = 48 | QString("%1/crash_%2.dmp") 49 | .arg(dumpDir.absolutePath()) 50 | .arg(QDateTime::currentDateTime().toString("yyyy-MM-dd_hh-mm-ss")); 51 | 52 | // 创建文件 53 | HANDLE hFile = CreateFile(dumpFileName.toStdWString().c_str(), 54 | GENERIC_WRITE, FILE_SHARE_READ, NULL, 55 | CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); 56 | 57 | if (hFile == INVALID_HANDLE_VALUE) 58 | { 59 | return EXCEPTION_CONTINUE_SEARCH; 60 | } 61 | 62 | // 加载dbghelp.dll 63 | HMODULE dbgHelp = LoadLibrary(L"dbghelp.dll"); 64 | if (!dbgHelp) 65 | { 66 | CloseHandle(hFile); 67 | return EXCEPTION_CONTINUE_SEARCH; 68 | } 69 | 70 | // 获取MiniDumpWriteDump函数地址 71 | MINIDUMPWRITEDUMP miniDumpWriteDump = 72 | (MINIDUMPWRITEDUMP)GetProcAddress(dbgHelp, "MiniDumpWriteDump"); 73 | 74 | if (!miniDumpWriteDump) 75 | { 76 | FreeLibrary(dbgHelp); 77 | CloseHandle(hFile); 78 | return EXCEPTION_CONTINUE_SEARCH; 79 | } 80 | 81 | // 配置异常信息 82 | MINIDUMP_EXCEPTION_INFORMATION exInfo; 83 | exInfo.ThreadId = GetCurrentThreadId(); 84 | exInfo.ExceptionPointers = exceptionPointers; 85 | exInfo.ClientPointers = FALSE; 86 | 87 | // 设置dump类型 88 | MINIDUMP_TYPE dumpType = 89 | (MINIDUMP_TYPE)(MiniDumpWithFullMemory | // 包含完整内存 90 | MiniDumpWithFullMemoryInfo | // 包含内存信息 91 | MiniDumpWithHandleData | // 包含句柄数据 92 | MiniDumpWithThreadInfo | // 包含线程信息 93 | MiniDumpWithUnloadedModules // 包含卸载的模块 94 | ); 95 | 96 | // 写入dump文件 97 | BOOL success = miniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), 98 | hFile, dumpType, &exInfo, NULL, NULL); 99 | 100 | // 清理资源 101 | FreeLibrary(dbgHelp); 102 | CloseHandle(hFile); 103 | 104 | // 显示通知 105 | if (success) 106 | { 107 | std::wstring message = 108 | QString("程序遇到错误已退出,崩溃转储文件已保存到:\n%1") 109 | .arg(dumpFileName) 110 | .toStdWString(); 111 | MessageBoxW(nullptr, message.c_str(), L"程序崩溃", 112 | MB_OK | MB_ICONERROR); 113 | } 114 | 115 | return EXCEPTION_EXECUTE_HANDLER; 116 | } 117 | 118 | #endif // WINDBG_H 119 | -------------------------------------------------------------------------------- /winutils.h: -------------------------------------------------------------------------------- 1 | /* 2 | * OpenSpeedy - Open Source Game Speed Controller 3 | * Copyright (C) 2025 Game1024 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see <https://www.gnu.org/licenses/>. 17 | */ 18 | #ifndef WINUTILS_H 19 | #define WINUTILS_H 20 | #include <windows.h> 21 | #include "taskscheduler.h" 22 | #include <QSet> 23 | #include <QString> 24 | #include <string> 25 | #include <tlhelp32.h> 26 | struct ProcessInfo 27 | { 28 | DWORD pid; 29 | DWORD parentPid; 30 | QString name; 31 | DWORD threadCount; 32 | bool is64Bit; 33 | DWORD priorityClass; 34 | SIZE_T memoryUsage; 35 | }; 36 | 37 | class winutils 38 | { 39 | public: 40 | winutils(); 41 | 42 | public: 43 | // DLL 注入 44 | static bool injectDll(DWORD processId, const QString& dllPath); 45 | 46 | // 远程 DLL 注入 47 | static bool injectDllViaCRTA(DWORD processId, const QString& dllPath); 48 | static bool injectDllViaCRTW(DWORD processId, const QString& dllPath); 49 | 50 | // APC DLL 注入 51 | static bool injectDllViaAPCA(DWORD processId, const QString& dllPath); 52 | static bool injectDllViaAPCW(DWORD processId, const QString& dllPath); 53 | 54 | // Windows Hooks 注入 55 | static bool injectDllViaWHKA(DWORD processId, const QString& dllPath); 56 | static bool injectDllViaWHKW(DWORD processId, const QString& dllPath); 57 | 58 | // DLL 卸载 59 | static bool unhookDll(DWORD processId, const QString& dllPath); 60 | 61 | // 检查DLL是否已挂载 62 | static bool checkDllExist(DWORD processId, const QString& dllPath); 63 | 64 | static bool checkProcessProtection(DWORD processId); 65 | 66 | static void setAutoStart(bool enable, 67 | const QString& appName, 68 | const QString& execPath); 69 | 70 | static bool isAutoStartEnabled(const QString& appName); 71 | 72 | static BOOL getWindowsVersion(DWORD* majorVersion, 73 | DWORD* minorVersion, 74 | DWORD* buildNumber); 75 | 76 | static QString getWindowsVersion(); 77 | 78 | // 获取进程快照 79 | static QList<ProcessInfo> getProcessList(); 80 | 81 | // 获取进程路径 82 | static QString getProcessPath(DWORD processId); 83 | 84 | // 获取进程中的主线程 85 | static DWORD getProcessMainThread(DWORD processId); 86 | 87 | static QString getProcessNameById(DWORD processId); 88 | 89 | static bool enableAllPrivilege(); 90 | }; 91 | 92 | #endif // WINUTILS_H 93 | --------------------------------------------------------------------------------