So I have the following code
(gdb) list
#include<stdio.h>
#include<string.h>
int main()
{
char str_a[20];
strcpy(str_a,"Hello World!\n");
printf(str_a);
}
But when I disassemble it with gdb, strcpy isn't referenced. Instead the inside of the function strcpy is shown.
(gdb) disassemble main
Dump of assembler code for function main:
0x00000000004004fd <+0>: push rbp
0x00000000004004fe <+1>: mov rbp,rsp
0x0000000000400501 <+4>: sub rsp,0x20
0x0000000000400505 <+8>: lea rax,[rbp-0x20]
0x0000000000400509 <+12>: movabs rdx,0x6f57206f6c6c6548
0x0000000000400513 <+22>: mov QWORD PTR [rax],rdx
0x0000000000400516 <+25>: mov DWORD PTR [rax+0x8],0x21646c72
0x000000000040051d <+32>: mov WORD PTR [rax+0xc],0xa
0x0000000000400523 <+38>: lea rax,[rbp-0x20]
0x0000000000400527 <+42>: mov rdi,rax
0x000000000040052a <+45>: mov eax,0x0
0x000000000040052f <+50>: call 0x4003e0 <printf#plt>
0x0000000000400534 <+55>: leave
0x0000000000400535 <+56>: ret
End of assembler dump.
How can I get GDB to reference strcpy the way it references printf?
I'm compiling with "gcc -g"
Try compiling your program with -fno-builtin.
In your gcc, strcpy is a builtin function. See also 6.56 Other Built-in Functions Provided by GCC.
Related
#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 tried to set a break-point on GDB when a function strcpy() is called, but GDB stops, and i don't know how to find the error, im new to GDB and i want to study binary exploitation, so the forum i'm reading does not explain nothing about this, here is the output;
(gdb) disassemble main
Dump of assembler code for function main:
0x00000000000011c9 <+0>: endbr64
0x00000000000011cd <+4>: push rbp
0x00000000000011ce <+5>: mov rbp,rsp
0x00000000000011d1 <+8>: sub rsp,0x50
0x00000000000011d5 <+12>: mov DWORD PTR [rbp-0x44],edi
0x00000000000011d8 <+15>: mov QWORD PTR [rbp-0x50],rsi
0x00000000000011dc <+19>: mov rax,QWORD PTR fs:0x28
0x00000000000011e5 <+28>: mov QWORD PTR [rbp-0x8],rax
0x00000000000011e9 <+32>: xor eax,eax
0x00000000000011eb <+34>: cmp DWORD PTR [rbp-0x44],0x1
0x00000000000011ef <+38>: jne 0x1207 <main+62>
0x00000000000011f1 <+40>: lea rsi,[rip+0xe10] # 0x2008
0x00000000000011f8 <+47>: mov edi,0x1
0x00000000000011fd <+52>: mov eax,0x0
0x0000000000001202 <+57>: call 0x10c0 <errx#plt>
0x0000000000001207 <+62>: mov DWORD PTR [rbp-0x34],0x0
0x000000000000120e <+69>: mov rax,QWORD PTR [rbp-0x50]
0x0000000000001212 <+73>: add rax,0x8
0x0000000000001216 <+77>: mov rdx,QWORD PTR [rax]
0x0000000000001219 <+80>: lea rax,[rbp-0x30]
0x000000000000121d <+84>: mov rsi,rdx
0x0000000000001220 <+87>: mov rdi,rax
0x0000000000001223 <+90>: call 0x1090 <strcpy#plt> // breakpoint here
0x0000000000001228 <+95>: mov eax,DWORD PTR [rbp-0x34]
0x000000000000122b <+98>: test eax,eax
0x000000000000122d <+100>: je 0x1247 <main+126>
0x000000000000122f <+102>: mov eax,DWORD PTR [rbp-0x34]
0x0000000000001232 <+105>: mov esi,eax
0x0000000000001234 <+107>: lea rdi,[rip+0xde5] # 0x2020
0x000000000000123b <+114>: mov eax,0x0
0x0000000000001240 <+119>: call 0x10d0 <printf#plt>
0x0000000000001245 <+124>: jmp 0x1253 <main+138>
0x0000000000001247 <+126>: lea rdi,[rip+0xe12] # 0x2060
0x000000000000124e <+133>: call 0x10a0 <puts#plt>
0x0000000000001253 <+138>: mov eax,0x0
0x0000000000001258 <+143>: mov rcx,QWORD PTR [rbp-0x8]
0x000000000000125c <+147>: xor rcx,QWORD PTR fs:0x28
0x0000000000001265 <+156>: je 0x126c <main+163>
0x0000000000001267 <+158>: call 0x10b0 <__stack_chk_fail#plt>
0x000000000000126c <+163>: leave
0x000000000000126d <+164>: ret
End of assembler dump.
(gdb) break *0x0000000000001223 // I want to set the breakpoint here
Breakpoint 1 at 0x1223
(gdb) r AAAA // I try to run the program providing arguments
Starting program: /home/ryan/liveoverflow_youtube/0x05_simple_crackme_intro_assembler/stackReg AAAA
[1]+ Stopped gdb stackReg // This is the problem?
GDB stopping like this is a bug which occurs when GDB throws an error while trying to place a breakpoint, it was fixed in upstream GDB with this patch:
https://sourceware.org/ml/gdb-patches/2019-05/msg00361.html
Once you see GDB stopped like this:
[1]+ Stopped
you should be dropped back to a shell. Just resume GDB with the fg command and continue your debug session. Once GDB 9 is out this bug will be fixed.
As was pointed out in a comment the reason the breakpoint address is incorrect is that you are using a Position Independent Executable (PIE), the code will be relocated when the process starts.
Start GDB with starti, then you can disassemble main and see where the code has actually been placed.
I am trying to understand reasoning for seg fault with dissemble code.
Case 1.
char *p = NULL;
printf("%s", p);
O/p: No crash. it give me null. Further looking at disassemble code, it shows this one.
Dump of assembler code for function printf#plt:
0x00000000004003b8 <+0>: jmpq *0x2004aa(%rip) # 0x600868 <printf#got.plt>
0x00000000004003be <+6>: pushq $0x0
0x00000000004003c3 <+11>: jmpq 0x4003a8
End of assembler dump.
While i am trying to further go beyond this but do not know how to move to next set of instructions and what exactly it does.
Case 2.
int
main()
{
char *p = NULL;
printf("%s\n", p);
}
It leads to seg fault.
Disassemble code:
Dump of assembler code for function main:
0x00000000004004c4 <+0>: push %rbp
0x00000000004004c5 <+1>: mov %rsp,%rbp
0x00000000004004c8 <+4>: sub $0x10,%rsp
0x00000000004004cc <+8>: movq $0x0,-0x8(%rbp)
0x00000000004004d4 <+16>: mov -0x8(%rbp),%rax
0x00000000004004d8 <+20>: mov %rax,%rdi
0x00000000004004db <+23>: callq 0x4003b8 <puts#plt>
0x00000000004004e0 <+28>: leaveq
0x00000000004004e1 <+29>: retq
End of assembler dump.
(gdb) disassemble puts
Dump of assembler code for function puts#plt:
0x00000000004003b8 <+0>: jmpq *0x2004aa(%rip) # 0x600868 <puts#got.plt>
0x00000000004003be <+6>: pushq $0x0
0x00000000004003c3 <+11>: jmpq 0x4003a8
End of assembler dump.
Can u please help me to identify what assembler instruction is leading to seg fault?
0x00000000004003b8 <+0>: jmpq *0x2004aa(%rip) # 0x600868 <puts#got.plt>
Two important codewords here:
GOT -> Global Offset Table
PLT -> Procedure Linkage Table
This indicates it calls puts from dynamic library. Address of puts is not know at disassembly only time. Program must be run in order to allow dynamic linker bind address of library function to PLT slot.
What you need is:
(gdb) start
Temporary breakpoint 1 at 0x40053e: file c.c, line 9.
Starting program: /home/josef/DEVEL/test/test/a.out
Temporary breakpoint 1, main () at c.c:9
9 char *p = NULL;
(gdb) disassemble main
Dump of assembler code for function main:
0x0000000000400536 <+0>: push %rbp
0x0000000000400537 <+1>: mov %rsp,%rbp
0x000000000040053a <+4>: sub $0x10,%rsp
=> 0x000000000040053e <+8>: movq $0x0,-0x8(%rbp)
0x0000000000400546 <+16>: mov -0x8(%rbp),%rax
0x000000000040054a <+20>: mov %rax,%rdi
0x000000000040054d <+23>: callq 0x400410 <puts#plt>
0x0000000000400552 <+28>: leaveq
0x0000000000400553 <+29>: retq
End of assembler dump.
(gdb) disassemble puts
Dump of assembler code for function _IO_puts:
0x00007ffff7a84d60 <+0>: push %r12
0x00007ffff7a84d62 <+2>: mov %rdi,%r12
0x00007ffff7a84d65 <+5>: push %rbp
0x00007ffff7a84d66 <+6>: push %rbx
0x00007ffff7a84d67 <+7>: callq 0x7ffff7a9d9b0 <strlen>
0x00007ffff7a84d6c <+12>: mov 0x34fafd(%rip),%rbx # 0x7ffff7dd4870 <stdout>
0x00007ffff7a84d73 <+19>: mov %rax,%rbp
0x00007ffff7a84d76 <+22>: mov (%rbx),%eax
0x00007ffff7a84d78 <+24>: mov %rbx,%rdi
0x00007ffff7a84d7b <+27>: and $0x8000,%eax
0x00007ffff7a84d80 <+32>: jne 0x7ffff7a84ddf <_IO_puts+127>
0x00007ffff7a84d82 <+34>: mov 0x88(%rbx),%r8
......
Now you see what is inside puts. You can go forward and disassemble strlen
(gdb) disassemble strlen
Dump of assembler code for function strlen:
0x00007ffff7a9d9b0 <+0>: pxor %xmm8,%xmm8
0x00007ffff7a9d9b5 <+5>: pxor %xmm9,%xmm9
0x00007ffff7a9d9ba <+10>: pxor %xmm10,%xmm10
0x00007ffff7a9d9bf <+15>: pxor %xmm11,%xmm11
0x00007ffff7a9d9c4 <+20>: mov %rdi,%rax
0x00007ffff7a9d9c7 <+23>: mov %rdi,%rcx
0x00007ffff7a9d9ca <+26>: and $0xfff,%rcx
0x00007ffff7a9d9d1 <+33>: cmp $0xfcf,%rcx
0x00007ffff7a9d9d8 <+40>: ja 0x7ffff7a9da40 <strlen+144>
0x00007ffff7a9d9da <+42>: movdqu (%rax),%xmm12
0x00007ffff7a9d9df <+47>: pcmpeqb %xmm8,%xmm12
0x00007ffff7a9d9e4 <+52>: pmovmskb %xmm12,%edx
0x00007ffff7a9d9e9 <+57>: test %edx,%edx
0x00007ffff7a9d9eb <+59>: je 0x7ffff7a9d9f1 <strlen+65>
......
Good luck with analyzing all the code :)
I'm reading Haching: the art of exploitation and I have found a difference in my compiled code and the one in the book.
The code:
void test_function(int a, int b, int c, int d) {
int flag;
char buffer[10];
flag = 31337;
buffer[0] = 'A';
}
int main() {
test_function(1, 2, 3, 4);
}
In the book he compiles with gcc and disassembles with gdb, I don't know the version of the softwares.
He uses the commands:
gcc -g program.c
gdb -q ./a.out
Then he does:
(gdb) disass main
Dump of assembler code for function main():
0x08048357 <main+0>: push ebp
0x08048358 <main+1>: mov ebp,esp
0x0804835a <main+3>: sub esp,0x18
0x0804835d <main+6>: and esp,0xfffffff0
0x08048360 <main+9>: mov eax,0x0
0x08048365 <main+14>: sub esp,eax
0x08048367 <main+16>: mov DWORD PTR [esp+12],0x4
0x0804836f <main+24>: mov DWORD PTR [esp+8],0x3
0x08048377 <main+32>: mov DWORD PTR [esp+4],0x2
0x0804837f <main+40>: mov DWORD PTR [esp],0x1
0x08048386 <main+47>: call 0x8048344 <test_function>
0x0804838b <main+52>: leave
0x0804838c <main+53>: ret
End of assembler dump
(gdb) disass test_function()
Dump of assembler code for function test_function:
0x08048344 <test_function+0>: push ebp
0x08048345 <test_function+1>: mov ebp,esp
0x08048347 <test_function+3>: sub esp,0x28
0x0804834a <test_function+6>: mov DWORD PTR [ebp-12],0x7a69
0x08048351 <test_function+13>: mov BYTE PTR [ebp-40],0x41
0x08048355 <test_function+17>: leave
0x08048356 <test_function+18>: ret
Instead this is my output (using the same command):
(gdb) disass main
Dump of assembler code for function main:
0x000000000040058b <+0>: push rbp
0x000000000040058c <+1>: mov rbp,rsp
0x000000000040058f <+4>: mov ecx,0x4
0x0000000000400594 <+9>: mov edx,0x3
0x0000000000400599 <+14>: mov esi,0x2
0x000000000040059e <+19>: mov edi,0x1
0x00000000004005a3 <+24>: call 0x400546 <test_function>
0x00000000004005a8 <+29>: mov eax,0x0
0x00000000004005ad <+34>: pop rbp
0x00000000004005ae <+35>: ret
End of assembler dump.
(gdb) disass test_function
Dump of assembler code for function test_function:
0x0000000000400546 <+0>: push rbp
0x0000000000400547 <+1>: mov rbp,rsp
0x000000000040054a <+4>: sub rsp,0x40
0x000000000040054e <+8>: mov DWORD PTR [rbp-0x34],edi
0x0000000000400551 <+11>: mov DWORD PTR [rbp-0x38],esi
0x0000000000400554 <+14>: mov DWORD PTR [rbp-0x3c],edx
0x0000000000400557 <+17>: mov DWORD PTR [rbp-0x40],ecx
0x000000000040055a <+20>: mov rax,QWORD PTR fs:0x28
0x0000000000400563 <+29>: mov QWORD PTR [rbp-0x8],rax
0x0000000000400567 <+33>: xor eax,eax
0x0000000000400569 <+35>: mov DWORD PTR [rbp-0x24],0x7a69
0x0000000000400570 <+42>: mov BYTE PTR [rbp-0x20],0x41
0x0000000000400574 <+46>: nop
0x0000000000400575 <+47>: mov rax,QWORD PTR [rbp-0x8]
0x0000000000400579 <+51>: xor rax,QWORD PTR fs:0x28
0x0000000000400582 <+60>: je 0x400589 <test_function+67>
0x0000000000400584 <+62>: call 0x400420 <__stack_chk_fail#plt>
0x0000000000400589 <+67>: leave
0x000000000040058a <+68>: ret
End of assembler dump.
I'm using gcc version 5.4.0 and gdb version 7.11.1.
I have two question:
Why is the function proloque different? What's the difference in the instructions given by the book compiler and the ones given by mine ? (I am not talking about the name of the register, I'm talking about why my main prologue does just push and move)
Could the difference in test_function due to a possible stack overflow and the compiler (that is newer than the other one) knows and patches it ? If so, how does it knows that a flaw exists and what method does it employ to patches it?
EDIT: I know the book version was compiled on a 32 bit architecture. My question was about the different instruction of the compiler, if they have to do the same things, why are they different?
The book version was compiled on a 32 bit architecture, your one on 64. Use the -m32 switch to generate 32 bit executable.
This question already has answers here:
Compiler changes printf to puts
(2 answers)
Closed 3 years ago.
I'm pretty new to programming and wanted to ask why I get the same result with different code. I'm actually reading a book and the example in the book is with printf (also in Assembler). In this case it says <printf#plt>. The assembler code in the book differs from mine but C Code is the same. Is my processor just computing different?
(Problem is at call <+34> <puts#plt>)
Code 1:
#include <stdio.h>
int main()
{
int i;
for(i=0; i<10; i++)
{
printf("Hello, world!\n");
}
return 0;
}
Code 2:
#include <stdio.h>
int main()
{
int i;
for(i=0; i<10; i++)
{
puts("Hello, world!\n");
}
return 0;
}
Code 1 disassembled:
Dump of assembler code for function main:
0x080483eb <+0>: lea ecx,[esp+0x4]
0x080483ef <+4>: and esp,0xfffffff0
0x080483f2 <+7>: push DWORD PTR [ecx-0x4]
0x080483f5 <+10>: push ebp
0x080483f6 <+11>: mov ebp,esp
0x080483f8 <+13>: push ecx
=> 0x080483f9 <+14>: sub esp,0x14
0x080483fc <+17>: mov DWORD PTR [ebp-0xc],0x0
0x08048403 <+24>: jmp 0x8048419 <main+46>
0x08048405 <+26>: sub esp,0xc
0x08048408 <+29>: push 0x80484b0
0x0804840d <+34>: call 0x80482c0 <puts#plt>
0x08048412 <+39>: add esp,0x10
0x08048415 <+42>: add DWORD PTR [ebp-0xc],0x1
0x08048419 <+46>: cmp DWORD PTR [ebp-0xc],0x9
0x0804841d <+50>: jle 0x8048405 <main+26>
0x0804841f <+52>: mov eax,0x0
0x08048424 <+57>: mov ecx,DWORD PTR [ebp-0x4]
0x08048427 <+60>: leave
0x08048428 <+61>: lea esp,[ecx-0x4]
0x0804842b <+64>: ret
End of assembler dump.
Code 2 disassembled:
Dump of assembler code for function main:
0x080483eb <+0>: lea ecx,[esp+0x4]
0x080483ef <+4>: and esp,0xfffffff0
0x080483f2 <+7>: push DWORD PTR [ecx-0x4]
0x080483f5 <+10>: push ebp
0x080483f6 <+11>: mov ebp,esp
0x080483f8 <+13>: push ecx
0x080483f9 <+14>: sub esp,0x14
0x080483fc <+17>: mov DWORD PTR [ebp-0xc],0x0
0x08048403 <+24>: jmp 0x8048419 <main+46>
=> 0x08048405 <+26>: sub esp,0xc
0x08048408 <+29>: push 0x80484b0
0x0804840d <+34>: call 0x80482c0 <puts#plt>
0x08048412 <+39>: add esp,0x10
0x08048415 <+42>: add DWORD PTR [ebp-0xc],0x1
0x08048419 <+46>: cmp DWORD PTR [ebp-0xc],0x9
0x0804841d <+50>: jle 0x8048405 <main+26>
0x0804841f <+52>: mov eax,0x0
0x08048424 <+57>: mov ecx,DWORD PTR [ebp-0x4]
0x08048427 <+60>: leave
0x08048428 <+61>: lea esp,[ecx-0x4]
0x0804842b <+64>: ret
End of assembler dump.
The puts function is preferred because it is simpler to in both functionality (no format string decoding) and argument passing.
For instance, System V ABI x86 calling conventions require to set number of XMM (YMM) arguments (printf is variadic) in RAX. puts is easier, as there is only single argument passed with RDI.