Renegade Public Forums
C&C: Renegade --> Dying since 2003™, resurrected in 2024!
Home » Renegade Discussions » Mod Forum » Function Hooking
Function Hooking [message #490115] Wed, 24 December 2014 13:26 Go to next message
Neijwiert is currently offline  Neijwiert
Messages: 124
Registered: October 2009
Karma: 0
Recruit
I've been trying and trying but I just cannot figure it out. I even asked it on StackOverflow but they aren't helping much either.

What I'm trying to achieve is: Call a custom (hook) function and then calling the original function (a trampoline effect, whilst keeping the stack intacked between the functions).

I did somehow achieve this when I hooked into the Commands->Find_Object function, I intercepted all calls to it and it worked fine. So I was all happy and satisfied how that worked out and I tried to put everything in a nice class. When I did that it just stoped working. So I was like, well yeah that sometimes happens you mess up some simple thing whilst copying it over. So I moved everything back to the old (messy) code and to my surprise that stoped working aswell...

My new code is actually pretty much a complete mirror and I doubt that the copy pasting went wrong so I'm just gonna put that version here in the hopes somebody of the renegade community can help me to find the problem.

I have the following header file:
Toggle Spoiler


Which has the following source file:
Toggle Spoiler


In my plugin source file I have these calls to the DetourClass:
Toggle Spoiler


Where TimeMachine is my plugin class (So the constructor gets called when SSGM loads the library). I have checked if the memory is actually changed after my function calls and it is indeed changed to the correct variables. But as soon as I call Foo() it just executes it as if nothing changed. The reason that I have it in OnLoadLevel is becouse in one of my earlier tests it started working when I moved it to OnLoadLevel (so outside the constructor). The reason why I'm not trying to hook Find_Object right now is becouse when internal engine calls go to Find_Object when the game starts it crashes the fds instantly (The hooking in the constructor goes without any problems).

If somebody comes up with a solution or pushes me in the right direction that would be greatly apreciated!
Re: Function Hooking [message #490117 is a reply to message #490115] Wed, 24 December 2014 14:42 Go to previous messageGo to next message
jonwil is currently offline  jonwil
Messages: 3557
Registered: February 2003
Karma: 0
General (3 Stars)

If you want to hook Commands->Find_Object, just read the address out of that variable (the "original" Find_Object) then replace it with the address of your new function.
Your new funxtion would then call the stock function through the pointer you saved ealier.
p


Jonathan Wilson aka Jonwil
Creator and Lead Coder of the Custom scripts.dll
Renegade Engine Guru
Creator and Lead Coder of TT.DLL
Official member of Tiberian Technologies
Re: Function Hooking [message #490118 is a reply to message #490117] Wed, 24 December 2014 17:41 Go to previous messageGo to next message
Neijwiert is currently offline  Neijwiert
Messages: 124
Registered: October 2009
Karma: 0
Recruit
jonwil wrote on Wed, 24 December 2014 14:42

If you want to hook Commands->Find_Object, just read the address out of that variable (the "original" Find_Object) then replace it with the address of your new function.
Your new funxtion would then call the stock function through the pointer you saved ealier.
p


That would result in an infinite loop? For example:

typedef GameObject *(** FindObjectPointer)(int);
FindObjectPointer OriginalFindObject;
GameObject *Find_Object_Test(int obj_id)
{
	Console_Output("Finding object with id: %d\n", obj_id);

	return (* OriginalFindObject)(obj_id);
}

TimeMachine::TimeMachine()
{
	OriginalFindObject = &Commands->Find_Object;
	*&Commands->Find_Object = &Find_Object_Test;
}


The OriginalFindObject would point right back to the hooked one. Im trying to catch all calls to the original method and then do some stuff. I'm just using Find_Object as an example, the actual command I'm going to target is Start_Timer.

When I compile and run this I get an infinite loop.

NOTE: I'm also trying to catch calls to the method outside of my DLL. So there's no other way than memory hooking it with a jump? Or am I just thinking to difficult right now?

Re: Function Hooking [message #490121 is a reply to message #490115] Wed, 24 December 2014 18:29 Go to previous messageGo to next message
jonwil is currently offline  jonwil
Messages: 3557
Registered: February 2003
Karma: 0
General (3 Stars)

do this:
OriginalFindObject = Commandsf>Find_Object;
Commands->Find_Object = Find_Object_Test;

then later do
eturn OriginalFindObject(bj_id);


Jonathan Wilson aka Jonwil
Creator and Lead Coder of the Custom scripts.dll
Renegade Engine Guru
Creator and Lead Coder of TT.DLL
Official member of Tiberian Technologies
Re: Function Hooking [message #490125 is a reply to message #490115] Thu, 25 December 2014 05:37 Go to previous messageGo to next message
Neijwiert is currently offline  Neijwiert
Messages: 124
Registered: October 2009
Karma: 0
Recruit
I must be completly retarded...
Talking about taking the hard route...
Well thanks, it works. But I'm still kind of curious as to why my first approach doesn't work. It isn't even affecting the execution of the original function, yet I'm overwriting memory.
Re: Function Hooking [message #490170 is a reply to message #490115] Sun, 28 December 2014 07:05 Go to previous messageGo to next message
iRANian is currently offline  iRANian
Messages: 4308
Registered: April 2011
Karma: 0
General (4 Stars)
What you can also do is place a JMP at the very start of the original function to your own hook. Then when you want to call the original function you re-create the first 5 bytes you overwrote in assembly then just jmp 5 bytes into the original function.


function:
push ebp ; byte 1
push edi ; byte 2
push esi ; byte 3
push ebx ; byte 4
push ecx ; byte 5
push edx ; byte 6

Then after jumping hooking:

function:
jmp <hookfunc> ; byte 1-5
push edx ; byte 6

void HookFunc()
{
blabla
}

void _declspec(naked)Call original func()
{
_asm
{
push ebp ; byte 1
push edi ; byte 2
push esi ; byte 3
push ebx ; byte 4
push ecx ; byte 5
jmp to byte 6; where 'push edx' is located
}
}


Long time and well respected Renegade community member, programmer, modder and tester.

Scripts 4.0 private beta tester since May 2011.

My Renegade server plugins releases
Re: Function Hooking [message #490171 is a reply to message #490170] Sun, 28 December 2014 10:58 Go to previous messageGo to next message
Neijwiert is currently offline  Neijwiert
Messages: 124
Registered: October 2009
Karma: 0
Recruit
iRANian wrote on Sun, 28 December 2014 07:05

What you can also do is place a JMP at the very start of the original function to your own hook. Then when you want to call the original function you re-create the first 5 bytes you overwrote in assembly then just jmp 5 bytes into the original function.


function:
push ebp ; byte 1
push edi ; byte 2
push esi ; byte 3
push ebx ; byte 4
push ecx ; byte 5
push edx ; byte 6

Then after jumping hooking:

function:
jmp <hookfunc> ; byte 1-5
push edx ; byte 6

void HookFunc()
{
blabla
}

void _declspec(naked)Call original func()
{
_asm
{
push ebp ; byte 1
push edi ; byte 2
push esi ; byte 3
push ebx ; byte 4
push ecx ; byte 5
jmp to byte 6; where 'push edx' is located
}
}



That was exactly what I was trying to achieve in my first attempt. Yet it somehow didn't jump to the new function, If you toggle the spoilers in the first post you can see how I tried it.
Re: Function Hooking [message #490187 is a reply to message #490115] Tue, 30 December 2014 16:39 Go to previous messageGo to next message
iRANian is currently offline  iRANian
Messages: 4308
Registered: April 2011
Karma: 0
General (4 Stars)
Yeah I saw that, but you're doing some complicated memory copying code.

Long time and well respected Renegade community member, programmer, modder and tester.

Scripts 4.0 private beta tester since May 2011.

My Renegade server plugins releases
Re: Function Hooking [message #490190 is a reply to message #490187] Tue, 30 December 2014 18:35 Go to previous messageGo to next message
Neijwiert is currently offline  Neijwiert
Messages: 124
Registered: October 2009
Karma: 0
Recruit
iRANian wrote on Tue, 30 December 2014 16:39

Yeah I saw that, but you're doing some complicated memory copying code.


How else can you execute the first 5 bytes then again if you don't store that anywhere?
Re: Function Hooking [message #490302 is a reply to message #490115] Sun, 11 January 2015 08:18 Go to previous message
iRANian is currently offline  iRANian
Messages: 4308
Registered: April 2011
Karma: 0
General (4 Stars)
By using a nakedspec function with asm

void _declspec(naked) blabla()
{
_asm
{
// epilogue (first 5 bytes or so)
push esp
push ebp
push edx
push ebx
push ecx

jmp FunctionAddress+5 //or just the direct adress
}
}


Long time and well respected Renegade community member, programmer, modder and tester.

Scripts 4.0 private beta tester since May 2011.

My Renegade server plugins releases
Previous Topic: Human Animations System
Next Topic: C&C_Walls_Flying
Goto Forum:
  


Current Time: Sat Nov 30 22:24:36 MST 2024

Total time taken to generate the page: 0.00749 seconds