Looking this snippet of code I can't figure out where is stored the return value of the scanf() function.


From man page, scanf() return an int value representing the number of input items successfully matched and assigned.

I was expecting 0x04 in the EAX register (user input = AAAA) but after returning from scanf(), EAX = 0x00000000:

       0x080483e4      55             push ebp
       0x080483e5      89e5           mov ebp, esp
       0x080483e7      83ec18         sub esp, 0x18
       0x080483ea      83e4f0         and esp, 0xfffffff0
       0x080483ed      b800000000     mov eax, 0
       0x080483f2      83c00f         add eax, 0xf
       0x080483f5      83c00f         add eax, 0xf
       0x080483f8      c1e804         shr eax, 4
       0x080483fb      c1e004         shl eax, 4
       0x080483fe      29c4           sub esp, eax
       0x08048400      c70424488504.  mov dword [esp], str.IOLI_Crackme_Level_0x02 ; [0x8048548:4]=0x494c4f49 ; "IOLI Crackme Level 0x02\n"
       0x08048407      e810ffffff     call sym.imp.printf         ; int printf(const char *format)
       0x0804840c      c70424618504.  mov dword [esp], str.Password: ; [0x8048561:4]=0x73736150 ; "Password: " ; const char * format
       0x08048413      e804ffffff     call sym.imp.printf         ; int printf(const char *format)
       0x08048418      8d45fc         lea eax, ebp - 4
       0x0804841b      89442404       mov dword [local_4h_2], eax
       0x0804841f      c704246c8504.  mov dword [esp], 0x804856c  ; [0x804856c:4]=0x50006425 ; const char * format
       ;-- eip:
       0x08048426 b    e8e1feffff     call sym.imp.scanf          ; int scanf(const char *format)
       0x0804842b      c745f85a0000.  mov dword [local_8h], 0x5a  ; 'Z' ; 90
       0x08048432      c745f4ec0100.  mov dword [local_ch], 0x1ec ; 492
       0x08048439      8b55f4         mov edx, dword [local_ch]
       0x0804843c      8d45f8         lea eax, ebp - 8
       0x0804843f      0110           add dword [eax], edx
       0x08048441      8b45f8         mov eax, dword [local_8h]
       0x08048444      0faf45f8       imul eax, dword [local_8h]
       0x08048448      8945f4         mov dword [local_ch], eax
       0x0804844b      8b45fc         mov eax, dword [local_4h]
       0x0804844e      3b45f4         cmp eax, dword [local_ch]
   ┌─< 0x08048451      750e           jne 0x8048461
   │   0x08048453      c704246f8504.  mov dword [esp], str.Password_OK_: ; [0x804856f:4]=0x73736150 ; "Password OK :)\n" ; const char * format
   │   0x0804845a      e8bdfeffff     call sym.imp.printf         ; int printf(const char *format)
  ┌──< 0x0804845f      eb0c           jmp 0x804846d
  │└─> 0x08048461      c704247f8504.  mov dword [esp], str.Invalid_Password ; [0x804857f:4]=0x61766e49 ; "Invalid Password!\n" ; const char * format
  │    0x08048468      e8affeffff     call sym.imp.printf         ; int printf(const char *format)
  │       ; JMP XREF from 0x0804845f (main)
  └──> 0x0804846d      b800000000     mov eax, 0
       0x08048472      c9             leave
       0x08048473      c3             ret

Also, I cannot find any reference to the user input (from the previous scanf() call). I think it's in local_4h because it's compared with the flag value (0x00052b24) stored in local_ch.

 var local_4h = 0xffa46fd4  0xf7f66000  ... @eax edi
 var local_8h = 0xffa46fd0  0x00000001  .... esi
 var local_ch = 0xffa46fcc  0x00000000  .... ecx

But, I cannot understand how.

For more info, this is the stack right before the scanf() call:

