1

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;
}
Rick
  • 421
  • 3
  • 15
  • tried a decompiler? https://stackoverflow.com/questions/205059/is-there-a-c-decompiler – Marc Stroebel Jan 10 '23 at 13:56
  • @MarcStroebel yes I've been using x64dbg and Ghidra, but I'm not understanding why visual studio is passing the 2 objects into the stack and putting a seemingly random address into ecx when calling the + operator... – Rick Jan 10 '23 at 20:35

0 Answers0