1


According to this paper and a few stackoverflow posts, argc is at the top of the stack and argv is below it. I've tried about 3-4 different ways of doing it:

  • Popping it into an initialized variable (.data) - output done by calling printf.
  • Popping it into uninitialized space (.bss) - output done by calling sys_write()
  • A mixture of the above + tweaks.

I've been told that argc and argv aren't in the stack by someone on a forum, which I don't understand; how are other people doing it with similar code?

Here's an example of what I've attempted (3 days worth of knowledge - try not to giggle):

section .bss
        argc:   resd 1      ; alloc 4 bytes for popped value

section .text
        global _start


_start:
        pop   dword[argc]   ; pop argc, place in var
        mov   ebx,0x01      ; file descriptor = STDOUT
        mov   ecx,argc      ; var (addr) - points to buffer
        mov   edx,1         ; length of buffer (single digit)
        mov   eax,0x04      ; syscall number for sys_write()
        int   0x80          ; request the kernel to make syscall

exit:
        mov   ebx,0x00      ; arg for sys_exit() - sys_exit(0)
        mov   eax,0x01      ; syscall number for sys_exit()
        int   0x80          ; request the kernel to make syscall

Solution: section .data msg db Value: %d\n

section .text
        global main
        extern printf

main:
        push   dword[esp+4]
        push   msg
        call   printf
        add    esp,8

        mov    eax,0
        ret
user1807879
  • 151
  • 2
  • 8

1 Answers1

0

The process of getting argc looks ok to me (for a 32-bit Linux machine), although you're 4 bytes off since the top of the stack most likely contains the return address to the startup code that called main.
Also, the sys_write system call expects a pointer to a string in ecx. What you're giving it is a pointer to an integer, which isn't the same thing.
If you want to print the value of argc you'll have to convert it to a string first (or use the printf function).

Here's some example code (I'm using the GNU assembler since I don't have NASM on this machine):

format: .asciz "%d\n"
.text
.globl main
  .type main, @function
main:
  pushl 4(%esp)       # push argc
  pushl $format       # push the format string
  call printf
  addl $8,%esp        # pop the arguments

  movl  $0, %eax      # return value 
  ret
Michael
  • 57,169
  • 9
  • 80
  • 125
  • I actually did notice that I wasn't able to output integers using `sys_write`, so I ended up using `printf` for that along with the appropriate format (**%d**). No dice. Thanks for your input! – user1807879 Apr 16 '13 at 12:48
  • You've answered it, although I'm unsure how it actually works. Instead of the first pop, I replaced it with NASM's equivalent (`push dword[esp+4]`) - I don't understand what happens to the stack pointer, does it go to the next 4 bytes above? I hope you can answer this small question for me. Thank you, again! – user1807879 Apr 16 '13 at 13:37
  • It takes the second dword on the stack and pushes it onto the top of the stack. The reason for picking the second dword is that the top of the stack when entering `main` will contain the return address to wherever the call to `main` came from (e.g. `__libc_start_main`). So the first sentence in my original answer was slightly off. I've corrected that. – Michael Apr 16 '13 at 13:50