 |
Cheat Engine The Official Site of Cheat Engine
|
View previous topic :: View next topic |
Author |
Message |
syj How do I cheat?
Reputation: 0
Joined: 21 Mar 2019 Posts: 2
|
Posted: Thu Mar 21, 2019 1:35 pm Post subject: Calling the Tutorial's Message Box function. |
|
|
Hello,
I would like to call the Message Box function in Cheat Engine's tutorial through a DLL that I inject. This Message Box shows up whenever you skip a stage of the tutorial or when your health reaches 0.
I am able to call the damage function for Step 2 as follows:
Code: |
void damage() {
using PlayerBase = DWORD_PTR;
static const auto player_base = *(PlayerBase*)0x1002cb9e0;
using DamageFuncPrototype = void(PlayerBase);
static const auto DamageFunc = (DamageFuncPrototype*)0x10002b2b0;
DamageFunc(player_base);
}
|
Calling damage() then decreases the player's health as if they clicked on the "Hit me" button in Step 2.
Looking at how the tutorial calls the Message Box function—which is at 0x1001596d0—I'm guessing the signature of the function is something like:
Code: | void MessageBox(const char* string) |
at least based on observing that the pointer of the string that the Message Box displays is moved into register RCX before the call:
Code: | Tutorial-x86_64.exe+2B305 - mov rcx,[Tutorial-x86_64.exe+19F628] { (1001F8FE8) }
Tutorial-x86_64.exe+2B30C - call Tutorial-x86_64.exe+1596D0
|
When I call the following, however, the tutorial crashes:
Code: | void ce_msg_box() {
using MsgBoxPrototype = void(const char*);
static const auto MsgBoxFunc = (MsgBoxPrototype*)0x1001596d0;
MsgBoxFunc("Test string.");
} |
I am not sure where to go from here, as I have just begun reverse engineering.
|
|
Back to top |
|
 |
Dark Byte Site Admin
Reputation: 470
Joined: 09 May 2003 Posts: 25791 Location: The netherlands
|
Posted: Fri Mar 22, 2019 1:23 am Post subject: |
|
|
Perhaps it needs a pointer to a string instance and not a raw string. strings in fpc start with a byte specifying the length following the string, and no idea how longer strings are handled, perhaps a full blown class object
_________________
Do not ask me about online cheats. I don't know any and wont help finding them.
Like my help? Join me on Patreon so i can keep helping |
|
Back to top |
|
 |
syj How do I cheat?
Reputation: 0
Joined: 21 Mar 2019 Posts: 2
|
Posted: Fri Mar 22, 2019 8:43 am Post subject: |
|
|
I looked at some of the functions that the Message Box calls, and you're right: there's a structure to the string in addition to the raw characters. Although we pass to the Message Box function a pointer to the raw string, other calls within this function will examine the memory 16 bytes before this pointer.
Specifically, as far as I can tell, strings in the tutorial are laid out as:
8 byte header of 1's.
8 byte value containing the string length.
The raw string bytes, aligned to the nearest 8 byte multiple.
8 byte footer with the value 0x10000.
Final code for anyone interested:
Code: | #include <Windows.h>
#include <chrono>
#include <sstream>
#include <thread>
using Address = DWORD_PTR;
class CeString {
private:
Address* buffer;
auto get_size_for_msg(std::size_t msg_len) const {
auto size = msg_len / double(sizeof Address);
size = std::ceil(size);
return std::size_t(size);
}
public:
CeString(const char* message) {
const auto msg_len = std::strlen(message);
const auto size_for_msg = get_size_for_msg(msg_len);
buffer = new Address[3 + size_for_msg];
// Header of 1's.
buffer[0] = ~0;
// Length of string.
buffer[1] = msg_len;
// The actual string placed in memory.
std::memcpy(buffer + 2, message, msg_len);
// The footer. I'm not sure what these bytes do,
// but all strings in the tutorial seem to have this final piece.
buffer[2 + size_for_msg] = 0x10000;
}
~CeString() {
delete[] buffer;
buffer = nullptr;
}
Address get_string_address() const {
return Address(buffer + 2);
}
};
void ce_msg_box(const CeString& s) {
using CeMsgBoxPrototype = void(Address);
static const auto CeMsgBox = (CeMsgBoxPrototype*)0x1001596d0;
CeMsgBox(s.get_string_address());
}
void ce_msg_box(const char* s) {
ce_msg_box(CeString(s));
}
using MessageBuffer = std::ostringstream;
void ce_msg_box(const MessageBuffer& body) {
ce_msg_box(body.str().c_str());
}
void sleep() {
using namespace std::literals::chrono_literals;
std::this_thread::sleep_for(100ms);
}
bool should_display_test_string() {
return GetAsyncKeyState(VK_HOME);
}
void display_test_string() {
CeString s("The quick brown fox jumps over the lazy dog.");
{
// Show the address of the string,
// so we can examine in memory if everything is properly layed out.
MessageBuffer b;
b << std::hex << s.get_string_address();
ce_msg_box(b);
}
ce_msg_box(s);
}
bool should_detach_dll() {
return GetAsyncKeyState(VK_END);
}
HANDLE g_MyThreadHandle = nullptr;
DWORD WINAPI MyThread(_In_ LPVOID lpParameter) {
while (true) {
if (should_display_test_string()) {
display_test_string();
}
if (should_detach_dll()) {
ce_msg_box("detach");
CloseHandle(g_MyThreadHandle);
FreeLibraryAndExitThread(HINSTANCE(lpParameter), 0);
break;
}
sleep();
}
return 0;
}
BOOL WINAPI DllMain(_In_ HINSTANCE hinstDLL, _In_ DWORD fdwReason, _In_ LPVOID lpvReserved) {
if (fdwReason == DLL_PROCESS_ATTACH) {
DisableThreadLibraryCalls(hinstDLL);
g_MyThreadHandle = CreateThread(nullptr, 0, MyThread, hinstDLL, 0, nullptr);
}
return TRUE;
} |
Description: |
|
Filesize: |
62.29 KB |
Viewed: |
1843 Time(s) |

|
Description: |
|
Filesize: |
17 KB |
Viewed: |
1843 Time(s) |

|
|
|
Back to top |
|
 |
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum You cannot attach files in this forum You can download files in this forum
|
|