Search code examples
ollydbg

Recognizing passed parameters in a CALL instruction using Ollydbg


The calling convention used in assembly differs depending to the compiler. The Question is: How ollydbg2.01 would help me to recognize the parameters passed from caller to the callee and values returned back to the caller from the callee for a CALL instruction. The assembly which I am working on is compiled by Microsoft visual C++.


Solution

  • Calling convention is not dependent on any compiler.

    By default microsoft visual studio uses __cdecl (user has to clean up the stack)

    You can force it to use __stdcall (called function is responsible for cleaning the stack)

    You can also compile with __declspec (naked) ( arbitrary cleanup )

    Afaik x64 is FASTCALL only (no other calling conventions are applicable)

    you can recognize calling convention by looking at the assembly

    if you observe

    call xxxx
    add esp,XXXXX 
    it most likely is __cdecl
    

    if you observe

    call xxxx
    inside the call 
    leave 
    retn XXX then it is likely to be __stdcall
    

    and so on

    you may need to recognize a specific construct by observation of disassembly and corelate it with the calling convention

    calling conventions can also be mixed arbitrarily so you may need to ascertain each function calls individually

    compile with cl /Zi /nologo /W4 /analyze xxx.cpp /link /RELEASE

    #include <stdio.h>
    char *domain = "i am calling me" , *formatstr = "%s %s\n";
    void __cdecl cdecprint (char *king) {
        printf(formatstr,domain,king);
    }
    void __stdcall stdprint (char *king) {
        printf(formatstr,domain,king);
    }
    void __fastcall fastprint (char *king) {
        printf(formatstr,domain,king);
    }
    __declspec(naked) void arbitprint (char *king) {
        (void)king; //unreferenced warning 
        __asm    {
            lea eax, [esp+4]
            push [eax]
            push domain
                push formatstr
                call printf
                add esp,0Ch
                retn
        }
    }
    int main (void) {
        cdecprint("cdecinking");
        stdprint("stdking");
        fastprint("fastking");
        arbitprint("arbitking");
        return 0x1337;
    }
    

    and the relevent disassembly of main

    004010A0 callme.main PUSH    EBP                     ; {
    004010A1             MOV     EBP, ESP
    004010A3             PUSH    callme.004121A4     ; cdecprint("cdecinking");
    004010A8             CALL    callme.cdecprint
    004010AD             ADD     ESP, 4  <---------- ; call above is likely __cdecl
    004010B0             PUSH    callme.004121B0     ; stdprint("stdking");
    004010B5             CALL    callme.stdprint  <--; no cleanup likely __stdcall
    004010BA             MOV     ECX, callme.004121B8; fastprint("fastking"); 
    004010BF             CALL    callme.fastprint <--; __stdcall ? No __fastcall 
    004010C4             PUSH    callme.004121C4     ; arbitprint("arbitking");
    004010C9             CALL    callme.arbitprint   ;
    004010CE             ADD     ESP, 4  <---------  ; __cdecl? No __declspec (naked)
    004010D1             MOV     EAX, 1337           ; return 0x1337;
    004010D6             POP     EBP                 ; }
    004010D7             RETN
    

    __cdecl

    00401000 callme.cdecprint  PUSH    EBP
    00401001                   MOV     EBP, ESP
    00401003                   MOV     EAX, DWORD PTR SS:[EBP+8]
    00401006                   PUSH    EAX
    00401007                   MOV     ECX, DWORD PTR DS:[domain]
    0040100D                   PUSH    ECX
    0040100E                   MOV     EDX, DWORD PTR DS:[formatstr]
    00401014                   PUSH    EDX
    00401015                   CALL    callme.printf
    0040101A                   ADD     ESP, 0C
    0040101D                   POP     EBP
    0040101E                   RETN
    

    __stdcall

    00401020 callme.stdprint   PUSH    EBP
    00401021                   MOV     EBP, ESP
    00401023                   MOV     EAX, DWORD PTR SS:[EBP+8]
    00401026                   PUSH    EAX
    00401027                   MOV     ECX, DWORD PTR DS:[domain]
    0040102D                   PUSH    ECX
    0040102E                   MOV     EDX, DWORD PTR DS:[formatstr]
    00401034                   PUSH    EDX
    00401035                   CALL    callme.printf
    0040103A                   ADD     ESP, 0C
    0040103D                   POP     EBP
    0040103E                   RETN    4
    

    __fastcall

    00401050 callme.fastprint  PUSH    EBP     
    00401051                   MOV     EBP, ESP
    00401053                   PUSH    ECX
    00401054                   MOV     DWORD PTR SS:[EBP-4], ECX
    00401057                   MOV     EAX, DWORD PTR SS:[EBP-4]
    0040105A                   PUSH    EAX
    0040105B                   MOV     ECX, DWORD PTR DS:[domain]
    00401061                   PUSH    ECX
    00401062                   MOV     EDX, DWORD PTR DS:[formatstr]
    00401068                   PUSH    EDX
    00401069                   CALL    callme.printf
    0040106E                   ADD     ESP, 0C
    00401071                   MOV     ESP, EBP
    00401073                   POP     EBP
    00401074                   RETN
    

    __declspec (naked)

    00401080 callme.arbitprint LEA     EAX, DWORD PTR SS:[ESP+4]
    00401084                   PUSH    DWORD PTR DS:[EAX]
    00401086                   PUSH    DWORD PTR DS:[domain]
    0040108C                   PUSH    DWORD PTR DS:[formatstr]
    00401092                   CALL    callme.printf
    00401097                   ADD     ESP, 0C
    0040109A                   RETN
    

    apart from the 4 above there are a few specialized calling conventions and obsolete calling conventions

    __clrcall is for managed 
    __vectorcall is for using streaming instructions (sse 2 .....)
    __thiscall used mostly oop and com methods
    __pascal etc obsolete