Skip to content

Instantly share code, notes, and snippets.

@absoIute
Created January 20, 2024 19:51
Show Gist options
  • Save absoIute/3c0db12e8b94f0acc609144eb1e69c0a to your computer and use it in GitHub Desktop.
Save absoIute/3c0db12e8b94f0acc609144eb1e69c0a to your computer and use it in GitHub Desktop.
1.9 level manager
//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