Compare commits

...

13 commits

13 changed files with 172 additions and 216 deletions

View file

@ -28,3 +28,4 @@ WIP Memory hacking library
- [Reclass.NET](https://github.com/ReClassNET/ReClass.NET) - [Reclass.NET](https://github.com/ReClassNET/ReClass.NET)
- [HxD](https://mh-nexus.de/en/hxd/) - [HxD](https://mh-nexus.de/en/hxd/)
- [Kaitai Struct](http://kaitai.io/) - [Kaitai Struct](http://kaitai.io/)
- [Radare2](https://www.radare.org/)

View file

@ -1,5 +1,6 @@
cmake_minimum_required(VERSION 3.1) cmake_minimum_required(VERSION 3.1)
cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}) cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION})
project(ScrapHacks project(ScrapHacks
VERSION 1.0 VERSION 1.0
DESCRIPTION "Scrapland memory hacking library" DESCRIPTION "Scrapland memory hacking library"
@ -18,7 +19,5 @@ if(WIN32)
set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} /SAFESEH:NO") set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} /SAFESEH:NO")
endif(MSVC) endif(MSVC)
endif(WIN32) endif(WIN32)
add_subdirectory(Injector) add_subdirectory(Injector)
add_subdirectory(ScrapHack) add_subdirectory(ScrapHack)

View file

@ -1,3 +1,3 @@
add_executable(Injector Injector.cpp) add_executable(Injector main.cpp)
target_compile_features(Injector PUBLIC cxx_std_11) target_compile_features(Injector PUBLIC cxx_std_11)
install(TARGETS Injector DESTINATION bin) install(TARGETS Injector DESTINATION bin)

View file

@ -32,56 +32,6 @@ void fail(char *msg)
exit(1); 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<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;
}
bool fexists(const char *filename) bool fexists(const char *filename)
{ {
ifstream ifile(filename); ifstream ifile(filename);
@ -116,16 +66,6 @@ bool HasModule(int PID, const char *modname)
return false; 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) bool adjustPrivs(HANDLE hProc)
{ {
@ -211,54 +151,19 @@ void InjectDll(DWORD PID)
return; return;
} }
vector<HANDLE> 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[]) int main(int argc, char *argv[])
{ {
string prog;
HANDLE hProc = INVALID_HANDLE_VALUE;
HANDLE hThread = INVALID_HANDLE_VALUE;
DWORD PID = 0; DWORD PID = 0;
char s_PID[MAX_PATH]; HWND ScrapWin=FindWindow("ScrapClass",NULL);
snprintf(s_PID, MAX_PATH, "%d", GetCurrentProcessId()); if (!ScrapWin) {
SetEnvironmentVariableA("Inj_PID", s_PID); cerr<<"Error: Scrapland window not found!"<<endl;
if ((argc > 1) && fexists(argv[1])) exit(1);
{
cout << "[*] Injector PID: " << GetCurrentProcessId() << endl;
cout << "[*] Spawning process for \"" << argv[1] << "\"" << endl;
vector<HANDLE> handles = spawn(argv[1]);
if (handles.empty())
{
fail("Failed to spawn process");
}
hProc = handles[0];
hThread = handles[1];
PID = GetProcessId(hProc);
}
else
{
cerr << "Usage: " << argv[0] << " <Path to Scrap.exe>" << endl;
return 1;
} }
GetWindowThreadProcessId(ScrapWin,&PID);
if (PID) {
InjectDll(PID); InjectDll(PID);
if (hThread != INVALID_HANDLE_VALUE) } else {
{ fail("Error getting PID");
while (ResumeThread(hThread))
;
} }
SetEnvironmentVariableA("Inj_PID", NULL);
cout << "[*] Done!" << endl;
return 0;
} }

View file

@ -17,3 +17,7 @@ cmake --build . --target install
this will drop the compiled files into `./build/bin` 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) (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)

View file

@ -14,9 +14,11 @@ link_directories(AFTER ${SOURCE_DIR}/8.0/lib/)
add_compile_definitions(_CRT_SECURE_NO_WARNINGS) add_compile_definitions(_CRT_SECURE_NO_WARNINGS)
add_compile_definitions(POINTER_64=__ptr64) add_compile_definitions(POINTER_64=__ptr64)
add_library(ScrapHack SHARED ScrapHack.cpp dllmain.cpp) add_library(ScrapHack SHARED ScrapHack.cpp dllmain.cpp)
add_dependencies(ScrapHack DirectX)
target_link_libraries(ScrapHack target_link_libraries(ScrapHack
d3d8 d3d8
d3dx8 d3dx8
dxerr8
legacy_stdio_definitions) legacy_stdio_definitions)
target_compile_features(ScrapHack PUBLIC cxx_std_11) target_compile_features(ScrapHack PUBLIC cxx_std_11)
install(TARGETS ScrapHack DESTINATION bin) install(TARGETS ScrapHack DESTINATION bin)

