Merge remote-tracking branch 'origin/1.0.0-0'

This commit is contained in:
ChrisMiuchiz 2019-09-22 19:27:13 -04:00
commit fbdc0cc24c
14 changed files with 504 additions and 539 deletions

View File

@ -1,416 +0,0 @@
#include "main.h"
#include <vector>
#define no_shenanigans __attribute__((noinline)) __declspec(dllexport)
#define MakeCallback(callbackName, callbackReturnType, registrarFunctionName, vectorName)\
typedef callbackReturnType (__stdcall *callbackName)( ... );\
std::vector<callbackName> vectorName;\
extern "C" void DLL_EXPORT registrarFunctionName(callbackName func){\
vectorName.push_back(func);\
}
UINT_PTR base;
//Chat Events
MakeCallback(ChatEventCallback, bool, RegisterChatEventCallback, chat_event_callbacks);
bool DLL_EXPORT HandleChatEvent(wchar_t buf[], unsigned int msg_size){
bool cancelChatDisplay = false;
wchar_t msg[1024] = { 0 };
memcpy(msg, buf, msg_size * 2); //the message should be null terminated
for (ChatEventCallback func : chat_event_callbacks){
bool cancel = func(msg, msg_size);
if (cancel){
cancelChatDisplay = true;
}
}
return cancelChatDisplay;
}
DWORD HandleChatEvent_ptr = (DWORD)&HandleChatEvent;
_declspec(naked) void DLL_EXPORT ASMHandleMessage(){
asm("mov eax, [_base]");
asm("add eax, 0x36B1C8");
asm("mov eax, [eax]"); //eax points to gamecontroller
asm("mov eax, dword ptr [eax + 0x800A14]"); //eax points to ChatWidget
asm("mov eax, dword ptr [eax + 0x178]"); //get message size
asm("push eax");
asm("lea eax, [ebp - 0x128 + 0x4]");
asm("mov eax, [eax]"); //get message
asm("push eax");
asm("call [_HandleChatEvent_ptr]");
asm("cmp eax, 0"); //message ptr
asm("je 0f");
asm("1:");
asm("mov ecx, [_base]"); //jump to end
asm("add ecx, 0x7E6BF");
asm("jmp ecx");
asm("0:"); //exit normally
asm("mov eax, [_base]"); //jump back
asm("add eax, 0x7E621");
asm("cmp dword ptr [edi + 0x8006CC], 0"); //original comparison
asm("jmp eax");
}
//Zone Loaded
MakeCallback(ZoneLoadedCallback, void, RegisterZoneLoadedCallback, zone_loaded_callbacks);
void __stdcall no_shenanigans HandleZoneLoaded(unsigned int zone_ptr){
for (ZoneLoadedCallback func : zone_loaded_callbacks){
func(zone_ptr);
}
}
DWORD HandleZoneLoaded_ptr = (DWORD)&HandleZoneLoaded;
unsigned int ASMHandleZoneLoaded_JMP_back;
_declspec(naked) void DLL_EXPORT ASMHandleZoneLoaded(){
asm("pushad");
asm("push eax");
asm("call [_HandleZoneLoaded_ptr]");
asm("popad");
asm("mov ecx, [ebx]"); //Original code
asm("add ecx, 0x800D44");
asm("jmp [_ASMHandleZoneLoaded_JMP_back]");
}
//Zone Destructed
MakeCallback(ZoneDeleteCallback, void, RegisterZoneDeleteCallback, zone_delete_callbacks);
void __stdcall no_shenanigans HandleZoneDelete(unsigned int zone_ptr){
for (ZoneDeleteCallback func : zone_delete_callbacks){
func(zone_ptr);
}
}
DWORD HandleZoneDelete_ptr = (DWORD)&HandleZoneDelete;
unsigned int ASMHandleZoneDelete_JMP_back;
_declspec(naked) void DLL_EXPORT ASMHandleZoneDelete(){
asm("pushad");
asm("push ecx"); //Zone ptr
asm("call [_HandleZoneDelete_ptr]");
asm("popad");
asm("push ebp"); //Original code
asm("mov ebp, esp");
asm("push esi");
asm("mov esi, ecx");
asm("jmp [_ASMHandleZoneDelete_JMP_back]");
}
//Check M3. returning -1 means force disable. 0 means act as normal. 1 means force enable
MakeCallback(DodgeAttemptCheckCallback, int, RegisterDodgeAttemptCheckCallback, dodge_attempt_check_callbacks);
int __stdcall no_shenanigans HandleDodgeAttemptCheck(unsigned int attempting_to_dodge){
int need_to_dodge = 0;
for (DodgeAttemptCheckCallback func : dodge_attempt_check_callbacks){
unsigned int need_to_dodge_2 = func(attempting_to_dodge);
if (need_to_dodge_2 != 0){
need_to_dodge = need_to_dodge_2;
}
}
return need_to_dodge;
}
DWORD HandleDodgeAttemptCheck_ptr = (DWORD)&HandleDodgeAttemptCheck;
unsigned int ASMM3Check_JMP_back;
_declspec(naked) void DLL_EXPORT ASMM3Check(){
asm("movss dword ptr [esp+0x18], xmm6"); //original code
asm("movss dword ptr [esp+0x80], xmm6");
asm("push ebx");
asm("push eax");
asm("push ebx");
asm("call [_HandleDodgeAttemptCheck_ptr]");
asm("mov ebx, eax"); //result
asm("cmp ebx, -1");
asm("je 0f"); //Disable
asm("cmp ebx, 0");
asm("je 1f"); //Do nothing
//Enable
asm("pop ebx");
asm("pop eax");
asm("mov ebx, 0");
asm("jmp [_ASMM3Check_JMP_back]");
asm("0:"); //Disable
asm("pop ebx");
asm("pop eax");
asm("mov ebx, 1");
asm("jmp [_ASMM3Check_JMP_back]");
asm("1:"); //Do nothing
asm("pop eax");
asm("pop ebx");
asm("jmp [_ASMM3Check_JMP_back]");
}
//Check M1. returning -1 means force disable. 0 means act as normal. 1 means force enable
MakeCallback(PrimaryAttackAttemptCheckCallback, int, RegisterPrimaryAttackAttemptCheckCallback, primary_attack_attempt_callbacks);
int __stdcall no_shenanigans HandlePrimaryAttackAttemptCheck(unsigned int attempting_to_attack){
int need_to_attack = 0;
for (PrimaryAttackAttemptCheckCallback func : primary_attack_attempt_callbacks){
unsigned int need_to_attack_2 = func(attempting_to_attack);
if (need_to_attack_2 != 0){
need_to_attack = need_to_attack_2;
}
}
return need_to_attack;
}
DWORD HandlePrimaryAttackAttemptCheck_ptr = (DWORD)&HandlePrimaryAttackAttemptCheck;
unsigned int ASMM1Check_JMP_Enable;
unsigned int ASMM1Check_JMP_Disable;
_declspec(naked) void DLL_EXPORT ASMM1Check(){
asm("push eax");
asm("movzx eax, byte ptr [edi+0x4]");
asm("push eax");
asm("call [_HandlePrimaryAttackAttemptCheck_ptr]");
asm("cmp eax, -1");
asm("je 0f"); //Disable
asm("cmp eax, 0");
asm("je 1f"); //Do nothing
//Enable
asm("pop eax");
asm("jmp [_ASMM1Check_JMP_Enable]");
asm("0:"); //Disable
asm("pop eax");
asm("jmp [_ASMM1Check_JMP_Disable]");
asm("1:"); //Do nothing
asm("pop eax");
asm("cmp byte ptr [edi+0x4], 0"); //original code
asm("jz 2f");
asm("jmp [_ASMM1Check_JMP_Enable]");
asm("2:"); //the disable option from original code
asm("jmp [_ASMM1Check_JMP_Disable]"); //Can't do this with jz
}
//Check abilities. returning -1 means force disable. 0 means act as normal. 1 means force enable
//I don't know why you would want to enable this, but for consistency it will be like this.
MakeCallback(AbilityAttackAttemptCheckCallback, int, RegisterAbilityAttackAttemptCheckCallback, ability_attack_attempt_callbacks);
int __stdcall no_shenanigans HandleAbilityAttackAttemptCheck(unsigned int attempting_to_attack, unsigned int keyNumber){
int need_to_attack = 0;
for (AbilityAttackAttemptCheckCallback func : ability_attack_attempt_callbacks){
unsigned int need_to_attack_2 = func(attempting_to_attack, keyNumber);
if (need_to_attack_2 != 0){
need_to_attack = need_to_attack_2;
}
}
return need_to_attack;
}
DWORD HandleAbilityAttackAttemptCheck_ptr = (DWORD)&HandleAbilityAttackAttemptCheck;
unsigned int ASMAbilitiesCheck_JMP_Back;
_declspec(naked) void DLL_EXPORT ASMAbilitiesCheck(){
asm("push eax");
asm("push esi"); //keyNumber
asm("movzx eax, byte ptr [edi+esi+0x4]"); //attempting to attack
asm("push eax");
asm("call [_HandleAbilityAttackAttemptCheck_ptr]");
asm("cmp eax, -1");
asm("je 0f"); //Disable
asm("cmp eax, 0"); //Do nothing
asm("je 1f");
//Enable
asm("mov eax, 1");
asm("cmp eax, 0");
asm("pop eax");
asm("jmp [_ASMAbilitiesCheck_JMP_Back]");
asm("0:"); //Disable
asm("mov eax, 0");
asm("cmp eax, 0");
asm("pop eax");
asm("jmp [_ASMAbilitiesCheck_JMP_Back]");
asm("1:"); //Do nothing
asm("cmp byte ptr [edi+esi+0x4], 0"); //original code
asm("pop eax");
asm("jmp [_ASMAbilitiesCheck_JMP_Back]");
}
//Packets
MakeCallback(PacketCallback, int, RegisterPacketCallback, packet_callbacks);
int __stdcall no_shenanigans HandlePacket(unsigned int packet_ID, unsigned int socket_ptr){
int handled = 0;
for (PacketCallback func : packet_callbacks){
unsigned int handled_2 = func(packet_ID, socket_ptr);
if (handled_2 != 0){
handled = handled_2;
}
}
return handled;
}
DWORD HandlePacket_ptr = (DWORD)&HandlePacket;
unsigned int ASMHandlePacket_Invalid_Packet_JMP;
unsigned int ASMHandlePacket_Valid_Packet_JMP;
unsigned int ASMHandlePacket_Already_Handled_JMP;
_declspec(naked) void __declspec(dllexport) ASMHandlePacket(){
asm("pushad");
asm("push [ebp-0x11D8]"); //socket
asm("push [ebp-0x1220]"); //Packet ID
asm("call [_HandlePacket_ptr]");
asm("cmp eax, 0");
asm("je 0f"); //The packet was not handled
asm("popad"); //The packet WAS handled
asm("mov cl, [ebp-0x11D1]");
asm("jmp [_ASMHandlePacket_Already_Handled_JMP]");
asm("0:"); //The packet was not handled
asm("popad");
asm("mov eax, [ebp-0x1220]");//original code
asm("cmp eax, 0xF");
asm("ja 1f");
asm("jmp [_ASMHandlePacket_Valid_Packet_JMP]");
asm("1:");
asm("jmp [_ASMHandlePacket_Invalid_Packet_JMP]");
}
//ready to send a packet
MakeCallback(ReadyToSendCallback, void, RegisterReadyToSendCallback, ready_to_send_callbacks);
void __stdcall no_shenanigans HandleReadyToSend(SOCKET s){
for (ReadyToSendCallback func : ready_to_send_callbacks){
func(s);
}
}
DWORD HandleReadyToSend_ptr = (DWORD)&HandleReadyToSend;
unsigned int ASMHandleReadyToSend_JMP_Back;
void no_shenanigans ASMHandleReadyToSend(){
asm("pushad");
asm("mov eax, [edi]"); //GameController
asm("push dword ptr [eax+0x8006CC]"); //socket
asm("call [_HandleReadyToSend_ptr]");
asm("popad");
asm("push 0"); //original code
asm("push 4"); //len
asm("lea eax, [ebp-0x2444]");
asm("jmp [_ASMHandleReadyToSend_JMP_Back]");
}
//Finish crafting
MakeCallback(FinishCraftingCallback, void, RegisterFinishCraftingCallback, finish_crafting_callbacks);
void __stdcall no_shenanigans HandleFinishCrafting(){
for (FinishCraftingCallback func : finish_crafting_callbacks){
func();
}
}
DWORD HandleFinishCrafting_ptr = (DWORD)&HandleFinishCrafting;
unsigned int ASMHandleFinishCrafting_JMP_Back;
void no_shenanigans ASMHandleFinishCrafting(){
asm("pushad");
asm("call [_HandleFinishCrafting_ptr]");
asm("popad");
asm("mov ecx, [ebp-0xC]"); //original code
asm("mov dword ptr fs:[0], ecx");
asm("jmp [_ASMHandleFinishCrafting_JMP_Back]");
}
void WriteJMP(BYTE* location, BYTE* newFunction){
DWORD dwOldProtection;
VirtualProtect(location, 5, PAGE_EXECUTE_READWRITE, &dwOldProtection);
location[0] = 0xE9; //jmp
*((DWORD*)(location + 1)) = (DWORD)(( (unsigned INT32)newFunction - (unsigned INT32)location ) - 5);
VirtualProtect(location, 5, dwOldProtection, &dwOldProtection);
}
extern "C" DLL_EXPORT BOOL APIENTRY DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
{
base = (UINT_PTR)GetModuleHandle(NULL);
switch (fdwReason)
{
case DLL_PROCESS_ATTACH:
//Chat
WriteJMP((BYTE*)(base + 0x7E61A), (BYTE*)&ASMHandleMessage);
//Zone Load
ASMHandleZoneLoaded_JMP_back = base + 0x6ACDE;
WriteJMP((BYTE*)(base + 0x6ACD6), (BYTE*)&ASMHandleZoneLoaded);
//Zone Delete
ASMHandleZoneDelete_JMP_back = base + 0x224766;
WriteJMP((BYTE*)(base + 0x224760), (BYTE*)&ASMHandleZoneDelete);
//Check M3
ASMM3Check_JMP_back = base + 0xA6CD2;
WriteJMP((BYTE*)(base + 0xA6CC3), (BYTE*)&ASMM3Check);
//Check M1
ASMM1Check_JMP_Enable = base + 0x9BF82;
ASMM1Check_JMP_Disable = base + 0x9BFC8;
WriteJMP((BYTE*)(base + 0x9BF7C), (BYTE*)&ASMM1Check);
//Check abilities
ASMAbilitiesCheck_JMP_Back = base + 0x9B63A;
WriteJMP((BYTE*)(base + 0x9B635), (BYTE*)&ASMAbilitiesCheck);
//Handle packet
ASMHandlePacket_Already_Handled_JMP = base + 0x6D0E3;
ASMHandlePacket_Invalid_Packet_JMP = base + 0x6D0DD;
ASMHandlePacket_Valid_Packet_JMP = base + 0x6B8B0;
WriteJMP((BYTE*)(base + 0x6B8A7), (BYTE*)&ASMHandlePacket);
//Ready to send packet
ASMHandleReadyToSend_JMP_Back = base + 0x69C92;
WriteJMP((BYTE*)(base + 0x69C88), (BYTE*)&ASMHandleReadyToSend);
ASMHandleFinishCrafting_JMP_Back = base + 0x70D6B;
WriteJMP((BYTE*)(base + 0x70D61), (BYTE*)&ASMHandleFinishCrafting);
break;
}
return true;
}

View File

@ -0,0 +1,43 @@
#include "Process.h"
#include <windows.h>
using namespace std;
Process::Process(string path)
{
this->path = path;
ZeroMemory(&si, sizeof(si));
ZeroMemory(&pi, sizeof(pi));
}
Process::~Process()
{
//dtor
}
bool Process::InjectDLL(string dllName) {
LPVOID load_library = (LPVOID) GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")), "LoadLibraryA");
LPVOID remote_string = (LPVOID) VirtualAllocEx(pi.hProcess, NULL, strlen(dllName.c_str()) + 1, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
WriteProcessMemory(pi.hProcess, remote_string, dllName.c_str(), strlen(dllName.c_str()) + 1, NULL);
HANDLE thread = CreateRemoteThread(pi.hProcess, NULL, NULL, (LPTHREAD_START_ROUTINE) load_library, remote_string, CREATE_SUSPENDED, NULL);
ResumeThread(thread);
return true;
}
bool Process::Create() {
return CreateProcess(NULL,
(char*)path.c_str(),
NULL,
NULL,
true,
CREATE_SUSPENDED,
NULL,
NULL,
&si,
&pi);
}
void Process::Run() {
ResumeThread(pi.hThread);
CloseHandle(pi.hProcess);
}

24
CubeModLauncher/Process.h Normal file
View File

@ -0,0 +1,24 @@
#ifndef PROCESS_H
#define PROCESS_H
#include <iostream>
#include <windows.h>
class Process
{
public:
Process(std::string path);
virtual ~Process();
bool InjectDLL(std::string dllName);
bool Create();
void Run();
protected:
private:
std::string path;
STARTUPINFO si;
PROCESS_INFORMATION pi;
};
#endif // PROCESS_H

74
CubeModLauncher/crc.cpp Normal file
View File

@ -0,0 +1,74 @@
#include "crc.h"
#include <iostream>
unsigned int crc32_table[] = {
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
};
unsigned int crc32_buf(const char* buf, unsigned long len)
{
unsigned int crc = ~0;
while (len--)
crc = crc32_table[(crc ^ *buf++) & 0xFF] ^ (crc >> 8);
return crc ^ ~0;
}
unsigned int crc32_file(const char* fileName){
FILE* file = fopen(fileName, "rb");
fseek(file, 0, SEEK_END);
int fileSize = ftell(file);
char* fileContents = new char[fileSize+1];
fseek(file, 0, SEEK_SET);
fread(fileContents, 1, fileSize, file);
fclose(file);
int result = crc32_buf(fileContents, fileSize);
delete[] fileContents;
return result;
}

7
CubeModLauncher/crc.h Normal file
View File

@ -0,0 +1,7 @@
#ifndef CRC_H
#define CRC_H
unsigned int crc32_buf(const char* buf, unsigned long len);
unsigned int crc32_file(const char* fileName);
#endif // CRC_H

103
CubeModLauncher/main.cpp Normal file
View File

@ -0,0 +1,103 @@
#include "main.h"
#include <iostream>
#include <windows.h>
#include <vector>
#include "Process.h"
#include "crc.h"
#define CUBE_VERSION "0.9.1-0"
#define CUBE_PACKED_CRC 0x8B2EE791
#define CUBE_UNPACKED_CRC 0xC2845E38
#define MODLOADER_CRC 0x5858F9D7
#define CUBE_EXECUTABLE "cubeworld.exe"
using namespace std;
bool FileExists(const char* fileName) {
DWORD dwAttrib = GetFileAttributes(fileName);
return (dwAttrib != INVALID_FILE_ATTRIBUTES && !(dwAttrib & FILE_ATTRIBUTE_DIRECTORY));
}
int Bail(int result){
printf("Press enter to exit.\n");
cin.ignore();
return result;
}
int main(int argc, char** argv) {
bool testMode = false;
if (argc >= 2 && !strcmp(argv[1], "test")) {
testMode = true;
printf("Test mode enabled. CRC checks will be bypassed.\n");
}
//Cube world is obviously required
if (!FileExists(CUBE_EXECUTABLE)) {
printf("%s not found.\n", CUBE_EXECUTABLE);
return Bail(1);
}
unsigned int checksum = crc32_file(CUBE_EXECUTABLE);
if (testMode) {
printf("%s CRC: %08X\n", CUBE_EXECUTABLE, checksum);
}
// Check if the game is still packed
if (checksum == CUBE_PACKED_CRC && !testMode) {
printf("Cube World was found, but it is not unpacked.\n"
"Use Steamless to unpack %s.\n", CUBE_EXECUTABLE);
return Bail(1);
}
if (checksum != CUBE_UNPACKED_CRC && !testMode) {
printf("Cube World was found, but it is not version %s.\n"
"(Found CRC %08X, expected %08X)\n"
"Please update your game.\n",
CUBE_VERSION, checksum, CUBE_UNPACKED_CRC);
return Bail(1);
}
//Inject our dll
if ( !FileExists("CubeModLoader.dll") ) {
printf("CubeModLoader.dll not found.\n");
return Bail(1);
}
unsigned int loaderChecksum = crc32_file("CubeModLoader.dll");
if (loaderChecksum != MODLOADER_CRC && !testMode) {
printf("CubeModLoader.dll is the wrong version (%08X)\n", loaderChecksum);
return Bail(1);
}
if (testMode) {
printf("CubeModLoader.dll CRC: %08X\n", loaderChecksum);
}
Process process(CUBE_EXECUTABLE);
//Create game in suspended state
printf("Starting %s...\n\n", CUBE_EXECUTABLE);
if (!process.Create()) {
printf("Failed to create process: %lu", GetLastError());
return Bail(1);
} else {
printf("%s was successfully started.\n\n", CUBE_EXECUTABLE);
}
process.InjectDLL( std::string("CubeModLoader.dll") );
// Need to give the loader some time to work
// This is a horrible thing and probably will result in a race condition please help me
Sleep(250);
// Let Cube World run!
process.Run();
Sleep(3000);
return 0;
}

8
CubeModLauncher/main.h Normal file
View File

@ -0,0 +1,8 @@
#ifndef MAIN_H_INCLUDED
#define MAIN_H_INCLUDED
bool FileExists(char* fileName);
int Bail(int result);
int main(int argc, char** argv);
#endif // MAIN_H_INCLUDED

20
CubeModLoader/DLL.cpp Normal file
View File

@ -0,0 +1,20 @@
#include "DLL.h"
#include <iostream>
DLL::DLL(std::string fileName) {
this->fileName = fileName;
this->handle = nullptr;
}
HMODULE DLL::Load() {
this->handle = LoadLibraryA(this->fileName.c_str());
if (!this->handle) {
printf("Could not load %s: %d\n", this->fileName.c_str(), GetLastError());
exit(1);
}
return this->handle;
}
DLL::~DLL() {
//dtor
}

29
CubeModLoader/DLL.h Normal file
View File

@ -0,0 +1,29 @@
#ifndef DLL_H
#define DLL_H
#include <iostream>
#include <windows.h>
class DLL
{
public:
std::string fileName;
HMODULE handle;
FARPROC ModPreInitialize;
FARPROC ModInitialize;
FARPROC ModMajorVersion;
FARPROC ModMinorVersion;
// Callbacks
FARPROC HandleChat;
DLL(std::string fileName);
HMODULE Load();
virtual ~DLL();
protected:
private:
};
#endif // DLL_H

View File

@ -0,0 +1,47 @@
int ChatHandler(wchar_t* msg) {
for (DLL* dll: modDLLs) {
if (dll->HandleChat) {
if ( ((int(*)(wchar_t*))dll->HandleChat)(msg) ){
return 1;
}
}
}
return 0;
}
void* ChatHandler_ptr = (void*)&ChatHandler;
void* ASMChatHandler_jmpback;
void* ASMChatHandler_bail;
void no_optimize ASMChatHandler() {
asm(PUSH_ALL
"mov rcx, rsi \n" // The message
PREPARE_STACK
"call [ChatHandler_ptr] \n"
RESTORE_STACK
// Did the handler return true?
"test al, al \n"
"jnz bail \n"
POP_ALL
// original code
"mov qword ptr [rbp+0x98], 7 \n"
"mov [rbp+0x90], r15 \n"
"jmp [ASMChatHandler_jmpback] \n"
"bail: \n"
POP_ALL
"jmp [ASMChatHandler_bail]"
);
}
void SetupChatHandler() {
WriteFarJMP(base+0x87611, (void*)&ASMChatHandler);
ASMChatHandler_jmpback = (void*)base+0x87624;
ASMChatHandler_bail = (void*)base+0x879B2;
}

123
CubeModLoader/main.cpp Normal file
View File

@ -0,0 +1,123 @@
#include <iostream>
#include <windows.h>
#include <vector>
#include "DLL.h"
#define MOD_MAJOR_VERSION 1
#define MOD_MINOR_VERSION 1
#define no_optimize __attribute__((optimize("O0")))
#define MUST_IMPORT(dllname, name)\
dllname->name = GetProcAddress(dllname->handle, #name);\
if (!dllname->name) {\
Popup("Error", "%s does not export " #name ".\n", dllname->fileName.c_str());\
exit(1);\
}
#define IMPORT(dllname, name)\
dllname->name = GetProcAddress(dllname->handle, #name);
#define PUSH_ALL "push rax\npush rbx\npush rcx\npush rdx\npush rsi\npush rdi\npush rbp\npush r8\npush r9\npush r10\npush r11\npush r12\npush r13\npush r14\npush r15\n"
#define POP_ALL "pop r15\npop r14\npop r13\npop r12\npop r11\npop r10\npop r9\npop r8\npop rbp\npop rdi\npop rsi\npop rdx\npop rcx\npop rbx\npop rax\n"
#define PREPARE_STACK "mov rax, rsp \n and rsp, 0xFFFFFFFFFFFFFFF0 \n push rax \n sub rsp, 0x28 \n"
#define RESTORE_STACK "add rsp, 0x28 \n pop rsp \n"
using namespace std;
void* base;
vector <DLL*> modDLLs;
void WriteFarJMP(void* source, void* destination) {
DWORD dwOldProtection;
VirtualProtect(source, 14, PAGE_EXECUTE_READWRITE, &dwOldProtection);
char* location = (char*)source;
// Far jump
*((UINT16*)&location[0]) = 0x25FF;
// mode
*((UINT32*)&location[2]) = 0x00000000;
*((UINT64*)&location[6]) = (UINT64)destination;
VirtualProtect(location, 14, dwOldProtection, &dwOldProtection);
}
#include "callbacks/ChatHandler.h"
void SetupHandlers() {
SetupChatHandler();
}
void Popup(char* title, char* format, ... ){
char msg[512] = {0};
sprintf(msg, format);
MessageBoxA(0, msg, title, MB_OK | MB_ICONINFORMATION);
}
extern "C" __declspec(dllexport) BOOL APIENTRY DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) {
switch (fdwReason) {
case DLL_PROCESS_ATTACH:
base = GetModuleHandle(NULL);
SetupHandlers();
//Find mods
HANDLE hFind;
WIN32_FIND_DATA data;
CreateDirectory("Mods", NULL);
hFind = FindFirstFile("Mods\\*.dll", &data);
if (hFind != INVALID_HANDLE_VALUE) {
do {
// We should be loaded into the application's address space, so we can just LoadLibraryA
DLL* dll = new DLL(string("Mods\\") + data.cFileName);
dll->Load();
printf("Loaded %s\n", dll->fileName.c_str());
modDLLs.push_back(dll);
} while (FindNextFile(hFind, &data));
FindClose(hFind);
}
// Find all the functions the mods may export
for (DLL* dll: modDLLs) {
MUST_IMPORT(dll, ModMajorVersion);
MUST_IMPORT(dll, ModMinorVersion);
MUST_IMPORT(dll, ModPreInitialize);
IMPORT(dll, ModInitialize);
IMPORT(dll, HandleChat);
}
// Ensure version compatibility
for (DLL* dll: modDLLs) {
int majorVersion = ((int(*)())dll->ModMajorVersion)();
int minorVersion = ((int(*)())dll->ModMinorVersion)();
if (majorVersion != MOD_MAJOR_VERSION) {
Popup("Error", "%s has major version %d but requires %d.\n", dll->fileName.c_str(), majorVersion, MOD_MAJOR_VERSION);
exit(1);
}
if (minorVersion > MOD_MINOR_VERSION) {
Popup("Error", "%s has minor version %d but requires %d or lower.\n", dll->fileName.c_str(), minorVersion, MOD_MINOR_VERSION);
exit(1);
}
}
// Run Initialization routines on all mods
for (DLL* dll: modDLLs) {
((void(*)())dll->ModPreInitialize)();
}
for (DLL* dll: modDLLs) {
if (dll->ModInitialize) {
((void(*)())dll->ModInitialize)();
}
}
}
return true;
}

12
CubeModLoader/main.h Normal file
View File

@ -0,0 +1,12 @@
#ifndef MAIN_H
#define MAIN_H
#include "DLL.h"
#include <vector>
#define no_optimize __attribute__((optimize("O0")))
using namespace std;
vector <DLL*> modDLLs;
void* base;
void WriteFarJMP(void* source, void* destination);
#endif // MAIN_H

View File

@ -2,14 +2,22 @@
Supports injecting Cube World mods. DLLs must go in a folder called "Mods". Supports injecting Cube World mods. DLLs must go in a folder called "Mods".
If something doesn't work, make sure you have the latest release for the launcher and all your mods, along with Cube World.
If you need to update Cube World, you can use this: https://github.com/ChrisMiuchiz/CubeWorld-Cracker
## Installing ## Installing
Get the latest executable from Releases and place it in the same folder as Cube.exe Get the latest executable from Releases and place it in the same folder as cubeworld.exe
https://github.com/ChrisMiuchiz/Cube-World-Mod-Launcher/releases https://github.com/ChrisMiuchiz/Cube-World-Mod-Launcher/releases
## Installing Mods ## Installing Mods
A "Mods" folder should be created in the same folder as Cube.exe, and mods should be installed by moving them into the Mods folder. A "Mods" folder should be created in the same folder as cubeworld.exe, and mods should be installed by moving them into the Mods folder.
## Preparing cubeworld.exe
Since Cube World is using SteamStub obfuscation, you need to remove the obfuscation using [Steamless](https://github.com/atom0s/Steamless).
## Building the launcher or mods
This project will only ever support GCC. This program will not even build using MSVC, not only because the inline assembly syntax is different, but because support for inline assembly was removed for x86-64.
All mods MUST include cwmods.h from [cwsdk](https://github.com/ChrisMiuchiz/CWSDK) to function.
Compiler/Linker flags: `-m64 -masm=intel -static -static-libgcc -static-libstdc++`

117
main.cpp
View File

@ -1,117 +0,0 @@
#include <iostream>
#include <windows.h>
#include <vector>
using namespace std;
bool FileExists(LPCTSTR szPath)
{
DWORD dwAttrib = GetFileAttributes(szPath);
return (dwAttrib != INVALID_FILE_ATTRIBUTES && !(dwAttrib & FILE_ATTRIBUTE_DIRECTORY));
}
int main()
{
vector <std::string> modDLLs;
//Cube world is obviously required
if (!FileExists("Cube.exe")){
printf("Cube World not found.\n");
Sleep(1000);
return 1;
}
FILE *file = fopen("Cube.exe", "rb");
fseek(file, 0, SEEK_END);
int fileSize = ftell(file);
fclose(file);
const int CUBE_SIZE = 3885568;
if (fileSize != CUBE_SIZE){
printf("Cube World was found, but it is not version 0.1.1. Please update your game.\n");
printf("Press enter to exit.\n");
cin.ignore();
return 1;
}
//The callback manager is required.
if ( !FileExists("CallbackManager.dll") ){
printf("Callback manager not found.\n");
Sleep(1000);
return 1;
}
modDLLs.push_back( std::string("CallbackManager.dll") );
const char MOD_PATH[] = "Mods\\*.dll";
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory(&si, sizeof(si));
ZeroMemory(&pi, sizeof(pi));
CreateDirectory("Mods", NULL);
//Create game in suspended state
printf("Starting Cube.exe...\n\n");
if (!CreateProcess(NULL,
"Cube.exe",
NULL,
NULL,
true,
CREATE_SUSPENDED,
NULL,
NULL,
&si,
&pi))
{
printf("Failed to create process: %lu", GetLastError());
return 1;
}
else {
printf("Cube.exe was successfully started.\n\n");
}
//Find mods
HANDLE hFind;
WIN32_FIND_DATA data;
hFind = FindFirstFile(MOD_PATH, &data);
if (hFind != INVALID_HANDLE_VALUE) {
do {
modDLLs.push_back( std::string("Mods\\") + data.cFileName);
} while (FindNextFile(hFind, &data));
FindClose(hFind);
}
//Inject DLLs
vector <HANDLE> threads;
for (string S_DLLName : modDLLs){
printf("Loading %s\n", S_DLLName.c_str());
LPVOID load_library = (LPVOID) GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")), "LoadLibraryA");
LPVOID remote_string = (LPVOID) VirtualAllocEx(pi.hProcess, NULL, strlen(S_DLLName.c_str()) + 1, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
WriteProcessMemory(pi.hProcess, remote_string, S_DLLName.c_str(), strlen(S_DLLName.c_str()) + 1, NULL);
HANDLE thread = CreateRemoteThread(pi.hProcess, NULL, NULL, (LPTHREAD_START_ROUTINE) load_library, remote_string, CREATE_SUSPENDED, NULL);
threads.push_back(thread);
ResumeThread(thread);
}
ResumeThread(pi.hThread);
CloseHandle(pi.hProcess);
printf("\nAll available mods have been loaded.\n");
Sleep(1500);
//
//
// WaitForSingleObject(pi.hThread, INFINITE);
// for (HANDLE thread : threads){
// CloseHandle(thread);
// }
return 0;
}