diff --git a/README.md b/README.md index 4bc57db..1b6c5ad 100644 --- a/README.md +++ b/README.md @@ -27,5 +27,4 @@ WIP Memory hacking library - [IDA](https://www.hex-rays.com/products/ida/index.shtml) and [x32dbg](https://x64dbg.com/) - [Reclass.NET](https://github.com/ReClassNET/ReClass.NET) - [HxD](https://mh-nexus.de/en/hxd/) -- [Kaitai Struct](http://kaitai.io/) -- [Radare2](https://www.radare.org/) \ No newline at end of file +- [Kaitai Struct](http://kaitai.io/) \ No newline at end of file diff --git a/ScrapHacks/CMakeLists.txt b/ScrapHacks/CMakeLists.txt index f9a92d3..d0f1452 100644 --- a/ScrapHacks/CMakeLists.txt +++ b/ScrapHacks/CMakeLists.txt @@ -1,6 +1,5 @@ cmake_minimum_required(VERSION 3.1) cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}) - project(ScrapHacks VERSION 1.0 DESCRIPTION "Scrapland memory hacking library" @@ -19,5 +18,7 @@ if(WIN32) set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} /SAFESEH:NO") endif(MSVC) endif(WIN32) + add_subdirectory(Injector) -add_subdirectory(ScrapHack) \ No newline at end of file +add_subdirectory(ScrapHack) + diff --git a/ScrapHacks/Injector/CMakeLists.txt b/ScrapHacks/Injector/CMakeLists.txt index e5e68a8..358ef5b 100644 --- a/ScrapHacks/Injector/CMakeLists.txt +++ b/ScrapHacks/Injector/CMakeLists.txt @@ -1,3 +1,3 @@ -add_executable(Injector main.cpp) +add_executable(Injector Injector.cpp) target_compile_features(Injector PUBLIC cxx_std_11) install(TARGETS Injector DESTINATION bin) diff --git a/ScrapHacks/Injector/main.cpp b/ScrapHacks/Injector/Injector.cpp similarity index 63% rename from ScrapHacks/Injector/main.cpp rename to ScrapHacks/Injector/Injector.cpp index 9afc442..f99ef1e 100644 --- a/ScrapHacks/Injector/main.cpp +++ b/ScrapHacks/Injector/Injector.cpp @@ -32,6 +32,56 @@ void fail(char *msg) exit(1); } +string fromhex(string input) +{ + transform(input.begin(), input.end(), input.begin(), ::toupper); + string hc = "0123456789ABCDEF"; + string o = ""; + int n = 0; + int v = 0; + for (unsigned char c : input) + { + if (hc.find(c) != size_t(-1)) + { + if ((n++) % 2 == 0) + { + v = hc.find(c) << 4; + } + else + { + o += char(v + hc.find(c)); + } + } + else + { + cout << "Invalid Character in hex string" << endl; + return ""; + } + } + return o; +} + +vector split(string str, char sep) +{ + vector 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; +} + bool fexists(const char *filename) { ifstream ifile(filename); @@ -66,6 +116,16 @@ bool HasModule(int PID, const char *modname) return false; } +bool ProcRunning(DWORD PID) +{ + HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE | TH32CS_SNAPMODULE32, PID); + if (hSnap == INVALID_HANDLE_VALUE) + { + return false; + } + CloseHandle(hSnap); + return true; +} bool adjustPrivs(HANDLE hProc) { @@ -151,19 +211,54 @@ void InjectDll(DWORD PID) return; } +vector spawn(char *binary) +{ + STARTUPINFO startupinfo; + PROCESS_INFORMATION processinfo; + ZeroMemory(&startupinfo, sizeof(startupinfo)); + ZeroMemory(&processinfo, sizeof(processinfo)); + startupinfo.cb = sizeof(startupinfo); + if (!CreateProcessA(NULL, binary, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &startupinfo, &processinfo)) + { + return {}; + } + return {processinfo.hProcess, processinfo.hThread}; +} int main(int argc, char *argv[]) { + string prog; + HANDLE hProc = INVALID_HANDLE_VALUE; + HANDLE hThread = INVALID_HANDLE_VALUE; DWORD PID = 0; - HWND ScrapWin=FindWindow("ScrapClass",NULL); - if (!ScrapWin) { - cerr<<"Error: Scrapland window not found!"< 1) && fexists(argv[1])) + { + cout << "[*] Injector PID: " << GetCurrentProcessId() << endl; + cout << "[*] Spawning process for \"" << argv[1] << "\"" << endl; + vector handles = spawn(argv[1]); + if (handles.empty()) + { + fail("Failed to spawn process"); + } + hProc = handles[0]; + hThread = handles[1]; + PID = GetProcessId(hProc); } - GetWindowThreadProcessId(ScrapWin,&PID); - if (PID) { - InjectDll(PID); - } else { - fail("Error getting PID"); + else + { + cerr << "Usage: " << argv[0] << " " << endl; + return 1; } + InjectDll(PID); + if (hThread != INVALID_HANDLE_VALUE) + { + while (ResumeThread(hThread)) + ; + } + SetEnvironmentVariableA("Inj_PID", NULL); + cout << "[*] Done!" << endl; + return 0; } diff --git a/ScrapHacks/README.md b/ScrapHacks/README.md index 5d57306..bd5ee52 100644 --- a/ScrapHacks/README.md +++ b/ScrapHacks/README.md @@ -10,14 +10,10 @@ Open VS 32-bit command prompt (`vcvars32.bat`) ```batch mkdir build cd build -cmake -G"NMake Makefiles" .. +cmake -G "NMake Makefiles" .. 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) - -## TODO - -- Injector-less version (patch Scrap.exe to load DLL) \ No newline at end of file +(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) \ No newline at end of file diff --git a/ScrapHacks/ScrapHack/CMakeLists.txt b/ScrapHacks/ScrapHack/CMakeLists.txt index 0e1648f..3fd10d9 100644 --- a/ScrapHacks/ScrapHack/CMakeLists.txt +++ b/ScrapHacks/ScrapHack/CMakeLists.txt @@ -14,11 +14,9 @@ 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) diff --git a/ScrapHacks/ScrapHack/D3D8_Hook.h b/ScrapHacks/ScrapHack/D3D8_Hook.h index 8b13651..28b44fc 100644 --- a/ScrapHacks/ScrapHack/D3D8_Hook.h +++ b/ScrapHacks/ScrapHack/D3D8_Hook.h @@ -1,8 +1,6 @@ #pragma once -#include #include #include -#include uintmax_t frame = 0; DWORD *GetVTable(void *addr) { @@ -55,6 +53,37 @@ HRESULT WINAPI H_EndScene(LPDIRECT3DDEVICE8 dev) return hook->func(Render(dev)); } +HRESULT WINAPI H_CreateDevice(void *pDirect3D, unsigned int uiAdapter, D3DDEVTYPE pDeviceType, HWND hFocusWindow, + unsigned long ulBehaviorFlags, D3DPRESENT_PARAMETERS *pPresentationParameters, + LPDIRECT3DDEVICE8 *ppReturnedDeviceInterface) +{ + typedef HRESULT(WINAPI * t_func)(void *, unsigned int, D3DDEVTYPE, HWND, unsigned long, D3DPRESENT_PARAMETERS *, LPDIRECT3DDEVICE8 *); + shared_ptr hook = Hook::get(H_CreateDevice); + HRESULT ret = hook->func(pDirect3D, uiAdapter, pDeviceType, hFocusWindow, ulBehaviorFlags, pPresentationParameters, ppReturnedDeviceInterface); + cout << "CreateDevice -> " << ret << endl; + void *EndScene = reinterpret_cast(GetVTable(ppReturnedDeviceInterface[0])[35]); + cout << "EndScene @ " << EndScene << endl; // EndScene + Hook::addr(EndScene, H_EndScene); + Hook::drop(H_CreateDevice); + return ret; +} + +LPDIRECT3D8 WINAPI H_Direct3DCreate8(unsigned int SDKVersion) +{ + typedef LPDIRECT3D8(_stdcall * t_func)(unsigned int); + shared_ptr hook = Hook::get(H_Direct3DCreate8); + + LPDIRECT3D8 ret = hook->func(SDKVersion); + cout << "D3D8-Create: " << SDKVersion << " -> " << ret << endl; + void *CreateDevice = reinterpret_cast(GetVTable(ret)[15]); + void *Release = reinterpret_cast(GetVTable(ret)[2]); + cout << "CreateDevice @ " << CreateDevice << endl; // CreateDevice + Hook::addr(CreateDevice, H_CreateDevice); + Hook::drop(H_Direct3DCreate8); + + return ret; +} + void unhook_d3d8() { if (hFont != INVALID_HANDLE_VALUE) @@ -70,13 +99,7 @@ void unhook_d3d8() 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(0x853954,0x2a3d8,0,4*35,0),H_EndScene); - shared_ptr hook = Hook::get(hook_d3d8); - hook->func_void(); - hook->disable(); - Hook::drop(hook_d3d8); - return; -} + Hook::module("d3d8.dll", "Direct3DCreate8", H_Direct3DCreate8); +} \ No newline at end of file diff --git a/ScrapHacks/ScrapHack/Hook.h b/ScrapHacks/ScrapHack/Hook.h index 01a9059..c35eb02 100644 --- a/ScrapHacks/ScrapHack/Hook.h +++ b/ScrapHacks/ScrapHack/Hook.h @@ -119,15 +119,6 @@ public: return this->orig; } - template - void func_void(Args... args) - { - disable(); - reinterpret_cast(this->orig)(args...); - enable(); - return; - } - template decltype(auto) func(Args... args) { diff --git a/ScrapHacks/ScrapHack/REPL.h b/ScrapHacks/ScrapHack/REPL.h deleted file mode 100644 index dbda1a8..0000000 --- a/ScrapHacks/ScrapHack/REPL.h +++ /dev/null @@ -1,54 +0,0 @@ -#include -#include -#include -#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<<"'"< cmd = split(string(_cmd), ' '); - cout<<"PARTS: "; - for (string c:cmd) { - cout<<"'"< [size]\n"); - return; - } - scrap_log(0xff0000, "READ!\n"); - cout<<"READ!"< \n"); - return; - } - scrap_log(0xff0000, "WRITE!\n"); - cout<<"WRITE!"< +#include #include #include #include @@ -17,18 +18,15 @@ using namespace std; #include "Hook.h" #include "VMT_Hook.h" #include "D3D8_Hook.h" -#include "REPL.h" -bool do_sleep=true; + 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(); +void hook_exit(); size_t size_ht(HashTable *ht) { @@ -121,13 +119,9 @@ size_t dump_ht(HashTable *ht) void MainLoop(HMODULE mod) { Sleep(100); - Hook::addr(reinterpret_cast(P_SCRAP_EXIT), H_Exit); - Hook::addr(reinterpret_cast(P_D3DCHECK),hook_d3d8); - Hook::addr(reinterpret_cast(P_CON_HANDLER), hooked_console); - overlay=true; + hook_exit(); 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; @@ -140,14 +134,11 @@ void MainLoop(HMODULE mod) 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; @@ -157,7 +148,6 @@ void MainLoop(HMODULE mod) { overlay = !overlay; } - if (key_down_norepeat(VK_F6)) { @@ -203,19 +193,33 @@ void InitConsole() SetupConsole(me); } +void handle_command(const char *cmd) +{ + cout << "CMD: " << cmd << endl; + scrap_log(0x00ff00, "HAXX: "); + scrap_log(0x00ff00, cmd); + scrap_log(0x00ff00, "\n"); + return; +} + int hooked_console(const char *cmd) { typedef int(_cdecl * t_func)(const char *); + shared_ptr hook = Hook::get(hooked_console); if (cmd[0] == '$') { handle_command(++cmd); return 0; } - shared_ptr hook = Hook::get(hooked_console); int ret = hook->func(cmd); return ret; } +void hook_console() +{ + Hook::addr(reinterpret_cast(P_CON_HANDLER), hooked_console); +} + void H_Exit() { typedef void(_cdecl * t_func)(void); @@ -226,20 +230,67 @@ void H_Exit() return; } +void hook_exit() +{ + Hook::addr(reinterpret_cast(P_SCRAP_EXIT), H_Exit); +} + +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; +} void DllPreInit(HMODULE _mod) { char mfn[1024]; + char inj[MAX_PATH]; + DWORD INJ_PID = 0; 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; + GetEnvironmentVariableA("Inj_PID", inj, MAX_PATH); + SetEnvironmentVariableA("Inj_PID", NULL); + hook_console(); + sscanf_s(inj, "%d", &INJ_PID); + cout << INJ_PID << "," << PPID() << endl; + if (PPID() == INJ_PID) + { + hook_d3d8(); + overlay = true; + } + else + { + cout << "[-] No launched by Injector, not hooking DX8" << endl; + } } void DllInit(HMODULE _mod) { initialized = true; mod = _mod; + Sleep(3000); cout << "[*] World: " << ptr(P_WORLD, 0) << endl; cout << "[*] Importing python dbg module" << endl; scrap_exec("import dbg"); diff --git a/ScrapHacks/ScrapHack/Scrapland.h b/ScrapHacks/ScrapHack/Scrapland.h index 1099a20..55716e7 100644 --- a/ScrapHacks/ScrapHack/Scrapland.h +++ b/ScrapHacks/ScrapHack/Scrapland.h @@ -10,13 +10,10 @@ //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 *) diff --git a/ScrapHacks/ScrapHack/Util.h b/ScrapHacks/ScrapHack/Util.h index b0da991..199f44b 100644 --- a/ScrapHacks/ScrapHack/Util.h +++ b/ScrapHacks/ScrapHack/Util.h @@ -37,14 +37,12 @@ void SetupStreams() void SetupConsole() { - if (!AttachConsole(-1)) { - if (!AllocConsole()) - { - FreeConsole(); - AllocConsole(); - } - AttachConsole(GetCurrentProcessId()); + if (!AllocConsole()) + { + FreeConsole(); + AllocConsole(); } + AttachConsole(GetCurrentProcessId()); SetupStreams(); } @@ -156,51 +154,3 @@ T *ptr(uintptr_t addr, Offsets... offsets) auto ret = __ptr(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 split(string str, char sep) -{ - vector 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; -} diff --git a/ScrapHacks/ScrapHack/dllmain.cpp b/ScrapHacks/ScrapHack/dllmain.cpp index 1665555..5954cd5 100644 --- a/ScrapHacks/ScrapHack/dllmain.cpp +++ b/ScrapHacks/ScrapHack/dllmain.cpp @@ -15,9 +15,6 @@ BOOL APIENTRY DllMain(HMODULE hModule, 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);