- offset -   0 1  2 3  4 5  6 7  8 9  A B  C D  E F  0123456789ABCDEF
0xffa46fb0  6c85 0408 d46f a4ff 0000 0000 fbb4 ddf7  l....o..........
0xffa46fc0  dc63 f6f7 f481 0408 0c9f 0408 0000 0000  .c..............
0xffa46fd0  0100 0000 0060 f6f7 0000 0000 5644 dcf7  .....`......VD..

And registers:

 eax = 0xffa46fd4
 ebx = 0x00000000
 ecx = 0x00000000
 edx = 0xf7f67870
 esi = 0x00000001
 edi = 0xf7f66000
 esp = 0xffa46fb0
 ebp = 0xffa46fd8
 eip = 0x08048426
 eflags = 0x00000286
 oeax = 0xffffffff
  • This "scanf return int value representing the total input chars from stdin" is most certainly not what that page says. It returns the successfully matched and assigned number of arguments. What is the format string for this scanf string? If it's something like "%d" then 0 is a correct result, with your input. – usr2564301 Jan 2 '18 at 23:44

According to man scanf

On success, these functions return the number of input items successfully matched and assigned; this can be fewer than provided for, or even zero, in the event of an early matching failure.

The value EOF is returned if the end of input is reached before either the first successful conversion or a matching failure occurs. EOF is also returned if a read error occurs, in which case the error indicator for the stream (see ferror(3)) is set, and errno is set to indicate the error.

Also during a function in x86 the stack looks something like this

► 0x80484f9 <main+62>    call   __isoc99_scanf@plt            <0x80483a0>
    format: 0x80485e0 ◂— 0x25006425 /* '%d' */
    vararg: 0xffffcfe8 —▸ 0xffffd0ac —▸ 0xffffd264 ◂— 0x5f474458 ('XDG_')
00:0000│ esp  0xffffcfc0 —▸ 0x80485e0 ◂— and    eax, 0x64250064 /* '%d' */
01:0004│      0xffffcfc4 —▸ 0xffffcfe8 —▸ 0xffffd0ac —▸ 0xffffd264 ◂— ...
02:0008│      0xffffcfc8 —▸ 0xf7f9f244 —▸ 0xf7e07020 (_IO_check_libio) ◂—  call   0xf7f0eb09

The top of the stack is the first parameter format followed by references to variables which will store the values matching with the format string. In your case mov dword [esp], 0x804856c kind of pushes format string to the stack top esp. Somewhere above this snippet you'd have mov dword [esp+4], stack_address_ref to add the variables which will be saving the values parsed.


Thanks to sudhackar comment i was able to understand scanf():

mov dword [esp], 0x804856c

pushes the format string on the stack:

:> px @ 0x804856c
- offset -   0 1  2 3  4 5  6 7  8 9  A B  C D  0123456789ABCD
0x0804856c  2564 0050 6173 7377 6f72 6420 4f4b  %d.Password OK
0x0804857a  203a 290a 0049 6e76 616c 6964 2050   :)..Invalid P
0x08048588  6173 7377 6f72 6421 0a00 0000 0000  assword!......

It's a %d so it references a decimal variable. After user input (in this case password was a number 23), local variable at ebp-0x04 contains its value:

:> afvd
var local_4h = 0xffe6cf34  0x00000017  ....
var local_8h = 0xffe6cf30  0x00000001  .... eax
var local_ch = 0xffe6cf2c  0x00000000  .... ecx



What differs from before is that previous password was AAAA, not a decimal number: scanf() was unable to match variables and returned nothing.

I have only a last small doubt: comparing disassembled code between radare2 and objdump I found a small difference but I think it's pretty important though:

from radare2:

   0x08048418      8d45fc         lea eax, ebp - 4
   0x0804841b      89442404       mov dword [local_4h_2], eax
   0x0804841f      c704246c8504.  mov dword [esp], 0x804856c  
   0x08048426 b    e8e1feffff     call sym.imp.scanf

from objdump:

   8048418: 8d 45 fc                lea    eax,[ebp-0x4]
   804841b: 89 44 24 04             mov    DWORD PTR [esp+0x4],eax
   804841f: c7 04 24 6c 85 04 08    mov    DWORD PTR [esp],0x804856c

Is there any reason for that difference in instruction at 0x08048418 ?

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.