0

I'm using IDA to disassemble a file, and one of the sections contained this. What is this doing? What would it look like in C?

I believe it pushes edx onto the stack, and converts it to an integer using _atoi, but what is left in eax after that, and why is it comparing it to 5?

mov     ecx, [ebp+argv]
mov     edx, [ecx+4]
push    edx             ; char *
call    _atoi
add     esp, 4
mov     [ebp+var_60], eax
cmp     [ebp+var_60], 5
jle     short loc_401167

Edit: Got a great answer, also another good answer here. https://stackoverflow.com/questions/33535720/what-does-this-code-do-and-what-does-it-look-like-in-c/33535891#33535891

  • What's with the downvote? Just curious, I always want to make my questions better. No comment after the downvote doesn't help though. – Austin Donley Nov 5 '15 at 3:00
  • Not the downvoter, but i think the problem is the same reason as the one for the close vote: "Questions asking for help reverse-engineering a specific system are off-topic unless they demonstrate an understanding of the concepts involved and clearly identify a specific problem" – Guntram Blohm Nov 5 '15 at 3:23
  • 1
    Hmm. I could post the rest of the code that I've already disassembled, to prove my "understanding," but I thought this was just a curious problem. I asked a specific set of questions, stated what my understanding so far was, and posted legitimate assembly code. I got it answered over at stackoverflow anyways. – Austin Donley Nov 5 '15 at 3:27
  • 2
    "I got it answered over at stackoverflow anyways" -- please don't cross-post, or at least mention that and link the questions, to stop people from putting needless effort into questions that already have a solution. – Guntram Blohm Nov 5 '15 at 3:34
  • No problem; won't do that again. Will link to overflow in an edit to the main post. – Austin Donley Nov 5 '15 at 3:35
3

seems to be unoptimized compilation anyway if you were using ollydbg and compiled this code with debug information ollydbg will show the source code in the next column

source used

#include <stdio.h>
#include <stdlib.h>
int main (int argc , char* argv[]) {
  if(argc!=2){return -1;}
  signed int foo =0;
  if((foo = atoi(argv[1])) > 5) {goto blah;}
  printf("notok");return 0;
  blah:
  printf("ok");return 1;
}

compiled with no optimisations

cl /Zi /EHsc /nologo /W4 /analyze *.cpp /link /RELEASE

00401000 a>PUSH    EBP                         ; {
00401001   MOV     EBP, ESP
00401003   PUSH    ECX
00401004   CMP     DWORD PTR SS:[EBP+8], 2     ; if(argc!=2){return -1;}
00401008   JE      SHORT atoitest.0040100F
0040100A   OR      EAX, FFFFFFFF
0040100D   JMP     SHORT atoitest.00401055
0040100F   MOV     DWORD PTR SS:[EBP-4], 0     ; signed int foo =0;
00401016   MOV     EAX, DWORD PTR SS:[EBP+C]   ; if((foo = atoi(argv[1])) > 5) {goto blah;}
00401019   MOV     ECX, DWORD PTR DS:[EAX+4]
0040101C   PUSH    ECX
0040101D   CALL    atoitest.atoi
00401022   ADD     ESP, 4
00401025   MOV     DWORD PTR SS:[EBP-4], EAX
00401028   CMP     DWORD PTR SS:[EBP-4], 5
0040102C   JLE     SHORT atoitest.00401032
0040102E   JMP     SHORT atoitest.00401043
00401030   JMP     SHORT atoitest.00401043
00401032   PUSH    atoitest.0041218C           ; printf("notok");return 0;
00401037   CALL    atoitest.printf
0040103C   ADD     ESP, 4
0040103F   XOR     EAX, EAX
00401041   JMP     SHORT atoitest.00401055
00401043   PUSH    atoitest.00412194           ; printf("ok");return 1;
00401048   CALL    atoitest.printf
0040104D   ADD     ESP, 4
00401050   MOV     EAX, 1
00401055   MOV     ESP, EBP                    ; }
00401057   POP     EBP
00401058   RETN

the same src code compiled with msvc /O1 does away all saves

cl /Zi /O1 /EHsc /nologo /W4 /analyze *.cpp /link /RELEASE

