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…
	
	Add table
		Add a link
		
	
		Reference in a new issue