DevMaster.net Forums
[[ Home | Forums | 3D Engines Database | Wiki | Articles/Tutorials | Game Dev Jobs | IRC Chat Network | Contact Us ]]

Go Back   DevMaster.net Forums > Site Discussions > Code & Snapshot Discussion
User Name
Password
Register FAQ Members List Search Today's Posts Mark Forums Read

Reply
 
Thread Tools Search this Thread Display Modes
Old 03-01-2005, 08:31 AM   #1
bladder
DevMaster Staff
 
bladder's Avatar
 
Join Date: Sep 2003
Location: Hell
Posts: 1,109
Default

A while back I started a type of c++ quiz thread - here. One of the forum members - Nick, asked a question of how to get a pointer to an objects constructor. A solution to the *problem* was presented, but it wasnt actually getting the address of the objects constructor. Anyway, quite recently, I was playing around with one of the Code Spotlight submissions: Nick's x86 Decoder, and with that, it is possible to get the actual address of an objects constructor. Now I dont really know how much use this actually is, but I figure it's a pretty neat trick.

So anyway, first of all you need to modify the x86 Decoder a bit. And you need to be able to resolve jmp instructions for this to work in debug builds.

Code:
void* GetActualStartOfFunction( void* ); int NicksModifiedFunction( void*, unsigned char* ); struct SomeStruct { SomeStruct() // we'll get the address of this ctor. :i_(3) {} int i_; }; // You need a function that will create the object you want the address of the // constructor of. void CreateSomeStruct() { SomeStruct ss; } void* GetAddrOfCtor( void (*creator_func)() ) { void* paddr = GetActualStartOfFunction((unsigned char*)creator_func); unsigned char* instr = (unsigned char*)paddr; while(1) // probably better put a limit on this... { int sz = NicksModifiedFunction(instr, 0); if( *instr == 0xE8 ) // the call instruction (should probably check for other versions of it) { paddr = (void*)(int(instr + sz) + *((int*)(instr + 1))); break; } instr += sz; } return paddr; } void main() { void* addr = GetAddrOfCtor(CreateSomeStruct); }

Next I present the modified x86 decoder, which now calculates the size of a single instruction and returns the actual opcode, and the GetActualAddrOfFunction which resolves the jmp instruction (in vc++7 builds at least) to get the actual address of a function.

Code:
void* GetActualAddrOfFunction( void* p ) { void* actual = p; unsigned char code = 0; int sz = NicksModifiedFunction( (unsigned char*)p, &code ); switch( code ) { case 0xeb: // Jump short, relative, displacement relative to next instruction // 8 bit break; case 0xe9: // Jump near, relative, displacement relative to next instruction // 32 or 16 bit. return (void*)(*(unsigned int*)instr + (unsigned int)p + sz); break; case 0xff: // Jump far, absolute indirect, address given in r/m16/32:16/32 // Jump near, absolute indirect, address given in m16/32:16/32 break; case 0xea: // Jump far, absolute, address given in operand // 32 or 16 bit break; } return actual; } int NicksModifiedFunction( void* instr, unsigned char* outCode ) { unsigned char* func = (unsigned char*)instr; int total = 0; int operandSize = 4; int FPU = 0; while(*func == 0xF0 || *func == 0xF2 || *func == 0xF3 || (*func & 0xFC) == 0x64 || (*func & 0xF8) == 0xD8 || (*func & 0x7E) == 0x62) { if(*func == 0x66) operandSize = 2; else if((*func & 0xF8) == 0xD8) { FPU = *func++; total++; break; } func++; total++; } bool twoByte = false; if(*func == 0x0F) { twoByte = true; func++; total++; } unsigned char opcode = *func++; total++; unsigned char modRM = 0xFF; if(FPU) { if((opcode & 0xC0) != 0xC0) modRM = opcode; } else if(!twoByte) { if((opcode & 0xC4) == 0x00 || (opcode & 0xF4) == 0x60 && ((opcode & 0x0A) == 0x02 || (opcode & 0x09) == 0x9) || (opcode & 0xF0) == 0x80 || (opcode & 0xF8) == 0xC0 && (opcode & 0x0E) != 0x02 || (opcode & 0xFC) == 0xD0 || (opcode & 0xF6) == 0xF6) { modRM = *func++; total++; } } else { if((opcode & 0xF0) == 0x00 && (opcode & 0x0F) >= 0x04 && (opcode & 0x0D) != 0x0D || (opcode & 0xF0) == 0x30 || opcode == 0x77 || (opcode & 0xF0) == 0x80 || (opcode & 0xF0) == 0xA0 && (opcode & 0x07) <= 0x02 || (opcode & 0xF8) == 0xC8) { // No mod R/M byte } else { modRM = *func++; total++; } } // Skip SIB if((modRM & 0x07) == 0x04 && (modRM & 0xC0) != 0xC0) { func += 1; total += 1; } // Skip displacement if((modRM & 0xC5) == 0x05) {func += 4;total+=4;} // Dword displacement, no base if((modRM & 0xC0) == 0x40) {func += 1;total+=1;} // Byte displacement if((modRM & 0xC0) == 0x80) {func += 4;total+=4;} // Dword displacement // Skip immediate if(FPU) { // Can't have immediate operand } else if(!twoByte) { if((opcode & 0xC7) == 0x04 || (opcode & 0xFE) == 0x6A || (opcode & 0xF0) == 0x70 || // Jcc opcode == 0x80 || opcode == 0x83 || (opcode & 0xFD) == 0xA0 || // MOV opcode == 0xA8 || (opcode & 0xF8) == 0xB0 || (opcode & 0xFE) == 0xC0 || opcode == 0xC6 || opcode == 0xCD || (opcode & 0xFE) == 0xD4 || // AAD/AAM (opcode & 0xF8) == 0xE0 || opcode == 0xEB || opcode == 0xF6 && (modRM & 0x30) == 0x00) // TEST { func += 1; total += 1; } else if((opcode & 0xF7) == 0xC2) { func += 2; total += 2; // RET } else if((opcode & 0xFC) == 0x80 || (opcode & 0xC7) == 0x05 || (opcode & 0xF8) == 0xB8 || (opcode & 0xFE) == 0xE8 || (opcode & 0xFE) == 0x68 || (opcode & 0xFC) == 0xA0 || (opcode & 0xEE) == 0xA8 || opcode == 0xC7 || opcode == 0xF7 && (modRM & 0x30) == 0x00) { func += operandSize; total += operandSize; } } else { if(opcode == 0xBA || opcode == 0x0F || (opcode & 0xFC) == 0x70 || // PSLLW (opcode & 0xF7) == 0xA4 || opcode == 0xC2 || opcode == 0xC4 || opcode == 0xC5 || opcode == 0xC6) { func += 1; total += 1; } else if((opcode & 0xF0) == 0x80) { func += operandSize; total += operandSize; // Jcc -i } } if( outCode ) *outCode = opcode; return total; }
___________________________________________
- TripleBuffer
- Me blog
bladder is offline   Reply With Quote
Old 03-01-2005, 12:49 PM   #2
SnprBoB86
Valued Member
 
Join Date: Aug 2004
Posts: 120
Default

I might be ignorant, but why is this useful? Or is not? And just nifty?
___________________________________________
Brandon Bloom
http://brandonbloom.name
SnprBoB86 is offline   Reply With Quote
Old 03-01-2005, 03:45 PM   #3
Nick
Senior Member
 
Join Date: Aug 2004
Location: Ghent, Belgium
Posts: 1,056
Default

Very creative!

SnprBoB86, indeed the usefulness is practically zero. A static function can just create any object you need and you can take the pointer of the static function. Anyway, ideas like these can become useful in rare situations like when writing your own debugger or profiling tool, or it can be used to fool crackers, etc. So it's valuable as an excercise and source of inspiration.
Nick is offline   Reply With Quote
Old 03-01-2005, 06:51 PM   #4
bladder
DevMaster Staff
 
bladder's Avatar
 
Join Date: Sep 2003
Location: Hell
Posts: 1,109
Default

Quote:
Originally Posted by SnprBoB86
I might be ignorant, but why is this useful? Or is not? And just nifty?
[snapback]16368[/snapback]


Quote:
Originally Posted by bladder
Now I dont really know how much use this actually is, but I figure it's a pretty neat trick.

___________________________________________
- TripleBuffer
- Me blog
bladder is offline   Reply With Quote
Old 03-01-2005, 10:50 PM   #5
SnprBoB86
Valued Member
 
Join Date: Aug 2004
Posts: 120
Default

lol, by the time I skimmed the code to the bottom, I had forgotten reading that.

I'm a dope hehe
___________________________________________
Brandon Bloom
http://brandonbloom.name
SnprBoB86 is offline   Reply With Quote
Old 03-03-2005, 03:38 AM   #6
Kenneth Gorking
Senior Member
 
Kenneth Gorking's Avatar
 
Join Date: Aug 2004
Location: Århus, Denmark
Posts: 688
Default

There is always the __ctor and __dtor, but MSVC won't allow me to take the address of them...

Time fer some hacking
___________________________________________
"Stupid bug! You go squish now!!" - Homer Simpson
Kenneth Gorking is offline   Reply With Quote
Old 09-19-2005, 04:35 PM   #7
{FluffysWhole}
New Member
 
Join Date: Jul 2005
Posts: 6
Default Re: Getting the address of an objects constructor

or as nick hinted you could do the following:

Code:
typedef (void)pTor*(void*); template< typename Type > class FactoryThing { public: static void ctor( Type* pType ) { new ( pType ) Type(); } static void dtor( Type* pType ) { reinterpret_cast< Type* >( pType )->~Type(); } static void reset( Type* pType ) { dtor( pType ); ctor( pType ); } public: static pTor GetCtorPtr( void ) { return reinterpret_cast< pTor >( &ctor ); } static pTor GetDtorPtr( void ) { return reinterpret_cast< pTor >( &dtor ); } static pTor GetResetPtr( void ) { return reinterpret_cast< pTor >( &reset ); } };

used as:

Code:
pTor pFruitCtor( FactoryThing<Fruit>::GetCtorPtr() ); pFruitCtor( NULL ); //<- hopefully bang in fruit::ctor :)

or:

Code:
FactoryThing<Fruit>::dtor( NULL ); //<- bang in fruit::dtor :)

Last edited by {FluffysWhole} : 09-19-2005 at 04:49 PM.
{FluffysWhole} is offline   Reply With Quote
Reply


Thread Tools Search this Thread
Search this Thread:

Advanced Search
Display Modes

Forum Jump


All times are GMT -7. The time now is 08:52 PM.


Powered by vBulletin
Copyright ©2000 - 2009, Jelsoft Enterprises Ltd.