00401000 a>CMP     DWORD PTR SS:[ESP+4], 2     ; {
00401005   JE      SHORT atoitest.0040100B
00401007   OR      EAX, FFFFFFFF
0040100A   RETN                                ; }
0040100B   MOV     EAX, DWORD PTR SS:[ESP+8]   ; if((foo = atoi(argv[1])) > 5) {goto blah;}
0040100F   PUSH    DWORD PTR DS:[EAX+4]
00401012   CALL    atoitest.atoi
00401017   POP     ECX
00401018   CMP     EAX, 5
0040101B   JLE     SHORT atoitest.0040102C
0040101D   PUSH    atoitest.00412194           ; printf("ok");return 1;
00401022   CALL    atoitest.printf
00401027   XOR     EAX, EAX
00401029   INC     EAX
0040102A   POP     ECX
0040102B   RETN                                ; }
0040102C   PUSH    atoitest.0041218C           ; printf("notok");return 0;
00401031   CALL    atoitest.printf
00401036   XOR     EAX, EAX
00401038   POP     ECX
00401039   RETN                                ; }

same code with single exit and no gotos

#include <stdio.h>
#include <stdlib.h>
int main (int argc , char* argv[]) {
  if(argc==2)  {
    int foo =0;
    if((foo = atoi(argv[1])) > 5) {
      printf("ok");
    } else {
      printf("notok");
    }
  }
  return 0;
}

unoptimesed compilation

00401000 a>PUSH    EBP                         ; int main (int argc , char* argv[]) {
00401001   MOV     EBP, ESP
00401003   PUSH    ECX
00401004   CMP     DWORD PTR SS:[EBP+8], 2     ; if(argc==2)  {
00401008   JNZ     SHORT atoitest.00401045
0040100A   MOV     DWORD PTR SS:[EBP-4], 0     ; int foo =0;
00401011   MOV     EAX, DWORD PTR SS:[EBP+C]   ; if((foo = atoi(argv[1])) > 5) {
00401014   MOV     ECX, DWORD PTR DS:[EAX+4]
00401017   PUSH    ECX
00401018   CALL    atoitest.atoi
0040101D   ADD     ESP, 4
00401020   MOV     DWORD PTR SS:[EBP-4], EAX
00401023   CMP     DWORD PTR SS:[EBP-4], 5
00401027   JLE     SHORT atoitest.00401038
00401029   PUSH    atoitest.0041218C           ; printf("ok");
0040102E   CALL    atoitest.printf
00401033   ADD     ESP, 4
00401036   JMP     SHORT atoitest.00401045     ; } else {
00401038   PUSH    atoitest.00412190           ; printf("notok");
0040103D   CALL    atoitest.printf
00401042   ADD     ESP, 4
00401045   XOR     EAX, EAX                    ; return 0;
00401047   MOV     ESP, EBP                    ; }
00401049   POP     EBP
0040104A   RETN

optimised compilation

00401000 a>CMP     DWORD PTR SS:[ESP+4], 2     ; int main (int argc , char* argv[]) {
00401005   JNZ     SHORT atoitest.0040102B
00401007   MOV     EAX, DWORD PTR SS:[ESP+8]   ; if((foo = atoi(argv[1])) > 5) {
0040100B   PUSH    DWORD PTR DS:[EAX+4]
0040100E   CALL    atoitest.atoi
00401013   POP     ECX
00401014   CMP     EAX, 5
00401017   JLE     SHORT atoitest.00401020
00401019   PUSH    atoitest.00412194           ; printf("ok");
0040101E   JMP     SHORT atoitest.00401025     ; } else {
00401020   PUSH    atoitest.0041218C           ; printf("notok");
00401025   CALL    atoitest.printf
0040102A   POP     ECX
0040102B   XOR     EAX, EAX                    ; return 0;
0040102D   RETN                                ; }
2

The part before the call to atoi gets the content of argv[1] on the stack:

  • mov ecx, [ebp+argv] gets argv into ecx
  • mov edx, [ecx+4] gets argv[1] into edx - note argv is an array of pointers, each 4 bytes in size, so [ecx+4] is the "first" (counting from 0) element
  • push edx puts it on the stack as the argument to atoi.

C functions return their result in eax*, so the mov [ebp+var_60], eax instruction saves the result of atoi(argv[1]) to a local variable.

We can't know why that result is compared to 5, this is part of the application logic. If that application was a crackme, and part of the challenge is "find out which number to give as a command line argument to make the program do something special", then 5 would be a good candidate for that special number.

(*) in most cases, unless they don't fit there, for example in the case of doubles or structs.

  • Great answer, thank you. It's nice to know C functions return their result to eax; I had forgotten. – Austin Donley Nov 5 '15 at 3:34

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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