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)
|
||||||
|
|
||||||
|
@ -50,4 +56,127 @@ 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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -258,118 +293,4 @@ vector<string> split(string str, char sep) {
|
||||||
if (part != "")
|
if (part != "")
|
||||||
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))
|
||||||
|
|
||||||
|
|
409
r2_analyze.py
409
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")
|
||||||
|
|
||||||
|
# 0x7fac20
|
||||||
|
# 0x7fac19
|
||||||
|
# 0x7faa4c
|
||||||
|
# 0x7fac1c # activate viewer
|
||||||
|
# 0x84d400 # lib preloaded
|
||||||
|
|
||||||
r2_cmd("aaaaa")
|
# 0x413ee0
|
||||||
|
|
||||||
#0x7fac20
|
# 0x7d2094 refcnt
|
||||||
#0x7fac19
|
|
||||||
#0x7faa4c
|
|
||||||
#0x7fac1c # activate viewer
|
|
||||||
#0x84d400
|
|
||||||
|
|
||||||
#0x413ee0
|
comments= {
|
||||||
|
0x6113f9:"Check if Window exists"
|
||||||
|
}
|
||||||
|
|
||||||
#0x7d2094 refcnt
|
flags = {
|
||||||
flags = {0x7FE944: ("P_World", 4), 0x79C698: ("Py_Mods", 4),0x852914: ("P_D3D8_Dev",4)}
|
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",
|
||||||
|
}
|
||||||
|
|
||||||
types = ["struct PyMethodDef {char *ml_name; void *ml_meth; int ml_flags; char *ml_doc;};"]
|
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…
Reference in a new issue