View file

@ -1,6 +1,8 @@
#pragma once #pragma once
#include <Windows.h>
#include <d3d8.h> #include <d3d8.h>
#include <d3dx8.h> #include <d3dx8.h>
#include <dxerr8.h>
uintmax_t frame = 0; uintmax_t frame = 0;
DWORD *GetVTable(void *addr) DWORD *GetVTable(void *addr)
{ {
@ -53,37 +55,6 @@ HRESULT WINAPI H_EndScene(LPDIRECT3DDEVICE8 dev)
return hook->func<t_func>(Render(dev)); return hook->func<t_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 = Hook::get(H_CreateDevice);
HRESULT ret = hook->func<t_func>(pDirect3D, uiAdapter, pDeviceType, hFocusWindow, ulBehaviorFlags, pPresentationParameters, ppReturnedDeviceInterface);
cout << "CreateDevice -> " << ret << endl;
void *EndScene = reinterpret_cast<void *>(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 = Hook::get(H_Direct3DCreate8);
LPDIRECT3D8 ret = hook->func<t_func>(SDKVersion);
cout << "D3D8-Create: " << SDKVersion << " -> " << ret << endl;
void *CreateDevice = reinterpret_cast<void *>(GetVTable(ret)[15]);
void *Release = reinterpret_cast<void *>(GetVTable(ret)[2]);
cout << "CreateDevice @ " << CreateDevice << endl; // CreateDevice
Hook::addr(CreateDevice, H_CreateDevice);
Hook::drop(H_Direct3DCreate8);
return ret;
}
void unhook_d3d8() void unhook_d3d8()
{ {
if (hFont != INVALID_HANDLE_VALUE) if (hFont != INVALID_HANDLE_VALUE)
@ -99,7 +70,13 @@ void unhook_d3d8()
void hook_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"); 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)); hBrush = CreateSolidBrush(D3DCOLOR_ARGB(25, 0, 0, 0));
Hook::module("d3d8.dll", "Direct3DCreate8", H_Direct3DCreate8); 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;
} }

View file

@ -119,6 +119,15 @@ public:
return this->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> template <typename F, typename... Args>
decltype(auto) func(Args... args) decltype(auto) func(Args... args)
{ {

View file

@ -0,0 +1,54 @@
#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;
}

View file

@ -1,5 +1,4 @@
#include <string> #include <string>
#include <sstream>
#include <vector> #include <vector>
#include <map> #include <map>
#include <iomanip> #include <iomanip>
@ -18,15 +17,18 @@ using namespace std;
#include "Hook.h" #include "Hook.h"
#include "VMT_Hook.h" #include "VMT_Hook.h"
#include "D3D8_Hook.h" #include "D3D8_Hook.h"
#include "REPL.h"
bool do_sleep=true;
HMODULE hD3D8Dll = 0; HMODULE hD3D8Dll = 0;
bool initialized = false; bool initialized = false;
bool running = true; bool running = true;
bool redirect_console = false;
HMODULE mod = 0; HMODULE mod = 0;
void DllUnload(HMODULE); void DllUnload(HMODULE);
void hook_exit(); int hooked_console(const char *);
void H_Exit();
size_t size_ht(HashTable<EntityList> *ht) size_t size_ht(HashTable<EntityList> *ht)
{ {
@ -119,9 +121,13 @@ size_t dump_ht(HashTable<Entity> *ht)
void MainLoop(HMODULE mod) void MainLoop(HMODULE mod)
{ {
Sleep(100); Sleep(100);
hook_exit(); 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 << "[*] Starting main Loop" << endl;
cout << endl; cout << endl;
cout << "[F2 ] Redirect game console to ScapHacks console" << endl;
cout << "[F3 ] Unload ScrapHacks" << endl; cout << "[F3 ] Unload ScrapHacks" << endl;
cout << "[F5 ] Show Overlay" << endl; cout << "[F5 ] Show Overlay" << endl;
cout << "[F6 ] Show Alarm status" << endl; cout << "[F6 ] Show Alarm status" << endl;
@ -134,11 +140,14 @@ void MainLoop(HMODULE mod)
while (running) while (running)
{ {
Sleep(100); Sleep(100);
while (key_down('F')) while (key_down('F'))
{ {
scrap_exec("dbg.brake()"); scrap_exec("dbg.brake()");
} }
if (key_down_norepeat(VK_F2))
{
redirect_console = !redirect_console;
}
if (key_down_norepeat(VK_F3)) if (key_down_norepeat(VK_F3))
{ {
break; break;
@ -148,6 +157,7 @@ void MainLoop(HMODULE mod)
{ {
overlay = !overlay; overlay = !overlay;
} }
if (key_down_norepeat(VK_F6)) if (key_down_norepeat(VK_F6))
{ {
@ -193,33 +203,19 @@ void InitConsole()
SetupConsole(me); 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) int hooked_console(const char *cmd)
{ {
typedef int(_cdecl * t_func)(const char *); typedef int(_cdecl * t_func)(const char *);
shared_ptr<Hook> hook = Hook::get(hooked_console);
if (cmd[0] == '$') if (cmd[0] == '$')
{ {
handle_command(++cmd); handle_command(++cmd);
return 0; return 0;
} }
shared_ptr<Hook> hook = Hook::get(hooked_console);
int ret = hook->func<t_func>(cmd); int ret = hook->func<t_func>(cmd);
return ret; return ret;
} }
void hook_console()
{
Hook::addr(reinterpret_cast<void *>(P_CON_HANDLER), hooked_console);
}
void H_Exit() void H_Exit()
{ {
typedef void(_cdecl * t_func)(void); typedef void(_cdecl * t_func)(void);
@ -230,67 +226,20 @@ void H_Exit()
return; return;
} }
void hook_exit()
{
Hook::addr(reinterpret_cast<void *>(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) void DllPreInit(HMODULE _mod)
{ {
char mfn[1024]; char mfn[1024];
char inj[MAX_PATH];
DWORD INJ_PID = 0;
InitConsole(); InitConsole();
GetModuleFileNameA(0, mfn, 1024); GetModuleFileNameA(0, mfn, 1024);
Py = get_modules(P_PY_MODS); Py = get_modules(P_PY_MODS);
cout << "[+] ScrapHacks v0.1 Loaded in " << mfn << " (PID: " << std::hex << GetCurrentProcessId() << std::dec << ")" << endl; 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) void DllInit(HMODULE _mod)
{ {
initialized = true; initialized = true;
mod = _mod; mod = _mod;
Sleep(3000);
cout << "[*] World: " << ptr<void>(P_WORLD, 0) << endl; cout << "[*] World: " << ptr<void>(P_WORLD, 0) << endl;
cout << "[*] Importing python dbg module" << endl; cout << "[*] Importing python dbg module" << endl;
scrap_exec("import dbg"); scrap_exec("import dbg");

View file

@ -10,10 +10,13 @@
//POINTERS //POINTERS
#define P_WORLD 0x7FE944 #define P_WORLD 0x7FE944
#define P_PY_MODS 0x79C698 #define P_PY_MODS 0x79C698
//FUNCTIONS
#define P_CON_HANDLER 0x402190 #define P_CON_HANDLER 0x402190
#define P_SCRAP_LOG 0x4134C0 #define P_SCRAP_LOG 0x4134C0
#define P_SCRAP_EXEC 0x5a8390 #define P_SCRAP_EXEC 0x5a8390
#define P_SCRAP_EXIT 0x4010c0 #define P_SCRAP_EXIT 0x4010c0
#define P_D3DCHECK 0x602a70
//FUNCTION TYPES //FUNCTION TYPES
#define T_SCRAP_LOG int(_cdecl *)(unsigned int, const char *) #define T_SCRAP_LOG int(_cdecl *)(unsigned int, const char *)

View file

@ -37,12 +37,14 @@ void SetupStreams()
void SetupConsole() void SetupConsole()
{ {
if (!AttachConsole(-1)) {
if (!AllocConsole()) if (!AllocConsole())
{ {
FreeConsole(); FreeConsole();
AllocConsole(); AllocConsole();
} }
AttachConsole(GetCurrentProcessId()); AttachConsole(GetCurrentProcessId());
}
SetupStreams(); SetupStreams();
} }
@ -154,3 +156,51 @@ T *ptr(uintptr_t addr, Offsets... offsets)
auto ret = __ptr<T>(addr, offsets...); auto ret = __ptr<T>(addr, offsets...);
return ret; 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;
}

View file

@ -15,6 +15,9 @@ BOOL APIENTRY DllMain(HMODULE hModule,
DisableThreadLibraryCalls(hModule); DisableThreadLibraryCalls(hModule);
DllPreInit(hModule); DllPreInit(hModule);
hThread = CreateThread(NULL, NULL, (LPTHREAD_START_ROUTINE)DllInit, hModule, 0, 0); hThread = CreateThread(NULL, NULL, (LPTHREAD_START_ROUTINE)DllInit, hModule, 0, 0);
if (hThread) {
CloseHandle(hThread);
}
break; break;
case DLL_PROCESS_DETACH: case DLL_PROCESS_DETACH:
DllUnload(hModule); DllUnload(hModule);