File main.s
.section .text
.global _start
.text
_start:
movabs $0xabcdabcdabcdabcd, %rax
push %rax
movabs $0x1234123412341234, %rax
push %rax
movq $60, %rax # syscall: exit
xorq %rdi, %rdi # exit code 0
syscallBuild.
as main.s -o main.o
ld main.o -o mainDebug.
(gdb) file main
(gdb) break _start
(gdb) run
Breakpoint 1, 0x0000000000401000 in _start ()Monitor stack.
(gdb) disassemble
Dump of assembler code for function _start:
=> 0x0000000000401000 <+0>: movabs $0xabcdabcdabcdabcd,%rax
0x000000000040100a <+10>: push %rax
0x000000000040100b <+11>: movabs $0x1234123412341234,%rax
0x0000000000401015 <+21>: push %rax
0x0000000000401016 <+22>: mov $0x3c,%rax
0x000000000040101d <+29>: xor %rdi,%rdi
0x0000000000401020 <+32>: syscall
(gdb) while 1
> x/4gx $rsp
> x/i $rip
> nexti
> end0x7fffffffe700: 0x0000000000000001 0x00007fffffffe9ab
0x7fffffffe710: 0x0000000000000000 0x00007fffffffe9bc
=> 0x401000 <_start>: movabs $0xabcdabcdabcdabcd,%rax
=> 0x40100a <_start+10>: push %rax
0x7fffffffe6f8: 0xabcdabcdabcdabcd 0x0000000000000001
0x7fffffffe708: 0x00007fffffffe9ab 0x0000000000000000
=> 0x40100b <_start+11>: movabs $0x1234123412341234,%rax
=> 0x401015 <_start+21>: push %rax
0x7fffffffe6f0: 0x1234123412341234 0xabcdabcdabcdabcd
0x7fffffffe700: 0x0000000000000001 0x00007fffffffe9abIllustrate.
┌───────────────┬───────────────────┐ ┌───────────────┬───────────────────┐ ┌───────────────┬───────────────────┐
│ address │ value │ │ address │ value │ │ address │ value │
├───────────────┼───────────────────┤ ├───────────────┼───────────────────┤ ├───────────────┼───────────────────┤
│ │ │ │ │ │ │ │ │
│ │ │ push │ │ │ push │0x7fffffffe6f0 │ 0x1234123412341234│
│ │ │ ─────► │0x7fffffffe6f8 │ 0xabcdabcdabcdabcd│ ─────► │0x7fffffffe6f8 │ 0xabcdabcdabcdabcd│
│0x7fffffffe700 │ 0x0000000000000001│ │0x7fffffffe700 │ 0x0000000000000001│ │0x7fffffffe700 │ 0x0000000000000001│
│0x7fffffffe708 │ 0x00007fffffffe9ab│ │0x7fffffffe708 │ 0x00007fffffffe9ab│ │0x7fffffffe708 │ 0x00007fffffffe9ab│
│0x7fffffffe710 │ 0x0000000000000000│ │0x7fffffffe710 │ 0x0000000000000000│ │0x7fffffffe710 │ 0x0000000000000000│
│0x7fffffffe718 │ 0x00007fffffffe9bc│ │0x7fffffffe718 │ 0x00007fffffffe9bc│ │0x7fffffffe718 │ 0x00007fffffffe9bc│
└───────────────┴───────────────────┘ └───────────────┴───────────────────┘ └───────────────┴───────────────────┘File main.s
.section .text
.global _start
_start:
mov $5, %rdi # x = 5
mov $7, %rsi # y = 7
call sum # sum(x, y)
mov $60, %rax # syscall: exit
xor %rdi, %rdi # exit code 0
syscall
# add two integers
sum:
add %rsi, %rdi # x += y
mov %rdi, %rax # rax = x
retas main.s -o main.o
ld main.o -o main(gdb) file main
(gdb) break _start
(gdb) run
Breakpoint 1, 0x0000000000401000 in _start ()Monitor stack.
(gdb) disassemble
Dump of assembler code for function _start:
=> 0x0000000000401000 <+0>: mov $0x5,%rdi
0x0000000000401007 <+7>: mov $0x7,%rsi
0x000000000040100e <+14>: call 0x40101f <sum>
0x0000000000401013 <+19>: mov $0x3c,%rax
0x000000000040101a <+26>: xor %rdi,%rdi
0x000000000040101d <+29>: syscall
(gdb) while 1
> x/4gx $rsp
> x/i $rip
> stepi
> end0x7fffffffe700: 0x0000000000000001 0x00007fffffffe9ab
0x7fffffffe710: 0x0000000000000000 0x00007fffffffe9bc
=> 0x40100e <_start+14>: call 0x40101f <sum>
0x7fffffffe6f8: 0x0000000000401013 0x0000000000000001
0x7fffffffe708: 0x00007fffffffe9ab 0x0000000000000000
=> 0x401025 <sum+6>: ret
0x7fffffffe700: 0x0000000000000001 0x00007fffffffe9ab
0x7fffffffe710: 0x0000000000000000 0x00007fffffffe9bcIllustrate.
┌───────────────┬───────────────────┐ ┌───────────────┬───────────────────┐ ┌───────────────┬───────────────────┐
│ address │ value │ │ address │ value │ │ address │ value │
├───────────────┼───────────────────┤ ├───────────────┼───────────────────┤ ├───────────────┼───────────────────┤
│ │ │ │ │ │ │ │ │
│ │ │ call │ │ │ ret │ │ │
│ │ │ ─────► │0x7fffffffe6f8 │ 0x0000000000401013│ ─────► │ │ │
│0x7fffffffe700 │ 0x0000000000000001│ │0x7fffffffe700 │ 0x0000000000000001│ │0x7fffffffe700 │ 0x0000000000000001│
│0x7fffffffe708 │ 0x00007fffffffe9ab│ │0x7fffffffe708 │ 0x00007fffffffe9ab│ │0x7fffffffe708 │ 0x00007fffffffe9ab│
│0x7fffffffe710 │ 0x0000000000000000│ │0x7fffffffe710 │ 0x0000000000000000│ │0x7fffffffe710 │ 0x0000000000000000│
│0x7fffffffe718 │ 0x00007fffffffe9bc│ │0x7fffffffe718 │ 0x00007fffffffe9bc│ │0x7fffffffe718 │ 0x00007fffffffe9bc│
└───────────────┴───────────────────┘ └───────────────┴───────────────────┘ └───────────────┴───────────────────┘Example: parent_func calls child_func.
parent_func() {
child_func()
}
child_func() {
}<parent_func>:
call child_func # save parent next instruction address (rip) to stack,
# jump to child_func.<child_func>:
# prolog
push %rbp # save parent base pointer (rbp) to stack.
mov %rsp, %rbp # move current base pointer to top of stack (rsp).
... # function body
# epilog
pop %rbp # restore parent base pointer from stack.
ret # restore parent next instruction address from stack,
# jump to this instruction (parent_func).Illustrate.
┌───────────┐ ┌───────────┐ ┌───────────┐ ┌───────────┐
│ stack │ │ stack │ │ stack │ │ stack │
$rbp ─┐ ├───────────┤ ├───────────┤ $rbp ─┐ ├───────────┤ $rbp ──┐ ├───────────┤
│ │ │ │ │ │ │ │ │ │ │
│ │ │ │ │ │ │ │ │ │ │
│ │ │ │ │ │ │ │ │ │ │
│ │ │ parent_func │ │ └─►│parent $rbp│ │ │ │
│ │ │ call │parent $rip│ │parent $rip│ │ │ │
└─┼► │ child_func │ │ prolog │ │ epilog └─┼► │
│ │ ───────────► │ │ ──────────► │ │ ──────────► │ │
└───────────┘ └───────────┘ └───────────┘ └───────────┘Local variables locates on the stack for each function call. Their addresses are based on negative offsets from the base pointer rbp.
int a, b, c;
a = 1;
b = 2;
c = 3;
movl $0x1,-0xc(%rbp) ; a at $rbp-0xc
movl $0x2,-0x8(%rbp) ; b at $rbp-0x8
movl $0x3,-0x4(%rbp) ; c at $rbp-0x4When the parent function calls the child function, the arguments are
saved in the registers rdi, rsi, rdx, rcx, r8, and r9. If more than 6
arguments, the extra arguments are saved on the stack.
Inside the child function, it reads the registers and saves the
arguments into its stack frame. The argument addresses in the stack
frame are based on the base pointer rbp.
parent_function()
{
child_func(a, b);
}
int child_func(int a, int b)
{
}<parent_function>:
mov -0x8(%rbp),%esi # save a to $esi
mov -0xc(%rbp),%edi # save b to $edi
call child_func
<child_func>:
mov %edi,-0x14(%rbp) # save $edi to stack, b
mov %esi,-0x18(%rbp) # save $esi to stack, aSo:
In GDB:
x/-6wx $rbp.x/2a $rbp.───low address ┌────────────────┐
│ stack │
├────────────────┤
│ │
│ ... │
│ argument │
│ argument │
│ ... │
│ local variable │
│ local variable │
$rbp ───► │ parent $rbp │
│ parent %rip │
│ │
──high address └────────────────┘File main.c
int func(int argv1, int argv2)
{
int a = 0xaaaaaaaa;
int b = 0xbbbbbbbb;
int c = 0xcccccccc;
int d = 0xdddddddd;
return 0;
}
int main(int argc, char** argv)
{
func(0x11111111, 0x22222222);
return 0;
}$ gcc main.c -o mainRun under GDB.
(gdb) file main
(gdb) disassemble func
0x0000000000001129 <+0>: endbr64
0x000000000000112d <+4>: push %rbp
0x000000000000112e <+5>: mov %rsp,%rbp
0x0000000000001131 <+8>: mov %edi,-0x14(%rbp)
0x0000000000001134 <+11>: mov %esi,-0x18(%rbp)
0x0000000000001137 <+14>: movl $0xaaaaaaaa,-0x10(%rbp)
0x000000000000113e <+21>: movl $0xbbbbbbbb,-0xc(%rbp)
0x0000000000001145 <+28>: movl $0xcccccccc,-0x8(%rbp)
0x000000000000114c <+35>: movl $0xdddddddd,-0x4(%rbp)
0x0000000000001153 <+42>: mov $0x0,%eax
0x0000000000001158 <+47>: pop %rbp
0x0000000000001159 <+48>: retSet breakpoint at the end of func.
(gdb) break *func+42
(gdb) run
Breakpoint 1, 0x0000555555555153 in func ()Examine arguments and local variables.
(gdb) x/-6wx $rbp
0x7fffffffe5b8: 0x22222222 0x11111111 0xaaaaaaaa 0xbbbbbbbb
0x7fffffffe5c8: 0xcccccccc 0xddddddddExamine parent’s $rip and $rbp.
(gdb) x/2a $rbp
0x7fffffffe5d0: 0x7fffffffe5f0 0x55555555517c <main+34>Illustrate the stack.
┌────────────────┐
│ stack │
───low address ├────────────────┤
│ │
0x7fffffffe5b8 │ 0x22222222 │ argument argv2
│ 0x11111111 │ argument argv2
│ 0xaaaaaaaa │ variable a
│ 0xbbbbbbbb │ variable b
0x7fffffffe5c8 │ 0xcccccccc │ variable c
│ 0xdddddddd │ variable d
$rbp ───► 0x7fffffffe5d0 │ 0x7fffffffe5f0 │ parent $rbp
│ 0x55555555517c │ parent $rip
│ │
──high address └────────────────┘ Search memory for the sequence of bytes.
find [/sn] start_addr, +len, vals...
find [/sn] start_addr, end_addr, vals...int main()
{
char str[] = "hello-hello";
short a = 0x0102;
int b = 0x0a0b0c0d;
}# find str
(gdb) find &str, +sizeof(str), "hello"
(gdb) find &str, +sizeof(str), 'h', 'e', 'l', 'l', 'o'
# find a
(gdb) find &a, +2, (short)0x0102
(gdb) find /h &a, +2, 0x0102
(gdb) find /b &a, +2, 0x02, 0x01
# find b
(gdb) find &b, +4, (int)0x0a0b0c0d
(gdb) find /w &b, +4, 0x0a0b0c0d
# find b, a
# (int)b , padding , (short)a
(gdb) find &b, +8, (int)0x0a0b0c0d, (short)0x0000, (short)0x0102Dump the contents of memory from start_addr to end_addr, or the value of expr, to file.
dump [format] memory filename start_addr end_addr
dump [format] value filename expr(gdb) p &str
$3 = (char (*)[12]) 0xffffffffec88
(gdb) dump memory mem.hex 0xffffffffec88 0xffffffffec88+12
(gdb) dump value val.hex str
$ hexdump -C mem.hex
00000000 68 65 6c 6c 6f 2d 68 65 6c 6c 6f 00 |hello-hello.|
$ hexdump -C val.hex
00000000 68 65 6c 6c 6f 2d 68 65 6c 6c 6f 00 |hello-hello.|Restore the contents of file filename into memory.
restore file [binary] offset start end(gdb) p &str
$3 = (char (*)[12]) 0xffffffffec88
# file start
(gdb) restore mem.hex binary 0xffffffffec88
Restoring binary file mem.hex into memory (0xffffffffec88 to 0xffffffffec94)
# file offset start
(gdb) restore mem.hex binary 0 0xffffffffec88
Start address is greater than length of binary file mem.hex.List memory regions.
info proc mappingSample: Add a memory region by gdb.
int main()
{
return 0
}hello world(gdb) set $fd = (int) open("hello.txt", 0)
(gdb) set $region_addr = (void*) mmap(0, 4096, 1, 1, $fd, 0)
(gdb) info proc mappings
Start Addr End Addr Size Offset Perms File
0x0000fffff7ff5000 0x0000fffff7ff6000 0x1000 0x0 r--s /root/demo/hello.txt
...
(gdb) x/s $region_addr
0xfffff7ff5000: "hello world\n"
Generate the core dump.
gcore [file]Load the core dump.
gdb program core