I want to develop a wrapper class that wraps a DLL class that I do not have the source to. Originally, my plan was to just do a bunch of inline assembly to call the real functions.. but I've spent several hours now researching and tinkering how to call member functions by their addresses.
I managed to successfully call the constructor method, and then I moved on to trying to call an operator method (specifically the + operator). This is where things started to go wrong, and I'm unsure if I'm defining/calling the method properly now...
MyStringWrapper.h
#pragma once
#include <string>
class MyStringWrapper
{
public:
static void InitializeAddresses();
static MyStringWrapper* CastFrom(
const uintptr_t address);
MyStringWrapper(
const std::wstring& original);
MyStringWrapper operator+(
const MyStringWrapper& other);
private:
uintptr_t m_string_address;
int m_u1;
int m_u2;
// Still need to figure out how to determine the correct size of a class, but hopefully this is big enough.
char mData[2900];
static struct FunctionDefinitions
{
typedef void(__thiscall* Create_FromArray)(void* pThis, wchar_t const* original);
Create_FromArray CreateFromArray;
// I think my issue is here, should I be returning/providing MyStringWrapper objects or the original MyString objects (that I do not have the source for).
// and... if I should be using MyString objects, how can I do this without the compiler being upset about incomplete types?
// Original symbol "public: class MyString __thiscall MyString::operator+(class MyString const &)"
typedef MyStringWrapper(__thiscall* Combine_MyString)(void* pThis, const MyStringWrapper& other);
Combine_MyString CombineMyString;
} CustomFunctions;
};
MyStringWrapper.cpp
#include "MyStringWrapper.h"
#include "GlobalDLLBases.h"
MyStringWrapper::FunctionDefinitions MyStringWrapper::CustomFunctions;
void MyStringWrapper::InitializeAddresses()
{
CustomFunctions.CreateFromArray = FunctionDefinitions::Create_FromArray((DWORD_PTR)DLLBase + 0x2c40);
CustomFunctions.CombineMyString = FunctionDefinitions::Combine_MyString((DWORD_PTR)DLLBase + 0x3740);
}
MyStringWrapper* MyStringWrapper::CastFrom(
const uintptr_t address)
{
return reinterpret_cast<MyStringWrapper*>(address);
}
MyStringWrapper::MyStringWrapper(
const std::wstring& original) :
m_string_address(0),
m_u1(0),
m_u2(0)
{
CustomFunctions.Create_FromArray(this, original.data());
}
MyStringWrapper MyStringWrapper::operator+(
const MyStringWrapper& other)
{
return CustomFunctions.CombineMyString(this, other);
}
Main.cpp
MyStringWrapper* obj1 = MyStringWrapper::CastFrom(address_to_existing_mystring);
MyStringWrapper* obj2 = MyStringWrapper::CastFrom(address_to_another_existing_mystring);
if(obj1 && obj2)
{
// It crashes calling this, I expected ECX to hold the address of obj1, but the compiler seems to push both obj1 and obj2 addresses on to the stack and moves some other address into ecx.
// It should only be pushing obj2's address, and moving obj1's address into ecx.
MyStringWrapper final_product = *obj1 + *obj2;
}