├── ,gitignore ├── .github └── workflows │ └── ci.yml ├── JavaExitHook.sln ├── JavaExitHook.vcxproj ├── JavaExitHook.vcxproj.filters ├── JavaExitHook.vcxproj.user ├── LICENSE ├── MinHook.h ├── README.md ├── buffer.c ├── buffer.h ├── dllmain.c ├── exit.c ├── exit.h ├── framework.h ├── hde32.c ├── hde32.h ├── hde64.c ├── hde64.h ├── hook.c ├── includes.h ├── pch.h ├── pstdint.h ├── scan.c ├── scan.h ├── table32.h ├── table64.h ├── trampoline.c ├── trampoline.h ├── utils.c └── utils.h /,gitignore: -------------------------------------------------------------------------------- 1 | # IDE files 2 | .idea 3 | .vs 4 | 5 | # Build paths 6 | x64 -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: [push, pull_request] 4 | 5 | env: 6 | # Path to the solution file relative to the root of the project. 7 | SOLUTION_FILE_PATH: . 8 | 9 | # Configuration type to build. 10 | # You can convert this to a build matrix if you need coverage of multiple configuration types. 11 | # https://docs.github.com/actions/learn-github-actions/managing-complex-workflows#using-a-build-matrix 12 | BUILD_CONFIGURATION: Release 13 | 14 | jobs: 15 | build: 16 | runs-on: windows-latest 17 | 18 | steps: 19 | - uses: actions/checkout@v2 20 | 21 | - name: Add MSBuild to PATH 22 | uses: microsoft/setup-msbuild@v1.0.2 23 | 24 | - name: Restore NuGet packages 25 | working-directory: ${{env.GITHUB_WORKSPACE}} 26 | run: nuget restore ${{env.SOLUTION_FILE_PATH}} 27 | 28 | - name: Build 29 | working-directory: ${{env.GITHUB_WORKSPACE}} 30 | # Add additional options to the MSBuild command line here (like platform or verbosity level). 31 | # See https://docs.microsoft.com/visualstudio/msbuild/msbuild-command-line-reference 32 | run: msbuild /m /p:Configuration=${{env.BUILD_CONFIGURATION}} ${{env.SOLUTION_FILE_PATH}} 33 | -------------------------------------------------------------------------------- /JavaExitHook.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.31229.75 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "JavaExitHook", "JavaExitHook.vcxproj", "{1E746E5D-3673-4054-87BD-4261926E75A1}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|x64 = Debug|x64 11 | Debug|x86 = Debug|x86 12 | Release|x64 = Release|x64 13 | Release|x86 = Release|x86 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {1E746E5D-3673-4054-87BD-4261926E75A1}.Debug|x64.ActiveCfg = Debug|x64 17 | {1E746E5D-3673-4054-87BD-4261926E75A1}.Debug|x64.Build.0 = Debug|x64 18 | {1E746E5D-3673-4054-87BD-4261926E75A1}.Debug|x86.ActiveCfg = Debug|Win32 19 | {1E746E5D-3673-4054-87BD-4261926E75A1}.Debug|x86.Build.0 = Debug|Win32 20 | {1E746E5D-3673-4054-87BD-4261926E75A1}.Release|x64.ActiveCfg = Release|x64 21 | {1E746E5D-3673-4054-87BD-4261926E75A1}.Release|x64.Build.0 = Release|x64 22 | {1E746E5D-3673-4054-87BD-4261926E75A1}.Release|x86.ActiveCfg = Release|Win32 23 | {1E746E5D-3673-4054-87BD-4261926E75A1}.Release|x86.Build.0 = Release|Win32 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | GlobalSection(ExtensibilityGlobals) = postSolution 29 | SolutionGuid = {44C08A16-7DA1-4A67-AD25-39E3D0FD55CC} 30 | EndGlobalSection 31 | EndGlobal 32 | -------------------------------------------------------------------------------- /JavaExitHook.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | 16.0 23 | Win32Proj 24 | {1e746e5d-3673-4054-87bd-4261926e75a1} 25 | JavaExitHook 26 | 10.0 27 | 28 | 29 | 30 | DynamicLibrary 31 | true 32 | v142 33 | Unicode 34 | 35 | 36 | DynamicLibrary 37 | false 38 | v142 39 | true 40 | Unicode 41 | 42 | 43 | DynamicLibrary 44 | true 45 | v142 46 | Unicode 47 | 48 | 49 | DynamicLibrary 50 | false 51 | v142 52 | true 53 | Unicode 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | true 75 | 76 | 77 | false 78 | 79 | 80 | true 81 | 82 | 83 | false 84 | 85 | 86 | 87 | Level3 88 | true 89 | WIN32;_DEBUG;JAVAEXITHOOK_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions);_CRT_SECURE_NO_WARNINGS 90 | true 91 | Use 92 | pch.h 93 | 94 | 95 | Windows 96 | true 97 | false 98 | 99 | 100 | 101 | 102 | Level3 103 | true 104 | true 105 | true 106 | WIN32;NDEBUG;JAVAEXITHOOK_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions);_CRT_SECURE_NO_WARNINGS 107 | true 108 | NotUsing 109 | pch.h 110 | 111 | 112 | Windows 113 | true 114 | true 115 | true 116 | false 117 | 118 | 119 | 120 | 121 | Level3 122 | true 123 | _DEBUG;JAVAEXITHOOK_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) 124 | true 125 | Use 126 | pch.h 127 | 128 | 129 | Windows 130 | true 131 | false 132 | 133 | 134 | 135 | 136 | Level3 137 | true 138 | true 139 | true 140 | NDEBUG;JAVAEXITHOOK_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions);_CRT_SECURE_NO_WARNINGS 141 | true 142 | NotUsing 143 | pch.h 144 | 145 | 146 | Windows 147 | true 148 | true 149 | true 150 | false 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | -------------------------------------------------------------------------------- /JavaExitHook.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Pliki nagłówkowe 20 | 21 | 22 | Pliki nagłówkowe 23 | 24 | 25 | Pliki nagłówkowe 26 | 27 | 28 | Pliki nagłówkowe 29 | 30 | 31 | Pliki nagłówkowe 32 | 33 | 34 | Pliki nagłówkowe 35 | 36 | 37 | Pliki nagłówkowe 38 | 39 | 40 | Pliki nagłówkowe 41 | 42 | 43 | Pliki nagłówkowe 44 | 45 | 46 | Pliki nagłówkowe 47 | 48 | 49 | Pliki nagłówkowe 50 | 51 | 52 | Pliki nagłówkowe 53 | 54 | 55 | Pliki nagłówkowe 56 | 57 | 58 | 59 | 60 | Pliki źródłowe 61 | 62 | 63 | Pliki źródłowe 64 | 65 | 66 | Pliki źródłowe 67 | 68 | 69 | Pliki źródłowe 70 | 71 | 72 | Pliki źródłowe 73 | 74 | 75 | Pliki źródłowe 76 | 77 | 78 | Pliki źródłowe 79 | 80 | 81 | Pliki źródłowe 82 | 83 | 84 | Pliki źródłowe 85 | 86 | 87 | -------------------------------------------------------------------------------- /JavaExitHook.vcxproj.user: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Mozilla Public License Version 2.0 2 | ================================== 3 | 4 | 1. Definitions 5 | -------------- 6 | 7 | 1.1. "Contributor" 8 | means each individual or legal entity that creates, contributes to 9 | the creation of, or owns Covered Software. 10 | 11 | 1.2. "Contributor Version" 12 | means the combination of the Contributions of others (if any) used 13 | by a Contributor and that particular Contributor's Contribution. 14 | 15 | 1.3. "Contribution" 16 | means Covered Software of a particular Contributor. 17 | 18 | 1.4. "Covered Software" 19 | means Source Code Form to which the initial Contributor has attached 20 | the notice in Exhibit A, the Executable Form of such Source Code 21 | Form, and Modifications of such Source Code Form, in each case 22 | including portions thereof. 23 | 24 | 1.5. "Incompatible With Secondary Licenses" 25 | means 26 | 27 | (a) that the initial Contributor has attached the notice described 28 | in Exhibit B to the Covered Software; or 29 | 30 | (b) that the Covered Software was made available under the terms of 31 | version 1.1 or earlier of the License, but not also under the 32 | terms of a Secondary License. 33 | 34 | 1.6. "Executable Form" 35 | means any form of the work other than Source Code Form. 36 | 37 | 1.7. "Larger Work" 38 | means a work that combines Covered Software with other material, in 39 | a separate file or files, that is not Covered Software. 40 | 41 | 1.8. "License" 42 | means this document. 43 | 44 | 1.9. "Licensable" 45 | means having the right to grant, to the maximum extent possible, 46 | whether at the time of the initial grant or subsequently, any and 47 | all of the rights conveyed by this License. 48 | 49 | 1.10. "Modifications" 50 | means any of the following: 51 | 52 | (a) any file in Source Code Form that results from an addition to, 53 | deletion from, or modification of the contents of Covered 54 | Software; or 55 | 56 | (b) any new file in Source Code Form that contains any Covered 57 | Software. 58 | 59 | 1.11. "Patent Claims" of a Contributor 60 | means any patent claim(s), including without limitation, method, 61 | process, and apparatus claims, in any patent Licensable by such 62 | Contributor that would be infringed, but for the grant of the 63 | License, by the making, using, selling, offering for sale, having 64 | made, import, or transfer of either its Contributions or its 65 | Contributor Version. 66 | 67 | 1.12. "Secondary License" 68 | means either the GNU General Public License, Version 2.0, the GNU 69 | Lesser General Public License, Version 2.1, the GNU Affero General 70 | Public License, Version 3.0, or any later versions of those 71 | licenses. 72 | 73 | 1.13. "Source Code Form" 74 | means the form of the work preferred for making modifications. 75 | 76 | 1.14. "You" (or "Your") 77 | means an individual or a legal entity exercising rights under this 78 | License. For legal entities, "You" includes any entity that 79 | controls, is controlled by, or is under common control with You. For 80 | purposes of this definition, "control" means (a) the power, direct 81 | or indirect, to cause the direction or management of such entity, 82 | whether by contract or otherwise, or (b) ownership of more than 83 | fifty percent (50%) of the outstanding shares or beneficial 84 | ownership of such entity. 85 | 86 | 2. License Grants and Conditions 87 | -------------------------------- 88 | 89 | 2.1. Grants 90 | 91 | Each Contributor hereby grants You a world-wide, royalty-free, 92 | non-exclusive license: 93 | 94 | (a) under intellectual property rights (other than patent or trademark) 95 | Licensable by such Contributor to use, reproduce, make available, 96 | modify, display, perform, distribute, and otherwise exploit its 97 | Contributions, either on an unmodified basis, with Modifications, or 98 | as part of a Larger Work; and 99 | 100 | (b) under Patent Claims of such Contributor to make, use, sell, offer 101 | for sale, have made, import, and otherwise transfer either its 102 | Contributions or its Contributor Version. 103 | 104 | 2.2. Effective Date 105 | 106 | The licenses granted in Section 2.1 with respect to any Contribution 107 | become effective for each Contribution on the date the Contributor first 108 | distributes such Contribution. 109 | 110 | 2.3. Limitations on Grant Scope 111 | 112 | The licenses granted in this Section 2 are the only rights granted under 113 | this License. No additional rights or licenses will be implied from the 114 | distribution or licensing of Covered Software under this License. 115 | Notwithstanding Section 2.1(b) above, no patent license is granted by a 116 | Contributor: 117 | 118 | (a) for any code that a Contributor has removed from Covered Software; 119 | or 120 | 121 | (b) for infringements caused by: (i) Your and any other third party's 122 | modifications of Covered Software, or (ii) the combination of its 123 | Contributions with other software (except as part of its Contributor 124 | Version); or 125 | 126 | (c) under Patent Claims infringed by Covered Software in the absence of 127 | its Contributions. 128 | 129 | This License does not grant any rights in the trademarks, service marks, 130 | or logos of any Contributor (except as may be necessary to comply with 131 | the notice requirements in Section 3.4). 132 | 133 | 2.4. Subsequent Licenses 134 | 135 | No Contributor makes additional grants as a result of Your choice to 136 | distribute the Covered Software under a subsequent version of this 137 | License (see Section 10.2) or under the terms of a Secondary License (if 138 | permitted under the terms of Section 3.3). 139 | 140 | 2.5. Representation 141 | 142 | Each Contributor represents that the Contributor believes its 143 | Contributions are its original creation(s) or it has sufficient rights 144 | to grant the rights to its Contributions conveyed by this License. 145 | 146 | 2.6. Fair Use 147 | 148 | This License is not intended to limit any rights You have under 149 | applicable copyright doctrines of fair use, fair dealing, or other 150 | equivalents. 151 | 152 | 2.7. Conditions 153 | 154 | Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted 155 | in Section 2.1. 156 | 157 | 3. Responsibilities 158 | ------------------- 159 | 160 | 3.1. Distribution of Source Form 161 | 162 | All distribution of Covered Software in Source Code Form, including any 163 | Modifications that You create or to which You contribute, must be under 164 | the terms of this License. You must inform recipients that the Source 165 | Code Form of the Covered Software is governed by the terms of this 166 | License, and how they can obtain a copy of this License. You may not 167 | attempt to alter or restrict the recipients' rights in the Source Code 168 | Form. 169 | 170 | 3.2. Distribution of Executable Form 171 | 172 | If You distribute Covered Software in Executable Form then: 173 | 174 | (a) such Covered Software must also be made available in Source Code 175 | Form, as described in Section 3.1, and You must inform recipients of 176 | the Executable Form how they can obtain a copy of such Source Code 177 | Form by reasonable means in a timely manner, at a charge no more 178 | than the cost of distribution to the recipient; and 179 | 180 | (b) You may distribute such Executable Form under the terms of this 181 | License, or sublicense it under different terms, provided that the 182 | license for the Executable Form does not attempt to limit or alter 183 | the recipients' rights in the Source Code Form under this License. 184 | 185 | 3.3. Distribution of a Larger Work 186 | 187 | You may create and distribute a Larger Work under terms of Your choice, 188 | provided that You also comply with the requirements of this License for 189 | the Covered Software. If the Larger Work is a combination of Covered 190 | Software with a work governed by one or more Secondary Licenses, and the 191 | Covered Software is not Incompatible With Secondary Licenses, this 192 | License permits You to additionally distribute such Covered Software 193 | under the terms of such Secondary License(s), so that the recipient of 194 | the Larger Work may, at their option, further distribute the Covered 195 | Software under the terms of either this License or such Secondary 196 | License(s). 197 | 198 | 3.4. Notices 199 | 200 | You may not remove or alter the substance of any license notices 201 | (including copyright notices, patent notices, disclaimers of warranty, 202 | or limitations of liability) contained within the Source Code Form of 203 | the Covered Software, except that You may alter any license notices to 204 | the extent required to remedy known factual inaccuracies. 205 | 206 | 3.5. Application of Additional Terms 207 | 208 | You may choose to offer, and to charge a fee for, warranty, support, 209 | indemnity or liability obligations to one or more recipients of Covered 210 | Software. However, You may do so only on Your own behalf, and not on 211 | behalf of any Contributor. You must make it absolutely clear that any 212 | such warranty, support, indemnity, or liability obligation is offered by 213 | You alone, and You hereby agree to indemnify every Contributor for any 214 | liability incurred by such Contributor as a result of warranty, support, 215 | indemnity or liability terms You offer. You may include additional 216 | disclaimers of warranty and limitations of liability specific to any 217 | jurisdiction. 218 | 219 | 4. Inability to Comply Due to Statute or Regulation 220 | --------------------------------------------------- 221 | 222 | If it is impossible for You to comply with any of the terms of this 223 | License with respect to some or all of the Covered Software due to 224 | statute, judicial order, or regulation then You must: (a) comply with 225 | the terms of this License to the maximum extent possible; and (b) 226 | describe the limitations and the code they affect. Such description must 227 | be placed in a text file included with all distributions of the Covered 228 | Software under this License. Except to the extent prohibited by statute 229 | or regulation, such description must be sufficiently detailed for a 230 | recipient of ordinary skill to be able to understand it. 231 | 232 | 5. Termination 233 | -------------- 234 | 235 | 5.1. The rights granted under this License will terminate automatically 236 | if You fail to comply with any of its terms. However, if You become 237 | compliant, then the rights granted under this License from a particular 238 | Contributor are reinstated (a) provisionally, unless and until such 239 | Contributor explicitly and finally terminates Your grants, and (b) on an 240 | ongoing basis, if such Contributor fails to notify You of the 241 | non-compliance by some reasonable means prior to 60 days after You have 242 | come back into compliance. Moreover, Your grants from a particular 243 | Contributor are reinstated on an ongoing basis if such Contributor 244 | notifies You of the non-compliance by some reasonable means, this is the 245 | first time You have received notice of non-compliance with this License 246 | from such Contributor, and You become compliant prior to 30 days after 247 | Your receipt of the notice. 248 | 249 | 5.2. If You initiate litigation against any entity by asserting a patent 250 | infringement claim (excluding declaratory judgment actions, 251 | counter-claims, and cross-claims) alleging that a Contributor Version 252 | directly or indirectly infringes any patent, then the rights granted to 253 | You by any and all Contributors for the Covered Software under Section 254 | 2.1 of this License shall terminate. 255 | 256 | 5.3. In the event of termination under Sections 5.1 or 5.2 above, all 257 | end user license agreements (excluding distributors and resellers) which 258 | have been validly granted by You or Your distributors under this License 259 | prior to termination shall survive termination. 260 | 261 | ************************************************************************ 262 | * * 263 | * 6. Disclaimer of Warranty * 264 | * ------------------------- * 265 | * * 266 | * Covered Software is provided under this License on an "as is" * 267 | * basis, without warranty of any kind, either expressed, implied, or * 268 | * statutory, including, without limitation, warranties that the * 269 | * Covered Software is free of defects, merchantable, fit for a * 270 | * particular purpose or non-infringing. The entire risk as to the * 271 | * quality and performance of the Covered Software is with You. * 272 | * Should any Covered Software prove defective in any respect, You * 273 | * (not any Contributor) assume the cost of any necessary servicing, * 274 | * repair, or correction. This disclaimer of warranty constitutes an * 275 | * essential part of this License. No use of any Covered Software is * 276 | * authorized under this License except under this disclaimer. * 277 | * * 278 | ************************************************************************ 279 | 280 | ************************************************************************ 281 | * * 282 | * 7. Limitation of Liability * 283 | * -------------------------- * 284 | * * 285 | * Under no circumstances and under no legal theory, whether tort * 286 | * (including negligence), contract, or otherwise, shall any * 287 | * Contributor, or anyone who distributes Covered Software as * 288 | * permitted above, be liable to You for any direct, indirect, * 289 | * special, incidental, or consequential damages of any character * 290 | * including, without limitation, damages for lost profits, loss of * 291 | * goodwill, work stoppage, computer failure or malfunction, or any * 292 | * and all other commercial damages or losses, even if such party * 293 | * shall have been informed of the possibility of such damages. This * 294 | * limitation of liability shall not apply to liability for death or * 295 | * personal injury resulting from such party's negligence to the * 296 | * extent applicable law prohibits such limitation. Some * 297 | * jurisdictions do not allow the exclusion or limitation of * 298 | * incidental or consequential damages, so this exclusion and * 299 | * limitation may not apply to You. * 300 | * * 301 | ************************************************************************ 302 | 303 | 8. Litigation 304 | ------------- 305 | 306 | Any litigation relating to this License may be brought only in the 307 | courts of a jurisdiction where the defendant maintains its principal 308 | place of business and such litigation shall be governed by laws of that 309 | jurisdiction, without reference to its conflict-of-law provisions. 310 | Nothing in this Section shall prevent a party's ability to bring 311 | cross-claims or counter-claims. 312 | 313 | 9. Miscellaneous 314 | ---------------- 315 | 316 | This License represents the complete agreement concerning the subject 317 | matter hereof. If any provision of this License is held to be 318 | unenforceable, such provision shall be reformed only to the extent 319 | necessary to make it enforceable. Any law or regulation which provides 320 | that the language of a contract shall be construed against the drafter 321 | shall not be used to construe this License against a Contributor. 322 | 323 | 10. Versions of the License 324 | --------------------------- 325 | 326 | 10.1. New Versions 327 | 328 | Mozilla Foundation is the license steward. Except as provided in Section 329 | 10.3, no one other than the license steward has the right to modify or 330 | publish new versions of this License. Each version will be given a 331 | distinguishing version number. 332 | 333 | 10.2. Effect of New Versions 334 | 335 | You may distribute the Covered Software under the terms of the version 336 | of the License under which You originally received the Covered Software, 337 | or under the terms of any subsequent version published by the license 338 | steward. 339 | 340 | 10.3. Modified Versions 341 | 342 | If you create software not governed by this License, and you want to 343 | create a new license for such software, you may create and use a 344 | modified version of this License if you rename the license and remove 345 | any references to the name of the license steward (except to note that 346 | such modified license differs from this License). 347 | 348 | 10.4. Distributing Source Code Form that is Incompatible With Secondary 349 | Licenses 350 | 351 | If You choose to distribute Source Code Form that is Incompatible With 352 | Secondary Licenses under the terms of this version of the License, the 353 | notice described in Exhibit B of this License must be attached. 354 | 355 | Exhibit A - Source Code Form License Notice 356 | ------------------------------------------- 357 | 358 | This Source Code Form is subject to the terms of the Mozilla Public 359 | License, v. 2.0. If a copy of the MPL was not distributed with this 360 | file, You can obtain one at http://mozilla.org/MPL/2.0/. 361 | 362 | If it is not possible or desirable to put the notice in a particular 363 | file, then You may include the notice in a location (such as a LICENSE 364 | file in a relevant directory) where a recipient would be likely to look 365 | for such a notice. 366 | 367 | You may add additional accurate notices of copyright ownership. 368 | 369 | Exhibit B - "Incompatible With Secondary Licenses" Notice 370 | --------------------------------------------------------- 371 | 372 | This Source Code Form is "Incompatible With Secondary Licenses", as 373 | defined by the Mozilla Public License, v. 2.0. 374 | -------------------------------------------------------------------------------- /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 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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 |

