I'm attaching my working code.
My implementation is slightly different than what was originally specified.
My 'Hook' class is called HookManager and its default constructor requires an instance of BlackMagic.
The HookApplication and DisposeOfHook methods are private and used only within the InjectAndExecute method.
HookManager Code:
Code:
public struct Direct3D
{
public static uint Direct3D9__Device = 0x98BCDC;
public static uint Direct3D9__Device__OffsetA = 0x27C4;
public static uint Direct3D9__Device__OffsetB = 0xA8;
}
public class HookManager
{
private BlackMagic process;
private bool mainThreadHooked;
private bool ExecutingCode;
private uint codeCave;
private uint injectionAddress;
private uint returnAddress;
public HookManager(BlackMagic process)
{
this.process = process;
this.mainThreadHooked = false;
this.ExecutingCode = false;
this.codeCave = 0;
this.injectionAddress = 0;
this.returnAddress = 0;
}
private void HookApplication()
{
if (!process.IsProcessOpen)
throw new Exception("Process is not open");
uint baseAddress = (uint)process.MainModule.BaseAddress;
uint pDevice = process.ReadUInt(baseAddress + Direct3D.Direct3D9__Device);
uint pEnd = process.ReadUInt(pDevice + Direct3D.Direct3D9__Device__OffsetA);
uint pScene = process.ReadUInt(pEnd);
uint pEndScene = process.ReadUInt(pScene + Direct3D.Direct3D9__Device__OffsetB);
if (process.ReadUInt(pEndScene) == 0xE9 && (codeCave == 0 || injectionAddress == 0))
{
DisposeOfHook();
}
if (process.ReadUInt(pEndScene) != 0xE9)
{
try
{
mainThreadHooked = false;
codeCave = process.AllocateMemory(2048);
injectionAddress = process.AllocateMemory(0x4);
process.WriteInt(injectionAddress, 0);
returnAddress = process.AllocateMemory(0x4);
process.WriteInt(returnAddress, 0);
process.Asm.Clear();
process.Asm.AddLine("mov edi, edi");
process.Asm.AddLine("push ebp");
process.Asm.AddLine("mov ebp, esp");
process.Asm.AddLine("pushfd");
process.Asm.AddLine("pushad");
//Test for waiting code?
process.Asm.AddLine("mov eax, [" + injectionAddress + "]");
process.Asm.AddLine("test eax, ebx");
process.Asm.AddLine("je @out");
//Execute waiting code
process.Asm.AddLine("mov eax, [" + injectionAddress + "]");
process.Asm.AddLine("call eax");
//Copy pointer to return value
process.Asm.AddLine("mov [" + returnAddress + "], eax");
process.Asm.AddLine("mov edx, " + injectionAddress);
process.Asm.AddLine("mov ecx, 0");
process.Asm.AddLine("mov [edx], ecx");
//Close Function
process.Asm.AddLine("@out:");
//Inject Code
uint sizeAsm = (uint)(process.Asm.Assemble().Length);
process.Asm.Inject(codeCave);
int sizeJumpBack = 5;
// create jump back stub
process.Asm.Clear();
process.Asm.AddLine("jmp " + (pEndScene + sizeJumpBack));
process.Asm.Inject(codeCave + sizeAsm);// + (uint)sizeJumpBack);
// create hook jump
process.Asm.Clear(); // $jmpto
process.Asm.AddLine("jmp " + (codeCave));
process.Asm.Inject(pEndScene);
}
catch
{
mainThreadHooked = false; return;
}
mainThreadHooked = true;
}
}
private void DisposeOfHook()
{
if (!process.IsProcessOpen)
throw new Exception("Process is not open");
uint baseAddress = (uint)process.MainModule.BaseAddress;
uint pDevice = process.ReadUInt(baseAddress + Direct3D.Direct3D9__Device);
uint pEnd = process.ReadUInt(pDevice + Direct3D.Direct3D9__Device__OffsetA);
uint pScene = process.ReadUInt(pEnd);
uint pEndScene = process.ReadUInt(pScene + Direct3D.Direct3D9__Device__OffsetB);
try
{
if (process.ReadByte(pEndScene) == 0xE9) // check if wow is already hooked and dispose Hook
{
// Restore origine endscene:
process.Asm.Clear();
process.Asm.AddLine("mov edi, edi");
process.Asm.AddLine("push ebp");
process.Asm.AddLine("mov ebp, esp");
process.Asm.Inject(pEndScene);
}
// free memory:
process.FreeMemory(codeCave);
process.FreeMemory(injectionAddress);
process.FreeMemory(returnAddress);
}
catch
{
}
}
public byte[] InjectAndExecute(string[] asm)
{
while (ExecutingCode)
{
System.Threading.Thread.Sleep(5);
}
ExecutingCode = true;
HookApplication();
byte[] tempsByte = new byte[0];
// reset return value pointer
process.WriteInt(returnAddress, 0);
if (process.IsProcessOpen && mainThreadHooked)
{
// Write the asm stuff
process.Asm.Clear();
foreach (string tempLineAsm in asm)
{
process.Asm.AddLine(tempLineAsm);
}
// Allocation Memory
int codeSize = process.Asm.Assemble().Length;
uint injectionAsm_Codecave = process.AllocateMemory(codeSize);
try
{
// Inject
process.Asm.Inject(injectionAsm_Codecave);
process.WriteInt(injectionAddress, (int)injectionAsm_Codecave);
// Wait to launch code
while (process.ReadInt(injectionAddress) > 0)
{
System.Threading.Thread.Sleep(5);
}
byte Buf = new Byte();
List<byte> retnByte = new List<byte>();
uint dwAddress = process.ReadUInt(returnAddress);
Buf = process.ReadByte(dwAddress);
while (Buf != 0)
{
retnByte.Add(Buf);
dwAddress = dwAddress + 1;
Buf = process.ReadByte(dwAddress);
}
tempsByte = retnByte.ToArray();
}
catch { }
// Free memory allocated
process.FreeMemory(injectionAsm_Codecave);
}
DisposeOfHook();
ExecutingCode = false;
return tempsByte;
}
}
I also have a function manager class.
The default constructor takes an instance of BlackMagic as a parameter and creates an instance of HookManager.
FunctionManager Code:
Code:
public class FunctionManager
{
private BlackMagic process;
private HookManager aHook;
public FunctionManager(BlackMagic process)
{
this.process = process;
this.aHook = new HookManager(process);
}
public void LuaDoString(string command)
{
int nSize = command.Length + 0x100;
uint codeCave = process.AllocateMemory(nSize);
uint moduleBase = (uint)process.MainModule.BaseAddress;
process.WriteASCIIString(codeCave, command);
process.Asm.Clear();
String[] asm = new String[]
{
"mov eax, " + codeCave,
"push 0",
"push eax",
"push eax",
"mov eax, " + (moduleBase + FrameScript__Execute),
"call eax",
"add esp, 0xC",
"retn",
};
aHook.InjectAndExecute(asm);
process.FreeMemory(codeCave);
}
}
Crappy Example Usage:
Code:
static void Main(string[] args)
{
BlackMagic application;
FunctionManager functionManager;
Process[] processes = Process.GetProcessesByName("Wow");
application = new BlackMagic(processes[0].id);
functionManager = new FunctionManager(application);
functionManager.LuaDoString("print(\"Hello World\");");
functionManager.LuaDoString("DoEmote(\"dance\");");
}