5

I'm using IDA Pro 6.5, and I got the offset of a function and its arguments. It looks like this:

.text:0000C0DE        int __cdecl func(char* a1, int a2, int a3, int a4, int a5, int a6, char* a7)

However, it has tons of xrefs (more than 200!)

Is there any way of dumping a1 and a7 arguments of every call to a list?
I cannot hook and dump the arguments at runtime.

I know I can walk the xref list with IDC, but once I'm on the call func instruction, I don't know how to get arguments from the stack.

3 Answers 3

5

If you have the Hex-Rays Decompiler, I'd recommend decompiling the entire binary and then grep'ing the resulting decompilation for func(.

This should provide you with more useful results than whatever IDC script one could develop.

0
1

Manual approach: you can write relevant parameter values (and other pertinent info) as a comment after each call. That way the info shows up in the crossrefs listing.

This can also be scripted but that involves walking the instructions before each call and emulating the instructions in a limited fashion. Once you reach the call instruction you can access your simulated mini stack and emulated registers to see if they have constant (known) values or not, and generate above-mentioned comment accordingly.

1

The problem is that those arguments may, and will in most cases, be calculated, not constants, so you don't really have one single instruction that gives you the parameter. Consider this test program:

#include <stdio.h>

int a, b, c, d, e, f, g, h, i, j;

void func(int a1, int a2, int a3, int a4, int a5) {
        printf("%d %d %d %d %d\n", a1, a2, a3, a4, a5);
}

int main(void) {
        int x, y;

        x=g+c;
        y=d*e+i;

        func(1, a, b+c, 7, j);
        printf("blarfl\n");
        func(e, j*c, 3, x, y);
}

After compiling it (with -O0 and without symbols) and loading it in IDA, the main functions looks like this:

push    rbp
mov     rbp, rsp
sub     rsp, 10h
mov     edx, cs:g
mov     eax, cs:c
add     eax, edx
mov     [rbp+var_8], eax
mov     edx, cs:d
mov     eax, cs:e
imul    edx, eax
mov     eax, cs:i
add     eax, edx
mov     [rbp+var_4], eax
mov     ecx, cs:j
mov     edx, cs:b
mov     eax, cs:c
add     edx, eax
mov     eax, cs:a
mov     r8d, ecx
mov     ecx, 7
mov     esi, eax
mov     edi, 1
call    func
mov     edi, offset s   ; "blarfl"
call    _puts
mov     edx, cs:j
mov     eax, cs:c
mov     esi, edx
imul    esi, eax
mov     eax, cs:e
mov     ecx, [rbp+var_4]
mov     edx, [rbp+var_8]
mov     r8d, ecx
mov     ecx, edx
mov     edx, 3
mov     edi, eax
call    func
leave

Once you define your function

; __int64 __cdecl func(int XYZ1, int XYZ2, int XYZ3, int XYZ4, int XYZ5)

the disassembly of main turns into

push    rbp
mov     rbp, rsp
sub     rsp, 10h
mov     edx, cs:g
mov     eax, cs:c
add     eax, edx
mov     [rbp+XYZ4], eax
mov     edx, cs:d
mov     eax, cs:e
imul    edx, eax
mov     eax, cs:i
add     eax, edx
mov     [rbp+XYZ5], eax
mov     ecx, cs:j
mov     edx, cs:b
mov     eax, cs:c
add     edx, eax        ; XYZ3
mov     eax, cs:a
mov     r8d, ecx        ; XYZ5
mov     ecx, 7          ; XYZ4
mov     esi, eax        ; XYZ2
mov     edi, 1          ; XYZ1
call    func
mov     edi, offset s   ; "blarfl"
call    _puts
mov     edx, cs:j
mov     eax, cs:c
mov     esi, edx
imul    esi, eax        ; XYZ2
mov     eax, cs:e
mov     ecx, [rbp+XYZ5]
mov     edx, [rbp+XYZ4]
mov     r8d, ecx        ; XYZ5
mov     ecx, edx        ; XYZ4
mov     edx, 3          ; XYZ3
mov     edi, eax        ; XYZ1
call    func
leave
retn

so you see ida auto-generates comments where the parameters are assigned. You can probably scan backwards 10 or 20 instructions from each xref using PrevNotTail, and check the comments for your parameter strings. If you make your parameter names sufficiently unique, this should identify the instructions quite well (that's why i used XYZ1 instead of a1).

Of course,

imul    esi, eax        ; XYZ2

won't really help you that much. But your results may be better if most parameters to your func are constants.

6
  • 1
    The problem with PrevNotTail() - and PrevHead(), for that matter - is that they are oblivious to branching; they go blindly backwards in a linear fashion. For a quick overview they work well enough but accurate, dependable results require analysing the whole web of basic blocks for a function.
    – DarthGizka
    Commented Jan 5, 2015 at 12:48
  • Isn't this answer specific to 64-bit? Most 32-bit programs get compiled using __stdcall and __cdecl calling conventions, and the parameters would most likely be pushed to the stack.
    – RoraΖ
    Commented Jan 5, 2015 at 13:33
  • @raz: Yes, but Ida will comment-mark the parameters in the same way. Of course, you'll mainly see push <reg> instructions if you look for the comments, so those instructions are even more unusable than the above examples. Commented Jan 5, 2015 at 14:19
  • 2
    @DarthGizka Doing it always correctly is probably impossible / equivalent to the halting problem. Something like func(1, (a<b ? 2 : 3), 4) will probably compile to a push 4, two branches that push 2 or 3 respectively, and a push 1. But how do you want to display this in your list of parameter-annotated xrefs anyway, unless you're trying to re-implement the Hex Rays Decompiler? Spending the time to process the 5% edge cases manually is probably much more efficient than trying to get everything handled in your helper program, especially if that program is intended for one specific task. Commented Jan 5, 2015 at 14:27
  • 2
    'Accurate' doesn't have to mean 'perfect'; 'no can do' is an answer that is accurate enough in many cases. A backwards scan should at least be augmented with checking xrefs to recognise when a basic block boundary has been crossed, in which case the result should be marked as questionable (needing manual inspection). The premise is that a wrong answer can be worse than no answer at all sometimes. Also, there is a very wide range between limited simulation of a handful of instructions (in a special IDA script for one special purpose) and a full general-purpose decompiler...
    – DarthGizka
    Commented Jan 5, 2015 at 14:55

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.