forked from ReScrap/ScrapHacks
		
	Code cleanup
This commit is contained in:
		
							parent
							
								
									bef8fcbaaa
								
							
						
					
					
						commit
						ffbcc30427
					
				
					 14 changed files with 328 additions and 288 deletions
				
			
		
							
								
								
									
										2
									
								
								.vscode/settings.json
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.vscode/settings.json
									
										
									
									
										vendored
									
									
								
							|  | @ -1,6 +1,6 @@ | ||||||
| { | { | ||||||
|     "spellright.language": [ |     "spellright.language": [ | ||||||
|         "de" |         "en" | ||||||
|     ], |     ], | ||||||
|     "spellright.documentTypes": [ |     "spellright.documentTypes": [ | ||||||
|         "markdown", |         "markdown", | ||||||
|  |  | ||||||
							
								
								
									
										40
									
								
								NOTES.md
									
										
									
									
									
								
							
							
						
						
									
										40
									
								
								NOTES.md
									
										
									
									
									
								
							|  | @ -2,7 +2,7 @@ | ||||||
| - Engine: ScrapEngine | - Engine: ScrapEngine | ||||||
| - Ingame Scripting Language: Python 1.5.2 | - Ingame Scripting Language: Python 1.5.2 | ||||||
| 
 | 
 | ||||||
| # Ingame-Console (Ctrl+\^) (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 | ||||||
|  | @ -14,7 +14,7 @@ | ||||||
| # External Console (Scenegraph Debugging?) (Handler@0x5f9520): | # External Console (Scenegraph Debugging?) (Handler@0x5f9520): | ||||||
| * `listar luces` | * `listar luces` | ||||||
| * `listar` | * `listar` | ||||||
| * `arbol` (Patch Scrap.exe@offset 0x314bc0 replace 0x20 with 0x00 (or just type `arbol ` with the space at the end)) | * `arbol` (Patch Scrap.exe@offset 0x314bc9 replace 0x20 with 0x00 (or just type `arbol ` with the space at the end)) | ||||||
| * `mem` | * `mem` | ||||||
| * `ver uniones` | * `ver uniones` | ||||||
| * Easter Eggs: | * Easter Eggs: | ||||||
|  | @ -23,27 +23,29 @@ | ||||||
|  - `capullo` |  - `capullo` | ||||||
| 
 | 
 | ||||||
| # Python Stuff | # Python Stuff | ||||||
| - Modules List @ 0x0079C698 (char* to Module Name followed by Pointer to Init Function) | - Modules List @ 0x79C698 (Module Name as `char*`  followed by Pointer to Init Function) | ||||||
| - InitPyMod @ 0x005A8FB0  | - InitPyMod @ 0x5A8FB0 | ||||||
| - PyExec @ 0x005A8390 | - PyExec @ 0x5A8390 | ||||||
| 
 | 
 | ||||||
| ## m3d.ini loader @0x05f7000 | ## m3d.ini loader @ 0x05f7000 | ||||||
| 
 | 
 | ||||||
| ## SM3 Secene Loader @ 0x650f80 (?) | ## SM3 Scene Loader @ 0x650f80 (?) | ||||||
| 
 | 
 | ||||||
| ## M3D File Loader @ 0x6665a0 (??) | ## M3D File Loader @ 0x6665a0 (??) | ||||||
| 
 | 
 | ||||||
| ## *.packed File Format: | ## *.packed File Format: | ||||||
|     Header: | ``` | ||||||
|         "BFPK\0\0\0\0" | Header: | ||||||
|         Int32ul: number of files |     "BFPK\0\0\0\0" | ||||||
|         for each file: |     Int32ul: number of files | ||||||
|             Int32ul: path length |     for each file: | ||||||
|             String: path |         Int32ul: path length | ||||||
|             Int32ul: size |         String: path | ||||||
|             Int32ul: offset in file |         Int32ul: size | ||||||
|  |         Int32ul: offset in file | ||||||
|  | ``` | ||||||
| 
 | 
 | ||||||
| ## Loading Custom Content | ## 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 | ||||||
| 
 | 
 | ||||||
|  | @ -54,9 +56,9 @@ | ||||||
| 
 | 
 | ||||||
| # How to enable External Console: | # How to enable External Console: | ||||||
| 1. exctract `Data.packed` | 1. exctract `Data.packed` | ||||||
| 2. in m3d.ini uncomment "ConsolaWnd" (GUI Console) or "ConsolaTxt" (Text Console) and set the value to "SI" | 2. in m3d.ini uncomment (remove `;`) "ConsolaWnd" (GUI Console) or "ConsolaTxt" (Text Console) and set the value to "SI" | ||||||
| 3. repack "Data.packed" | 3. repack "Data.packed" | ||||||
| or Use a custom Content Pack | 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 load your own Python Modules | ||||||
|  |  | ||||||
							
								
								
									
										16
									
								
								README.md
									
										
									
									
									
								
							
							
						
						
									
										16
									
								
								README.md
									
										
									
									
									
								
							|  | @ -4,20 +4,26 @@ | ||||||
| * `parse_save.py`: Dumps information extracted from Save file | * `parse_save.py`: Dumps information extracted from Save file | ||||||
| * `scrapper.py`: Extractor and Repacker for *.packed files, needs the `construct` and `tqdm` python modules and python 3.x | * `scrapper.py`: Extractor and Repacker for *.packed files, needs the `construct` and `tqdm` python modules and python 3.x | ||||||
|  - Run `scrapper.py -h` for help |  - Run `scrapper.py -h` for help | ||||||
| * `lib/dbg.py`: general Script for poking around  inside the game's scripting system | * `lib/dbg.py`: general Script for poking around inside the game's scripting system | ||||||
|  - Run `import dbg` inside the Game's Console, |  - Run `import dbg` inside the Game's Console, | ||||||
|   this will load all builtin modules and enable godmode |   this will load all builtin modules and enable godmode | ||||||
|  - The dbg module also enables writing to the ingame console using `print <var>` |  - The dbg module also enables writing to the ingame console using `print <var>` | ||||||
|   and defines two global functions s_write() and e_write() for writing to the Ingame Console's Stdout and Stderr Stream |   and defines two global functions s_write() and e_write() for writing to the Ingame Console's Stdout and Stderr Stream | ||||||
|  - `dbg.menu()` Displays the Game's built in Debug Menu (you can't exit it though) |  - `dbg.menu()` Displays the Game's built in Debug Menu (doesn't work properly) | ||||||
|  - `dbg.enable_all_conv()` allows you to "overwrite" any character, even if they are protected/invulnerable |  - `dbg.enable_all_conv()` allows you to "overwrite" any character, even if they are protected/invulnerable | ||||||
|  - `dbg.become(name)` allows you to transform into any character |  - `dbg.become(name)` allows you to transform into any character | ||||||
|  - `dbg.helplib()` generates a file `helplib.txt` in the Game's folder containing all available Documentation for all available classes and functions |  - `dbg.helplib()` generates a file `helplib.txt` in the Game's folder containing all available Documentation for all available classes and functions | ||||||
|  - `dbg.settrace()` Logs all Python function calls together with their arguments into a  |  - `dbg.settrace()` Logs all Python function calls together with their arguments into a  `dbg.txt` file inside the Game's folder | ||||||
|  - `dbg.txt` file inside the Game's folder |  | ||||||
| 
 | 
 | ||||||
| ## [ScrapHacks](ScrapHacks/README.md) | ## [ScrapHacks](ScrapHacks/README.md) | ||||||
| 
 | 
 | ||||||
| WIP Memory hacking library | WIP Memory hacking library | ||||||
| 
 | 
 | ||||||
| ## [Notes](NOTES.md) | ## [Notes](NOTES.md) | ||||||
|  | 
 | ||||||
|  | # Tools used: | ||||||
|  | 
 | ||||||
|  | - [Python 3](https://python.org/) + [Construct](https://construct.readthedocs.io/en/latest/) | ||||||
|  | - [IDA](https://www.hex-rays.com/products/ida/index.shtml) and [x32dbg](https://x64dbg.com/#start) | ||||||
|  | - [Reclass.NET](https://github.com/ReClassNET/ReClass.NET) | ||||||
|  | - [HxD](https://mh-nexus.de/en/hxd/) | ||||||
|  |  | ||||||
|  | @ -230,13 +230,8 @@ int main(int argc, char *argv[]) | ||||||
| 	{ | 	{ | ||||||
| 		Sleep(100); | 		Sleep(100); | ||||||
| 		GetWindowThreadProcessId(FindWindowA("ScrapClass", NULL), &PID); | 		GetWindowThreadProcessId(FindWindowA("ScrapClass", NULL), &PID); | ||||||
| 		if (PID) |  | ||||||
| 		{ |  | ||||||
| 			cout << "[+] Found PID: " << PID << endl; |  | ||||||
| 			cout << "[*] Sleeping 10 seconds to wait for it to fully load" << endl; |  | ||||||
| 			Sleep(10000); |  | ||||||
| 		} |  | ||||||
| 	} | 	} | ||||||
|  | 	cout << "[+] Found PID: " << PID << endl; | ||||||
| 	InjectDll(PID); | 	InjectDll(PID); | ||||||
| 	cout << "[*] Done!" << endl; | 	cout << "[*] Done!" << endl; | ||||||
| 	return 0; | 	return 0; | ||||||
|  |  | ||||||
|  | @ -5,6 +5,11 @@ | ||||||
| 0. Build Project | 0. Build Project | ||||||
| 1. Run Injector `.\Injector.exe` | 1. Run Injector `.\Injector.exe` | ||||||
| 2. Run Game | 2. Run Game | ||||||
| 3. Wait ~10 Seconds for game to load and Injector to works its magic |  | ||||||
| 
 |  | ||||||
| 
 | 
 | ||||||
|  | ``` | ||||||
|  | [F3 ] Unload ScrapHacks | ||||||
|  | [F7 ] Set Money to 0x7fffffff | ||||||
|  | [F8 ] Dump python modules to console | ||||||
|  | [F10] Enable python tracing | ||||||
|  | [ F ] "Handbrake" (*Will* crash the game after some time!) | ||||||
|  | ``` | ||||||
							
								
								
									
										61
									
								
								ScrapHacks/ScrapHack/Py_Utils.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										61
									
								
								ScrapHacks/ScrapHack/Py_Utils.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,61 @@ | ||||||
|  | #pragma once | ||||||
|  | #include "Structures.h" | ||||||
|  | 
 | ||||||
|  | map<string, Module> Py; | ||||||
|  | 
 | ||||||
|  | PyMethodDef *find_method_table(uintptr_t base, uintptr_t needle) | ||||||
|  | { | ||||||
|  | 	for (ptrdiff_t offset = 0; offset < 64; ++offset) | ||||||
|  | 	{ | ||||||
|  | 		uintptr_t instr = reinterpret_cast<uintptr_t *>(base + offset)[0]; | ||||||
|  | 		if (instr == needle) { | ||||||
|  | 			uintptr_t mod_addr = reinterpret_cast<uintptr_t *>(base + offset - (1 + 4))[0]; | ||||||
|  | 			return reinterpret_cast<PyMethodDef*>(mod_addr); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return reinterpret_cast<PyMethodDef *>(0); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | map<string, Module> get_modules(uintptr_t base) | ||||||
|  | { | ||||||
|  | 	map<string, Module> Py; | ||||||
|  | 	PyMod *modules = reinterpret_cast<PyMod *>(base); | ||||||
|  | 	for (size_t i = 0; modules[i].init_func != NULL; i++) | ||||||
|  | 	{ | ||||||
|  | 		Module mod; | ||||||
|  | 		mod.mod = &modules[i]; | ||||||
|  | 		PyMethodDef *method_table = find_method_table((size_t)modules[i].init_func, reinterpret_cast<uintptr_t>(modules[i].name)); | ||||||
|  | 		for (size_t j = 0; method_table != NULL && method_table[j].ml_name != NULL; j++) | ||||||
|  | 		{ | ||||||
|  | 			mod.methods[method_table[j].ml_name] = method_table[j]; | ||||||
|  | 		} | ||||||
|  | 		Py[mod.mod->name] = mod; | ||||||
|  | 	} | ||||||
|  | 	return Py; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void *get_py(const char *mod, const char *meth) | ||||||
|  | { | ||||||
|  | 	try | ||||||
|  | 	{ | ||||||
|  | 		return Py.at(mod).methods.at(meth).ml_meth; | ||||||
|  | 	} | ||||||
|  | 	catch (out_of_range) | ||||||
|  | 	{ | ||||||
|  | 		return NULL; | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void inject(const char *mod, const char *meth, void *detour) | ||||||
|  | { | ||||||
|  | 	try | ||||||
|  | 	{ | ||||||
|  | 		void *orig = get_py(mod, meth); | ||||||
|  | 		Py.at(mod).methods.at(meth).ml_meth = detour; | ||||||
|  | 		cout << mod << "." << meth << ": " << orig << " -> " << detour << endl; | ||||||
|  | 	} | ||||||
|  | 	catch (out_of_range) | ||||||
|  | 	{ | ||||||
|  | 		cout << mod << "." << meth << " not found!" << endl; | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | @ -3,251 +3,35 @@ | ||||||
| #include <sstream> | #include <sstream> | ||||||
| #include <vector> | #include <vector> | ||||||
| #include <map> | #include <map> | ||||||
| #include <deque> |  | ||||||
| #include <iomanip> | #include <iomanip> | ||||||
| #include <iostream> | #include <iostream> | ||||||
| #include <Windows.h> | #include <Windows.h> | ||||||
| #include <TlHelp32.h> | #include <TlHelp32.h> | ||||||
| #include "Scrapland.h" | //#include <D3d8.h>
 | ||||||
| 
 | 
 | ||||||
| #define DLL_EXPORT extern "C" __declspec(dllexport) |  | ||||||
| 
 |  | ||||||
| struct Module; |  | ||||||
| using namespace std; | using namespace std; | ||||||
| 
 | 
 | ||||||
| map<string, Module> Py; | #include "Scrapland.h" | ||||||
|  | #include "Util.h" | ||||||
|  | #include "Structures.h" | ||||||
|  | #include "Py_Utils.h" | ||||||
|  | 
 | ||||||
|  | HMODULE hD3D8Dll = 0; | ||||||
| 
 | 
 | ||||||
| bool initialized = false; | bool initialized = false; | ||||||
| bool running = true; | bool running = true; | ||||||
| HMODULE mod = 0; | HMODULE mod = 0; | ||||||
| 
 | 
 | ||||||
| string GetLastErrorAsString() |  | ||||||
| { |  | ||||||
| 	DWORD errorMessageID = GetLastError(); |  | ||||||
| 	if (errorMessageID == 0) |  | ||||||
| 		return "No error"; |  | ||||||
| 	LPSTR messageBuffer = NULL; |  | ||||||
| 	size_t m_size = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, |  | ||||||
| 								   NULL, errorMessageID, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&messageBuffer, 0, NULL); |  | ||||||
| 	string message(messageBuffer, m_size); |  | ||||||
| 	LocalFree(messageBuffer); |  | ||||||
| 	if (!message.empty() && message[message.length() - 1] == '\n') |  | ||||||
| 	{ |  | ||||||
| 		message.erase(message.length() - 1); |  | ||||||
| 	} |  | ||||||
| 	return message; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void SetupStreams() |  | ||||||
| { |  | ||||||
| 	FILE *fIn; |  | ||||||
| 	FILE *fOut; |  | ||||||
| 	freopen_s(&fIn, "conin$", "r", stdin); |  | ||||||
| 	freopen_s(&fOut, "conout$", "w", stdout); |  | ||||||
| 	freopen_s(&fOut, "conout$", "w", stderr); |  | ||||||
| 	ios::sync_with_stdio(); |  | ||||||
| 	std::wcout.clear(); |  | ||||||
| 	std::cout.clear(); |  | ||||||
| 	std::wcerr.clear(); |  | ||||||
| 	std::cerr.clear(); |  | ||||||
| 	std::wcin.clear(); |  | ||||||
| 	std::cin.clear(); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void SetupConsole() |  | ||||||
| { |  | ||||||
| 	if (!AllocConsole()) |  | ||||||
| 	{ |  | ||||||
| 		FreeConsole(); |  | ||||||
| 		AllocConsole(); |  | ||||||
| 	} |  | ||||||
| 	AttachConsole(GetCurrentProcessId()); |  | ||||||
| 	SetupStreams(); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void SetupConsole(const char *title) |  | ||||||
| { |  | ||||||
| 	SetupConsole(); |  | ||||||
| 	SetConsoleTitleA(title); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void FreeConsole(bool wait) |  | ||||||
| { |  | ||||||
| 	if (wait) |  | ||||||
| 	{ |  | ||||||
| 		cout << "[?] Press Enter to Exit"; |  | ||||||
| 		cin.ignore(); |  | ||||||
| 	} |  | ||||||
| 	FreeConsole(); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| bool in_foreground = false; |  | ||||||
| BOOL CALLBACK EnumWindowsProcMy(HWND hwnd, LPARAM lParam) |  | ||||||
| { |  | ||||||
| 	DWORD lpdwProcessId; |  | ||||||
| 	GetWindowThreadProcessId(hwnd, &lpdwProcessId); |  | ||||||
| 	if (lpdwProcessId == lParam) |  | ||||||
| 	{ |  | ||||||
| 		in_foreground = (hwnd == GetForegroundWindow()) || (hwnd == GetActiveWindow()); |  | ||||||
| 		return FALSE; |  | ||||||
| 	} |  | ||||||
| 	return TRUE; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| bool key_down(int keycode, int delay = 100) |  | ||||||
| { |  | ||||||
| 	in_foreground = false; |  | ||||||
| 	EnumWindows(EnumWindowsProcMy, GetCurrentProcessId()); |  | ||||||
| 	if (in_foreground) |  | ||||||
| 	{ |  | ||||||
| 		if (GetAsyncKeyState(keycode)) |  | ||||||
| 		{ |  | ||||||
| 			Sleep(delay); |  | ||||||
| 			return true; |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 	return false; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| bool key_down_norepeat(int keycode, int delay = 100) |  | ||||||
| { |  | ||||||
| 	in_foreground = false; |  | ||||||
| 	EnumWindows(EnumWindowsProcMy, GetCurrentProcessId()); |  | ||||||
| 	if (in_foreground) |  | ||||||
| 	{ |  | ||||||
| 		if (GetAsyncKeyState(keycode)) |  | ||||||
| 		{ |  | ||||||
| 			while (GetAsyncKeyState(keycode)) |  | ||||||
| 			{ |  | ||||||
| 				Sleep(delay); |  | ||||||
| 			} |  | ||||||
| 			return true; |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 	return false; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| struct PyMethodDef |  | ||||||
| { |  | ||||||
| 	char *ml_name; |  | ||||||
| 	void *ml_meth; |  | ||||||
| 	int ml_flags; |  | ||||||
| 	char *ml_doc; |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| struct PyMod |  | ||||||
| { |  | ||||||
| 	char *name; |  | ||||||
| 	void *init_func; |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| struct Module |  | ||||||
| { |  | ||||||
| 	PyMod *mod; |  | ||||||
| 	map<string, PyMethodDef> methods; |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| void hexdump(void *addr, size_t count) |  | ||||||
| { |  | ||||||
| 	for (size_t i = 0; i < count; ++i) |  | ||||||
| 	{ |  | ||||||
| 		unsigned int val = (unsigned int)((unsigned char *)addr)[i]; |  | ||||||
| 		cout << setfill('0') << setw(2) << std::hex << val << " "; |  | ||||||
| 		if (((i + 1) % 16) == 0) |  | ||||||
| 		{ |  | ||||||
| 			cout << endl; |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 	cout << endl; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| PyMethodDef *find_method_table(size_t base, size_t size) |  | ||||||
| { |  | ||||||
| 	uint8_t *ptr = reinterpret_cast<uint8_t *>(base); |  | ||||||
| 	for (size_t offset = 0; offset < size; ++offset) |  | ||||||
| 	{ |  | ||||||
| 		if ((uint16_t)ptr[offset] == 0x68) |  | ||||||
| 		{ |  | ||||||
| 			uint32_t mod_addr = reinterpret_cast<uint32_t *>(base + offset + 1)[0]; |  | ||||||
| 			if ((mod_addr & 0xf00000) == 0x700000) |  | ||||||
| 			{ |  | ||||||
| 				if (strlen(reinterpret_cast<char *>(mod_addr)) == 3) |  | ||||||
| 				{ |  | ||||||
| 					return reinterpret_cast<PyMethodDef *>(mod_addr); |  | ||||||
| 				} |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 	return reinterpret_cast<PyMethodDef *>(0); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| map<string, Module> get_modules(size_t base) |  | ||||||
| { |  | ||||||
| 	map<string, Module> Py; |  | ||||||
| 	PyMod *modules = reinterpret_cast<PyMod *>(base); |  | ||||||
| 	for (int i = 0; modules[i].init_func != NULL; i++) |  | ||||||
| 	{ |  | ||||||
| 		Module mod; |  | ||||||
| 		mod.mod = &modules[i]; |  | ||||||
| 		PyMethodDef *method_table = find_method_table((size_t)modules[i].init_func, 64); |  | ||||||
| 		for (int j = 0; method_table != NULL && method_table[j].ml_name != NULL; j++) |  | ||||||
| 		{ |  | ||||||
| 			mod.methods[method_table[j].ml_name] = method_table[j]; |  | ||||||
| 		} |  | ||||||
| 		Py[mod.mod->name] = mod; |  | ||||||
| 	} |  | ||||||
| 	return Py; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void *get_py(const char *mod, const char *meth) |  | ||||||
| { |  | ||||||
| 	try |  | ||||||
| 	{ |  | ||||||
| 		return Py.at(mod).methods.at(meth).ml_meth; |  | ||||||
| 	} |  | ||||||
| 	catch (out_of_range) |  | ||||||
| 	{ |  | ||||||
| 		return NULL; |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void inject(const char *mod, const char *meth, void *detour) |  | ||||||
| { |  | ||||||
| 	try |  | ||||||
| 	{ |  | ||||||
| 		void *orig = get_py(mod, meth); |  | ||||||
| 		Py.at(mod).methods.at(meth).ml_meth = detour; |  | ||||||
| 		cout << mod << "." << meth << ": " << orig << " -> " << detour << endl; |  | ||||||
| 	} |  | ||||||
| 	catch (out_of_range) |  | ||||||
| 	{ |  | ||||||
| 		cout << mod << "." << meth << " not found!" << endl; |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| uint32_t ptr(uint32_t addr, vector<uint32_t> offsets) |  | ||||||
| { |  | ||||||
| 	cout << "[" << (void *)addr << "]"; |  | ||||||
| 	for (uint32_t offset : offsets) |  | ||||||
| 	{ |  | ||||||
| 		addr = reinterpret_cast<uint32_t *>(addr)[0]; |  | ||||||
| 		cout << " -> [" << (void *)addr << " + " << offset << "]"; |  | ||||||
| 		addr += offset; |  | ||||||
| 	}; |  | ||||||
| 	cout << " -> " << (void *)addr; |  | ||||||
| 	cout << endl; |  | ||||||
| 	return addr; |  | ||||||
| } |  | ||||||
| 
 | 
 | ||||||
| void MainLoop(HMODULE mod) | void MainLoop(HMODULE mod) | ||||||
| { | { | ||||||
| 	Sleep(100); | 	Sleep(100); | ||||||
| 	cout << "[*] Starting main Loop" << endl; | 	cout << "[*] Starting main Loop" << endl; | ||||||
| 	cout << endl; | 	cout << endl; | ||||||
|  | 	cout << "[F3 ] Unload ScrapHacks" << endl; | ||||||
| 	cout << "[F7 ] Set Money to 0x7fffffff" << endl; | 	cout << "[F7 ] Set Money to 0x7fffffff" << endl; | ||||||
| 	cout << "[F8 ] Dump python modules" << endl; | 	cout << "[F8 ] Dump python modules" << endl; | ||||||
| 	cout << "[F10] Enable python tracing" << endl; | 	cout << "[F10] Enable python tracing" << endl; | ||||||
| 	cout << "[F11] Unload ScrapHacks" << endl; |  | ||||||
| 	cout << "[ F ] \"Handbrake\" (*Will* crash the game after some time!)" << endl; | 	cout << "[ F ] \"Handbrake\" (*Will* crash the game after some time!)" << endl; | ||||||
| 
 | 
 | ||||||
| 	while (running) | 	while (running) | ||||||
|  | @ -274,9 +58,8 @@ void MainLoop(HMODULE mod) | ||||||
| 			mov     ecx, [7FE944h] | 			mov     ecx, [7FE944h] | ||||||
| 			mov     edx, [ecx + 2090h] | 			mov     edx, [ecx + 2090h] | ||||||
| 			==========================*/ | 			==========================*/ | ||||||
| 			int32_t *money = reinterpret_cast<int32_t *>(ptr(WORLD, {0x2090})); | 			int32_t *money = ptr<int32_t>(P_WORLD,O_MONEY); | ||||||
| 			cout << "Money: " << money[0] << endl; | 			*money = 0x7fffffff; | ||||||
| 			money[0] = 0x7fffffff; |  | ||||||
| 		} | 		} | ||||||
| 		if (key_down_norepeat(VK_F8)) | 		if (key_down_norepeat(VK_F8)) | ||||||
| 		{ | 		{ | ||||||
|  | @ -284,14 +67,11 @@ void MainLoop(HMODULE mod) | ||||||
| 			{ | 			{ | ||||||
| 				for (auto meth : mod.second.methods) | 				for (auto meth : mod.second.methods) | ||||||
| 				{ | 				{ | ||||||
| 					if (meth.second.ml_doc != NULL) | 					cout << mod.first << "." << meth.first << " @ " << meth.second.ml_meth << endl; | ||||||
| 					{ |  | ||||||
| 						cout << mod.first << "." << meth.first << " @ " << meth.second.ml_meth << " [" << &(meth.second) << "]" << endl; |  | ||||||
| 					} |  | ||||||
| 				} | 				} | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 		if (key_down_norepeat(VK_F11)) | 		if (key_down_norepeat(VK_F3)) | ||||||
| 		{ | 		{ | ||||||
| 			break; | 			break; | ||||||
| 		} | 		} | ||||||
|  | @ -318,12 +98,15 @@ void DllInit(HMODULE _mod) | ||||||
| 	InitConsole(); | 	InitConsole(); | ||||||
| 	GetModuleFileName(0, mfn, 1024); | 	GetModuleFileName(0, mfn, 1024); | ||||||
| 	cout << "[+] ScrapHacks v0.1 Loaded in " << mfn << endl; | 	cout << "[+] ScrapHacks v0.1 Loaded in " << mfn << endl; | ||||||
| 	Py = get_modules(PY_MODS); | 	Sleep(3000); | ||||||
|  | 	Py = get_modules(P_PY_MODS); | ||||||
| 	cout << "[*] Importing python dbg module" << endl; | 	cout << "[*] Importing python dbg module" << endl; | ||||||
| 	scrap_exec("import dbg"); | 	scrap_exec("import dbg"); | ||||||
|  | 	cout << "[*] World: " << ptr<void>(P_WORLD,0) << endl; | ||||||
|  | 	hD3D8Dll = GetModuleHandle("d3d8.dll"); | ||||||
|  | 	cout << "[*] D3D8 DLL @0x"<< hD3D8Dll << endl; | ||||||
| 	CreateThread(NULL, NULL, (LPTHREAD_START_ROUTINE)MainLoop, mod, 0, 0); | 	CreateThread(NULL, NULL, (LPTHREAD_START_ROUTINE)MainLoop, mod, 0, 0); | ||||||
| 	cout << "[*] Starting message pump" << endl; | 	cout << "[*] Starting message pump" << endl; | ||||||
| 	; |  | ||||||
| 	MSG msg; | 	MSG msg; | ||||||
| 	while (GetMessage(&msg, NULL, 0, 0)) | 	while (GetMessage(&msg, NULL, 0, 0)) | ||||||
| 	{ | 	{ | ||||||
|  |  | ||||||
|  | @ -150,9 +150,12 @@ | ||||||
|     </Link> |     </Link> | ||||||
|   </ItemDefinitionGroup> |   </ItemDefinitionGroup> | ||||||
|   <ItemGroup> |   <ItemGroup> | ||||||
|  |     <ClInclude Include="Py_Utils.h" /> | ||||||
|  |     <ClInclude Include="Structures.h" /> | ||||||
|     <ClInclude Include="Scrapland.h" /> |     <ClInclude Include="Scrapland.h" /> | ||||||
|     <ClInclude Include="stdafx.h" /> |     <ClInclude Include="stdafx.h" /> | ||||||
|     <ClInclude Include="targetver.h" /> |     <ClInclude Include="targetver.h" /> | ||||||
|  |     <ClInclude Include="Util.h" /> | ||||||
|   </ItemGroup> |   </ItemGroup> | ||||||
|   <ItemGroup> |   <ItemGroup> | ||||||
|     <ClCompile Include="dllmain.cpp" /> |     <ClCompile Include="dllmain.cpp" /> | ||||||
|  |  | ||||||
|  | @ -24,6 +24,15 @@ | ||||||
|     <ClInclude Include="Scrapland.h"> |     <ClInclude Include="Scrapland.h"> | ||||||
|       <Filter>Headerdateien</Filter> |       <Filter>Headerdateien</Filter> | ||||||
|     </ClInclude> |     </ClInclude> | ||||||
|  |     <ClInclude Include="Util.h"> | ||||||
|  |       <Filter>Headerdateien</Filter> | ||||||
|  |     </ClInclude> | ||||||
|  |     <ClInclude Include="Structures.h"> | ||||||
|  |       <Filter>Headerdateien</Filter> | ||||||
|  |     </ClInclude> | ||||||
|  |     <ClInclude Include="Py_Utils.h"> | ||||||
|  |       <Filter>Headerdateien</Filter> | ||||||
|  |     </ClInclude> | ||||||
|   </ItemGroup> |   </ItemGroup> | ||||||
|   <ItemGroup> |   <ItemGroup> | ||||||
|     <ClCompile Include="stdafx.cpp"> |     <ClCompile Include="stdafx.cpp"> | ||||||
|  |  | ||||||
|  | @ -1,6 +1,7 @@ | ||||||
| #pragma once | #pragma once | ||||||
| #define WORLD 0x7FE944 | #define P_WORLD 0x7FE944 | ||||||
| #define PY_MODS 0x79C698 | #define P_PY_MODS 0x79C698 | ||||||
|  | #define O_MONEY 0x2090 | ||||||
| 
 | 
 | ||||||
| auto scrap_log = (int(_cdecl*)(int, const char*))0x4134C0; | auto scrap_log = (int(_cdecl*)(int, const char*))0x4134C0; | ||||||
| auto scrap_exec = (void(_cdecl*)(const char*))0x5a8390; | auto scrap_exec = (void(_cdecl*)(const char*))0x5a8390; | ||||||
|  |  | ||||||
							
								
								
									
										34
									
								
								ScrapHacks/ScrapHack/Structures.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								ScrapHacks/ScrapHack/Structures.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,34 @@ | ||||||
|  | #pragma once | ||||||
|  | 
 | ||||||
|  | struct Vector3 { | ||||||
|  | 	float x; | ||||||
|  | 	float y; | ||||||
|  | 	float z; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | struct Matrix3x3 { | ||||||
|  | 	Vector3 a; | ||||||
|  | 	Vector3 b; | ||||||
|  | 	Vector3 c; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | struct PyMethodDef | ||||||
|  | { | ||||||
|  | 	char *ml_name; | ||||||
|  | 	void *ml_meth; | ||||||
|  | 	int ml_flags; | ||||||
|  | 	char *ml_doc; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | struct PyMod | ||||||
|  | { | ||||||
|  | 	char *name; | ||||||
|  | 	void *init_func; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | struct Module | ||||||
|  | { | ||||||
|  | 	PyMod *mod; | ||||||
|  | 	map<string, PyMethodDef> methods; | ||||||
|  | }; | ||||||
							
								
								
									
										159
									
								
								ScrapHacks/ScrapHack/Util.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										159
									
								
								ScrapHacks/ScrapHack/Util.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,159 @@ | ||||||
|  | #pragma once | ||||||
|  | #include <string> | ||||||
|  | #define DLL_EXPORT extern "C" __declspec(dllexport) | ||||||
|  | 
 | ||||||
|  | string GetLastErrorAsString() | ||||||
|  | { | ||||||
|  | 	DWORD errorMessageID = GetLastError(); | ||||||
|  | 	if (errorMessageID == 0) | ||||||
|  | 		return "No error"; | ||||||
|  | 	LPSTR messageBuffer = NULL; | ||||||
|  | 	size_t m_size = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, | ||||||
|  | 		NULL, errorMessageID, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&messageBuffer, 0, NULL); | ||||||
|  | 	string message(messageBuffer, m_size); | ||||||
|  | 	LocalFree(messageBuffer); | ||||||
|  | 	if (!message.empty() && message[message.length() - 1] == '\n') | ||||||
|  | 	{ | ||||||
|  | 		message.erase(message.length() - 1); | ||||||
|  | 	} | ||||||
|  | 	return message; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void SetupStreams() | ||||||
|  | { | ||||||
|  | 	FILE *fIn; | ||||||
|  | 	FILE *fOut; | ||||||
|  | 	freopen_s(&fIn, "conin$", "r", stdin); | ||||||
|  | 	freopen_s(&fOut, "conout$", "w", stdout); | ||||||
|  | 	freopen_s(&fOut, "conout$", "w", stderr); | ||||||
|  | 	ios::sync_with_stdio(); | ||||||
|  | 	std::wcout.clear(); | ||||||
|  | 	std::cout.clear(); | ||||||
|  | 	std::wcerr.clear(); | ||||||
|  | 	std::cerr.clear(); | ||||||
|  | 	std::wcin.clear(); | ||||||
|  | 	std::cin.clear(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void SetupConsole() | ||||||
|  | { | ||||||
|  | 	if (!AllocConsole()) | ||||||
|  | 	{ | ||||||
|  | 		FreeConsole(); | ||||||
|  | 		AllocConsole(); | ||||||
|  | 	} | ||||||
|  | 	AttachConsole(GetCurrentProcessId()); | ||||||
|  | 	SetupStreams(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void SetupConsole(const char *title) | ||||||
|  | { | ||||||
|  | 	SetupConsole(); | ||||||
|  | 	SetConsoleTitleA(title); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void FreeConsole(bool wait) | ||||||
|  | { | ||||||
|  | 	if (wait) | ||||||
|  | 	{ | ||||||
|  | 		cout << "[?] Press Enter to Exit"; | ||||||
|  | 		cin.ignore(); | ||||||
|  | 	} | ||||||
|  | 	FreeConsole(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | bool in_foreground = false; | ||||||
|  | BOOL CALLBACK EnumWindowsProcMy(HWND hwnd, LPARAM lParam) | ||||||
|  | { | ||||||
|  | 	DWORD lpdwProcessId; | ||||||
|  | 	GetWindowThreadProcessId(hwnd, &lpdwProcessId); | ||||||
|  | 	if (lpdwProcessId == lParam) | ||||||
|  | 	{ | ||||||
|  | 		in_foreground = (hwnd == GetForegroundWindow()) || (hwnd == GetActiveWindow()); | ||||||
|  | 		return FALSE; | ||||||
|  | 	} | ||||||
|  | 	return TRUE; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool key_down(int keycode, int delay = 100) | ||||||
|  | { | ||||||
|  | 	in_foreground = false; | ||||||
|  | 	EnumWindows(EnumWindowsProcMy, GetCurrentProcessId()); | ||||||
|  | 	if (in_foreground) | ||||||
|  | 	{ | ||||||
|  | 		if (GetAsyncKeyState(keycode)) | ||||||
|  | 		{ | ||||||
|  | 			Sleep(delay); | ||||||
|  | 			return true; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return false; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool key_down_norepeat(int keycode, int delay = 100) | ||||||
|  | { | ||||||
|  | 	in_foreground = false; | ||||||
|  | 	EnumWindows(EnumWindowsProcMy, GetCurrentProcessId()); | ||||||
|  | 	if (in_foreground) | ||||||
|  | 	{ | ||||||
|  | 		if (GetAsyncKeyState(keycode)) | ||||||
|  | 		{ | ||||||
|  | 			while (GetAsyncKeyState(keycode)) | ||||||
|  | 			{ | ||||||
|  | 				Sleep(delay); | ||||||
|  | 			} | ||||||
|  | 			return true; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return false; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | void hexdump(void *addr, size_t count) | ||||||
|  | { | ||||||
|  | 	for (size_t i = 0; i < count; ++i) | ||||||
|  | 	{ | ||||||
|  | 		unsigned int val = (unsigned int)((unsigned char *)addr)[i]; | ||||||
|  | 		cout << setfill('0') << setw(2) << std::hex << val << " "; | ||||||
|  | 		if (((i + 1) % 16) == 0) | ||||||
|  | 		{ | ||||||
|  | 			cout << endl; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	cout << endl; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | template<typename T> | ||||||
|  | T* __ptr(uintptr_t addr) | ||||||
|  | { | ||||||
|  | 	return reinterpret_cast<T*>(addr); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | template<typename T> | ||||||
|  | T* __ptr(uintptr_t addr, ptrdiff_t offset) | ||||||
|  | { | ||||||
|  | 	cout << "[" << (void*)addr << "] + " << (void*)offset << " = "; | ||||||
|  | 	addr = reinterpret_cast<uintptr_t*>(addr)[0] + offset; | ||||||
|  | 	cout << (void*)addr << endl;; | ||||||
|  | 	auto ret = __ptr<T>(addr); | ||||||
|  | 	return ret; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | template<typename T, typename... Offsets> | ||||||
|  | T* __ptr(uintptr_t addr, ptrdiff_t offset, Offsets... offsets) { | ||||||
|  | 	cout << "[" << (void*)addr << "] + " << (void*)offset << " = "; | ||||||
|  | 	addr = reinterpret_cast<uintptr_t*>(addr)[0] + offset; | ||||||
|  | 	cout << (void*)addr << endl;; | ||||||
|  | 	auto ret = __ptr<T>(addr, offsets...); | ||||||
|  | 	return ret; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | template<typename T, typename... Offsets> | ||||||
|  | T* ptr(uintptr_t addr, Offsets... offsets) { | ||||||
|  | 	auto ret = __ptr<T>(addr, offsets...); | ||||||
|  | 	return ret; | ||||||
|  | } | ||||||
|  | @ -10,6 +10,7 @@ BOOL APIENTRY DllMain(HMODULE hModule, | ||||||
|     switch (ul_reason_for_call) |     switch (ul_reason_for_call) | ||||||
|     { |     { | ||||||
|     case DLL_PROCESS_ATTACH: |     case DLL_PROCESS_ATTACH: | ||||||
|  | 		DisableThreadLibraryCalls(hModule); | ||||||
|         hThread = CreateThread(NULL, NULL, (LPTHREAD_START_ROUTINE)DllInit, hModule, 0, 0); |         hThread = CreateThread(NULL, NULL, (LPTHREAD_START_ROUTINE)DllInit, hModule, 0, 0); | ||||||
|         break; |         break; | ||||||
|     case DLL_PROCESS_DETACH: |     case DLL_PROCESS_DETACH: | ||||||
|  |  | ||||||
|  | @ -1,19 +0,0 @@ | ||||||
| Stack trace: |  | ||||||
| Frame        Function    Args |  | ||||||
| 00180000000  0018006021E (00180233AB9, 001802340B9, 000FFFFC560, 000FFFFB6F0) |  | ||||||
| 00180000000  00180048859 (FFFFFF00EEEEEE, 557BDB00453FCD, 56CA9F0069CDE6, 00000F22C80) |  | ||||||
| 00180000000  00180048892 (00180233A96, 000FFFFC458, 000FFFFC560, 453FCD00FFFFFF) |  | ||||||
| 00180000000  001800454A3 (00000000000, 00180000000, 00000000000, 001800004EC) |  | ||||||
| 00180000000  0018006DF51 (FFFFFF00EEEEEE, 557BDB00453FCD, 56CA9F0069CDE6, DBB55500BEDB55) |  | ||||||
| 00180000000  0018006EDDE (00000000000, 00100674A28, 00000000000, 00000000000) |  | ||||||
| 00180000000  001800713A4 (00000000000, 00000000008, 00000000000, 00000000000) |  | ||||||
| 006000331E0  0018013ABC1 (00100674A20, 00000000008, 00000000000, 00000000000) |  | ||||||
| 006000331E0  001801214AB (00100674A20, 00000000008, 00000000000, 00000000000) |  | ||||||
| 006000331E0  001004FC754 (0010057D324, 0010067B2B8, 00000000000, 0010067B2BC) |  | ||||||
| 006000331E0  0010058CC73 (00600000008, 0010067C940, 00000000000, 00000000000) |  | ||||||
| 006000331E0  0010057E416 (00000000000, 0005C16CB0E, 0001FCBD224, 00000010000) |  | ||||||
| 006000331E0  001005E614F (00000000002, 0000000000E, 00000000002, 005FCB11020) |  | ||||||
| 006000331E0  001005F46A7 (0000000002F, 00000000000, 00180214320, 00180329968) |  | ||||||
| 000FFFFCCD0  00180049E84 (00000000000, 00000000000, 00000000000, 00000000000) |  | ||||||
| 00000000000  00180047963 (00000000000, 00000000000, 00000000000, 00000000000) |  | ||||||
| End of stack trace (more stack frames may be present) |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue