Skip to content

Commit

Permalink
[Enhancement] Restore pointer after send message #1
Browse files Browse the repository at this point in the history
  • Loading branch information
SakuraKoi committed Jan 25, 2021
1 parent 2a9a74e commit dee9daa
Show file tree
Hide file tree
Showing 5 changed files with 226 additions and 122 deletions.
117 changes: 75 additions & 42 deletions BattlefieldChat/BattlefieldChat.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,66 +41,99 @@ int main() {
cout.flags(f);

hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
cout << " [*] 正在预分配内存..." << endl;
// This memory should not be freed, otherwise the game will crash (I'm too lazy to restore the pointer LOL)
// Possible memory leaks, but the size is small and therefore not a big problem
cout << " [*] 正在初始化..." << endl;
messageCaveAddr = (uintptr_t)VirtualAllocEx(hProcess, NULL, sizeof(char) * 91, MEM_COMMIT, PAGE_READWRITE);
cout << " [+] 申请内存成功: 0x" << hex << messageCaveAddr << endl;
cout << " [+] 预分配内存成功: 0x" << hex << messageCaveAddr << endl;
cout.flags(f);

Pointer messageCavePtr(hProcess, moduleBaseAddr);
messageCavePtr.pointer = messageCaveAddr;
ChatOpenPointer chatOpenPtr;
ChatLengthPointer chatLengthPtr;
ChatMessagePointer chatMessagePtr;

cout << " [+] Done! 在游戏中打开聊天即可自动呼出输入框" << endl;

InputDialog dialog;
bool lastState = false;
while (IsWindow(gameWindow)) {
bool state = isBattlefieldChatOpen();
if (!isFullscreenWindow(gameWindow) && !lastState && state) {
cout << endl << " [+] 检测到聊天框打开" << endl;
wstring str = dialog.showInputDialog(L"", gameWindow, isBorderlessWindow(gameWindow) ? 2 : 1);

SetForegroundWindow(gameWindow);
if (str.length() == 0) {
press(VK_ESCAPE, 20);
cout << " [-] 取消输入操作" << endl;
goto outer;
}
// Convert Simplified Chinese std::wstring to Traditional Chinese std::string
wstring trad = CHS2CHT(str);
string converted = WStrToStr(trad);
if (chatOpenPtr.refreshPointer()) {
bool state = chatOpenPtr.readBoolean();
if (!isFullscreenWindow(gameWindow) && !lastState && state) {
cout << endl << " [+] 检测到聊天框打开" << endl;
wstring str = dialog.showInputDialog(L"", gameWindow, isBorderlessWindow(gameWindow) ? 2 : 1);

int length = (converted.size() / sizeof(char));
SetForegroundWindow(gameWindow);
if (str.length() == 0) {
press(VK_ESCAPE, 20);
cout << " [-] 取消输入操作" << endl;
goto outer;
}
// Convert Simplified Chinese std::wstring to Traditional Chinese std::string
wstring trad = CHS2CHT(str);
string converted = WStrToStr(trad);

if (length > 90) {
press(VK_ESCAPE, 20);
MessageBox(NULL, L"聊天消息长度不能超过90字节", L"错误", 0);
cout << " [-] 聊天消息长度超过90字节" << endl;
goto outer;
}
int length = (converted.size() / sizeof(char));

if (!writeBattlefieldChatMessage(converted)) {
cout << " [-] 写入消息数据失败" << endl;
goto outer;
}
if (length > 90) {
press(VK_ESCAPE, 20);
MessageBox(NULL, L"聊天消息长度不能超过90字节", L"错误", 0);
cout << " [-] 聊天消息长度超过90字节" << endl;
goto outer;
}

if (!writeBattlefieldChatPointer()) {
cout << " [-] 重定向消息指针失败" << endl;
goto outer;
}
if (!chatLengthPtr.refreshPointer()) {
cout << " [-] 错误: 刷新指针失败 [ChatLength]" << endl;
goto outer;
}

// It may be possible to exceed the chat message length limit? But shouldn't do so, at risk of being banned
if (!writeBattlefieldChatLength(length)) {
cout << " [-] 写入消息长度失败" << endl;
goto outer;
}
if (!chatMessagePtr.refreshPointer()) {
cout << " [-] 错误: 刷新指针失败 [ChatMessage]" << endl;
goto outer;
}

uintptr_t oldAddr = chatMessagePtr.readAddress();
if (oldAddr == 0) {
cout << " [-] 错误: 读取指针失败 [ChatMessage]" << endl;
goto outer;
}

cout << " [+] 写入消息数据成功" << endl;
press(VK_RETURN, 20);
cout << " [+] 模拟发送完成" << endl;

if (!messageCavePtr.writeString(converted)) {
cout << " [-] 错误: 写入数据失败 [ChatMessage]" << endl;
goto resume;
}

if (!chatMessagePtr.writeAddress(messageCaveAddr)) {
cout << " [-] 错误: 写入指针失败 [ChatMessage]" << endl;
goto resume;
}

// It may be possible to exceed the chat message length limit? But shouldn't do so, at risk of being banned
if (!chatLengthPtr.writeAddress(messageCaveAddr + length)) {
cout << " [-] 错误: 写入数据失败 [ChatLength]" << endl;
goto resume;
}

cout << " [+] 写入消息数据成功" << endl;
press(VK_RETURN, 20);
cout << " [+] 模拟发送完成" << endl;


resume:
if (!chatMessagePtr.writeAddress(oldAddr)) {
cout << " [-] 错误: 恢复指针失败 [ChatMessage]" << endl;
}
if (!chatLengthPtr.writeAddress(oldAddr)) {
cout << " [-] 错误: 恢复指针失败 [ChatLength]" << endl;
}
}
lastState = state;
}
outer:
lastState = state;
Sleep(200);
}
VirtualFreeEx(hProcess, (LPVOID)messageCaveAddr, 0, MEM_RELEASE);
CloseHandle(hProcess);
cout << endl << " [*] 游戏已退出, Thanks for using!" << endl;
Sleep(3000);
Expand Down
114 changes: 40 additions & 74 deletions BattlefieldChat/Offsets.cpp
Original file line number Diff line number Diff line change
@@ -1,83 +1,49 @@
#include "Offsets.h"
#include "Utils.h"

HANDLE hProcess;
uintptr_t moduleBaseAddr;
uintptr_t messageCaveAddr;

bool isBattlefieldChatOpen() {
uintptr_t ptr = readPointer(hProcess, moduleBaseAddr, 0x39f1e50);
if (ptr == 0) return false;

ptr = readPointer(hProcess, ptr, 0x8);
if (ptr == 0) return false;
ptr = readPointer(hProcess, ptr, 0x28);
if (ptr == 0) return false;
ptr = readPointer(hProcess, ptr, 0x0);
if (ptr == 0) return false;
ptr = readPointer(hProcess, ptr, 0x20);
if (ptr == 0) return false;
ptr = readPointer(hProcess, ptr, 0x18);
if (ptr == 0) return false;
ptr = readPointer(hProcess, ptr, 0x28);
if (ptr == 0) return false;
ptr = readPointer(hProcess, ptr, 0x38);
if (ptr == 0) return false;
ptr = readPointer(hProcess, ptr, 0x40);
if (ptr == 0) return false;
unsigned char value = readByte(hProcess, ptr, 0x30);
return value == 1;
}


bool writeBattlefieldChatLength(int length) {
uintptr_t ptr = readPointer(hProcess, moduleBaseAddr, 0x3A2CA60);
if (ptr == 0) return false;

ptr = readPointer(hProcess, ptr, 0x20);
if (ptr == 0) return false;
ptr = readPointer(hProcess, ptr, 0x38);
if (ptr == 0) return false;
ptr = readPointer(hProcess, ptr, 0x18);
if (ptr == 0) return false;
ptr = readPointer(hProcess, ptr, 0x10);
if (ptr == 0) return false;
ptr = readPointer(hProcess, ptr, 0x30);
if (ptr == 0) return false;
ptr = readPointer(hProcess, ptr, 0x20);
if (ptr == 0) return false;
ptr = readPointer(hProcess, ptr, 0xB8);
if (ptr == 0) return false;
ptr = readPointer(hProcess, ptr, 0x10);
if (ptr == 0) return false;
ptr = readPointer(hProcess, ptr, 0x10);
if (ptr == 0) return false;
return writeLong(hProcess, ptr, 0x188, messageCaveAddr + length);
bool ChatOpenPointer::refreshPointer() {
pointer = baseModuleAddress;
if (!offset(0x39f1e50)) return false;
if (!offset(0x8)) return false;
if (!offset(0x28)) return false;
if (!offset(0x0)) return false;
if (!offset(0x20)) return false;
if (!offset(0x18)) return false;
if (!offset(0x28)) return false;
if (!offset(0x38)) return false;
if (!offset(0x40)) return false;
pointer += 0x30;
return true;
}

bool writeBattlefieldChatPointer() {
uintptr_t ptr = readPointer(hProcess, moduleBaseAddr, 0x3a327e0);
if (ptr == 0) return false;

ptr = readPointer(hProcess, ptr, 0x20);
if (ptr == 0) return false;
ptr = readPointer(hProcess, ptr, 0x18);
if (ptr == 0) return false;
ptr = readPointer(hProcess, ptr, 0x38);
if (ptr == 0) return false;
ptr = readPointer(hProcess, ptr, 0x8);
if (ptr == 0) return false;
ptr = readPointer(hProcess, ptr, 0x68);
if (ptr == 0) return false;
ptr = readPointer(hProcess, ptr, 0xb8);
if (ptr == 0) return false;
ptr = readPointer(hProcess, ptr, 0x10);
if (ptr == 0) return false;
ptr = readPointer(hProcess, ptr, 0x10);
if (ptr == 0) return false;
return writePointer(hProcess, ptr, 0x180, messageCaveAddr);
bool ChatLengthPointer::refreshPointer() {
pointer = baseModuleAddress;
if (!offset(0x3a327e0)) return false;
if (!offset(0x20)) return false;
if (!offset(0x18)) return false;
if (!offset(0x38)) return false;
if (!offset(0x8)) return false;
if (!offset(0x68)) return false;
if (!offset(0xB8)) return false;
if (!offset(0x10)) return false;
if (!offset(0x10)) return false;
pointer += 0x188;
return true;
}

bool writeBattlefieldChatMessage(std::string str) {
return writeString(hProcess, messageCaveAddr, str.c_str(), str.size());
}
bool ChatMessagePointer::refreshPointer() {
pointer = baseModuleAddress;
if (!offset(0x3a327e0)) return false;
if (!offset(0x20)) return false;
if (!offset(0x18)) return false;
if (!offset(0x38)) return false;
if (!offset(0x8)) return false;
if (!offset(0x68)) return false;
if (!offset(0xB8)) return false;
if (!offset(0x10)) return false;
if (!offset(0x10)) return false;
pointer += 0x180;
return true;
}
24 changes: 18 additions & 6 deletions BattlefieldChat/Offsets.h
Original file line number Diff line number Diff line change
@@ -1,12 +1,24 @@
#pragma once
#include <string>
#include <Windows.h>
#include "Pointer.h"

extern HANDLE hProcess;
extern uintptr_t moduleBaseAddr;
extern uintptr_t messageCaveAddr;

bool isBattlefieldChatOpen();
bool writeBattlefieldChatLength(int length);
bool writeBattlefieldChatMessage(std::string str);
bool writeBattlefieldChatPointer();
class ChatOpenPointer : public Pointer {
public:
ChatOpenPointer() : Pointer(hProcess, moduleBaseAddr) {}
bool refreshPointer();
};

class ChatLengthPointer : public Pointer {
public:
ChatLengthPointer() : Pointer(hProcess, moduleBaseAddr) {}
bool refreshPointer();
};

class ChatMessagePointer : public Pointer {
public:
ChatMessagePointer() : Pointer(hProcess, moduleBaseAddr) {}
bool refreshPointer();
};
66 changes: 66 additions & 0 deletions BattlefieldChat/Pointer.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
#include "Pointer.h"

bool Pointer::refreshPointer() {
return false;
}

bool Pointer::readBoolean() {
bool value;
if (ReadProcessMemory(hProcess, (LPCVOID)pointer, &value, sizeof(value), 0))
return value;
return false;
}

uintptr_t Pointer::readAddress() {
uintptr_t value;
if (ReadProcessMemory(hProcess, (LPCVOID)pointer, &value, sizeof(value), 0))
return value;
return 0;
}
bool Pointer::writeAddress(uintptr_t address) {
SIZE_T size = sizeof(address);
DWORD oldprotect;
if (!VirtualProtectEx(hProcess, (LPVOID)pointer, size, PAGE_EXECUTE_READWRITE, &oldprotect))
return false;
if (!WriteProcessMemory(hProcess, (LPVOID)pointer, (LPCVOID)&address, size, nullptr))
return false;
if (!VirtualProtectEx(hProcess, (LPVOID)pointer, size, oldprotect, &oldprotect))
return false;
return true;
}

bool Pointer::writeStringPtr(std::string data) {
uintptr_t address = readAddress();
if (address == 0) throw 1;
SIZE_T size = data.size();
DWORD oldprotect;
if (!VirtualProtectEx(hProcess, (LPVOID)address, size, PAGE_EXECUTE_READWRITE, &oldprotect))
return false;
if (!WriteProcessMemory(hProcess, (LPVOID)address, data.c_str(), size, nullptr))
return false;
if (!VirtualProtectEx(hProcess, (LPVOID)address, size, oldprotect, &oldprotect))
return false;
return true;
}

bool Pointer::writeString(std::string data) {
SIZE_T size = data.size();
DWORD oldprotect;
if (!VirtualProtectEx(hProcess, (LPVOID)pointer, size, PAGE_EXECUTE_READWRITE, &oldprotect))
return false;
if (!WriteProcessMemory(hProcess, (LPVOID)pointer, data.c_str(), size, nullptr))
return false;
if (!VirtualProtectEx(hProcess, (LPVOID)pointer, size, oldprotect, &oldprotect))
return false;
return true;
}

Pointer::Pointer(HANDLE pProcessHandle, uintptr_t pBaseModuleAddress) {
hProcess = pProcessHandle;
baseModuleAddress = pBaseModuleAddress;
}

bool Pointer::offset(uintptr_t offset) {
pointer += offset;
return (pointer = readAddress()) != 0;
}
27 changes: 27 additions & 0 deletions BattlefieldChat/Pointer.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#pragma once
#include <string>
#include <cstdint>
#include <Windows.h>

class Pointer {
public:
uintptr_t pointer = 0;

bool refreshPointer();

bool readBoolean();

uintptr_t readAddress();
bool writeAddress(uintptr_t address);

bool writeStringPtr(std::string data);
bool writeString(std::string data);

Pointer(HANDLE pProcessHandle, uintptr_t pBaseModuleAddress);
protected:
HANDLE hProcess;
uintptr_t baseModuleAddress;

bool offset(uintptr_t offset);
};

0 comments on commit dee9daa

Please sign in to comment.