Cube-World-Mod-Launcher/CallbackManager/main.cpp

411 lines
12 KiB
C++

#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("push eax");
asm("push ebx");
asm("push ecx");
asm("push edx");
asm("push edi");
asm("push esi");
asm("push eax");
asm("call [_HandleZoneLoaded_ptr]");
asm("pop esi");
asm("pop edi");
asm("pop edx");
asm("pop ecx");
asm("pop ebx");
asm("pop eax");
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("push eax");
asm("push ebx");
asm("push ecx");
asm("push edx");
asm("push edi");
asm("push esi");
asm("push ecx"); //Zone ptr
asm("call [_HandleZoneDelete_ptr]");
asm("pop esi");
asm("pop edi");
asm("pop edx");
asm("pop ecx");
asm("pop ebx");
asm("pop eax");
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]");
}
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]");
}
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);
break;
}
return true;
}