Raised This Month: $51 Target: $400
 12% 

New Virtual function table hook - worlds better, linux compa


Post New Thread Closed Thread   
 
Thread Tools Display Modes
Author Message
vancelorgin
Senior Member
Join Date: Dec 2004
Location: san frandisco
Old 01-18-2005 , 19:20   New Virtual function table hook - worlds better, linux compa
#1

Well this one's alot better. Again, it lets you hook virtual funcs on any class, but this time it's alot easier to work with, can do more, is faster, smaller, and should make the same code work on windows and linux with no hassle to the coder. Not a bad update. I horribly overengineered the first one. My bad - I blame the drugs. The goods are in the attachment, but here's a HL2 sample:

Code:
//declare the original func and the gate if in windows. syntax is:
//DEFVFUNC_
//        <name of the var you want to hold the original func>,
//        <return type>,
//        <args INCLUDING a pointer to the type of class it is in the beginning>
DEFVFUNC_(engine_CreateEdict, edict_t*, (IVEngineServer* pEngine, int iForceEdictIndex));

//just define the func you want to be called instead of the original
//making sure to include VFUNC between the return type and name
edict_t* VFUNC mycreateedict(IVEngineServer* pEngine, int iForceEdictIndex){
	LOG("Created edict: [%x] [%d]", pEngine, iForceEdictIndex);

	return engine_CreateEdict(pEngine, iForceEdictIndex);
}

your fkn load func {
//actually hooks the func. syntax is
//HOOKVFUNC
//        <a valid pointer to a class with that func in it>,
//        <the index of it in the vtable (weve been over this)>,
//        <name of original func var>,
//        <name of your hook func>
	HOOKVFUNC(engine, 21, engine_CreateEdict, mycreateedict);
}
Not too shabby eh?

This *should* work on linux - I went according to XAD's findings. I haven't even compiled it under linux though, but it's childishly simple to get working. When you do, please post so I can update the header
Attached Files
File Type: h vfnhook.h (3.9 KB, 607 views)
__________________
Avoid like the plague.
vancelorgin is offline
BAILOPAN
Join Date: Jan 2004
Old 01-18-2005 , 19:27  
#2

Nice again, lance! Great
__________________
egg
BAILOPAN is offline
Roger Devil
Senior Member
Join Date: Dec 2004
Location: Germany
Old 03-14-2005 , 09:48  
#3

Hi Vance,
thanks, but i have 2 Questions :
1. How to unhook a function
2. Does not work under linux --> Segmentation fault.

Do you have a new version ???
Roger Devil is offline
Send a message via ICQ to Roger Devil
vancelorgin
Senior Member
Join Date: Dec 2004
Location: san frandisco
Old 03-14-2005 , 21:49  
#4

updated with unhook, and you gotta deprotect the table in linux - just look at xads

oh, and in this ver theres HDEFVFUNC and DEFVFUNC

put HDEFVFUNC in a header to allow other files to use it, and DEFVFUNC in the source file - or just DEFVFUNC_ if you don't need it to be exported
__________________
Avoid like the plague.
vancelorgin is offline
XAD
Senior Member
Join Date: Mar 2004
Location: Sweden
Old 03-15-2005 , 02:26  
#5

Quote:
Originally Posted by vancelorgin
updated with unhook, and you gotta deprotect the table in linux - just look at xads
Vance, don't tell people to unhook, PLEASE... if more than one plugin is using hooks this will cause havoc as you don't know who's hook you have hooked...

It should be a rule that a plugin using hooks MUST NOT be unloaded...

/X
XAD is offline
Roger Devil
Senior Member
Join Date: Dec 2004
Location: Germany
Old 03-15-2005 , 08:32  
#6

Thanks vancelorgin, works great under Windows.
I have done a protection under linux by using :
Quote:
#include <sys/mman.h>
inline bool DeProtect(void* pMemory, unsigned int uiLen, bool bLock = false)
{
return (mprotect(pMemory, uiLen, ((bLock) ? PROT_READ | PROT_EXEC : PROT_READ | PROT_WRITE | PROT_EXEC)) ? true : false);
}
#define VFUNC

#define DEFVFUNC( funcname , returntype , proto ) \
funcname##Func funcname = NULL;

