Reputation: 31
I've been banging my head for days trying to figure this out, finally posting here for some help. This exercise is purely academic for me, but it's come to a point where I simply need to understand why this doesn't work or what I'm doing wrong.
section .text
global _start
_start:
pop eax
pop ebx
pop ecx
_exit:
mov eax, 1
mov ebx, 0
int 0x80
Compiling/linking with:
$ nasm -f elf -o test.o test.asm
$ gcc -o test test.o
Running it in gdb with argument of "5":
$ gdb test
...
(gdb) b _exit
Breakpoint 1 at 0x8048063
(gdb) r 5
Starting program: /home/rich/asm/test 5
Breakpoint 1, 0x08048063 in _exit ()
(gdb) i r
eax 0x2 2
ebx 0xbffff8b0 -1073743696
ecx 0xbffff8c8 -1073743672
edx 0x0 0
esp 0xbffff78c 0xbffff78c
ebp 0x0 0x0
...
So eax
makes sense here - it's 0x2, or 2, argc. My question is: how do I get the value "5" (or 0x5) into a register? As I understand it, ecx
is a pointer to my value 5, so how do I "dereference" it into a usable digit, i.e. one that I can do arithmetic things to?
Upvotes: 3
Views: 2092
Reputation: 620
I realise this may be a little late and you may have already worked this out or moved on to something else, but I came across this question while googling something related and figured I could help out for anyone else that comes across this.
The problem I think you are facing here is that the "5" you are passing to your program is not then stored as an integer 5 like one might assume. The argument is passed to your program as a char, and so as Andy pointed out you would have a pointer to a byte containing 0x35 - which is the integer value that represents an ASCII character 5 - rather than a pointer to an integer value 5.
To use your argument as an integer, you would need to convert the byte to its integer equivalent as defined by the ASCII table - otherwise you will find that you pass in the char 5 but any math you attempt to do with this will be using 53 (0x35) because that represents a 5 in ASCII.
You can find an example of how to perform that conversion in the rsi_to_bin function of the example asm program here . Once you have converted the ascii code to its actual integer equivalent you will have the correct number you passed in, and will be able to perform whatever arithmetic you wanted with it. An extremely simple example would be to just subtract 48 from the input - this would work assuming you only passed in a single integer of value 0-9.
Upvotes: 1
Reputation: 12033
What do you want to do with it? Your understanding is right: the kernel pushes the argc count on the top of the stack, underneath which is argv[0] ... argv[argc-1] in reverse order (i.e. top of the stack / lowest memory address holds the first argument). You can check this with gdb on any binary on the system:
$ echo "int main(){return 0;}" > test.c
$ gcc test.c
$ gdb ./a.out
(gdb) b _start
(gdb) r A B C D E
(gdb) p ((void**)$rsp)[0]
$2 = (void *) 0x6
(gdb) p (char*)((void**)$rsp)[1]
$4 = 0x7fffffffeab7 "/home/andy/a.out"
(gdb) p (char*)((void**)$rsp)[2]
$5 = 0x7fffffffeac8 "A"
(gdb) p (char*)((void**)$rsp)[3]
$6 = 0x7fffffffeaca "B"
(gdb) p (char*)((void**)$rsp)[4]
$7 = 0x7fffffffeacc "C"
(gdb) p (char*)((void**)$rsp)[5]
$8 = 0x7fffffffeace "D"
(gdb) p (char*)((void**)$rsp)[6]
$9 = 0x7fffffffead0 "E"
Are you maybe asking how to parse the strings? That's a more involved question.
Upvotes: 3