JavaExitHook

4 |
5 | Build: passing 6 | License: MPL 7 | discord 8 | 9 |
10 |
11 |

Simple hook that prevent to halt Java Virtual Machine (mostly used in hacking java programs)

12 | 13 | ## What is used for? 14 | 15 | Idea to create that simple hook was born when i saw a lot of system licenses in minecraft plugins on MC-Market working in that way, when valid pass it through, but when invalid call JVM Exit. 16 | This way completely bypass that checks and causes the virtual machine to move on next instructions. 17 | Hook and the way is very simple :) 18 | 19 | ## Building 20 | 21 | ### Visual Studio 22 | Simplest way to build project. Just import or clone repo and click "Build". Simple as that. 23 | 24 | ### Command line 25 | Just run `msbuild /m /p:Configuration=Release .` 26 | 27 | ## Screenshots 28 | 29 | Example java code: 30 | 31 | ![alt text](https://i.imgur.com/YNcbrYj.png) 32 | 33 | Injected DLL cause that our code will throw Your license is not active disabling" but after that Your license is active! and whole code after that, completely ignoring fact that Virtual Machine should be halted. 34 | 35 | 36 | ## License 37 | 38 | [MPL-2.0](https://github.com/TheEasyPeasy/JavaExitHook/blob/master/LICENSE) 39 | 40 | Copyright (c) 2021-present, TheEasyPeasy 41 | -------------------------------------------------------------------------------- /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 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 | 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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /dllmain.c: -------------------------------------------------------------------------------- 1 | #include "pch.h" 2 | #include "psapi.h" 3 | #include 4 | #include "scan.h" 5 | #include "exit.h" 6 | 7 | 8 | 9 | 10 | 11 | BOOL APIENTRY DllMain( HMODULE hModule, 12 | DWORD ul_reason_for_call, 13 | LPVOID lpReserved 14 | ) 15 | { 16 | switch (ul_reason_for_call) 17 | { 18 | case DLL_PROCESS_ATTACH: 19 | case DLL_THREAD_ATTACH: 20 | case DLL_THREAD_DETACH: 21 | case DLL_PROCESS_DETACH: 22 | CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)setupHook, NULL, 0, NULL); 23 | break; 24 | } 25 | return TRUE; 26 | } 27 | 28 | -------------------------------------------------------------------------------- /exit.c: -------------------------------------------------------------------------------- 1 |  2 | #include "exit.h" 3 | #include 4 | #include 5 | #include "scan.h" 6 | 7 | bool started = false; 8 | 9 | void setupHook(void) { 10 | if (started) return; 11 | started = true; 12 | AllocConsole(); 13 | //freopen("CONOUT$", "w", stdout); 14 | HMODULE jvmModule = GetModuleHandle(L"jvm.dll"); 15 | if (jvmModule == NULL) { 16 | puts("jvm.dll module not found!"); 17 | return; 18 | } 19 | MODULEINFO moduleinfo; 20 | HANDLE procHandle = GetCurrentProcess(); 21 | GetModuleInformation(procHandle, jvmModule, &moduleinfo, sizeof(moduleinfo)); 22 | CloseHandle(procHandle); 23 | //use if necessary 24 | //uintptr_t found = ps_find_idastyle("48 89 5C 24 08 48 89 74 24 10 57 48 83 EC 20 8B F9 8B 0D 11 4B 63 00 FF 15 E3 B3 45 00 48 8B D8 C7 80 70 02 00 00 05 00 00 00", (uintptr_t)moduleinfo.EntryPoint, moduleinfo.SizeOfImage); 25 | void* found = GetProcAddress(jvmModule, "JVM_Halt"); 26 | if (found) 27 | { 28 | if (MH_Initialize() != MH_OK) { 29 | puts("Something went wrong while initializing hooks"); 30 | return; 31 | } 32 | 33 | if (MH_CreateHook((void*)found, (void*)hookedExit, NULL) != MH_OK) { 34 | puts("Hook failed!"); 35 | return; 36 | } 37 | 38 | if (MH_EnableHook((void*)found) != MH_OK) { 39 | puts("Hook failed!"); 40 | } 41 | puts("Hook has been initialized and enabled!"); 42 | } 43 | } 44 | 45 | void hookedExit(int status) { 46 | //puts("¯\_(ツ)_/¯"); 47 | } 48 | 49 | -------------------------------------------------------------------------------- /exit.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "MinHook.h" 4 | 5 | typedef int(__fastcall* EXITCALL) (int status); 6 | 7 | 8 | void setupHook(void); 9 | 10 | void hookedExit(int status); 11 | -------------------------------------------------------------------------------- /framework.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define WIN32_LEAN_AND_MEAN // Wyklucz rzadko używane rzeczy z nagłówków systemu Windows 4 | // Pliki nagłówkowe systemu Windows 5 | #include 6 | -------------------------------------------------------------------------------- /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 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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 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 | } 250 | 251 | if (m_mod != 3 && m_rm == 4) { 252 | hs->flags |= F_SIB; 253 | p++; 254 | hs->sib = c; 255 | hs->sib_scale = c >> 6; 256 | hs->sib_index = (c & 0x3f) >> 3; 257 | if ((hs->sib_base = c & 7) == 5 && !(m_mod & 1)) 258 | disp_size = 4; 259 | } 260 | 261 | p--; 262 | switch (disp_size) { 263 | case 1: 264 | hs->flags |= F_DISP8; 265 | hs->disp.disp8 = *p; 266 | break; 267 | case 2: 268 | hs->flags |= F_DISP16; 269 | hs->disp.disp16 = *(uint16_t *)p; 270 | break; 271 | case 4: 272 | hs->flags |= F_DISP32; 273 | hs->disp.disp32 = *(uint32_t *)p; 274 | } 275 | p += disp_size; 276 | } else if (pref & PRE_LOCK) 277 | hs->flags |= F_ERROR | F_ERROR_LOCK; 278 | 279 | if (cflags & C_IMM_P66) { 280 | if (cflags & C_REL32) { 281 | if (pref & PRE_66) { 282 | hs->flags |= F_IMM16 | F_RELATIVE; 283 | hs->imm.imm16 = *(uint16_t *)p; 284 | p += 2; 285 | goto disasm_done; 286 | } 287 | goto rel32_ok; 288 | } 289 | if (op64) { 290 | hs->flags |= F_IMM64; 291 | hs->imm.imm64 = *(uint64_t *)p; 292 | p += 8; 293 | } else if (!(pref & PRE_66)) { 294 | hs->flags |= F_IMM32; 295 | hs->imm.imm32 = *(uint32_t *)p; 296 | p += 4; 297 | } else 298 | goto imm16_ok; 299 | } 300 | 301 | 302 | if (cflags & C_IMM16) { 303 | imm16_ok: 304 | hs->flags |= F_IMM16; 305 | hs->imm.imm16 = *(uint16_t *)p; 306 | p += 2; 307 | } 308 | if (cflags & C_IMM8) { 309 | hs->flags |= F_IMM8; 310 | hs->imm.imm8 = *p++; 311 | } 312 | 313 | if (cflags & C_REL32) { 314 | rel32_ok: 315 | hs->flags |= F_IMM32 | F_RELATIVE; 316 | hs->imm.imm32 = *(uint32_t *)p; 317 | p += 4; 318 | } else if (cflags & C_REL8) { 319 | hs->flags |= F_IMM8 | F_RELATIVE; 320 | hs->imm.imm8 = *p++; 321 | } 322 | 323 | disasm_done: 324 | 325 | if ((hs->len = (uint8_t)(p-(uint8_t *)code)) > 15) { 326 | hs->flags |= F_ERROR | F_ERROR_LENGTH; 327 | hs->len = 15; 328 | } 329 | 330 | return (unsigned int)hs->len; 331 | } 332 | 333 | #endif // defined(_M_X64) || defined(__x86_64__) 334 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /hook.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 30 | #include 31 | #include 32 | 33 | #include "MinHook.h" 34 | #include "buffer.h" 35 | #include "trampoline.h" 36 | 37 | #ifndef ARRAYSIZE 38 | #define ARRAYSIZE(A) (sizeof(A)/sizeof((A)[0])) 39 | #endif 40 | 41 | // Initial capacity of the HOOK_ENTRY buffer. 42 | #define INITIAL_HOOK_CAPACITY 32 43 | 44 | // Initial capacity of the thread IDs buffer. 45 | #define INITIAL_THREAD_CAPACITY 128 46 | 47 | // Special hook position values. 48 | #define INVALID_HOOK_POS UINT_MAX 49 | #define ALL_HOOKS_POS UINT_MAX 50 | 51 | // Freeze() action argument defines. 52 | #define ACTION_DISABLE 0 53 | #define ACTION_ENABLE 1 54 | #define ACTION_APPLY_QUEUED 2 55 | 56 | // Thread access rights for suspending/resuming threads. 57 | #define THREAD_ACCESS \ 58 | (THREAD_SUSPEND_RESUME | THREAD_GET_CONTEXT | THREAD_QUERY_INFORMATION | THREAD_SET_CONTEXT) 59 | 60 | // Hook information. 61 | typedef struct _HOOK_ENTRY 62 | { 63 | LPVOID pTarget; // Address of the target function. 64 | LPVOID pDetour; // Address of the detour or relay function. 65 | LPVOID pTrampoline; // Address of the trampoline function. 66 | UINT8 backup[8]; // Original prologue of the target function. 67 | 68 | UINT8 patchAbove : 1; // Uses the hot patch area. 69 | UINT8 isEnabled : 1; // Enabled. 70 | UINT8 queueEnable : 1; // Queued for enabling/disabling when != isEnabled. 71 | 72 | UINT nIP : 4; // Count of the instruction boundaries. 73 | UINT8 oldIPs[8]; // Instruction boundaries of the target function. 74 | UINT8 newIPs[8]; // Instruction boundaries of the trampoline function. 75 | } HOOK_ENTRY, *PHOOK_ENTRY; 76 | 77 | // Suspended threads for Freeze()/Unfreeze(). 78 | typedef struct _FROZEN_THREADS 79 | { 80 | LPDWORD pItems; // Data heap 81 | UINT capacity; // Size of allocated data heap, items 82 | UINT size; // Actual number of data items 83 | } FROZEN_THREADS, *PFROZEN_THREADS; 84 | 85 | //------------------------------------------------------------------------- 86 | // Global Variables: 87 | //------------------------------------------------------------------------- 88 | 89 | // Spin lock flag for EnterSpinLock()/LeaveSpinLock(). 90 | volatile LONG g_isLocked = FALSE; 91 | 92 | // Private heap handle. If not NULL, this library is initialized. 93 | HANDLE g_hHeap = NULL; 94 | 95 | // Hook entries. 96 | struct 97 | { 98 | PHOOK_ENTRY pItems; // Data heap 99 | UINT capacity; // Size of allocated data heap, items 100 | UINT size; // Actual number of data items 101 | } g_hooks; 102 | 103 | //------------------------------------------------------------------------- 104 | // Returns INVALID_HOOK_POS if not found. 105 | static UINT FindHookEntry(LPVOID pTarget) 106 | { 107 | UINT i; 108 | for (i = 0; i < g_hooks.size; ++i) 109 | { 110 | if ((ULONG_PTR)pTarget == (ULONG_PTR)g_hooks.pItems[i].pTarget) 111 | return i; 112 | } 113 | 114 | return INVALID_HOOK_POS; 115 | } 116 | 117 | //------------------------------------------------------------------------- 118 | static PHOOK_ENTRY AddHookEntry() 119 | { 120 | if (g_hooks.pItems == NULL) 121 | { 122 | g_hooks.capacity = INITIAL_HOOK_CAPACITY; 123 | g_hooks.pItems = (PHOOK_ENTRY)HeapAlloc( 124 | g_hHeap, 0, g_hooks.capacity * sizeof(HOOK_ENTRY)); 125 | if (g_hooks.pItems == NULL) 126 | return NULL; 127 | } 128 | else if (g_hooks.size >= g_hooks.capacity) 129 | { 130 | PHOOK_ENTRY p = (PHOOK_ENTRY)HeapReAlloc( 131 | g_hHeap, 0, g_hooks.pItems, (g_hooks.capacity * 2) * sizeof(HOOK_ENTRY)); 132 | if (p == NULL) 133 | return NULL; 134 | 135 | g_hooks.capacity *= 2; 136 | g_hooks.pItems = p; 137 | } 138 | 139 | return &g_hooks.pItems[g_hooks.size++]; 140 | } 141 | 142 | //------------------------------------------------------------------------- 143 | static VOID DeleteHookEntry(UINT pos) 144 | { 145 | if (pos < g_hooks.size - 1) 146 | g_hooks.pItems[pos] = g_hooks.pItems[g_hooks.size - 1]; 147 | 148 | g_hooks.size--; 149 | 150 | if (g_hooks.capacity / 2 >= INITIAL_HOOK_CAPACITY && g_hooks.capacity / 2 >= g_hooks.size) 151 | { 152 | PHOOK_ENTRY p = (PHOOK_ENTRY)HeapReAlloc( 153 | g_hHeap, 0, g_hooks.pItems, (g_hooks.capacity / 2) * sizeof(HOOK_ENTRY)); 154 | if (p == NULL) 155 | return; 156 | 157 | g_hooks.capacity /= 2; 158 | g_hooks.pItems = p; 159 | } 160 | } 161 | 162 | //------------------------------------------------------------------------- 163 | static DWORD_PTR FindOldIP(PHOOK_ENTRY pHook, DWORD_PTR ip) 164 | { 165 | UINT i; 166 | 167 | if (pHook->patchAbove && ip == ((DWORD_PTR)pHook->pTarget - sizeof(JMP_REL))) 168 | return (DWORD_PTR)pHook->pTarget; 169 | 170 | for (i = 0; i < pHook->nIP; ++i) 171 | { 172 | if (ip == ((DWORD_PTR)pHook->pTrampoline + pHook->newIPs[i])) 173 | return (DWORD_PTR)pHook->pTarget + pHook->oldIPs[i]; 174 | } 175 | 176 | #if defined(_M_X64) || defined(__x86_64__) 177 | // Check relay function. 178 | if (ip == (DWORD_PTR)pHook->pDetour) 179 | return (DWORD_PTR)pHook->pTarget; 180 | #endif 181 | 182 | return 0; 183 | } 184 | 185 | //------------------------------------------------------------------------- 186 | static DWORD_PTR FindNewIP(PHOOK_ENTRY pHook, DWORD_PTR ip) 187 | { 188 | UINT i; 189 | for (i = 0; i < pHook->nIP; ++i) 190 | { 191 | if (ip == ((DWORD_PTR)pHook->pTarget + pHook->oldIPs[i])) 192 | return (DWORD_PTR)pHook->pTrampoline + pHook->newIPs[i]; 193 | } 194 | 195 | return 0; 196 | } 197 | 198 | //------------------------------------------------------------------------- 199 | static VOID ProcessThreadIPs(HANDLE hThread, UINT pos, UINT action) 200 | { 201 | // If the thread suspended in the overwritten area, 202 | // move IP to the proper address. 203 | 204 | CONTEXT c; 205 | #if defined(_M_X64) || defined(__x86_64__) 206 | DWORD64 *pIP = &c.Rip; 207 | #else 208 | DWORD *pIP = &c.Eip; 209 | #endif 210 | UINT count; 211 | 212 | c.ContextFlags = CONTEXT_CONTROL; 213 | if (!GetThreadContext(hThread, &c)) 214 | return; 215 | 216 | if (pos == ALL_HOOKS_POS) 217 | { 218 | pos = 0; 219 | count = g_hooks.size; 220 | } 221 | else 222 | { 223 | count = pos + 1; 224 | } 225 | 226 | for (; pos < count; ++pos) 227 | { 228 | PHOOK_ENTRY pHook = &g_hooks.pItems[pos]; 229 | BOOL enable; 230 | DWORD_PTR ip; 231 | 232 | switch (action) 233 | { 234 | case ACTION_DISABLE: 235 | enable = FALSE; 236 | break; 237 | 238 | case ACTION_ENABLE: 239 | enable = TRUE; 240 | break; 241 | 242 | default: // ACTION_APPLY_QUEUED 243 | enable = pHook->queueEnable; 244 | break; 245 | } 246 | if (pHook->isEnabled == enable) 247 | continue; 248 | 249 | if (enable) 250 | ip = FindNewIP(pHook, *pIP); 251 | else 252 | ip = FindOldIP(pHook, *pIP); 253 | 254 | if (ip != 0) 255 | { 256 | *pIP = ip; 257 | SetThreadContext(hThread, &c); 258 | } 259 | } 260 | } 261 | 262 | //------------------------------------------------------------------------- 263 | static BOOL EnumerateThreads(PFROZEN_THREADS pThreads) 264 | { 265 | BOOL succeeded = FALSE; 266 | 267 | HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0); 268 | if (hSnapshot != INVALID_HANDLE_VALUE) 269 | { 270 | THREADENTRY32 te; 271 | te.dwSize = sizeof(THREADENTRY32); 272 | if (Thread32First(hSnapshot, &te)) 273 | { 274 | succeeded = TRUE; 275 | do 276 | { 277 | if (te.dwSize >= (FIELD_OFFSET(THREADENTRY32, th32OwnerProcessID) + sizeof(DWORD)) 278 | && te.th32OwnerProcessID == GetCurrentProcessId() 279 | && te.th32ThreadID != GetCurrentThreadId()) 280 | { 281 | if (pThreads->pItems == NULL) 282 | { 283 | pThreads->capacity = INITIAL_THREAD_CAPACITY; 284 | pThreads->pItems 285 | = (LPDWORD)HeapAlloc(g_hHeap, 0, pThreads->capacity * sizeof(DWORD)); 286 | if (pThreads->pItems == NULL) 287 | { 288 | succeeded = FALSE; 289 | break; 290 | } 291 | } 292 | else if (pThreads->size >= pThreads->capacity) 293 | { 294 | pThreads->capacity *= 2; 295 | LPDWORD p = (LPDWORD)HeapReAlloc( 296 | g_hHeap, 0, pThreads->pItems, pThreads->capacity * sizeof(DWORD)); 297 | if (p == NULL) 298 | { 299 | succeeded = FALSE; 300 | break; 301 | } 302 | 303 | pThreads->pItems = p; 304 | } 305 | pThreads->pItems[pThreads->size++] = te.th32ThreadID; 306 | } 307 | 308 | te.dwSize = sizeof(THREADENTRY32); 309 | } while (Thread32Next(hSnapshot, &te)); 310 | 311 | if (succeeded && GetLastError() != ERROR_NO_MORE_FILES) 312 | succeeded = FALSE; 313 | 314 | if (!succeeded && pThreads->pItems != NULL) 315 | { 316 | HeapFree(g_hHeap, 0, pThreads->pItems); 317 | pThreads->pItems = NULL; 318 | } 319 | } 320 | CloseHandle(hSnapshot); 321 | } 322 | 323 | return succeeded; 324 | } 325 | 326 | //------------------------------------------------------------------------- 327 | static MH_STATUS Freeze(PFROZEN_THREADS pThreads, UINT pos, UINT action) 328 | { 329 | MH_STATUS status = MH_OK; 330 | 331 | pThreads->pItems = NULL; 332 | pThreads->capacity = 0; 333 | pThreads->size = 0; 334 | if (!EnumerateThreads(pThreads)) 335 | { 336 | status = MH_ERROR_MEMORY_ALLOC; 337 | } 338 | else if (pThreads->pItems != NULL) 339 | { 340 | UINT i; 341 | for (i = 0; i < pThreads->size; ++i) 342 | { 343 | HANDLE hThread = OpenThread(THREAD_ACCESS, FALSE, pThreads->pItems[i]); 344 | if (hThread != NULL) 345 | { 346 | SuspendThread(hThread); 347 | ProcessThreadIPs(hThread, pos, action); 348 | CloseHandle(hThread); 349 | } 350 | } 351 | } 352 | 353 | return status; 354 | } 355 | 356 | //------------------------------------------------------------------------- 357 | static VOID Unfreeze(PFROZEN_THREADS pThreads) 358 | { 359 | if (pThreads->pItems != NULL) 360 | { 361 | UINT i; 362 | for (i = 0; i < pThreads->size; ++i) 363 | { 364 | HANDLE hThread = OpenThread(THREAD_ACCESS, FALSE, pThreads->pItems[i]); 365 | if (hThread != NULL) 366 | { 367 | ResumeThread(hThread); 368 | CloseHandle(hThread); 369 | } 370 | } 371 | 372 | HeapFree(g_hHeap, 0, pThreads->pItems); 373 | } 374 | } 375 | 376 | //------------------------------------------------------------------------- 377 | static MH_STATUS EnableHookLL(UINT pos, BOOL enable) 378 | { 379 | PHOOK_ENTRY pHook = &g_hooks.pItems[pos]; 380 | DWORD oldProtect; 381 | SIZE_T patchSize = sizeof(JMP_REL); 382 | LPBYTE pPatchTarget = (LPBYTE)pHook->pTarget; 383 | 384 | if (pHook->patchAbove) 385 | { 386 | pPatchTarget -= sizeof(JMP_REL); 387 | patchSize += sizeof(JMP_REL_SHORT); 388 | } 389 | 390 | if (!VirtualProtect(pPatchTarget, patchSize, PAGE_EXECUTE_READWRITE, &oldProtect)) 391 | return MH_ERROR_MEMORY_PROTECT; 392 | 393 | if (enable) 394 | { 395 | PJMP_REL pJmp = (PJMP_REL)pPatchTarget; 396 | pJmp->opcode = 0xE9; 397 | pJmp->operand = (UINT32)((LPBYTE)pHook->pDetour - (pPatchTarget + sizeof(JMP_REL))); 398 | 399 | if (pHook->patchAbove) 400 | { 401 | PJMP_REL_SHORT pShortJmp = (PJMP_REL_SHORT)pHook->pTarget; 402 | pShortJmp->opcode = 0xEB; 403 | pShortJmp->operand = (UINT8)(0 - (sizeof(JMP_REL_SHORT) + sizeof(JMP_REL))); 404 | } 405 | } 406 | else 407 | { 408 | if (pHook->patchAbove) 409 | memcpy(pPatchTarget, pHook->backup, sizeof(JMP_REL) + sizeof(JMP_REL_SHORT)); 410 | else 411 | memcpy(pPatchTarget, pHook->backup, sizeof(JMP_REL)); 412 | } 413 | 414 | VirtualProtect(pPatchTarget, patchSize, oldProtect, &oldProtect); 415 | 416 | // Just-in-case measure. 417 | FlushInstructionCache(GetCurrentProcess(), pPatchTarget, patchSize); 418 | 419 | pHook->isEnabled = enable; 420 | pHook->queueEnable = enable; 421 | 422 | return MH_OK; 423 | } 424 | 425 | //------------------------------------------------------------------------- 426 | static MH_STATUS EnableAllHooksLL(BOOL enable) 427 | { 428 | MH_STATUS status = MH_OK; 429 | UINT i, first = INVALID_HOOK_POS; 430 | 431 | for (i = 0; i < g_hooks.size; ++i) 432 | { 433 | if (g_hooks.pItems[i].isEnabled != enable) 434 | { 435 | first = i; 436 | break; 437 | } 438 | } 439 | 440 | if (first != INVALID_HOOK_POS) 441 | { 442 | FROZEN_THREADS threads; 443 | status = Freeze(&threads, ALL_HOOKS_POS, enable ? ACTION_ENABLE : ACTION_DISABLE); 444 | if (status == MH_OK) 445 | { 446 | for (i = first; i < g_hooks.size; ++i) 447 | { 448 | if (g_hooks.pItems[i].isEnabled != enable) 449 | { 450 | status = EnableHookLL(i, enable); 451 | if (status != MH_OK) 452 | break; 453 | } 454 | } 455 | 456 | Unfreeze(&threads); 457 | } 458 | } 459 | 460 | return status; 461 | } 462 | 463 | //------------------------------------------------------------------------- 464 | static VOID EnterSpinLock(VOID) 465 | { 466 | SIZE_T spinCount = 0; 467 | 468 | // Wait until the flag is FALSE. 469 | while (InterlockedCompareExchange(&g_isLocked, TRUE, FALSE) != FALSE) 470 | { 471 | // No need to generate a memory barrier here, since InterlockedCompareExchange() 472 | // generates a full memory barrier itself. 473 | 474 | // Prevent the loop from being too busy. 475 | if (spinCount < 32) 476 | Sleep(0); 477 | else 478 | Sleep(1); 479 | 480 | spinCount++; 481 | } 482 | } 483 | 484 | //------------------------------------------------------------------------- 485 | static VOID LeaveSpinLock(VOID) 486 | { 487 | // No need to generate a memory barrier here, since InterlockedExchange() 488 | // generates a full memory barrier itself. 489 | 490 | InterlockedExchange(&g_isLocked, FALSE); 491 | } 492 | 493 | //------------------------------------------------------------------------- 494 | MH_STATUS WINAPI MH_Initialize(VOID) 495 | { 496 | MH_STATUS status = MH_OK; 497 | 498 | EnterSpinLock(); 499 | 500 | if (g_hHeap == NULL) 501 | { 502 | g_hHeap = HeapCreate(0, 0, 0); 503 | if (g_hHeap != NULL) 504 | { 505 | // Initialize the internal function buffer. 506 | InitializeBuffer(); 507 | } 508 | else 509 | { 510 | status = MH_ERROR_MEMORY_ALLOC; 511 | } 512 | } 513 | else 514 | { 515 | status = MH_ERROR_ALREADY_INITIALIZED; 516 | } 517 | 518 | LeaveSpinLock(); 519 | 520 | return status; 521 | } 522 | 523 | //------------------------------------------------------------------------- 524 | MH_STATUS WINAPI MH_Uninitialize(VOID) 525 | { 526 | MH_STATUS status = MH_OK; 527 | 528 | EnterSpinLock(); 529 | 530 | if (g_hHeap != NULL) 531 | { 532 | status = EnableAllHooksLL(FALSE); 533 | if (status == MH_OK) 534 | { 535 | // Free the internal function buffer. 536 | 537 | // HeapFree is actually not required, but some tools detect a false 538 | // memory leak without HeapFree. 539 | 540 | UninitializeBuffer(); 541 | 542 | HeapFree(g_hHeap, 0, g_hooks.pItems); 543 | HeapDestroy(g_hHeap); 544 | 545 | g_hHeap = NULL; 546 | 547 | g_hooks.pItems = NULL; 548 | g_hooks.capacity = 0; 549 | g_hooks.size = 0; 550 | } 551 | } 552 | else 553 | { 554 | status = MH_ERROR_NOT_INITIALIZED; 555 | } 556 | 557 | LeaveSpinLock(); 558 | 559 | return status; 560 | } 561 | 562 | //------------------------------------------------------------------------- 563 | MH_STATUS WINAPI MH_CreateHook(LPVOID pTarget, LPVOID pDetour, LPVOID *ppOriginal) 564 | { 565 | MH_STATUS status = MH_OK; 566 | 567 | EnterSpinLock(); 568 | 569 | if (g_hHeap != NULL) 570 | { 571 | if (IsExecutableAddress(pTarget) && IsExecutableAddress(pDetour)) 572 | { 573 | UINT pos = FindHookEntry(pTarget); 574 | if (pos == INVALID_HOOK_POS) 575 | { 576 | LPVOID pBuffer = AllocateBuffer(pTarget); 577 | if (pBuffer != NULL) 578 | { 579 | TRAMPOLINE ct; 580 | 581 | ct.pTarget = pTarget; 582 | ct.pDetour = pDetour; 583 | ct.pTrampoline = pBuffer; 584 | if (CreateTrampolineFunction(&ct)) 585 | { 586 | PHOOK_ENTRY pHook = AddHookEntry(); 587 | if (pHook != NULL) 588 | { 589 | pHook->pTarget = ct.pTarget; 590 | #if defined(_M_X64) || defined(__x86_64__) 591 | pHook->pDetour = ct.pRelay; 592 | #else 593 | pHook->pDetour = ct.pDetour; 594 | #endif 595 | pHook->pTrampoline = ct.pTrampoline; 596 | pHook->patchAbove = ct.patchAbove; 597 | pHook->isEnabled = FALSE; 598 | pHook->queueEnable = FALSE; 599 | pHook->nIP = ct.nIP; 600 | memcpy(pHook->oldIPs, ct.oldIPs, ARRAYSIZE(ct.oldIPs)); 601 | memcpy(pHook->newIPs, ct.newIPs, ARRAYSIZE(ct.newIPs)); 602 | 603 | // Back up the target function. 604 | 605 | if (ct.patchAbove) 606 | { 607 | memcpy( 608 | pHook->backup, 609 | (LPBYTE)pTarget - sizeof(JMP_REL), 610 | sizeof(JMP_REL) + sizeof(JMP_REL_SHORT)); 611 | } 612 | else 613 | { 614 | memcpy(pHook->backup, pTarget, sizeof(JMP_REL)); 615 | } 616 | 617 | if (ppOriginal != NULL) 618 | *ppOriginal = pHook->pTrampoline; 619 | } 620 | else 621 | { 622 | status = MH_ERROR_MEMORY_ALLOC; 623 | } 624 | } 625 | else 626 | { 627 | status = MH_ERROR_UNSUPPORTED_FUNCTION; 628 | } 629 | 630 | if (status != MH_OK) 631 | { 632 | FreeBuffer(pBuffer); 633 | } 634 | } 635 | else 636 | { 637 | status = MH_ERROR_MEMORY_ALLOC; 638 | } 639 | } 640 | else 641 | { 642 | status = MH_ERROR_ALREADY_CREATED; 643 | } 644 | } 645 | else 646 | { 647 | status = MH_ERROR_NOT_EXECUTABLE; 648 | } 649 | } 650 | else 651 | { 652 | status = MH_ERROR_NOT_INITIALIZED; 653 | } 654 | 655 | LeaveSpinLock(); 656 | 657 | return status; 658 | } 659 | 660 | //------------------------------------------------------------------------- 661 | MH_STATUS WINAPI MH_RemoveHook(LPVOID pTarget) 662 | { 663 | MH_STATUS status = MH_OK; 664 | 665 | EnterSpinLock(); 666 | 667 | if (g_hHeap != NULL) 668 | { 669 | UINT pos = FindHookEntry(pTarget); 670 | if (pos != INVALID_HOOK_POS) 671 | { 672 | if (g_hooks.pItems[pos].isEnabled) 673 | { 674 | FROZEN_THREADS threads; 675 | status = Freeze(&threads, pos, ACTION_DISABLE); 676 | if (status == MH_OK) 677 | { 678 | status = EnableHookLL(pos, FALSE); 679 | 680 | Unfreeze(&threads); 681 | } 682 | } 683 | 684 | if (status == MH_OK) 685 | { 686 | FreeBuffer(g_hooks.pItems[pos].pTrampoline); 687 | DeleteHookEntry(pos); 688 | } 689 | } 690 | else 691 | { 692 | status = MH_ERROR_NOT_CREATED; 693 | } 694 | } 695 | else 696 | { 697 | status = MH_ERROR_NOT_INITIALIZED; 698 | } 699 | 700 | LeaveSpinLock(); 701 | 702 | return status; 703 | } 704 | 705 | //------------------------------------------------------------------------- 706 | static MH_STATUS EnableHook(LPVOID pTarget, BOOL enable) 707 | { 708 | MH_STATUS status = MH_OK; 709 | 710 | EnterSpinLock(); 711 | 712 | if (g_hHeap != NULL) 713 | { 714 | if (pTarget == MH_ALL_HOOKS) 715 | { 716 | status = EnableAllHooksLL(enable); 717 | } 718 | else 719 | { 720 | UINT pos = FindHookEntry(pTarget); 721 | if (pos != INVALID_HOOK_POS) 722 | { 723 | if (g_hooks.pItems[pos].isEnabled != enable) 724 | { 725 | FROZEN_THREADS threads; 726 | status = Freeze(&threads, pos, ACTION_ENABLE); 727 | if (status == MH_OK) 728 | { 729 | status = EnableHookLL(pos, enable); 730 | 731 | Unfreeze(&threads); 732 | } 733 | } 734 | else 735 | { 736 | status = enable ? MH_ERROR_ENABLED : MH_ERROR_DISABLED; 737 | } 738 | } 739 | else 740 | { 741 | status = MH_ERROR_NOT_CREATED; 742 | } 743 | } 744 | } 745 | else 746 | { 747 | status = MH_ERROR_NOT_INITIALIZED; 748 | } 749 | 750 | LeaveSpinLock(); 751 | 752 | return status; 753 | } 754 | 755 | //------------------------------------------------------------------------- 756 | MH_STATUS WINAPI MH_EnableHook(LPVOID pTarget) 757 | { 758 | return EnableHook(pTarget, TRUE); 759 | } 760 | 761 | //------------------------------------------------------------------------- 762 | MH_STATUS WINAPI MH_DisableHook(LPVOID pTarget) 763 | { 764 | return EnableHook(pTarget, FALSE); 765 | } 766 | 767 | //------------------------------------------------------------------------- 768 | static MH_STATUS QueueHook(LPVOID pTarget, BOOL queueEnable) 769 | { 770 | MH_STATUS status = MH_OK; 771 | 772 | EnterSpinLock(); 773 | 774 | if (g_hHeap != NULL) 775 | { 776 | if (pTarget == MH_ALL_HOOKS) 777 | { 778 | UINT i; 779 | for (i = 0; i < g_hooks.size; ++i) 780 | g_hooks.pItems[i].queueEnable = queueEnable; 781 | } 782 | else 783 | { 784 | UINT pos = FindHookEntry(pTarget); 785 | if (pos != INVALID_HOOK_POS) 786 | { 787 | g_hooks.pItems[pos].queueEnable = queueEnable; 788 | } 789 | else 790 | { 791 | status = MH_ERROR_NOT_CREATED; 792 | } 793 | } 794 | } 795 | else 796 | { 797 | status = MH_ERROR_NOT_INITIALIZED; 798 | } 799 | 800 | LeaveSpinLock(); 801 | 802 | return status; 803 | } 804 | 805 | //------------------------------------------------------------------------- 806 | MH_STATUS WINAPI MH_QueueEnableHook(LPVOID pTarget) 807 | { 808 | return QueueHook(pTarget, TRUE); 809 | } 810 | 811 | //------------------------------------------------------------------------- 812 | MH_STATUS WINAPI MH_QueueDisableHook(LPVOID pTarget) 813 | { 814 | return QueueHook(pTarget, FALSE); 815 | } 816 | 817 | //------------------------------------------------------------------------- 818 | MH_STATUS WINAPI MH_ApplyQueued(VOID) 819 | { 820 | MH_STATUS status = MH_OK; 821 | UINT i, first = INVALID_HOOK_POS; 822 | 823 | EnterSpinLock(); 824 | 825 | if (g_hHeap != NULL) 826 | { 827 | for (i = 0; i < g_hooks.size; ++i) 828 | { 829 | if (g_hooks.pItems[i].isEnabled != g_hooks.pItems[i].queueEnable) 830 | { 831 | first = i; 832 | break; 833 | } 834 | } 835 | 836 | if (first != INVALID_HOOK_POS) 837 | { 838 | FROZEN_THREADS threads; 839 | status = Freeze(&threads, ALL_HOOKS_POS, ACTION_APPLY_QUEUED); 840 | if (status == MH_OK) 841 | { 842 | for (i = first; i < g_hooks.size; ++i) 843 | { 844 | PHOOK_ENTRY pHook = &g_hooks.pItems[i]; 845 | if (pHook->isEnabled != pHook->queueEnable) 846 | { 847 | status = EnableHookLL(i, pHook->queueEnable); 848 | if (status != MH_OK) 849 | break; 850 | } 851 | } 852 | 853 | Unfreeze(&threads); 854 | } 855 | } 856 | } 857 | else 858 | { 859 | status = MH_ERROR_NOT_INITIALIZED; 860 | } 861 | 862 | LeaveSpinLock(); 863 | 864 | return status; 865 | } 866 | 867 | //------------------------------------------------------------------------- 868 | MH_STATUS WINAPI MH_CreateHookApiEx( 869 | LPCWSTR pszModule, LPCSTR pszProcName, LPVOID pDetour, 870 | LPVOID *ppOriginal, LPVOID *ppTarget) 871 | { 872 | HMODULE hModule; 873 | LPVOID pTarget; 874 | 875 | hModule = GetModuleHandleW(pszModule); 876 | if (hModule == NULL) 877 | return MH_ERROR_MODULE_NOT_FOUND; 878 | 879 | pTarget = (LPVOID)GetProcAddress(hModule, pszProcName); 880 | if (pTarget == NULL) 881 | return MH_ERROR_FUNCTION_NOT_FOUND; 882 | 883 | if(ppTarget != NULL) 884 | *ppTarget = pTarget; 885 | 886 | return MH_CreateHook(pTarget, pDetour, ppOriginal); 887 | } 888 | 889 | //------------------------------------------------------------------------- 890 | MH_STATUS WINAPI MH_CreateHookApi( 891 | LPCWSTR pszModule, LPCSTR pszProcName, LPVOID pDetour, LPVOID *ppOriginal) 892 | { 893 | return MH_CreateHookApiEx(pszModule, pszProcName, pDetour, ppOriginal, NULL); 894 | } 895 | 896 | //------------------------------------------------------------------------- 897 | const char * WINAPI MH_StatusToString(MH_STATUS status) 898 | { 899 | #define MH_ST2STR(x) \ 900 | case x: \ 901 | return #x; 902 | 903 | switch (status) { 904 | MH_ST2STR(MH_UNKNOWN) 905 | MH_ST2STR(MH_OK) 906 | MH_ST2STR(MH_ERROR_ALREADY_INITIALIZED) 907 | MH_ST2STR(MH_ERROR_NOT_INITIALIZED) 908 | MH_ST2STR(MH_ERROR_ALREADY_CREATED) 909 | MH_ST2STR(MH_ERROR_NOT_CREATED) 910 | MH_ST2STR(MH_ERROR_ENABLED) 911 | MH_ST2STR(MH_ERROR_DISABLED) 912 | MH_ST2STR(MH_ERROR_NOT_EXECUTABLE) 913 | MH_ST2STR(MH_ERROR_UNSUPPORTED_FUNCTION) 914 | MH_ST2STR(MH_ERROR_MEMORY_ALLOC) 915 | MH_ST2STR(MH_ERROR_MEMORY_PROTECT) 916 | MH_ST2STR(MH_ERROR_MODULE_NOT_FOUND) 917 | MH_ST2STR(MH_ERROR_FUNCTION_NOT_FOUND) 918 | } 919 | 920 | #undef MH_ST2STR 921 | 922 | return "(unknown)"; 923 | } 924 | -------------------------------------------------------------------------------- /includes.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // silence MSVC warnings... 4 | #ifdef _MSC_VER 5 | #define _CRT_SECURE_NO_WARNINGS 6 | #define _CRT_NONSTDC_NO_DEPRECATE 7 | #endif 8 | 9 | /* types */ 10 | 11 | typedef unsigned long ulong_t; 12 | 13 | /* includes */ 14 | 15 | // stl 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include -------------------------------------------------------------------------------- /pch.h: -------------------------------------------------------------------------------- 1 | // pch.h: wstępnie skompilowany plik nagłówka. 2 | // Wymienione poniżej pliki są kompilowane tylko raz, co poprawia wydajność kompilacji dla przyszłych kompilacji. 3 | // Ma to także wpływ na wydajność funkcji IntelliSense, w tym uzupełnianie kodu i wiele funkcji przeglądania kodu. 4 | // Jednak WSZYSTKIE wymienione tutaj pliki będą ponownie kompilowane, jeśli którykolwiek z nich zostanie zaktualizowany między kompilacjami. 5 | // Nie dodawaj tutaj plików, które będziesz często aktualizować (obniża to korzystny wpływ na wydajność). 6 | 7 | #ifndef PCH_H 8 | #define PCH_H 9 | 10 | // w tym miejscu dodaj nagłówki, które mają być wstępnie kompilowane 11 | #include "framework.h" 12 | 13 | #endif //PCH_H 14 | -------------------------------------------------------------------------------- /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 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 | -------------------------------------------------------------------------------- /scan.c: -------------------------------------------------------------------------------- 1 | #include "includes.h" 2 | #include "utils.h" 3 | #include "scan.h" 4 | 5 | PS_NOINLINE PS_PatternByte *ps_make_pattern_byte( uint8_t value, bool is_wildcard ) 6 | { 7 | PS_PatternByte *byte = (PS_PatternByte *)( malloc( sizeof( PS_PatternByte ) ) ); 8 | if( byte ) 9 | { 10 | byte->m_value = value; 11 | byte->m_is_wildcard = is_wildcard; 12 | 13 | return byte; 14 | } 15 | 16 | return 0; 17 | } 18 | 19 | PS_NOINLINE bool ps_add_pattern_byte( PS_Pattern *pattern, PS_PatternByte *byte ) 20 | { 21 | if( pattern && byte ) 22 | { 23 | // save off last amount and increment total 24 | size_t amount = pattern->m_amount++; 25 | 26 | // make more room if needed and add a new byte 27 | PS_PatternByte **bytes = (PS_PatternByte **)( realloc( pattern->m_bytes, sizeof( PS_PatternByte * ) * ( (size_t)amount + 1 ) ) ); 28 | if( bytes ) 29 | { 30 | pattern->m_bytes = bytes; 31 | pattern->m_bytes[ amount ] = byte; 32 | 33 | return true; 34 | } 35 | } 36 | 37 | return false; 38 | } 39 | 40 | PS_NOINLINE void ps_free_pattern( PS_Pattern *pattern ) 41 | { 42 | if( pattern ) 43 | { 44 | // free each byte 45 | for( size_t i = 0; i < pattern->m_amount; ++i ) 46 | { 47 | free( pattern->m_bytes[ i ] ); 48 | } 49 | 50 | free( pattern->m_bytes ); 51 | } 52 | } 53 | 54 | PS_NOINLINE bool ps_build_idastyle( PS_Pattern *out_pattern, const char *pattern ) 55 | { 56 | if( out_pattern && pattern && strlen( pattern ) ) 57 | { 58 | // make a copy of the input string 59 | char *str = strdup( pattern ); 60 | 61 | // clean up the input string 62 | str = util_trim_pattern_str( str ); 63 | if( str ) 64 | { 65 | bool valid = true; 66 | PS_Pattern out = { 0 }; 67 | 68 | // iteratively split the input string by space 69 | for( 70 | char *token = strtok( str, " " ); 71 | token; 72 | token = strtok( 0, " " ) 73 | ) 74 | { 75 | // make sure tokens aren't too long 76 | size_t token_len = strlen( token ); 77 | if( !token_len || token_len > 2 ) 78 | { 79 | ps_free_pattern( &out ); 80 | valid = false; 81 | 82 | break; 83 | } 84 | 85 | PS_PatternByte *byte; 86 | 87 | if( token[ 0 ] == L'?' ) // wildcard 88 | { 89 | // add a wildcard byte to array 90 | byte = ps_make_pattern_byte( 0, true ); 91 | if( !byte ) 92 | { 93 | ps_free_pattern( &out ); 94 | valid = false; 95 | 96 | break; 97 | } 98 | 99 | if( !ps_add_pattern_byte( &out, byte ) ) 100 | { 101 | ps_free_pattern( &out ); 102 | valid = false; 103 | 104 | break; 105 | } 106 | } 107 | else // probably a byte 108 | { 109 | // ensure the current token is a valid byte (should only be 1 or 2 chars and valid hex digit(s)) 110 | bool is_valid_byte = false; 111 | 112 | if( token_len == 1 && isxdigit( token[ 0 ] ) ) // 1-char 113 | is_valid_byte = true; 114 | else if( token_len == 2 && isxdigit( token[ 0 ] ) && isxdigit( token[ 1 ] ) ) // 2-char 115 | is_valid_byte = true; 116 | 117 | if( !is_valid_byte ) 118 | { 119 | ps_free_pattern( &out ); 120 | valid = false; 121 | 122 | break; 123 | } 124 | 125 | // attempt to convert the string to a base 16 int and make sure it's in bounds of a uint8_t 126 | ulong_t val = strtoul( token, 0, 16 ); 127 | if( !val || val == ULONG_MAX || val > UINT8_MAX ) 128 | { 129 | ps_free_pattern( &out ); 130 | valid = false; 131 | 132 | break; 133 | } 134 | 135 | // add normal byte to array 136 | byte = ps_make_pattern_byte( (uint8_t)val, false ); 137 | if( !byte ) 138 | { 139 | ps_free_pattern( &out ); 140 | valid = false; 141 | 142 | break; 143 | } 144 | 145 | if( !ps_add_pattern_byte( &out, byte ) ) 146 | { 147 | ps_free_pattern( &out ); 148 | valid = false; 149 | 150 | break; 151 | } 152 | } 153 | } 154 | 155 | free( str ); 156 | 157 | if( valid ) 158 | { 159 | *out_pattern = out; 160 | return true; 161 | } 162 | } 163 | } 164 | 165 | return false; 166 | } 167 | 168 | PS_NOINLINE bool ps_build_codestyle( PS_Pattern *out_pattern, const char *pattern, const char *mask ) 169 | { 170 | if( out_pattern && pattern && mask ) 171 | { 172 | 173 | } 174 | 175 | return false; 176 | } 177 | 178 | PS_NOINLINE uintptr_t ps_find( PS_Pattern *pattern, uintptr_t start, size_t size ) 179 | { 180 | if( pattern && pattern->m_amount && pattern->m_bytes && start && size ) 181 | { 182 | uint8_t *scan_start = (uint8_t *)start; 183 | uint8_t *scan_end = (uint8_t *)( start + size ); 184 | size_t matched = 0; 185 | uintptr_t found = 0; 186 | 187 | // iterate over the range of memory 188 | for( uint8_t *i = scan_start; i < scan_end; ++i ) 189 | { 190 | PS_PatternByte *byte = pattern->m_bytes[ matched ]; 191 | 192 | if( byte->m_value == *i || byte->m_is_wildcard ) // compare byte value. also, wildcards are always a "match" 193 | { 194 | // first match is the "found" location 195 | if( !matched ) 196 | found = (uintptr_t)i; 197 | 198 | ++matched; 199 | } 200 | else // didn't match 201 | { 202 | matched = 0; 203 | found = 0; 204 | } 205 | 206 | // if all matched then return the address to the first match 207 | if( matched >= pattern->m_amount ) 208 | return found; 209 | } 210 | } 211 | 212 | return 0; 213 | } 214 | 215 | PS_NOINLINE uintptr_t ps_find_idastyle( const char *pattern, uintptr_t start, size_t size ) 216 | { 217 | PS_Pattern ptrn; 218 | 219 | if( ps_build_idastyle( &ptrn, pattern ) ) 220 | { 221 | return ps_find( &ptrn, start, size ); 222 | } 223 | 224 | return 0; 225 | } 226 | 227 | PS_NOINLINE uintptr_t ps_find_codestyle( const char *pattern, const char *mask, uintptr_t start, size_t size ) 228 | { 229 | PS_Pattern ptrn; 230 | 231 | if( ps_build_codestyle( &ptrn, pattern, mask ) ) 232 | { 233 | return ps_find( &ptrn, start, size ); 234 | } 235 | 236 | return 0; 237 | } 238 | 239 | PS_NOINLINE void ps_free_pattern_batch( PS_PatternBatches *batch ) 240 | { 241 | if( batch ) 242 | { 243 | 244 | } 245 | } 246 | 247 | PS_NOINLINE void ps_add_idastyle_batch( PS_PatternBatches *batch, uintptr_t *found, const char *pattern ) 248 | { 249 | if( batch && found && pattern ) 250 | { 251 | 252 | } 253 | } 254 | 255 | PS_NOINLINE void ps_add_codestyle_batch( PS_PatternBatches *batch, uintptr_t *found, const char *pattern, const char *mask ) 256 | { 257 | if( batch && found && pattern && mask ) 258 | { 259 | 260 | } 261 | } 262 | 263 | PS_NOINLINE void ps_find_batch( PS_PatternBatches *batch, uintptr_t start, size_t size ) 264 | { 265 | if( batch && batch->m_amount && batch->m_patterns && start && size ) 266 | { 267 | 268 | } 269 | } -------------------------------------------------------------------------------- /scan.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | /* shorthands */ 7 | 8 | #ifdef _MSC_VER 9 | #define PS_NOINLINE __declspec( noinline ) 10 | #elif __GNUC__ 11 | #define PS_NOINLINE __attribute__( ( noinline ) ) 12 | #else 13 | #error "Unknown compiler." 14 | #endif 15 | 16 | /* types */ 17 | 18 | typedef struct PS_PatternByte 19 | { 20 | uint8_t m_value; 21 | bool m_is_wildcard; 22 | } PS_PatternByte; 23 | 24 | typedef struct PS_Pattern 25 | { 26 | size_t m_amount; // amount of bytes in array 27 | PS_PatternByte **m_bytes; // array of bytes 28 | } PS_Pattern; 29 | 30 | typedef struct PS_PatternBatch 31 | { 32 | PS_Pattern *m_pattern; // input pattern 33 | uintptr_t *m_addr; // output address 34 | } PS_PatternBatch; 35 | 36 | typedef struct PS_PatternBatches 37 | { 38 | size_t m_amount; // amount of patterns in array 39 | PS_PatternBatch **m_patterns; // array of batched patterns 40 | } PS_PatternBatches; 41 | 42 | /* funcs */ 43 | 44 | #ifdef __cplusplus 45 | extern "C" 46 | { 47 | #endif 48 | 49 | /* single pattern */ 50 | 51 | // construct "PS_PatternByte", must be freed 52 | // returns NULL on failure 53 | PS_NOINLINE PS_PatternByte *ps_make_pattern_byte( uint8_t value, bool is_wildcard ); 54 | 55 | // attempt to add a byte to a "PS_Pattern", byte must be created with "ps_make_pattern_byte" 56 | // returns false on failure 57 | PS_NOINLINE bool ps_add_pattern_byte( PS_Pattern *pattern, PS_PatternByte *byte ); 58 | 59 | // free a "PS_Pattern" with bytes in it 60 | PS_NOINLINE void ps_free_pattern( PS_Pattern *pattern ); 61 | 62 | // convert an IDA-style pattern string to a "PS_Pattern" type 63 | // returns false on failure 64 | PS_NOINLINE bool ps_build_idastyle( PS_Pattern *out_pattern, const char *pattern ); 65 | 66 | // convert a code-style pattern string to a "PS_Pattern" type 67 | // returns false on failure 68 | PS_NOINLINE bool ps_build_codestyle( PS_Pattern *out_pattern, const char *pattern, const char *mask ); 69 | 70 | // find pattern by "PS_Pattern" 71 | // must construct a "PS_Pattern" from "ps_make_pattern" and "ps_add_pattern_byte", free with "ps_free_pattern" 72 | // returns NULL on failure 73 | PS_NOINLINE uintptr_t ps_find( PS_Pattern *pattern, uintptr_t start, size_t size ); 74 | 75 | // find pattern by IDA-style pattern 76 | // example: "AA B CC ? DD" (double question marks and single bytes are supported) 77 | // returns NULL on failure 78 | PS_NOINLINE uintptr_t ps_find_idastyle( const char *pattern, uintptr_t start, size_t size ); 79 | 80 | // find pattern by code-style pattern 81 | // example: "\xAA\xBB\xCC\x00\xDD", "xxx?x" 82 | // returns NULL on failure 83 | PS_NOINLINE uintptr_t ps_find_codestyle( const char *pattern, const char *mask, uintptr_t start, size_t size ); 84 | 85 | /* multiple patterns */ 86 | 87 | // free a "PS_PatternBatches" with patterns in it 88 | PS_NOINLINE void ps_free_pattern_batch( PS_PatternBatches *batch ); 89 | 90 | // adds an IDA-style pattern to a "PS_PatternBatch" 91 | PS_NOINLINE void ps_add_codestyle_batch( PS_PatternBatches *batch, uintptr_t *found, const char *pattern, const char *mask ); 92 | 93 | // adds a code-style pattern to a "PS_PatternBatch" 94 | PS_NOINLINE void ps_add_idastyle_batch( PS_PatternBatches *batch, uintptr_t *found, const char *pattern ); 95 | 96 | // find all patterns in a batch 97 | PS_NOINLINE void ps_find_batch( PS_PatternBatches *batch, uintptr_t start, size_t size ); 98 | 99 | #ifdef __cplusplus 100 | } 101 | #endif -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 30 | 31 | #ifdef _MSC_VER 32 | #include 33 | #endif 34 | 35 | #ifndef ARRAYSIZE 36 | #define ARRAYSIZE(A) (sizeof(A)/sizeof((A)[0])) 37 | #endif 38 | 39 | #if defined(_M_X64) || defined(__x86_64__) 40 | #include "hde64.h" 41 | typedef hde64s HDE; 42 | #define HDE_DISASM(code, hs) hde64_disasm(code, hs) 43 | #else 44 | #include "hde32.h" 45 | typedef hde32s HDE; 46 | #define HDE_DISASM(code, hs) hde32_disasm(code, hs) 47 | #endif 48 | 49 | #include "trampoline.h" 50 | #include "buffer.h" 51 | 52 | // Maximum size of a trampoline function. 53 | #if defined(_M_X64) || defined(__x86_64__) 54 | #define TRAMPOLINE_MAX_SIZE (MEMORY_SLOT_SIZE - sizeof(JMP_ABS)) 55 | #else 56 | #define TRAMPOLINE_MAX_SIZE MEMORY_SLOT_SIZE 57 | #endif 58 | 59 | //------------------------------------------------------------------------- 60 | static BOOL IsCodePadding(LPBYTE pInst, UINT size) 61 | { 62 | UINT i; 63 | 64 | if (pInst[0] != 0x00 && pInst[0] != 0x90 && pInst[0] != 0xCC) 65 | return FALSE; 66 | 67 | for (i = 1; i < size; ++i) 68 | { 69 | if (pInst[i] != pInst[0]) 70 | return FALSE; 71 | } 72 | return TRUE; 73 | } 74 | 75 | //------------------------------------------------------------------------- 76 | BOOL CreateTrampolineFunction(PTRAMPOLINE ct) 77 | { 78 | #if defined(_M_X64) || defined(__x86_64__) 79 | CALL_ABS call = { 80 | 0xFF, 0x15, 0x00000002, // FF15 00000002: CALL [RIP+8] 81 | 0xEB, 0x08, // EB 08: JMP +10 82 | 0x0000000000000000ULL // Absolute destination address 83 | }; 84 | JMP_ABS jmp = { 85 | 0xFF, 0x25, 0x00000000, // FF25 00000000: JMP [RIP+6] 86 | 0x0000000000000000ULL // Absolute destination address 87 | }; 88 | JCC_ABS jcc = { 89 | 0x70, 0x0E, // 7* 0E: J** +16 90 | 0xFF, 0x25, 0x00000000, // FF25 00000000: JMP [RIP+6] 91 | 0x0000000000000000ULL // Absolute destination address 92 | }; 93 | #else 94 | CALL_REL call = { 95 | 0xE8, // E8 xxxxxxxx: CALL +5+xxxxxxxx 96 | 0x00000000 // Relative destination address 97 | }; 98 | JMP_REL jmp = { 99 | 0xE9, // E9 xxxxxxxx: JMP +5+xxxxxxxx 100 | 0x00000000 // Relative destination address 101 | }; 102 | JCC_REL jcc = { 103 | 0x0F, 0x80, // 0F8* xxxxxxxx: J** +6+xxxxxxxx 104 | 0x00000000 // Relative destination address 105 | }; 106 | #endif 107 | 108 | UINT8 oldPos = 0; 109 | UINT8 newPos = 0; 110 | ULONG_PTR jmpDest = 0; // Destination address of an internal jump. 111 | BOOL finished = FALSE; // Is the function completed? 112 | #if defined(_M_X64) || defined(__x86_64__) 113 | UINT8 instBuf[16]; 114 | #endif 115 | 116 | ct->patchAbove = FALSE; 117 | ct->nIP = 0; 118 | 119 | do 120 | { 121 | HDE hs; 122 | UINT copySize; 123 | LPVOID pCopySrc; 124 | ULONG_PTR pOldInst = (ULONG_PTR)ct->pTarget + oldPos; 125 | ULONG_PTR pNewInst = (ULONG_PTR)ct->pTrampoline + newPos; 126 | 127 | copySize = HDE_DISASM((LPVOID)pOldInst, &hs); 128 | if (hs.flags & F_ERROR) 129 | return FALSE; 130 | 131 | pCopySrc = (LPVOID)pOldInst; 132 | if (oldPos >= sizeof(JMP_REL)) 133 | { 134 | // The trampoline function is long enough. 135 | // Complete the function with the jump to the target function. 136 | #if defined(_M_X64) || defined(__x86_64__) 137 | jmp.address = pOldInst; 138 | #else 139 | jmp.operand = (UINT32)(pOldInst - (pNewInst + sizeof(jmp))); 140 | #endif 141 | pCopySrc = &jmp; 142 | copySize = sizeof(jmp); 143 | 144 | finished = TRUE; 145 | } 146 | #if defined(_M_X64) || defined(__x86_64__) 147 | else if ((hs.modrm & 0xC7) == 0x05) 148 | { 149 | // Instructions using RIP relative addressing. (ModR/M = 00???101B) 150 | 151 | // Modify the RIP relative address. 152 | PUINT32 pRelAddr; 153 | 154 | // Avoid using memcpy to reduce the footprint. 155 | #ifndef _MSC_VER 156 | memcpy(instBuf, (LPBYTE)pOldInst, copySize); 157 | #else 158 | __movsb(instBuf, (LPBYTE)pOldInst, copySize); 159 | #endif 160 | pCopySrc = instBuf; 161 | 162 | // Relative address is stored at (instruction length - immediate value length - 4). 163 | pRelAddr = (PUINT32)(instBuf + hs.len - ((hs.flags & 0x3C) >> 2) - 4); 164 | *pRelAddr 165 | = (UINT32)((pOldInst + hs.len + (INT32)hs.disp.disp32) - (pNewInst + hs.len)); 166 | 167 | // Complete the function if JMP (FF /4). 168 | if (hs.opcode == 0xFF && hs.modrm_reg == 4) 169 | finished = TRUE; 170 | } 171 | #endif 172 | else if (hs.opcode == 0xE8) 173 | { 174 | // Direct relative CALL 175 | ULONG_PTR dest = pOldInst + hs.len + (INT32)hs.imm.imm32; 176 | #if defined(_M_X64) || defined(__x86_64__) 177 | call.address = dest; 178 | #else 179 | call.operand = (UINT32)(dest - (pNewInst + sizeof(call))); 180 | #endif 181 | pCopySrc = &call; 182 | copySize = sizeof(call); 183 | } 184 | else if ((hs.opcode & 0xFD) == 0xE9) 185 | { 186 | // Direct relative JMP (EB or E9) 187 | ULONG_PTR dest = pOldInst + hs.len; 188 | 189 | if (hs.opcode == 0xEB) // isShort jmp 190 | dest += (INT8)hs.imm.imm8; 191 | else 192 | dest += (INT32)hs.imm.imm32; 193 | 194 | // Simply copy an internal jump. 195 | if ((ULONG_PTR)ct->pTarget <= dest 196 | && dest < ((ULONG_PTR)ct->pTarget + sizeof(JMP_REL))) 197 | { 198 | if (jmpDest < dest) 199 | jmpDest = dest; 200 | } 201 | else 202 | { 203 | #if defined(_M_X64) || defined(__x86_64__) 204 | jmp.address = dest; 205 | #else 206 | jmp.operand = (UINT32)(dest - (pNewInst + sizeof(jmp))); 207 | #endif 208 | pCopySrc = &jmp; 209 | copySize = sizeof(jmp); 210 | 211 | // Exit the function if it is not in the branch. 212 | finished = (pOldInst >= jmpDest); 213 | } 214 | } 215 | else if ((hs.opcode & 0xF0) == 0x70 216 | || (hs.opcode & 0xFC) == 0xE0 217 | || (hs.opcode2 & 0xF0) == 0x80) 218 | { 219 | // Direct relative Jcc 220 | ULONG_PTR dest = pOldInst + hs.len; 221 | 222 | if ((hs.opcode & 0xF0) == 0x70 // Jcc 223 | || (hs.opcode & 0xFC) == 0xE0) // LOOPNZ/LOOPZ/LOOP/JECXZ 224 | dest += (INT8)hs.imm.imm8; 225 | else 226 | dest += (INT32)hs.imm.imm32; 227 | 228 | // Simply copy an internal jump. 229 | if ((ULONG_PTR)ct->pTarget <= dest 230 | && dest < ((ULONG_PTR)ct->pTarget + sizeof(JMP_REL))) 231 | { 232 | if (jmpDest < dest) 233 | jmpDest = dest; 234 | } 235 | else if ((hs.opcode & 0xFC) == 0xE0) 236 | { 237 | // LOOPNZ/LOOPZ/LOOP/JCXZ/JECXZ to the outside are not supported. 238 | return FALSE; 239 | } 240 | else 241 | { 242 | UINT8 cond = ((hs.opcode != 0x0F ? hs.opcode : hs.opcode2) & 0x0F); 243 | #if defined(_M_X64) || defined(__x86_64__) 244 | // Invert the condition in x64 mode to simplify the conditional jump logic. 245 | jcc.opcode = 0x71 ^ cond; 246 | jcc.address = dest; 247 | #else 248 | jcc.opcode1 = 0x80 | cond; 249 | jcc.operand = (UINT32)(dest - (pNewInst + sizeof(jcc))); 250 | #endif 251 | pCopySrc = &jcc; 252 | copySize = sizeof(jcc); 253 | } 254 | } 255 | else if ((hs.opcode & 0xFE) == 0xC2) 256 | { 257 | // RET (C2 or C3) 258 | 259 | // Complete the function if not in a branch. 260 | finished = (pOldInst >= jmpDest); 261 | } 262 | 263 | // Can't alter the instruction length in a branch. 264 | if (pOldInst < jmpDest && copySize != hs.len) 265 | return FALSE; 266 | 267 | // Trampoline function is too large. 268 | if ((newPos + copySize) > TRAMPOLINE_MAX_SIZE) 269 | return FALSE; 270 | 271 | // Trampoline function has too many instructions. 272 | if (ct->nIP >= ARRAYSIZE(ct->oldIPs)) 273 | return FALSE; 274 | 275 | ct->oldIPs[ct->nIP] = oldPos; 276 | ct->newIPs[ct->nIP] = newPos; 277 | ct->nIP++; 278 | 279 | // Avoid using memcpy to reduce the footprint. 280 | #ifndef _MSC_VER 281 | memcpy((LPBYTE)ct->pTrampoline + newPos, pCopySrc, copySize); 282 | #else 283 | __movsb((LPBYTE)ct->pTrampoline + newPos, (LPBYTE)pCopySrc, copySize); 284 | #endif 285 | newPos += copySize; 286 | oldPos += hs.len; 287 | } 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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /utils.c: -------------------------------------------------------------------------------- 1 | #include "utils.h" 2 | 3 | PS_NOINLINE char *util_trim_pattern_str( const char *str ) 4 | { 5 | if( str ) 6 | { 7 | size_t len = strlen( str ); 8 | if( len ) 9 | { 10 | char *start = (char *)str; 11 | char *end = ( start + len ) - 1; 12 | 13 | // move start ptr up 14 | for( size_t i = 0; i < len; ++i ) 15 | { 16 | if( isspace( *start ) || *start == '?' ) 17 | ++start; 18 | } 19 | 20 | // move end ptr down 21 | for( size_t i = len; len--; ) 22 | { 23 | if( isspace( *end ) || *end == '?' ) 24 | --end; 25 | } 26 | 27 | // add null terminator 28 | *( end + 1 ) = '\0'; 29 | 30 | // shift string bytes, this must be done in case the string is dynamically allocated and the original ptr isn't changed 31 | size_t new_len = strlen( start ); 32 | if( new_len ) 33 | { 34 | return memmove( (char *)str, start, ( new_len * sizeof( char ) ) + 1 ); 35 | } 36 | } 37 | } 38 | 39 | return 0; 40 | } -------------------------------------------------------------------------------- /utils.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "includes.h" 4 | #include "scan.h" 5 | 6 | // remove some unwanted characters from the input string 7 | extern PS_NOINLINE char *util_trim_pattern_str( const char *str ); --------------------------------------------------------------------------------