Intercept problem

09/27/2011 01:53 RunzelEier#1
Hi i have some trouble with a new project.

i want to binary intercept a WSprintf function.
as i dont want to intercept all WSprintf functions i dont directly detour it, i call my own function where WSprintf() gets called.
to make things clearer i will show you some screens:

original function:
[Only registered and activated users can see links. Click Here To Register...]

original function detoured:
(dbghelp.WSprintF_D is my function)
[Only registered and activated users can see links. Click Here To Register...]

this is my source code:
i want to have the information stored in EAX and ECX
PHP Code:
__declspecnaked void WSprintF_D() {
    
__asm{
        
PUSH EBP;
        
MOV EBP,ESP;
    }
    
DWORD d1;
    
DWORD d2;
    
__asm{
        
mov d1ECX;
        
mov d2EAX;
        
PUSH ECX;
        
PUSH EAX

    
}
     
GETInfo((wchar_t*)d1,(wchar_t*)d2);
    
__asm{
        
POP EAX;
        
POP ECX;
        
MOV ESP,EBP;
        
POP EBP;
        
                
PUSH ECX//Saved bytes from original function
        
PUSH EAX;
        
LEA EAXDWORD PTR SS:[EBP-0xA74];
        
jmp WPrintF_back// Jump back to original address
    
}

unfortunately it crashes my game all the time :confused:
if followed in my debugger and the crashes get caused by:

caused EXCEPTION_ACCESS_VIOLATION (0xc0000005)
in module kernel32.dll at 001b:76E7C35D.
this confuses me even more ...
but as the error gets caused by my function you maybe see whats wrong.

mfg,
RunzelEier

PS: könnt natürlich auch auf deutsch antworten ;)
09/27/2011 10:21 link#2
1. Deine lokalen Variablen sind sehr wirr, da du für sie keinen Platz auf dem Stack reservierst. Sie werden zwar wahrscheinlich durch EBP korrekt addressiert, dann durch die PUSHs überschrieben, was an für sich immer noch funktioniert und die Werte richtig bleiben, allerdings sehr unsauber ist, weil das eigentlich unbeabsichtig war, denke ich.

2. Dein Hook besteht aus einem CALL und du beendest deine Funktion mit einem JMP. Entweder musst du wsprintf selber callen oder via JMP hooken.

Wenn du CALL zu JMP ändern würdest, dürfte es so gehen
(beim wsprintf-Aufruf kommt eax zuerst, dann ecx, deine GETInfo-Funktion erwartet sie anscheinend im umgedrehter Reihenfolge, hab's hier mal sozusagen richtig herum übergeben, damit es direkt in den CALL übergeht (angenommen, dass GETInfo cdecl ist)):

Code:
__declspec(naked) void WSprintF_D(void)
{
    __asm
    {
        push ecx
        push eax
        call GETInfo
        lea eax,[ebp-A74h]
        jmp WPrintF_back;
    }
}
So sollte es (oder auch nicht..) mit deinem CALL funktionieren:

Code:
__declspec(naked) void WSprintF_D(void)
{
    __asm
    {
        push ebx
        push ecx
        push eax
        call GETInfo
        mov eax,[esp+0Ch]
        mov eax,[eax+1]
        push eax
        lea ebx,[ebp-A74h]
        push ebx
        call wsprintfW
        xchg eax,ebx
        add esp,10h
        pop ebx
        add dword ptr [esp],15h
        retn
    }
}
09/27/2011 12:44 RunzelEier#3
Hi,
danke für die hilfe.
mit dem jump klappt es jetzt.

nun steh ich aber vor dem nächsten problem.
EAC und ECX halten pointer auf einen UNICODE string.
ich hab schon einwenig rumprobiert, habe aber bisher nur geschaft mir den ersten buchstaben ausgeben zu lassen.

so sieht sie bisher aus
PHP Code:
void __cdecl GETInfo(wchar_tArg1,wchar_tArg2){
    
std::wcout << "Arg1: " << *Arg1 << "  Arg2: " << *Arg2 << std::endl;
    return;

09/27/2011 13:19 link#4
"EAC und ECX halten pointer auf einen UNICODE string."
Wenn's so ist, muss es ja an wcout liegen.
Hast du es also mal mit printf, cout oder MessageBox probiert?

Ich würd's irgendwie so mal testen:

Code:
void __cdecl GETInfo(LPCWSTR Arg1, LPCWSTR Arg2)
{
    char buffer1[128], buffer2[128], *p1;
    wchar *p2;
    p1 = &buffer1;
    p2 = Arg1;
    do
    {
      *p1++ = (char)*p2++;
    } while (*(p1-1) != '\0');
    p1 = &buffer2;
    p2 = Arg2;
    do
    {
      *p1++ = (char)*p2++;
    } while (*(p1-1) != '\0');
    MessageBoxA(NULL, &buffer1, "", MB_OK);
    MessageBoxA(NULL, &buffer2, "", MB_OK);
    MessageBoxW(NULL, Arg1, "", MB_OK);
    MessageBoxW(NULL, Arg2, "", MB_OK);
}
Edit:
Achso, ja..
std::wcout << "Arg1: " << *Arg1 << " Arg2: " << *Arg2 << std::endl;
Hab die Sternchen übersehen.
Mach sie einfach weg und dann werden die Pointer nicht mehr dereferenziert,
sodass du die Adressen der Strings übergibst und nicht nur den ersten Char.
09/27/2011 21:04 RunzelEier#5
Hab jetzt mein problem gefunden.

ist klar, das man nur einen buchstaben bekommt, wenn sich nur einen übergeben lässt.
die lösung:
PHP Code:
void __cdecl GETInfo(wchar_t Arg1[],wchar_t Arg2[]){
    
std::wcout << "Arg1: " << Arg1 << "  Arg2: " << Arg2 << std::endl;
    return;

bin noch nicht lange bei c++ dabei :D

EDIT:
ich möchte die beiden argumente nun weiter verarbeiten und das mit der wsprintfW funktion.
nur steh ich vor dem problem, das sich danach aus mir unerklärlichen gründen der return von wsprintfW auf dem stack dort steht, wo die original funktion ihr zweites parameter herbekommt. :confused:
warum überschreibt die mir mein zuvor gepushtes ECX?
deswegen kommt bei der original funktion nicht mehr der original text an.
und beim nochmaligem aufruf der original funktion crashed das game mit ner null pointer exception.

hier der kot, den ich verbrochen habe

PHP Code:
void __cdecl GETInfo(wchar_t Arg1[] ,wchar_t Arg2[]){
    
LPWSTR buffer;
    
wsprintfW(buffer,L"Arg1=%s&Arg2=%s ",Arg1,Arg2);
    
std::wcout << buffer << std::endl;
    return;
}


__declspec(nakedvoid WSprintF_D(void)
{
    
__asm
    
{
        
push ecx
        push eax
        call GETInfo
        lea eax
,[ebp-0xA74]
        
jmp WPrintF_back
    
}

abgesehen davon, liefer mir wsprintfW einen falschen wert zurück.
undzwar z.b.
GETInfo(L"Test1",L"Test2")

gibt zurück: Arg1=Test1&Arg2=Arg1=Test1&Arg2=A