I am writing a dynamic link library to be injected into a singleplayer game on Windows and serve as a "cinematic tool" (overwriting camera transforms, timescale, etc.):
Let's say that the base address for the game executable in the virtual memory space is 0x140000000 and there's an instruction at foo.exe+0x10D64B81 that I want to overwrite. The instruction is mulss xmm1,[rdi+0000027C] (F3 0F 59 8F 7C 02 00 00, 8 bytes), the modified code to be written starting at that address/offset is xorps xmm1,xmm1 / nop / nop / nop / nop / nop (0F 57 C9 90 90 90 90 90, 8 bytes).
I have the following implementation (simplified for demonstration purposes):
#include <Windows.h>
using byte = unsigned char;
class FunctionMod
{
public:
FunctionMod(void* baseAddress, size_t offset, const byte* code, size_t length)
: m_BaseAddress(baseAddress), m_Offset(offset), m_ModifiedCode(), m_Length(length)
{
m_ModifiedCode = new byte[m_Length];
std::copy(code, &code[m_Length], m_ModifiedCode);
}
~FunctionMod() noexcept
{
delete[] m_ModifiedCode;
}
void overwrite() const
{
for (size_t i = 0; i < m_Length; i++)
*((byte*)m_BaseAddress + m_Offset + i) = m_ModifiedCode[i];
}
private:
void* m_BaseAddress;
size_t m_Offset;
size_t m_Length;
byte* m_ModifiedCode;
};
...
DWORD64 functionOffset = 0x10D64B81;
byte functionCode[8] = { 0x0F, 0x57, 0xC9, 0x90, 0x90, 0x90, 0x90, 0x90 };
FunctionMod guiMod(
(void*)GetModuleHandle(NULL),
functionOffset,
functionCode,
sizeof(functionCode)
);
guiMod.overwrite();
This works perfectly fine with other offsets and instructions, but for some reason, this particular example consistently writes 0F **A2** C9 90 ... to the respective memory location, instead of 0F **57** C9 90 ..., translating to cpuid \ leave \ nop ... and thus crashing the process.
I'm losing my mind trying to figure out what I'm doing wrong. There doesn't seem to be a point where 0x57 could somehow become 0xA2. I have verified that the memory is copied correctly in the class constructor, printing out the bytes to a console instead of writing them to the actual memory also gives the expected result, the pointer arithmetic checks out as well. The only time the 0xA2 is written is when I dereference the pointer and write to the actual memory.
Anyone, please, any ideas?
EDIT: Overwriting the memory from a different process running as administrator with WriteProcessMemory works properly, but I "need" (it would be much less work) to do this from the dll.