There's a program I'm messing around with to get more experience with hooking, and the problems that can arise. The target makes very heavy use of classes, member functions, virtual functions, etc. In this instance, the target is always compiled in Visual Studio 2005, so I don't need to worry about cross-platform semantics & the like. I have access to the source code, and symbols, so I have a lot of freedom to figure out how things work.
The target function is a non-virtual member function using the __thiscall calling convention, so this should be passed in ECX. Here's a sample of the code:
#include <windows.h>
#include <iostream>
#include <string>
#include <sstream>
#include "detours.h"
#define getECX(p) _asm {mov p, ECX}
#define setECX(p) _asm {mov ECX, p}
typedef int (__stdcall *IIPtrType)(int param1);
IIPtrType REAL_originalFunction = 0;
int DETOUR_originalFunction (int result) {
unsigned int pThis;
getECX(pthis);
std::stringstream msg;
std::string *dataptr = (std::string *)(*(unsigned int *)(pThis + Off_1) + Off_2);
std::string data(dataptr->c_str());
/*...*/
}
The this object has a member at offset Off_1, which has an std::string at offset Off_2. It's a very simple situation, but I'm running into a few issues and I'm trying to understand what the ultimate cause is.
The first problem is not a huge deal (I think). The debugger shows pThis as having value 99d, but when I check the value in memory at ebp+4 it has the correct value of what is in ECX when the function is entered. Additionally, when pThis is used elsewhere, the correct value does get used, so I'm convinced it's just an issue with the debugger. Any idea what may be at issue here?
The second problem is more serious. The disassembly looks like this:
int DETOUR_originalFunction (int result) {
020C1050 sub esp,0ACh
020C1056 mov eax,dword ptr [___security_cookie (20C5008h)]
020C105B xor eax,esp
020C105D mov dword ptr [esp+0A8h],eax
020C1064 push esi
unsigned int pThis;
getECX (pThis);
020C1065 mov dword ptr [esp+4],ecx
std::stringstream msg;
020C1069 push 1
020C106B push 3
020C106D lea ecx,[esp+10h]
020C1071 call dword ptr [__imp_std::basic_stringstream<char,std::char_traits<char>,std::allocator<char> >::basic_stringstream<char,std::char_traits<char>,std::allocator<char> > (20C3064h)]
std::string *methodPtr = (std::string *)(*(unsigned int *)(pThis + Off_1) + Off_2);
020C1077 mov eax,dword ptr [esp+4]
020C107B mov eax,dword ptr [eax+0A4h]
020C1081 add eax,0DCh
If I check the location pointed at by (this + Off_1) before the stringstream constructor is called, there is a non-null value there. After the constructor executes, it zeros that memory. Therefore, when the instruction:
mov eax,dword ptr [eax+0A4h]... executes, it loads zeros into eax, then adds 0xDC to that, then tries to treat memory location 0x000000DC as an std::string (which, of course, results in an access violation).
Any comments?
-Brian






