Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Hooking a function with variadic arguments #246

Open
asaadmohammed74 opened this issue Jun 30, 2018 · 2 comments
Open

Hooking a function with variadic arguments #246

asaadmohammed74 opened this issue Jun 30, 2018 · 2 comments
Labels

Comments

@asaadmohammed74
Copy link

how can i hook _snprintf ? i don't know how to define its delegate since i don't know what is the alternative of c ...

@justinstenning
Copy link
Member

justinstenning commented Jun 30, 2018

Take a look at this delegate implementation (I haven’t tested this myself): https://www.ownedcore.com/forums/world-of-warcraft/world-of-warcraft-bots-programs/wow-memory-editing/301588-how-hooking-functions-wow-variable-arguments-c.html

...it turned out you can't use the __arglist keyword in delegates...
...To my surprise, I discovered that __arglist translates directly into a structure. This structure is a special structure and is called RuntimeArgumentHandle. This structure can not be boxed into an object, which means you won't be able to call the original function if you use a late bound delegate, like WhiteMagic does. Fortunately I wrote my own library that uses generics and it works with that.

RuntimeArgumentHandle was originally thought to be used together with ArgIterator to iterate through arguments. This, however, throws an exception when you do it in WoW (?!? why?). Fortunately RuntimeArgumentHandle contains a single member which is an IntPtr and points to the first argument on the stack. Unfortunately Microsoft made this member internal, so my first thought was to use Reflection. But oops, RuntimeArgumentHandle can not be boxed to an object, so you can't get the value on the instance! I fixed this by simply casting a pointer to it to an IntPtr* and dereferencing that.

IntPtr ptr = *(IntPtr*)&args;

Here is a fictional example that is for a function that accepts a string like formatted like %b%d%f and an arg for each of those three format specifiers (e.g. SomeVariadicFunc("%b%d%f", true, 123, 1.123)).

[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate void SomeVariadicFuncDelegate(string fmt, RuntimeArgumentHandle args);
private static unsafe void SomeVariadicFuncHook(string fmt, RuntimeArgumentHandle args)
{
    // call original
    OriginalSomeVariadicFunc(fmt, args);

    if (fmt == null)
        return;

    IntPtr ptr = *(IntPtr*)&args;
    var vals = new List<object>(fmt.Length / 2);
    for (int i = 1; i < fmt.Length; i += 2)
    {
        switch (fmt[i])
        {
            case 'b':
                vals.Add(Memory.Read<uint>(ptr) != 0);
                ptr += 4;
                break;
            case 'd':
                vals.Add(Memory.Read<int>(ptr));
                ptr += 4;
                break;
            case 'f':
                vals.Add(Memory.Read<double>(ptr));
                ptr += 8;
                break;
            case 'u':
                vals.Add(Memory.Read<uint>(ptr));
                ptr += 4;
                break;
            case 's':
                vals.Add(Memory.Read<string>((uint)ptr, 0));
                ptr += 4;
                break;
        }
    }
}

@zengfr
Copy link

zengfr commented Oct 19, 2020

it is my code but not working
#351

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants