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",
|
||||||
|
|
38
NOTES.md
38
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
|
14
README.md
14
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…
Reference in a new issue