🎉 Celebrating 25 Years of GameDev.net! 🎉

Not many can claim 25 years on the Internet! Join us in celebrating this milestone. Learn more about our history, and thank you for being a part of our community!

Hacking

Started by
12 comments, last by smart_idiot 20 years, 10 months ago
I''m trying to write a wrapper to make MinGW work with GDArena. This is a log generated by my MinGW compiled GDArena DLL:

 <
   Player_interface invoked with (const char *)0x00413854 "IPlayer" for argument 1 and (IPlayer **)0x00b02fe8 for argument 2.
   Size of IPlayer (bytes): 12
   Size of IPlayer''s vtable (bytes): 20
   Size of ICore (bytes): 4
   Size of ICore''s vtable (bytes): 56
   Dereferencing the second argument, and assigning it to 0.
   Allocating space for a new IPlayer object.
   Space allocated at 0x00b01030.
   Invoking the constructor for the new object.
    <
      IPlayer::IPlayer invoked with (IPlayer *)0x00b01030 as this pointer.
      Setting this->vtbl to 0x023d400c
      Setting this->refcount to 0.
      Setting this->core to 0.
      Returning from IPlayer::IPlayer
    >

   Invoking the new object''s QueryInterface function.
    <
      IPlayer::QueryInterface invoked with (IPlayer *)0x00b01030 as this pointer, (const char *)0x00413854 "IPlayer" as argument 1, and (IPlayer **)0x00b02fe8 as argument 2.
      Dereferencing second argument, and assigning it to this.
      Increasing this->refcount.
      this->refcount is now equal to 0x00000001.
      Returning 0x01 from IPlayer::QueryInterface.
    >

   The object''s QueryInterface function didn''t return 0.
   Returning 0x01 from Player_interface
 >

 <
   IPlayer::AttachToGame invoked with (IPlayer *)0x00aa1020 as this pointer, and (ICore *)0x00aa2310 as argument 1.
   Assigning the second argument to this->core.
   Returning 0x00 from IPlayer::AttachToGame.
 >

(... Some other stuff, followed by a crash.)
It works perfectly with the driver program I wrote to run it, but in any place GDArena calls one of the object''s function, the this pointer is pointing to the wrong place. The virtual function table is hacked together correctly and GDArena has the correct address of the object since it needs it to find the table and execute the AttachToGame function, so I''m probably not looking for it in the right place. So my question is: Where is the this pointer? In a register? Burried on the stack somewhere? Where?
Chess is played by three people. Two people play the game; the third provides moral support for the pawns. The object of the game is to kill your opponent by flinging captured pieces at his head. Since the only piece that can be killed is a pawn, the two armies agree to meet in a pawn-infested area (or even a pawn shop) and kill as many pawns as possible in the crossfire. If the game goes on for an hour, one player may legally attempt to gouge out the other player's eyes with his King.
Advertisement
hAx t3h pl4n3t j00d!!!
=-=l33t hax0r? logitank.net
Found it, the pointer is stored in register ecx.
Chess is played by three people. Two people play the game; the third provides moral support for the pawns. The object of the game is to kill your opponent by flinging captured pieces at his head. Since the only piece that can be killed is a pawn, the two armies agree to meet in a pawn-infested area (or even a pawn shop) and kill as many pawns as possible in the crossfire. If the game goes on for an hour, one player may legally attempt to gouge out the other player's eyes with his King.
The log seems to be filled with the correct values now:
 <   Player_interface invoked with (const char *)0x00413854 "IPlayer" for argument 1 and (IPlayer **)0x00afda58 for argument 2.   Size of IPlayer (bytes): 12   Size of IPlayer''s vtable (bytes): 20   Size of ICore (bytes): 4   Size of ICore''s vtable (bytes): 56   Dereferencing the second argument, and assigning it to 0.   Allocating space for a new IPlayer object.   Space allocated at 0x00af95b0.   Invoking the constructor for the new object.    <      IPlayer::IPlayer invoked with (IPlayer *)0x00af95b0 as this pointer.      Setting this->vtbl to 0x01fd4004      Setting this->refcount to 0.      Setting this->core to 0.      Returning from IPlayer::IPlayer    >   Invoking the new object''s QueryInterface function.    <      IPlayer::QueryInterface invoked with (IPlayer *)0x00af95b0 as this pointer, (const char *)0x00413854 "IPlayer" as argument 1, and (IPlayer **)0x00afda58 as argument 2.      Dereferencing second argument, and assigning it to this.      Increasing this->refcount.      this->refcount is now equal to 0x00000001.      Returning 0x01 from IPlayer::QueryInterface.    >   The object''s QueryInterface function didn''t return 0.   Returning 0x01 from Player_interface > <   IPlayer::AttachToGame invoked with (IPlayer *)0x00af95b0 as this pointer, and (ICore *)0x00aa1020 as argument 1.   Assigning the second argument to this->core.   Returning 0x00 from IPlayer::AttachToGame. > <   IPlayer::Init invoked with (IPlayer *)0x00af95b0 as this pointer.   this->core is (ICore *)0x00aa1020.   this->core''s vtable is located at 0x004107c8.   Invoking this->core''s Register function.   Returning from IPlayer::Init. > ***CRASH***


