forked from ReScrap/ScrapHacks
code cleanup, expand REPL, Automatically generate D3D8-VMT header file from include file, made ScrapHacks importable as python module
This commit is contained in:
parent
37c64ea9ce
commit
493b10e78b
26 changed files with 1894 additions and 973 deletions
127
ScrapHacks/.clang-format
Normal file
127
ScrapHacks/.clang-format
Normal file
|
@ -0,0 +1,127 @@
|
|||
---
|
||||
Language: Cpp
|
||||
# BasedOnStyle: LLVM
|
||||
AccessModifierOffset: -2
|
||||
AlignAfterOpenBracket: Align
|
||||
AlignConsecutiveMacros: false
|
||||
AlignConsecutiveAssignments: false
|
||||
AlignConsecutiveDeclarations: false
|
||||
AlignEscapedNewlines: Right
|
||||
AlignOperands: true
|
||||
AlignTrailingComments: true
|
||||
AllowAllArgumentsOnNextLine: true
|
||||
AllowAllConstructorInitializersOnNextLine: true
|
||||
AllowAllParametersOfDeclarationOnNextLine: true
|
||||
AllowShortBlocksOnASingleLine: false
|
||||
AllowShortCaseLabelsOnASingleLine: false
|
||||
AllowShortFunctionsOnASingleLine: All
|
||||
AllowShortLambdasOnASingleLine: All
|
||||
AllowShortIfStatementsOnASingleLine: Never
|
||||
AllowShortLoopsOnASingleLine: false
|
||||
AlwaysBreakAfterDefinitionReturnType: None
|
||||
AlwaysBreakAfterReturnType: None
|
||||
AlwaysBreakBeforeMultilineStrings: false
|
||||
AlwaysBreakTemplateDeclarations: MultiLine
|
||||
BinPackArguments: true
|
||||
BinPackParameters: true
|
||||
BraceWrapping:
|
||||
AfterCaseLabel: false
|
||||
AfterClass: false
|
||||
AfterControlStatement: false
|
||||
AfterEnum: false
|
||||
AfterFunction: false
|
||||
AfterNamespace: false
|
||||
AfterObjCDeclaration: false
|
||||
AfterStruct: false
|
||||
AfterUnion: false
|
||||
AfterExternBlock: false
|
||||
BeforeCatch: false
|
||||
BeforeElse: false
|
||||
IndentBraces: false
|
||||
SplitEmptyFunction: true
|
||||
SplitEmptyRecord: true
|
||||
SplitEmptyNamespace: true
|
||||
BreakBeforeBinaryOperators: None
|
||||
BreakBeforeBraces: Attach
|
||||
BreakBeforeInheritanceComma: false
|
||||
BreakInheritanceList: BeforeColon
|
||||
BreakBeforeTernaryOperators: true
|
||||
BreakConstructorInitializersBeforeComma: false
|
||||
BreakConstructorInitializers: BeforeColon
|
||||
BreakAfterJavaFieldAnnotations: false
|
||||
BreakStringLiterals: true
|
||||
ColumnLimit: 80
|
||||
CommentPragmas: '^ IWYU pragma:'
|
||||
CompactNamespaces: false
|
||||
ConstructorInitializerAllOnOneLineOrOnePerLine: false
|
||||
ConstructorInitializerIndentWidth: 4
|
||||
ContinuationIndentWidth: 4
|
||||
Cpp11BracedListStyle: true
|
||||
DerivePointerAlignment: false
|
||||
DisableFormat: false
|
||||
ExperimentalAutoDetectBinPacking: false
|
||||
FixNamespaceComments: true
|
||||
ForEachMacros:
|
||||
- foreach
|
||||
- Q_FOREACH
|
||||
- BOOST_FOREACH
|
||||
IncludeBlocks: Preserve
|
||||
IncludeCategories:
|
||||
- Regex: '^"(llvm|llvm-c|clang|clang-c)/'
|
||||
Priority: 2
|
||||
- Regex: '^(<|"(gtest|gmock|isl|json)/)'
|
||||
Priority: 3
|
||||
- Regex: '.*'
|
||||
Priority: 1
|
||||
IncludeIsMainRegex: '(Test)?$'
|
||||
IndentCaseLabels: false
|
||||
IndentPPDirectives: None
|
||||
IndentWidth: 4
|
||||
IndentWrappedFunctionNames: false
|
||||
JavaScriptQuotes: Leave
|
||||
JavaScriptWrapImports: true
|
||||
KeepEmptyLinesAtTheStartOfBlocks: true
|
||||
MacroBlockBegin: ''
|
||||
MacroBlockEnd: ''
|
||||
MaxEmptyLinesToKeep: 1
|
||||
NamespaceIndentation: All
|
||||
ObjCBinPackProtocolList: Auto
|
||||
ObjCBlockIndentWidth: 2
|
||||
ObjCSpaceAfterProperty: false
|
||||
ObjCSpaceBeforeProtocolList: true
|
||||
PenaltyBreakAssignment: 2
|
||||
PenaltyBreakBeforeFirstCallParameter: 19
|
||||
PenaltyBreakComment: 300
|
||||
PenaltyBreakFirstLessLess: 120
|
||||
PenaltyBreakString: 1000
|
||||
PenaltyBreakTemplateDeclaration: 10
|
||||
PenaltyExcessCharacter: 1000000
|
||||
PenaltyReturnTypeOnItsOwnLine: 60
|
||||
PointerAlignment: Right
|
||||
ReflowComments: true
|
||||
SortIncludes: true
|
||||
SortUsingDeclarations: true
|
||||
SpaceAfterCStyleCast: false
|
||||
SpaceAfterLogicalNot: false
|
||||
SpaceAfterTemplateKeyword: true
|
||||
SpaceBeforeAssignmentOperators: true
|
||||
SpaceBeforeCpp11BracedList: false
|
||||
SpaceBeforeCtorInitializerColon: true
|
||||
SpaceBeforeInheritanceColon: true
|
||||
SpaceBeforeParens: ControlStatements
|
||||
SpaceBeforeRangeBasedForLoopColon: true
|
||||
SpaceInEmptyParentheses: false
|
||||
SpacesBeforeTrailingComments: 1
|
||||
SpacesInAngles: false
|
||||
SpacesInContainerLiterals: true
|
||||
SpacesInCStyleCastParentheses: false
|
||||
SpacesInParentheses: false
|
||||
SpacesInSquareBrackets: false
|
||||
Standard: Cpp11
|
||||
StatementMacros:
|
||||
- Q_UNUSED
|
||||
- QT_REQUIRE_VERSION
|
||||
TabWidth: 8
|
||||
UseTab: Never
|
||||
...
|
||||
|
82
ScrapHacks/.vscode/settings.json
vendored
Normal file
82
ScrapHacks/.vscode/settings.json
vendored
Normal file
|
@ -0,0 +1,82 @@
|
|||
{
|
||||
"files.associations": {
|
||||
"xlocale": "cpp",
|
||||
"system_error": "cpp",
|
||||
"fstream": "cpp",
|
||||
"ostream": "cpp",
|
||||
"iosfwd": "cpp",
|
||||
"algorithm": "cpp",
|
||||
"array": "cpp",
|
||||
"atomic": "cpp",
|
||||
"bitset": "cpp",
|
||||
"cctype": "cpp",
|
||||
"chrono": "cpp",
|
||||
"clocale": "cpp",
|
||||
"cmath": "cpp",
|
||||
"codecvt": "cpp",
|
||||
"complex": "cpp",
|
||||
"condition_variable": "cpp",
|
||||
"csignal": "cpp",
|
||||
"cstdarg": "cpp",
|
||||
"cstddef": "cpp",
|
||||
"cstdint": "cpp",
|
||||
"cstdio": "cpp",
|
||||
"cstdlib": "cpp",
|
||||
"cstring": "cpp",
|
||||
"ctime": "cpp",
|
||||
"cwchar": "cpp",
|
||||
"cwctype": "cpp",
|
||||
"deque": "cpp",
|
||||
"exception": "cpp",
|
||||
"functional": "cpp",
|
||||
"future": "cpp",
|
||||
"initializer_list": "cpp",
|
||||
"iomanip": "cpp",
|
||||
"ios": "cpp",
|
||||
"iostream": "cpp",
|
||||
"istream": "cpp",
|
||||
"iterator": "cpp",
|
||||
"limits": "cpp",
|
||||
"list": "cpp",
|
||||
"locale": "cpp",
|
||||
"map": "cpp",
|
||||
"memory": "cpp",
|
||||
"mutex": "cpp",
|
||||
"new": "cpp",
|
||||
"numeric": "cpp",
|
||||
"optional": "cpp",
|
||||
"ratio": "cpp",
|
||||
"regex": "cpp",
|
||||
"set": "cpp",
|
||||
"shared_mutex": "cpp",
|
||||
"sstream": "cpp",
|
||||
"stdexcept": "cpp",
|
||||
"streambuf": "cpp",
|
||||
"string": "cpp",
|
||||
"strstream": "cpp",
|
||||
"thread": "cpp",
|
||||
"tuple": "cpp",
|
||||
"type_traits": "cpp",
|
||||
"typeindex": "cpp",
|
||||
"typeinfo": "cpp",
|
||||
"unordered_map": "cpp",
|
||||
"utility": "cpp",
|
||||
"variant": "cpp",
|
||||
"vector": "cpp",
|
||||
"xfacet": "cpp",
|
||||
"xhash": "cpp",
|
||||
"xiosbase": "cpp",
|
||||
"xlocbuf": "cpp",
|
||||
"xlocinfo": "cpp",
|
||||
"xlocmes": "cpp",
|
||||
"xlocmon": "cpp",
|
||||
"xlocnum": "cpp",
|
||||
"xloctime": "cpp",
|
||||
"xmemory": "cpp",
|
||||
"xstddef": "cpp",
|
||||
"xstring": "cpp",
|
||||
"xtr1common": "cpp",
|
||||
"xtree": "cpp",
|
||||
"xutility": "cpp"
|
||||
}
|
||||
}
|
|
@ -19,5 +19,71 @@ if(WIN32)
|
|||
set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} /SAFESEH:NO")
|
||||
endif(MSVC)
|
||||
endif(WIN32)
|
||||
add_subdirectory(Injector)
|
||||
add_subdirectory(ScrapHack)
|
||||
|
||||
include(ExternalProject)
|
||||
|
||||
ExternalProject_Add(
|
||||
DirectX
|
||||
PREFIX ${CMAKE_CURRENT_BINARY_DIR}
|
||||
CONFIGURE_COMMAND ""
|
||||
BUILD_COMMAND ""
|
||||
INSTALL_COMMAND ""
|
||||
URL
|
||||
https://archive.org/download/DirectX.8.0a.SDK_includes_libs_only/DirectX.8.0a.SDK.zip
|
||||
URL_HASH SHA1=39f168336d0df92ff14d62d5e3aef1b9e3191312)
|
||||
ExternalProject_Get_Property(DirectX SOURCE_DIR)
|
||||
include_directories(AFTER ${SOURCE_DIR}/8.0/include/)
|
||||
link_directories(AFTER ${SOURCE_DIR}/8.0/lib/)
|
||||
|
||||
add_custom_target(
|
||||
MAKE_D3D8_VMT python ${CMAKE_CURRENT_SOURCE_DIR}/src/make_D3D8_VMT.py ${CMAKE_CURRENT_SOURCE_DIR}/src/D3D8_VMT.hpp ${SOURCE_DIR}/8.0/include/d3d8.h
|
||||
DEPENDS DirectX
|
||||
)
|
||||
|
||||
# ExternalProject_Add(
|
||||
# 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(POINTER_64=__ptr64)
|
||||
add_library(ScrapHack SHARED
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/dllmain.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/ScrapHack.cpp
|
||||
)
|
||||
set_target_properties(ScrapHack PROPERTIES SUFFIX ".pyd")
|
||||
add_dependencies(ScrapHack DirectX)
|
||||
add_dependencies(ScrapHack MAKE_D3D8_VMT)
|
||||
add_dependencies(MAKE_D3D8_VMT DirectX)
|
||||
# add_dependencies(ScrapHack Python152)
|
||||
# add_dependencies(ScrapHack Python152_Bin)
|
||||
target_link_libraries(ScrapHack
|
||||
d3d8
|
||||
d3dx8
|
||||
dxerr8
|
||||
# PYTHON15
|
||||
legacy_stdio_definitions)
|
||||
target_compile_features(ScrapHack PUBLIC cxx_std_11)
|
||||
install(TARGETS ScrapHack DESTINATION bin)
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
- Visual Studio 2017/2019 (others might work)
|
||||
- CMake
|
||||
- Python 3.6 or newer
|
||||
|
||||
## Building
|
||||
|
||||
|
@ -11,13 +12,22 @@ Open VS 32-bit command prompt (`vcvars32.bat`)
|
|||
mkdir build
|
||||
cd build
|
||||
cmake -G"NMake Makefiles" ..
|
||||
cmake --build . --target install
|
||||
mkdir bin
|
||||
cd bin
|
||||
cmake --build .. --target install
|
||||
```
|
||||
|
||||
this will drop the compiled files into `./build/bin`
|
||||
|
||||
(this has only been tested with a (cracked/deobfuscated) `Scrap.exe` v1.0 with a SHA1 checksum of `d2dde960e8eca69d60c2e39a439088b75f0c89fa`, other version might crash if the memory offsets don't match)
|
||||
## Usage
|
||||
|
||||
## TODO
|
||||
- create a `lib` folder next to `Scrapland.exe`
|
||||
- copy `ScrapHack.pyd` into said folder
|
||||
- open the ingame console (Ctrl+^)
|
||||
- type `import ScrapHack`
|
||||
- Done!
|
||||
|
||||
## Notes
|
||||
|
||||
(this has only been tested with a (cracked/de-obfuscated) `Scrap.exe` v1.0 with a SHA1 checksum of `d2dde960e8eca69d60c2e39a439088b75f0c89fa`, other version might crash if the memory offsets don't match)
|
||||
|
||||
- Injector-less version (patch Scrap.exe to load DLL)
|
|
@ -1,24 +0,0 @@
|
|||
include(ExternalProject)
|
||||
ExternalProject_Add(
|
||||
DirectX
|
||||
PREFIX ${CMAKE_CURRENT_BINARY_DIR}
|
||||
CONFIGURE_COMMAND ""
|
||||
BUILD_COMMAND ""
|
||||
INSTALL_COMMAND ""
|
||||
URL
|
||||
https://archive.org/download/DirectX.8.0a.SDK_includes_libs_only/DirectX.8.0a.SDK.zip
|
||||
URL_HASH SHA1=39f168336d0df92ff14d62d5e3aef1b9e3191312)
|
||||
ExternalProject_Get_Property(DirectX SOURCE_DIR)
|
||||
include_directories(AFTER ${SOURCE_DIR}/8.0/include/)
|
||||
link_directories(AFTER ${SOURCE_DIR}/8.0/lib/)
|
||||
add_compile_definitions(_CRT_SECURE_NO_WARNINGS)
|
||||
add_compile_definitions(POINTER_64=__ptr64)
|
||||
add_library(ScrapHack SHARED ScrapHack.cpp dllmain.cpp)
|
||||
add_dependencies(ScrapHack DirectX)
|
||||
target_link_libraries(ScrapHack
|
||||
d3d8
|
||||
d3dx8
|
||||
dxerr8
|
||||
legacy_stdio_definitions)
|
||||
target_compile_features(ScrapHack PUBLIC cxx_std_11)
|
||||
install(TARGETS ScrapHack DESTINATION bin)
|
|
@ -1,82 +0,0 @@
|
|||
#pragma once
|
||||
#include <Windows.h>
|
||||
#include <d3d8.h>
|
||||
#include <d3dx8.h>
|
||||
#include <dxerr8.h>
|
||||
uintmax_t frame = 0;
|
||||
DWORD *GetVTable(void *addr)
|
||||
{
|
||||
return (DWORD *)(*(DWORD *)addr);
|
||||
}
|
||||
bool overlay = false;
|
||||
LPD3DXFONT m_pFont;
|
||||
HFONT hFont;
|
||||
HBRUSH hBrush;
|
||||
D3DCOLOR color = D3DCOLOR_ARGB(255, 255, 0, 0);
|
||||
RECT Rect = {0, 0, 0, 0};
|
||||
D3DRECT panel;
|
||||
|
||||
size_t size_ht(HashTable<EntityList> *ht);
|
||||
size_t size_ht(HashTable<Entity> *ht);
|
||||
|
||||
LPDIRECT3DDEVICE8 Render(LPDIRECT3DDEVICE8 dev)
|
||||
{
|
||||
if (!overlay)
|
||||
{
|
||||
return dev;
|
||||
}
|
||||
char text[4096];
|
||||
int32_t money = 0;
|
||||
size_t num_ents = 0;
|
||||
size_t num_ent_lst = 0;
|
||||
if (ptr<void>(P_WORLD, 0) != nullptr)
|
||||
{
|
||||
money = ptr<int32_t>(P_WORLD, O_MONEY)[0];
|
||||
num_ents = size_ht(ptr<HashTable<Entity>>(P_WORLD, O_ENTS));
|
||||
num_ent_lst = size_ht(ptr<HashTable<EntityList>>(P_WORLD, O_ENTLISTS));
|
||||
}
|
||||
snprintf(text, 4096, "ScrapHack v0.1\nFrame: [%lld]\nMoney: [%d]\nEntities: [%ld]\nEntity Lists: [%ld]", ++frame, money, num_ents, num_ent_lst);
|
||||
if (m_pFont == nullptr)
|
||||
{
|
||||
D3DXCreateFont(dev, hFont, &m_pFont);
|
||||
CloseHandle(hFont);
|
||||
}
|
||||
m_pFont->Begin();
|
||||
m_pFont->DrawTextA(text, -1, &Rect, DT_CALCRECT, 0);
|
||||
m_pFont->DrawTextA(text, -1, &Rect, DT_LEFT, color);
|
||||
m_pFont->End();
|
||||
return dev;
|
||||
}
|
||||
|
||||
HRESULT WINAPI H_EndScene(LPDIRECT3DDEVICE8 dev)
|
||||
{
|
||||
typedef HRESULT(WINAPI * t_func)(LPDIRECT3DDEVICE8);
|
||||
shared_ptr<Hook> hook = Hook::get(H_EndScene);
|
||||
return hook->func<t_func>(Render(dev));
|
||||
}
|
||||
|
||||
void unhook_d3d8()
|
||||
{
|
||||
if (hFont != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
CloseHandle(hFont);
|
||||
}
|
||||
if (m_pFont != nullptr)
|
||||
{
|
||||
m_pFont->Release();
|
||||
}
|
||||
Hook::drop(H_EndScene);
|
||||
}
|
||||
|
||||
void hook_d3d8()
|
||||
{
|
||||
typedef void(_cdecl * t_func)();
|
||||
hFont = CreateFont(20, 0, 0, 0, FW_BOLD, 0, 0, 0, ANSI_CHARSET, 0, 0, 0, 0, "Verdana");
|
||||
hBrush = CreateSolidBrush(D3DCOLOR_ARGB(25, 0, 0, 0));
|
||||
Hook::addr(ptr<void>(0x853954,0x2a3d8,0,4*35,0),H_EndScene);
|
||||
shared_ptr<Hook> hook = Hook::get(hook_d3d8);
|
||||
hook->func_void<t_func>();
|
||||
hook->disable();
|
||||
Hook::drop(hook_d3d8);
|
||||
return;
|
||||
}
|
|
@ -1,141 +0,0 @@
|
|||
#pragma once
|
||||
#include <functional>
|
||||
class Hook
|
||||
{
|
||||
private:
|
||||
MEMORY_BASIC_INFORMATION mbi;
|
||||
void *orig;
|
||||
void *detour;
|
||||
bool enabled;
|
||||
uint8_t orig_bytes[6];
|
||||
uint8_t jmp_bytes[6];
|
||||
static map<uintptr_t, shared_ptr<Hook>> hooks;
|
||||
|
||||
public:
|
||||
Hook(void *func, void *detour)
|
||||
{
|
||||
uintptr_t dest = reinterpret_cast<uintptr_t>(detour);
|
||||
uintptr_t src = reinterpret_cast<uintptr_t>(func);
|
||||
this->orig = func;
|
||||
this->detour = detour;
|
||||
this->jmp_bytes[0] = 0x68; // push
|
||||
this->jmp_bytes[1] = (dest >> 0) & 0xff;
|
||||
this->jmp_bytes[2] = (dest >> 8) & 0xff;
|
||||
this->jmp_bytes[3] = (dest >> 16) & 0xff;
|
||||
this->jmp_bytes[4] = (dest >> 24) & 0xff;
|
||||
this->jmp_bytes[5] = 0xC3; // ret
|
||||
VirtualQuery(func, &mbi, sizeof(mbi));
|
||||
VirtualProtect(mbi.BaseAddress, mbi.RegionSize, PAGE_EXECUTE_READWRITE, &mbi.Protect);
|
||||
memcpy(this->orig_bytes, this->orig, 1 + 4 + 1);
|
||||
VirtualProtect(mbi.BaseAddress, mbi.RegionSize, mbi.Protect, NULL);
|
||||
this->enabled = false;
|
||||
}
|
||||
|
||||
~Hook()
|
||||
{
|
||||
cout << "Unhooking: [" << this->orig << " <- " << this->detour << "]" << endl;
|
||||
this->disable();
|
||||
}
|
||||
|
||||
static void addr(void *addr, void *detour)
|
||||
{
|
||||
cout << "Hooking: [" << addr << " -> " << detour << "]" << endl;
|
||||
uintptr_t key = reinterpret_cast<uintptr_t>(detour);
|
||||
hooks[key] = make_shared<Hook>(addr, detour);
|
||||
hooks[key]->enable();
|
||||
}
|
||||
|
||||
static void module(const char *mod, const char *func, void *detour)
|
||||
{
|
||||
cout << "Hooking: [" << mod << "]." << func << " -> " << detour << endl;
|
||||
void *addr = GetProcAddress(GetModuleHandle(mod), func);
|
||||
if (addr != NULL)
|
||||
{
|
||||
Hook::addr(addr, detour);
|
||||
}
|
||||
else
|
||||
{
|
||||
cerr << "[" << mod << "]." << func << " not found!" << endl;
|
||||
};
|
||||
}
|
||||
|
||||
static shared_ptr<Hook> get(void *func)
|
||||
{
|
||||
uintptr_t addr = reinterpret_cast<uintptr_t>(func);
|
||||
return Hook::get(addr);
|
||||
}
|
||||
|
||||
static shared_ptr<Hook> get(uintptr_t addr)
|
||||
{
|
||||
return hooks.at(addr);
|
||||
}
|
||||
|
||||
static size_t drop(void *func)
|
||||
{
|
||||
uintptr_t addr = reinterpret_cast<uintptr_t>(func);
|
||||
return Hook::drop(addr);
|
||||
}
|
||||
|
||||
static size_t drop(uintptr_t addr)
|
||||
{
|
||||
return hooks.erase(addr);
|
||||
}
|
||||
|
||||
static void clear()
|
||||
{
|
||||
cout << "Clearing Hooks" << endl;
|
||||
for (pair<uintptr_t, shared_ptr<Hook>> h : hooks)
|
||||
{
|
||||
h.second->disable();
|
||||
}
|
||||
return hooks.clear();
|
||||
}
|
||||
|
||||
void disable()
|
||||
{
|
||||
if (enabled)
|
||||
{
|
||||
//cout << "Disabling: [" << this->orig << " <- " << this->detour << "]" << endl;
|
||||
VirtualProtect(mbi.BaseAddress, mbi.RegionSize, PAGE_EXECUTE_READWRITE, NULL);
|
||||
memcpy(this->orig, this->orig_bytes, 1 + 4 + 1);
|
||||
VirtualProtect(mbi.BaseAddress, mbi.RegionSize, mbi.Protect, NULL);
|
||||
enabled = false;
|
||||
}
|
||||
}
|
||||
void enable()
|
||||
{
|
||||
if (!enabled)
|
||||
{
|
||||
//cout << "Enabling: [" << this->orig << " -> " << this->detour << "]" << endl;
|
||||
VirtualProtect(mbi.BaseAddress, mbi.RegionSize, PAGE_EXECUTE_READWRITE, NULL);
|
||||
memcpy(this->orig, this->jmp_bytes, 1 + 4 + 1);
|
||||
VirtualProtect(mbi.BaseAddress, mbi.RegionSize, mbi.Protect, NULL);
|
||||
enabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
void *get_orig()
|
||||
{
|
||||
return this->orig;
|
||||
}
|
||||
|
||||
template <typename F, typename... Args>
|
||||
void func_void(Args... args)
|
||||
{
|
||||
disable();
|
||||
reinterpret_cast<F>(this->orig)(args...);
|
||||
enable();
|
||||
return;
|
||||
}
|
||||
|
||||
template <typename F, typename... Args>
|
||||
decltype(auto) func(Args... args)
|
||||
{
|
||||
disable();
|
||||
auto ret = reinterpret_cast<F>(this->orig)(args...);
|
||||
enable();
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
|
||||
map<uintptr_t, shared_ptr<Hook>> Hook::hooks;
|
|
@ -1,62 +0,0 @@
|
|||
#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;
|
||||
}
|
||||
}
|
|
@ -1,54 +0,0 @@
|
|||
#include <sstream>
|
||||
#include <regex>
|
||||
#include <Windows.h>
|
||||
#include "Util.h"
|
||||
|
||||
DWORD get_protection(void *addr)
|
||||
{
|
||||
MEMORY_BASIC_INFORMATION mbi;
|
||||
VirtualQuery(addr, &mbi, sizeof(mbi));
|
||||
return mbi.Protect;
|
||||
}
|
||||
|
||||
void handle_command(const char *_cmd)
|
||||
{
|
||||
cout<<"CMD: '"<<_cmd<<"'"<<endl;
|
||||
vector<string> cmd = split(string(_cmd), ' ');
|
||||
cout<<"PARTS: ";
|
||||
for (string c:cmd) {
|
||||
cout<<"'"<<c<<"' ";
|
||||
}
|
||||
cout<<endl;
|
||||
if (cmd.size() == 0)
|
||||
{
|
||||
cout<<"EMPTY!"<<endl;
|
||||
return;
|
||||
}
|
||||
scrap_log(0x00ff00,_cmd);
|
||||
scrap_log(0x00ff00,"\n");
|
||||
if (cmd[0] == "r")
|
||||
{
|
||||
if (cmd.size()!=2) {
|
||||
scrap_log(0xff0000, "Usage: $r <addr> [size]\n");
|
||||
return;
|
||||
}
|
||||
scrap_log(0xff0000, "READ!\n");
|
||||
cout<<"READ!"<<endl;
|
||||
}
|
||||
else if (cmd[0] == "w")
|
||||
{
|
||||
if (cmd.size()!=2) {
|
||||
scrap_log(0xff0000, "Usage: $w <addr> <hex_data>\n");
|
||||
return;
|
||||
}
|
||||
scrap_log(0xff0000, "WRITE!\n");
|
||||
cout<<"WRITE!"<<endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
scrap_log(0xff0000, "Unknown command!\n");
|
||||
}
|
||||
|
||||
scrap_log(0x00ff00, "HAXX\n");
|
||||
return;
|
||||
}
|
|
@ -1,266 +0,0 @@
|
|||
#include <string>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
#include <typeinfo>
|
||||
#include <functional>
|
||||
#include <Windows.h>
|
||||
#include <TlHelp32.h>
|
||||
|
||||
using namespace std;
|
||||
|
||||
#include "Scrapland.h"
|
||||
#include "Util.h"
|
||||
#include "Structures.h"
|
||||
#include "Py_Utils.h"
|
||||
#include "Hook.h"
|
||||
#include "D3D8_Hook.h"
|
||||
#include "REPL.h"
|
||||
HMODULE hD3D8Dll = 0;
|
||||
|
||||
bool initialized = false;
|
||||
bool running = true;
|
||||
bool redirect_console = false;
|
||||
HMODULE mod = 0;
|
||||
|
||||
void DllUnload(HMODULE);
|
||||
int hooked_console(const char *);
|
||||
void H_Exit();
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
void MainLoop(HMODULE mod)
|
||||
{
|
||||
Sleep(100);
|
||||
Hook::addr(reinterpret_cast<void *>(P_SCRAP_EXIT), H_Exit);
|
||||
Hook::addr(reinterpret_cast<void *>(P_D3DCHECK),hook_d3d8);
|
||||
Hook::addr(reinterpret_cast<void *>(P_CON_HANDLER), hooked_console);
|
||||
overlay=true;
|
||||
cout << "[*] Starting main Loop" << endl;
|
||||
cout << endl;
|
||||
cout << "[F2 ] Redirect game console to ScapHacks console" << endl;
|
||||
cout << "[F3 ] Unload ScrapHacks" << endl;
|
||||
cout << "[F5 ] Show Overlay" << endl;
|
||||
cout << "[F6 ] Show Alarm status" << endl;
|
||||
cout << "[F7 ] Set Money to 0x7fffffff" << endl;
|
||||
cout << "[F8 ] Dump python modules" << endl;
|
||||
cout << "[F9 ] Dump Entity hashtable" << endl;
|
||||
cout << "[F10] Enable python tracing" << endl;
|
||||
cout << "[ F ] \"Handbrake\" (*Will* crash the game after some time!)" << endl;
|
||||
|
||||
while (running)
|
||||
{
|
||||
Sleep(100);
|
||||
while (key_down('F'))
|
||||
{
|
||||
scrap_exec("dbg.brake()");
|
||||
}
|
||||
if (key_down_norepeat(VK_F2))
|
||||
{
|
||||
redirect_console = !redirect_console;
|
||||
}
|
||||
if (key_down_norepeat(VK_F3))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (key_down_norepeat(VK_F5))
|
||||
{
|
||||
overlay = !overlay;
|
||||
}
|
||||
|
||||
if (key_down_norepeat(VK_F6))
|
||||
{
|
||||
|
||||
float *alarm = ptr<float>(P_WORLD, O_ALARM);
|
||||
float *alarm_grow = ptr<float>(P_WORLD, O_ALARM_GROW);
|
||||
cout << "Alarm: " << alarm[0] << " + " << alarm_grow[0] << endl;
|
||||
}
|
||||
if (key_down_norepeat(VK_F7))
|
||||
{
|
||||
int32_t *money = ptr<int32_t>(P_WORLD, O_MONEY);
|
||||
*money = 0x7fffffff;
|
||||
}
|
||||
if (key_down_norepeat(VK_F8))
|
||||
{
|
||||
for (auto mod : Py)
|
||||
{
|
||||
for (auto meth : mod.second.methods)
|
||||
{
|
||||
cout << mod.first << "." << meth.first << " @ " << meth.second->ml_meth << endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (key_down_norepeat(VK_F9))
|
||||
{
|
||||
cout << "Entities:" << endl;
|
||||
dump_ht(ptr<HashTable<Entity>>(P_WORLD, O_ENTS));
|
||||
cout << "Entity Lists:" << endl;
|
||||
dump_ht(ptr<HashTable<EntityList>>(P_WORLD, O_ENTLISTS));
|
||||
}
|
||||
if (key_down_norepeat(VK_F10))
|
||||
{
|
||||
scrap_exec("dbg.settrace()");
|
||||
}
|
||||
}
|
||||
FreeLibraryAndExitThread(mod, 0);
|
||||
}
|
||||
|
||||
void InitConsole()
|
||||
{
|
||||
char me[1024];
|
||||
GetModuleFileName(mod, me, 1024);
|
||||
SetupConsole(me);
|
||||
}
|
||||
|
||||
int hooked_console(const char *cmd)
|
||||
{
|
||||
typedef int(_cdecl * t_func)(const char *);
|
||||
if (cmd[0] == '$')
|
||||
{
|
||||
handle_command(++cmd);
|
||||
return 0;
|
||||
}
|
||||
shared_ptr<Hook> hook = Hook::get(hooked_console);
|
||||
int ret = hook->func<t_func>(cmd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void H_Exit()
|
||||
{
|
||||
typedef void(_cdecl * t_func)(void);
|
||||
shared_ptr<Hook> hook = Hook::get(H_Exit);
|
||||
DllUnload(mod);
|
||||
HWND hMainWindow = ptr<HWND>(0x7FA830, 0x7c)[0];
|
||||
SendMessage(hMainWindow, WM_CLOSE, 0, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
void DllPreInit(HMODULE _mod)
|
||||
{
|
||||
char mfn[1024];
|
||||
InitConsole();
|
||||
GetModuleFileNameA(0, mfn, 1024);
|
||||
Py = get_modules(P_PY_MODS);
|
||||
cout << "[+] ScrapHacks v0.1 Loaded in " << mfn << " (PID: " << std::hex << GetCurrentProcessId() << std::dec << ")" << endl;
|
||||
}
|
||||
|
||||
void DllInit(HMODULE _mod)
|
||||
{
|
||||
initialized = true;
|
||||
mod = _mod;
|
||||
cout << "[*] World: " << ptr<void>(P_WORLD, 0) << endl;
|
||||
cout << "[*] Importing python dbg module" << endl;
|
||||
scrap_exec("import dbg");
|
||||
scrap_log(0xff0000, "ScrapHacks loaded!\n");
|
||||
CreateThread(NULL, NULL, (LPTHREAD_START_ROUTINE)MainLoop, mod, 0, 0);
|
||||
cout << "[*] Starting message pump" << endl;
|
||||
MSG msg;
|
||||
while (GetMessage(&msg, NULL, 0, 0))
|
||||
{
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessage(&msg);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
void DllUnload(HMODULE _mod)
|
||||
{
|
||||
SetConsoleCtrlHandler(NULL, false);
|
||||
unhook_d3d8();
|
||||
Hook::clear();
|
||||
scrap_log(0xff0000, "ScrapHacks unloaded!\n");
|
||||
cout << "[+] ScrapHacks unloaded, you can now close the console!" << endl;
|
||||
FreeConsole();
|
||||
DestroyWindow(GetConsoleWindow());
|
||||
return;
|
||||
}
|
|
@ -1,26 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
//OFFSETS
|
||||
#define O_MONEY 0x2090
|
||||
#define O_ALARM 0x1C6C
|
||||
#define O_ALARM_GROW 0x1C68
|
||||
#define O_ENTS 0x4
|
||||
#define O_ENTLISTS 0x2b8
|
||||
|
||||
//POINTERS
|
||||
#define P_WORLD 0x7FE944
|
||||
#define P_PY_MODS 0x79C698
|
||||
|
||||
//FUNCTIONS
|
||||
#define P_CON_HANDLER 0x402190
|
||||
#define P_SCRAP_LOG 0x4134C0
|
||||
#define P_SCRAP_EXEC 0x5a8390
|
||||
#define P_SCRAP_EXIT 0x4010c0
|
||||
#define P_D3DCHECK 0x602a70
|
||||
|
||||
//FUNCTION TYPES
|
||||
#define T_SCRAP_LOG int(_cdecl *)(unsigned int, const char *)
|
||||
#define T_SCRAP_EXEC int(_cdecl *)(const char *)
|
||||
|
||||
auto scrap_log = (T_SCRAP_LOG)P_SCRAP_LOG;
|
||||
auto scrap_exec = (T_SCRAP_EXEC)P_SCRAP_EXEC;
|
|
@ -1,66 +0,0 @@
|
|||
#pragma once
|
||||
template <typename T>
|
||||
struct HashTableEntry;
|
||||
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;
|
||||
};
|
||||
|
||||
struct Entity
|
||||
{
|
||||
void *vmt;
|
||||
const char *name;
|
||||
};
|
||||
|
||||
struct EntityList
|
||||
{
|
||||
const char *name;
|
||||
void *unk_1;
|
||||
void *unk_2;
|
||||
const char *mod;
|
||||
const char *func;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct HashTable
|
||||
{
|
||||
uint32_t size;
|
||||
HashTableEntry<T> **chains;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct HashTableEntry
|
||||
{
|
||||
T *data;
|
||||
const char *name;
|
||||
HashTableEntry *next;
|
||||
};
|
|
@ -1,206 +0,0 @@
|
|||
#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 (!AttachConsole(-1)) {
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
DWORD PPID()
|
||||
{
|
||||
DWORD PID = GetCurrentProcessId();
|
||||
HANDLE hSnapShot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
|
||||
PROCESSENTRY32 procentry;
|
||||
if (hSnapShot == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
cout << GetLastErrorAsString() << endl;
|
||||
return -1;
|
||||
}
|
||||
if (Process32First(hSnapShot, &procentry))
|
||||
{
|
||||
do
|
||||
{
|
||||
if (procentry.th32ProcessID == PID)
|
||||
{
|
||||
CloseHandle(hSnapShot);
|
||||
return procentry.th32ParentProcessID;
|
||||
}
|
||||
procentry.dwSize = sizeof(PROCESSENTRY32);
|
||||
} while (Process32Next(hSnapShot, &procentry));
|
||||
}
|
||||
CloseHandle(hSnapShot);
|
||||
return -1;
|
||||
}
|
||||
|
||||
vector<string> split(string str, char sep)
|
||||
{
|
||||
vector<string> ret;
|
||||
string part;
|
||||
for (auto n : str)
|
||||
{
|
||||
if (n == sep)
|
||||
{
|
||||
ret.push_back(part);
|
||||
part.clear();
|
||||
}
|
||||
else
|
||||
{
|
||||
part = part + n;
|
||||
}
|
||||
}
|
||||
if (part != "")
|
||||
ret.push_back(part);
|
||||
return ret;
|
||||
}
|
|
@ -1,30 +0,0 @@
|
|||
#include <Windows.h>
|
||||
#define DLL_EXPORT extern "C" __declspec(dllexport)
|
||||
void DllInit(HMODULE);
|
||||
void DllPreInit(HMODULE);
|
||||
void DllUnload(HMODULE);
|
||||
|
||||
BOOL APIENTRY DllMain(HMODULE hModule,
|
||||
DWORD ul_reason_for_call,
|
||||
LPVOID lpReserved)
|
||||
{
|
||||
HANDLE hThread = INVALID_HANDLE_VALUE;
|
||||
switch (ul_reason_for_call)
|
||||
{
|
||||
case DLL_PROCESS_ATTACH:
|
||||
DisableThreadLibraryCalls(hModule);
|
||||
DllPreInit(hModule);
|
||||
hThread = CreateThread(NULL, NULL, (LPTHREAD_START_ROUTINE)DllInit, hModule, 0, 0);
|
||||
if (hThread) {
|
||||
CloseHandle(hThread);
|
||||
}
|
||||
break;
|
||||
case DLL_PROCESS_DETACH:
|
||||
DllUnload(hModule);
|
||||
break;
|
||||
case DLL_THREAD_ATTACH:
|
||||
case DLL_THREAD_DETACH:
|
||||
break;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
136
ScrapHacks/src/D3D8_Hook.hpp
Normal file
136
ScrapHacks/src/D3D8_Hook.hpp
Normal file
|
@ -0,0 +1,136 @@
|
|||
#pragma once
|
||||
#include <Windows.h>
|
||||
#include <d3d8.h>
|
||||
#include <d3dx8.h>
|
||||
#include <dxerr8.h>
|
||||
|
||||
#include "D3D8_VMT.hpp"
|
||||
#include "Hook.hpp"
|
||||
#include "Scrapland.hpp"
|
||||
#include "Structures.hpp"
|
||||
#include "Util.hpp"
|
||||
|
||||
uintmax_t frame = 0;
|
||||
bool hooked=false;
|
||||
bool overlay = false;
|
||||
LPD3DXFONT m_pFont;
|
||||
HFONT hFont;
|
||||
HBRUSH hBrush;
|
||||
D3DCOLOR color = D3DCOLOR_ARGB(255, 255, 0, 0);
|
||||
RECT Rect = {0, 0, 0, 0};
|
||||
D3DRECT panel;
|
||||
|
||||
size_t size_ht(HashTable<EntityList> *ht);
|
||||
size_t size_ht(HashTable<Entity> *ht);
|
||||
|
||||
LPDIRECT3DDEVICE8
|
||||
Render(LPDIRECT3DDEVICE8 dev) {
|
||||
if (!overlay) {
|
||||
return dev;
|
||||
}
|
||||
char text[4096];
|
||||
int32_t money = 0;
|
||||
size_t num_ents = 0;
|
||||
size_t num_ent_lst = 0;
|
||||
if (ptr<void>(P_WORLD, 0) != nullptr) {
|
||||
money = ptr<int32_t>(P_WORLD, O_MONEY)[0];
|
||||
num_ents = size_ht(ptr<HashTable<Entity>>(P_WORLD, O_ENTS));
|
||||
num_ent_lst = size_ht(ptr<HashTable<EntityList>>(P_WORLD, O_ENTLISTS));
|
||||
}
|
||||
snprintf(text, 4096,
|
||||
R"(ScrapHack v0.1
|
||||
Frame: [%lld]
|
||||
Money: [%d]
|
||||
Entities: [%ld]
|
||||
Entity Lists: [%ld])",
|
||||
++frame, money, num_ents, num_ent_lst);
|
||||
if (m_pFont == nullptr) {
|
||||
D3DXCreateFont(dev, hFont, &m_pFont);
|
||||
hFont = nullptr;
|
||||
}
|
||||
m_pFont->Begin();
|
||||
m_pFont->DrawTextA(text, -1, &Rect, DT_CALCRECT, 0);
|
||||
m_pFont->DrawTextA(text, -1, &Rect, DT_LEFT, color);
|
||||
m_pFont->End();
|
||||
return dev;
|
||||
}
|
||||
|
||||
HRESULT WINAPI H_EndScene(LPDIRECT3DDEVICE8 dev) {
|
||||
typedef decltype(&H_EndScene) t_func;
|
||||
shared_ptr<Hook> hook = Hook::get(H_EndScene);
|
||||
return hook->func<t_func>(Render(dev));
|
||||
}
|
||||
|
||||
HRESULT WINAPI H_SetLight(LPDIRECT3DDEVICE8 dev, DWORD index,
|
||||
D3DLIGHT8 *light) {
|
||||
typedef decltype(&H_SetLight) t_func;
|
||||
shared_ptr<Hook> hook = Hook::get(H_SetLight);
|
||||
light->Diffuse.r = ((float)rand() / (float)RAND_MAX);
|
||||
light->Diffuse.g = ((float)rand() / (float)RAND_MAX);
|
||||
light->Diffuse.b = ((float)rand() / (float)RAND_MAX);
|
||||
light->Diffuse.a = 1.0;
|
||||
light->Specular.r = ((float)rand() / (float)RAND_MAX);
|
||||
light->Specular.g = ((float)rand() / (float)RAND_MAX);
|
||||
light->Specular.b = ((float)rand() / (float)RAND_MAX);
|
||||
light->Specular.r = 1.0;
|
||||
light->Ambient.r = ((float)rand() / (float)RAND_MAX);
|
||||
light->Ambient.g = ((float)rand() / (float)RAND_MAX);
|
||||
light->Ambient.b = ((float)rand() / (float)RAND_MAX);
|
||||
light->Ambient.a = 1.0;
|
||||
return hook->func<t_func>(dev, index, light);
|
||||
}
|
||||
|
||||
HRESULT WINAPI H_DrawIndexedPrimitive(LPDIRECT3DDEVICE8 dev,
|
||||
D3DPRIMITIVETYPE Type, UINT minIndex,
|
||||
UINT NumVertices, UINT startIndex,
|
||||
UINT primCount) {
|
||||
typedef decltype(&H_DrawIndexedPrimitive) t_func;
|
||||
DWORD AMBIENT;
|
||||
shared_ptr<Hook> hook = Hook::get(H_DrawIndexedPrimitive);
|
||||
dev->GetRenderState(D3DRS_AMBIENT, &AMBIENT);
|
||||
dev->SetRenderState(D3DRS_AMBIENT, D3DCOLOR_XRGB(255, 255, 255));
|
||||
dev->SetRenderState(D3DRS_FILLMODE, D3DFILLMODE::D3DFILL_SOLID);
|
||||
dev->SetRenderState(D3DRS_ZENABLE, 0);
|
||||
auto ret = hook->func<t_func>(dev, Type, minIndex, NumVertices, startIndex,
|
||||
primCount);
|
||||
dev->SetRenderState(D3DRS_AMBIENT, AMBIENT);
|
||||
dev->SetRenderState(D3DRS_ZENABLE, 1);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void unhook_d3d8() {
|
||||
if (!hooked) {
|
||||
return;
|
||||
}
|
||||
if (m_pFont != nullptr) {
|
||||
m_pFont->Release();
|
||||
m_pFont = nullptr;
|
||||
}
|
||||
Hook::drop(H_EndScene);
|
||||
Hook::drop(H_DrawIndexedPrimitive);
|
||||
Hook::drop(H_SetLight);
|
||||
hooked=false;
|
||||
}
|
||||
|
||||
void hook_d3d8() {
|
||||
if (hooked) {
|
||||
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;
|
||||
while (true) {
|
||||
dev = ptr<void>(P_D3DDEV);
|
||||
if (dev) {
|
||||
break;
|
||||
}
|
||||
Sleep(100);
|
||||
};
|
||||
Hook::addr(GetVTable(dev)[VMT_IDirect3DDevice8::m_EndScene], H_EndScene);
|
||||
Hook::addr(GetVTable(dev)[VMT_IDirect3DDevice8::m_DrawIndexedPrimitive],
|
||||
H_DrawIndexedPrimitive);
|
||||
Hook::addr(GetVTable(dev)[VMT_IDirect3DDevice8::m_SetLight], H_SetLight);
|
||||
hooked=true;
|
||||
return;
|
||||
}
|
274
ScrapHacks/src/D3D8_VMT.hpp
Normal file
274
ScrapHacks/src/D3D8_VMT.hpp
Normal file
|
@ -0,0 +1,274 @@
|
|||
namespace VMT_IDirect3D8 {
|
||||
const size_t m_QueryInterface = 0;
|
||||
const size_t m_AddRef = 1;
|
||||
const size_t m_Release = 2;
|
||||
const size_t m_RegisterSoftwareDevice = 3;
|
||||
const size_t m_GetAdapterCount = 4;
|
||||
const size_t m_GetAdapterIdentifier = 5;
|
||||
const size_t m_GetAdapterModeCount = 6;
|
||||
const size_t m_EnumAdapterModes = 7;
|
||||
const size_t m_GetAdapterDisplayMode = 8;
|
||||
const size_t m_CheckDeviceType = 9;
|
||||
const size_t m_CheckDeviceFormat = 10;
|
||||
const size_t m_CheckDeviceMultiSampleType = 11;
|
||||
const size_t m_CheckDepthStencilMatch = 12;
|
||||
const size_t m_GetDeviceCaps = 13;
|
||||
const size_t m_GetAdapterMonitor = 14;
|
||||
const size_t m_CreateDevice = 15;
|
||||
}
|
||||
namespace VMT_IDirect3DBaseTexture8_IDirect3DResource8 {
|
||||
const size_t m_QueryInterface = 0;
|
||||
const size_t m_AddRef = 1;
|
||||
const size_t m_Release = 2;
|
||||
const size_t m_GetDevice = 3;
|
||||
const size_t m_SetPrivateData = 4;
|
||||
const size_t m_GetPrivateData = 5;
|
||||
const size_t m_FreePrivateData = 6;
|
||||
const size_t m_SetPriority = 7;
|
||||
const size_t m_GetPriority = 8;
|
||||
const size_t m_PreLoad = 9;
|
||||
const size_t m_GetType = 10;
|
||||
const size_t m_SetLOD = 11;
|
||||
const size_t m_GetLOD = 12;
|
||||
const size_t m_GetLevelCount = 13;
|
||||
}
|
||||
namespace VMT_IDirect3DCubeTexture8_IDirect3DBaseTexture8 {
|
||||
const size_t m_QueryInterface = 0;
|
||||
const size_t m_AddRef = 1;
|
||||
const size_t m_Release = 2;
|
||||
const size_t m_GetDevice = 3;
|
||||
const size_t m_SetPrivateData = 4;
|
||||
const size_t m_GetPrivateData = 5;
|
||||
const size_t m_FreePrivateData = 6;
|
||||
const size_t m_SetPriority = 7;
|
||||
const size_t m_GetPriority = 8;
|
||||
const size_t m_PreLoad = 9;
|
||||
const size_t m_GetType = 10;
|
||||
const size_t m_SetLOD = 11;
|
||||
const size_t m_GetLOD = 12;
|
||||
const size_t m_GetLevelCount = 13;
|
||||
const size_t m_GetLevelDesc = 14;
|
||||
const size_t m_GetCubeMapSurface = 15;
|
||||
const size_t m_LockRect = 16;
|
||||
const size_t m_UnlockRect = 17;
|
||||
const size_t m_AddDirtyRect = 18;
|
||||
}
|
||||
namespace VMT_IDirect3DDevice8 {
|
||||
const size_t m_QueryInterface = 0;
|
||||
const size_t m_AddRef = 1;
|
||||
const size_t m_Release = 2;
|
||||
const size_t m_TestCooperativeLevel = 3;
|
||||
const size_t m_GetAvailableTextureMem = 4;
|
||||
const size_t m_ResourceManagerDiscardBytes = 5;
|
||||
const size_t m_GetDirect3D = 6;
|
||||
const size_t m_GetDeviceCaps = 7;
|
||||
const size_t m_GetDisplayMode = 8;
|
||||
const size_t m_GetCreationParameters = 9;
|
||||
const size_t m_SetCursorProperties = 10;
|
||||
const size_t m_SetCursorPosition = 11;
|
||||
const size_t m_ShowCursor = 12;
|
||||
const size_t m_CreateAdditionalSwapChain = 13;
|
||||
const size_t m_Reset = 14;
|
||||
const size_t m_Present = 15;
|
||||
const size_t m_GetBackBuffer = 16;
|
||||
const size_t m_GetRasterStatus = 17;
|
||||
const size_t m_SetGammaRamp = 18;
|
||||
const size_t m_GetGammaRamp = 19;
|
||||
const size_t m_CreateTexture = 20;
|
||||
const size_t m_CreateVolumeTexture = 21;
|
||||
const size_t m_CreateCubeTexture = 22;
|
||||
const size_t m_CreateVertexBuffer = 23;
|
||||
const size_t m_CreateIndexBuffer = 24;
|
||||
const size_t m_CreateRenderTarget = 25;
|
||||
const size_t m_CreateDepthStencilSurface = 26;
|
||||
const size_t m_CreateImageSurface = 27;
|
||||
const size_t m_CopyRects = 28;
|
||||
const size_t m_UpdateTexture = 29;
|
||||
const size_t m_GetFrontBuffer = 30;
|
||||
const size_t m_SetRenderTarget = 31;
|
||||
const size_t m_GetRenderTarget = 32;
|
||||
const size_t m_GetDepthStencilSurface = 33;
|
||||
const size_t m_BeginScene = 34;
|
||||
const size_t m_EndScene = 35;
|
||||
const size_t m_Clear = 36;
|
||||
const size_t m_SetTransform = 37;
|
||||
const size_t m_GetTransform = 38;
|
||||
const size_t m_MultiplyTransform = 39;
|
||||
const size_t m_SetViewport = 40;
|
||||
const size_t m_GetViewport = 41;
|
||||
const size_t m_SetMaterial = 42;
|
||||
const size_t m_GetMaterial = 43;
|
||||
const size_t m_SetLight = 44;
|
||||
const size_t m_GetLight = 45;
|
||||
const size_t m_LightEnable = 46;
|
||||
const size_t m_GetLightEnable = 47;
|
||||
const size_t m_SetClipPlane = 48;
|
||||
const size_t m_GetClipPlane = 49;
|
||||
const size_t m_SetRenderState = 50;
|
||||
const size_t m_GetRenderState = 51;
|
||||
const size_t m_BeginStateBlock = 52;
|
||||
const size_t m_EndStateBlock = 53;
|
||||
const size_t m_ApplyStateBlock = 54;
|
||||
const size_t m_CaptureStateBlock = 55;
|
||||
const size_t m_DeleteStateBlock = 56;
|
||||
const size_t m_CreateStateBlock = 57;
|
||||
const size_t m_SetClipStatus = 58;
|
||||
const size_t m_GetClipStatus = 59;
|
||||
const size_t m_GetTexture = 60;
|
||||
const size_t m_SetTexture = 61;
|
||||
const size_t m_GetTextureStageState = 62;
|
||||
const size_t m_SetTextureStageState = 63;
|
||||
const size_t m_ValidateDevice = 64;
|
||||
const size_t m_GetInfo = 65;
|
||||
const size_t m_SetPaletteEntries = 66;
|
||||
const size_t m_GetPaletteEntries = 67;
|
||||
const size_t m_SetCurrentTexturePalette = 68;
|
||||
const size_t m_GetCurrentTexturePalette = 69;
|
||||
const size_t m_DrawPrimitive = 70;
|
||||
const size_t m_DrawIndexedPrimitive = 71;
|
||||
const size_t m_DrawPrimitiveUP = 72;
|
||||
const size_t m_DrawIndexedPrimitiveUP = 73;
|
||||
const size_t m_ProcessVertices = 74;
|
||||
const size_t m_CreateVertexShader = 75;
|
||||
const size_t m_SetVertexShader = 76;
|
||||
const size_t m_GetVertexShader = 77;
|
||||
const size_t m_DeleteVertexShader = 78;
|
||||
const size_t m_SetVertexShaderConstant = 79;
|
||||
const size_t m_GetVertexShaderConstant = 80;
|
||||
const size_t m_GetVertexShaderDeclaration = 81;
|
||||
const size_t m_GetVertexShaderFunction = 82;
|
||||
const size_t m_SetStreamSource = 83;
|
||||
const size_t m_GetStreamSource = 84;
|
||||
const size_t m_SetIndices = 85;
|
||||
const size_t m_GetIndices = 86;
|
||||
const size_t m_CreatePixelShader = 87;
|
||||
const size_t m_SetPixelShader = 88;
|
||||
const size_t m_GetPixelShader = 89;
|
||||
const size_t m_DeletePixelShader = 90;
|
||||
const size_t m_SetPixelShaderConstant = 91;
|
||||
const size_t m_GetPixelShaderConstant = 92;
|
||||
const size_t m_GetPixelShaderFunction = 93;
|
||||
const size_t m_DrawRectPatch = 94;
|
||||
const size_t m_DrawTriPatch = 95;
|
||||
const size_t m_DeletePatch = 96;
|
||||
}
|
||||
namespace VMT_IDirect3DIndexBuffer8_IDirect3DResource8 {
|
||||
const size_t m_QueryInterface = 0;
|
||||
const size_t m_AddRef = 1;
|
||||
const size_t m_Release = 2;
|
||||
const size_t m_GetDevice = 3;
|
||||
const size_t m_SetPrivateData = 4;
|
||||
const size_t m_GetPrivateData = 5;
|
||||
const size_t m_FreePrivateData = 6;
|
||||
const size_t m_SetPriority = 7;
|
||||
const size_t m_GetPriority = 8;
|
||||
const size_t m_PreLoad = 9;
|
||||
const size_t m_GetType = 10;
|
||||
const size_t m_Lock = 11;
|
||||
const size_t m_Unlock = 12;
|
||||
const size_t m_GetDesc = 13;
|
||||
}
|
||||
namespace VMT_IDirect3DResource8 {
|
||||
const size_t m_QueryInterface = 0;
|
||||
const size_t m_AddRef = 1;
|
||||
const size_t m_Release = 2;
|
||||
const size_t m_GetDevice = 3;
|
||||
const size_t m_SetPrivateData = 4;
|
||||
const size_t m_GetPrivateData = 5;
|
||||
const size_t m_FreePrivateData = 6;
|
||||
const size_t m_SetPriority = 7;
|
||||
const size_t m_GetPriority = 8;
|
||||
const size_t m_PreLoad = 9;
|
||||
const size_t m_GetType = 10;
|
||||
}
|
||||
namespace VMT_IDirect3DSurface8 {
|
||||
const size_t m_QueryInterface = 0;
|
||||
const size_t m_AddRef = 1;
|
||||
const size_t m_Release = 2;
|
||||
const size_t m_GetDevice = 3;
|
||||
const size_t m_SetPrivateData = 4;
|
||||
const size_t m_GetPrivateData = 5;
|
||||
const size_t m_FreePrivateData = 6;
|
||||
const size_t m_GetContainer = 7;
|
||||
const size_t m_GetDesc = 8;
|
||||
const size_t m_LockRect = 9;
|
||||
const size_t m_UnlockRect = 10;
|
||||
}
|
||||
namespace VMT_IDirect3DSwapChain8 {
|
||||
const size_t m_QueryInterface = 0;
|
||||
const size_t m_AddRef = 1;
|
||||
const size_t m_Release = 2;
|
||||
const size_t m_Present = 3;
|
||||
const size_t m_GetBackBuffer = 4;
|
||||
}
|
||||
namespace VMT_IDirect3DTexture8_IDirect3DBaseTexture8 {
|
||||
const size_t m_QueryInterface = 0;
|
||||
const size_t m_AddRef = 1;
|
||||
const size_t m_Release = 2;
|
||||
const size_t m_GetDevice = 3;
|
||||
const size_t m_SetPrivateData = 4;
|
||||
const size_t m_GetPrivateData = 5;
|
||||
const size_t m_FreePrivateData = 6;
|
||||
const size_t m_SetPriority = 7;
|
||||
const size_t m_GetPriority = 8;
|
||||
const size_t m_PreLoad = 9;
|
||||
const size_t m_GetType = 10;
|
||||
const size_t m_SetLOD = 11;
|
||||
const size_t m_GetLOD = 12;
|
||||
const size_t m_GetLevelCount = 13;
|
||||
const size_t m_GetLevelDesc = 14;
|
||||
const size_t m_GetSurfaceLevel = 15;
|
||||
const size_t m_LockRect = 16;
|
||||
const size_t m_UnlockRect = 17;
|
||||
const size_t m_AddDirtyRect = 18;
|
||||
}
|
||||
namespace VMT_IDirect3DVertexBuffer8_IDirect3DResource8 {
|
||||
const size_t m_QueryInterface = 0;
|
||||
const size_t m_AddRef = 1;
|
||||
const size_t m_Release = 2;
|
||||
const size_t m_GetDevice = 3;
|
||||
const size_t m_SetPrivateData = 4;
|
||||
const size_t m_GetPrivateData = 5;
|
||||
const size_t m_FreePrivateData = 6;
|
||||
const size_t m_SetPriority = 7;
|
||||
const size_t m_GetPriority = 8;
|
||||
const size_t m_PreLoad = 9;
|
||||
const size_t m_GetType = 10;
|
||||
const size_t m_Lock = 11;
|
||||
const size_t m_Unlock = 12;
|
||||
const size_t m_GetDesc = 13;
|
||||
}
|
||||
namespace VMT_IDirect3DVolume8 {
|
||||
const size_t m_QueryInterface = 0;
|
||||
const size_t m_AddRef = 1;
|
||||
const size_t m_Release = 2;
|
||||
const size_t m_GetDevice = 3;
|
||||
const size_t m_SetPrivateData = 4;
|
||||
const size_t m_GetPrivateData = 5;
|
||||
const size_t m_FreePrivateData = 6;
|
||||
const size_t m_GetContainer = 7;
|
||||
const size_t m_GetDesc = 8;
|
||||
const size_t m_LockBox = 9;
|
||||
const size_t m_UnlockBox = 10;
|
||||
}
|
||||
namespace VMT_IDirect3DVolumeTexture8_IDirect3DBaseTexture8 {
|
||||
const size_t m_QueryInterface = 0;
|
||||
const size_t m_AddRef = 1;
|
||||
const size_t m_Release = 2;
|
||||
const size_t m_GetDevice = 3;
|
||||
const size_t m_SetPrivateData = 4;
|
||||
const size_t m_GetPrivateData = 5;
|
||||
const size_t m_FreePrivateData = 6;
|
||||
const size_t m_SetPriority = 7;
|
||||
const size_t m_GetPriority = 8;
|
||||
const size_t m_PreLoad = 9;
|
||||
const size_t m_GetType = 10;
|
||||
const size_t m_SetLOD = 11;
|
||||
const size_t m_GetLOD = 12;
|
||||
const size_t m_GetLevelCount = 13;
|
||||
const size_t m_GetLevelDesc = 14;
|
||||
const size_t m_GetVolumeLevel = 15;
|
||||
const size_t m_LockBox = 16;
|
||||
const size_t m_UnlockBox = 17;
|
||||
const size_t m_AddDirtyBox = 18;
|
||||
}
|
124
ScrapHacks/src/Hook.hpp
Normal file
124
ScrapHacks/src/Hook.hpp
Normal file
|
@ -0,0 +1,124 @@
|
|||
#pragma once
|
||||
#include <Windows.h>
|
||||
|
||||
#include <functional>
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
|
||||
using namespace std;
|
||||
|
||||
class Hook {
|
||||
private:
|
||||
MEMORY_BASIC_INFORMATION mbi;
|
||||
void *orig;
|
||||
void *detour;
|
||||
bool enabled;
|
||||
uint8_t orig_bytes[6];
|
||||
uint8_t jmp_bytes[6];
|
||||
static map<uintptr_t, shared_ptr<Hook>> hooks;
|
||||
|
||||
public:
|
||||
Hook(void *func, void *detour) {
|
||||
uintptr_t dest = reinterpret_cast<uintptr_t>(detour);
|
||||
uintptr_t src = reinterpret_cast<uintptr_t>(func);
|
||||
this->orig = func;
|
||||
this->detour = detour;
|
||||
this->jmp_bytes[0] = 0x68; // push
|
||||
this->jmp_bytes[1] = (dest >> 0) & 0xff;
|
||||
this->jmp_bytes[2] = (dest >> 8) & 0xff;
|
||||
this->jmp_bytes[3] = (dest >> 16) & 0xff;
|
||||
this->jmp_bytes[4] = (dest >> 24) & 0xff;
|
||||
this->jmp_bytes[5] = 0xC3; // ret
|
||||
VirtualQuery(func, &mbi, sizeof(mbi));
|
||||
VirtualProtect(mbi.BaseAddress, mbi.RegionSize, PAGE_EXECUTE_READWRITE,
|
||||
&mbi.Protect);
|
||||
memcpy(this->orig_bytes, this->orig, 1 + 4 + 1);
|
||||
VirtualProtect(mbi.BaseAddress, mbi.RegionSize, mbi.Protect, NULL);
|
||||
this->enabled = false;
|
||||
}
|
||||
|
||||
~Hook() {
|
||||
cout << "Unhooking: [" << this->orig << " <- " << this->detour << "]"
|
||||
<< endl;
|
||||
this->disable();
|
||||
}
|
||||
|
||||
static void addr(void *addr, void *detour) {
|
||||
cout << "Hooking: [" << addr << " -> " << detour << "]" << endl;
|
||||
uintptr_t key = reinterpret_cast<uintptr_t>(detour);
|
||||
hooks[key] = make_shared<Hook>(addr, detour);
|
||||
hooks[key]->enable();
|
||||
}
|
||||
|
||||
static void module(const char *mod, const char *func, void *detour) {
|
||||
cout << "Hooking: [" << mod << "]." << func << " -> " << detour << endl;
|
||||
void *addr = GetProcAddress(GetModuleHandle(mod), func);
|
||||
if (addr != NULL) {
|
||||
Hook::addr(addr, detour);
|
||||
} else {
|
||||
cerr << "[" << mod << "]." << func << " not found!" << endl;
|
||||
};
|
||||
}
|
||||
|
||||
static shared_ptr<Hook> get(void *func) {
|
||||
uintptr_t addr = reinterpret_cast<uintptr_t>(func);
|
||||
return Hook::get(addr);
|
||||
}
|
||||
|
||||
static shared_ptr<Hook> get(uintptr_t addr) { return hooks.at(addr); }
|
||||
|
||||
static size_t drop(void *func) {
|
||||
uintptr_t addr = reinterpret_cast<uintptr_t>(func);
|
||||
return Hook::drop(addr);
|
||||
}
|
||||
|
||||
static size_t drop(uintptr_t addr) { return hooks.erase(addr); }
|
||||
|
||||
static void clear() {
|
||||
cout << "Clearing Hooks" << endl;
|
||||
for (pair<uintptr_t, shared_ptr<Hook>> h : hooks) {
|
||||
h.second->disable();
|
||||
}
|
||||
return hooks.clear();
|
||||
}
|
||||
|
||||
void disable() {
|
||||
if (enabled) {
|
||||
// cout << "Disabling: [" << this->orig << " <- " << this->detour <<
|
||||
// "]"
|
||||
// << endl;
|
||||
VirtualProtect(mbi.BaseAddress, mbi.RegionSize,
|
||||
PAGE_EXECUTE_READWRITE, NULL);
|
||||
memcpy(this->orig, this->orig_bytes, 1 + 4 + 1);
|
||||
VirtualProtect(mbi.BaseAddress, mbi.RegionSize, mbi.Protect, NULL);
|
||||
enabled = false;
|
||||
}
|
||||
}
|
||||
void enable() {
|
||||
if (!this->enabled) {
|
||||
// cout << "Enabling: [" << this->orig << " -> " << this->detour <<
|
||||
// "]" << endl;
|
||||
VirtualProtect(mbi.BaseAddress, mbi.RegionSize,
|
||||
PAGE_EXECUTE_READWRITE, NULL);
|
||||
memcpy(this->orig, this->jmp_bytes, 1 + 4 + 1);
|
||||
VirtualProtect(mbi.BaseAddress, mbi.RegionSize, mbi.Protect, NULL);
|
||||
this->enabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename F, typename... Args> void func_void(Args... args) {
|
||||
this->disable();
|
||||
reinterpret_cast<F>(this->orig)(args...);
|
||||
this->enable();
|
||||
return;
|
||||
}
|
||||
|
||||
template <typename F, typename... Args> auto func(Args... args) {
|
||||
this->disable();
|
||||
auto ret = reinterpret_cast<F>(this->orig)(args...);
|
||||
this->enable();
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
|
||||
map<uintptr_t, shared_ptr<Hook>> Hook::hooks;
|
58
ScrapHacks/src/Py_Utils.hpp
Normal file
58
ScrapHacks/src/Py_Utils.hpp
Normal file
|
@ -0,0 +1,58 @@
|
|||
#pragma once
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
#include "Structures.hpp"
|
||||
|
||||
using namespace std;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
259
ScrapHacks/src/REPL.hpp
Normal file
259
ScrapHacks/src/REPL.hpp
Normal file
|
@ -0,0 +1,259 @@
|
|||
#pragma once
|
||||
#include <Windows.h>
|
||||
|
||||
#include <regex>
|
||||
#include <sstream>
|
||||
|
||||
#include "Scrapland.hpp"
|
||||
#include "Util.hpp"
|
||||
|
||||
void DllUnload();
|
||||
|
||||
|
||||
void unhook_d3d8();
|
||||
void hook_d3d8();
|
||||
|
||||
typedef void(_cdecl *t_cmd_func)(vector<string>);
|
||||
|
||||
struct t_cmd {
|
||||
t_cmd_func func;
|
||||
const char* usage;
|
||||
const char* doc;
|
||||
};
|
||||
|
||||
void cmd_help(vector<string>);
|
||||
|
||||
DWORD
|
||||
get_protection(void *addr) {
|
||||
MEMORY_BASIC_INFORMATION mbi;
|
||||
VirtualQuery(addr, &mbi, sizeof(mbi));
|
||||
return mbi.Protect;
|
||||
}
|
||||
|
||||
void cmd_write(vector<string> args) {
|
||||
MEMORY_BASIC_INFORMATION mbi;
|
||||
if (args.size() != 2) {
|
||||
scrap_log(ERR_COLOR, "Usage: $w <addr> <data(hex)>\n");
|
||||
return;
|
||||
}
|
||||
void *addr = 0;
|
||||
vector<uint8_t> data;
|
||||
try {
|
||||
addr = (void *)stoull(args[0], 0, 16);
|
||||
data = fromhex(args[1]);
|
||||
} catch (exception e) {
|
||||
scrap_log(ERR_COLOR, "ERROR!\n");
|
||||
return;
|
||||
}
|
||||
uint8_t *buffer = new uint8_t[data.size()];
|
||||
size_t idx = 0;
|
||||
for (uint8_t v : data) {
|
||||
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);
|
||||
if (buffer) {
|
||||
free(buffer);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
void cmd_read(vector<string> args) {
|
||||
MEMORY_BASIC_INFORMATION mbi;
|
||||
if (args.size() != 2) {
|
||||
scrap_log(ERR_COLOR, "Usage: $r <addr> <size>\n");
|
||||
return;
|
||||
}
|
||||
uintptr_t addr = UINTPTR_MAX;
|
||||
size_t size = 0;
|
||||
unsigned char *buffer;
|
||||
try {
|
||||
addr = stoull(args[0], 0, 16);
|
||||
size = stoull(args[1]);
|
||||
buffer = new unsigned char[size];
|
||||
} catch (exception e) {
|
||||
scrap_log(ERR_COLOR, "ERROR!\n");
|
||||
return;
|
||||
}
|
||||
void *mptr = reinterpret_cast<void *>(addr);
|
||||
if (VirtualQuery(mptr, &mbi, sizeof(mbi)) == 0) {
|
||||
scrap_log(ERR_COLOR, "ERROR!\n");
|
||||
return;
|
||||
};
|
||||
VirtualProtect(mbi.BaseAddress, mbi.RegionSize, PAGE_EXECUTE_READWRITE,
|
||||
&mbi.Protect);
|
||||
string hxd = hexdump_s(mptr, size);
|
||||
scrap_log(INFO_COLOR, hxd.c_str());
|
||||
VirtualProtect(mbi.BaseAddress, mbi.RegionSize, mbi.Protect, NULL);
|
||||
if (buffer) {
|
||||
free(buffer);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
void cmd_dx8(vector<string> args) {
|
||||
if (args.size()!=1) {
|
||||
scrap_log(ERR_COLOR, "Usage: $dx8 (hook|unhook)\n");
|
||||
return;
|
||||
}
|
||||
if (args[0]=="hook") {
|
||||
hook_d3d8();
|
||||
scrap_log(INFO_COLOR,"DX8 hooked!\n");
|
||||
return;
|
||||
}
|
||||
if (args[0]=="unhook") {
|
||||
unhook_d3d8();
|
||||
scrap_log(INFO_COLOR,"DX8 unhooked!\n");
|
||||
return;
|
||||
};
|
||||
scrap_log(ERR_COLOR,"Invalid argument!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
void cmd_dump_py(vector<string> args) {
|
||||
stringstream out;
|
||||
for (auto mod : Py) {
|
||||
for (auto meth : mod.second.methods) {
|
||||
out << mod.first << "." << meth.first << " @ "
|
||||
<< meth.second->ml_meth << endl;
|
||||
}
|
||||
}
|
||||
scrap_log(INFO_COLOR,out.str().c_str());
|
||||
}
|
||||
|
||||
void cmd_dump_ents(vector<string> args) {
|
||||
stringstream out;
|
||||
out << "Entities:" << endl;
|
||||
dump_ht(ptr<HashTable<Entity>>(P_WORLD, O_ENTS), &out);
|
||||
out << "Entity Lists:" << endl;
|
||||
dump_ht(ptr<HashTable<EntityList>>(P_WORLD, O_ENTLISTS), &out);
|
||||
scrap_log(INFO_COLOR,out.str().c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
void cmd_toggle_overlay(vector<string> args) {
|
||||
overlay=!overlay;
|
||||
if (overlay) {
|
||||
scrap_log(INFO_COLOR,"Overlay enabled!\n");
|
||||
} else {
|
||||
scrap_log(INFO_COLOR,"Overlay disabled!\n");
|
||||
}
|
||||
}
|
||||
|
||||
void cmd_print_alarm(vector<string> args) {
|
||||
stringstream out;
|
||||
float *alarm = ptr<float>(P_WORLD, O_ALARM);
|
||||
float *alarm_grow = ptr<float>(P_WORLD, O_ALARM_GROW);
|
||||
out << "Alarm: " << alarm[0] << " + " << alarm_grow[0] << endl;
|
||||
scrap_log(INFO_COLOR,out.str().c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
void cmd_unload(vector<string> args) {
|
||||
scrap_log(INFO_COLOR,"Unloading ScrapHacks... bye!\n");
|
||||
DllUnload();
|
||||
}
|
||||
|
||||
static map<string, t_cmd> commands = {
|
||||
{"w", {
|
||||
cmd_write,
|
||||
"Usage: $w <addr> <data(hex)>",
|
||||
"Write memory"
|
||||
}},
|
||||
{"r", {
|
||||
cmd_read,
|
||||
"Usage: $r <addr> <num_bytes>",
|
||||
"Read memory"
|
||||
}},
|
||||
{"unload", {
|
||||
cmd_unload,
|
||||
"Usage: $unload",
|
||||
"Unload ScrapHacks"
|
||||
}},
|
||||
{"dx8", {
|
||||
cmd_dx8,
|
||||
"Usage: $dx8 (hook|unhook)",
|
||||
"Hook/Unhook DirectX 8 functions"
|
||||
}},
|
||||
{"dump_py",{
|
||||
cmd_dump_py,
|
||||
"Usage: $dump_py",
|
||||
"Dump python modules to console"
|
||||
}},
|
||||
{"overlay",{
|
||||
cmd_toggle_overlay,
|
||||
"Usage: $overlay",
|
||||
"Toggle DX8 Overlay"
|
||||
}},
|
||||
{"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;
|
||||
}
|
||||
if (!commands.count(args[0])) {
|
||||
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 handle_command(const char *_cmd) {
|
||||
scrap_log(ERR_COLOR, "$");
|
||||
scrap_log(ERR_COLOR, _cmd);
|
||||
scrap_log(ERR_COLOR, "\n");
|
||||
cout << "CMD: '" << _cmd << "'" << endl;
|
||||
vector<string> cmd = 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;
|
||||
}
|
177
ScrapHacks/src/ScrapHack.cpp
Normal file
177
ScrapHacks/src/ScrapHack.cpp
Normal file
|
@ -0,0 +1,177 @@
|
|||
|
||||
#include <functional>
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <typeinfo>
|
||||
#include <vector>
|
||||
|
||||
#include <Windows.h>
|
||||
|
||||
// Socket stuff
|
||||
|
||||
#include <Ws2tcpip.h>
|
||||
#include <stdio.h>
|
||||
#include <winsock2.h>
|
||||
|
||||
using namespace std;
|
||||
|
||||
#include "D3D8_Hook.hpp"
|
||||
#include "Hook.hpp"
|
||||
#include "Py_Utils.hpp"
|
||||
#include "REPL.hpp"
|
||||
#include "Scrapland.hpp"
|
||||
#include "Structures.hpp"
|
||||
#include "Util.hpp"
|
||||
|
||||
bool initialized = false;
|
||||
bool running = true;
|
||||
|
||||
HMODULE hMod = nullptr;
|
||||
|
||||
void DllUnload();
|
||||
int hooked_console(const char *);
|
||||
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() {
|
||||
Hook::addr(reinterpret_cast<void *>(P_SCRAP_EXIT), hook_exit);
|
||||
Hook::addr(reinterpret_cast<void *>(P_CON_HANDLER), hooked_console);
|
||||
}
|
||||
|
||||
void MainLoop() {
|
||||
setup_hooks();
|
||||
overlay = true;
|
||||
cout << "[*] Starting main Loop" << endl;
|
||||
cout << endl;
|
||||
cout << "[F2 ] Redirect game console to ScapHacks console" << endl;
|
||||
cout << "[F3 ] Unload ScrapHacks" << endl;
|
||||
cout << "[F5 ] Show Overlay" << endl;
|
||||
cout << "[F6 ] Show Alarm status" << endl;
|
||||
cout << "[F7 ] Set Money to 0x7fffffff" << endl;
|
||||
cout << "[F8 ] Dump python modules" << endl;
|
||||
cout << "[F9 ] Dump Entity hashtable" << endl;
|
||||
cout << "[F10] Enable python tracing" << endl;
|
||||
cout << "[ F ] \"Handbrake\" (*Will* crash the game after some time!)"
|
||||
<< endl;
|
||||
|
||||
while (running) {
|
||||
Sleep(100);
|
||||
while (key_down('F')) {
|
||||
scrap_exec("dbg.brake()");
|
||||
}
|
||||
if (key_down_norepeat(VK_F3)) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (key_down_norepeat(VK_F7)) {
|
||||
int32_t *money = ptr<int32_t>(P_WORLD, O_MONEY);
|
||||
money[0] = 0x7fffffff;
|
||||
}
|
||||
|
||||
if (key_down_norepeat(VK_F9)) {
|
||||
cout << "Entities:" << endl;
|
||||
dump_ht(ptr<HashTable<Entity>>(P_WORLD, O_ENTS));
|
||||
cout << "Entity Lists:" << endl;
|
||||
dump_ht(ptr<HashTable<EntityList>>(P_WORLD, O_ENTLISTS));
|
||||
}
|
||||
if (key_down_norepeat(VK_F10)) {
|
||||
scrap_exec("dbg.settrace()");
|
||||
}
|
||||
}
|
||||
FreeLibraryAndExitThread(hMod, 0);
|
||||
}
|
||||
|
||||
void InitConsole() {
|
||||
char me[1024];
|
||||
GetModuleFileName(hMod, me, 1024);
|
||||
SetupConsole(me);
|
||||
}
|
||||
|
||||
int hooked_console(const char *cmd) {
|
||||
typedef decltype(&hooked_console) t_func;
|
||||
if (cmd[0] == '$') {
|
||||
handle_command(++cmd);
|
||||
return 0;
|
||||
}
|
||||
shared_ptr<Hook> hook = Hook::get(hooked_console);
|
||||
int ret = hook->func<t_func>(cmd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void hook_exit() {
|
||||
typedef decltype(&hook_exit) t_func;
|
||||
shared_ptr<Hook> hook = Hook::get(hook_exit);
|
||||
DllUnload();
|
||||
HWND hMainWindow = ptr<HWND>(0x7FA830, 0x7c)[0];
|
||||
SendMessage(hMainWindow, WM_CLOSE, 0, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
void DllInit(HMODULE mod) {
|
||||
hMod = mod;
|
||||
char mfn[1024];
|
||||
InitConsole();
|
||||
GetModuleFileNameA(0, mfn, 1024);
|
||||
Py = get_modules(P_PY_MODS);
|
||||
cout << "[+] ScrapHacks v0.1 Loaded in " << mfn << " (PID: " << std::hex
|
||||
<< GetCurrentProcessId() << std::dec << ")" << endl;
|
||||
|
||||
initialized = true;
|
||||
cout << "[*] World: " << ptr<void>(P_WORLD, 0) << endl;
|
||||
cout << "[*] Importing python dbg module" << endl;
|
||||
scrap_exec("import dbg");
|
||||
scrap_log(INFO_COLOR, "=== ScrapHacks loaded! ===\n");
|
||||
scrap_log(INFO_COLOR, "=== Use '$help' for help! ===\n");
|
||||
CreateThread(NULL, NULL, (LPTHREAD_START_ROUTINE)MainLoop, NULL, 0, 0);
|
||||
cout << "[*] Starting message pump" << endl;
|
||||
MSG msg;
|
||||
while (GetMessage(&msg, NULL, 0, 0)) {
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessage(&msg);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
void *H_port_FixupExtension(char *name, char *filename) {
|
||||
Hook::drop(H_port_FixupExtension);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void *H_PyEval_CallObjectWithKeywords(void *func, void *arg, void *kwarg) {
|
||||
Hook::drop(H_PyEval_CallObjectWithKeywords);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void DllPreInit() {
|
||||
Hook::addr(reinterpret_cast<void *>(0x5a9ca0), H_port_FixupExtension);
|
||||
Hook::addr(reinterpret_cast<void *>(0x5cdb00),
|
||||
H_PyEval_CallObjectWithKeywords);
|
||||
}
|
||||
|
||||
void DllUnload() {
|
||||
SetConsoleCtrlHandler(NULL, false);
|
||||
unhook_d3d8();
|
||||
Hook::clear();
|
||||
scrap_log(0xff0000, "ScrapHacks unloaded!\n");
|
||||
cout << "[+] ScrapHacks unloaded, you can now close the console!" << endl;
|
||||
FreeConsole();
|
||||
DestroyWindow(GetConsoleWindow());
|
||||
return;
|
||||
}
|
53
ScrapHacks/src/Scrapland.hpp
Normal file
53
ScrapHacks/src/Scrapland.hpp
Normal file
|
@ -0,0 +1,53 @@
|
|||
#pragma once
|
||||
|
||||
// OFFSETS
|
||||
#define O_MONEY 0x2090
|
||||
#define O_ALARM 0x1C6C
|
||||
#define O_ALARM_GROW 0x1C68
|
||||
#define O_ENTS 0x4
|
||||
#define O_ENTLISTS 0x2b8
|
||||
|
||||
// POINTERS
|
||||
#define P_WORLD 0x7FE944
|
||||
#define P_PY_MODS 0x79C698
|
||||
|
||||
// FUNCTION ADDRESSES
|
||||
#define P_CON_HANDLER 0x402190
|
||||
#define P_SCRAP_LOG 0x4134C0
|
||||
#define P_SCRAP_EXEC 0x5a8390
|
||||
#define P_SCRAP_EXIT 0x4010c0
|
||||
#define P_D3DCHECK 0x602a70
|
||||
#define P_D3DDEV 0x852914
|
||||
#define P_Py_InitModule 0x5A8FB0
|
||||
#define P_PyArg_ParseTuple 0x5bb9d0
|
||||
|
||||
|
||||
#define MSG_COLOR scrap_RGB(255,128,0)
|
||||
#define ERR_COLOR scrap_RGB(255,0,0)
|
||||
#define INFO_COLOR scrap_RGB(0,0,255)
|
||||
|
||||
|
||||
uint32_t scrap_RGB(uint8_t r,uint8_t g,uint8_t b) {
|
||||
return r|g<<8|b<<16;
|
||||
}
|
||||
|
||||
// FUNCTION TYPES
|
||||
typedef int(_cdecl *t_scrap_log)(unsigned int color, const char *message);
|
||||
typedef int(_cdecl *t_scrap_exec)(const char *code);
|
||||
typedef int(_cdecl *t_PyArg_ParseTuple)(void *PyObj, char *format, ...);
|
||||
typedef int(_cdecl *t_Py_InitModule)(const char *name, void *methods,
|
||||
const char *doc, void *passthrough,
|
||||
int module_api_version);
|
||||
|
||||
// GLOBAL FUNCTIONS
|
||||
auto scrap_exec = (t_scrap_exec)P_SCRAP_EXEC;
|
||||
auto pyarg_parsetuple = (t_PyArg_ParseTuple)P_PyArg_ParseTuple;
|
||||
auto py_initmodule = (t_Py_InitModule)P_Py_InitModule;
|
||||
|
||||
int scrap_log(unsigned int color,const char* msg) {
|
||||
return ((t_scrap_log)P_SCRAP_LOG)(color,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);
|
||||
}
|
54
ScrapHacks/src/Structures.hpp
Normal file
54
ScrapHacks/src/Structures.hpp
Normal file
|
@ -0,0 +1,54 @@
|
|||
#pragma once
|
||||
template <typename T> struct HashTableEntry;
|
||||
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;
|
||||
};
|
||||
|
||||
struct Entity {
|
||||
void *vmt;
|
||||
const char *name;
|
||||
};
|
||||
|
||||
struct EntityList {
|
||||
const char *name;
|
||||
void *unk_1;
|
||||
void *unk_2;
|
||||
const char *mod;
|
||||
const char *func;
|
||||
};
|
||||
|
||||
template <typename T> struct HashTable {
|
||||
uint32_t size;
|
||||
HashTableEntry<T> **chains;
|
||||
};
|
||||
|
||||
template <typename T> struct HashTableEntry {
|
||||
T *data;
|
||||
const char *name;
|
||||
HashTableEntry *next;
|
||||
};
|
375
ScrapHacks/src/Util.hpp
Normal file
375
ScrapHacks/src/Util.hpp
Normal file
|
@ -0,0 +1,375 @@
|
|||
#pragma once
|
||||
#include <TlHelp32.h>
|
||||
#include <Windows.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "Structures.hpp"
|
||||
#include "Py_Utils.hpp"
|
||||
|
||||
using namespace std;
|
||||
|
||||
#define DLL_EXPORT extern "C" __declspec(dllexport)
|
||||
|
||||
template <typename T> void **GetVTable(T *obj) {
|
||||
void *addr = reinterpret_cast<void **>(obj)[0];
|
||||
return (void **)(*(void **)addr);
|
||||
}
|
||||
|
||||
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 (!AttachConsole(-1)) {
|
||||
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;
|
||||
}
|
||||
|
||||
string hexdump_s(void *addr, size_t count=0xff) {
|
||||
ostringstream out;
|
||||
uintptr_t offset=reinterpret_cast<uintptr_t>(addr);
|
||||
for (size_t i = 0; i < count; ++i) {
|
||||
unsigned int val = (unsigned int)(((unsigned char *)(offset+i))[0]);
|
||||
if ((i % 16) == 0) {
|
||||
out << endl;
|
||||
out << setfill('0') << setw(8) << std::hex << std::uppercase << (offset+i) << ": ";
|
||||
}
|
||||
out << setfill('0') << setw(2) << std::hex << val << " ";
|
||||
}
|
||||
out << endl;
|
||||
return out.str();
|
||||
}
|
||||
|
||||
void hexdump(void *addr, size_t count=0xff) {
|
||||
uintptr_t offset=reinterpret_cast<uintptr_t>(addr);
|
||||
for (size_t i = 0; i < count; ++i) {
|
||||
unsigned int val = (unsigned int)(((unsigned char *)(offset+i))[0]);
|
||||
if ((i % 16) == 0) {
|
||||
cout << endl;
|
||||
cout << setfill('0') << setw(8) << std::hex << std::uppercase << (offset+i) << ": ";
|
||||
}
|
||||
cout << setfill('0') << setw(2) << std::hex << val << " ";
|
||||
}
|
||||
cout << endl;
|
||||
return;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
template <typename T>
|
||||
void __to_str(ostream& o, T t)
|
||||
{
|
||||
o << t;
|
||||
}
|
||||
|
||||
template<typename T, typename... Args>
|
||||
void __to_str(ostream& o, T t, Args... args) // recursive variadic function
|
||||
{
|
||||
__to_str(o, t);
|
||||
__to_str(o, args...);
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
const char* to_str(Args... args)
|
||||
{
|
||||
ostringstream oss;
|
||||
__to_str(oss, args...);
|
||||
return oss.str().c_str();
|
||||
}
|
||||
|
||||
DWORD
|
||||
PPID() {
|
||||
DWORD PID = GetCurrentProcessId();
|
||||
HANDLE hSnapShot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
|
||||
PROCESSENTRY32 procentry;
|
||||
if (hSnapShot == INVALID_HANDLE_VALUE) {
|
||||
cout << GetLastErrorAsString() << endl;
|
||||
return -1;
|
||||
}
|
||||
if (Process32First(hSnapShot, &procentry)) {
|
||||
do {
|
||||
if (procentry.th32ProcessID == PID) {
|
||||
CloseHandle(hSnapShot);
|
||||
return procentry.th32ParentProcessID;
|
||||
}
|
||||
procentry.dwSize = sizeof(PROCESSENTRY32);
|
||||
} while (Process32Next(hSnapShot, &procentry));
|
||||
}
|
||||
CloseHandle(hSnapShot);
|
||||
return -1;
|
||||
}
|
||||
|
||||
vector<uint8_t> fromhex(string input) {
|
||||
vector<uint8_t> ret = {};
|
||||
if (input.size() % 2) {
|
||||
return ret;
|
||||
}
|
||||
transform(input.begin(), input.end(), input.begin(), ::toupper);
|
||||
string hc = "0123456789ABCDEF";
|
||||
int v = 0;
|
||||
size_t n = 0;
|
||||
size_t idx;
|
||||
for (unsigned char c : input) {
|
||||
idx = hc.find(c);
|
||||
if (idx != size_t(-1)) {
|
||||
if ((n++) % 2 == 0) {
|
||||
v = hc.find(c) << 4;
|
||||
} else {
|
||||
v |= hc.find(c);
|
||||
ret.push_back(v);
|
||||
}
|
||||
} else {
|
||||
cout << "Invalid Character in hex string" << endl;
|
||||
ret.clear();
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
vector<string> split(string str, char sep) {
|
||||
vector<string> ret;
|
||||
string part;
|
||||
for (auto n : str) {
|
||||
if (n == sep) {
|
||||
ret.push_back(part);
|
||||
part.clear();
|
||||
} else {
|
||||
part = part + n;
|
||||
}
|
||||
}
|
||||
if (part != "")
|
||||
ret.push_back(part);
|
||||
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;
|
||||
}
|
31
ScrapHacks/src/dllmain.cpp
Normal file
31
ScrapHacks/src/dllmain.cpp
Normal file
|
@ -0,0 +1,31 @@
|
|||
|
||||
#include <Windows.h>
|
||||
|
||||
|
||||
#define DLL_EXPORT extern "C" __declspec(dllexport)
|
||||
|
||||
using namespace std;
|
||||
|
||||
void DllInit(HMODULE);
|
||||
void DllUnload();
|
||||
void DllPreInit();
|
||||
|
||||
HANDLE hThread = INVALID_HANDLE_VALUE;
|
||||
bool loaded = false;
|
||||
HMODULE mod = nullptr;
|
||||
|
||||
DLL_EXPORT void initScrapHack() {
|
||||
DllPreInit();
|
||||
if (!loaded) {
|
||||
hThread = CreateThread(NULL, NULL, (LPTHREAD_START_ROUTINE)DllInit, mod,
|
||||
0, 0);
|
||||
CloseHandle(hThread);
|
||||
loaded = true;
|
||||
}
|
||||
}
|
||||
|
||||
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call,
|
||||
LPVOID lpReserved) {
|
||||
mod = hModule;
|
||||
return true;
|
||||
}
|
31
ScrapHacks/src/make_D3D8_VMT.py
Normal file
31
ScrapHacks/src/make_D3D8_VMT.py
Normal file
|
@ -0,0 +1,31 @@
|
|||
import os
|
||||
import sys
|
||||
import re
|
||||
outfile,infile=sys.argv[1:]
|
||||
|
||||
re_interface=re.compile(r"^DECLARE_INTERFACE_{0,1}\((.*?)\)$")
|
||||
re_method=re.compile(r"^\w*STDMETHOD_{0,1}\((.*?)\)\((.*?)\).*;")
|
||||
name=None
|
||||
idx=0
|
||||
VMTs={}
|
||||
with open(infile,"r") as infh:
|
||||
for line in infh:
|
||||
line=line.strip()
|
||||
interf=re_interface.match(line)
|
||||
meth=re_method.match(line)
|
||||
if interf:
|
||||
idx=0
|
||||
name="VMT_"+"_".join([name for name in interf.groups()[0].split(", ") if name!="IUnknown"])
|
||||
VMTs[name]={}
|
||||
if meth:
|
||||
meth_name,meth_args=meth.groups()
|
||||
meth_name=meth_name.split(",")[-1].strip()
|
||||
VMTs[name][meth_name]=idx
|
||||
idx+=1
|
||||
print(f"Generating: {outfile} from {infile} ...")
|
||||
with open(outfile,"w") as ofh:
|
||||
for name in sorted(VMTs.keys()):
|
||||
print(f"namespace {name} {{",file=ofh)
|
||||
for method,idx in sorted(VMTs[name].items(),key=lambda v:v[1]):
|
||||
print(f"\tconst size_t m_{method} = {idx};",file=ofh)
|
||||
print("}",file=ofh)
|
|
@ -52,7 +52,7 @@ r2_cmd("aaaaa")
|
|||
#0x413ee0
|
||||
|
||||
#0x7d2094 refcnt
|
||||
flags = {0x7FE944: ("World_Ptr", 4), 0x79C698: ("Py_Mods", 4)}
|
||||
flags = {0x7FE944: ("P_World", 4), 0x79C698: ("Py_Mods", 4),0x852914: ("P_D3D8_Dev",4)}
|
||||
|
||||
types = ["struct PyMethodDef {char *ml_name; void *ml_meth; int ml_flags; char *ml_doc;};"]
|
||||
|
||||
|
@ -70,6 +70,9 @@ func_sigs = {
|
|||
0x419950: "int fopen_2(const char* filename);",
|
||||
0x41AB50: "int open_pak(const char* filename, int unk_1,void* unk_ptr);",
|
||||
0x404460: "int register_c_callback(const char* name,void* func);"
|
||||
0x414070: "void throw_assertion_2(const char* check,const char* file, unsigned int line);"
|
||||
0x5FBC50: "void throw_assertion_1(const char* check,const char* file,const char* date, unsigned int line);",
|
||||
0x5bc140: "static char* convertsimple1(void *arg, char **p_format, void *p_va);"
|
||||
}
|
||||
|
||||
functions = {
|
||||
|
@ -154,30 +157,38 @@ def c_callbacks():
|
|||
|
||||
def assertions():
|
||||
assertions = {}
|
||||
for a_addr in ["fcn.throw_assertion_1", "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}")
|
||||
res = r2_cmd(f"/r {a_addr} ~CALL[1]").splitlines()
|
||||
print()
|
||||
for line in tqdm(res, ascii=True):
|
||||
addr = line.strip()
|
||||
file, msg = r2_cmdJ(f"s {addr};so -2;pij 2") # seek and print disassembly
|
||||
dis=r2_cmdJ(f"s {addr};so -{n_args};pij {n_args}") # seek and print disassembly
|
||||
if n_args==4:
|
||||
file, msg, date, line = dis
|
||||
elif n_args==3:
|
||||
date=None
|
||||
file, msg, line = dis
|
||||
try:
|
||||
file = r2_cmd(f"psz @{file.refs[0].addr}").strip()
|
||||
msg = r2_cmd(f"psz @{msg.refs[0].addr}").strip()
|
||||
path = os.path.abspath(file.replace("\\\\", "\\"))
|
||||
if date:
|
||||
r2_cmd(f"psz @{date.refs[0].addr}").strip()
|
||||
line=line.val
|
||||
file=file.replace("\\\\", "\\")
|
||||
os.path.isabs(file):
|
||||
file = os.path.abspath(file)
|
||||
assertions.setdefault(path, [])
|
||||
assertions[path].append([addr, msg])
|
||||
assertions[path].append({'line':line,'date':date,'addr':addr,'msg': msg})
|
||||
except:
|
||||
pass
|
||||
for path in assertions:
|
||||
assertions[path].sort(key=lambda v:int(v[0],16))
|
||||
assertions[path].sort(key=lambda v:v['line'])
|
||||
return assertions
|
||||
|
||||
|
||||
def world():
|
||||
def bb_refs(addr):
|
||||
ret={}
|
||||
print("[*] Parsing World offsets")
|
||||
res = r2_cmd("/r loc.World_Ptr ~fcn[0,1]").splitlines()
|
||||
res = r2_cmd(f"/r {addr} ~fcn[0,1]").splitlines()
|
||||
print()
|
||||
for ent in res:
|
||||
func,hit=ent.split()
|
||||
|
@ -186,6 +197,15 @@ def world():
|
|||
ret[hit]['asm'].append(ins.disasm)
|
||||
return ret
|
||||
|
||||
def world():
|
||||
print("[*] Parsing World offsets")
|
||||
return bb_refs("loc.P_World")
|
||||
|
||||
def render():
|
||||
print("[*] Parsing D3D_Device offsets")
|
||||
return bb_refs("loc.P_D3D8_Dev")
|
||||
|
||||
|
||||
def py_mods():
|
||||
print("[*] Parsing Python modules")
|
||||
res = r2_cmd("/r fcn.Py_InitModule ~CALL[1]").splitlines()
|
||||
|
@ -260,6 +280,7 @@ ret = dict(
|
|||
assertions=assertions(),
|
||||
vtables=vtables(),
|
||||
world=world(),
|
||||
render=render(),
|
||||
)
|
||||
|
||||
r2_cmd("aaaaa") # Propagate type infos
|
||||
|
|
Loading…
Reference in a new issue