#define HOOKVFUNC( classptr , index , funcname , newfunc ) \
DeProtect((void*)VTBL( classptr ), ( index * sizeof(void*)) + 4 ); \
funcname = ( funcname##Func )VFN( classptr , index ); \
*(ADDRTYPE*)PVFN( classptr , index ) = newfunc ;\
DeProtect((void*)VTBL( classptr ), ( index * sizeof(void*)) + 4, true ); \
During the hook i got a segmentation-fault, dont know why ???
Is the calling-convention different under Linux??
Im no Linux-Expert, so some folks from the Linux-Front can help me out

P.S.
By the way XAD, I know the problem of unhooking functions. I dont use this in a server-plugin.
Roger Devil is offline
Send a message via ICQ to Roger Devil
vancelorgin
Senior Member
Join Date: Dec 2004
Location: san frandisco
Old 03-16-2005 , 22:08  
#7

Quote:
Originally Posted by XAD
Quote:
Originally Posted by vancelorgin
updated with unhook, and you gotta deprotect the table in linux - just look at xads
Vance, don't tell people to unhook, PLEASE... if more than one plugin is using hooks this will cause havoc as you don't know who's hook you have hooked...

It should be a rule that a plugin using hooks MUST NOT be unloaded...

/X
It can be done right - yeah, usually it's not, but in certain applications it's fine. For example, in a test plugin, on the fly unhooking is the easiest and best way to do things :/
__________________
Avoid like the plague.
vancelorgin is offline
theqizmo
Member
Join Date: Oct 2004
Old 03-23-2005 , 13:04  
#8

I used to get seg faults regularly, however, I found out that it was an issue with the size with which mprotect unwrite/rewrite pages, thus, I went back and deprotected a _ton_ of stuff.

I use this for HOOKVFUNC:

Code:
#define HOOKVFUNC( classptr , index , funcname , newfunc ) \
	LOG("[" #classptr ": %d] RW: %s", index , (PROTECT( classptr , index ,  true)) ? "pass" : "fail"); \
	funcname = ( funcname##Func )VFN( classptr , index ); \
	*(DWORD*)PVFN( classptr , index ) = newfunc; \
	LOG("[" #classptr ": %d] RO: %s", index , (PROTECT( classptr , index ,  true)) ? "pass" : "fail"); \
	LOG( #funcname " = 0x%X " #newfunc " = 0x%X" , funcname , newfunc );
where PROTECT is:

Code:
#define PROTECT( ptr, index, val ) DeProtect( ( void* ) ptr , 2048 , val )
and DeProtect is:

Code:
#define PAGE_EXECUTE_READ	PROT_EXEC | PROT_READ
#define PAGE_EXECUTE_READWRITE 	PROT_EXEC | PROT_READ | PROT_WRITE

bool DeProtect(void *pMemory, unsigned int uiLen, bool bWrite)
{
	char *p; 
	p = (char*)((int)(*(void**)pMemory) & ~(PAGESIZE-1));
	
	return (!mprotect(p, (int)(*(char**)pMemory - p) + uiLen, (bWrite) ? PAGE_EXECUTE_READWRITE : PAGE_EXECUTE_READ) ? true : false); 
};
I included the extra windows macros because they just made _sense_ when you read them.

This is not guaranteed to work, but this worked for me 5 weeks ago when I last compiled and ran this code.

More specifically, this code does not crash, at least for me, on:

Code:
	HOOKVFUNC(engine, 21, engine_CreateEdict, myCreateEdict); 
	HOOKVFUNC(engine, 22, engine_RemoveEdict, myRemoveEdict); 
	HOOKVFUNC(engine, 43, engine_UserMessageBegin, myUserMessageBegin);
	HOOKVFUNC(engine, 76, engine_LogPrint, myLogPrint);
You can reach me in IRC when I am available, pm u, long term response, or theqizmo, short term response, for any other code excerpts.

p.s.
BAILOPAN, this _is_ is nifty.

p.s.s
_yams_
theqizmo is offline
Send a message via ICQ to theqizmo Send a message via AIM to theqizmo Send a message via MSN to theqizmo
Ruckus
Junior Member
Join Date: Feb 2005
Old 03-27-2005 , 14:13  
#9

I'm having trouble getting this to work. I'm compiling on a Linux system so I combined Vance's and Qizmo's code into this:

Code:
#define ADDRTYPE unsigned long

#define VTBL( classptr ) (*(ADDRTYPE*)classptr)
#define PVFN_( classptr , offset ) (VTBL( classptr ) + offset)
#define VFN_( classptr , offset ) *(ADDRTYPE*)PVFN_( classptr , offset )
#define PVFN( classptr , offset ) PVFN_( classptr , ( offset * sizeof(void*) ) )
#define VFN( classptr , offset ) VFN_( classptr , ( offset * sizeof(void*) ) )

#define HDEFVFUNC( funcname , returntype , proto ) \
	typedef returntype ( VFUNC * funcname##Func ) proto ; \
	extern funcname##Func funcname ;

#ifndef __LINUX__
	#define WIN32_LEAN_AND_MEAN
	#define WIN32_EXTRA_LEAN
	//#include <windows.h>

	class CVirtualCallGate {
	public:

		void Build(void* pOrigFunc, void* pNewFunc, void* pOrgFuncCaller){
			BYTE szGate[] = {
				//pop a	push c	push a	mov a, <dword>	jmp a
				0x58,	0x51,	0x50,	0xB8, 0,0,0,0,	0xFF, 0xE0,
				//pop a	pop c	push a	mov a, <dword>	jmp a
				0x58,	0x59,	0x50,	0xB8, 0,0,0,0,	0xFF, 0xE0
			};

			memcpy(m_szGate, &szGate, sizeof(szGate));

			*(ADDRTYPE*)&m_szGate[4] = (ADDRTYPE)pNewFunc;
			*(ADDRTYPE*)&m_szGate[14] = (ADDRTYPE)pOrigFunc;
			
			*(ADDRTYPE*)pOrgFuncCaller = (ADDRTYPE)&m_szGate[10];
		}

		ADDRTYPE Gate(){
			return (ADDRTYPE)&m_szGate[0];
		}

	private:
		char m_szGate[20];
	};

	inline bool DeProtect(void* pMemory, unsigned int uiLen, bool bLock = false){
		DWORD dwIDontCare;
		
		//return (VirtualProtect(pMemory, uiLen, ((bLock) ? PAGE_READONLY : PAGE_EXECUTE_READWRITE), &dwIDontCare) ? true : false);
	}

	#define VFUNC __stdcall

	#define DEFVFUNC( funcname , returntype , proto ) \
		funcname##Func funcname = NULL; \
		void* funcname##Raw_Org = NULL; \
		CVirtualCallGate funcname##Gate;
	
	#define HOOKVFUNC( classptr , index , funcname , newfunc ) \
		DeProtect((void*)VTBL( classptr ), ( index * sizeof(void*)) + 4 ); \
		funcname##Raw_Org = (void*)VFN( classptr , index ); \
		funcname##Gate.Build( funcname##Raw_Org , newfunc , & funcname ); \
		*(ADDRTYPE*)PVFN( classptr , index ) = funcname##Gate.Gate(); \
		DeProtect((void*)VTBL( classptr ), ( index * sizeof(void*)) + 4 );

	#define UNHOOKVFUNC( classptr , index , funcname ) \
		*(ADDRTYPE*)PVFN( classptr , index ) = (ADDRTYPE) funcname##Raw_Org ;

#else

	#define VFUNC

	#define PAGE_EXECUTE_READ   PROT_EXEC | PROT_READ
	#define PAGE_EXECUTE_READWRITE    PROT_EXEC | PROT_READ | PROT_WRITE

	#define DEFVFUNC( funcname , returntype , proto ) \
		funcname##Func funcname = NULL; 

	inline bool DeProtect(void *pMemory, unsigned int uiLen, bool bWrite)
	{
		char *p;
		p = (char*)((int)(*(void**)pMemory) & ~(PAGESIZE-1));
		   
		return (!mprotect(p, (int)(*(char**)pMemory - p) + uiLen, (bWrite) ? PAGE_EXECUTE_READWRITE : PAGE_EXECUTE_READ) ? true : false);
	}; 

	#define PROTECT( ptr, index, val ) DeProtect( ( void* ) ptr , 2048 , val ) 

	#define HOOKVFUNC( classptr , index , funcname , newfunc ) \
		LOG("[" #classptr ": %d] RW: %s", index , (PROTECT( classptr , index ,  true)) ? "pass" : "fail"); \
		funcname = ( funcname##Func )VFN( classptr , index ); \
		*(DWORD*)PVFN( classptr , index ) = newfunc; \
		LOG("[" #classptr ": %d] RO: %s", index , (PROTECT( classptr , index ,  true)) ? "pass" : "fail"); \
		LOG( #funcname " = 0x%X " #newfunc " = 0x%X" , funcname , newfunc ); 

	#define UNHOOKVFUNC( classptr , index , funcname , newfunc ) \
		*(ADDRTYPE*)PVFN( classptr , index ) = funcname ;

#endif

#define DEFVFUNC_( funcname , returntype , proto ) \
	HDEFVFUNC(funcname, returntype, proto); \
	DEFVFUNC(funcname, returntype, proto)
That compiles fine, but when I try using this line in a plugin:

Code:
DEFVFUNC(engine_CreateEdict, edict_t*, (IVEngineServer* pEngine, int iForceEdictIndex));
I get this error:

Code:
../utils/serverplugin/serverplugin.h:71: error: `engine_CreateEdictFunc' does not name a type
I tried the same thing with Lance's original code and I get the same compilation error. What am I doing wrong?
Ruckus is offline
vancelorgin
Senior Member
Join Date: Dec 2004
Location: san frandisco
Old 03-27-2005 , 15:45  
#10

You have to now either do HDEVFUNC and DEFVFUNC with the same params or DEFVFUNC_ - I made it this way so original functions may be exported to other source files (put HDEFVFUNC in a header and DEFVFUNC in *one* source file - the one with your function to be called in it). If you don't need to export it just add the _ on the end and it'll be equivilant to HDEFVFUNC and DEFVFUNC.

Long story short, add a _ to DEFVFUNC.
__________________
Avoid like the plague.
vancelorgin is offline
Closed Thread



Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT -4. The time now is 05:46.


Powered by vBulletin®
Copyright ©2000 - 2024, vBulletin Solutions, Inc.
Theme made by Freecode