forked from ReScrap/ScrapHacks
		
	Lots of changes (expand to read more)
- Update NOTES with new findings - Add Cutter link to README - Add ASMJIT, ASMTK and Zydis to CMake - Make DX8 setting cofigurable via ScrapHacks REPL - Add scaffolding for build hook trampolines using asmjit - Add on the fly assembling of code to REPL - Clean up command structure - Add memory RWX to REPL - Add stack dumping to REPL - Add Gamevar dumping to REPL - Add hook check to overlay commands (don't work if DX8 not hooked) - Allow nested command definitions for cleaner REPL - AllocConsole() as early as possible - shuffle some code around for cleanup - Add GameVar, PakEntry and HashIndex structures
This commit is contained in:
		
							parent
							
								
									48bf3773c9
								
							
						
					
					
						commit
						7e044f0114
					
				
					 20 changed files with 1607 additions and 760 deletions
				
			
		
							
								
								
									
										6
									
								
								.vscode/settings.json
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										6
									
								
								.vscode/settings.json
									
										
									
									
										vendored
									
									
								
							|  | @ -6,5 +6,9 @@ | ||||||
|         "markdown", |         "markdown", | ||||||
|         "latex", |         "latex", | ||||||
|         "plaintext" |         "plaintext" | ||||||
|     ] |     ], | ||||||
|  |     "files.associations": { | ||||||
|  |         "xstring": "cpp", | ||||||
|  |         "iterator": "cpp" | ||||||
|  |     } | ||||||
| } | } | ||||||
							
								
								
									
										210
									
								
								NOTES.md
									
										
									
									
									
								
							
							
						
						
									
										210
									
								
								NOTES.md
									
										
									
									
									
								
							|  | @ -1,4 +1,5 @@ | ||||||
| # Infos | # Infos | ||||||
|  | 
 | ||||||
| - Engine: ScrapEngine | - Engine: ScrapEngine | ||||||
| - Ingame Scripting Language: Python 1.5.2 | - Ingame Scripting Language: Python 1.5.2 | ||||||
| 
 | 
 | ||||||
|  | @ -9,7 +10,8 @@ | ||||||
| 
 | 
 | ||||||
| # Functions identified: | # Functions identified: | ||||||
| 
 | 
 | ||||||
| ## Ingame-Console (Ctrl+\^ or right click on titlebar and select "switch console") (Handler@0x402190): | ## Ingame-Console (Ctrl+\^ or right click on titlebar and select "switch console") (Handler@`0x402190`): | ||||||
|  | 
 | ||||||
| * `<Command>`: Try to evaluate Command as Python expression | * `<Command>`: Try to evaluate Command as Python expression | ||||||
| * `:<Var>`: Get Game Engine Global Variable | * `:<Var>`: Get Game Engine Global Variable | ||||||
| * `:<Var> <Val>`: Set Game Engine Global Variable | * `:<Var> <Val>`: Set Game Engine Global Variable | ||||||
|  | @ -18,7 +20,8 @@ | ||||||
| * `/<command>`: Run Command defined in `QuickConsole.py`: `import quickconsole;quickconsole.%s()` | * `/<command>`: Run Command defined in `QuickConsole.py`: `import quickconsole;quickconsole.%s()` | ||||||
| * `/<command> <arg>,<arg>`: Run function in `QuickConsole.py` with argument(s) `import quickconsole;quickconsole.%s(%s)` | * `/<command> <arg>,<arg>`: Run function in `QuickConsole.py` with argument(s) `import quickconsole;quickconsole.%s(%s)` | ||||||
| 
 | 
 | ||||||
| ## External Console (Scenegraph Debugging?) (Handler@0x5f9520): | ## External Console (Scenegraph Debugging?) (Handler @ `0x5f9520`): | ||||||
|  | 
 | ||||||
| * `listar luces` | * `listar luces` | ||||||
| * `listar` | * `listar` | ||||||
| * `arbol` (Patch Scrap.exe@offset 0x314bc9 replace 0x20 with 0x00 (or just type `arbol ` with a space at the end)) | * `arbol` (Patch Scrap.exe@offset 0x314bc9 replace 0x20 with 0x00 (or just type `arbol ` with a space at the end)) | ||||||
|  | @ -30,36 +33,114 @@ | ||||||
|   * `capullo` |   * `capullo` | ||||||
| 
 | 
 | ||||||
| ## Python Stuff | ## Python Stuff | ||||||
| - Modules List @ 0x79C698 (Module Name as `char*`  followed by Pointer to Init Function) | 
 | ||||||
| - InitPyMod @ 0x5A8FB0 | - `0x79C698`: Modules List (Module Name as `char*`  followed by Pointer to Init Function) | ||||||
| - PyExec @ 0x5A8390 | - `0x5A8FB0`: InitPyMod | ||||||
|  | - `0x5A8390`: PyExec | ||||||
|  | 
 | ||||||
|  | ## Other interesting Memory Addresses | ||||||
|  | 
 | ||||||
|  | - `0x852914`: D3D8-Device pointer | ||||||
|  | - `0x7FCC00`: number of opened `.packed` files | ||||||
|  | - `0x84cb64`: pointer to console command handler | ||||||
|  | - `0x7fac84`: pointer to C++ callback list structure | ||||||
|  | - `0x80b2cc`: pointer to ActionClassList (???) | ||||||
|  | - `0x807a20`: pointer to SScorer (ingame GUI/Menu/Text system) structure (???) | ||||||
|  | - `0x80a398`: pointer to SoundSystem (???) | ||||||
|  | - `0x8b18f0`: pointer to Models Data (can be dumped using scenegraph debugging console) | ||||||
|  | - `0x8b18f4`: pointer to Scenes Data (can be dumped using scenegraph debugging console) | ||||||
|  | - `0x8b18f8`: pointer to active Models Data (can be dumped using scenegraph debugging console) | ||||||
|  | 
 | ||||||
|  | ## Hash-function used in Hash-Tables | ||||||
|  | 
 | ||||||
|  | ```c | ||||||
|  | unsigned long hash(const unsigned char *s) | ||||||
|  | { | ||||||
|  |     unsigned long h = 0, high; | ||||||
|  |     while ( *s ) | ||||||
|  |     { | ||||||
|  |         h = ( h << 4 ) + *s++; | ||||||
|  |         if ( high = h & 0xF0000000 ) | ||||||
|  |             h ^= high >> 24; | ||||||
|  |         h &= ~high; | ||||||
|  |     } | ||||||
|  |     return h; | ||||||
|  | } | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
| 
 | 
 | ||||||
| ## Other Functions: | ## Other Functions: | ||||||
| 
 | 
 | ||||||
| - FindEntity @ 0x404a50 | Check `r2_analyze.py` for full list | ||||||
| - HashTable hashfunc @ 0x404bb0 |  | ||||||
| - Register C Callback @ 0x404460 |  | ||||||
| - Load Game @ 0x417470 |  | ||||||
| - File opening functions @ 0x5e3800 and 0x419950 |  | ||||||
| - Scrap_Debug_Init @ 0x403370 |  | ||||||
| - Scrap_Init @ 0x401770 |  | ||||||
| - Scrap_InitPy @ 0x4026d0 |  | ||||||
| - Scrap_OpenPak @ 0x41ab50 |  | ||||||
| - PyExec @ 0x5a8390 |  | ||||||
| - Setup_Game_Var @ 0x414570 |  | ||||||
| - Throw_Assertion @ 0x5fbc50 |  | ||||||
| - m3d.ini loader @ 0x5f7000 |  | ||||||
| - SM3 Scene Loader @ 0x650f80 (?) |  | ||||||
| - M3D Model Loader @ 0x6665a0 (??) |  | ||||||
| - World_Constructor @ 0x479b20 (???) |  | ||||||
| - World_Init @ 0x479b40 |  | ||||||
| - World_DeInit @ 0x402510 |  | ||||||
| - Make_World @ 0x479870 |  | ||||||
| - RenderFrame(?) @ 0x602a70 |  | ||||||
| 
 | 
 | ||||||
| # Data Structures | ## File Index struct @ `0x7fcbec` | ||||||
| 
 | 
 | ||||||
| D3D8-Device @ `0x852914` | ```cpp | ||||||
|  | 
 | ||||||
|  | struct FileEntry { | ||||||
|  |   uint32_t offset; | ||||||
|  |   uint32_t size; | ||||||
|  |   uint32_t unk; // seems to always be 0xBADFOO1 | ||||||
|  |   unsigned char* path; | ||||||
|  |   FileEntry* next; // next entry in hashtable chain | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | struct FileIDX { | ||||||
|  |   uint32_t size; | ||||||
|  |   FileEntry** entries; | ||||||
|  | }; | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | ## Packed Index struct (array @ `0x7fc1b0`) | ||||||
|  | ```cpp | ||||||
|  | struct PackedIDX { | ||||||
|  |   void** VMT; | ||||||
|  |   unsigned char* filename; | ||||||
|  |   uint32_t locked; // not sure | ||||||
|  |   void* data; | ||||||
|  |   uint32_t seek; | ||||||
|  | } | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | ## C(++)-Callbacks @ `0x7fac84` | ||||||
|  | 
 | ||||||
|  | Structure: | ||||||
|  | 
 | ||||||
|  | ```cpp | ||||||
|  | struct CPP_Callback { | ||||||
|  |   const char* name; | ||||||
|  |   void* func; | ||||||
|  |   CPP_Callback* left; | ||||||
|  |   CPP_Callback* right; | ||||||
|  | } | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | ## Game engine Variables Pointer @ `0x7FBE4C` | ||||||
|  | 
 | ||||||
|  | Structure: | ||||||
|  | 
 | ||||||
