-
Member
__fastcall with C# using a C++ wrapper?
I've spent the best part of the last week trying to get my head around this part of the implementation and I've hit a point where I'm not quite sure what to do.
Originally read through this: https://drewkestell.us/Article/6/Chapter/7 which I believe is slightly outdated now as I think the signature has changed from (pseudo) __fastcall ((int, int), int) to __fastcall((__fastcall)(int, int), int)). If I try and call the C++ function as is with no changes using the following:
Code:
void __declspec(dllexport) __stdcall EnumerateVisibleObjects(unsigned int callback, int filter, unsigned int ptr)
{
typedef char __fastcall func(unsigned int callback, int64_t filter);
func* function = (func*)ptr;
function(callback, filter);
}
C# caller
Code:
[DllImport("FastCall.dll", EntryPoint = "EnumerateVisibleObjects")]
static extern void EnumerateVisibleObjects(IntPtr callback, long filter, IntPtr ptr);
internal static void EnumerateVisibleObjects(IntPtr callback, long filter) =>
EnumerateVisibleObjects(
callback,
filter,
System.Diagnostics.Process.GetCurrentProcess().MainModule.BaseAddress + 0x12DECA0
);
void Test()
{
var callbackPtr = Marshal.GetFunctionPointerForDelegate(callback);
ThreadSynchronizer.RunOnMainThread(() =>
{
Functions.EnumerateVisibleObjects(callbackPtr, 0);
});
}
static int Callback(IntPtr one, IntPtr two)
{
MessageBox.Show("Got call");
return 1;
}
The app is injected and running within the Wow process.
-
x64 only uses the __fastcall
you should change unsigned int -> unitptr_t
the uint is uint32_t (where ptr on x64 is not)
-
Post Thanks / Like - 1 Thanks
Reghero (1 members gave Thanks to 0xa4fba0 for this useful post)
-
Member
Originally Posted by
0xa4fba0
x64 only uses the __fastcall
you should change unsigned int -> unitptr_t
the uint is uint32_t (where ptr on x64 is not)
Thanks.
I've made that change:
Code:
void __declspec(dllexport) __stdcall EnumerateVisibleObjects(uintptr_t callback, int filter, unsigned int ptr)
{
typedef char __fastcall func(uintptr_t callback, int64_t filter);
func* function = (func*)ptr;
function(callback, filter);
}
C#
Code:
[DllImport("FastCall.dll", EntryPoint = "EnumerateVisibleObjects")]
static extern void EnumerateVisibleObjects(IntPtr callback, long filter, IntPtr ptr);
internal static void EnumerateVisibleObjects(IntPtr callback, long filter) =>
EnumerateVisibleObjects(
callback,
filter,
System.Diagnostics.Process.GetCurrentProcess().MainModule.BaseAddress + 0x12DECA0
);
This still gets me:
crashmem.PNG
-
your crash location looks wrong
System.Diagnostics.Process.GetCurrentProcess().MainModule.BaseAddress <- should be baseaddr of wow.exe
-
Why do you use a C++ stub? It's completely unnecessary.
-
Active Member
Originally Posted by
Jadd
Why do you use a C++ stub? It's completely unnecessary.
As Jadd mentioned you dont need cpp stub.,
Also you were still using unsigned int as a pointer "ptr" in your C code
-
Member
Originally Posted by
Jadd
Why do you use a C++ stub? It's completely unnecessary.
Would you mind expanding? My understanding was that C# had no ability to call unmanaged fastcall direct in process.
Originally Posted by
InnerSilence
As Jadd mentioned you dont need cpp stub.,
Also you were still using unsigned int as a pointer "ptr" in your C code
Thanks, I've changed that but with similar results.
Originally Posted by
0xa4fba0
your crash location looks wrong
System.Diagnostics.Process.GetCurrentProcess().MainModule.BaseAddress <- should be baseaddr of wow.exe
I double checked the base address and it is based on Wowclassic.exe and comparing that to the one that Process.NET gets me, they are both the same.
Last edited by Reghero; 07-11-2021 at 04:16 AM.
-
Active Member
Originally Posted by
Reghero
Would you mind expanding? My understanding was that C# had no ability to call unmanaged fastcall direct in process.
Thanks, I've changed that but with similar results.
I double checked the base address and it is based on Wowclassic.exe and comparing that to the one that Process.NET gets me, they are both the same.
In the 64-bit apps, pinvoke marshaller only supports the x64 ABI which is based on __fastcall anyway. Using Marshal.GetDelegateForFunctionPointer u should be able to create a delegate and call that function.
-
you can check Errors folder for crash stack
wow code addresses are close to 0x00007ffxxxxxxx typically
-
Member
Got it working! Thanks all:
Code:
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
delegate long EnumerateVisibleObjectsCallback(IntPtr a, long b);
static EnumerateVisibleObjectsCallback callback;
private static List<WowObject> ObjectBuffer = new List<WowObject>();
public ObjectsController()
{
callback = Callback;
callbackPtr = Marshal.GetFunctionPointerForDelegate(callback);
}
[Route("enumObjects")]
public IHttpActionResult GetEnumObjects()
{
var pointer = System.Diagnostics.Process.GetCurrentProcess().MainModule.BaseAddress + ENUMERATE_VISIBLE_OBJECTS_FUN_PTR;
EnumerateVisibleObjectsFunc func = (EnumerateVisibleObjectsFunc)Marshal.GetDelegateForFunctionPointer(pointer, typeof(EnumerateVisibleObjectsFunc));
ObjectBuffer.Clear();
var rc = func(this.callbackPtr, 0);
return Json(true);
}
static long Callback(IntPtr ptr, long guid)
{
ObjectBuffer.Add(new WowObject(new ProcessSharp("WowClassic", MemoryType.Local), ptr));
return 1;
}
Has anyone recently injected WPF into WoW? I've stopping trying to get my WPF solution working in process and have instead resorted to using a gRPC service to handle communication between the UI and the bot itself. Would love to know if it's possible to inject in WPF without instantly crashing wow though!