diff --git a/README.md b/README.md index 1b6c5ad..4bc57db 100644 --- a/README.md +++ b/README.md @@ -27,4 +27,5 @@ 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/) \ No newline at end of file +- [Kaitai Struct](http://kaitai.io/) +- [Radare2](https://www.radare.org/) \ No newline at end of file diff --git a/ScrapHacks/CMakeLists.txt b/ScrapHacks/CMakeLists.txt index d0f1452..f9a92d3 100644 --- a/ScrapHacks/CMakeLists.txt +++ b/ScrapHacks/CMakeLists.txt @@ -1,5 +1,6 @@ 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" @@ -18,7 +19,5 @@ if(WIN32) set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} /SAFESEH:NO") endif(MSVC) endif(WIN32) - add_subdirectory(Injector) -add_subdirectory(ScrapHack) - +add_subdirectory(ScrapHack) \ No newline at end of file diff --git a/ScrapHacks/Injector/CMakeLists.txt b/ScrapHacks/Injector/CMakeLists.txt index 358ef5b..e5e68a8 100644 --- a/ScrapHacks/Injector/CMakeLists.txt +++ b/ScrapHacks/Injector/CMakeLists.txt @@ -1,3 +1,3 @@ -add_executable(Injector Injector.cpp) +add_executable(Injector main.cpp) target_compile_features(Injector PUBLIC cxx_std_11) install(TARGETS Injector DESTINATION bin) diff --git a/ScrapHacks/Injector/Injector.cpp b/ScrapHacks/Injector/main.cpp similarity index 63% rename from ScrapHacks/Injector/Injector.cpp rename to ScrapHacks/Injector/main.cpp index f99ef1e..9afc442 100644 --- a/ScrapHacks/Injector/Injector.cpp +++ b/ScrapHacks/Injector/main.cpp @@ -32,56 +32,6 @@ 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); @@ -116,16 +66,6 @@ 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) { @@ -211,54 +151,19 @@ 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; - char s_PID[MAX_PATH]; - snprintf(s_PID, MAX_PATH, "%d", GetCurrentProcessId()); - SetEnvironmentVariableA("Inj_PID", s_PID); - if ((argc > 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); + HWND ScrapWin=FindWindow("ScrapClass",NULL); + if (!ScrapWin) { + cerr<<"Error: Scrapland window not found!"<" << endl; - return 1; + GetWindowThreadProcessId(ScrapWin,&PID); + if (PID) { + InjectDll(PID); + } else { + fail("Error getting PID"); } - 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 bd5ee52..5d57306 100644 --- a/ScrapHacks/README.md +++ b/ScrapHacks/README.md @@ -10,10 +10,14 @@ 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) \ 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) + +## TODO + +- Injector-less version (patch Scrap.exe to load DLL) \ No newline at end of file diff --git a/ScrapHacks/ScrapHack/CMakeLists.txt b/ScrapHacks/ScrapHack/CMakeLists.txt index 3fd10d9..0e1648f 100644 --- a/ScrapHacks/ScrapHack/CMakeLists.txt +++ b/ScrapHacks/ScrapHack/CMakeLists.txt @@ -14,9 +14,11 @@ 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 28b44fc..8b13651 100644 --- a/ScrapHacks/ScrapHack/D3D8_Hook.h +++ b/ScrapHacks/ScrapHack/D3D8_Hook.h @@ -1,6 +1,8 @@ #pragma once +#include #include #include +#include uintmax_t frame = 0; DWORD *GetVTable(void *addr) { @@ -53,37 +55,6 @@ 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) @@ -99,7 +70,13 @@ 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::module("d3d8.dll", "Direct3DCreate8", H_Direct3DCreate8); -} \ No newline at end of file + 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; +} diff --git a/ScrapHacks/ScrapHack/Hook.h b/ScrapHacks/ScrapHack/Hook.h index c35eb02..01a9059 100644 --- a/ScrapHacks/ScrapHack/Hook.h +++ b/ScrapHacks/ScrapHack/Hook.h @@ -119,6 +119,15 @@ 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 new file mode 100644 index 0000000..dbda1a8 --- /dev/null +++ b/ScrapHacks/ScrapHack/REPL.h @@ -0,0 +1,54 @@ +#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 @@ -18,15 +17,18 @@ 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); -void hook_exit(); +int hooked_console(const char *); +void H_Exit(); size_t size_ht(HashTable *ht) { @@ -119,9 +121,13 @@ size_t dump_ht(HashTable *ht) void MainLoop(HMODULE mod) { Sleep(100); - hook_exit(); + 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; 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; @@ -134,11 +140,14 @@ 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; @@ -148,6 +157,7 @@ void MainLoop(HMODULE mod) { overlay = !overlay; } + if (key_down_norepeat(VK_F6)) { @@ -193,33 +203,19 @@ 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); @@ -230,67 +226,20 @@ 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 55716e7..1099a20 100644 --- a/ScrapHacks/ScrapHack/Scrapland.h +++ b/ScrapHacks/ScrapHack/Scrapland.h @@ -10,10 +10,13 @@ //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 199f44b..b0da991 100644 --- a/ScrapHacks/ScrapHack/Util.h +++ b/ScrapHacks/ScrapHack/Util.h @@ -37,12 +37,14 @@ void SetupStreams() void SetupConsole() { - if (!AllocConsole()) - { - FreeConsole(); - AllocConsole(); + if (!AttachConsole(-1)) { + if (!AllocConsole()) + { + FreeConsole(); + AllocConsole(); + } + AttachConsole(GetCurrentProcessId()); } - AttachConsole(GetCurrentProcessId()); SetupStreams(); } @@ -154,3 +156,51 @@ 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 5954cd5..1665555 100644 --- a/ScrapHacks/ScrapHack/dllmain.cpp +++ b/ScrapHacks/ScrapHack/dllmain.cpp @@ -15,6 +15,9 @@ 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);