Problem function calling, with compilation options

hi!

I'm developer of a program designed to provide features for games under GoldSrc (Half-Life #1 based games, like counter-strike 1.6, etc.) and I'm experiencing an issue when I compile a new module.

Question #1:
I'm using MinGW for the Windows binary, CygWin for the Linux one (with Makefile for both).

I have functions like this:
https://github.com/ValveSoftware/halflife/blob/master/dlls/player.cpp#L396

Which can't be called or hooked (I mean, once I call the function using my module or once the hook I've made using a memory patcher include is called, the game crash).
From my tests, it seems the "Vector" (https://github.com/ValveSoftware/halflife/blob/master/dlls/vector.h) class among the format of the function is the problem, especially due to the fact it is passed at a standard (non-pointer) format.
I precise that this problem doesn't happen with functions that pass a such class at a pointer format (like "Vector *vecOrigin" or "Vector &vecOrigin".
I also precise this "bug/crash" only happens using MinGW compiler, this doesn't happen for the Linux binary using CygWin, neither when I use Visual Studio C++ 2010 Express.
You may wondering why I just not use VS2010 to fix? The reason is I'm using Windows XP, and my project requires variadic templates usage which, are not supported by this visual.

And about MinGW, I tried disabled & enabled a lot of options flags in the Makefile, but nothing has changed, and I don't know much about options, and even in C++ where I'm not expert with (that I do is just a hobby).

But I think an appropriate option may fix that problem (something to properly handle classes in the format of a function, once triggered), so, does anyone have an idea about?


Question #2:
The memory patcher include I'm using allows me to make hooks/detours (I mean, catch the function, then I can change the parameters, or block it), but the format of the callback is the standard one.
For example with that function: https://github.com/ValveSoftware/halflife/blob/master/dlls/player.cpp#L396
The hook format is like this:
1
2
3
4
5
6
7
8
9
10
#if defined WIN32
void __fastcall HOOK_CBasePlayer_TraceAttack(void *pTargetClass, int i, entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType) {
#else
void HOOK_CBasePlayer_TraceAttack(void *pTargetClass, entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType) {
#endif
... function call
if(pHookFunction->Disable()) {
reinterpret_cast<void FUNCTION_FORMAT_CLASSES_PART1, entvars_t *, float, Vector, TraceResult *, int)>(pFunctionAddress)(pTargetClass, pevAttacker, lDamage, vecDir, ptr, bitsDamageType);
pHookFunction->Enable();
}


I would like to know if someone know how I could add an additionnal parameter (which will be the pointer of "pHookFunction" matching to some function data) in the hook/detour format? (before "void *pTargetClass).
In order to have a format like:

 
void HOOK_CBasePlayer_TraceAttack(void *pHookFuncAddress, void *pTargetClass, entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType) {


I'm pretty sure it's possible since I've already seen some hooks like this. But I don't know that I have to modify in the code because it's away from my knownledge. Any idea?
This is highly important for me and the goals of my project.

The main/start code that make the hook is like this:
1
2
3
4
5
6
m_vDetour = vDest;
memcpy(m_pOriginalAddress, m_vAddress, sizeof(m_szOriginalAddress));

m_pPatchedAddress[0] = 0xE9;
unsigned int *p = ( unsigned int* )( m_pPatchedAddress + 1 );
*p              = ( unsigned int )vDest - ( unsigned int )m_vAddress - sizeof(m_szOriginalAddress);


Members infos:
m_vDetour & vDest is the callback (HOOK_CBasePlayer_TraceAttack), m_vAddress is the original function (pointer of "CBasePlayer::TraceAttack").
Like:
1
2
3
4
5
6
7
void* m_vAddress; // Function to patch.
void* m_vDetour;  // Hook callback.

unsigned char m_szOriginalAddress[5];
unsigned char m_szPatchedAddress[5];
unsigned char *m_pOriginalAddress;
unsigned char *m_pPatchedAddress;



Question #3:
Due to the fact I'm using Windows XP & Visual C++2010 which has limits, is there a way to add support for variadic template to that software? (by remplacing some internal files or something similar?).


Feel free to ask me more details/content if you feel the need (as the list of options in the Makefile, etc.).

Thanks.
Last edited on
#1: I don't understand what the question is.

#2: You can't add parameters to a hooked function. How would the function know how to use that parameter? If you need to hold data so that other hooks deeper in the stack can use it you should use thread-local storage.

#3: No, variadic templates are implemented in the compiler. Newer versions of MSVC support compiling for XP, but if that's not an option (e.g. due to linking issues) then you just can't use variadic templates, unfortunately.
#1: I'm asking if someone has an idea (and solution) why the function crash when the module is compiled with MinGW, and not with Visual, knowing Visual is different than MinGW using a custom Makefile. So it probably comes from options flags in the Makefile, but I don't know. And as I said, from my tests, it sounds the "Vector" class at standard format is not properly handled/casted after compilation, which causes crash on call/hook.

#2: Are you sure with all the ways?
Look for example at this:
https://github.com/alliedmodders/amxmodx/blob/master/modules/hamsandwich/hook.h#L52
Which creates a "trampoline" (some kind of callback), and the result is this (example with TraceAttack function):
https://github.com/alliedmodders/amxmodx/blob/master/modules/hamsandwich/hook_callbacks.cpp#L763
I'm personnaly using this include for patching: https://pastebin.com/DvYuhBSY
But I've reviewed it and added a few options, functions & fixes, but the global behavior/format remains the same.

The reason I need the "CFunc" pointer (the result of "CreateHook") is in order to retrieve the original address of the function, and also be able to redirect all the functions that share the same format, toward the same callback (like for the trampoline example I gave). However, it will be a pain to add all the functions I've plan to add, one by one...
Because without this feature, how can I know which function/hook is called when I have more than one created for the same callback? huh!
You can see a "GET_ORIG_FUNC" at the top, normally used for that purpose, but it appears on Linux this doesn't return the same pointer as it should, and on Windows I can't compile that, besides I don't know assembler language then I'll prefer to have in the format like I requested (the first parameter is the CFunc pointer, then all the parameters of the function starts from the second parameter of the callback).
Meantime, if in case that I ask (+ one more parameter in the callback) is impossible, and if someone can find another way to get the "CFunc" pointer related to the current hook called, I'll like.

#3: Thanks for the information. I guess we can't "crack" that compiler...
Last edited on
#1: Difficult to say without debugging, sorry.

#2: Oh, I see what you mean now. You have functions void foo(T *); and
 
void bar(T *);
, and you want a single callback for both like
1
2
3
4
void callback(void (*function)(T *), T *param){
    //do something
    function(param);
}
Yes, this is possible, but how to achieve it depends on the facilities your hooking engine provides. You will probably need to generate code at run time.
#1: So, is there a way I can debug my program in order to give more infos to you with this is crashing? (currently, I've just the windows msg "hlds.exe encoutered a problem and has to stop... blablabla).

#2: Yeah, you get it!
I've made a fast example in order to told you again that I want (just to make sure there is no confusion at all).
The hooks in these examples are only with the Linux format, on Windows fastcall convention needs to be used, then a ", int" needs to be added after the "pTargetClass".

The functions used for the example:
https://github.com/ValveSoftware/halflife/blob/master/dlls/player.cpp#L1268
https://github.com/ValveSoftware/halflife/blob/master/dlls/player.cpp#L1360


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
/* METHOD #1 */

void *g_pMemFunc_CBasePlayer_PlayerDeathThink = NULL; // Original address.
CFunc *g_pMemHook_CBasePlayer_PlayerDeathThink = NULL; // Hooked function address.

void *g_pMemFunc_CBasePlayer_StartDeathCam = NULL; // Original address.
CFunc *g_pMemHook_CBasePlayer_StartDeathCam = NULL; // Hooked function address.

void Initialize() {
	g_pMemFunc_CBasePlayer_PlayerDeathThink = g_CMemoryHooker->SearchAddress<void *>("PlayerDeathThink__11CBasePlayer", (void *)MDLL_Spawn, true); // search the function address
	if(g_pMemFunc_CBasePlayer_PlayerDeathThink) { // Function found, make the hook with.
		g_pMemHook_CBasePlayer_PlayerDeathThink = g_CMemoryHooker->CreateHook(g_pMemFunc_CBasePlayer_PlayerDeathThink, (void *)HOOK_CBasePlayer_PlayerDeathThink, true);
	}

	g_pMemFunc_CBasePlayer_StartDeathCam = g_CMemoryHooker->SearchAddress<void *>("StartDeathCam__11CBasePlayer", (void *)MDLL_Spawn, true); // search the function address
	if(g_pMemFunc_CBasePlayer_StartDeathCam) { // Function found, make the hook with.
		g_pMemHook_CBasePlayer_StartDeathCam = g_CMemoryHooker->CreateHook(g_pMemFunc_CBasePlayer_StartDeathCam, (void *)HOOK_CBasePlayer_StartDeathCam, true);
	}
}

void HOOK_CBasePlayer_PlayerDeathThink(void *pTargetClass) {
	// Here is my hook, if I don't do that follows, the function is blocked.

	if(g_pMemHook_CBasePlayer_PlayerDeathThink->Disable()) { // Disable the hook.
		reinterpret_cast<void ( *)(void *)>(g_pMemFunc_CBasePlayer_PlayerDeathThink)(pTargetClass); // Call the original function.
		g_pMemHook_CBasePlayer_PlayerDeathThink->Enable(); // Enable the hook.
	}
}

void HOOK_CBasePlayer_StartDeathCam(void *pTargetClass) {
	// Here is my hook, if I don't do that follows, the function is blocked.

	if(g_pMemHook_CBasePlayer_StartDeathCam->Disable()) { // Disable the hook.
		reinterpret_cast<void ( *)(void *)>(g_pMemFunc_CBasePlayer_StartDeathCam)(pTargetClass); // Call the original function.
		g_pMemHook_CBasePlayer_StartDeathCam->Enable(); // Enable the hook.
	}
}


/* METHOD #2 (what I want to simplify my stuff). */
void Initialize() {
	g_pMemFunc_CBasePlayer_PlayerDeathThink = g_CMemoryHooker->SearchAddress<void *>("PlayerDeathThink__11CBasePlayer", (void *)MDLL_Spawn, true); // search the function address
	if(g_pMemFunc_CBasePlayer_PlayerDeathThink) { // Function found, make the hook with.
		g_pMemHook_CBasePlayer_PlayerDeathThink = g_CMemoryHooker->CreateHook(g_pMemFunc_CBasePlayer_PlayerDeathThink, (void *)HOOK_Void_Target, true);
	}

	g_pMemFunc_CBasePlayer_StartDeathCam = g_CMemoryHooker->SearchAddress<void *>("StartDeathCam__11CBasePlayer", (void *)MDLL_Spawn, true); // search the function address
	if(g_pMemFunc_CBasePlayer_StartDeathCam) { // Function found, make the hook with.
		g_pMemHook_CBasePlayer_StartDeathCam = g_CMemoryHooker->CreateHook(g_pMemFunc_CBasePlayer_StartDeathCam, (void *)HOOK_Void_Target, true);
	}
}

// I don't remember trying this, but this should work for sure (the hooker has only a restriction when the function and the callback are the same).
// Meantime the problems I have specified inside persists.
void HOOK_Void_Target(void *pTargetClass) {
	// Here is my hook, if I don't do that follows, the function is blocked.

	// Same as above here, but since two functions are redirected to the same callback, how do I know which one is called right now?
	// What's why I need a format like below.
	// Or, if not possible, a way to find the current hook called (current CFunc pointer).
	// It's something "GET_ORIG_FUNC" at the top of the hooker file I've posted in pastebin is supposed to do, but I explained why this doesn't work properly.
}

// So that I need is a format like:
void HOOK_Void_Target(CFunc *pMemHook, void *pTargetClass) {
	// So now I can do that (will work properly for any kind of function address, once the format remains the same):

	if(pMemHook->Disable()) { // Disable the hook.
		reinterpret_cast<void ( *)(void *)>(pMemHook->GetOriginal())(pTargetClass); // Call the original function.
		pMemHook->Enable(); // Enable the hook.
	}
}


Well, if this kind of hook would be possible, I'll be very happy! (I could even contribute a bit to the work by doing a donation) But I need this to be implemented in the hooker include I've put to pastebin (as modification), for some reasons.
Last edited on
So, can you confirm me it's possible? And, is there anyone you can do that? As I said, I can make a donation for the work, it's not problem.
Sorry I didn't reply yesterday. I was totally wiped from training and had no energy to look at this.

Contact me via email (see my user profile) and we'll discuss the details.
Topic archived. No new replies allowed.