Entire code is:
#include <stdio.h>
#include <string.h>
#include <unistd.h>
char *secret = "1234";
void go_shell()
{
char *shell = "/bin/sh";
char *cmd[] = { "/bin/sh", 0};
printf("WOuld you like to play a game?\n");
setreuid(0, 0);
execve(shell, cmd, 0);
}
int authorize()
{
char password[64];
printf("Enter password: ");
gets(password);
if (!strcmp(password, secret))
return 1;
else
return 0;
}
int main()
{
if (authorize()) {
printf("Login successfully\n");
go_shell();
} else {
printf("Incorrect password\n");
}
return 0;
}
I want to see the $ebp when authorize() is just called.
Compiled with
gcc -Wall -ggdb <source_code> -o <exe>
Then I started gdb
gdb <exe>
(gdb) disass authorize
Dump of assembler code for function authorize:
0x000000000040076d <+0>: push %rbp
0x000000000040076e <+1>: mov %rsp,%rbp
0x0000000000400771 <+4>: sub $0x50,%rsp
0x0000000000400775 <+8>: mov %fs:0x28,%rax
0x000000000040077e <+17>: mov %rax,-0x8(%rbp)
0x0000000000400782 <+21>: xor %eax,%eax
0x0000000000400784 <+23>: mov $0x4008d8,%edi
0x0000000000400789 <+28>: mov $0x0,%eax
0x000000000040078e <+33>: callq 0x400590 <printf#plt>
0x0000000000400793 <+38>: lea -0x50(%rbp),%rax
0x0000000000400797 <+42>: mov %rax,%rdi
0x000000000040079a <+45>: mov $0x0,%eax
0x000000000040079f <+50>: callq 0x4005d0 <gets#plt>
0x00000000004007a4 <+55>: mov 0x2008bd(%rip),%rdx # 0x601068 <secret>
0x00000000004007ab <+62>: lea -0x50(%rbp),%rax
0x00000000004007af <+66>: mov %rdx,%rsi
0x00000000004007b2 <+69>: mov %rax,%rdi
0x00000000004007b5 <+72>: callq 0x4005c0 <strcmp#plt>
0x00000000004007ba <+77>: test %eax,%eax
0x00000000004007bc <+79>: jne 0x4007c5 <authorize+88>
0x00000000004007be <+81>: mov $0x1,%eax
0x00000000004007c3 <+86>: jmp 0x4007ca <authorize+93>
0x00000000004007c5 <+88>: mov $0x0,%eax
0x00000000004007ca <+93>: mov -0x8(%rbp),%rcx
0x00000000004007ce <+97>: xor %fs:0x28,%rcx
0x00000000004007d7 <+106>: je 0x4007de <authorize+113>
0x00000000004007d9 <+108>: callq 0x400580 <__stack_chk_fail#plt>
0x00000000004007de <+113>: leaveq
0x00000000004007df <+114>: retq
End of assembler dump.
(gdb) br *authorize+33
Breakpoint 1 at 0x40078e: file simple_login.c, line 19.
(gdb) run
Starting program: ./a.out
Breakpoint 1, 0x000000000040078e in authorize () at simple_login.c:19
19 printf("Enter password: ");
(gdb) where
#0 0x000000000040078e in authorize () at simple_login.c:19
#1 0x00000000004007ee in main () at simple_login.c:29
(gdb) x/2x $ebp
0xffffffffffffe4a0: Cannot access memory at address 0xffffffffffffe4a0
On ubuntu64 bit, Linux version 4.8.0-44-generic (buildd#xxxx) (gcc version 5.4.0 20160609 (Ubuntu 5.4.0-6ubuntu1~16.04.4) ) #47~16.04.1-Ubuntu SMP
Thanks in advance.
Dump of assembler code for function authorize:
0x000000000040076d <+0>: push %rbp
This is a 64-bit build. You should use x/2x $rbp instead.
Related
(gdb) run `python -c "print('A'*524+'\x55\x61\x55\x56')"`
Starting program: /home/xxx/Documents/ethical_hacking/buffer_overflow/simplebuffer `python -c "print('A'*524+'\x55\x61\x55\x56')"`
Off to 0x56556155
Program received signal SIGSEGV, Segmentation fault.
0x56556155 in register_tm_clones ()
(gdb) run `python -c "print('A'*524+'\xcd\x61\x55\x56')"`
Starting program: /home/nepalidai/Documents/ethical_hacking/buffer_overflow/simplebuffer `python -c "print('A'*524+'\xcd\x61\x55\x56')"`
Off to 0x55618dc3
Program received signal SIGSEGV, Segmentation fault.
0x55618dc3 in ?? ()
When I include \x55\x61\x55\x56 in my payload, I get the segmentation fault at 0x56556155, but when I include \xcd\x61\x55\x56 in my payload, I get the segmentation fault at 0x55618dc3.
I was thinking \xcd\x61\x55\x56 would give seg. fault at 0x565561cd.
I can only reproduce this when I use gdb in Arch Linux. In Kali linux this works as intended and I was successfully able to run a function by overwriting EBP, but not in Arch linux.
another example of payload that doesn't work:
(gdb) run `python -c "print('A'*524+'\xaa\x61\x55\x56')"`
Starting program: /home/nepalidai/Documents/ethical_hacking/buffer_overflow/simplebuffer `python -c "print('A'*524+'\xaa\x61\x55\x56')"`
Off to 0x5561aac2
Program received signal SIGSEGV, Segmentation fault.
0x5561aac2 in ?? ()
source code:
#include <stdio.h>
#include <string.h>
int BUFFER=500;
void win(void){
/*Win Condition
We Want to jump here
*/
printf("\n ===== Win ===== \n\n");
}
void lose(void){
/* Lose Condition */
printf("Current Memory Address is %p\n",lose);
printf("Aim for %p\n", win);
printf("Lose :(\n");
}
int main(int argc, char* argv[]){
/* Main Function*/
//Pointer to the lose function
void (*fp)(void) = lose;
char buffer[BUFFER];
if (argc != 2){
printf("Overflow the buffer\n");
printf("Hint! Try `python -c \"print 'A'*100\"`\n");
return -1;
}
memcpy(buffer, argv[1], strlen(argv[1]));
printf("Off to %p\n",fp);
fp();
return 0;
}
disassembly:
(gdb) disassemble main
Dump of assembler code for function main:
0x56556254 <+0>: lea ecx,[esp+0x4]
0x56556258 <+4>: and esp,0xfffffff0
0x5655625b <+7>: push DWORD PTR [ecx-0x4]
0x5655625e <+10>: push ebp
0x5655625f <+11>: mov ebp,esp
0x56556261 <+13>: push edi
0x56556262 <+14>: push esi
0x56556263 <+15>: push ebx
0x56556264 <+16>: push ecx
0x56556265 <+17>: sub esp,0x18
0x56556268 <+20>: call 0x565560d0 <__x86.get_pc_thunk.bx>
0x5655626d <+25>: add ebx,0x2d93
0x56556273 <+31>: mov esi,ecx
0x56556275 <+33>: mov eax,esp
0x56556277 <+35>: mov edi,eax
0x56556279 <+37>: lea eax,[ebx-0x2e08]
0x5655627f <+43>: mov DWORD PTR [ebp-0x1c],eax
0x56556282 <+46>: mov eax,DWORD PTR [ebx+0x28]
0x56556288 <+52>: lea edx,[eax-0x1]
0x5655628b <+55>: mov DWORD PTR [ebp-0x20],edx
0x5655628e <+58>: mov edx,eax
0x56556290 <+60>: mov eax,0x10
0x56556295 <+65>: sub eax,0x1
0x56556298 <+68>: add eax,edx
0x5655629a <+70>: mov ecx,0x10
0x5655629f <+75>: mov edx,0x0
0x565562a4 <+80>: div ecx
0x565562a6 <+82>: imul eax,eax,0x10
0x565562a9 <+85>: sub esp,eax
0x565562ab <+87>: mov eax,esp
0x565562ad <+89>: add eax,0x0
0x565562b0 <+92>: mov DWORD PTR [ebp-0x24],eax
0x565562b3 <+95>: cmp DWORD PTR [esi],0x2
0x565562b6 <+98>: je 0x565562e3 <main+143>
0x565562b8 <+100>: sub esp,0xc
0x565562bb <+103>: lea eax,[ebx-0x1fb2]
0x565562c1 <+109>: push eax
0x565562c2 <+110>: call 0x56556060 <puts#plt>
0x565562c7 <+115>: add esp,0x10
0x565562ca <+118>: sub esp,0xc
0x565562cd <+121>: lea eax,[ebx-0x1f9c]
0x565562d3 <+127>: push eax
0x565562d4 <+128>: call 0x56556060 <puts#plt>
0x565562d9 <+133>: add esp,0x10
0x565562dc <+136>: mov eax,0xffffffff
0x565562e1 <+141>: jmp 0x5655632e <main+218>
0x565562e3 <+143>: mov eax,DWORD PTR [esi+0x4]
0x565562e6 <+146>: add eax,0x4
0x565562e9 <+149>: mov eax,DWORD PTR [eax]
0x565562eb <+151>: sub esp,0xc
0x565562ee <+154>: push eax
0x565562ef <+155>: call 0x56556070 <strlen#plt>
0x565562f4 <+160>: add esp,0x10
0x565562f7 <+163>: mov edx,DWORD PTR [esi+0x4]
0x565562fa <+166>: add edx,0x4
0x565562fd <+169>: mov edx,DWORD PTR [edx]
0x565562ff <+171>: sub esp,0x4
0x56556302 <+174>: push eax
0x56556303 <+175>: push edx
0x56556304 <+176>: push DWORD PTR [ebp-0x24]
0x56556307 <+179>: call 0x56556050 <memcpy#plt>
0x5655630c <+184>: add esp,0x10
0x5655630f <+187>: sub esp,0x8
0x56556312 <+190>: push DWORD PTR [ebp-0x1c]
0x56556315 <+193>: lea eax,[ebx-0x1f76]
0x5655631b <+199>: push eax
0x5655631c <+200>: call 0x56556040 <printf#plt>
0x56556321 <+205>: add esp,0x10
0x56556324 <+208>: mov eax,DWORD PTR [ebp-0x1c]
0x56556327 <+211>: call eax
0x56556329 <+213>: mov eax,0x0
0x5655632e <+218>: mov esp,edi
0x56556330 <+220>: lea esp,[ebp-0x10]
0x56556333 <+223>: pop ecx
0x56556334 <+224>: pop ebx
0x56556335 <+225>: pop esi
0x56556336 <+226>: pop edi
0x56556337 <+227>: pop ebp
0x56556338 <+228>: lea esp,[ecx-0x4]
0x5655633b <+231>: ret
End of assembler dump.
(gdb) disassemble lose
Dump of assembler code for function win:
0x565561cd <+0>: push ebp
0x565561ce <+1>: mov ebp,esp
0x565561d0 <+3>: push ebx
0x565561d1 <+4>: sub esp,0x4
0x565561d4 <+7>: call 0x5655633c <__x86.get_pc_thunk.ax>
0x565561d9 <+12>: add eax,0x2e27
0x565561de <+17>: sub esp,0xc
0x565561e1 <+20>: lea edx,[eax-0x1ff8]
0x565561e7 <+26>: push edx
0x565561e8 <+27>: mov ebx,eax
0x565561ea <+29>: call 0x56556060 <puts#plt>
0x565561ef <+34>: add esp,0x10
0x565561f2 <+37>: nop
0x565561f3 <+38>: mov ebx,DWORD PTR [ebp-0x4]
0x565561f6 <+41>: leave
0x565561f7 <+42>: ret
End of assembler dump.
(gdb) disassemble lose
Dump of assembler code for function lose:
0x565561f8 <+0>: push ebp
0x565561f9 <+1>: mov ebp,esp
0x565561fb <+3>: push ebx
0x565561fc <+4>: sub esp,0x4
0x565561ff <+7>: call 0x565560d0 <__x86.get_pc_thunk.bx>
0x56556204 <+12>: add ebx,0x2dfc
0x5655620a <+18>: sub esp,0x8
0x5655620d <+21>: lea eax,[ebx-0x2e08]
0x56556213 <+27>: push eax
0x56556214 <+28>: lea eax,[ebx-0x1fe4]
0x5655621a <+34>: push eax
0x5655621b <+35>: call 0x56556040 <printf#plt>
0x56556220 <+40>: add esp,0x10
0x56556223 <+43>: sub esp,0x8
0x56556226 <+46>: lea eax,[ebx-0x2e33]
0x5655622c <+52>: push eax
0x5655622d <+53>: lea eax,[ebx-0x1fc6]
0x56556233 <+59>: push eax
0x56556234 <+60>: call 0x56556040 <printf#plt>
0x56556239 <+65>: add esp,0x10
0x5655623c <+68>: sub esp,0xc
0x5655623f <+71>: lea eax,[ebx-0x1fba]
0x56556245 <+77>: push eax
0x56556246 <+78>: call 0x56556060 <puts#plt>
0x5655624b <+83>: add esp,0x10
0x5655624e <+86>: nop
0x5655624f <+87>: mov ebx,DWORD PTR [ebp-0x4]
0x56556252 <+90>: leave
0x56556253 <+91>: ret
End of assembler dump.
What am I doing wrong? I am very new to assembly language and bufferoverflow, please go easy on me.
#include<stdio.h>
#include<string.h>
int main(int argc, char ** argv)
{
char buffer[500];
strcpy(buffer, argv[1]);
return 0;
}
I can compiling this program using gcc -m32 -fno-stack-protector -z execstack -fno-pie -no-pie -g -o vuln vuln.c
On disassembling the main function using the debugger, I am getting this as the output:
Dump of assembler code for function main:
0x0804840b <+0>: lea 0x4(%esp),%ecx
0x0804840f <+4>: and $0xfffffff0,%esp
0x08048412 <+7>: pushl -0x4(%ecx)
0x08048415 <+10>: push %ebp
0x08048416 <+11>: mov %esp,%ebp
0x08048418 <+13>: push %ecx
0x08048419 <+14>: sub $0x204,%esp
0x0804841f <+20>: mov %ecx,%eax
0x08048421 <+22>: mov 0x4(%eax),%eax
0x08048424 <+25>: add $0x4,%eax
0x08048427 <+28>: mov (%eax),%eax
0x08048429 <+30>: sub $0x8,%esp
0x0804842c <+33>: push %eax
0x0804842d <+34>: lea -0x1fc(%ebp),%eax
0x08048433 <+40>: push %eax
0x08048434 <+41>: call 0x80482e0 <strcpy#plt>
0x08048439 <+46>: add $0x10,%esp
0x0804843c <+49>: mov $0x0,%eax
0x08048441 <+54>: mov -0x4(%ebp),%ecx
0x08048444 <+57>: leave
0x08048445 <+58>: lea -0x4(%ecx),%esp
0x08048448 <+61>: ret
End of assembler dump.
GCC version : 6.5.0
OS : Ubuntu 16.04
GDB version : 7.11.1
The tutorial which I was refering was showed this assembly code :
Dump of assembler code for function main:
0x080483fb <+0>: push %ebp
0x080483fc <+1>: mov %esp,%ebp
0x080483fe <+3>: sub $0x1f4,%esp
0x08048404 <+9>: mov 0xc(%ebp),%eax
0x08048407 <+12>: add $0x4,%eax
0x0804840a <+15>: mov (%eax),%eax
0x0804840c <+17>: push %eax
0x0804840d <+18>: lea -0x1f4(%ebp),%eax
0x08048413 <+24>: push %eax
0x08048414 <+25>: call 0x80482d0 <strcpy#plt>
0x08048419 <+30>: add $0x8,%esp
0x0804841c <+33>: mov $0x0,%eax
0x08048421 <+38>: leave
0x08048422 <+39>: ret
End of assembler dump.
I have the following questions:
How can I get the exact same assembly code dump mentioned in the tutorial?
The difference in the output seems because of ecx register. What does that register do and why is it not part of tutorial's assembly code ?
In main function, I constructed buffer array of size 500 which is 1f4 in hexadecimal, that's why the assembly code of the tutorial is subtracting 1f4 from esp register, but my assembly code is subtracting 204 which is 516 in decimal. I am not able to understand this.
Edit: As noted in the comments, If I add -mpreferred-stack-boundary=2 to the compiler flags, then I get the same assembly code as the tutorial. Why?
I have binary Phase that is not returning required result i.e 12. Any suggestions?
Phase 4
Dump of assembler code for function phase_4:
0x000000000040100b <+0>: sub $0x18,%rsp
0x000000000040100f <+4>: lea 0x8(%rsp),%rcx
0x0000000000401014 <+9>: lea 0xc(%rsp),%rdx
0x0000000000401019 <+14>: mov $0x40278d,%esi
0x000000000040101e <+19>: mov $0x0,%eax
0x0000000000401023 <+24>: callq 0x400b90 <__isoc99_sscanf#plt>
0x0000000000401028 <+29>: cmp $0x2,%eax
=> 0x000000000040102b <+32>: je 0x401054 <phase_4+73>
0x000000000040102d <+34>: callq 0x401538 <explode_bomb>
0x0000000000401032 <+39>: mov $0xe,%edx
0x0000000000401037 <+44>: mov $0x0,%esi
0x000000000040103c <+49>: mov 0xc(%rsp),%edi
0x0000000000401040 <+53>: callq 0x400fd7 <func4>
0x0000000000401045 <+58>: cmp $0x12,%eax
0x0000000000401048 <+61>: je 0x40105d <phase_4+82>
0x000000000040104a <+63>: callq 0x401538 <explode_bomb>
0x000000000040104f <+68>: add $0x18,%rsp
0x0000000000401053 <+72>: retq
0x0000000000401054 <+73>: cmpl $0xe,0xc(%rsp)
0x0000000000401059 <+78>: jbe 0x401032 <phase_4+39>
0x000000000040105b <+80>: jmp 0x40102d <phase_4+34>
0x000000000040105d <+82>: cmpl $0x12,0x8(%rsp)
0x0000000000401062 <+87>: jne 0x40104a <phase_4+63>
0x0000000000401064 <+89>: jmp 0x40104f <phase_4+68>
End of assembler dump.
func4 is as follows:
Dump of assembler code for function func4:
=> 0x0000000000400fd7 <+0>: push %rbx
0x0000000000400fd8 <+1>: mov %edx,%eax
0x0000000000400fda <+3>: sub %esi,%eax
0x0000000000400fdc <+5>: mov %eax,%ebx
0x0000000000400fde <+7>: shr $0x1f,%ebx
0x0000000000400fe1 <+10>: add %eax,%ebx
0x0000000000400fe3 <+12>: sar %ebx
0x0000000000400fe5 <+14>: add %esi,%ebx
0x0000000000400fe7 <+16>: cmp %edi,%ebx
0x0000000000400fe9 <+18>: jg 0x400ff3 <func4+28>
0x0000000000400feb <+20>: cmp %edi,%ebx
0x0000000000400fed <+22>: jl 0x400fff <func4+40>
0x0000000000400fef <+24>: mov %ebx,%eax
0x0000000000400ff1 <+26>: pop %rbx
0x0000000000400ff2 <+27>: retq
0x0000000000400ff3 <+28>: lea -0x1(%rbx),%edx
0x0000000000400ff6 <+31>: callq 0x400fd7 <func4>
0x0000000000400ffb <+36>: add %eax,%ebx
0x0000000000400ffd <+38>: jmp 0x400fef <func4+24>
0x0000000000400fff <+40>: lea 0x1(%rbx),%esi
0x0000000000401002 <+43>: callq 0x400fd7 <func4>
0x0000000000401007 <+48>: add %eax,%ebx
0x0000000000401009 <+50>: jmp 0x400fef <func4+24>
End of assembler dump.
I have written a test C program that I believe equivalent to above assembly code for func4.
#include <stdio.h>
int main()
{
int i=0;
for(int i=0;i<15;i++)
{
int z=func4(i,0,14);
printf("in main program: For input %d -> %d\n",i,z);
}
return 0;
}
int func4(int x, int low, int high) {
int mid = (low + high) / 2;
if (x == mid) {
return (mid);
} else if (x < mid) {
int w=mid+func4(x, low, mid - 1);
return w;
} else {
int p=mid+func4(x, mid + 1, high);
return p;
}
}
This program returns OUTPUT as follows:
in main program: For input 0 -> 11
in main program: For input 1 -> 11
in main program: For input 2 -> 13
in main program: For input 3 -> 10
in main program: For input 4 -> 19
in main program: For input 5 -> 15
in main program: For input 6 -> 21
in main program: For input 7 -> 7
in main program: For input 8 -> 35
in main program: For input 9 -> 27
in main program: For input 10 -> 37
in main program: For input 11 -> 18
in main program: For input 12 -> 43
in main program: For input 13 -> 31
in main program: For input 14 -> 45
I figured out that function will take two arguments and the second argument should be 12. But I am not to get value 12 returned from func4.
Any suggestions??
The assembly code is actually expecting a value of 0x12 (18 rather than 12) from func4:
0x0000000000401040 <+53>: callq 0x400fd7 <func4>
0x0000000000401045 <+58>: cmp $0x12,%eax <- Compare result to 0x12
0x0000000000401048 <+61>: je 0x40105d <phase_4+82>
0x000000000040104a <+63>: callq 0x401538 <explode_bomb>
I haven't looked at your C translation of func4 for correctness, but assuming it's correct it looks like func4(11, 0, 14) gives you what you want.
I just got started with buffer overflows and when I look for tutorials everyone has printf#plt and gets#plt in their assembler code, but I don't see them. Am I doing something wrong?
Source code:
#include <stdio.h>
#include <string.h>
int main()
{
char password[16];
int passcheck = 0;
void secret();
printf("\nWhat's the password?\n");
gets(password);
if (strcmp(password, "password1"))
{
printf("\nYou fail/n");
}
else
{
printf("\nCorrect password\n");
passcheck = 1;
}
if(passcheck)
{
secret();
}
return 0;
}
void secret()
{
printf("\nYou got it!!!\n");
}
assembler code:
0x00001e50 <+0>: push %ebp
0x00001e51 <+1>: mov %esp,%ebp
0x00001e53 <+3>: push %edi
0x00001e54 <+4>: push %esi
0x00001e55 <+5>: sub $0x40,%esp
0x00001e58 <+8>: call 0x1e5d <main+13>
0x00001e5d <+13>: pop %eax
0x00001e5e <+14>: lea 0x101(%eax),%ecx
0x00001e64 <+20>: movl $0x0,-0xc(%ebp)
0x00001e6b <+27>: movl $0x0,-0x20(%ebp)
0x00001e72 <+34>: mov %ecx,(%esp)
0x00001e75 <+37>: mov %eax,-0x24(%ebp)
0x00001e78 <+40>: call 0x1f28
0x00001e7d <+45>: lea -0x1c(%ebp),%ecx
0x00001e80 <+48>: mov %ecx,(%esp)
0x00001e83 <+51>: mov %eax,-0x28(%ebp)
0x00001e86 <+54>: call 0x1f22
0x00001e8b <+59>: lea -0x1c(%ebp),%ecx
0x00001e8e <+62>: mov -0x24(%ebp),%edx
0x00001e91 <+65>: lea 0x118(%edx),%esi
0x00001e97 <+71>: mov %esp,%edi
0x00001e99 <+73>: mov %esi,0x4(%edi)
0x00001e9c <+76>: mov %ecx,(%edi)
0x00001e9e <+78>: mov %eax,-0x2c(%ebp)
0x00001ea1 <+81>: call 0x1f2e
0x00001ea6 <+86>: cmp $0x0,%eax
0x00001ea9 <+89>: je 0x1ec8 <main+120>
0x00001eaf <+95>: mov -0x24(%ebp),%eax
0x00001eb2 <+98>: lea 0x122(%eax),%ecx
0x00001eb8 <+104>: mov %ecx,(%esp)
0x00001ebb <+107>: call 0x1f28
0x00001ec0 <+112>: mov %eax,-0x30(%ebp)
0x00001ec3 <+115>: jmp 0x1ee3 <main+147>
0x00001ec8 <+120>: mov -0x24(%ebp),%eax
0x00001ecb <+123>: lea 0x12e(%eax),%ecx
0x00001ed1 <+129>: mov %ecx,(%esp)
0x00001ed4 <+132>: call 0x1f28
0x00001ed9 <+137>: movl $0x1,-0x20(%ebp)
0x00001ee0 <+144>: mov %eax,-0x34(%ebp)
0x00001ee3 <+147>: cmpl $0x0,-0x20(%ebp)
0x00001ee7 <+151>: je 0x1ef2 <main+162>
0x00001eed <+157>: call 0x1f00 <secret>
0x00001ef2 <+162>: xor %eax,%eax
0x00001ef4 <+164>: add $0x40,%esp
0x00001ef7 <+167>: pop %esi
0x00001ef8 <+168>: pop %edi
0x00001ef9 <+169>: pop %ebp
0x00001efa <+170>: ret
0x00001efb <+171>: nopl 0x0(%eax,%eax,1)
Add debug symbols to your binaries by compiling your C program with appropriate switch for your C compiler. For example if you use gcc, use -g switch as is described here:. After that you will be able to see original C symbols names when executing your binary under gdb
Regarding your comment - maybe your object files weren't recompiled from scratch. Try to make clean if you use makefiles or just delete all the object (.o) files and then recompile your program with -ggdb switch (it is the same as -g switch but generates debug info specifically for gdb). After recompiling look in your binary for debug infor - couple of strings like 'printf#plt' and 'gets#plt'.
I'm looking at how the memory is laid out on the stack, but I don't understand why it looks like there are 12 bytes worth of space for storing each of the variables. Here is a simple C program that prints out the location of various variables:
#include <stdio.h>
#include <stdlib.h>
int test (long p1, long p2){
int l1 = 9999;
int l2 = 99993333;
printf("%p p1\n", &p1);
printf("%p p2\n", &p2);
printf("%p l1\n", &l1);
printf("%p l1\n", &l2);
}
int main(int argc, const char** argv)
{
register void* stack asm("esp");
int x = 22;
int y = 1000;
printf("%p stack\n", stack);
printf("%p argv\n", &argv);
printf("%p argc\n", &argc);
printf("%p l1\n", &x);
printf("%p l2\n", &y);
test(1, 888);
return 0;
}
When run, here is the output:
~/gc$ ./a.out
0x7fff5496b200 stack
0x7fff5496b200 argv
0x7fff5496b20c argc
0x7fff5496b218 l1
0x7fff5496b21c l2
0x7fff5496b1d8 p1
0x7fff5496b1d0 p2
0x7fff5496b1e8 l1
0x7fff5496b1ec l1
Why is there 12 space between the address of argv and argc, and 12 space between l1 and l2? I expected 8 for the longs and pointers, and for the int parameter of main, I would understand either 4 or 8 characters, but I don't see any reason it should be 12.
Someone mentioned that the assembly code would be useful, so I got that as well:
Dump of assembler code for function main:
0x0000000000400614 <+0>: push %rbp
0x0000000000400615 <+1>: mov %rsp,%rbp
0x0000000000400618 <+4>: sub $0x20,%rsp
0x000000000040061c <+8>: mov %edi,-0x14(%rbp)
0x000000000040061f <+11>: mov %rsi,-0x20(%rbp)
0x0000000000400623 <+15>: movl $0x16,-0x8(%rbp)
0x000000000040062a <+22>: movl $0x3e8,-0x4(%rbp)
0x0000000000400631 <+29>: mov %rsp,%rax
0x0000000000400634 <+32>: mov %rax,%rsi
0x0000000000400637 <+35>: mov $0x40079c,%edi
0x000000000040063c <+40>: mov $0x0,%eax
0x0000000000400641 <+45>: callq 0x400410 <printf#plt>
0x0000000000400646 <+50>: lea -0x20(%rbp),%rax
0x000000000040064a <+54>: mov %rax,%rsi
0x000000000040064d <+57>: mov $0x4007a6,%edi
0x0000000000400652 <+62>: mov $0x0,%eax
0x0000000000400657 <+67>: callq 0x400410 <printf#plt>
0x000000000040065c <+72>: lea -0x14(%rbp),%rax
0x0000000000400660 <+76>: mov %rax,%rsi
0x0000000000400663 <+79>: mov $0x4007af,%edi
0x0000000000400668 <+84>: mov $0x0,%eax
0x000000000040066d <+89>: callq 0x400410 <printf#plt>
0x0000000000400672 <+94>: lea -0x8(%rbp),%rax
0x0000000000400676 <+98>: mov %rax,%rsi
0x0000000000400679 <+101>: mov $0x400780,%edi
0x000000000040067e <+106>: mov $0x0,%eax
0x0000000000400683 <+111>: callq 0x400410 <printf#plt>
0x0000000000400688 <+116>: lea -0x4(%rbp),%rax
0x000000000040068c <+120>: mov %rax,%rsi
0x000000000040068f <+123>: mov $0x400787,%edi
0x0000000000400694 <+128>: mov $0x0,%eax
0x0000000000400699 <+133>: callq 0x400410 <printf#plt>
0x000000000040069e <+138>: mov $0x14d,%ecx
0x00000000004006a3 <+143>: mov $0x1589e,%edx
0x00000000004006a8 <+148>: mov $0x378,%esi
0x00000000004006ad <+153>: mov $0x1,%edi
0x00000000004006b2 <+158>: callq 0x40052c <test>
0x00000000004006b7 <+163>: mov $0x0,%eax
0x00000000004006bc <+168>: leaveq
0x00000000004006bd <+169>: retq
End of assembler dump.
(gdb) disassemble test
Dump of assembler code for function test:
0x000000000040052c <+0>: push %rbp
0x000000000040052d <+1>: mov %rsp,%rbp
0x0000000000400530 <+4>: sub $0x40,%rsp
0x0000000000400534 <+8>: mov %rdi,-0x28(%rbp)
0x0000000000400538 <+12>: mov %rsi,-0x30(%rbp)
0x000000000040053c <+16>: mov %rdx,-0x38(%rbp)
0x0000000000400540 <+20>: mov %rcx,-0x40(%rbp)
0x0000000000400544 <+24>: movl $0x270f,-0x18(%rbp)
0x000000000040054b <+31>: movq $0x5f5c6f5,-0x10(%rbp)
0x0000000000400553 <+39>: movl $0x63,-0x14(%rbp)
0x000000000040055a <+46>: movq $0x371,-0x8(%rbp)
0x0000000000400562 <+54>: lea -0x28(%rbp),%rax
0x0000000000400566 <+58>: mov %rax,%rsi
0x0000000000400569 <+61>: mov $0x400764,%edi
0x000000000040056e <+66>: mov $0x0,%eax
0x0000000000400573 <+71>: callq 0x400410 <printf#plt>
0x0000000000400578 <+76>: lea -0x30(%rbp),%rax
0x000000000040057c <+80>: mov %rax,%rsi
0x000000000040057f <+83>: mov $0x40076b,%edi
0x0000000000400584 <+88>: mov $0x0,%eax
0x0000000000400589 <+93>: callq 0x400410 <printf#plt>
0x000000000040058e <+98>: lea -0x38(%rbp),%rax
0x0000000000400592 <+102>: mov %rax,%rsi
0x0000000000400595 <+105>: mov $0x400772,%edi
0x000000000040059a <+110>: mov $0x0,%eax
0x000000000040059f <+115>: callq 0x400410 <printf#plt>
0x00000000004005a4 <+120>: lea -0x40(%rbp),%rax
0x00000000004005a8 <+124>: mov %rax,%rsi
0x00000000004005ab <+127>: mov $0x400779,%edi
0x00000000004005b0 <+132>: mov $0x0,%eax
0x00000000004005b5 <+137>: callq 0x400410 <printf#plt>
0x00000000004005ba <+142>: lea -0x18(%rbp),%rax
0x00000000004005be <+146>: mov %rax,%rsi
0x00000000004005c1 <+149>: mov $0x400780,%edi
0x00000000004005c6 <+154>: mov $0x0,%eax
0x00000000004005cb <+159>: callq 0x400410 <printf#plt>
0x00000000004005d0 <+164>: lea -0x10(%rbp),%rax
0x00000000004005d4 <+168>: mov %rax,%rsi
0x00000000004005d7 <+171>: mov $0x400787,%edi
0x00000000004005dc <+176>: mov $0x0,%eax
0x00000000004005e1 <+181>: callq 0x400410 <printf#plt>
0x00000000004005e6 <+186>: lea -0x14(%rbp),%rax
0x00000000004005ea <+190>: mov %rax,%rsi
0x00000000004005ed <+193>: mov $0x40078e,%edi
0x00000000004005f2 <+198>: mov $0x0,%eax
0x00000000004005f7 <+203>: callq 0x400410 <printf#plt>
0x00000000004005fc <+208>: lea -0x8(%rbp),%rax
0x0000000000400600 <+212>: mov %rax,%rsi
0x0000000000400603 <+215>: mov $0x400795,%edi
0x0000000000400608 <+220>: mov $0x0,%eax
0x000000000040060d <+225>: callq 0x400410 <printf#plt>
0x0000000000400612 <+230>: leaveq
0x0000000000400613 <+231>: retq
End of assembler dump.
You are using a 64-bit system (based on the size of the pointers printed), which means you're probably using x86-64.
Certain arguments to functions in the x86-64 ABI do not have addresses because they are passed in registers. However, according to the C standard, you are allowed to take their addresses. So, when you write &argc, the compiler reserves space for it on the stack and returns that address.
So it is just another local variable. The compiler is free to put argc anywhere on the stack. This behavior is not mandatory, it's just the way that your compiler works.
As for the reason why 12 happens coincidentally on this particular occasion to be the spacing, remember that the stack grows downwards on x86-64. So if you push argc onto the stack the stack pointer will go down 4 bytes, and if you push argv onto the stack it will first go down another 4 bytes to be aligned correctly, then it will go down 8 bytes after argv is pushed. Of course the compiler is free to do other things, like put argv and argc in arbitrary other locations on the stack.
Demonstration
C code:
void otherfunc(int *ptr);
int func(int value)
{
otherfunc(&value);
return 0;
}
Assembly code:
func:
subq $24, %rsp ; Allocate 24 bytes on the stack
movl %edi, 12(%rsp) ; Store 'value' on the stack
leaq 12(%rsp), %rdi ; Calculate the address of 'value'
call otherfunc ; Call 'otherfunc'
xorl %eax, %eax ; Return value 0
addq $24, %rsp ; Deallocate stack
ret ; Return
Remember that %rsp is the stack pointer, %edi / %rdi is the first parameter to a function, and %eax is the return value of a function.