Use this .gdbinit. Make sure you save it as your ~/.gdbinit file in $HOME. This adds functionality: you can see the stack, data, registers and code and how they change on each cmd entered into gdb. For best results use 80x24 sized windows (It acts like a motion picture in that size.)
Given a trivial program:
#include <stdio.h>
#include <unistd.h>
void inject() { printf("injected.\n"); }
int main()
{
int i = 0x10;
int *x = &i;
printf("%d\n", i);
return write(0, "Hello, sailor!\n", 100);
}
Run GDB and display 16 4-Byte Blocks on the stack.
$ gdb foo
gdb> break main
gdb> run
gdb> x /16xw $esp
0xbfb4c894: 0xbfb4c8b0 0xbfb4c928 0xb76bcbd6 0x08048410
0xbfb4c8a4: 0x00000000 0xbfb4c928 0xb76bcbd6 0x00000001
0xbfb4c8b4: 0xbfb4c954 0xbfb4c95c 0xb7818858 0xbfb4c910
0xbfb4c8c4: 0xffffffff 0xb7834ff4 0x08048229 0x00000001
Setting memory in gdb:
Setting a memory address:
gdb> set {int}0xbfb4c8a4 = 0x01010101
0xbfb4c894: 0xbfb4c8b0 0xbfb4c928 0xb76bcbd6 0x08048410
0xbfb4c8a4: 0x01010101 0xbfb4c928 0xb76bcbd6 0x00000001
Addresses can be accessed by offsets, for example to access the next 4 bytes:
gdb> set {int}0xbfb4c8a8 = 0x02020202 gdb> set {int}0xbfb4c8ac = 0x03030303 gdb> x /16xw $esp
0xbfb4c894: 0xbfb4c8b0 0xbfb4c928 0xb76bcbd6 0x08048410
0xbfb4c8a4: 0x01010101 0x02020202 0x03030303 0x00000001
Setting variables in gdb:
gdb> print i
$1 = 0x10
we can set variables to whatever we want:
gdb> set variable i = 0x40 gdb> print i $2 = 0x40
You can also do this with pointers:
gdb> set variable *x=ee gdb> print i $6 = 0xee gdb> print *x $7 = 0xee
You can do this with registers as well: Find the address of inject function:
$ objdump -D foo | grep inject
08048424 <inject>:
You can then set $eip to change the code path.
gdb> print $eip $1 = (void (*)()) 0x8048456 gdb> set $eip=0x8048424 gdb> n 0x08048425 4 void inject() { printf("injected.\n"); } gdb> n injected.