here the DLL code,worked with a older version i don't play rom anymore but maybe it will help you:
Code:
/* MouseControl.cpp
Exports 2 functions:
- void MouseClick(DWORD X,DWORD Y)
- void MouseMove(DWORD X,DWORD Y)
Credits to:
-me(backtoreality) ;)
-elverion
*/
//Header
#include "stdafx.h"
#include <windows.h>
#include <tchar.h>
#include <stdio.h>
//Detours 2.1
#include <detours.h>
#pragma comment(lib, "detours.lib" )
#define EXPORT extern "C" __declspec(dllexport)
//Logfile
#define LOGFILENAME "C:\\temp\\Log.txt"
//Adresses
#define PLAYERBASE_PTR 0x0088FF40
#define InjectAddress 0x00681D7A
#define InjectAddressJumpFrom (InjectAddress + 6)
//Offsets
#define OFF_MOUSE_X 0x03A4 //DWORD
#define OFF_MOUSE_Y 0x03A8 //DWORD
#define OFF_INGAME_MOUSE_BUTTON_UP 0x03AC //DWORD
#define OFF_INGAME_MOUSE_BUTTON_DOWN 0x03B0 //DWORD
#define OFF_BG_Flag 0x2C //Byte
//Globale Variablen
DWORD BasePTR;
LPVOID MemSpace;
DWORD VarPTR;
bool Injected=false;
enum Events{No_Event,DoMouseClick,DoResetMouseButtons,DoMouseMove};
#pragma data_seg(".shared")
bool Inject = true;
int Event = No_Event;
DWORD Mouse_X = 0;
DWORD Mouse_Y = 0;
#pragma data_seg()
#pragma comment(linker,"/SECTION:.shared,RWS")
//Functions we need:
void CreateJump(DWORD JumpFrom,DWORD JumpTo,BYTE* buffer);
void InsertAdress(DWORD Addr,BYTE* buffer);
void AdjustCodeCave(DWORD VarPTR,BYTE* CodeCave);
void InsertCodeCave();
bool LogWriteProcessMemory(HANDLE hProcess,LPVOID lpBaseAddress,LPCVOID lpBuffer,SIZE_T nSize);
void WriteLogFileLine(char * format,...);
//Exported Functions
//performs a mouse click at X,Y
EXPORT void MouseClick(DWORD X,DWORD Y){
Mouse_X = X;
Mouse_Y = Y;
Event = DoMouseClick;
}
//moves the mouse to X,Y in memory
EXPORT void MouseMove(DWORD X,DWORD Y){
Mouse_X = X;
Mouse_Y = Y;
Event = DoMouseMove;
}
//Hooked Functions
extern "C" {
//Runes of Magic uses ASCII
static LRESULT (WINAPI *Real_DispatchMessageA)( const MSG* msg) = DispatchMessageA;
}
//DispatchMessage is very often called so we use this function to check if we have something to do
LRESULT WINAPI Mine_DispatchMessageA( const MSG* msg )
{
if( Event == DoMouseClick ){
BYTE BNull = 0x00;
DWORD PerformClick = 0x00000001;
DWORD NullWert = 0x00000000;
DWORD error;
WriteLogFileLine("Performing MouseClick at X: %i Y: %i",(int)Mouse_X,(int)Mouse_Y);
//Set BG_Flag to 0
LogWriteProcessMemory(GetCurrentProcess(),(LPVOID)(BasePTR+OFF_BG_Flag),(LPCVOID)&BNull,sizeof(BYTE));
//Set MousePos_X
LogWriteProcessMemory(GetCurrentProcess(),(LPVOID)(BasePTR+OFF_MOUSE_X),&Mouse_X,sizeof(DWORD));
//Set MousePos_Y
LogWriteProcessMemory(GetCurrentProcess(),(LPVOID)(BasePTR+OFF_MOUSE_Y),&Mouse_Y,sizeof(DWORD));
//Set Ingame Mouse Button Down
LogWriteProcessMemory(GetCurrentProcess(),(LPVOID)(BasePTR+OFF_INGAME_MOUSE_BUTTON_DOWN),&PerformClick,sizeof(DWORD));
//And remove the up value
LogWriteProcessMemory(GetCurrentProcess(),(LPVOID)(BasePTR+OFF_INGAME_MOUSE_BUTTON_UP),&NullWert,sizeof(DWORD));
//Execute Click
LogWriteProcessMemory(GetCurrentProcess(),(LPVOID)VarPTR,(LPCVOID)&PerformClick,sizeof(DWORD));
Event = DoResetMouseButtons;
return Real_DispatchMessageA( msg );
}
else if(Event == DoResetMouseButtons){
DWORD dEins = 0x00000001;
DWORD dNull = 0x00000000;
//Set Ingame Left Mouse Button Up
LogWriteProcessMemory(GetCurrentProcess(),(LPVOID)(BasePTR+OFF_INGAME_MOUSE_BUTTON_DOWN),&dNull,sizeof(DWORD));
LogWriteProcessMemory(GetCurrentProcess(),(LPVOID)(BasePTR+OFF_INGAME_MOUSE_BUTTON_UP),&dEins,sizeof(DWORD));
}
else if(Event == DoMouseMove){
BYTE BNull = 0x00;
WriteLogFileLine("Performing MouseMove to X: %i Y: %i",(int)Mouse_X,(int)Mouse_Y);
//Set BG_Flag to 0
LogWriteProcessMemory(GetCurrentProcess(),(LPVOID)(BasePTR+OFF_BG_Flag),(LPCVOID)&BNull,sizeof(BYTE));
//Set MousePos_X
LogWriteProcessMemory(GetCurrentProcess(),(LPVOID)(BasePTR+OFF_MOUSE_X),&Mouse_X,sizeof(DWORD));
//Set MousePos_Y
LogWriteProcessMemory(GetCurrentProcess(),(LPVOID)(BasePTR+OFF_MOUSE_Y),&Mouse_Y,sizeof(DWORD));
}
Event = No_Event;
return Real_DispatchMessageA( msg );
}
BOOL APIENTRY DllMain( HMODULE hModule, DWORD dwReason, LPVOID lpReserved )
{
int err = 0;
switch( dwReason ) {
case DLL_PROCESS_ATTACH:
DisableThreadLibraryCalls( hModule );
if(Inject == true){
remove(LOGFILENAME);
WriteLogFileLine("Attached...");
//Avoid anew injection
Inject = false;
Injected = true;
//Insert our CodeCave to enable MouseClick
InsertCodeCave();
//Read PlayerbasePTR, because we need it for BG_FLAG, Mouse X,Y Coord and Ingame MouseButton
ReadProcessMemory(GetCurrentProcess(),(VOID*)PLAYERBASE_PTR,&BasePTR,sizeof(DWORD),NULL);
WriteLogFileLine("PlayerBase: %X",BasePTR);
DetourTransactionBegin();
DetourUpdateThread( GetCurrentThread() );
DetourAttach( &(PVOID&)Real_DispatchMessageA, Mine_DispatchMessageA );
DetourTransactionCommit();
}
break;
case DLL_PROCESS_DETACH:
if(Injected){
WriteLogFileLine("Detached...");
DetourTransactionBegin();
DetourUpdateThread( GetCurrentThread() );
DetourDetach( &(PVOID&)Real_DispatchMessageA, Mine_DispatchMessageA );
DetourTransactionCommit();
}
break;
}
return TRUE;
}
//write to log
void WriteLogFileLine(char * format,...){
FILE* pLog = fopen(LOGFILENAME,"a");
char buffer[512];
va_list args;
va_start (args, format);
vsprintf (buffer,format, args);
strcat(buffer,"\n");
fputs(buffer,pLog);
va_end (args);
fclose(pLog);
}
//insert the codecave into memory
void InsertCodeCave(){
//Patch and CodeCave
/*
CodeCave:
CMP BYTE PTR DS:[VAR],1
JNE SHORT 0x0E
MOV BYTE PTR DS:[ESI+100],1
MOV BYTE PTR DS:[VAR],0
CMP BYTE PTR DS:[ESI+100],AL
JMP 00681D80
*/
BYTE CodeCave[] = {0x80,0x3D,0x00,0x00,0x00,0x00,0x01,0x75,0x0E,0xC6,0x86,0x00,0x01,0x00,0x00,0x01,0xC6,0x05,0x00,0x00,0x00,0x00,0x00,0x38,0x86,0x00,0x01,0x00,0x00,0xE9,0xFE,0x1D,0xC0,0x88};
BYTE CallToCC[6];
//CodeCave sizeof(CodeCave)
//Variable 4 Byte
MemSpace = VirtualAlloc(NULL,sizeof(CodeCave)+4,MEM_COMMIT | MEM_RESERVE,PAGE_EXECUTE_READWRITE);
VarPTR = (DWORD)((DWORD)MemSpace + sizeof(CodeCave));
CallToCC[0] = 0x90; //NOP damit es passt
CreateJump(InjectAddressJumpFrom,((DWORD)MemSpace),&CallToCC[1]);
AdjustCodeCave((DWORD)MemSpace+sizeof(CodeCave),CodeCave);
WriteLogFileLine("CodeCave at: %X",(DWORD)MemSpace);
//Write CodeCave first
LogWriteProcessMemory(GetCurrentProcess(),(LPVOID)((DWORD)MemSpace),CodeCave,sizeof(CodeCave));
//Now write Call into Process
LogWriteProcessMemory(GetCurrentProcess(),(LPVOID)InjectAddress,CallToCC,sizeof(CallToCC));
}
//adjust códecave with VarPTR and adjust jump at the end
void AdjustCodeCave(DWORD VarPTR,BYTE* CodeCave){
/*Anzupassende Adressen:
- 2 VarPTR
- 18 VarPTR
- 30 InjectAddressJumpFrom
*/
InsertAdress(VarPTR,&CodeCave[2]);
InsertAdress(VarPTR,&CodeCave[18]);
CreateJump(VarPTR,InjectAddressJumpFrom,&CodeCave[29]);
}
//Insert an adress into an array of bytes
void InsertAdress(DWORD Addr,BYTE* buffer){
buffer[0] = Addr;
buffer[1] = Addr>>8;
buffer[2] = Addr>>16;
buffer[3] = Addr>>24;
}
//Creates an Jump from JumpFrom to JumpTo which needs 5 Bytes
void CreateJump(DWORD JumpFrom,DWORD JumpTo,BYTE* buffer){
DWORD diff = JumpTo-JumpFrom;
buffer[0] = 0xE9; //JMP
buffer[1] = diff;
buffer[2] = diff>>8;
buffer[3] = diff>>16;
buffer[4] = diff>>24;
}
bool LogWriteProcessMemory(HANDLE hProcess,LPVOID lpBaseAddress,LPCVOID lpBuffer,SIZE_T nSize){
unsigned long BytesWritten=0,error=0;
DWORD Address;
if( WriteProcessMemory(hProcess,lpBaseAddress,lpBuffer,nSize,&BytesWritten) == NULL ){
error = GetLastError();
Address = (DWORD)lpBaseAddress;
WriteLogFileLine("Error: %i. Fail to write at Address: %X. ",error,Address);
return false;
} else {
WriteLogFileLine("Success writing at: %X. %i Bytes written.",(DWORD)lpBaseAddress,BytesWritten);
return true;
}
}
Some comments in code and here is an explanation of injected code:
Code in Client.exe at 0x00681D6E:
Code:
00681D6E 8B7424 14 MOV ESI,DWORD PTR SS:[ESP+14] //unimportant
00681D72 8A91 00090000 MOV DL,BYTE PTR DS:[ECX+900] //unimportant
00681D78 32C0 XOR AL,AL //set AL = 0
00681D7A 3886 00010000 CMP BYTE PTR DS:[ESI+100],AL //is BYTE PTR DS:[ESI+100] = 0?
00681D80 74 0A JE SHORT Client.00681D8C //if yes then jump
Explanation of this code snippet:
CMP BYTE PTR DS:[ESI+100],AL: compares a Stack Variable(looks like Heap but its really on stack, i checked it with ollydbg) which is set by GetStateDevice(which i found with your help) and if [ESI+100] = 1 then jump is not taken(else we would jump JE SHORT Client.00681D8C) and if jump is not taken mouseclick is performed at mouse coords, which also are located in memory(PLAYERBASE_PTR + OFF_MOUSE_X/OFF_MOUSE_Y).
Because we can't write to Stack with WriteProcessMemory we need this little codecave which sets MOV BYTE PTR DS:[ESI+100],1 when we set VAR to 1. Now we can "write to stack" with that codecave.
CodeCave in ASM:
Code:
CMP BYTE PTR DS:[VAR],1 //Check if we should modify stack so our dll should manipulate Var
JNE SHORT 0x0E //when VAR = 0 leave everything untouched
MOV BYTE PTR DS:[ESI+100],1 //else set stack variable to 1
MOV BYTE PTR DS:[VAR],0 //set var to 0 so only 1 click is performed
CMP BYTE PTR DS:[ESI+100],AL //copy from real code, because we must override 00681D7A with our jump to this codecave
JMP 00681D80 //jump to 00681D80( JE SHORT Client.00681D8C)
So now we only need to override CMP BYTE PTR DS:[ESI+100],AL with a jump to our codecave which will look like this:
New Code in Client.exe after overriding CMP BYTE PTR DS:[ESI+100],AL
Code:
00681D6E 8B7424 14 MOV ESI,DWORD PTR SS:[ESP+14] //unimportant
00681D72 8A91 00090000 MOV DL,BYTE PTR DS:[ECX+900] //unimportant
00681D78 32C0 XOR AL,AL
00681D7A E9 CodeCave JMP CODECAVE //Jump to CodeCave
90 NOP //need a NOP here because CMP BYTE PTR
// DS:[ESI+100],AL = 6bytes but
// our jump needs only 5 bytes so 1 NOP
00681D80 74 0A JE SHORT Client.00681D8C //here we jump after codecave
So InjectAddress 0x00681D7A is the Address where we must override the code with our jump to our codecave. CodeCave helps to manipulate the stack variable for our mouseclick.
By the way you have to set the BG_Flag(Is in backgorund_flag) to false, otherwise the codecave wouldn't be executed.
Mouse click also works with hidden window!!
EDIT: If you want to use this in newest version you only have to edit:
#define PLAYERBASE_PTR 0x0088FF40
#define InjectAddress 0x00681D7A
to get the InjectAddress you only need to scan client.exe for 8B 74 24 14 8A 91 00 09 00 00 32 C0 38 86 00 01 00 00.