|  | ```cpp | ||||||
|  | struct GameVar { | ||||||
|  |   GameVar* next; | ||||||
|  |   const char* name; | ||||||
|  |   const char* desc; | ||||||
|  |   uint8_t subtype; | ||||||
|  |   uint8_t type; | ||||||
|  |   uint16_t unk; | ||||||
|  |   void* value; | ||||||
|  |   void* def_value; | ||||||
|  | } | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | Types | ||||||
|  | 
 | ||||||
|  | | Value  | Type                    | | ||||||
|  | | ------ | ----------------------- | | ||||||
|  | | `0x10` | const char*             | | ||||||
|  | | `0x20` | int32_t                 | | ||||||
|  | | `0x30` | User Control Definition | | ||||||
|  | | `0x40` | float                   | | ||||||
|  | | `0x60` | Callback function       | | ||||||
| 
 | 
 | ||||||
| ## Game World/State Pointer @ `0x7fe944` | ## Game World/State Pointer @ `0x7fe944` | ||||||
| 
 | 
 | ||||||
|  | @ -70,6 +151,10 @@ Points to World struct | ||||||
| | 0x0000 | `void**`                 | Virtual Method Table                   | | | 0x0000 | `void**`                 | Virtual Method Table                   | | ||||||
| | 0x0004 | `uint32_t`               | Size of Entity Hashtable               | | | 0x0004 | `uint32_t`               | Size of Entity Hashtable               | | ||||||
| | 0x0008 | `void**`                 | Pointer to Entity Hashtable            | | | 0x0008 | `void**`                 | Pointer to Entity Hashtable            | | ||||||
|  | | 0x0288 | `pyEntity*`              | UsrEntity[0]                           | | ||||||
|  | | 0x028C | `pyEntity*`              | UsrEntity[1]                           | | ||||||
|  | | 0x0290 | `pyEntity*`              | UsrEntity[2]                           | | ||||||
|  | | 0x0294 | `pyEntity*`              | UsrEntity[3]                           | | ||||||
| | 0x02B8 | `uint32_t`               | Number of entity lists                 | | | 0x02B8 | `uint32_t`               | Number of entity lists                 | | ||||||
| | 0x02BC | `void**`                 | Pointer to entity list Hashtable       | | | 0x02BC | `void**`                 | Pointer to entity list Hashtable       | | ||||||
| | 0x0330 | `float[3]`               | Time (why 3 times?)                    | | | 0x0330 | `float[3]`               | Time (why 3 times?)                    | | ||||||
|  | @ -91,18 +176,19 @@ Points to World struct | ||||||
| | 0x2238 | `???`                    | Used in `World_Init`                   | | | 0x2238 | `???`                    | Used in `World_Init`                   | | ||||||
| | 0x2254 | `float`                  | Used in `World_Init`                   | | | 0x2254 | `float`                  | Used in `World_Init`                   | | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
| ## Entity Hash Table | ## Entity Hash Table | ||||||
| 
 | 
 | ||||||
| Hash-function used: [PJW](https://en.wikipedia.org/wiki/PJW_hash_function) (Same parameters as the example implementation) | Hash-function used: [PJW](https://en.wikipedia.org/wiki/PJW_hash_function) (Same parameters as the example implementation) | ||||||
| 
 | 
 | ||||||
| Entry format: | Entry format: | ||||||
| 
 | 
 | ||||||
| | Offset | Type          | Description                    | | ```cpp | ||||||
| | ------ | ------------- | ------------------------------ | | struct HT_Entry { | ||||||
| | 0x0    | `void*`       | Pointer to data                | |   void* data; | ||||||
| | 0x4    | `const char*` | key as `char*`                 | |   const char* key; | ||||||
| | 0x8    | `void*`       | Pointer to next entry in chain | |   HT_Entry* next; | ||||||
|  | } | ||||||
|  | ``` | ||||||
| 
 | 
 | ||||||
| Data format: | Data format: | ||||||
| 
 | 
 | ||||||
|  | @ -113,10 +199,19 @@ Data format: | ||||||
| | 0x14   | `void*`       | pointer to self (why?)   | | | 0x14   | `void*`       | pointer to self (why?)   | | ||||||
| | 0x28   | `float[3]`    | Position in Game World   | | | 0x28   | `float[3]`    | Position in Game World   | | ||||||
| 
 | 
 | ||||||
|  | ## EntityList Hash Table | ||||||
|  | 
 | ||||||
|  | Attributes: | ||||||
|  | - `Near` | ||||||
|  | - `First` | ||||||
|  | - `Num` | ||||||
|  | - `OnDeath` | ||||||
|  | - `OnDamage` | ||||||
| 
 | 
 | ||||||
| # File Formats | # File Formats | ||||||
| 
 | 
 | ||||||
| ## .packed File Format: | ## .packed File Format: | ||||||
|  | 
 | ||||||
| ``` | ``` | ||||||
| Header: | Header: | ||||||
|     "BFPK\0\0\0\0" |     "BFPK\0\0\0\0" | ||||||
|  | @ -128,35 +223,44 @@ Header: | ||||||
|         Int32ul: offset in file |         Int32ul: offset in file | ||||||
| ``` | ``` | ||||||
| 
 | 
 | ||||||
|  | # Virtual Method Tables: | ||||||
| 
 | 
 | ||||||
|  | check `r2_analyze.py` for full list | ||||||
| 
 | 
 | ||||||
| ## Loading Custom Content (not really working) | ## Loading Custom Content (not really working) | ||||||
|  | 
 | ||||||
| 1. Create a folder `mods` | 1. Create a folder `mods` | ||||||
| 2. Drop a `*.packed` file into it | 2. Drop a `*.packed` file into it | ||||||
| 3. Change `Scrap.cfg` as follows | 3. Change `Scrap.cfg` as follows | ||||||
|    1. Add `ModPathName = mods` |    1. Add `ModPathName = mods` | ||||||
|    2. Add `ModFileName = <filename>` |    2. Add `ModFileName = <filename>` | ||||||
| 
 | 
 | ||||||
| ## Interesting file: | ## Interesting file inside `Data.packed` | ||||||
|  | 
 | ||||||
| * `m3d.ini`: Rendering Engine Configuration | * `m3d.ini`: Rendering Engine Configuration | ||||||
| * `scripts/`: Game Engine Scripts | * `scripts/`: Game Engine Scripts | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| # How to enable External Console: | # How to enable External Console: | ||||||
| 1. exctract `Data.packed` | 
 | ||||||
|  | 1. Right click on the title bar (in windowed mode) and click "Switch Console" | ||||||
|  | 2. or Use a custom Content Pack (**untested!**) | ||||||
|  | 
 | ||||||
|  | # How to enable Scenegraph debugging console | ||||||
|  | 
 | ||||||
|  | 1. extract `Data.packed` | ||||||
| 2. in m3d.ini uncomment (remove `;`) `ConsolaWnd` (GUI Console) and/or `ConsolaTxt` (Text Console) and set the value to `SI` | 2. in m3d.ini uncomment (remove `;`) `ConsolaWnd` (GUI Console) and/or `ConsolaTxt` (Text Console) and set the value to `SI` | ||||||
| 3. repack `Data.packed` | 3. repack `Data.packed` | ||||||
| 
 | 
 | ||||||
| or right click on the title bar (in windowed mode) and click "Switch Console" |  | ||||||
| 
 |  | ||||||
| or Use a custom Content Pack (**untested!**) |  | ||||||
| 
 |  | ||||||
| # Misc. Interesting things | # Misc. Interesting things | ||||||
| - sys.path contains "./lib" so you can load your own Python Modules | 
 | ||||||
|  | - `sys.path` contains "./lib" so you can import your own Python Modules | ||||||
|  | - Games crashes when starting a multiplayer server and feeding it random UDP data | ||||||
| 
 | 
 | ||||||
| # Code Snippets | # Code Snippets | ||||||
| 
 | 
 | ||||||
| ## [Kaitai Struct](http://kaitai.io/) Parser for .packed files | ## [Kaitai Struct](http://kaitai.io/) Parser for .packed files | ||||||
|  | 
 | ||||||
| ```yaml | ```yaml | ||||||
| meta: | meta: | ||||||
|   id: packed |   id: packed | ||||||
|  | @ -170,9 +274,9 @@ seq: | ||||||
|   - id: magic |   - id: magic | ||||||
|     contents: BFPK |     contents: BFPK | ||||||
|     doc: File Magic |     doc: File Magic | ||||||
|   - id: magic2 |   - id: version | ||||||
|     contents: [0,0,0,0] |     contents: [0,0,0,0] | ||||||
|     doc: Second File Magic |     doc: File Version | ||||||
|   - id: num_files |   - id: num_files | ||||||
|     type: u4 |     type: u4 | ||||||
|     doc: Number of files |     doc: Number of files | ||||||
|  | @ -180,7 +284,7 @@ seq: | ||||||
|     type: file_entry |     type: file_entry | ||||||
|     repeat: expr |     repeat: expr | ||||||
|     repeat-expr: num_files |     repeat-expr: num_files | ||||||
|     doc: Directory entry for each file |     doc: Entry for each file | ||||||
| types: | types: | ||||||
|   file_entry: |   file_entry: | ||||||
|     seq: |     seq: | ||||||
|  | @ -203,19 +307,9 @@ types: | ||||||
|         size: size |         size: size | ||||||
| ``` | ``` | ||||||
| 
 | 
 | ||||||
| ## Hashfunction used in Entity Hash-Table | # TODO: | ||||||
| 
 | 
 | ||||||
| ```c | - Figure out how C++ Callbacks work | ||||||
| unsigned long ElfHash(const unsigned char *s) | - Figure out SM3 (Models), CM3 (Animations) file formats | ||||||
| { | - Figure out rest of World structure | ||||||
|     unsigned long h = 0, high; | - Figure out rest of Entity structure | ||||||
|     while ( *s ) |  | ||||||
|     { |  | ||||||
|         h = ( h << 4 ) + *s++; |  | ||||||
|         if ( high = h & 0xF0000000 ) |  | ||||||
|             h ^= high >> 24; |  | ||||||
|         h &= ~high; |  | ||||||
|     } |  | ||||||
|     return h; |  | ||||||
| } |  | ||||||
| ``` |  | ||||||
|  | @ -29,4 +29,4 @@ WIP Memory hacking library | ||||||
| - [Reclass.NET](https://github.com/ReClassNET/ReClass.NET) | - [Reclass.NET](https://github.com/ReClassNET/ReClass.NET) | ||||||
| - [HxD](https://mh-nexus.de/en/hxd/) | - [HxD](https://mh-nexus.de/en/hxd/) | ||||||
| - [Kaitai Struct](http://kaitai.io/) | - [Kaitai Struct](http://kaitai.io/) | ||||||
| - [Radare2](https://www.radare.org/) | - [Radare2](https://www.radare.org/) + [Cutter](https://cutter.re/) | ||||||
							
								
								
									
										25
									
								
								ScrapHacks/.vscode/c_cpp_properties.json
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								ScrapHacks/.vscode/c_cpp_properties.json
									
										
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,25 @@ | ||||||
|  | { | ||||||
|  |     "configurations": [ | ||||||
|  |         { | ||||||
|  |             "name": "Win32", | ||||||
|  |             "includePath": [ | ||||||
|  |                 "${workspaceFolder}/**", | ||||||
|  |                 "${vcpkgRoot}/x64-windows/include", | ||||||
|  |                 "C:/Program Files (x86)/Microsoft Visual Studio/2019/Community/VC/Tools/MSVC/14.22.27905/include" | ||||||
|  |             ], | ||||||
|  |             "defines": [ | ||||||
|  |                 "_DEBUG", | ||||||
|  |                 "UNICODE", | ||||||
|  |                 "_UNICODE" | ||||||
|  |             ], | ||||||
|  |             "windowsSdkVersion": "10.0.18362.0", | ||||||
|  |             "compilerPath": "C:/Program Files (x86)/Microsoft Visual Studio/2019/Community/VC/Tools/MSVC/14.22.27905/bin/Hostx64/x64/cl.exe", | ||||||
|  |             "cStandard": "c11", | ||||||
|  |             "cppStandard": "c++17", | ||||||
|  |             "intelliSenseMode": "msvc-x86", | ||||||
|  |             "configurationProvider": "vector-of-bool.cmake-tools", | ||||||
|  |             "compileCommands": "${workspaceFolder}/build/compile_commands.json" | ||||||
|  |         } | ||||||
|  |     ], | ||||||
|  |     "version": 4 | ||||||
|  | } | ||||||
|  | @ -6,88 +6,123 @@ project(ScrapHacks | ||||||
|         DESCRIPTION "Scrapland memory hacking library" |         DESCRIPTION "Scrapland memory hacking library" | ||||||
|         LANGUAGES CXX) |         LANGUAGES CXX) | ||||||
| 
 | 
 | ||||||
| set(CMAKE_BUILD_TYPE "Release") | message(STATUS "Fetching Scrapland installation folder") | ||||||
|  | get_filename_component(SCRAPLAND_DIR "[HKEY_LOCAL_MACHINE\\SOFTWARE\\WOW6432Node\\MercurySteam Entertainment\\Scrapland;DIRECTORY]" ABSOLUTE CACHE) | ||||||
|  | 
 | ||||||
|  | if(NOT IS_ABSOLUTE "${SCRAPLAND_DIR}" OR NOT EXISTS "${SCRAPLAND_DIR}") | ||||||
|  |   message(FATAL_ERROR "Scrapland installation folder not found!") | ||||||
|  | endif() | ||||||
|  | 
 | ||||||
|  | message(STATUS "Checking Scrap.exe hash") | ||||||
|  | file(SHA1 "${SCRAPLAND_DIR}/Bin/Scrap.exe" SCRAP_EXE_HASH) | ||||||
|  | 
 | ||||||
|  | if(NOT ${SCRAP_EXE_HASH} STREQUAL "d2dde960e8eca69d60c2e39a439088b75f0c89fa") | ||||||
|  |   message(FATAL_ERROR "Scrap.exe hash miss match!") | ||||||
|  | endif() | ||||||
|  | 
 | ||||||
|  | set(FETCHCONTENT_QUIET 0) | ||||||
|  | set(CMAKE_BUILD_TYPE "RelMinSize") | ||||||
| set(CMAKE_INSTALL_PREFIX "${CMAKE_BINARY_DIR}") | set(CMAKE_INSTALL_PREFIX "${CMAKE_BINARY_DIR}") | ||||||
|  | set(ASMJIT_EMBED true) | ||||||
|  | set(ASMTK_EMBED true) | ||||||
|  | set(ZYDIS_BUILD_TOOLS false) | ||||||
|  | set(ZYDIS_BUILD_EXAMPLES false) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| if(WIN32) | if(WIN32) | ||||||
|   if(MSVC) |   if(MSVC) | ||||||
|     # ensure we use minimal "windows.h" lib without the crazy min max macros |     # ensure we use minimal "windows.h" lib without the crazy min max macros | ||||||
|     set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /D \"WIN32_LEAN_AND_MEAN\"") |     # set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /D \"WIN32_LEAN_AND_MEAN\"") | ||||||
|     set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /D \"NOMINMAX\"") |     set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /D \"NOMINMAX\"") | ||||||
|     # disable SAFESEH - to avoid "LNK2026: module unsafe" |     # disable SAFESEH - to avoid "LNK2026: module unsafe" | ||||||
|     set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /D \"SAFESEH:NO\"") |     set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /D \"SAFESEH:NO\"") | ||||||
|     set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /SAFESEH:NO") |     set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /SAFESEH:NO /ignore:4217") | ||||||
|     set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} /SAFESEH:NO") |     set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} /SAFESEH:NO /ignore:4217") | ||||||
|     set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} /SAFESEH:NO") |     set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} /SAFESEH:NO /ignore:4217") | ||||||
|   endif(MSVC) |   endif(MSVC) | ||||||
| endif(WIN32) | endif(WIN32) | ||||||
| 
 | 
 | ||||||
| include(ExternalProject) | include(FetchContent) | ||||||
| 
 | 
 | ||||||
| ExternalProject_Add( | FetchContent_Declare( | ||||||
|   DirectX |   DirectX | ||||||
|   PREFIX ${CMAKE_CURRENT_BINARY_DIR} |   PREFIX ${CMAKE_CURRENT_BINARY_DIR} | ||||||
|   CONFIGURE_COMMAND "" |  | ||||||
|   BUILD_COMMAND "" |  | ||||||
|   INSTALL_COMMAND "" |  | ||||||
|   URL |   URL | ||||||
|     https://archive.org/download/DirectX.8.0a.SDK_includes_libs_only/DirectX.8.0a.SDK.zip |     https://archive.org/download/DirectX.8.0a.SDK_includes_libs_only/DirectX.8.0a.SDK.zip | ||||||
|   URL_HASH SHA1=39f168336d0df92ff14d62d5e3aef1b9e3191312) |   URL_HASH SHA1=39f168336d0df92ff14d62d5e3aef1b9e3191312) | ||||||
| 
 | 
 | ||||||
|  | FetchContent_MakeAvailable(DirectX) | ||||||
| 
 | 
 | ||||||
| ExternalProject_Get_Property(DirectX SOURCE_DIR) | FetchContent_Declare( | ||||||
| include_directories(AFTER ${SOURCE_DIR}/8.0/include/) |     ASM_JIT | ||||||
| link_directories(AFTER ${SOURCE_DIR}/8.0/lib/) |     PREFIX ${CMAKE_CURRENT_BINARY_DIR} | ||||||
|  |     GIT_REPOSITORY git@github.com:asmjit/asmjit.git | ||||||
|  |     GIT_SHALLOW true | ||||||
|  |     GIT_PROGRESS true | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | FetchContent_MakeAvailable(ASM_JIT) | ||||||
|  | 
 | ||||||
|  | FetchContent_Declare( | ||||||
|  |     ASM_TK | ||||||
|  |     PREFIX ${CMAKE_CURRENT_BINARY_DIR} | ||||||
|  |     GIT_REPOSITORY git@github.com:asmjit/asmtk.git | ||||||
|  |     GIT_SHALLOW true | ||||||
|  |     GIT_PROGRESS true | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | FetchContent_MakeAvailable(ASM_TK) | ||||||
|  | 
 | ||||||
|  | set(ASMJIT_DIR ${asm_jit_SOURCE_DIR}) | ||||||
|  | 
 | ||||||
|  | include(${asm_tk_SOURCE_DIR}/CMakeLists.txt) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | FetchContent_Declare( | ||||||
|  |     Zydis | ||||||
|  |     PREFIX ${CMAKE_CURRENT_BINARY_DIR} | ||||||
|  |     GIT_REPOSITORY git@github.com:zyantific/zydis.git | ||||||
|  |     GIT_SHALLOW true | ||||||
|  |     GIT_PROGRESS true | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | # FetchContent_MakeAvailable(Zydis) | ||||||
|  | 
 | ||||||
|  | include_directories(AFTER ${directx_SOURCE_DIR}/8.0/include/ ${ASMTK_INCLUDE_DIRS} ${ASMJIT_INCLUDE_DIRS}) | ||||||
|  | link_directories(AFTER ${directx_SOURCE_DIR}/8.0/lib/) | ||||||
| 
 | 
 | ||||||
| find_package(Python3 3.6 REQUIRED COMPONENTS Interpreter) | find_package(Python3 3.6 REQUIRED COMPONENTS Interpreter) | ||||||
| 
 | 
 | ||||||
| add_custom_target( | add_custom_command( | ||||||
|   MAKE_D3D8_VMT ${Python3_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/src/make_D3D8_VMT.py ${CMAKE_CURRENT_SOURCE_DIR}/src/D3D8_VMT.hpp ${SOURCE_DIR}/8.0/include/d3d8.h |   OUTPUT ${CMAKE_CURRENT_SOURCE_DIR}/src/D3D8_VMT.hpp | ||||||
|   DEPENDS DirectX |   COMMAND ${Python3_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/utils/make_D3D8_VMT.py ${CMAKE_CURRENT_SOURCE_DIR}/src/D3D8_VMT.hpp ${directx_SOURCE_DIR}/8.0/include/d3d8.h | ||||||
|  |   COMMENT "Generating D3D8_VMT.hpp from d3d8.h" | ||||||
|  |   VERBATIM | ||||||
| ) | ) | ||||||
| 
 | add_custom_target(D3D8_VMT ALL | ||||||
| # ExternalProject_Add( |     DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/src/D3D8_VMT.hpp") | ||||||
| #   Python152 |  | ||||||
| #   PREFIX ${CMAKE_CURRENT_BINARY_DIR} |  | ||||||
| #   CONFIGURE_COMMAND "" |  | ||||||
| #   BUILD_COMMAND "" |  | ||||||
| #   INSTALL_COMMAND "" |  | ||||||
| #   URL |  | ||||||
| #     https://www.python.org/ftp/python/src/py152.tgz |  | ||||||
| #   URL_HASH SHA1=2d648d07b1aa1aab32a3a24851c33715141779b9 |  | ||||||
| # ) |  | ||||||
| # ExternalProject_Get_Property(Python152 SOURCE_DIR) |  | ||||||
| # include_directories(AFTER ${SOURCE_DIR}/Include/) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| # ExternalProject_Add( |  | ||||||
| #   Python152_Bin |  | ||||||
| #   PREFIX ${CMAKE_CURRENT_BINARY_DIR} |  | ||||||
| #   CONFIGURE_COMMAND "" |  | ||||||
| #   BUILD_COMMAND "" |  | ||||||
| #   INSTALL_COMMAND "" |  | ||||||
| #   URL |  | ||||||
| #   https://www.python.org/ftp/python/win32/py152.exe |  | ||||||
| #   URL_HASH SHA1=dfaf2dcc3704fb1bbc339db4f33ff94bd61c74c6 |  | ||||||
| # ) |  | ||||||
| # ExternalProject_Get_Property(Python152 SOURCE_DIR) |  | ||||||
| # link_directories(AFTER ${SOURCE_DIR}/) |  | ||||||
| 
 | 
 | ||||||
| add_compile_definitions(_CRT_SECURE_NO_WARNINGS) | add_compile_definitions(_CRT_SECURE_NO_WARNINGS) | ||||||
| add_compile_definitions(POINTER_64=__ptr64) | add_compile_definitions(POINTER_64=__ptr64) | ||||||
| add_library(ScrapHack SHARED | add_library(ScrapHack SHARED | ||||||
|   ${CMAKE_CURRENT_SOURCE_DIR}/src/dllmain.cpp |   ${CMAKE_CURRENT_SOURCE_DIR}/src/dllmain.cpp | ||||||
|   ${CMAKE_CURRENT_SOURCE_DIR}/src/ScrapHack.cpp |   ${CMAKE_CURRENT_SOURCE_DIR}/src/ScrapHack.cpp | ||||||
|   ) |   ${ASMTK_SRC} | ||||||
|  |   ${ASMJIT_SRC} | ||||||
|  | ) | ||||||
|  | 
 | ||||||
| set_target_properties(ScrapHack PROPERTIES SUFFIX ".pyd") | set_target_properties(ScrapHack PROPERTIES SUFFIX ".pyd") | ||||||
| add_dependencies(ScrapHack DirectX) | add_dependencies(ScrapHack D3D8_VMT) | ||||||
| add_dependencies(ScrapHack MAKE_D3D8_VMT) |  | ||||||
| add_dependencies(MAKE_D3D8_VMT DirectX) |  | ||||||
| # add_dependencies(ScrapHack Python152) | # add_dependencies(ScrapHack Python152) | ||||||
| # add_dependencies(ScrapHack Python152_Bin) | # add_dependencies(ScrapHack Python152_Bin) | ||||||
| target_link_libraries(ScrapHack | target_link_libraries(ScrapHack | ||||||
|                       d3d8 |                       d3d8 | ||||||
|                       d3dx8 |                       d3dx8 | ||||||
|                       dxerr8 |                       dxerr8 | ||||||
|  |                       gdiplus | ||||||
|                       # PYTHON15 |                       # PYTHON15 | ||||||
|  |                       # Zydis | ||||||
|                       legacy_stdio_definitions) |                       legacy_stdio_definitions) | ||||||
|  | 
 | ||||||
|  | install(TARGETS ScrapHack RUNTIME DESTINATION ${SCRAPLAND_DIR}/lib) | ||||||
| target_compile_features(ScrapHack PUBLIC cxx_std_11) | target_compile_features(ScrapHack PUBLIC cxx_std_11) | ||||||
|  |  | ||||||
|  | @ -1,3 +1,12 @@ | ||||||
|  | ## Features | ||||||
|  | 
 | ||||||
|  | - read and write memory | ||||||
|  | - change DirectX state | ||||||
|  | - Draw DirectX overlay (still need to make a useful overlay) | ||||||
|  | - Dump various data structures to the console | ||||||
|  | - Assemble and execute code on the fly | ||||||
|  | - Can be controlled via keyboard shortcuts (TODO: allow defining own shortcuts for commands) | ||||||
|  | 
 | ||||||
| ## Prerequisites | ## Prerequisites | ||||||
| 
 | 
 | ||||||
| - Visual Studio  2017/2019 (others might work) | - Visual Studio  2017/2019 (others might work) | ||||||
|  | @ -13,16 +22,13 @@ cmake -G"NMake Makefiles" -B build | ||||||
| cmake --build build --target install | cmake --build build --target install | ||||||
| ``` | ``` | ||||||
| 
 | 
 | ||||||
| this will generate `ScrapHack.pyd` in `./build` | This will find the Games's installation folder, verify that the version you have is compatible with ScrapHacks and drop the compiled `.pyd` file into the correct folder to be imported | ||||||
| 
 | 
 | ||||||
| ## Usage | ## Getting started | ||||||
| 
 | 
 | ||||||
| - create a `lib` folder next to `Scrapland.exe` |  | ||||||
| - copy `ScrapHack.pyd` into said folder |  | ||||||
| - open the ingame console (Ctrl+^) | - open the ingame console (Ctrl+^) | ||||||
| - type `import ScrapHack` | - type `import ScrapHack` | ||||||
| - type `$help` | - type `$help` | ||||||
| - Done! |  | ||||||
| 
 | 
 | ||||||
| ## Notes | ## Notes | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
							
								
								
									
										10
									
								
								ScrapHacks/build.bat
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								ScrapHacks/build.bat
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,10 @@ | ||||||
|  | @echo off | ||||||
|  | setlocal | ||||||
|  | if "%VSINSTALLDIR%"=="" ( | ||||||
|  |   for /f "usebackq tokens=*" %%i in (`vswhere -latest -find **\vcvarsall.bat`) do ( | ||||||
|  |     call "%%i" x86 | ||||||
|  |   ) | ||||||
|  | ) | ||||||
|  | if not exist build cmake -G"NMake Makefiles" -B build | ||||||
|  | cmake --build build --target install | ||||||
|  | endlocal | ||||||
|  | @ -1,33 +1,55 @@ | ||||||
| #pragma once | #pragma once | ||||||
|  | #include <algorithm> | ||||||
|  | using namespace std; | ||||||
|  | 
 | ||||||
| #include <Windows.h> | #include <Windows.h> | ||||||
|  | 
 | ||||||
| #include <d3d8.h> | #include <d3d8.h> | ||||||
| #include <d3dx8.h> | #include <d3dx8.h> | ||||||
| #include <dxerr8.h> | #include <dxerr8.h> | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
| #include "D3D8_VMT.hpp" | #include "D3D8_VMT.hpp" | ||||||
| #include "Hook.hpp" | #include "Hook.hpp" | ||||||
| #include "Scrapland.hpp" | #include "Scrapland.hpp" | ||||||
| #include "Structures.hpp" | #include "Structures.hpp" | ||||||
| #include "Util.hpp" | #include "Util.hpp" | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
| uintmax_t frame = 0; | uintmax_t frame = 0; | ||||||
| bool hooked=false; | bool hooked = false; | ||||||
| bool overlay = false; | bool overlay = false; | ||||||
| LPD3DXFONT m_pFont; | LPD3DXFONT m_pFont; | ||||||
| HFONT hFont; | HFONT hFont; | ||||||
| HBRUSH hBrush; | HBRUSH hBrush; | ||||||
| D3DCOLOR color = D3DCOLOR_ARGB(255, 255, 0, 0); | D3DCOLOR color = D3DCOLOR_XRGB(255, 0, 0); | ||||||
| RECT Rect = {0, 0, 0, 0}; | RECT Rect = {0, 0, 0, 0}; | ||||||
| D3DRECT panel; | D3DRECT panel; | ||||||
| 
 | 
 | ||||||
|  | D3DFILLMODE fillmode = D3DFILLMODE::D3DFILL_SOLID; | ||||||
|  | boolean use_z; | ||||||
|  | 
 | ||||||
| size_t size_ht(HashTable<EntityList> *ht); | size_t size_ht(HashTable<EntityList> *ht); | ||||||
| size_t size_ht(HashTable<Entity> *ht); | size_t size_ht(HashTable<Entity> *ht); | ||||||
| 
 | 
 | ||||||
|  | #define STRINGIFY(x) #x | ||||||
|  | #define TOSTRING(x) STRINGIFY(x) | ||||||
|  | 
 | ||||||
|  | #define DX_Check(call) (_DX_Check(call,TOSTRING(call),__LINE__,__FILE__)) | ||||||
|  | 
 | ||||||
|  | HRESULT _DX_Check(HRESULT res,char* call,size_t line, char* file) { | ||||||
|  |     if (res!=D3D_OK) { | ||||||
|  |         return DXTraceA(file,line,res,call,true); | ||||||
|  |     } | ||||||
|  |     return res; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| LPDIRECT3DDEVICE8 | LPDIRECT3DDEVICE8 | ||||||
| Render(LPDIRECT3DDEVICE8 dev) { | Render(LPDIRECT3DDEVICE8 dev) { | ||||||
|     if (!overlay) { |     if (!overlay) { | ||||||
|         return dev; |         return dev; | ||||||
|     } |     } | ||||||
|  |     IDirect3DSurface8* surf; | ||||||
|     char text[4096]; |     char text[4096]; | ||||||
|     int32_t money = 0; |     int32_t money = 0; | ||||||
|     size_t num_ents = 0; |     size_t num_ents = 0; | ||||||
|  | @ -37,30 +59,42 @@ Render(LPDIRECT3DDEVICE8 dev) { | ||||||
|         num_ents = size_ht(ptr<HashTable<Entity>>(P_WORLD, O_ENTS)); |         num_ents = size_ht(ptr<HashTable<Entity>>(P_WORLD, O_ENTS)); | ||||||
|         num_ent_lst = size_ht(ptr<HashTable<EntityList>>(P_WORLD, O_ENTLISTS)); |         num_ent_lst = size_ht(ptr<HashTable<EntityList>>(P_WORLD, O_ENTLISTS)); | ||||||
|     } |     } | ||||||
|     snprintf(text, 4096, |     snprintf(text, 4096,"ScrapHack v0.1\nFrame: [%lld]\nMoney: [%d]\nEntities: [%ld]\nEntity Lists: [%ld]",++frame, money, num_ents, num_ent_lst); | ||||||
|              R"(ScrapHack v0.1 |  | ||||||
| Frame: [%lld] |  | ||||||
| Money: [%d] |  | ||||||
| Entities: [%ld] |  | ||||||
| Entity Lists: [%ld])", |  | ||||||
|              ++frame, money, num_ents, num_ent_lst); |  | ||||||
|     if (m_pFont == nullptr) { |     if (m_pFont == nullptr) { | ||||||
|         D3DXCreateFont(dev, hFont, &m_pFont); |         D3DXCreateFont(dev, hFont, &m_pFont); | ||||||
|         hFont = nullptr; |         hFont = nullptr; | ||||||
|     } |     } | ||||||
|     m_pFont->Begin(); |     m_pFont->Begin(); | ||||||
|     m_pFont->DrawTextA(text, -1, &Rect, DT_CALCRECT, 0); |     m_pFont->DrawTextA(text, -1, &Rect, DT_CALCRECT, 0); | ||||||
|  |     D3DRECT rec = {Rect.left,Rect.top,Rect.right,Rect.bottom}; | ||||||
|  |     // dev->Clear(1,NULL,D3DCLEAR_TARGET,D3DCOLOR_ARGB(10,255,255,255),0,0);
 | ||||||
|     m_pFont->DrawTextA(text, -1, &Rect, DT_LEFT, color); |     m_pFont->DrawTextA(text, -1, &Rect, DT_LEFT, color); | ||||||
|     m_pFont->End(); |     m_pFont->End(); | ||||||
|     return dev; |     return dev; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
|  | LPDIRECT3DDEVICE8 | ||||||
|  | BeforeRender(LPDIRECT3DDEVICE8 dev) { | ||||||
|  |     return dev; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| HRESULT WINAPI H_EndScene(LPDIRECT3DDEVICE8 dev) { | HRESULT WINAPI H_EndScene(LPDIRECT3DDEVICE8 dev) { | ||||||
|     typedef decltype(&H_EndScene) t_func; |     typedef decltype(&H_EndScene) t_func; | ||||||
|     shared_ptr<Hook> hook = Hook::get(H_EndScene); |     shared_ptr<Hook> hook = Hook::get(H_EndScene); | ||||||
|     return hook->func<t_func>(Render(dev)); |     return hook->func<t_func>(Render(dev)); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
|  | HRESULT WINAPI H_BeginScene(LPDIRECT3DDEVICE8 dev) { | ||||||
|  |     typedef decltype(&H_BeginScene) t_func; | ||||||
|  |     shared_ptr<Hook> hook = Hook::get(H_BeginScene); | ||||||
|  |     HRESULT ret=hook->func<t_func>(dev); | ||||||
|  |     BeforeRender(dev); | ||||||
|  |     return ret; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| HRESULT WINAPI H_SetLight(LPDIRECT3DDEVICE8 dev, DWORD index, | HRESULT WINAPI H_SetLight(LPDIRECT3DDEVICE8 dev, DWORD index, | ||||||
|                           D3DLIGHT8 *light) { |                           D3DLIGHT8 *light) { | ||||||
|     typedef decltype(&H_SetLight) t_func; |     typedef decltype(&H_SetLight) t_func; | ||||||
|  | @ -87,13 +121,13 @@ HRESULT WINAPI H_DrawIndexedPrimitive(LPDIRECT3DDEVICE8 dev, | ||||||
|     typedef decltype(&H_DrawIndexedPrimitive) t_func; |     typedef decltype(&H_DrawIndexedPrimitive) t_func; | ||||||
|     DWORD AMBIENT; |     DWORD AMBIENT; | ||||||
|     shared_ptr<Hook> hook = Hook::get(H_DrawIndexedPrimitive); |     shared_ptr<Hook> hook = Hook::get(H_DrawIndexedPrimitive); | ||||||
|     dev->GetRenderState(D3DRS_AMBIENT, &AMBIENT); |     // dev->GetRenderState(D3DRS_AMBIENT, &AMBIENT);
 | ||||||
|     dev->SetRenderState(D3DRS_AMBIENT, D3DCOLOR_XRGB(255, 255, 255)); |     // dev->SetRenderState(D3DRS_AMBIENT, D3DCOLOR_XRGB(255, 255, 255));
 | ||||||
|     dev->SetRenderState(D3DRS_FILLMODE, D3DFILLMODE::D3DFILL_SOLID); |     dev->SetRenderState(D3DRS_FILLMODE, fillmode); | ||||||
|     dev->SetRenderState(D3DRS_ZENABLE, 0); |     dev->SetRenderState(D3DRS_ZENABLE, use_z); | ||||||
|     auto ret = hook->func<t_func>(dev, Type, minIndex, NumVertices, startIndex, |     auto ret = hook->func<t_func>(dev, Type, minIndex, NumVertices, startIndex, | ||||||
|                                   primCount); |                                   primCount); | ||||||
|     dev->SetRenderState(D3DRS_AMBIENT, AMBIENT); |     // dev->SetRenderState(D3DRS_AMBIENT, AMBIENT);
 | ||||||
|     dev->SetRenderState(D3DRS_ZENABLE, 1); |     dev->SetRenderState(D3DRS_ZENABLE, 1); | ||||||
|     return ret; |     return ret; | ||||||
| } | } | ||||||
|  | @ -107,6 +141,7 @@ void unhook_d3d8() { | ||||||
|         m_pFont = nullptr; |         m_pFont = nullptr; | ||||||
|     } |     } | ||||||
|     Hook::drop(H_EndScene); |     Hook::drop(H_EndScene); | ||||||
|  |     Hook::drop(H_BeginScene); | ||||||
|     Hook::drop(H_DrawIndexedPrimitive); |     Hook::drop(H_DrawIndexedPrimitive); | ||||||
|     Hook::drop(H_SetLight); |     Hook::drop(H_SetLight); | ||||||
|     hooked=false; |     hooked=false; | ||||||
|  | @ -116,9 +151,6 @@ void hook_d3d8() { | ||||||
|     if (hooked) { |     if (hooked) { | ||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
|     hFont = CreateFontA(15, 0, 0, 0, FW_EXTRABOLD, 0, 0, 0, ANSI_CHARSET, 0, 0, |  | ||||||
|                         0, 0, "Lucida Console"); |  | ||||||
|     hBrush = CreateSolidBrush(D3DCOLOR_ARGB(25, 0, 0, 0)); |  | ||||||
|     void *dev = nullptr; |     void *dev = nullptr; | ||||||
|     while (true) { |     while (true) { | ||||||
|         dev = ptr<void>(P_D3DDEV); |         dev = ptr<void>(P_D3DDEV); | ||||||
|  | @ -127,7 +159,11 @@ void hook_d3d8() { | ||||||
|         } |         } | ||||||
|         Sleep(100); |         Sleep(100); | ||||||
|     }; |     }; | ||||||
|  |     hFont = CreateFontA(15, 0, 0, 0, FW_EXTRABOLD, 0, 0, 0, ANSI_CHARSET, 0, 0, | ||||||
|  |                         0, 0, "Lucida Console"); | ||||||
|  |     hBrush = CreateSolidBrush(D3DCOLOR_ARGB(25, 0, 0, 0)); | ||||||
|     Hook::addr(GetVTable(dev)[VMT_IDirect3DDevice8::m_EndScene], H_EndScene); |     Hook::addr(GetVTable(dev)[VMT_IDirect3DDevice8::m_EndScene], H_EndScene); | ||||||
|  |     Hook::addr(GetVTable(dev)[VMT_IDirect3DDevice8::m_BeginScene], H_BeginScene); | ||||||
|     Hook::addr(GetVTable(dev)[VMT_IDirect3DDevice8::m_DrawIndexedPrimitive], |     Hook::addr(GetVTable(dev)[VMT_IDirect3DDevice8::m_DrawIndexedPrimitive], | ||||||
|                H_DrawIndexedPrimitive); |                H_DrawIndexedPrimitive); | ||||||
|     Hook::addr(GetVTable(dev)[VMT_IDirect3DDevice8::m_SetLight], H_SetLight); |     Hook::addr(GetVTable(dev)[VMT_IDirect3DDevice8::m_SetLight], H_SetLight); | ||||||
|  |  | ||||||
|  | @ -1,274 +1,274 @@ | ||||||
| namespace VMT_IDirect3D8 { | namespace VMT_IDirect3D8 { | ||||||
| 	const size_t m_QueryInterface = 0; |     const size_t m_QueryInterface = 0; | ||||||
| 	const size_t m_AddRef = 1; |     const size_t m_AddRef = 1; | ||||||
| 	const size_t m_Release = 2; |     const size_t m_Release = 2; | ||||||
| 	const size_t m_RegisterSoftwareDevice = 3; |     const size_t m_RegisterSoftwareDevice = 3; | ||||||
| 	const size_t m_GetAdapterCount = 4; |     const size_t m_GetAdapterCount = 4; | ||||||
| 	const size_t m_GetAdapterIdentifier = 5; |     const size_t m_GetAdapterIdentifier = 5; | ||||||
| 	const size_t m_GetAdapterModeCount = 6; |     const size_t m_GetAdapterModeCount = 6; | ||||||
| 	const size_t m_EnumAdapterModes = 7; |     const size_t m_EnumAdapterModes = 7; | ||||||
| 	const size_t m_GetAdapterDisplayMode = 8; |     const size_t m_GetAdapterDisplayMode = 8; | ||||||
| 	const size_t m_CheckDeviceType = 9; |     const size_t m_CheckDeviceType = 9; | ||||||
| 	const size_t m_CheckDeviceFormat = 10; |     const size_t m_CheckDeviceFormat = 10; | ||||||
| 	const size_t m_CheckDeviceMultiSampleType = 11; |     const size_t m_CheckDeviceMultiSampleType = 11; | ||||||
| 	const size_t m_CheckDepthStencilMatch = 12; |     const size_t m_CheckDepthStencilMatch = 12; | ||||||
| 	const size_t m_GetDeviceCaps = 13; |     const size_t m_GetDeviceCaps = 13; | ||||||
| 	const size_t m_GetAdapterMonitor = 14; |     const size_t m_GetAdapterMonitor = 14; | ||||||
| 	const size_t m_CreateDevice = 15; |     const size_t m_CreateDevice = 15; | ||||||
| } | } | ||||||
| namespace VMT_IDirect3DBaseTexture8_IDirect3DResource8 { | namespace VMT_IDirect3DBaseTexture8_IDirect3DResource8 { | ||||||
| 	const size_t m_QueryInterface = 0; |     const size_t m_QueryInterface = 0; | ||||||
| 	const size_t m_AddRef = 1; |     const size_t m_AddRef = 1; | ||||||
| 	const size_t m_Release = 2; |     const size_t m_Release = 2; | ||||||
| 	const size_t m_GetDevice = 3; |     const size_t m_GetDevice = 3; | ||||||
| 	const size_t m_SetPrivateData = 4; |     const size_t m_SetPrivateData = 4; | ||||||
| 	const size_t m_GetPrivateData = 5; |     const size_t m_GetPrivateData = 5; | ||||||
| 	const size_t m_FreePrivateData = 6; |     const size_t m_FreePrivateData = 6; | ||||||
| 	const size_t m_SetPriority = 7; |     const size_t m_SetPriority = 7; | ||||||
| 	const size_t m_GetPriority = 8; |     const size_t m_GetPriority = 8; | ||||||
| 	const size_t m_PreLoad = 9; |     const size_t m_PreLoad = 9; | ||||||
| 	const size_t m_GetType = 10; |     const size_t m_GetType = 10; | ||||||
| 	const size_t m_SetLOD = 11; |     const size_t m_SetLOD = 11; | ||||||
| 	const size_t m_GetLOD = 12; |     const size_t m_GetLOD = 12; | ||||||
| 	const size_t m_GetLevelCount = 13; |     const size_t m_GetLevelCount = 13; | ||||||
| } | } | ||||||
| namespace VMT_IDirect3DCubeTexture8_IDirect3DBaseTexture8 { | namespace VMT_IDirect3DCubeTexture8_IDirect3DBaseTexture8 { | ||||||
| 	const size_t m_QueryInterface = 0; |     const size_t m_QueryInterface = 0; | ||||||
| 	const size_t m_AddRef = 1; |     const size_t m_AddRef = 1; | ||||||
| 	const size_t m_Release = 2; |     const size_t m_Release = 2; | ||||||
| 	const size_t m_GetDevice = 3; |     const size_t m_GetDevice = 3; | ||||||
| 	const size_t m_SetPrivateData = 4; |     const size_t m_SetPrivateData = 4; | ||||||
| 	const size_t m_GetPrivateData = 5; |     const size_t m_GetPrivateData = 5; | ||||||
| 	const size_t m_FreePrivateData = 6; |     const size_t m_FreePrivateData = 6; | ||||||
| 	const size_t m_SetPriority = 7; |     const size_t m_SetPriority = 7; | ||||||
| 	const size_t m_GetPriority = 8; |     const size_t m_GetPriority = 8; | ||||||
| 	const size_t m_PreLoad = 9; |     const size_t m_PreLoad = 9; | ||||||
| 	const size_t m_GetType = 10; |     const size_t m_GetType = 10; | ||||||
| 	const size_t m_SetLOD = 11; |     const size_t m_SetLOD = 11; | ||||||
| 	const size_t m_GetLOD = 12; |     const size_t m_GetLOD = 12; | ||||||
| 	const size_t m_GetLevelCount = 13; |     const size_t m_GetLevelCount = 13; | ||||||
| 	const size_t m_GetLevelDesc = 14; |     const size_t m_GetLevelDesc = 14; | ||||||
| 	const size_t m_GetCubeMapSurface = 15; |     const size_t m_GetCubeMapSurface = 15; | ||||||
| 	const size_t m_LockRect = 16; |     const size_t m_LockRect = 16; | ||||||
| 	const size_t m_UnlockRect = 17; |     const size_t m_UnlockRect = 17; | ||||||
| 	const size_t m_AddDirtyRect = 18; |     const size_t m_AddDirtyRect = 18; | ||||||
| } | } | ||||||
| namespace VMT_IDirect3DDevice8 { | namespace VMT_IDirect3DDevice8 { | ||||||
| 	const size_t m_QueryInterface = 0; |     const size_t m_QueryInterface = 0; | ||||||
| 	const size_t m_AddRef = 1; |     const size_t m_AddRef = 1; | ||||||
| 	const size_t m_Release = 2; |     const size_t m_Release = 2; | ||||||
| 	const size_t m_TestCooperativeLevel = 3; |     const size_t m_TestCooperativeLevel = 3; | ||||||
| 	const size_t m_GetAvailableTextureMem = 4; |     const size_t m_GetAvailableTextureMem = 4; | ||||||
| 	const size_t m_ResourceManagerDiscardBytes = 5; |     const size_t m_ResourceManagerDiscardBytes = 5; | ||||||
| 	const size_t m_GetDirect3D = 6; |     const size_t m_GetDirect3D = 6; | ||||||
| 	const size_t m_GetDeviceCaps = 7; |     const size_t m_GetDeviceCaps = 7; | ||||||
| 	const size_t m_GetDisplayMode = 8; |     const size_t m_GetDisplayMode = 8; | ||||||
| 	const size_t m_GetCreationParameters = 9; |     const size_t m_GetCreationParameters = 9; | ||||||
| 	const size_t m_SetCursorProperties = 10; |     const size_t m_SetCursorProperties = 10; | ||||||
| 	const size_t m_SetCursorPosition = 11; |     const size_t m_SetCursorPosition = 11; | ||||||
| 	const size_t m_ShowCursor = 12; |     const size_t m_ShowCursor = 12; | ||||||
| 	const size_t m_CreateAdditionalSwapChain = 13; |     const size_t m_CreateAdditionalSwapChain = 13; | ||||||
| 	const size_t m_Reset = 14; |     const size_t m_Reset = 14; | ||||||
| 	const size_t m_Present = 15; |     const size_t m_Present = 15; | ||||||
| 	const size_t m_GetBackBuffer = 16; |     const size_t m_GetBackBuffer = 16; | ||||||
| 	const size_t m_GetRasterStatus = 17; |     const size_t m_GetRasterStatus = 17; | ||||||
| 	const size_t m_SetGammaRamp = 18; |     const size_t m_SetGammaRamp = 18; | ||||||
| 	const size_t m_GetGammaRamp = 19; |     const size_t m_GetGammaRamp = 19; | ||||||
| 	const size_t m_CreateTexture = 20; |     const size_t m_CreateTexture = 20; | ||||||
| 	const size_t m_CreateVolumeTexture = 21; |     const size_t m_CreateVolumeTexture = 21; | ||||||
| 	const size_t m_CreateCubeTexture = 22; |     const size_t m_CreateCubeTexture = 22; | ||||||
| 	const size_t m_CreateVertexBuffer = 23; |     const size_t m_CreateVertexBuffer = 23; | ||||||
| 	const size_t m_CreateIndexBuffer = 24; |     const size_t m_CreateIndexBuffer = 24; | ||||||
| 	const size_t m_CreateRenderTarget = 25; |     const size_t m_CreateRenderTarget = 25; | ||||||
| 	const size_t m_CreateDepthStencilSurface = 26; |     const size_t m_CreateDepthStencilSurface = 26; | ||||||
| 	const size_t m_CreateImageSurface = 27; |     const size_t m_CreateImageSurface = 27; | ||||||
| 	const size_t m_CopyRects = 28; |     const size_t m_CopyRects = 28; | ||||||
| 	const size_t m_UpdateTexture = 29; |     const size_t m_UpdateTexture = 29; | ||||||
| 	const size_t m_GetFrontBuffer = 30; |     const size_t m_GetFrontBuffer = 30; | ||||||
| 	const size_t m_SetRenderTarget = 31; |     const size_t m_SetRenderTarget = 31; | ||||||
| 	const size_t m_GetRenderTarget = 32; |     const size_t m_GetRenderTarget = 32; | ||||||
| 	const size_t m_GetDepthStencilSurface = 33; |     const size_t m_GetDepthStencilSurface = 33; | ||||||
| 	const size_t m_BeginScene = 34; |     const size_t m_BeginScene = 34; | ||||||
| 	const size_t m_EndScene = 35; |     const size_t m_EndScene = 35; | ||||||
| 	const size_t m_Clear = 36; |     const size_t m_Clear = 36; | ||||||
| 	const size_t m_SetTransform = 37; |     const size_t m_SetTransform = 37; | ||||||
| 	const size_t m_GetTransform = 38; |     const size_t m_GetTransform = 38; | ||||||
| 	const size_t m_MultiplyTransform = 39; |     const size_t m_MultiplyTransform = 39; | ||||||
| 	const size_t m_SetViewport = 40; |     const size_t m_SetViewport = 40; | ||||||
| 	const size_t m_GetViewport = 41; |     const size_t m_GetViewport = 41; | ||||||
| 	const size_t m_SetMaterial = 42; |     const size_t m_SetMaterial = 42; | ||||||
| 	const size_t m_GetMaterial = 43; |     const size_t m_GetMaterial = 43; | ||||||
| 	const size_t m_SetLight = 44; |     const size_t m_SetLight = 44; | ||||||
| 	const size_t m_GetLight = 45; |     const size_t m_GetLight = 45; | ||||||
| 	const size_t m_LightEnable = 46; |     const size_t m_LightEnable = 46; | ||||||
| 	const size_t m_GetLightEnable = 47; |     const size_t m_GetLightEnable = 47; | ||||||
| 	const size_t m_SetClipPlane = 48; |     const size_t m_SetClipPlane = 48; | ||||||
| 	const size_t m_GetClipPlane = 49; |     const size_t m_GetClipPlane = 49; | ||||||
| 	const size_t m_SetRenderState = 50; |     const size_t m_SetRenderState = 50; | ||||||
| 	const size_t m_GetRenderState = 51; |     const size_t m_GetRenderState = 51; | ||||||
| 	const size_t m_BeginStateBlock = 52; |     const size_t m_BeginStateBlock = 52; | ||||||
| 	const size_t m_EndStateBlock = 53; |     const size_t m_EndStateBlock = 53; | ||||||
| 	const size_t m_ApplyStateBlock = 54; |     const size_t m_ApplyStateBlock = 54; | ||||||
| 	const size_t m_CaptureStateBlock = 55; |     const size_t m_CaptureStateBlock = 55; | ||||||
| 	const size_t m_DeleteStateBlock = 56; |     const size_t m_DeleteStateBlock = 56; | ||||||
| 	const size_t m_CreateStateBlock = 57; |     const size_t m_CreateStateBlock = 57; | ||||||
| 	const size_t m_SetClipStatus = 58; |     const size_t m_SetClipStatus = 58; | ||||||
| 	const size_t m_GetClipStatus = 59; |     const size_t m_GetClipStatus = 59; | ||||||
| 	const size_t m_GetTexture = 60; |     const size_t m_GetTexture = 60; | ||||||
| 	const size_t m_SetTexture = 61; |     const size_t m_SetTexture = 61; | ||||||
| 	const size_t m_GetTextureStageState = 62; |     const size_t m_GetTextureStageState = 62; | ||||||
| 	const size_t m_SetTextureStageState = 63; |     const size_t m_SetTextureStageState = 63; | ||||||
| 	const size_t m_ValidateDevice = 64; |     const size_t m_ValidateDevice = 64; | ||||||
| 	const size_t m_GetInfo = 65; |     const size_t m_GetInfo = 65; | ||||||
| 	const size_t m_SetPaletteEntries = 66; |     const size_t m_SetPaletteEntries = 66; | ||||||
| 	const size_t m_GetPaletteEntries = 67; |     const size_t m_GetPaletteEntries = 67; | ||||||
| 	const size_t m_SetCurrentTexturePalette = 68; |     const size_t m_SetCurrentTexturePalette = 68; | ||||||
| 	const size_t m_GetCurrentTexturePalette = 69; |     const size_t m_GetCurrentTexturePalette = 69; | ||||||
| 	const size_t m_DrawPrimitive = 70; |     const size_t m_DrawPrimitive = 70; | ||||||
| 	const size_t m_DrawIndexedPrimitive = 71; |     const size_t m_DrawIndexedPrimitive = 71; | ||||||
| 	const size_t m_DrawPrimitiveUP = 72; |     const size_t m_DrawPrimitiveUP = 72; | ||||||
| 	const size_t m_DrawIndexedPrimitiveUP = 73; |     const size_t m_DrawIndexedPrimitiveUP = 73; | ||||||
| 	const size_t m_ProcessVertices = 74; |     const size_t m_ProcessVertices = 74; | ||||||
| 	const size_t m_CreateVertexShader = 75; |     const size_t m_CreateVertexShader = 75; | ||||||
| 	const size_t m_SetVertexShader = 76; |     const size_t m_SetVertexShader = 76; | ||||||
| 	const size_t m_GetVertexShader = 77; |     const size_t m_GetVertexShader = 77; | ||||||
| 	const size_t m_DeleteVertexShader = 78; |     const size_t m_DeleteVertexShader = 78; | ||||||
| 	const size_t m_SetVertexShaderConstant = 79; |     const size_t m_SetVertexShaderConstant = 79; | ||||||
| 	const size_t m_GetVertexShaderConstant = 80; |     const size_t m_GetVertexShaderConstant = 80; | ||||||
| 	const size_t m_GetVertexShaderDeclaration = 81; |     const size_t m_GetVertexShaderDeclaration = 81; | ||||||
| 	const size_t m_GetVertexShaderFunction = 82; |     const size_t m_GetVertexShaderFunction = 82; | ||||||
| 	const size_t m_SetStreamSource = 83; |     const size_t m_SetStreamSource = 83; | ||||||
| 	const size_t m_GetStreamSource = 84; |     const size_t m_GetStreamSource = 84; | ||||||
| 	const size_t m_SetIndices = 85; |     const size_t m_SetIndices = 85; | ||||||
| 	const size_t m_GetIndices = 86; |     const size_t m_GetIndices = 86; | ||||||
| 	const size_t m_CreatePixelShader = 87; |     const size_t m_CreatePixelShader = 87; | ||||||
| 	const size_t m_SetPixelShader = 88; |     const size_t m_SetPixelShader = 88; | ||||||
| 	const size_t m_GetPixelShader = 89; |     const size_t m_GetPixelShader = 89; | ||||||
| 	const size_t m_DeletePixelShader = 90; |     const size_t m_DeletePixelShader = 90; | ||||||
| 	const size_t m_SetPixelShaderConstant = 91; |     const size_t m_SetPixelShaderConstant = 91; | ||||||
| 	const size_t m_GetPixelShaderConstant = 92; |     const size_t m_GetPixelShaderConstant = 92; | ||||||
| 	const size_t m_GetPixelShaderFunction = 93; |     const size_t m_GetPixelShaderFunction = 93; | ||||||
| 	const size_t m_DrawRectPatch = 94; |     const size_t m_DrawRectPatch = 94; | ||||||
| 	const size_t m_DrawTriPatch = 95; |     const size_t m_DrawTriPatch = 95; | ||||||
| 	const size_t m_DeletePatch = 96; |     const size_t m_DeletePatch = 96; | ||||||
| } | } | ||||||
| namespace VMT_IDirect3DIndexBuffer8_IDirect3DResource8 { | namespace VMT_IDirect3DIndexBuffer8_IDirect3DResource8 { | ||||||
| 	const size_t m_QueryInterface = 0; |     const size_t m_QueryInterface = 0; | ||||||
| 	const size_t m_AddRef = 1; |     const size_t m_AddRef = 1; | ||||||
| 	const size_t m_Release = 2; |     const size_t m_Release = 2; | ||||||
| 	const size_t m_GetDevice = 3; |     const size_t m_GetDevice = 3; | ||||||
| 	const size_t m_SetPrivateData = 4; |     const size_t m_SetPrivateData = 4; | ||||||
| 	const size_t m_GetPrivateData = 5; |     const size_t m_GetPrivateData = 5; | ||||||
| 	const size_t m_FreePrivateData = 6; |     const size_t m_FreePrivateData = 6; | ||||||
| 	const size_t m_SetPriority = 7; |     const size_t m_SetPriority = 7; | ||||||
| 	const size_t m_GetPriority = 8; |     const size_t m_GetPriority = 8; | ||||||
| 	const size_t m_PreLoad = 9; |     const size_t m_PreLoad = 9; | ||||||
| 	const size_t m_GetType = 10; |     const size_t m_GetType = 10; | ||||||
| 	const size_t m_Lock = 11; |     const size_t m_Lock = 11; | ||||||
| 	const size_t m_Unlock = 12; |     const size_t m_Unlock = 12; | ||||||
| 	const size_t m_GetDesc = 13; |     const size_t m_GetDesc = 13; | ||||||
| } | } | ||||||
| namespace VMT_IDirect3DResource8 { | namespace VMT_IDirect3DResource8 { | ||||||
| 	const size_t m_QueryInterface = 0; |     const size_t m_QueryInterface = 0; | ||||||
| 	const size_t m_AddRef = 1; |     const size_t m_AddRef = 1; | ||||||
| 	const size_t m_Release = 2; |     const size_t m_Release = 2; | ||||||
| 	const size_t m_GetDevice = 3; |     const size_t m_GetDevice = 3; | ||||||
| 	const size_t m_SetPrivateData = 4; |     const size_t m_SetPrivateData = 4; | ||||||
| 	const size_t m_GetPrivateData = 5; |     const size_t m_GetPrivateData = 5; | ||||||
| 	const size_t m_FreePrivateData = 6; |     const size_t m_FreePrivateData = 6; | ||||||
| 	const size_t m_SetPriority = 7; |     const size_t m_SetPriority = 7; | ||||||
| 	const size_t m_GetPriority = 8; |     const size_t m_GetPriority = 8; | ||||||
| 	const size_t m_PreLoad = 9; |     const size_t m_PreLoad = 9; | ||||||
| 	const size_t m_GetType = 10; |     const size_t m_GetType = 10; | ||||||
| } | } | ||||||
| namespace VMT_IDirect3DSurface8 { | namespace VMT_IDirect3DSurface8 { | ||||||
| 	const size_t m_QueryInterface = 0; |     const size_t m_QueryInterface = 0; | ||||||
| 	const size_t m_AddRef = 1; |     const size_t m_AddRef = 1; | ||||||
| 	const size_t m_Release = 2; |     const size_t m_Release = 2; | ||||||
| 	const size_t m_GetDevice = 3; |     const size_t m_GetDevice = 3; | ||||||
| 	const size_t m_SetPrivateData = 4; |     const size_t m_SetPrivateData = 4; | ||||||
| 	const size_t m_GetPrivateData = 5; |     const size_t m_GetPrivateData = 5; | ||||||
| 	const size_t m_FreePrivateData = 6; |     const size_t m_FreePrivateData = 6; | ||||||
| 	const size_t m_GetContainer = 7; |     const size_t m_GetContainer = 7; | ||||||
| 	const size_t m_GetDesc = 8; |     const size_t m_GetDesc = 8; | ||||||
| 	const size_t m_LockRect = 9; |     const size_t m_LockRect = 9; | ||||||
| 	const size_t m_UnlockRect = 10; |     const size_t m_UnlockRect = 10; | ||||||
| } | } | ||||||
| namespace VMT_IDirect3DSwapChain8 { | namespace VMT_IDirect3DSwapChain8 { | ||||||
| 	const size_t m_QueryInterface = 0; |     const size_t m_QueryInterface = 0; | ||||||
| 	const size_t m_AddRef = 1; |     const size_t m_AddRef = 1; | ||||||
| 	const size_t m_Release = 2; |     const size_t m_Release = 2; | ||||||
| 	const size_t m_Present = 3; |     const size_t m_Present = 3; | ||||||
| 	const size_t m_GetBackBuffer = 4; |     const size_t m_GetBackBuffer = 4; | ||||||
| } | } | ||||||
| namespace VMT_IDirect3DTexture8_IDirect3DBaseTexture8 { | namespace VMT_IDirect3DTexture8_IDirect3DBaseTexture8 { | ||||||
| 	const size_t m_QueryInterface = 0; |     const size_t m_QueryInterface = 0; | ||||||
| 	const size_t m_AddRef = 1; |     const size_t m_AddRef = 1; | ||||||
| 	const size_t m_Release = 2; |     const size_t m_Release = 2; | ||||||
| 	const size_t m_GetDevice = 3; |     const size_t m_GetDevice = 3; | ||||||
| 	const size_t m_SetPrivateData = 4; |     const size_t m_SetPrivateData = 4; | ||||||
| 	const size_t m_GetPrivateData = 5; |     const size_t m_GetPrivateData = 5; | ||||||
| 	const size_t m_FreePrivateData = 6; |     const size_t m_FreePrivateData = 6; | ||||||
| 	const size_t m_SetPriority = 7; |     const size_t m_SetPriority = 7; | ||||||
| 	const size_t m_GetPriority = 8; |     const size_t m_GetPriority = 8; | ||||||
| 	const size_t m_PreLoad = 9; |     const size_t m_PreLoad = 9; | ||||||
| 	const size_t m_GetType = 10; |     const size_t m_GetType = 10; | ||||||
| 	const size_t m_SetLOD = 11; |     const size_t m_SetLOD = 11; | ||||||
| 	const size_t m_GetLOD = 12; |     const size_t m_GetLOD = 12; | ||||||
| 	const size_t m_GetLevelCount = 13; |     const size_t m_GetLevelCount = 13; | ||||||
| 	const size_t m_GetLevelDesc = 14; |     const size_t m_GetLevelDesc = 14; | ||||||
| 	const size_t m_GetSurfaceLevel = 15; |     const size_t m_GetSurfaceLevel = 15; | ||||||
| 	const size_t m_LockRect = 16; |     const size_t m_LockRect = 16; | ||||||
| 	const size_t m_UnlockRect = 17; |     const size_t m_UnlockRect = 17; | ||||||
| 	const size_t m_AddDirtyRect = 18; |     const size_t m_AddDirtyRect = 18; | ||||||
| } | } | ||||||
| namespace VMT_IDirect3DVertexBuffer8_IDirect3DResource8 { | namespace VMT_IDirect3DVertexBuffer8_IDirect3DResource8 { | ||||||
| 	const size_t m_QueryInterface = 0; |     const size_t m_QueryInterface = 0; | ||||||
| 	const size_t m_AddRef = 1; |     const size_t m_AddRef = 1; | ||||||
| 	const size_t m_Release = 2; |     const size_t m_Release = 2; | ||||||
| 	const size_t m_GetDevice = 3; |     const size_t m_GetDevice = 3; | ||||||
| 	const size_t m_SetPrivateData = 4; |     const size_t m_SetPrivateData = 4; | ||||||
| 	const size_t m_GetPrivateData = 5; |     const size_t m_GetPrivateData = 5; | ||||||
| 	const size_t m_FreePrivateData = 6; |     const size_t m_FreePrivateData = 6; | ||||||
| 	const size_t m_SetPriority = 7; |     const size_t m_SetPriority = 7; | ||||||
| 	const size_t m_GetPriority = 8; |     const size_t m_GetPriority = 8; | ||||||
| 	const size_t m_PreLoad = 9; |     const size_t m_PreLoad = 9; | ||||||
| 	const size_t m_GetType = 10; |     const size_t m_GetType = 10; | ||||||
| 	const size_t m_Lock = 11; |     const size_t m_Lock = 11; | ||||||
| 	const size_t m_Unlock = 12; |     const size_t m_Unlock = 12; | ||||||
| 	const size_t m_GetDesc = 13; |     const size_t m_GetDesc = 13; | ||||||
| } | } | ||||||
| namespace VMT_IDirect3DVolume8 { | namespace VMT_IDirect3DVolume8 { | ||||||
| 	const size_t m_QueryInterface = 0; |     const size_t m_QueryInterface = 0; | ||||||
| 	const size_t m_AddRef = 1; |     const size_t m_AddRef = 1; | ||||||
| 	const size_t m_Release = 2; |     const size_t m_Release = 2; | ||||||
| 	const size_t m_GetDevice = 3; |     const size_t m_GetDevice = 3; | ||||||
| 	const size_t m_SetPrivateData = 4; |     const size_t m_SetPrivateData = 4; | ||||||
| 	const size_t m_GetPrivateData = 5; |     const size_t m_GetPrivateData = 5; | ||||||
| 	const size_t m_FreePrivateData = 6; |     const size_t m_FreePrivateData = 6; | ||||||
| 	const size_t m_GetContainer = 7; |     const size_t m_GetContainer = 7; | ||||||
| 	const size_t m_GetDesc = 8; |     const size_t m_GetDesc = 8; | ||||||
| 	const size_t m_LockBox = 9; |     const size_t m_LockBox = 9; | ||||||
| 	const size_t m_UnlockBox = 10; |     const size_t m_UnlockBox = 10; | ||||||
| } | } | ||||||
| namespace VMT_IDirect3DVolumeTexture8_IDirect3DBaseTexture8 { | namespace VMT_IDirect3DVolumeTexture8_IDirect3DBaseTexture8 { | ||||||
| 	const size_t m_QueryInterface = 0; |     const size_t m_QueryInterface = 0; | ||||||
| 	const size_t m_AddRef = 1; |     const size_t m_AddRef = 1; | ||||||
| 	const size_t m_Release = 2; |     const size_t m_Release = 2; | ||||||
| 	const size_t m_GetDevice = 3; |     const size_t m_GetDevice = 3; | ||||||
| 	const size_t m_SetPrivateData = 4; |     const size_t m_SetPrivateData = 4; | ||||||
| 	const size_t m_GetPrivateData = 5; |     const size_t m_GetPrivateData = 5; | ||||||
| 	const size_t m_FreePrivateData = 6; |     const size_t m_FreePrivateData = 6; | ||||||
| 	const size_t m_SetPriority = 7; |     const size_t m_SetPriority = 7; | ||||||
| 	const size_t m_GetPriority = 8; |     const size_t m_GetPriority = 8; | ||||||
| 	const size_t m_PreLoad = 9; |     const size_t m_PreLoad = 9; | ||||||
| 	const size_t m_GetType = 10; |     const size_t m_GetType = 10; | ||||||
| 	const size_t m_SetLOD = 11; |     const size_t m_SetLOD = 11; | ||||||
| 	const size_t m_GetLOD = 12; |     const size_t m_GetLOD = 12; | ||||||
| 	const size_t m_GetLevelCount = 13; |     const size_t m_GetLevelCount = 13; | ||||||
| 	const size_t m_GetLevelDesc = 14; |     const size_t m_GetLevelDesc = 14; | ||||||
| 	const size_t m_GetVolumeLevel = 15; |     const size_t m_GetVolumeLevel = 15; | ||||||
| 	const size_t m_LockBox = 16; |     const size_t m_LockBox = 16; | ||||||
| 	const size_t m_UnlockBox = 17; |     const size_t m_UnlockBox = 17; | ||||||
| 	const size_t m_AddDirtyBox = 18; |     const size_t m_AddDirtyBox = 18; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -4,9 +4,29 @@ | ||||||
| #include <functional> | #include <functional> | ||||||
| #include <iostream> | #include <iostream> | ||||||
| #include <map> | #include <map> | ||||||
|  | #include <vector> | ||||||
|  | #include <asmjit/asmjit.h> | ||||||
| 
 | 
 | ||||||
| using namespace std; | using namespace std; | ||||||
| 
 | 
 | ||||||
|  | /*
 | ||||||
|  | vector<uint8_t> make_trampoline(uintptr_t orig,uintptr_t hook) { | ||||||
|  |     using namespace asmjit; | ||||||
|  |     JitRuntime rt; | ||||||
|  |     CodeHolder code; | ||||||
|  |     CodeInfo ci=rt.codeInfo(); | ||||||
|  |     code.init(ci); | ||||||
|  |     x86::Assembler a(&code); | ||||||
|  |     a.jmp(hook); | ||||||
|  |     a.ret(); | ||||||
|  |     code.flatten(); | ||||||
|  |     code.resolveUnresolvedLinks(); | ||||||
|  |     code.relocateToBase(orig); | ||||||
|  |     size_t code_size=code.sectionById(0)->buffer().size(); | ||||||
|  |     code.copyFlattenedData((void*)orig, code_size, CodeHolder::kCopyWithPadding); | ||||||
|  | } | ||||||
|  | */ | ||||||
|  | 
 | ||||||
| class Hook { | class Hook { | ||||||
|   private: |   private: | ||||||
|     MEMORY_BASIC_INFORMATION mbi; |     MEMORY_BASIC_INFORMATION mbi; | ||||||
|  | @ -19,6 +39,7 @@ class Hook { | ||||||
| 
 | 
 | ||||||
|   public: |   public: | ||||||
|     Hook(void *func, void *detour) { |     Hook(void *func, void *detour) { | ||||||
|  |         // TODO: build jmp_bytes using asmjit
 | ||||||
|         uintptr_t dest = reinterpret_cast<uintptr_t>(detour); |         uintptr_t dest = reinterpret_cast<uintptr_t>(detour); | ||||||
|         uintptr_t src = reinterpret_cast<uintptr_t>(func); |         uintptr_t src = reinterpret_cast<uintptr_t>(func); | ||||||
|         this->orig = func; |         this->orig = func; | ||||||
|  | @ -83,7 +104,7 @@ class Hook { | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     void disable() { |     void disable() { | ||||||
|         if (enabled) { |         if (this->enabled) { | ||||||
|             // cout << "Disabling: [" << this->orig << " <- " << this->detour <<
 |             // cout << "Disabling: [" << this->orig << " <- " << this->detour <<
 | ||||||
|             // "]"
 |             // "]"
 | ||||||
|             // << endl;
 |             // << endl;
 | ||||||
|  | @ -91,7 +112,7 @@ class Hook { | ||||||
|                            PAGE_EXECUTE_READWRITE, NULL); |                            PAGE_EXECUTE_READWRITE, NULL); | ||||||
|             memcpy(this->orig, this->orig_bytes, 1 + 4 + 1); |             memcpy(this->orig, this->orig_bytes, 1 + 4 + 1); | ||||||
|             VirtualProtect(mbi.BaseAddress, mbi.RegionSize, mbi.Protect, NULL); |             VirtualProtect(mbi.BaseAddress, mbi.RegionSize, mbi.Protect, NULL); | ||||||
|             enabled = false; |             this->enabled = false; | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|     void enable() { |     void enable() { | ||||||
|  |  | ||||||
|  | @ -1,9 +1,15 @@ | ||||||
| #pragma once | #pragma once | ||||||
| #include <Windows.h> | #include <Windows.h> | ||||||
|  | #include <DbgHelp.h> | ||||||
|  | 
 | ||||||
|  | #define ASMJIT_EMBED | ||||||
|  | #define ASMTK_EMBED | ||||||
| 
 | 
 | ||||||
| #include <regex> | #include <regex> | ||||||
| #include <sstream> | #include <sstream> | ||||||
|  | #include <string> | ||||||
| 
 | 
 | ||||||
|  | #include <asmtk/asmtk.h> | ||||||
| #include "Scrapland.hpp" | #include "Scrapland.hpp" | ||||||
| #include "Util.hpp" | #include "Util.hpp" | ||||||
| 
 | 
 | ||||||
|  | @ -13,15 +19,196 @@ void DllUnload(); | ||||||
| void unhook_d3d8(); | void unhook_d3d8(); | ||||||
| void hook_d3d8(); | void hook_d3d8(); | ||||||
| 
 | 
 | ||||||
| typedef void(_cdecl *t_cmd_func)(vector<string>); | struct Command; | ||||||
| 
 | 
 | ||||||
| struct t_cmd { | typedef void(_cdecl *t_cmd_func)(Command*,vector<string>); | ||||||
|  | 
 | ||||||
|  | size_t assemble(vector<string> assembly,uint64_t base) { | ||||||
|  |     using namespace asmjit; | ||||||
|  |     using namespace asmtk; | ||||||
|  | 
 | ||||||
|  |     char err_msg[1024]; | ||||||
|  |     Error err; | ||||||
|  |      | ||||||
|  |     CodeInfo ci(ArchInfo::kIdX86); | ||||||
|  |     ci.setBaseAddress(base); | ||||||
|  |     CodeHolder code; | ||||||
|  |     code.init(ci); | ||||||
|  |     x86::Assembler a(&code); | ||||||
|  |     AsmParser p(&a); | ||||||
|  |      | ||||||
|  |     for (string line:assembly) { | ||||||
|  |         if (err = p.parse((line+"\n").c_str())) { | ||||||
|  |             snprintf(err_msg,1024,"PARSE ERROR: [%s] %08x (%s)\n",line.c_str(), err, DebugUtils::errorAsString(err)); | ||||||
|  |             scrap_log(ERR_COLOR,err_msg); | ||||||
|  |             return 0; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     if (err=code.flatten()) { | ||||||
|  |         snprintf(err_msg,1024,"FLATTEN ERROR: %08x (%s)\n", err, DebugUtils::errorAsString(err)); | ||||||
|  |         scrap_log(ERR_COLOR,err_msg); | ||||||
|  |         return 0; | ||||||
|  |     } | ||||||
|  |     if (err=code.resolveUnresolvedLinks()) { | ||||||
|  |         snprintf(err_msg,1024,"RESOLVE ERROR: %08x (%s)\n", err, DebugUtils::errorAsString(err)); | ||||||
|  |         scrap_log(ERR_COLOR,err_msg); | ||||||
|  |         return 0; | ||||||
|  |     } | ||||||
|  |     CodeBuffer& buffer = code.sectionById(0)->buffer(); | ||||||
|  |      | ||||||
|  |     if (base==0) { | ||||||
|  |         return buffer.size(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     MEMORY_BASIC_INFORMATION mbi; | ||||||
|  |      | ||||||
|  |     if (VirtualQuery((void*)base, &mbi, sizeof(mbi)) == 0) { | ||||||
|  |         scrap_log(ERR_COLOR, "ERROR: "); | ||||||
|  |         scrap_log(ERR_COLOR, GetLastErrorAsString()); | ||||||
|  |         scrap_log(ERR_COLOR, "\n"); | ||||||
|  |         return 0; | ||||||
|  |     }; | ||||||
|  |     if (!VirtualProtect(mbi.BaseAddress, mbi.RegionSize, PAGE_EXECUTE_READWRITE, &mbi.Protect)) | ||||||
|  |     { | ||||||
|  |         scrap_log(ERR_COLOR, "ERROR: "); | ||||||
|  |         scrap_log(ERR_COLOR, GetLastErrorAsString()); | ||||||
|  |         scrap_log(ERR_COLOR, "\n"); | ||||||
|  |         return 0; | ||||||
|  |     }; | ||||||
|  |     memcpy((void*)base,buffer.data(),buffer.size()); | ||||||
|  |     scrap_log(INFO_COLOR,"Code:"+hexdump_s((void*)base,buffer.size())); | ||||||
|  |     VirtualProtect(mbi.BaseAddress, mbi.RegionSize, mbi.Protect, NULL); | ||||||
|  |     return buffer.size(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | size_t asm_size(vector<string> assembly) { | ||||||
|  |     return assemble(assembly,0); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | struct Command { | ||||||
|     t_cmd_func func; |     t_cmd_func func; | ||||||
|     const char* usage; |     string usage; | ||||||
|     const char* doc; |     string doc; | ||||||
|  |     map<string,Command*> subcommands; | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |     Command(t_cmd_func func=nullptr,string usage="",string doc="",map<string,Command*> subcommands={}) { | ||||||
|  |         this->func=func; | ||||||
|  |         this->usage=usage; | ||||||
|  |         this->doc=doc; | ||||||
|  |         this->subcommands=subcommands; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |      | ||||||
|  |     Command(string usage="",string doc="",map<string,Command*> subcommands={}):  | ||||||
|  |         Command(nullptr,usage,doc,subcommands) {}; | ||||||
|  | 
 | ||||||
|  |     void add_subcommand(string name,Command *cmd) { | ||||||
|  |         this->subcommands[name]=cmd; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     void set_subcommands(const map<string,Command*> &subcommands) { | ||||||
|  |         for (auto subcmd:subcommands) { | ||||||
|  |             this->add_subcommand(subcmd.first,subcmd.second); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     bool has_subcommand(string cmd) { | ||||||
|  |         return this->subcommands.count(cmd)>0; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     void exec(vector<string> args) { | ||||||
|  |         if (args.size()>1) { | ||||||
|  |             string cmd=args[0]; | ||||||
|  |             if (this->has_subcommand(cmd)) { | ||||||
|  |                 // matching subcommand found, strip first part and forward args
 | ||||||
|  |                 args.erase(args.begin()); | ||||||
|  |                 return this->subcommands[cmd]->exec(args); | ||||||
|  |             }; | ||||||
|  |         } | ||||||
|  |         // args vector empty or no subcommand found, check if we have a func ptr and call it
 | ||||||
|  |         if (this->func!=nullptr) { | ||||||
|  |             this->func(this,args); | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |         scrap_log(ERR_COLOR, "Unknown command!\n"); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| void cmd_help(vector<string>); | struct REPL { | ||||||
|  |      | ||||||
|  |     map<string,Command*> commands; | ||||||
|  |     REPL(map<string,Command*> commands) { | ||||||
|  |         this->commands=commands; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     bool has_command(string cmd) { | ||||||
|  |         return this->commands.count(cmd)>0; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     bool exec(vector<string> args) { | ||||||
|  |         vector<tuple<string,Command*>> cmd_stack; | ||||||
|  |         map<string,Command*> cmds=this->commands; | ||||||
|  |         if (args.size()==0) { | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |         while (cmds.count(args[0])) { | ||||||
|  |             cmd_stack.push_back(make_tuple(args[0],cmds[args[0]])); | ||||||
|  |             cmds=cmds[args[0]]->subcommands; | ||||||
|  |             args.erase(args.begin()); | ||||||
|  |             if (args.empty()) break; | ||||||
|  |         } | ||||||
|  |         while (cmd_stack.size()) { | ||||||
|  |             auto elem=cmd_stack.back(); | ||||||
|  |             string cmd=get<0>(elem); | ||||||
|  |             Command* cmd_ptr=get<1>(elem); | ||||||
|  |             cmd_stack.pop_back(); | ||||||
|  |             if (cmd_ptr->func!=nullptr) { | ||||||
|  |                 cmd_ptr->func(cmd_ptr,args); | ||||||
|  |                 return true; | ||||||
|  |             } | ||||||
|  |             args.insert(args.begin(),cmd); | ||||||
|  |         } | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     string help(vector<string> args) { | ||||||
|  |         map<string,Command*> cmds=this->commands; | ||||||
|  |         string ret; | ||||||
|  |         if (args.empty()) { | ||||||
|  |             return this->show_commands(cmds); | ||||||
|  |         } | ||||||
|  |         pair<string,Command*> cmd=make_pair("",nullptr); | ||||||
|  |         for (string part: args) { | ||||||
|  |             if (cmds.count(part)==0) { | ||||||
|  |                 return "No help for (sub)command '"+part+"'"; | ||||||
|  |             } | ||||||
|  |             cmd=make_pair(part,cmds[part]); | ||||||
|  |             cmds=cmd.second->subcommands; | ||||||
|  |         } | ||||||
|  |         ret=cmd.first+": "+cmd.second->usage+"\n"; | ||||||
|  |         if (cmds.size()) { | ||||||
|  |             ret+="Subcommands:\n"+this->show_commands(cmds,1)+"\n"; | ||||||
|  |         }; | ||||||
|  |         return ret; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     string show_commands(map<string,Command*> cmds,size_t depth=0) { | ||||||
|  |         string s; | ||||||
|  |         for (auto cmd:cmds) { | ||||||
|  |             for (size_t n=0;n<depth;++n) { | ||||||
|  |                 s+="    "; | ||||||
|  |             } | ||||||
|  |             s+=cmd.first+": "+cmd.second->doc+" ("+cmd.second->usage+")\n"+this->show_commands(cmd.second->subcommands,depth+1); | ||||||
|  |         } | ||||||
|  |         return s; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | }; | ||||||
| 
 | 
 | ||||||
| DWORD | DWORD | ||||||
| get_protection(void *addr) { | get_protection(void *addr) { | ||||||
|  | @ -30,66 +217,127 @@ get_protection(void *addr) { | ||||||
|     return mbi.Protect; |     return mbi.Protect; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void cmd_write(vector<string> args) { | void cmd_exec(Command* cmd, vector<string> args) { | ||||||
|  |     void *addr; | ||||||
|     MEMORY_BASIC_INFORMATION mbi; |     MEMORY_BASIC_INFORMATION mbi; | ||||||
|     if (args.size() != 2) { |     if (args.size()<1) { | ||||||
|         scrap_log(ERR_COLOR, "Usage: $w <addr> <data(hex)>\n"); |         scrap_log(ERR_COLOR, cmd->usage); | ||||||
|         return; |         scrap_log(ERR_COLOR, "\n"); | ||||||
|     } |     } | ||||||
|     void *addr = 0; |  | ||||||
|     vector<uint8_t> data; |  | ||||||
|     try { |     try { | ||||||
|         addr = (void *)stoull(args[0], 0, 16); |         addr = (void *)stoull(args[0], 0, 16); | ||||||
|         data = fromhex(args[1]); |  | ||||||
|     } catch (exception e) { |     } catch (exception e) { | ||||||
|         scrap_log(ERR_COLOR, "ERROR!\n"); |         scrap_log(ERR_COLOR, "ERROR: "); | ||||||
|  |         scrap_log(ERR_COLOR, e.what()); | ||||||
|  |         scrap_log(ERR_COLOR, "\n"); | ||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
|     uint8_t *buffer = new uint8_t[data.size()]; |      | ||||||
|  |     if (VirtualQuery(addr, &mbi, sizeof(mbi)) == 0) { | ||||||
|  |         scrap_log(ERR_COLOR, "ERROR: "); | ||||||
|  |         scrap_log(ERR_COLOR, GetLastErrorAsString()); | ||||||
|  |         scrap_log(ERR_COLOR, "\n"); | ||||||
|  |         return; | ||||||
|  |     }; | ||||||
|  |     if (!VirtualProtect(mbi.BaseAddress, mbi.RegionSize, PAGE_EXECUTE_READWRITE, &mbi.Protect)) | ||||||
|  |     { | ||||||
|  |         scrap_log(ERR_COLOR, "ERROR: "); | ||||||
|  |         scrap_log(ERR_COLOR, GetLastErrorAsString()); | ||||||
|  |         scrap_log(ERR_COLOR, "\n"); | ||||||
|  |     }; | ||||||
|  |     CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)addr,0,NULL,NULL); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void cmd_write(Command* cmd,vector<string> args) { | ||||||
|  |     MEMORY_BASIC_INFORMATION mbi; | ||||||
|  |     if (args.size()==0) { | ||||||
|  |         scrap_log(ERR_COLOR, cmd->usage); | ||||||
|  |         scrap_log(ERR_COLOR, "\n"); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |     uint8_t *buffer = nullptr; | ||||||
|  |     vector<uint8_t> data; | ||||||
|  |     try { | ||||||
|  |         if (args.size()>1) { | ||||||
|  |             buffer = (uint8_t *)stoull(args[0], 0, 16); | ||||||
|  |             data = fromhex(args[1]); | ||||||
|  |         } else { | ||||||
|  |             data = fromhex(args[0]); | ||||||
|  |             buffer = new uint8_t[data.size()]; | ||||||
|  |             if (buffer==nullptr) { | ||||||
|  |                 scrap_log(ERR_COLOR, "ERROR: "); | ||||||
|  |                 scrap_log(ERR_COLOR, "new[] failed"); | ||||||
|  |                 scrap_log(ERR_COLOR, "\n"); | ||||||
|  |                 return; | ||||||
|  |             } | ||||||
|  |             char ptr[255]; | ||||||
|  |             snprintf(ptr,255,"Buffer @ %p\n",buffer); | ||||||
|  |             scrap_log(INFO_COLOR,ptr); | ||||||
|  |         } | ||||||
|  |     } catch (exception e) { | ||||||
|  |         scrap_log(ERR_COLOR, "ERROR: "); | ||||||
|  |         scrap_log(ERR_COLOR, e.what()); | ||||||
|  |         scrap_log(ERR_COLOR, "\n"); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |     if (VirtualQuery(buffer, &mbi, sizeof(mbi)) == 0) { | ||||||
|  |         scrap_log(ERR_COLOR, "ERROR: "); | ||||||
|  |         scrap_log(ERR_COLOR, GetLastErrorAsString()); | ||||||
|  |         scrap_log(ERR_COLOR, "\n"); | ||||||
|  |         return; | ||||||
|  |     }; | ||||||
|  |     if (!VirtualProtect(mbi.BaseAddress, mbi.RegionSize, PAGE_EXECUTE_READWRITE, &mbi.Protect)) | ||||||
|  |     { | ||||||
|  |         scrap_log(ERR_COLOR, "ERROR: "); | ||||||
|  |         scrap_log(ERR_COLOR, GetLastErrorAsString()); | ||||||
|  |         scrap_log(ERR_COLOR, "\n"); | ||||||
|  |     }; | ||||||
|  |      | ||||||
|     size_t idx = 0; |     size_t idx = 0; | ||||||
|     for (uint8_t v : data) { |     for (uint8_t v : data) { | ||||||
|         buffer[idx++] = v; |         buffer[idx++] = v; | ||||||
|     } |     } | ||||||
|     cout << "W:" << (void *)addr << endl; | 
 | ||||||
|     cout << buffer << endl; |  | ||||||
|     if (VirtualQuery(addr, &mbi, sizeof(mbi)) == 0) { |  | ||||||
|         scrap_log(ERR_COLOR, "ERROR!\n"); |  | ||||||
|         return; |  | ||||||
|     }; |  | ||||||
|     VirtualProtect(mbi.BaseAddress, mbi.RegionSize, PAGE_EXECUTE_READWRITE, |  | ||||||
|                    &mbi.Protect); |  | ||||||
|     memcpy(addr, buffer, data.size()); |  | ||||||
|     VirtualProtect(mbi.BaseAddress, mbi.RegionSize, mbi.Protect, NULL); |     VirtualProtect(mbi.BaseAddress, mbi.RegionSize, mbi.Protect, NULL); | ||||||
|     if (buffer) { |  | ||||||
|         free(buffer); |  | ||||||
|     } |  | ||||||
|     return; |     return; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void cmd_read(vector<string> args) { | void cmd_read(Command* cmd,vector<string> args) { | ||||||
|     MEMORY_BASIC_INFORMATION mbi; |     MEMORY_BASIC_INFORMATION mbi; | ||||||
|     if (args.size() != 2) { |     if (args.size()<1) { | ||||||
|         scrap_log(ERR_COLOR, "Usage: $r <addr> <size>\n"); |         scrap_log(ERR_COLOR, cmd->usage); | ||||||
|  |         scrap_log(ERR_COLOR, "\n"); | ||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
|     uintptr_t addr = UINTPTR_MAX; |     uintptr_t addr = UINTPTR_MAX; | ||||||
|     size_t size = 0; |     size_t size = 0xff; | ||||||
|     unsigned char *buffer; |     unsigned char *buffer; | ||||||
|     try { |     try { | ||||||
|         addr = stoull(args[0], 0, 16); |         addr = stoull(args[0], 0, 16); | ||||||
|         size = stoull(args[1]); |         if (args.size()>1) { | ||||||
|  |             size = stoull(args[1]); | ||||||
|  |         } | ||||||
|         buffer = new unsigned char[size]; |         buffer = new unsigned char[size]; | ||||||
|     } catch (exception e) { |     } catch (exception e) { | ||||||
|         scrap_log(ERR_COLOR, "ERROR!\n"); |         scrap_log(ERR_COLOR, "ERROR: "); | ||||||
|  |         scrap_log(ERR_COLOR, e.what()); | ||||||
|  |         scrap_log(ERR_COLOR, "\n"); | ||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
|     void *mptr = reinterpret_cast<void *>(addr); |     void *mptr = reinterpret_cast<void *>(addr); | ||||||
|     if (VirtualQuery(mptr, &mbi, sizeof(mbi)) == 0) { |     if (VirtualQuery(mptr, &mbi, sizeof(mbi)) == 0) { | ||||||
|         scrap_log(ERR_COLOR, "ERROR!\n"); |         scrap_log(ERR_COLOR, "ERROR: "); | ||||||
|  |         scrap_log(ERR_COLOR, GetLastErrorAsString()); | ||||||
|  |         scrap_log(ERR_COLOR, "\n"); | ||||||
|  |         return; | ||||||
|  |     }; | ||||||
|  |     if (!VirtualProtect(mbi.BaseAddress, mbi.RegionSize, PAGE_EXECUTE_READWRITE, | ||||||
|  |                    &mbi.Protect)) { | ||||||
|  |         scrap_log(ERR_COLOR, "ERROR: "); | ||||||
|  |         scrap_log(ERR_COLOR, GetLastErrorAsString()); | ||||||
|  |         scrap_log(ERR_COLOR, "\n"); | ||||||
|         return; |         return; | ||||||
|     }; |     }; | ||||||
|     VirtualProtect(mbi.BaseAddress, mbi.RegionSize, PAGE_EXECUTE_READWRITE, |  | ||||||
|                    &mbi.Protect); |  | ||||||
|     string hxd = hexdump_s(mptr, size); |     string hxd = hexdump_s(mptr, size); | ||||||
|     scrap_log(INFO_COLOR, hxd.c_str()); |     scrap_log(INFO_COLOR, hxd.c_str()); | ||||||
|     VirtualProtect(mbi.BaseAddress, mbi.RegionSize, mbi.Protect, NULL); |     VirtualProtect(mbi.BaseAddress, mbi.RegionSize, mbi.Protect, NULL); | ||||||
|  | @ -99,26 +347,78 @@ void cmd_read(vector<string> args) { | ||||||
|     return; |     return; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void cmd_dx8(vector<string> args) { | void cmd_hook_dx8(Command* cmd,vector<string> args) { | ||||||
|  |     hook_d3d8(); | ||||||
|  |     scrap_log(INFO_COLOR,"DX8 hooked!\n"); | ||||||
|  |     return; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void cmd_unhook_dx8(Command* cmd,vector<string> args) { | ||||||
|  |     unhook_d3d8(); | ||||||
|  |     scrap_log(INFO_COLOR,"DX8 unhooked!\n"); | ||||||
|  |     return; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | void cmd_dx8(Command* cmd,vector<string> args) { | ||||||
|     if (args.size()!=1) { |     if (args.size()!=1) { | ||||||
|         scrap_log(ERR_COLOR, "Usage: $dx8 (hook|unhook)\n"); |         scrap_log(ERR_COLOR, cmd->usage); | ||||||
|  |         scrap_log(ERR_COLOR, "\n"); | ||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
|     if (args[0]=="hook") { |      if (args[0]=="zenable:true") { | ||||||
|         hook_d3d8(); |         use_z=true; | ||||||
|         scrap_log(INFO_COLOR,"DX8 hooked!\n"); |         scrap_log(INFO_COLOR,"DX8 mode switched!\n"); | ||||||
|         return; |         return; | ||||||
|     } |     }; | ||||||
|     if (args[0]=="unhook") { |     if (args[0]=="zenable:false") { | ||||||
|         unhook_d3d8(); |         use_z=false; | ||||||
|         scrap_log(INFO_COLOR,"DX8 unhooked!\n"); |         scrap_log(INFO_COLOR,"DX8 mode switched!\n"); | ||||||
|  |         return; | ||||||
|  |     }; | ||||||
|  |      | ||||||
|  |     if (args[0]=="fill:wire") { | ||||||
|  |         fillmode=D3DFILLMODE::D3DFILL_WIREFRAME; | ||||||
|  |         scrap_log(INFO_COLOR,"DX8 mode switched!\n"); | ||||||
|  |         return; | ||||||
|  |     }; | ||||||
|  |      | ||||||
|  |     if (args[0]=="fill:solid") { | ||||||
|  |         fillmode=D3DFILLMODE::D3DFILL_SOLID; | ||||||
|  |         scrap_log(INFO_COLOR,"DX8 mode switched!\n"); | ||||||
|  |         return; | ||||||
|  |     }; | ||||||
|  |      | ||||||
|  |     if (args[0]=="fill:point") { | ||||||
|  |         fillmode=D3DFILLMODE::D3DFILL_POINT; | ||||||
|  |         scrap_log(INFO_COLOR,"DX8 mode switched!\n"); | ||||||
|         return; |         return; | ||||||
|     }; |     }; | ||||||
|     scrap_log(ERR_COLOR,"Invalid argument!\n"); |     scrap_log(ERR_COLOR,"Invalid argument!\n"); | ||||||
|     return; |     return; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void cmd_dump_py(vector<string> args) { | void cmd_dump_stack(Command* cmd, vector<string> args) { | ||||||
|  |     void** stack=(void**)_AddressOfReturnAddress(); | ||||||
|  |     cout<<"ESP:    "<<stack<<endl; | ||||||
|  |     for (size_t n=0;n<0x100;++n) { | ||||||
|  |         if (!addr_exists(stack[n])) { | ||||||
|  |             continue; | ||||||
|  |         } | ||||||
|  |         char R=can_read(stack[n]) ? 'R' : ' '; | ||||||
|  |         char W=can_write(stack[n]) ? 'W' : ' '; | ||||||
|  |         char X=can_execute(stack[n]) ? 'X' : ' '; | ||||||
|  |         cout<<"ESP[" << std::hex << setfill('0') << setw(2) << n <<"]: "<<stack[n]<<" "<<R<<W<<X; | ||||||
|  |         if (can_read(stack[n])) { | ||||||
|  |             cout<<" [ "<<hexdump_s(stack[n],0xf,true)<<"]"<<endl; | ||||||
|  |         } else { | ||||||
|  |             cout<<endl; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     return; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void cmd_dump_py(Command* cmd,vector<string> args) { | ||||||
|     stringstream out; |     stringstream out; | ||||||
|     for (auto mod : Py) { |     for (auto mod : Py) { | ||||||
|         for (auto meth : mod.second.methods) { |         for (auto meth : mod.second.methods) { | ||||||
|  | @ -129,7 +429,18 @@ void cmd_dump_py(vector<string> args) { | ||||||
|     scrap_log(INFO_COLOR,out.str().c_str()); |     scrap_log(INFO_COLOR,out.str().c_str()); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void cmd_dump_ents(vector<string> args) { | void cmd_dump_vars(Command* cmd, vector<string> args) { | ||||||
|  |     stringstream out; | ||||||
|  |     GameVar* var=ptr<GameVar>(P_VARS,0); | ||||||
|  |     out << "GameVars:" << endl; | ||||||
|  |     while (var!=nullptr) { | ||||||
|  |         out<<var->name<< "[" <<std::hex <<(uint16_t)var->type <<","<< (uint16_t)var->subtype << std::dec << "]: " << var->desc<<" ("<<var->value<<", "<<var->default<<")"<<endl; | ||||||
|  |         var=var->next; | ||||||
|  |     } | ||||||
|  |     scrap_log(INFO_COLOR,out.str().c_str()); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void cmd_dump_ents(Command* cmd,vector<string> args) { | ||||||
|     stringstream out; |     stringstream out; | ||||||
|     out << "Entities:" << endl; |     out << "Entities:" << endl; | ||||||
|     dump_ht(ptr<HashTable<Entity>>(P_WORLD, O_ENTS), &out); |     dump_ht(ptr<HashTable<Entity>>(P_WORLD, O_ENTS), &out); | ||||||
|  | @ -139,7 +450,11 @@ void cmd_dump_ents(vector<string> args) { | ||||||
|     return; |     return; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void cmd_toggle_overlay(vector<string> args) { | void cmd_toggle_overlay(Command* cmd,vector<string> args) { | ||||||
|  |     if (!hooked) { | ||||||
|  |         scrap_log(INFO_COLOR,"DX8 not hooked, run '$dx8 hook' first!\n"); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|     overlay=!overlay; |     overlay=!overlay; | ||||||
|     if (overlay) { |     if (overlay) { | ||||||
|         scrap_log(INFO_COLOR,"Overlay enabled!\n"); |         scrap_log(INFO_COLOR,"Overlay enabled!\n"); | ||||||
|  | @ -148,7 +463,20 @@ void cmd_toggle_overlay(vector<string> args) { | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void cmd_print_alarm(vector<string> args) { | void cmd_enable_overlay(Command* cmd,vector<string> args) { | ||||||
|  |     if (!overlay) { | ||||||
|  |         cmd_toggle_overlay(cmd,args); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void cmd_disable_overlay(Command* cmd,vector<string> args) { | ||||||
|  |     if (overlay) { | ||||||
|  |         cmd_toggle_overlay(cmd,args); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | void cmd_print_alarm(Command* cmd,vector<string> args) { | ||||||
|     stringstream out; |     stringstream out; | ||||||
|     float *alarm = ptr<float>(P_WORLD, O_ALARM); |     float *alarm = ptr<float>(P_WORLD, O_ALARM); | ||||||
|     float *alarm_grow = ptr<float>(P_WORLD, O_ALARM_GROW); |     float *alarm_grow = ptr<float>(P_WORLD, O_ALARM_GROW); | ||||||
|  | @ -157,103 +485,88 @@ void cmd_print_alarm(vector<string> args) { | ||||||
|     return; |     return; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void cmd_unload(vector<string> args) {  | void cmd_unload(Command* cmd,vector<string> args) {  | ||||||
|     scrap_log(INFO_COLOR,"Unloading ScrapHacks... bye!\n"); |     scrap_log(INFO_COLOR,"Unloading ScrapHacks... bye!\n"); | ||||||
|     DllUnload();  |     DllUnload();  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static map<string, t_cmd> commands = { | void cmd_asm(Command* cmd, vector<string> args) { | ||||||
|     {"w", { |     string code; | ||||||
|         cmd_write, |     uintptr_t buffer_addr; | ||||||
|         "Usage: $w <addr> <data(hex)>", |     bool has_addr=false; | ||||||
|         "Write memory" |     if (args.size()<1) { | ||||||
|     }}, |         scrap_log(ERR_COLOR, cmd->usage); | ||||||
|     {"r", { |         return; | ||||||
|         cmd_read, |     } | ||||||
|         "Usage: $r <addr> <num_bytes>", |     try { | ||||||
|         "Read memory" |         buffer_addr=stoull(args[0], 0, 16); | ||||||
|     }}, |         has_addr=true; | ||||||
|     {"unload", { |     } catch (exception e) { | ||||||
|         cmd_unload, |         // NOP
 | ||||||
|         "Usage: $unload", |         has_addr=false; | ||||||
|         "Unload ScrapHacks" |     } | ||||||
|     }}, |     if (has_addr) { | ||||||
|     {"dx8", { |         // remove address from args
 | ||||||
|         cmd_dx8, |         args.erase(args.begin()); | ||||||
|         "Usage: $dx8 (hook|unhook)", |     } | ||||||
|         "Hook/Unhook DirectX 8 functions" |     for (string arg:args) { | ||||||
|     }}, |         code+=arg+" "; | ||||||
|     {"dump_py",{ |     }; | ||||||
|         cmd_dump_py, |     size_t data_size=asm_size(split(code,';')); | ||||||
|         "Usage: $dump_py", |     if (!has_addr) { | ||||||
|         "Dump python modules to console" |         buffer_addr = (uintptr_t)malloc(data_size); | ||||||
|     }}, |         if (buffer_addr==0) { | ||||||
|     {"overlay",{ |             scrap_log(ERR_COLOR, "ERROR: "); | ||||||
|         cmd_toggle_overlay, |             scrap_log(ERR_COLOR, "malloc() failed"); | ||||||
|         "Usage: $overlay", |             scrap_log(ERR_COLOR, "\n"); | ||||||
|         "Toggle DX8 Overlay" |             return; | ||||||
|     }}, |  | ||||||
|     {"alarm",{ |  | ||||||
|         cmd_print_alarm, |  | ||||||
|         "Usage: $alarm", |  | ||||||
|         "Print alarm status" |  | ||||||
|     }}, |  | ||||||
|     {"ents",{ |  | ||||||
|         cmd_dump_ents, |  | ||||||
|         "Usage: $ents", |  | ||||||
|         "Dump entity information" |  | ||||||
|     }}, |  | ||||||
|     {"help", { |  | ||||||
|         cmd_help, |  | ||||||
|         "Usage: $help [command]", |  | ||||||
|         "Print help for ScrapHacks command"}}, |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| void cmd_help(vector<string> args) { |  | ||||||
|     if (args.size()!=1) { |  | ||||||
|         for (auto cmd: commands) { |  | ||||||
|             scrap_log(INFO_COLOR,cmd.first.c_str()); |  | ||||||
|             scrap_log(INFO_COLOR,": "); |  | ||||||
|             scrap_log(INFO_COLOR,cmd.second.doc); |  | ||||||
|             scrap_log(INFO_COLOR,"\n"); |  | ||||||
|         } |         } | ||||||
|         return; |         char ptr[255]; | ||||||
|  |         snprintf(ptr,255,"Buffer @ %p\n",(void*)buffer_addr); | ||||||
|  |         scrap_log(INFO_COLOR,ptr); | ||||||
|     } |     } | ||||||
|     if (!commands.count(args[0])) { |     assemble(split(code,';'),buffer_addr); | ||||||
|         scrap_log(ERR_COLOR, "Unknown command '"); |  | ||||||
|         scrap_log(ERR_COLOR, args[0].c_str()); |  | ||||||
|         scrap_log(ERR_COLOR, "'!\n"); |  | ||||||
|         return; |  | ||||||
|     } |  | ||||||
|     t_cmd cmd=commands[args[0]]; |  | ||||||
|     scrap_log(INFO_COLOR,args[0].c_str()); |  | ||||||
|     scrap_log(INFO_COLOR,": "); |  | ||||||
|     scrap_log(INFO_COLOR,cmd.usage); |  | ||||||
|     scrap_log(INFO_COLOR,"\n\t"); |  | ||||||
|     scrap_log(INFO_COLOR,cmd.doc); |  | ||||||
|     scrap_log(INFO_COLOR,"\n"); |  | ||||||
|     return; |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | void cmd_help(Command* cmd,vector<string> args); | ||||||
|  | 
 | ||||||
|  | static REPL* repl=new REPL( | ||||||
|  | { | ||||||
|  |     {"mem",new Command("Usage: $mem (read|write)","Manipulate memory",{ | ||||||
|  |         {"read",new Command(cmd_read,"Usage: $mem read <addr> [size]","Read memory")}, | ||||||
|  |         {"write",new Command(cmd_write,"Usage: $mem write [addr] <data(hex)>","Write memory, if no address is specifiew we VirtualAlloc() a region")}, | ||||||
|  |         {"exec",new Command(cmd_exec,"Usage: $exec <addr>","Start a new thread at the specified address")}, | ||||||
|  |         {"asm",new Command(cmd_asm,"Usage: $asm [addr] <inst1>;<inst2>;...","Assemble instructions at address, if no address is given allocate memory and assemble code into that")}, | ||||||
|  |         {"stack",new Command(cmd_dump_stack,"Usage: $mem stack","Dump stack contents")}, | ||||||
|  |     })}, | ||||||
|  |     {"unload",new Command(cmd_unload,"Usage: $unload","Unload ScrapHacks")}, | ||||||
|  |     {"dx8",new Command(cmd_dx8,"Usage: $dx8 <subcommand>","Manipulate DirectX 8 functions and state",{ | ||||||
|  |         {"overlay",new Command("Usage: $dx8 overlay <subcommand>","Control DX8 overlay",{ | ||||||
|  |             {"toggle",new Command(cmd_toggle_overlay,"Usage: $dx8 overlay toggle","Toggle overlay")}, | ||||||
|  |             {"enable",new Command(cmd_enable_overlay,"Usage: $dx8 overlay enable","Enable overlay")}, | ||||||
|  |             {"disable",new Command(cmd_disable_overlay,"Usage: $dx8 overlay disable","Disable overlay")}, | ||||||
|  |         })}, | ||||||
|  |         {"hook",new Command(cmd_hook_dx8,"Usage: $dx8 hook","Enable DirectX 8 hook")}, | ||||||
|  |         {"unhook",new Command(cmd_unhook_dx8,"Usage: $dx8 hook","Disable DirectX 8 hook")} | ||||||
|  |     })}, | ||||||
|  |     {"dump",new Command("Usage: $dump <subcommand>","Dump various data to the console",{ | ||||||
|  |         {"py",new Command(cmd_dump_py,"Usage: $dump py","Dump python module information")}, | ||||||
|  |         {"ents",new Command(cmd_dump_ents,"Usage: $dump ents","Dump entity information")}, | ||||||
|  |         {"alarm",new Command(cmd_print_alarm,"Usage: $dump alarm","Print alarm status")}, | ||||||
|  |         {"vars",new Command(cmd_dump_vars,"Usage: $dump vars","Print engine variables")}, | ||||||
|  |     })}, | ||||||
|  |     {"help",new Command(cmd_help,"Usage: $help [command]","Print help for ScrapHacks command")} | ||||||
|  | }); | ||||||
|  | 
 | ||||||
|  | void cmd_help(Command* cmd,vector<string> args) { | ||||||
|  |     scrap_log(INFO_COLOR,repl->help(args)+"\n"); | ||||||
|  | }; | ||||||
| 
 | 
 | ||||||
| void handle_command(const char *_cmd) { | void handle_command(const char *_cmd) { | ||||||
|     scrap_log(ERR_COLOR, "$"); |     scrap_log(ERR_COLOR, "$"); | ||||||
|     scrap_log(ERR_COLOR, _cmd); |     scrap_log(ERR_COLOR, _cmd); | ||||||
|     scrap_log(ERR_COLOR, "\n"); |     scrap_log(ERR_COLOR, "\n"); | ||||||
|     cout << "CMD: '" << _cmd << "'" << endl; |     cout << "CMD: '" << _cmd << "'" << endl; | ||||||
|     vector<string> cmd = split(string(_cmd), ' '); |     repl->exec(split(string(_cmd), ' ')); | ||||||
|     if (cmd.size() == 0) { |  | ||||||
|         return; |  | ||||||
|     } |  | ||||||
|     if (commands.count(cmd[0])) { |  | ||||||
|         string command = cmd[0]; |  | ||||||
|         cmd.erase(cmd.begin()); |  | ||||||
|         commands[command].func(cmd); |  | ||||||
|     } else { |  | ||||||
|         scrap_log(ERR_COLOR, "Unknown command '"); |  | ||||||
|         scrap_log(ERR_COLOR, cmd[0].c_str()); |  | ||||||
|         scrap_log(ERR_COLOR, "'!\n"); |  | ||||||
|     } |  | ||||||
|     return; |     return; | ||||||
| } | } | ||||||
|  | @ -9,12 +9,6 @@ | ||||||
| 
 | 
 | ||||||
| #include <Windows.h> | #include <Windows.h> | ||||||
| 
 | 
 | ||||||
| // Socket stuff
 |  | ||||||
| 
 |  | ||||||
| #include <Ws2tcpip.h> |  | ||||||
| #include <stdio.h> |  | ||||||
| #include <winsock2.h> |  | ||||||
| 
 |  | ||||||
| using namespace std; | using namespace std; | ||||||
| 
 | 
 | ||||||
| #include "D3D8_Hook.hpp" | #include "D3D8_Hook.hpp" | ||||||
|  | @ -34,22 +28,6 @@ void DllUnload(); | ||||||
| int hooked_console(const char *); | int hooked_console(const char *); | ||||||
| void hook_exit(); | void hook_exit(); | ||||||
| 
 | 
 | ||||||
| int hook_recvfrom(SOCKET s, char *buf, int len, int flags, sockaddr *from, |  | ||||||
|                   int *fromlen) { |  | ||||||
|     typedef decltype(&hook_recvfrom) t_func; |  | ||||||
|     shared_ptr<Hook> hook = Hook::get(hook_recvfrom); |  | ||||||
|     int ret = hook->func<t_func>(s, buf, len, flags, from, fromlen); |  | ||||||
|     return ret; |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| int hook_sendto(SOCKET s, const char *buf, int len, int flags, |  | ||||||
|                 const sockaddr *to, int tolen) { |  | ||||||
|     typedef decltype(&hook_sendto) t_func; |  | ||||||
|     shared_ptr<Hook> hook = Hook::get(hook_sendto); |  | ||||||
|     int ret = hook->func<t_func>(s, buf, len, flags, to, tolen); |  | ||||||
|     return ret; |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| void setup_hooks() { | void setup_hooks() { | ||||||
|     Hook::addr(reinterpret_cast<void *>(P_SCRAP_EXIT), hook_exit); |     Hook::addr(reinterpret_cast<void *>(P_SCRAP_EXIT), hook_exit); | ||||||
|     Hook::addr(reinterpret_cast<void *>(P_CON_HANDLER), hooked_console); |     Hook::addr(reinterpret_cast<void *>(P_CON_HANDLER), hooked_console); | ||||||
|  | @ -127,7 +105,6 @@ void hook_exit() { | ||||||
| void DllInit(HMODULE mod) { | void DllInit(HMODULE mod) { | ||||||
|     hMod = mod; |     hMod = mod; | ||||||
|     char mfn[1024]; |     char mfn[1024]; | ||||||
|     InitConsole(); |  | ||||||
|     GetModuleFileNameA(0, mfn, 1024); |     GetModuleFileNameA(0, mfn, 1024); | ||||||
|     Py = get_modules(P_PY_MODS); |     Py = get_modules(P_PY_MODS); | ||||||
|     cout << "[+] ScrapHacks v0.1 Loaded in " << mfn << " (PID: " << std::hex |     cout << "[+] ScrapHacks v0.1 Loaded in " << mfn << " (PID: " << std::hex | ||||||
|  | @ -150,16 +127,22 @@ void DllInit(HMODULE mod) { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void *H_port_FixupExtension(char *name, char *filename) { | void *H_port_FixupExtension(char *name, char *filename) { | ||||||
|  |     cout<<"FixupExtension: "<<name<<": "<<filename<<endl; | ||||||
|     Hook::drop(H_port_FixupExtension); |     Hook::drop(H_port_FixupExtension); | ||||||
|     return NULL; |     return NULL; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void *H_PyEval_CallObjectWithKeywords(void *func, void *arg, void *kwarg) { | void *H_PyEval_CallObjectWithKeywords(void *func, void *arg, void *kwarg) { | ||||||
|  |     cout<<"PyEval_CallObjectWithKeywords:"<<endl; | ||||||
|  |     cout<<"\t func: "<<func<<endl; | ||||||
|  |     cout<<"\t arg: "<<arg<<endl; | ||||||
|  |     cout<<"\t kwarg: "<<kwarg<<endl; | ||||||
|     Hook::drop(H_PyEval_CallObjectWithKeywords); |     Hook::drop(H_PyEval_CallObjectWithKeywords); | ||||||
|     return NULL; |     return NULL; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void DllPreInit() { | void DllPreInit() { | ||||||
|  |     InitConsole(); | ||||||
|     Hook::addr(reinterpret_cast<void *>(0x5a9ca0), H_port_FixupExtension); |     Hook::addr(reinterpret_cast<void *>(0x5a9ca0), H_port_FixupExtension); | ||||||
|     Hook::addr(reinterpret_cast<void *>(0x5cdb00), |     Hook::addr(reinterpret_cast<void *>(0x5cdb00), | ||||||
|                H_PyEval_CallObjectWithKeywords); |                H_PyEval_CallObjectWithKeywords); | ||||||
|  |  | ||||||
|  | @ -1,4 +1,8 @@ | ||||||
| #pragma once | #pragma once | ||||||
|  | #include "Structures.hpp" | ||||||
|  | 
 | ||||||
|  | #include <sstream> | ||||||
|  | using namespace std; | ||||||
| 
 | 
 | ||||||
| // OFFSETS
 | // OFFSETS
 | ||||||
| #define O_MONEY 0x2090 | #define O_MONEY 0x2090 | ||||||
|  | @ -9,6 +13,7 @@ | ||||||
| 
 | 
 | ||||||
| // POINTERS
 | // POINTERS
 | ||||||
| #define P_WORLD 0x7FE944 | #define P_WORLD 0x7FE944 | ||||||
|  | #define P_VARS 0x7FBE4C | ||||||
| #define P_PY_MODS 0x79C698 | #define P_PY_MODS 0x79C698 | ||||||
| 
 | 
 | ||||||
| // FUNCTION ADDRESSES
 | // FUNCTION ADDRESSES
 | ||||||
|  | @ -22,7 +27,8 @@ | ||||||
| #define P_PyArg_ParseTuple 0x5bb9d0 | #define P_PyArg_ParseTuple 0x5bb9d0 | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| #define MSG_COLOR scrap_RGB(255,128,0) | #define MSG_COLOR scrap_RGB(128,0,255) | ||||||
|  | #define WARN_COLOR scrap_RGB(255,128,0) | ||||||
| #define ERR_COLOR scrap_RGB(255,0,0) | #define ERR_COLOR scrap_RGB(255,0,0) | ||||||
| #define INFO_COLOR scrap_RGB(0,0,255) | #define INFO_COLOR scrap_RGB(0,0,255) | ||||||
| 
 | 
 | ||||||
|  | @ -51,3 +57,126 @@ int scrap_log(unsigned int color,const char* msg) { | ||||||
| int scrap_log(uint8_t r,uint8_t g,uint8_t b,const char* msg) { | int scrap_log(uint8_t r,uint8_t g,uint8_t b,const char* msg) { | ||||||
|     return ((t_scrap_log)P_SCRAP_LOG)(scrap_RGB(r,g,b),msg); |     return ((t_scrap_log)P_SCRAP_LOG)(scrap_RGB(r,g,b),msg); | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | int scrap_log(unsigned int color,string msg) { | ||||||
|  |     return ((t_scrap_log)P_SCRAP_LOG)(color,msg.c_str()); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | int scrap_log(uint8_t r,uint8_t g,uint8_t b,string msg) { | ||||||
|  |     return ((t_scrap_log)P_SCRAP_LOG)(scrap_RGB(r,g,b),msg.c_str()); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | size_t size_ht(HashTable<EntityList> *ht) { | ||||||
|  |     size_t cnt = 0; | ||||||
|  |     for (size_t i = 0; i < ht->size; ++i) { | ||||||
|  |         HashTableEntry<EntityList> *ent = ht->chains[i]; | ||||||
|  |         if (ent) { | ||||||
|  |             while (ent) { | ||||||
|  |                 ++cnt; | ||||||
|  |                 ent = ent->next; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     return cnt; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | size_t size_ht(HashTable<Entity> *ht) { | ||||||
|  |     size_t cnt = 0; | ||||||
|  |     for (size_t i = 0; i < ht->size; ++i) { | ||||||
|  |         HashTableEntry<Entity> *ent = ht->chains[i]; | ||||||
|  |         if (ent) { | ||||||
|  |             while (ent) { | ||||||
|  |                 ++cnt; | ||||||
|  |                 ent = ent->next; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     return cnt; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | size_t dump_ht(HashTable<EntityList> *ht) { | ||||||
|  |     size_t cnt = 0; | ||||||
|  |     for (size_t i = 0; i < ht->size; ++i) { | ||||||
|  |         HashTableEntry<EntityList> *ent = ht->chains[i]; | ||||||
|  |         if (ent) { | ||||||
|  |             cout << i << ": "; | ||||||
|  |             while (ent) { | ||||||
|  |                 ++cnt; | ||||||
|  |                 cout << "[ " << ent->name << ": " << ent->data << "]"; | ||||||
|  |                 if (ent->next) { | ||||||
|  |                     cout << " -> "; | ||||||
|  |                 }; | ||||||
|  |                 ent = ent->next; | ||||||
|  |             } | ||||||
|  |             cout << endl; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     cout << cnt << " Entries" << endl; | ||||||
|  |     return cnt; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | size_t dump_ht(HashTable<Entity> *ht) { | ||||||
|  |     size_t cnt = 0; | ||||||
|  |     for (size_t i = 0; i < ht->size; ++i) { | ||||||
|  |         HashTableEntry<Entity> *ent = ht->chains[i]; | ||||||
|  |         if (ent) { | ||||||
|  |             cout << i << ": "; | ||||||
|  |             while (ent) { | ||||||
|  |                 ++cnt; | ||||||
|  |                 cout << "[ " << ent->name << ": " << ent->data << "]"; | ||||||
|  |                 if (ent->next) { | ||||||
|  |                     cout << " -> "; | ||||||
|  |                 }; | ||||||
|  |                 ent = ent->next; | ||||||
|  |             } | ||||||
|  |             cout << endl; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     cout << cnt << " Entries" << endl; | ||||||
|  |     return cnt; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | size_t dump_ht(HashTable<EntityList> *ht,stringstream *out) { | ||||||
|  |     size_t cnt = 0; | ||||||
|  |     for (size_t i = 0; i < ht->size; ++i) { | ||||||
|  |         HashTableEntry<EntityList> *ent = ht->chains[i]; | ||||||
|  |         if (ent) { | ||||||
|  |             *out << i << ": "; | ||||||
|  |             while (ent) { | ||||||
|  |                 ++cnt; | ||||||
|  |                 *out << "[ " << ent->name << ": " << ent->data << "]"; | ||||||
|  |                 if (ent->next) { | ||||||
|  |                     *out << " -> "; | ||||||
|  |                 }; | ||||||
|  |                 ent = ent->next; | ||||||
|  |             } | ||||||
|  |             *out << endl; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     *out << cnt << " Entries" << endl; | ||||||
|  |     return cnt; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | size_t dump_ht(HashTable<Entity> *ht,stringstream *out) { | ||||||
|  |     size_t cnt = 0; | ||||||
|  |     for (size_t i = 0; i < ht->size; ++i) { | ||||||
|  |         HashTableEntry<Entity> *ent = ht->chains[i]; | ||||||
|  |         if (ent) { | ||||||
|  |             *out << i << ": "; | ||||||
|  |             while (ent) { | ||||||
|  |                 ++cnt; | ||||||
|  |                 *out << "[ " << ent->name << ": " << ent->data << "]"; | ||||||
|  |                 if (ent->next) { | ||||||
|  |                     *out << " -> "; | ||||||
|  |                 }; | ||||||
|  |                 ent = ent->next; | ||||||
|  |             } | ||||||
|  |             *out << endl; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     *out << cnt << " Entries" << endl; | ||||||
|  |     return cnt; | ||||||
|  | } | ||||||
|  | @ -1,5 +1,7 @@ | ||||||
| #pragma once | #pragma once | ||||||
|  | using namespace std; | ||||||
| template <typename T> struct HashTableEntry; | template <typename T> struct HashTableEntry; | ||||||
|  | 
 | ||||||
| struct Vector3 { | struct Vector3 { | ||||||
|     float x; |     float x; | ||||||
|     float y; |     float y; | ||||||
|  | @ -7,9 +9,9 @@ struct Vector3 { | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| struct Matrix3x3 { | struct Matrix3x3 { | ||||||
|     Vector3 a; |     struct Vector3 a; | ||||||
|     Vector3 b; |     struct Vector3 b; | ||||||
|     Vector3 c; |     struct Vector3 c; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| struct PyMethodDef { | struct PyMethodDef { | ||||||
|  | @ -42,9 +44,41 @@ struct EntityList { | ||||||
|     const char *func; |     const char *func; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | struct GameVar { | ||||||
|  |     struct GameVar* next; | ||||||
|  |     const char* name; | ||||||
|  |     const char* desc; | ||||||
|  |     uint8_t type; | ||||||
|  |     uint8_t subtype; | ||||||
|  |     uint16_t unk; | ||||||
|  |     void* value; | ||||||
|  |     void* default; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | struct PakEntry { | ||||||
|  |     unsigned char* filename; | ||||||
|  |     uint32_t locked; | ||||||
|  |     void* data; | ||||||
|  |     uint32_t seek; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | struct HashIndexEntry { | ||||||
|  |     uint32_t offset; | ||||||
|  |     uint32_t size; | ||||||
|  |     uint32_t status; | ||||||
|  |     const char* name; | ||||||
|  |     struct HashIndexEntry* next; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | struct HashIndex { | ||||||
|  |     uint32_t size; | ||||||
|  |     struct HashIndexEntry** data; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| template <typename T> struct HashTable { | template <typename T> struct HashTable { | ||||||
|     uint32_t size; |     uint32_t size; | ||||||
|     HashTableEntry<T> **chains; |     struct HashTableEntry<T> **chains; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| template <typename T> struct HashTableEntry { | template <typename T> struct HashTableEntry { | ||||||
|  |  | ||||||
|  | @ -9,9 +9,6 @@ | ||||||
| #include <string> | #include <string> | ||||||
| #include <vector> | #include <vector> | ||||||
| 
 | 
 | ||||||
| #include "Structures.hpp" |  | ||||||
| #include "Py_Utils.hpp" |  | ||||||
| 
 |  | ||||||
| using namespace std; | using namespace std; | ||||||
| 
 | 
 | ||||||
| #define DLL_EXPORT extern "C" __declspec(dllexport) | #define DLL_EXPORT extern "C" __declspec(dllexport) | ||||||
|  | @ -116,18 +113,56 @@ bool key_down_norepeat(int keycode, int delay = 100) { | ||||||
|     return false; |     return false; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| string hexdump_s(void *addr, size_t count=0xff) { | bool addr_exists(void* addr) { | ||||||
|  |     MEMORY_BASIC_INFORMATION mbi; | ||||||
|  |     if (!VirtualQuery(addr,&mbi,sizeof(mbi))) { | ||||||
|  |         return false; | ||||||
|  |     }; | ||||||
|  |     return true; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool can_read(void* addr) { | ||||||
|  |     MEMORY_BASIC_INFORMATION mbi; | ||||||
|  |     if (!VirtualQuery(addr,&mbi,sizeof(mbi))) { | ||||||
|  |         return false; | ||||||
|  |     }; | ||||||
|  |     return (mbi.Protect==PAGE_EXECUTE_READ)||(mbi.Protect==PAGE_EXECUTE_READWRITE)||(mbi.Protect==PAGE_READONLY)||(mbi.Protect==PAGE_READWRITE); | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool can_write(void* addr) { | ||||||
|  |     MEMORY_BASIC_INFORMATION mbi; | ||||||
|  |     if (!VirtualQuery(addr,&mbi,sizeof(mbi))) { | ||||||
|  |         return false; | ||||||
|  |     }; | ||||||
|  |     return (mbi.Protect==PAGE_EXECUTE_READWRITE)||(mbi.Protect==PAGE_EXECUTE_WRITECOPY)||(mbi.Protect==PAGE_READWRITE)||(mbi.Protect==PAGE_WRITECOPY); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool can_execute(void* addr) { | ||||||
|  |     MEMORY_BASIC_INFORMATION mbi; | ||||||
|  |     if (!VirtualQuery(addr,&mbi,sizeof(mbi))) { | ||||||
|  |         return false; | ||||||
|  |     }; | ||||||
|  |     return (mbi.Protect==PAGE_EXECUTE_READWRITE)||(mbi.Protect==PAGE_EXECUTE_WRITECOPY)||(mbi.Protect==PAGE_EXECUTE_READ)||(mbi.Protect==PAGE_EXECUTE); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | string hexdump_s(void *addr, size_t count=0x100,bool compact=false) { | ||||||
|     ostringstream out; |     ostringstream out; | ||||||
|     uintptr_t offset=reinterpret_cast<uintptr_t>(addr); |     uintptr_t offset=reinterpret_cast<uintptr_t>(addr); | ||||||
|     for (size_t i = 0; i < count; ++i) { |     for (size_t i = 0; i < count; ++i) { | ||||||
|         unsigned int val = (unsigned int)(((unsigned char *)(offset+i))[0]); |         unsigned int val = (unsigned int)(((unsigned char *)(offset+i))[0]); | ||||||
|         if ((i % 16) == 0) { |         if ((i % 16) == 0) { | ||||||
|             out << endl; |             if (!compact) { | ||||||
|             out << setfill('0') << setw(8) << std::hex << std::uppercase << (offset+i) << ": "; |                 out << endl; | ||||||
|  |                 out << setfill('0') << setw(8) << std::hex << std::uppercase << (offset+i) << ": "; | ||||||
|  |             } | ||||||
|         } |         } | ||||||
|         out << setfill('0') << setw(2) << std::hex << val << " "; |         out << setfill('0') << setw(2) << std::hex << val << " "; | ||||||
|     } |     } | ||||||
|     out << endl; |     if (!compact) { | ||||||
|  |         out << endl; | ||||||
|  |     } | ||||||
|     return out.str(); |     return out.str(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -259,117 +294,3 @@ vector<string> split(string str, char sep) { | ||||||
|         ret.push_back(part); |         ret.push_back(part); | ||||||
|     return ret; |     return ret; | ||||||
| } | } | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| size_t size_ht(HashTable<EntityList> *ht) { |  | ||||||
|     size_t cnt = 0; |  | ||||||
|     for (size_t i = 0; i < ht->size; ++i) { |  | ||||||
|         HashTableEntry<EntityList> *ent = ht->chains[i]; |  | ||||||
|         if (ent) { |  | ||||||
|             while (ent) { |  | ||||||
|                 ++cnt; |  | ||||||
|                 ent = ent->next; |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|     return cnt; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| size_t size_ht(HashTable<Entity> *ht) { |  | ||||||
|     size_t cnt = 0; |  | ||||||
|     for (size_t i = 0; i < ht->size; ++i) { |  | ||||||
|         HashTableEntry<Entity> *ent = ht->chains[i]; |  | ||||||
|         if (ent) { |  | ||||||
|             while (ent) { |  | ||||||
|                 ++cnt; |  | ||||||
|                 ent = ent->next; |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|     return cnt; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| size_t dump_ht(HashTable<EntityList> *ht) { |  | ||||||
|     size_t cnt = 0; |  | ||||||
|     for (size_t i = 0; i < ht->size; ++i) { |  | ||||||
|         HashTableEntry<EntityList> *ent = ht->chains[i]; |  | ||||||
|         if (ent) { |  | ||||||
|             cout << i << ": "; |  | ||||||
|             while (ent) { |  | ||||||
|                 ++cnt; |  | ||||||
|                 cout << "[ " << ent->name << ": " << ent->data << "]"; |  | ||||||
|                 if (ent->next) { |  | ||||||
|                     cout << " -> "; |  | ||||||
|                 }; |  | ||||||
|                 ent = ent->next; |  | ||||||
|             } |  | ||||||
|             cout << endl; |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|     cout << cnt << " Entries" << endl; |  | ||||||
|     return cnt; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| size_t dump_ht(HashTable<Entity> *ht) { |  | ||||||
|     size_t cnt = 0; |  | ||||||
|     for (size_t i = 0; i < ht->size; ++i) { |  | ||||||
|         HashTableEntry<Entity> *ent = ht->chains[i]; |  | ||||||
|         if (ent) { |  | ||||||
|             cout << i << ": "; |  | ||||||
|             while (ent) { |  | ||||||
|                 ++cnt; |  | ||||||
|                 cout << "[ " << ent->name << ": " << ent->data << "]"; |  | ||||||
|                 if (ent->next) { |  | ||||||
|                     cout << " -> "; |  | ||||||
|                 }; |  | ||||||
|                 ent = ent->next; |  | ||||||
|             } |  | ||||||
|             cout << endl; |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|     cout << cnt << " Entries" << endl; |  | ||||||
|     return cnt; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| size_t dump_ht(HashTable<EntityList> *ht,stringstream *out) { |  | ||||||
|     size_t cnt = 0; |  | ||||||
|     for (size_t i = 0; i < ht->size; ++i) { |  | ||||||
|         HashTableEntry<EntityList> *ent = ht->chains[i]; |  | ||||||
|         if (ent) { |  | ||||||
|             *out << i << ": "; |  | ||||||
|             while (ent) { |  | ||||||
|                 ++cnt; |  | ||||||
|                 *out << "[ " << ent->name << ": " << ent->data << "]"; |  | ||||||
|                 if (ent->next) { |  | ||||||
|                     *out << " -> "; |  | ||||||
|                 }; |  | ||||||
|                 ent = ent->next; |  | ||||||
|             } |  | ||||||
|             *out << endl; |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|     *out << cnt << " Entries" << endl; |  | ||||||
|     return cnt; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| size_t dump_ht(HashTable<Entity> *ht,stringstream *out) { |  | ||||||
|     size_t cnt = 0; |  | ||||||
|     for (size_t i = 0; i < ht->size; ++i) { |  | ||||||
|         HashTableEntry<Entity> *ent = ht->chains[i]; |  | ||||||
|         if (ent) { |  | ||||||
|             *out << i << ": "; |  | ||||||
|             while (ent) { |  | ||||||
|                 ++cnt; |  | ||||||
|                 *out << "[ " << ent->name << ": " << ent->data << "]"; |  | ||||||
|                 if (ent->next) { |  | ||||||
|                     *out << " -> "; |  | ||||||
|                 }; |  | ||||||
|                 ent = ent->next; |  | ||||||
|             } |  | ||||||
|             *out << endl; |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|     *out << cnt << " Entries" << endl; |  | ||||||
|     return cnt; |  | ||||||
| } |  | ||||||
|  | @ -1,7 +1,5 @@ | ||||||
| 
 |  | ||||||
| #include <Windows.h> | #include <Windows.h> | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
| #define DLL_EXPORT extern "C" __declspec(dllexport) | #define DLL_EXPORT extern "C" __declspec(dllexport) | ||||||
| 
 | 
 | ||||||
| using namespace std; | using namespace std; | ||||||
|  |  | ||||||
|  | @ -2,7 +2,6 @@ import os | ||||||
| import sys | import sys | ||||||
| import re | import re | ||||||
| outfile,infile=sys.argv[1:] | outfile,infile=sys.argv[1:] | ||||||
| 
 |  | ||||||
| re_interface=re.compile(r"^DECLARE_INTERFACE_{0,1}\((.*?)\)$") | re_interface=re.compile(r"^DECLARE_INTERFACE_{0,1}\((.*?)\)$") | ||||||
| re_method=re.compile(r"^\w*STDMETHOD_{0,1}\((.*?)\)\((.*?)\).*;") | re_method=re.compile(r"^\w*STDMETHOD_{0,1}\((.*?)\)\((.*?)\).*;") | ||||||
| name=None | name=None | ||||||
|  | @ -22,7 +21,6 @@ with open(infile,"r") as infh: | ||||||
|             meth_name=meth_name.split(",")[-1].strip() |             meth_name=meth_name.split(",")[-1].strip() | ||||||
|             VMTs[name][meth_name]=idx |             VMTs[name][meth_name]=idx | ||||||
|             idx+=1 |             idx+=1 | ||||||
| print(f"Generating: {outfile} from {infile} ...") |  | ||||||
| with open(outfile,"w") as ofh: | with open(outfile,"w") as ofh: | ||||||
|     for name in sorted(VMTs.keys()): |     for name in sorted(VMTs.keys()): | ||||||
|         print(f"namespace {name} {{",file=ofh) |         print(f"namespace {name} {{",file=ofh) | ||||||
							
								
								
									
										14
									
								
								lib/dbg.py
									
										
									
									
									
								
							
							
						
						
									
										14
									
								
								lib/dbg.py
									
										
									
									
									
								
							|  | @ -244,6 +244,20 @@ def nuke(): | ||||||
|         E = Scrap.GetEntity(E.NextInSlot) |         E = Scrap.GetEntity(E.NextInSlot) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | def test_func(): | ||||||
|  |     E = Scrap.GetFirst() | ||||||
|  |     me = Scrap.UsrEntity(0) | ||||||
|  |     while E: | ||||||
|  |         if E.Name == me.Name: | ||||||
|  |             E = Scrap.GetEntity(E.NextInSlot) | ||||||
|  |         try: | ||||||
|  |             E.Money=1024*1024*1024 | ||||||
|  |             # SAI.SetStateVehicle(8,me.Name,E.Name) | ||||||
|  |         except: | ||||||
|  |             pass | ||||||
|  |         E = Scrap.GetEntity(E.NextInSlot) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| def become(name): | def become(name): | ||||||
|     import CharConversor |     import CharConversor | ||||||
|     enable_all_conv() |     enable_all_conv() | ||||||
|  |  | ||||||
|  | @ -1,3 +1,4 @@ | ||||||
|  | import sys | ||||||
| from construct import * | from construct import * | ||||||
| from pprint import pprint | from pprint import pprint | ||||||
| 
 | 
 | ||||||
|  | @ -11,10 +12,10 @@ ScrapSave = "ScarpSaveGame" / Struct( | ||||||
|     "data" / PrefixedArray(Int32ul, ScrapSaveVar), |     "data" / PrefixedArray(Int32ul, ScrapSaveVar), | ||||||
|     Terminated, |     Terminated, | ||||||
| ) | ) | ||||||
| with open("Save0.sav", "rb") as sav_file: | with open(sys.argv[1], "rb") as sav_file: | ||||||
|     save = ScrapSave.parse_stream(sav_file) |     save = ScrapSave.parse_stream(sav_file) | ||||||
|     print("ID:", save.id) |     print("ID:", save.id) | ||||||
|     print("Title:", save.title) |     print("Title:", save.title) | ||||||
|     for var in save.data: |     for var in save.data: | ||||||
|         print(" - {}: {}".format(var.name, var.data)) |         print("   {}: {}".format(var.name, var.data)) | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
							
								
								
									
										407
									
								
								r2_analyze.py
									
										
									
									
									
								
							
							
						
						
									
										407
									
								
								r2_analyze.py
									
										
									
									
									
								
							|  | @ -1,14 +1,20 @@ | ||||||
| import r2pipe | import r2pipe | ||||||
| import os | import os | ||||||
| import json | import json | ||||||
|  | from datetime import datetime | ||||||
|  | import subprocess as SP | ||||||
| from tqdm import tqdm | from tqdm import tqdm | ||||||
| from pprint import pprint | from pprint import pprint | ||||||
| import os | import os | ||||||
| import sys | import sys | ||||||
| 
 | 
 | ||||||
| r2cmds = [] | r2cmds = [] | ||||||
| scrap_exe = sys.argv[1] | x64_dbg_script=[] | ||||||
|  | scrap_exe = os.path.abspath(sys.argv[1]) | ||||||
| folder = os.path.abspath(os.path.dirname(scrap_exe)) | folder = os.path.abspath(os.path.dirname(scrap_exe)) | ||||||
|  | script_path=os.path.join(folder, "scrap_dissect.r2") | ||||||
|  | x64_dbg_script_path=os.path.join(folder, "scrap_dissect.x32dbg.txt") | ||||||
|  | json_path=os.path.join(folder, "scrap_dissect.json") | ||||||
| 
 | 
 | ||||||
| assert os.path.isfile(scrap_exe), "File not found!" | assert os.path.isfile(scrap_exe), "File not found!" | ||||||
| r2 = r2pipe.open(scrap_exe) | r2 = r2pipe.open(scrap_exe) | ||||||
|  | @ -20,6 +26,14 @@ target_hashes = { | ||||||
| 
 | 
 | ||||||
| assert file_hashes == target_hashes, "Hash mismatch" | assert file_hashes == target_hashes, "Hash mismatch" | ||||||
| 
 | 
 | ||||||
|  | def x64_dbg_label(addr,name,prefix=None): | ||||||
|  |     global x64_dbg_script | ||||||
|  |     if isinstance(addr,int): | ||||||
|  |         addr=hex(addr) | ||||||
|  |     if prefix: | ||||||
|  |         x64_dbg_script.append(f'lbl {addr},"{prefix}.{name}"') | ||||||
|  |     else: | ||||||
|  |         x64_dbg_script.append(f'lbl {addr},"{name}"') | ||||||
| 
 | 
 | ||||||
| def r2_cmd(cmd): | def r2_cmd(cmd): | ||||||
|     global r2, r2cmds |     global r2, r2cmds | ||||||
|  | @ -38,54 +52,139 @@ def r2_cmdJ(cmd): | ||||||
|     r2cmds.append(cmd) |     r2cmds.append(cmd) | ||||||
|     return r2.cmdJ(cmd) |     return r2.cmdJ(cmd) | ||||||
| 
 | 
 | ||||||
|  | t_start=datetime.today() | ||||||
| 
 | 
 | ||||||
| print("[*] Running 'aaaaa'") | def analysis(full=False): | ||||||
|  |     print("[*] Running analysis") | ||||||
|  |     steps=[] | ||||||
|  |     if full: | ||||||
|  |         steps=[ | ||||||
|  |             "e anal.dataref = true", | ||||||
|  |             # "e anal.esil = true", | ||||||
|  |             "e anal.jmp.after = true", | ||||||
|  |             "e anal.jmp.indir = true", | ||||||
|  |             "e anal.loads = true", | ||||||
|  |             "e anal.pushret = true", | ||||||
|  |             "e anal.refstr = true", | ||||||
|  |             "e anal.strings = true", | ||||||
|  |             "e anal.vinfun = true", | ||||||
|  |             "e asm.anal = true", | ||||||
|  |         ] | ||||||
|  |     steps+=["aaaaa"] | ||||||
|  |     for ac in steps: | ||||||
|  |         print(f"[*] Running '{ac}'") | ||||||
|  |         r2_cmd(f"{ac} 2>NUL") | ||||||
|      |      | ||||||
| r2_cmd("aaaaa") | # 0x7fac20 | ||||||
|  | # 0x7fac19 | ||||||
|  | # 0x7faa4c | ||||||
|  | # 0x7fac1c # activate viewer | ||||||
|  | # 0x84d400 # lib preloaded | ||||||
| 
 | 
 | ||||||
| #0x7fac20 | # 0x413ee0 | ||||||
| #0x7fac19 |  | ||||||
| #0x7faa4c |  | ||||||
| #0x7fac1c # activate viewer |  | ||||||
| #0x84d400 |  | ||||||
| 
 | 
 | ||||||
| #0x413ee0 | # 0x7d2094 refcnt | ||||||
| 
 | 
 | ||||||
| #0x7d2094 refcnt | comments= { | ||||||
| flags = {0x7FE944: ("P_World", 4), 0x79C698: ("Py_Mods", 4),0x852914: ("P_D3D8_Dev",4)} |     0x6113f9:"Check if Window exists" | ||||||
|  | } | ||||||
| 
 | 
 | ||||||
| types = ["struct PyMethodDef {char *ml_name; void *ml_meth; int ml_flags; char *ml_doc;};"] | flags = { | ||||||
|  |     0x7FE944: "P_World",  | ||||||
|  |     0x7FBE4C: "P_Vars",  | ||||||
|  |     0x79C698: "Py_Mods",  | ||||||
|  |     0x852914: "P_D3D8_Dev",  | ||||||
|  |     0x7FCC00: "N_Paks_opened",  | ||||||
|  |     0x7fcbec: "Hash_Index_Size",  | ||||||
|  |     0x7fcbf0: "P_Hash_Index",  | ||||||
|  |     0x7fcc08: "Lst_File",  | ||||||
|  |     0x7fcc04: "Pak_Locked",  | ||||||
|  |     0x7fc1b0: "Pak_Index",  | ||||||
|  |     0x84cb64: "P_ConHandler",  | ||||||
|  |     0x801e10: "num_arrows",  | ||||||
|  |     0x7fac84: "P_Callbacks",  | ||||||
|  |     0x80b2cc: "P_ActClassList",  | ||||||
|  |     0x807a20: "P_Scorer",  | ||||||
|  |     0x80a398: "P_SoundSys",  | ||||||
|  |     0x84cb58: "H_RichEd", | ||||||
|  |     0x84cb4c: "P_HWND_Console", | ||||||
|  |     0x80cb40: "Console_Win_Buffer", | ||||||
|  |     0x84d400: "Lib_preloaded", | ||||||
|  |     0x7fac1c: "Activate_Viewer", | ||||||
|  |     0x8b18f0: "P_Models", | ||||||
|  |     0x8b18f4: "P_Scenes", | ||||||
|  |     0x8b18f8: "P_ActiveModels", | ||||||
|  |     0x803bc0: "net_is_server", | ||||||
|  |     0x8045e4: "net_is_master", | ||||||
|  |     0x8038a8: "net_is_client", | ||||||
|  |     0x7fadd8: "is_python", | ||||||
|  |     0x7fc084: "pak_lock", | ||||||
|  |     0x7fbe7c: "current_language", | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | VMTs = { | ||||||
|  |     0x78d4d8: "Py_entity", | ||||||
|  |     0x78cc6c: "World", | ||||||
|  |     0x78b680: "FilePak_1", | ||||||
|  |     0x78b6a4: "FilePak_2", | ||||||
|  |     0x78b638: "AbstractFile", | ||||||
|  |     0x78b4d8: "App", | ||||||
|  |     0x78b480: "Window", | ||||||
|  |     0x78b5c0: "File", | ||||||
|  |     0x78b65c: "FileMem", | ||||||
|  |     0x78b6d0: "IDevice_1", | ||||||
|  |     0x78b6f4: "IDevice_2", | ||||||
|  |     0x78b6fc: "IDevice_Kb", | ||||||
|  |     0x78b720: "IDevice_Mouse", | ||||||
|  |     0x78b74c: "IDevice_Joy", | ||||||
|  |     0x7933ac: "3d_Gfx", | ||||||
|  |     0x7933a0: "NodeFX", | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | types = [ | ||||||
|  |     "struct PyMethodDef { char *ml_name; void *ml_meth; int ml_flags; char *ml_doc;};", | ||||||
|  |     "struct GameVar { struct GameVar* next; const char* name; const char* desc; uint64_t d_type; void* value; void* def_value; };", | ||||||
|  |     "struct HT_Entry { void* data; const char* key; struct HT_Entry* next;};", | ||||||
|  |     "struct PakEntry { unsigned char* filename; bool locked; void* data; uint32_t seek;};", | ||||||
|  |     "struct HashIndexEntry { uint32_t offset; uint32_t size; uint32_t status; const char* name; struct HashIndexEntry* next; };", | ||||||
|  |     "struct HashIndex { uint32_t size; struct HashIndexEntry** data; };", | ||||||
|  |     "struct HashTableEntry { void* data; const char *key; struct HashTableEntry* next; };", | ||||||
|  |     "struct HashTable { uint32_t size; struct HashTableEntry** data; };", | ||||||
|  | ] | ||||||
| 
 | 
 | ||||||
| func_sigs = { | func_sigs = { | ||||||
|     0x5a8390: "int py_exec(const char* script);", |     0x5A8390: "int py_exec(const char* script);", | ||||||
|     0x5bb9d0: "int PyArg_ParseTuple(void* PyObj, char* format, ...);", |     0x5BB9D0: "int PyArg_ParseTuple(void* PyObj, char* format, ...);", | ||||||
|     0x4134c0: "int write_log(unsigned int color, const char* msg);", |     0x413ee0: "int dbg_log(const char* fmt,...);", | ||||||
|  |     0x4134C0: "int write_log(unsigned int color, const char* msg);", | ||||||
|     0x47C1E0: "int ht_hash_ent_list(const char* str);", |     0x47C1E0: "int ht_hash_ent_list(const char* str);", | ||||||
|     0x404BB0: "int ht_hash_ent(const char* str);", |     0x404BB0: "int ht_hash_ent(const char* str);", | ||||||
|     0x4016f0: "int reg_get_val(const char* value);", |     0x4016F0: "int reg_get_val(const char* value);", | ||||||
|     0x414280: "int prepare_html_log(const char* filename);", |     0x414280: "int prepare_html_log(const char* filename);", | ||||||
|     0x6b1c70: "bool strcmp(const char* s1,const char* s2);", |     0x6597d0: "bool read_ini_entry(void* dest,const char* key, const char* section);", | ||||||
|     0x5A8FB0: "void* Py_InitModule(const char* name,void* methods);", |     0x5A8FB0: "void* Py_InitModule(const char* name,void* methods);", | ||||||
|     0x5E3800: "int fopen_1(const char* filename);", |     0x5E3800: "int fopen_from_pak(const char* filename);", | ||||||
|     0x419950: "int fopen_2(const char* filename);", |     0x419950: "int fopen_2(const char* filename);", | ||||||
|     0x41AB50: "int open_pak(const char* filename, int unk_1,void* unk_ptr);", |     0x41AB50: "int open_pak(const char* filename, int unk_1,void* unk_ptr);", | ||||||
|     0x404460: "int register_c_callback(const char* name,void* func);" |     0x404460: "int register_c_callback(const char* name,void* func);", | ||||||
|     0x414070: "void throw_assertion_2(const char* check,const char* file, unsigned int line);" |     0x414070: "void throw_assertion_2(const char* check,const char* file,const char* date, unsigned int line);", | ||||||
|     0x5FBC50: "void throw_assertion_1(const char* check,const char* file,const char* date, unsigned int line);", |     0x5FBC50: "void throw_assertion_1(const char* check,const char* file, unsigned int line);", | ||||||
|     0x5bc140: "static char* convertsimple1(void *arg, char **p_format, void *p_va);" |     0x5BC140: "static char* convertsimple1(void *arg, char **p_format, void *p_va);", | ||||||
|  |     0x5E3800: "int32_t fopen_from_pak(const char* filename,const char* mode);", | ||||||
|  |     0x5a90f0: "void* Py_BuildValue(const char* format, ...);" | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| functions = { | functions = { | ||||||
|     0x6b1c70: "strcmp", |     0x6B1C70: "strcmp", | ||||||
|     0x5bb9d0: "PyArg_ParseTuple", |     0x5BB9D0: "PyArg_ParseTuple", | ||||||
|     0x5dd510: "init_engine_3d", |     0x5DD510: "init_engine_3d", | ||||||
|     0x401180: "create_window", |     0x401180: "create_window", | ||||||
|     0x401240: "create_main_window", |     0x401240: "create_main_window", | ||||||
|     0x4016f0: "reg_get_val", |     0x4016F0: "reg_get_val", | ||||||
|     0x4134c0: "write_log", |     0x4134C0: "write_log", | ||||||
|     0x414280: "prepare_html_log", |     0x414280: "prepare_html_log", | ||||||
|     0x418220: "get_version_info", |     0x418220: "get_version_info", | ||||||
|     0x4137e0: "write_html_log", |     0x4137E0: "write_html_log", | ||||||
|     0x402190: "handle_console_input", |     0x402190: "handle_console_input", | ||||||
|     0x5F9520: "handle_render_console_input", |     0x5F9520: "handle_render_console_input", | ||||||
|     0x404A50: "find_entity", |     0x404A50: "find_entity", | ||||||
|  | @ -93,9 +192,9 @@ functions = { | ||||||
|     0x404BB0: "ht_hash_ent", |     0x404BB0: "ht_hash_ent", | ||||||
|     0x404460: "register_c_callback", |     0x404460: "register_c_callback", | ||||||
|     0x417470: "load_game", |     0x417470: "load_game", | ||||||
|     0x5E3800: "fopen_1", |     0x5E3800: "fopen_from_pak", | ||||||
|     0x419950: "fopen_2", |     0x5e3500: "fopen", | ||||||
|     0x403370: "debug_init", |     0x403370: "init_debug", | ||||||
|     0x401770: "init", |     0x401770: "init", | ||||||
|     0x4026D0: "init_py", |     0x4026D0: "init_py", | ||||||
|     0x405B40: "init_py_sub", |     0x405B40: "init_py_sub", | ||||||
|  | @ -105,25 +204,105 @@ functions = { | ||||||
|     0x414570: "setup_game_vars", |     0x414570: "setup_game_vars", | ||||||
|     0x5FBC50: "throw_assertion_1", |     0x5FBC50: "throw_assertion_1", | ||||||
|     0x414070: "throw_assertion_2", |     0x414070: "throw_assertion_2", | ||||||
|     0x5F7000: "load_m3d_ini", |     0x5F7000: "read_ini", | ||||||
|     0x650F80: "load_sm3", |     0x650F80: "load_sm3", | ||||||
|     0x6665A0: "load_m3d_1", |     0x6665A0: "load_m3d_1", | ||||||
|     0x666900: "load_m3d_2", |     0x666900: "load_m3d_2", | ||||||
|     0x479B20: "world_constructor", |     0x479B20: "world_constructor", | ||||||
|     0x479B40: "world_init", |     0x479B40: "init_world", | ||||||
|     0x402510: "world_deinit", |     0x402510: "deinit_world", | ||||||
|     0x479870: "make_world", |     0x479870: "make_world", | ||||||
|     0x602a70: "render_frame" |     0x602A70: "render_frame", | ||||||
|  |     0x6B738C: "handle_exception", | ||||||
|  |     0x5B9E70: "py_getattr", | ||||||
|  |     0x413ee0: "dbg_log", | ||||||
|  |     0x5f75e0: "init_d3d", | ||||||
|  |     0x63a2f0: "gdi_draw_line", | ||||||
|  |     0x5e3250: "read_stream", | ||||||
|  |     0x5e3bb0: "read_stream_wrapper", | ||||||
|  |     0x50b9b0: "init_scorer", | ||||||
|  |     0x582e10: "init_action_class_list", | ||||||
|  |     0x528910: "init_sound_sys", | ||||||
|  |     0x5268d0: "try_init_sound_sys", | ||||||
|  |     0x404280: "cPyFunction_set_func", | ||||||
|  |     0x414680: "load_config", | ||||||
|  |     0x414810: "save_config", | ||||||
|  |     0x4f42a0: "close_server_socket", | ||||||
|  |     0x4f4d10: "close_server", | ||||||
|  |     0x4f48e0: "close_client", | ||||||
|  |     0x4f4fb0: "is_server", | ||||||
|  |     0x4f4a10: "is_client", | ||||||
|  |     0x4fac50: "is_master", | ||||||
|  |     0x526910: "close_sound_sys", | ||||||
|  |     0x526520: "shutdown_sound_sys", | ||||||
|  |     0x5dd700: "close_3d_engine", | ||||||
|  |     0x5a7320: "close_window", | ||||||
|  |     0x5dff20: "set_exception_handler", | ||||||
|  |     0x5a7f20: "get_console_wnd", | ||||||
|  |     0x5a73a0: "show_console", | ||||||
|  |     0x666c60: "read_m3d", | ||||||
|  |     0x417df0: "snprintf", | ||||||
|  |     0x5fc930: "printf", | ||||||
|  |     0x6597d0: "read_ini_entry", | ||||||
|  |     0x5fc0a0: "engine_debug_log", | ||||||
|  |     0x5a7440: "create_console_window", | ||||||
|  |     0x6114e0: "setup_window", | ||||||
|  |     0x404420: "clear_functions", | ||||||
|  |     0x405ca0: "close_py_subsys", | ||||||
|  |     0x50bcb0: "close_scorer", | ||||||
|  |     0x479b20: "close_world", | ||||||
|  |     0x582e70: "close_action_class", | ||||||
|  |     0x50b6a0: "get_scorer", | ||||||
|  |     0x50ea20: "scorer_parse_type", | ||||||
|  |     0x636580: "list_models", | ||||||
|  |     0x5a90f0: "Py_BuildValue", | ||||||
|  |     0x41c5a0: "has_lst_file", | ||||||
|  |     0x5a8e90: "py_error", | ||||||
|  |     0x5a9890: "get_module_dict", | ||||||
|  |     0x5c7bb0: "get_current_thread", | ||||||
|  |     0x5aa140: "preload_lib", | ||||||
|  |     0x413c10: "sprintf", | ||||||
|  |     0x405850: "check_is_python", | ||||||
|  |     0x47bf90: "setup_ent_list", | ||||||
|  |     0x474f80: "ent_list_get_set", | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | # 0x853954 ??? some obj ptr | ||||||
|  | 
 | ||||||
|  | # [0x7fbe98] | ||||||
|  | 
 | ||||||
|  | # [0x853954]+0x2a3cc debug flag, checked in 0x006113a0 called from 0x005dd5ea | ||||||
|  | cfg=""" | ||||||
|  | e asm.cmt.right = true | ||||||
|  | e cmd.stack = true | ||||||
|  | e scr.utf8 = true | ||||||
|  | e asm.describe = false | ||||||
|  | e graph.cmtright = true | ||||||
|  | e cfg.sandbox = false | ||||||
|  | e cfg.newtab = true | ||||||
|  | e cfg.fortunes.type = tips,fun,creepy,nsfw | ||||||
|  | e dbg.status = true | ||||||
|  | e pdb.autoload = true | ||||||
|  | e emu.str = true | ||||||
|  | e asm.flags.offset = true | ||||||
|  | """.strip().splitlines() | ||||||
|  | for line in cfg: | ||||||
|  |     r2_cmd(line) | ||||||
|  | 
 | ||||||
|  | analysis(False) | ||||||
|  | 
 | ||||||
|  | for addr,comment in comments.items(): | ||||||
|  |     r2_cmd(f"CC {comment} @ {hex(addr)}") | ||||||
|  | 
 | ||||||
| for t in types: | for t in types: | ||||||
|     r2_cmd(f'"td {t}"') |     r2_cmd(f'"td {t}"') | ||||||
| 
 | 
 | ||||||
| for addr, args in flags.items(): | for addr, name in flags.items(): | ||||||
|     name, size = args |     x64_dbg_label(addr,name,"loc") | ||||||
|     r2_cmd(f"f loc.{name} {size} {hex(addr)}") |     r2_cmd(f"f loc.{name} 4 {hex(addr)}") | ||||||
| 
 | 
 | ||||||
| for addr, name in functions.items(): | for addr, name in functions.items(): | ||||||
|  |     x64_dbg_label(addr,name,"fcn") | ||||||
|     r2_cmd(f"afr fcn.{name} {hex(addr)}") |     r2_cmd(f"afr fcn.{name} {hex(addr)}") | ||||||
|     if addr in func_sigs: |     if addr in func_sigs: | ||||||
|         r2_cmd(f'"afs {func_sigs[addr]}" @{hex(addr)}') |         r2_cmd(f'"afs {func_sigs[addr]}" @{hex(addr)}') | ||||||
|  | @ -135,9 +314,13 @@ def vtables(): | ||||||
|     vtables = r2_cmdJ("avj") |     vtables = r2_cmdJ("avj") | ||||||
|     for c in tqdm(vtables, ascii=True): |     for c in tqdm(vtables, ascii=True): | ||||||
|         methods = [] |         methods = [] | ||||||
|         for m in tqdm(c.methods, ascii=True, leave=False): |         name=VMTs.get(c.offset,f"{c.offset:08x}") | ||||||
|  |         x64_dbg_label(c.offset,name,"vmt") | ||||||
|  |         r2_cmd(f"f vmt.{name} 4 {hex(c.offset)}") | ||||||
|  |         for idx,m in enumerate(tqdm(c.methods, ascii=True, leave=False)): | ||||||
|             methods.append(hex(m.offset)) |             methods.append(hex(m.offset)) | ||||||
|             r2.cmd(f"afr @{hex(m.offset)} 2>{os.devnull}") |             x64_dbg_label(m.offset,f"{name}.{idx}","fcn.vmt") | ||||||
|  |             r2_cmd(f"afr fcn.vmt.{name}.{idx} {hex(m.offset)} 2>NUL") | ||||||
|         ret[hex(c.offset)] = methods |         ret[hex(c.offset)] = methods | ||||||
|     return ret |     return ret | ||||||
| 
 | 
 | ||||||
|  | @ -147,60 +330,71 @@ def c_callbacks(): | ||||||
|     funcs = {} |     funcs = {} | ||||||
|     res = r2_cmd("/r fcn.register_c_callback ~CALL[1]").splitlines() |     res = r2_cmd("/r fcn.register_c_callback ~CALL[1]").splitlines() | ||||||
|     for addr in tqdm(res, ascii=True): |     for addr in tqdm(res, ascii=True): | ||||||
|         func, name = r2_cmdJ(f"s {addr};so -3;pdj 2") |         r2_cmd(f"s {addr}") | ||||||
|  |         r2_cmd(f"so -3") | ||||||
|  |         func, name = r2_cmdJ(f"pdj 2") | ||||||
|         func = func.refs[0].addr |         func = func.refs[0].addr | ||||||
|         name = r2_cmd(f"psz @{hex(name.refs[0].addr)}").strip() |         name = r2_cmd(f"psz @{hex(name.refs[0].addr)}").strip() | ||||||
|         r2_cmd(f"afr fcn.CB_{name} {hex(func)} 2>NUL") |         r2_cmd(f"afr fcn.callbacks.{name} {hex(func)} 2>NUL") | ||||||
|  |         x64_dbg_label(func,f"{name}","fcn.callbacks") | ||||||
|         funcs[name] = hex(func) |         funcs[name] = hex(func) | ||||||
|     return funcs |     return funcs | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| def assertions(): | def assertions(): | ||||||
|     assertions = {} |     assertions = {} | ||||||
|     for (n_args,a_addr) in [(4,"fcn.throw_assertion_1"), (3,"fcn.throw_assertion_2")]: |     for (n_args, a_addr) in [ | ||||||
|  |         (4, "fcn.throw_assertion_1"), | ||||||
|  |         (3, "fcn.throw_assertion_2"), | ||||||
|  |     ]: | ||||||
|         print(f"[*] Parsing C assertions for {a_addr}") |         print(f"[*] Parsing C assertions for {a_addr}") | ||||||
|         res = r2_cmd(f"/r {a_addr} ~CALL[1]").splitlines() |         res = r2_cmd(f"/r {a_addr} ~CALL[1]").splitlines() | ||||||
|         print() |         print() | ||||||
|         for line in tqdm(res, ascii=True): |         for line in tqdm(res, ascii=True): | ||||||
|             addr = line.strip() |             addr = line.strip() | ||||||
|             dis=r2_cmdJ(f"s {addr};so -{n_args};pij {n_args}")  # seek and print disassembly |             r2_cmd(f"s {addr}") | ||||||
|             if n_args==4: |             r2_cmd(f"so -{n_args}") | ||||||
|  |             dis=r2_cmdJ(f"pij {n_args}") | ||||||
|  |             if n_args == 4: | ||||||
|                 file, msg, date, line = dis |                 file, msg, date, line = dis | ||||||
|             elif n_args==3: |             elif n_args == 3: | ||||||
|                 date=None |                 date = None | ||||||
|                 file, msg, line = dis |                 file, msg, line = dis | ||||||
|             try: |             try: | ||||||
|                 file = r2_cmd(f"psz @{file.refs[0].addr}").strip() |                 file = r2_cmd(f"psz @{file.refs[0].addr}").strip() | ||||||
|                 msg = r2_cmd(f"psz @{msg.refs[0].addr}").strip() |                 msg = r2_cmd(f"psz @{msg.refs[0].addr}").strip() | ||||||
|                 if date: |                 if date: | ||||||
|                     r2_cmd(f"psz @{date.refs[0].addr}").strip() |                     date = r2_cmd(f"psz @{date.refs[0].addr}").strip() | ||||||
|                 line=line.val |                 line = line.val | ||||||
|                 file=file.replace("\\\\", "\\") |                 file = file.replace("\\\\", "\\") | ||||||
|                 os.path.isabs(file): |                 assertions.setdefault(file, []) | ||||||
|                     file = os.path.abspath(file) |                 assertions[file].append( | ||||||
|                 assertions.setdefault(path, []) |                     {"line": line, "date": date, "addr": addr, "msg": msg} | ||||||
|                 assertions[path].append({'line':line,'date':date,'addr':addr,'msg': msg}) |                 ) | ||||||
|             except: |             except: | ||||||
|                 pass |                 pass | ||||||
|     for path in assertions: |     for path in assertions: | ||||||
|         assertions[path].sort(key=lambda v:v['line']) |         assertions[path].sort(key=lambda v: v["line"]) | ||||||
|     return assertions |     return assertions | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
| def bb_refs(addr): | def bb_refs(addr): | ||||||
|     ret={} |     ret = {} | ||||||
|     res = r2_cmd(f"/r {addr} ~fcn[0,1]").splitlines() |     res = r2_cmd(f"/r {addr} ~fcn[0,1]").splitlines() | ||||||
|     print() |     print() | ||||||
|     for ent in res: |     for ent in res: | ||||||
|         func,hit=ent.split() |         func, hit = ent.split() | ||||||
|         ret[hit]={'asm':[],'func':func} |         ret[hit] = {"asm": [], "func": func} | ||||||
|         for ins in r2_cmdJ(f"pdbj @{hit}"): |         for ins in r2_cmdJ(f"pdbj @{hit}"): | ||||||
|             ret[hit]['asm'].append(ins.disasm) |             ret[hit]["asm"].append(ins.disasm) | ||||||
|     return ret |     return ret | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
| def world(): | def world(): | ||||||
|     print("[*] Parsing World offsets") |     print("[*] Parsing World offsets") | ||||||
|     return bb_refs("loc.P_World") |     return bb_refs("loc.P_World") | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
| def render(): | def render(): | ||||||
|     print("[*] Parsing D3D_Device offsets") |     print("[*] Parsing D3D_Device offsets") | ||||||
|     return bb_refs("loc.P_D3D8_Dev") |     return bb_refs("loc.P_D3D8_Dev") | ||||||
|  | @ -212,7 +406,9 @@ def py_mods(): | ||||||
|     print() |     print() | ||||||
|     py_mods = {} |     py_mods = {} | ||||||
|     for call_loc in tqdm(res, ascii=True): |     for call_loc in tqdm(res, ascii=True): | ||||||
|         args = r2_cmdJ(f"s {call_loc};so -3;pdj 3") |         r2_cmd(f"s {call_loc}") | ||||||
|  |         r2_cmd(f"so -3") | ||||||
|  |         args = r2_cmdJ("pdj 3") | ||||||
|         refs = [] |         refs = [] | ||||||
|         if not all([arg.type == "push" for arg in args]): |         if not all([arg.type == "push" for arg in args]): | ||||||
|             continue |             continue | ||||||
|  | @ -222,7 +418,8 @@ def py_mods(): | ||||||
|         doc = r2_cmd(f"psz @{doc}").strip() |         doc = r2_cmd(f"psz @{doc}").strip() | ||||||
|         name = r2_cmd(f"psz @{name}").strip() |         name = r2_cmd(f"psz @{name}").strip() | ||||||
|         r2_cmd(f"s {methods}") |         r2_cmd(f"s {methods}") | ||||||
|         r2_cmd(f"f loc.py.MethodDef_{name} 4 {methods}") |         r2_cmd(f"f py.{name} 4 {methods}") | ||||||
|  |         x64_dbg_label(methods,f"{name}","py") | ||||||
|         py_mods[name] = {"methods_addr": methods, "doc": doc, "methods": {}} |         py_mods[name] = {"methods_addr": methods, "doc": doc, "methods": {}} | ||||||
|         while True: |         while True: | ||||||
|             m_name, m_func, _, m_doc = [v.value for v in r2_cmdJ(f"pfj xxxx")] |             m_name, m_func, _, m_doc = [v.value for v in r2_cmdJ(f"pfj xxxx")] | ||||||
|  | @ -230,16 +427,21 @@ def py_mods(): | ||||||
|                 break |                 break | ||||||
|             m_name, m_func, m_doc = map(hex, (m_name, m_func, m_doc)) |             m_name, m_func, m_doc = map(hex, (m_name, m_func, m_doc)) | ||||||
|             m_name = r2_cmd(f"psz @{m_name}").strip() |             m_name = r2_cmd(f"psz @{m_name}").strip() | ||||||
|             r2_cmd(f"f Py_{name}_{m_name}_doc 4 {m_doc}") |             r2_cmd(f"f py.{name}.{m_name}.__doc__ 4 {m_doc}") | ||||||
|             m_doc = r2_cmd(f"psz @{m_doc}").strip() |             if int(m_doc,16)!=0: | ||||||
|  |                 x64_dbg_label(m_doc,f"{name}.{m_name}.__doc__","py") | ||||||
|  |                 m_doc = r2_cmd(f"psz @{m_doc}").strip() | ||||||
|  |             else: | ||||||
|  |                 m_doc=None | ||||||
|             py_mods[name]["methods"][m_name] = {"addr": m_func, "doc": m_doc} |             py_mods[name]["methods"][m_name] = {"addr": m_func, "doc": m_doc} | ||||||
|             r2_cmd(f"afr fcn.py.{name}.{m_name} {m_func} 2>NUL") |             r2_cmd(f"afr py.{name}.{m_name} {m_func} 2>NUL") | ||||||
|  |             x64_dbg_label(m_func,f"{name}.{m_name}","fcn.py") | ||||||
|             r2_cmd("s +16") |             r2_cmd("s +16") | ||||||
|     return py_mods |     return py_mods | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| def game_vars(): | def game_vars(): | ||||||
|     ret={} |     ret = {} | ||||||
|     print("[*] Parsing Game variables") |     print("[*] Parsing Game variables") | ||||||
|     res = r2_cmd("/r fcn.setup_game_vars ~CALL[1]").splitlines() |     res = r2_cmd("/r fcn.setup_game_vars ~CALL[1]").splitlines() | ||||||
|     print() |     print() | ||||||
|  | @ -249,27 +451,28 @@ def game_vars(): | ||||||
|         args = r2_cmd("pdj -5")  # seek and print disassembly |         args = r2_cmd("pdj -5")  # seek and print disassembly | ||||||
|         if not args: |         if not args: | ||||||
|             continue |             continue | ||||||
|         args=json.loads(args) |         args = json.loads(args) | ||||||
|         args_a = [] |         args_a = [] | ||||||
|         push_cnt=0 |         push_cnt = 0 | ||||||
|         for arg in args[::-1]: |         for arg in args[::-1]: | ||||||
|             if arg['type'] not in ["push","mov"]: |             if arg["type"] not in ["push", "mov"]: | ||||||
|                 continue |                 continue | ||||||
|             if arg['type']=="push": |             if arg["type"] == "push": | ||||||
|                 push_cnt+=1 |                 push_cnt += 1 | ||||||
|             args_a.append(arg) |             args_a.append(arg) | ||||||
|             if push_cnt==3: |             if push_cnt == 3: | ||||||
|                 break |                 break | ||||||
|         if len(args_a)!=4: |         if len(args_a) != 4: | ||||||
|             continue |             continue | ||||||
|         if not all(['val' in v for v in args_a]): |         if not all(["val" in v for v in args_a]): | ||||||
|             continue |             continue | ||||||
|         addr,name,_,desc=[v['val'] for v in args_a] |         addr, name, _, desc = [v["val"] for v in args_a] | ||||||
|         name=r2_cmd(f"psz @{hex(name)}").strip() |         name = r2_cmd(f"psz @{hex(name)}").strip() | ||||||
|         desc=r2_cmd(f"psz @{hex(desc)}").strip() |         desc = r2_cmd(f"psz @{hex(desc)}").strip() | ||||||
|         addr=hex(addr) |         addr = hex(addr) | ||||||
|         r2_cmd(f"f var_{name} 4 {addr}") |         r2_cmd(f"f loc.gvar.{name} 4 {addr}") | ||||||
|         ret[addr]={'name':name,'desc':desc} |         x64_dbg_label(addr,f"{name}","loc.gvar") | ||||||
|  |         ret[addr] = {"name": name, "desc": desc} | ||||||
|     return ret |     return ret | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | @ -283,23 +486,45 @@ ret = dict( | ||||||
|     render=render(), |     render=render(), | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| r2_cmd("aaaaa") # Propagate type infos | analysis(True) | ||||||
| 
 | 
 | ||||||
| with open(os.path.join(folder, "Scrap_dissect.json"), "w") as of: | with open(json_path, "w") as of: | ||||||
|     json.dump(ret, of, indent=4) |     json.dump(ret, of, indent=4) | ||||||
| print("[+] Wrote Scrap_dissect.json") |  | ||||||
| 
 | 
 | ||||||
| with open(os.path.join(folder, "Scrap_dissect.r2"), "w") as of: | print("[+] Wrote scrap_dissect.json") | ||||||
|  | 
 | ||||||
|  | with open(x64_dbg_script_path,"w") as of: | ||||||
|  |     of.write("\n".join(x64_dbg_script)) | ||||||
|  | 
 | ||||||
|  | print("[+] Wrote scrap_dissect.x32dbg.txt") | ||||||
|  | 
 | ||||||
|  | with open(script_path, "w") as of: | ||||||
|     wcmds = [] |     wcmds = [] | ||||||
|     for cmd in r2cmds: |     for cmd in r2cmds: | ||||||
|         for start in ["f ", "afr ", "aaaaa","afs"]: |         record=True | ||||||
|  |         for start in ["p","/","s"]: | ||||||
|             if cmd.strip('"').startswith(start): |             if cmd.strip('"').startswith(start): | ||||||
|                 wcmds.append(cmd) |                 record=False | ||||||
|                 break |         if record: | ||||||
|  |             wcmds.append(cmd) | ||||||
|     of.write("\n".join(wcmds)) |     of.write("\n".join(wcmds)) | ||||||
| 
 | 
 | ||||||
| print("[+] Wrote Scrap_dissect.r2") | print("[+] Wrote scrap_dissect.r2") | ||||||
| print(f"[*] Done, now cd to '{folder}'...") | 
 | ||||||
| print( | r2.quit() | ||||||
|     "[*] ...and run 'r2 -i Scrap_dissect.r2 Scrap.exe' to load the parsed infos into radare2" | 
 | ||||||
| ) | def start_program(cmdl,**kwargs): | ||||||
|  |     if os.name=='nt': | ||||||
|  |         return SP.Popen(['cmd','/c','start']+cmdl,**kwargs) | ||||||
|  |     else: | ||||||
|  |         return SP.Popen(cmdl,**kwargs) | ||||||
|  | 
 | ||||||
|  | print("[+] Analysis took:",datetime.today()-t_start) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | print("[+] Executing Cutter") | ||||||
|  | try: | ||||||
|  |     start_program(['cutter','-A','0','-i',script_path,scrap_exe],cwd=folder,shell=False) | ||||||
|  | except FileNotFoundError: | ||||||
|  |     print("[-] cutter not installed, falling back to r2") | ||||||
|  |     start_program(['r2','-i',script_path,scrap_exe],cwd=folder,shell=False) | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue