Created
January 20, 2024 19:51
-
-
Save absoIute/3c0db12e8b94f0acc609144eb1e69c0a to your computer and use it in GitHub Desktop.
1.9 level manager
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//THIS CODE IS OLD AND CRINGE | |
//AND FOUR YEARS OLD | |
#define _CRT_SECURE_NO_WARNINGS | |
#pragma comment(lib, "opengl32.lib") | |
#pragma comment(lib, "C:\\Users\\benst\\Documents\\Developer\\Libraries\\Detours\\lib\\detours.lib") | |
#pragma comment(lib, "C:\\Users\\benst\\Downloads\\discord_game_sdk\\lib\\x86\\discord_game_sdk.dll.lib") | |
#include <Windows.h> | |
#include <cstdint> | |
#include <vector> | |
#include <iostream> | |
#include "U8Overlay.h" | |
#define DEFAULT_LEVELS 18 | |
#define DEFAULT_NAMES 19 | |
#define NAME_ALLOC_OFFSET 0x100 | |
#define STR_ALLOC_OFFSET 0x200 | |
#define SONG_ALLOC_OFFSET 0x300 | |
#define STR2_ALLOC_OFFSET 0x400 | |
const uint8_t _level_payload[] = | |
{ | |
/*00*/ 0x83, 0xEC, 0x18, /*sub esp, 18h */ | |
/*03*/ 0xBA, 0x00, 0x00, 0x00, 0x00, /*mov edx, 0 */ /*level id*/ | |
/*08*/ 0x8B, 0xCC, /*mov ecx, esp */ | |
/*0A*/ 0xE8, 0x00, 0x00, 0x00, 0x00, /*call 0x4A9AD0 */ /*get main level name*/ | |
/*0F*/ 0x8B, 0x06, /*mov eax, [esi] */ | |
/*11*/ 0x8B, 0xCE, /*mov ecx, esi */ | |
/*13*/ 0xFF, 0x90, 0xC0, 0x01, 0x00, 0x00, /*call dword ptr [eax+1C0h]*/ | |
/*19*/ 0x8B, 0x06, /*mov eax, [esi] */ | |
/*1B*/ 0x8B, 0xCE, /*mov ecx, esi */ | |
/*1D*/ 0x6A, 0x00, /*push 0 */ /*level id*/ | |
/*1F*/ 0xFF, 0x90, 0x08, 0x02, 0x00, 0x00, /*call dword ptr [eax+208h]*/ | |
/*25*/ 0x8B, 0x06, /*mov eax, [esi] */ | |
/*27*/ 0x8B, 0xCE, /*mov ecx, esi */ | |
/*29*/ 0x6A, 0x01, /*push 1 */ /*difficulty (1/2/3/4/5/6)*/ | |
/*2B*/ 0xFF, 0x90, 0x00, 0x02, 0x00, 0x00, /*call dword ptr [eax+200h]*/ | |
/*31*/ 0x8B, 0x06, /*mov eax, [esi] */ | |
/*33*/ 0x8B, 0xCE, /*mov ecx, esi */ | |
/*35*/ 0x6A, 0x01, /*push 1 */ /*stars*/ | |
/*37*/ 0xFF, 0x90, 0xC8, 0x02, 0x00, 0x00, /*call dword ptr [eax+2C8h]*/ | |
/*3D*/ 0x8B, 0x06, /*mov eax, [esi] */ | |
/*3F*/ 0x8B, 0xCE, /*mov ecx, esi */ | |
/*41*/ 0x6A, 0x62, /*push 98 */ | |
/*43*/ 0xFF, 0x90, 0xA4, 0x03, 0x00, 0x00, /*call dword ptr [eax+3A4h]*/ | |
/*49*/ 0x8B, 0x06, /*mov eax, [esi] */ | |
/*4B*/ 0x8B, 0xCE, /*mov ecx, esi */ | |
/*4D*/ 0x6A, 0x62, /*push 98 */ | |
/*4F*/ 0xFF, 0x90, 0xAC, 0x03, 0x00, 0x00, /*call dword ptr [eax+3ACh]*/ | |
/*55*/ 0x8B, 0x06, /*mov eax, [esi] */ | |
/*57*/ 0x8B, 0xCE, /*mov ecx, esi */ | |
/*59*/ 0x68, 0xB1, 0x00, 0x00, 0x00, /*push 177 */ | |
/*5E*/ 0xFF, 0x90, 0xB4, 0x03, 0x00, 0x00, /*call dword ptr [eax+3B4h]*/ | |
/*64*/ 0x6A, 0x1D, /*push 29 */ | |
/*66*/ 0xE9, 0x00, 0x00, 0x00, 0x00, /*jmp loc_4A9A25 */ | |
}; | |
const uint8_t _name_payload[] = | |
{ | |
0x68, 0x00, 0x00, 0x00, 0x00, //push LEVEL_NAME | |
0xE8, 0x00, 0x00, 0x00, 0x00, //call 0x4055C0 | |
0x8B, 0xC6, //mov eax, esi | |
0x5E, //pop esi | |
0x8B, 0xE5, //mov esp, ebp | |
0x5D, //pop ebp | |
0xC3 //retn | |
}; | |
struct Level | |
{ | |
char *name, *song; | |
uint8_t stars, difficulty; | |
}; | |
std::vector<Level> levels; | |
uint32_t *jump_table; | |
uint32_t *name_table; | |
uint32_t *song_table; | |
uint32_t SetupLevel(const Level &level, int8_t iter, uint32_t base); | |
void SetupLevels(); | |
void CopyOver(uint32_t address, const void *data, size_t len); | |
template <typename T> void SetMem(uint32_t address, T data); | |
void Hook(uint32_t from, void *to, bool call); | |
DWORD WINAPI MainThread(LPVOID lpParam) | |
{ | |
AllocConsole(); | |
freopen("CONOUT$", "w", stdout); | |
//LoadLibraryA("overlay.dll"); | |
Level thumper; | |
thumper.name = new char[100](); | |
thumper.difficulty = 4; | |
thumper.song = new char[100](); | |
thumper.stars = 10; | |
strcpy(thumper.name, "Thumper"); | |
strcpy(thumper.song, "../Songs/thumper.mp3"); | |
Level cf2; | |
cf2.name = new char[100](); | |
cf2.difficulty = 6; | |
cf2.song = new char[100](); | |
cf2.stars = 16; | |
strcpy(cf2.name, "Clutterfunk 2"); | |
strcpy(cf2.song, "../Songs/Clutterfunk2.mp3"); | |
Level aura; | |
aura.name = new char[100](); | |
aura.difficulty = 5; | |
aura.song = new char[100](); | |
aura.stars = 11; | |
strcpy(aura.name, "Aura"); | |
strcpy(aura.song, "../Songs/Aura.mp3"); | |
Level jr; | |
jr.name = new char[100](); | |
jr.difficulty = 5; | |
jr.song = new char[100](); | |
jr.stars = 12; | |
strcpy(jr.name, "Jack Russel"); | |
strcpy(jr.song, "../Songs/JackRussel.mp3"); | |
levels.push_back(thumper); | |
levels.push_back(cf2); | |
levels.push_back(aura); | |
levels.push_back(jr); | |
SetupLevels(); | |
U8Overlay *director = new U8Overlay(); | |
return 0; | |
} | |
BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved) | |
{ | |
if (dwReason == DLL_PROCESS_ATTACH) | |
CreateThread(NULL, 0x1000, &MainThread, NULL, 0, NULL); | |
return TRUE; | |
} | |
//applying functions | |
uint32_t SetupLevel(const Level &level, int8_t iter, uint32_t base) | |
{ | |
uint8_t *addr; | |
if (addr = reinterpret_cast<uint8_t*>(VirtualAlloc(NULL, 0x1000, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE))) | |
{ | |
memcpy(addr, _level_payload, 107); //writing level assembly chunk to allocation | |
memcpy(&addr[0x04], &iter, sizeof(iter)); //writing level id | |
memcpy(&addr[0x1E], &iter, sizeof(iter)); //writing level id | |
memcpy(&addr[0x36], &level.stars, sizeof(level.stars)); //writing level stars | |
memcpy(&addr[0x2A], &level.difficulty, sizeof(level.difficulty)); //writing level difficulty id | |
Hook(reinterpret_cast<uint32_t>(&addr[0x0A]), reinterpret_cast<void*>(0x4A9AD0), true); //writing get level name call | |
Hook(reinterpret_cast<uint32_t>(&addr[0x66]), reinterpret_cast<void*>(0x4A9A25), false); //writing jmp break | |
memcpy(&addr[NAME_ALLOC_OFFSET], _name_payload, 17); //writing level name assembly chunk to allocation | |
memcpy(&addr[STR_ALLOC_OFFSET], level.name, strlen(level.name)); //writing level name | |
SetMem(reinterpret_cast<uint32_t>(&addr[NAME_ALLOC_OFFSET + 1]), reinterpret_cast<uint32_t>(&addr[STR_ALLOC_OFFSET])); //writing level name address | |
Hook(reinterpret_cast<uint32_t>(&addr[NAME_ALLOC_OFFSET + 5]), reinterpret_cast<void*>(0x4055C0), true); | |
memcpy(&addr[SONG_ALLOC_OFFSET], _name_payload, 17); //writing song assembly chunk to allocation | |
memcpy(&addr[STR2_ALLOC_OFFSET], level.song, strlen(level.song)); //writing song file name | |
SetMem(reinterpret_cast<uint32_t>(&addr[SONG_ALLOC_OFFSET + 1]), reinterpret_cast<uint32_t>(&addr[STR2_ALLOC_OFFSET])); //writing song file name address | |
Hook(reinterpret_cast<uint32_t>(&addr[SONG_ALLOC_OFFSET + 5]), reinterpret_cast<void*>(0x4055C0), true); | |
} | |
return reinterpret_cast<uint32_t>(addr); | |
} | |
void SetupLevels() | |
{ | |
if (levels.size() == 0) //if there are zero levels the game will crash, so we just don't patch anything if so | |
return; | |
uint32_t base = reinterpret_cast<uint32_t>(GetModuleHandle(NULL)); | |
jump_table = new uint32_t[DEFAULT_LEVELS + levels.size()]; //allocating space for jump table | |
memcpy(&jump_table[0], reinterpret_cast<void*>(0x4A9A7C), 4 * DEFAULT_LEVELS); //copying over current jump table | |
SetMem(0x4A92A2, &jump_table[0]); //writing new address of jump table | |
SetMem(0x4A6158, static_cast<int8_t>(levels.size() + DEFAULT_LEVELS + 0)); //changing loop iteration count | |
SetMem(0x4A929C, static_cast<int8_t>(levels.size() + DEFAULT_LEVELS - 1)); //change switch default jump value | |
//ditto | |
name_table = new uint32_t[DEFAULT_NAMES + levels.size()]; | |
memcpy(&name_table[0], reinterpret_cast<void*>(0x4A9C68), 4 * DEFAULT_NAMES); | |
SetMem(0x4A9AEB, &name_table[0]); | |
SetMem(0x4A9AE1, static_cast<int8_t>(levels.size() + DEFAULT_NAMES - 1)); | |
//ditto | |
song_table = new uint32_t[DEFAULT_LEVELS + levels.size()]; | |
memcpy(&song_table[0], reinterpret_cast<void*>(0x4A9E48), 4 * DEFAULT_LEVELS); | |
SetMem(0x4A9CDA, &song_table[0]); | |
SetMem(0x4A9CD0, static_cast<int8_t>(levels.size() + DEFAULT_LEVELS - 1)); | |
for (int i = 0; i < levels.size(); ++i) | |
{ | |
jump_table[DEFAULT_LEVELS + i] = SetupLevel(levels[i], DEFAULT_LEVELS + i, base); | |
//std::cout << std::hex << jump_table[DEFAULT_LEVELS + i] << '\n'; | |
name_table[DEFAULT_NAMES + i] = jump_table[DEFAULT_LEVELS + i] + NAME_ALLOC_OFFSET; | |
song_table[DEFAULT_LEVELS + i] = jump_table[DEFAULT_LEVELS + i] + SONG_ALLOC_OFFSET; | |
} | |
//song picker | |
SetMem<uint8_t>(0x49A37E, levels.size() + DEFAULT_LEVELS - 1); | |
SetMem<uint32_t>(0x49A38B, levels.size() + DEFAULT_LEVELS - 1); | |
SetMem<uint32_t>(0x49A40A, levels.size() + DEFAULT_LEVELS - 1); | |
} | |
//memory functions | |
void CopyOver(uint32_t address, const void *data, size_t len) | |
{ | |
DWORD old; | |
VirtualProtect(reinterpret_cast<void*>(address), len, PAGE_EXECUTE_READWRITE, &old); | |
memcpy(reinterpret_cast<void*>(address), data, len); | |
VirtualProtect(reinterpret_cast<void*>(address), len, old, &old); | |
} | |
template <typename T> | |
void SetMem(uint32_t address, T data) | |
{ | |
DWORD old; | |
VirtualProtect(reinterpret_cast<void*>(address), sizeof(T), PAGE_EXECUTE_READWRITE, &old); | |
memcpy(reinterpret_cast<void*>(address), &data, sizeof(T)); | |
VirtualProtect(reinterpret_cast<void*>(address), sizeof(T), old, &old); | |
} | |
void Hook(uint32_t from, void *to, bool call) | |
{ | |
HANDLE hProcess = GetCurrentProcess(); | |
DWORD old; | |
uint32_t offset = (uint32_t)to - from - 5; | |
VirtualProtectEx(hProcess, (void*)from, 5, PAGE_EXECUTE_READWRITE, &old) && | |
WriteProcessMemory(hProcess, (void*)from, call ? "\xE8" : "\xE9", 1, NULL) && | |
WriteProcessMemory(hProcess, (void*)(from + 1), &offset, 4, NULL) && | |
VirtualProtectEx(hProcess, (void*)from, 5, old, &old); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment