Merge remote-tracking branch 'origin/1.0.0-0'
This commit is contained in:
commit
fbdc0cc24c
|
@ -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;
|
|
||||||
}
|
|
|
@ -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);
|
||||||
|
}
|
|
@ -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
|
|
@ -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;
|
||||||
|
}
|
|
@ -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
|
|
@ -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;
|
||||||
|
}
|
|
@ -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
|
|
@ -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
|
||||||
|
}
|
|
@ -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
|
|
@ -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;
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
|
@ -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
|
20
README.md
20
README.md
|
@ -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
117
main.cpp
|
@ -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;
|
|
||||||
}
|
|
Loading…
Reference in New Issue