This method of registering a lua callback has been covered on a few occasions and although I've spent the last few days (more like months on and off) searching for the solution to this bug, it continues to painfully allude me. The function appears to register but when I call it using something like
Code:
FrameScript_Execute("FooInput("CastSpellByName(\"Shadow Bolt\"));
My toon casts the spell (verified by dead mob on relog) but the application crashes with reference to "FooInput" as the addon in the crash log. I'm guessing I'm doing something retarded but I can't seem to see what it is.
How it's done:
Basically I'm trying to write a jmp operand E9 MY AD DR ES somewhere in the .text section of the executable which jumps to the delegate of my callback function. The memory address I choose for the patch is definately within the bounds of the .text segment of the executable's memory. My method of finding these 5 bytes of 0x0 is via a sort of randomized sigscan (Not starting the scan from 0x1000 either because I feel that it's safer further from that boundary with limited randomization). I've also used many hardcoded offsets but the same crash occurs.
Here's some of the code:
Credit goes to Apoc for his .NET implementation and everyone else that contributed
to understanding this portion of Wow's internals.
Code:
public class LuaManager
{
private static FScriptExecuteDelegate _execute;
private static FScriptGetTopDelegate _getTop;
private static FScriptRegisterDelegate _register;
private static CallbackDelegate _callback;
private static FScriptToLStringDelegate _toLString;
/// <summary>
/// Initializes a new instance of the <see cref="LuaManager"/> class.
/// </summary>
public LuaManager()
{
_luaValues = new List<string>();
// Function Pointer Initialization Stuff.
_execute = Memory.RegisterDelegate<FScriptExecuteDelegate>
(Memory.Patterns["FrameScript_Execute"]);
_getTop = Memory.RegisterDelegate<FScriptGetTopDelegate>
(Memory.Patterns["FrameScript_GetTop"]);
_register = Memory.RegisterDelegate<FScriptRegisterDelegate>
(Memory.Patterns["FrameScript_RegisterFunction"]);
_toLString = Memory.RegisterDelegate<FScriptToLStringDelegate>
(Memory.Patterns["FrameScript_ToLString"]);
// This is required to get a pointer to the
// callback (used in _register)
_callback = CallbackHandler;
RegisterCallback();
}
private List<string> _luaValues;
/// <summary>
/// Injects a string of lua into the games framescript engine
/// </summary>
/// <param name="strCommand">The lua command.</param>
public void DoString(string strCommand)
{
_execute(strCommand, "IPittyTheFoo.lua", 0);
}
/// <summary>
/// Registers a lua function called "FooInput"
/// </summary>
public void RegisterCallback()
{
// This installs a patch (a jump) to my CallbackHandler
// in the .text section of the client.
IntPtr patchAddress = Memory.Patterns["FrameScript_PatchAddress"];
IntPtr callbackAddress = Marshal.GetFunctionPointerForDelegate(_callback);
FooModule.Logs["Debug"].AddMessage(string.Format("Patch address : {0}", patchAddress));
FooModule.Logs["Debug"].AddMessage(string.Format("Callback address: {0}", callbackAddress));
List<byte> bytes = new List<byte>();
// Generating the Byte array...
bytes.Add(0xE9); // jmp statement
byte[] temp = BitConverter.GetBytes((uint) callbackAddress);
// Adding the address bytes in reverse order
for (int i = temp.Length - 1; i >= 0; i--)
{
bytes.Add(temp[i]);
}
Memory.PatchManager.CreateAndApply(patchAddress, bytes.ToArray(), "RegisterFunction");
_register("FooInput", patchAddress);
}
private int CallbackHandler(IntPtr pLuaState)
{
FooModule.Logs["Debug"].AddMessage("Lua callback called");
_luaValues.Clear();
int num = _getTop(pLuaState);
for (int i = 0; i < num; i++)
{
string tmp = ToLString(pLuaState, i);
_luaValues.Add(tmp);
}
return 0;
}
private string ToLString(IntPtr pLuaState, int index)
{
return _toLString(pLuaState, index + 1, 0);
}
/// <summary>
/// Executes a string of lua and returns the
/// values of the function as a string array.
/// </summary>
/// <param name="lua">The lua string.</param>
/// <returns></returns>
public string[] GetReturnVal(string lua)
{
DoString(String.Format("MaiaInput({0})", lua));
return _luaValues.ToArray();
}
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate int FScriptExecuteDelegate(string lua, string fileName, uint pState);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate uint FScriptRegisterDelegate(string szName, IntPtr pFunc);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate string FScriptToLStringDelegate(IntPtr pLuaState, int idx, int length);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate int CallbackDelegate(IntPtr pLuaState);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate int FScriptGetTopDelegate(IntPtr pLuaState);
Well.. that's it, I'm not sure if it's something totally retarded that I'm missing and I'd sure appreciate a fresh set of eyes if you can spot anything that might yield a clue pertaining to the cause.
Also, just for the sake of documenting something so that this thread might be useful for something I think the pointer check looks like this...
Code:
unsigned int FrameScript__InvalidPtrCheck(unsigned int * myFunctionPointer)
{
int * lowBoundary;
int * highBoundary;
lowBoundary = (int*)(D872E8);
highBoundary = (int*)(D872EC);
if ( !lowBoundary || !highBoundary )
{
sub_7D6300(); // Press CTRL + R and try again
lowBoundary = (int*)(D872E8);
highBoundary = (int*)(D872EC);
}
if ( myFunctionPointer < lowBoundary || myFunctionPointer >= highBoundary )
{
throw("Invalid function pointer... rawr!");
}
return lowBoundary;
}
Everytime I try to chart the XREFS to this function my IDA crashes, I'm assuming that It gets called somewhere in the Execute chain because I can't seem to find it referenced in FrameScript::RegisterFunction.
I'm also assuming that these two (D872E8) and (D872EC) hold pointers to the start and end of the .text segment but I'm not 100% sure.
Any help of advice would be highly appreciated.
Related Threads :
Highly relevant
http://www.mmowned.com/forums/world-...ml#post1567311
http://www.mmowned.com/forums/world-...callbacks.html
http://www.mmowned.com/forums/world-...ml#post1436155
http://www.mmowned.com/forums/world-...ml#post1707663
Moderately relevant
http://www.mmowned.com/forums/world-...ml#post1879902
Not so relevant really
http://www.mmowned.com/forums/world-...-commands.html
http://www.mmowned.com/forums/world-...functions.html