I''m not sure if the pointer to the core is correct as I have nothing to compare it to, but since it get''s used in the Init function and didn''t crash it, I assume it''s right.

Still crashing, but at least it''s getting farther than it was, and the crash isn''t inside the DLL anymore. Maybe it''s clobbering a register or something.
Chess is played by three people. Two people play the game; the third provides moral support for the pawns. The object of the game is to kill your opponent by flinging captured pieces at his head. Since the only piece that can be killed is a pawn, the two armies agree to meet in a pawn-infested area (or even a pawn shop) and kill as many pawns as possible in the crossfire. If the game goes on for an hour, one player may legally attempt to gouge out the other player's eyes with his King.
Just wondering...

I was trying to hack it too, so I can test my bot. And decided to disassembly it. I realized that in lots of functions, parameters are passed via ecx register (I guess they are not __fastcalls, because there''s only one param passed through it, and MS''s __fastcalls use 2 registers to pass it --ecx and edx--).

I''m thinking if this is a compiler''s optimization to handle the "this" pointer, mostly because i''ve seen lots of [ecx+04h] or similars, as if ecx where the pointer to a struct (or class).

I want to know if MSVC uses ecx to pass the "this" pointer, and if so, I''d point it as the possible reason of why the Arena doesn''t works with other compilers (almost every other compiler uses the stack to pass the "this" pointer).

--
After typeing all this, I realized that smart_idiot also found it. Then I MUST ask it: WHY IN COMPILING-GOD''S SAKE DOES VC++ USES ECX TO PASS THE THIS POINTER?
It is. MSVC is using ecx, MinGW is putting it on the stack as if it were a hidden parameter to the function. In MinGW I could just cast it to a function who''s prototype includes that hidden parameter, but with MSVC I had to resort to inline assembly to get to it.

It''s really just plain not nice. I hope the next version has a more multi-compiler friendly interface.
Chess is played by three people. Two people play the game; the third provides moral support for the pawns. The object of the game is to kill your opponent by flinging captured pieces at his head. Since the only piece that can be killed is a pawn, the two armies agree to meet in a pawn-infested area (or even a pawn shop) and kill as many pawns as possible in the crossfire. If the game goes on for an hour, one player may legally attempt to gouge out the other player's eyes with his King.
As I''ve no doubt proved before, I''m not an expert on this stuff, but could this problem be solved by making all interface functions use the stdcall calling convention? As far as I know, calling conventions are what dicates how parameters are passed, so specifically marking the functions as stdcall would force both compilers to use the same system, wouldn''t it?

John B
The best thing about the internet is the way people with no experience or qualifications can pretend to be completely superior to other people who have no experience or qualifications.
As far as I know that just controls which function removes the arguments from the stack.
Chess is played by three people. Two people play the game; the third provides moral support for the pawns. The object of the game is to kill your opponent by flinging captured pieces at his head. Since the only piece that can be killed is a pawn, the two armies agree to meet in a pawn-infested area (or even a pawn shop) and kill as many pawns as possible in the crossfire. If the game goes on for an hour, one player may legally attempt to gouge out the other player's eyes with his King.
I''ve removed access to the "this" pointer in the next update. I don''t know if it will help, but I''m trying.

Admin for GameDev.net.

Any attempt will be greatly appreciated, thankyou.
Chess is played by three people. Two people play the game; the third provides moral support for the pawns. The object of the game is to kill your opponent by flinging captured pieces at his head. Since the only piece that can be killed is a pawn, the two armies agree to meet in a pawn-infested area (or even a pawn shop) and kill as many pawns as possible in the crossfire. If the game goes on for an hour, one player may legally attempt to gouge out the other player's eyes with his King.

This topic is closed to new replies.

Advertisement