update heap

This commit is contained in:
firmianay 2017-08-15 13:35:39 +08:00
parent 403225985a
commit 1231d2e3d1
8 changed files with 151 additions and 7 deletions

View File

@ -13,6 +13,7 @@
- [1.5.5 静态链接](doc/1.5.5_static_link.md)
- [1.5.6 动态链接](doc/1.5.6_dynamic_link.md)
- [1.5.7 内存管理](doc/1.5.7_memory.md)
- [1.5.8 glibc malloc](doc/glibc_malloc.md)
- [1.6 密码学基础](doc/1.6_crypto_basic.md)
- [1.7 Android 安全基础](doc/1.7_android_basic.md)
@ -39,6 +40,7 @@
- [四、技巧篇](doc/4_tips.md)
- [4.1 AWD模式](doc/4.1_AWD.md)
- [4.2 Linux 命令行技巧](doc/4.2_Linux_terminal_tips.md)
- [4.3 GCC 安全编译参数](doc/4.3_gcc.md)
- [五、高级篇](doc/5_advanced.md)
- [5.1 Fuzz 测试](doc/5.1_fuzz.md)

View File

@ -14,6 +14,7 @@
* [1.5.5 静态链接](doc/1.5.5_static_link.md)
* [1.5.6 动态链接](doc/1.5.6_dynamic_link.md)
* [1.5.7 内存管理](doc/1.5.7_memory.md)
* [1.5.8 glibc malloc](doc/glibc_malloc.md)
* [1.6 密码学基础](doc/1.6_crypto_basic.md)
* [1.7 Android 安全基础](doc/1.7_android_basic.md)
* [二、工具篇](doc/2_tools.md)
@ -37,6 +38,7 @@
* [四、技巧篇](doc/4_tips.md)
* [4.1 AWD模式](doc/4.1_AWD.md)
* [4.2 Linux 命令行技巧](doc/4.2_Linux_terminal_tips.md)
* [4.3 GCC 安全编译参数](doc/4.3_gcc.md)
* [五、高级篇](doc/5_advanced.md)
* [5.1 Fuzz 测试](doc/5.1_fuzz.md)
* [5.2 Pin 动态二进制插桩](doc/5.2_pin.md)
@ -46,5 +48,5 @@
* [6.1 更多 Linux 工具](doc/6.1_Linuxtools.md)
* [6.2 更多 Windows 工具](doc/6.2_wintools.md)
* [6.3 博客、文章和书籍](doc/6.3_books&blogs.md)
* [6.4 习题 write*up](doc/6.4_writeup.md)
* [6.4 习题 write-up](doc/6.4_writeup.md)
* [6.5 Linux x86-64 系统调用表](doc/6.5_syscall.md)

View File

@ -99,20 +99,20 @@ Dump of assembler code for function main:
0x0000058e <+43>: push DWORD PTR [ebp-0xc] ;将 b 压入栈中
0x00000591 <+46>: push DWORD PTR [ebp-0x10] ;将 a 压入栈中
0x00000594 <+49>: call 0x53d <add> ;调用 add() 函数,返回值保存在 eax 中
0x00000599 <+54>: add esp,0x8
0x0000059c <+57>: sub esp,0x8
0x00000599 <+54>: add esp,0x8 ;清理 add() 的参数
0x0000059c <+57>: sub esp,0x8 ;调整 esp 使 16 位对齐
0x0000059f <+60>: push eax ;eax 入栈
0x000005a0 <+61>: lea eax,[ebx-0x19b0] ;ebx-0x19b0 的地址保存到 eax该地址处保存字符串 "%d\n"
0x000005a6 <+67>: push eax ;eax 入栈
0x000005a7 <+68>: call 0x3d0 <printf@plt> ;调用 printf() 函数
0x000005ac <+73>: add esp,0x10 ;调整栈顶指针 esp删除 add() 和 printf() 的参数
0x000005ac <+73>: add esp,0x10 ;调整栈顶指针 esp清理 printf() 的参数
0x000005af <+76>: mov eax,0x0 ;eax=0x0
0x000005b4 <+81>: lea esp,[ebp-0x8] ;ebp-0x8 的地址保存到 esp
0x000005b7 <+84>: pop ecx ;弹栈恢复 ecx、ebx、ebp
0x000005b8 <+85>: pop ebx
0x000005b9 <+86>: pop ebp
0x000005ba <+87>: lea esp,[ecx-0x4] ;ecx-0x4 的地址保存到 esp
0x000005bd <+90>: ret ;返回
0x000005bd <+90>: ret ;返回,相当于 pop eip;
End of assembler dump.
gdb-peda$ disassemble add
Dump of assembler code for function add:
@ -155,7 +155,7 @@ Dump of assembler code for function _start:
0x0000042c <+44>: call 0x3e0 <__libc_start_main@plt> ;call 指令调用 main() 函数
0x00000431 <+49>: hlt ;hlt 指令使程序停止运行,处理器进入暂停状态,不执行任何操作,不影响标志。当 RESET 线上有复位信号、CPU 响应非屏蔽终端、CPU 响应可屏蔽终端 3 种情况之一时CPU 脱离暂停状态,执行下一条指令
0x00000432 <+50>: mov ebx,DWORD PTR [esp] ;esp 强制转换为双字数据后保存到 ebx
0x00000435 <+53>: ret ;返回
0x00000435 <+53>: ret ;返回,相当于 pop eip;
0x00000436 <+54>: xchg ax,ax ;交换 ax 和 ax 的数据,相当于 nop
0x00000438 <+56>: xchg ax,ax
0x0000043a <+58>: xchg ax,ax
@ -180,11 +180,146 @@ cdecl | 函数调用方 | 从右到左的顺序压参数入栈 | 下划线+函
stdcall | 函数本身 | 从右到左的顺序压参数入栈 | 下划线+函数名+@+参数的字节数
fastcall | 函数本身 | 都两个 DWORD4 字节)类型或者占更少字节的参数被放入寄存器,其他剩下的参数按从右到左的顺序压入栈 | @+函数名+@+参数的字节数
除了参数的传递之外,函数与调用方还可以通过返回值进行交互。当返回值不大于 4 字节时,返回值存储在 eax 寄存器中,当返回值在 5~8 字节时,采用 eax 和 edx 结合的形式返回,其中 eax 存储低 4 字节, edx 存储高 4 字节。
## 堆与内存管理
#### 堆
堆是用于存放除了栈里的东西之外所有其他东西的内存区域,当使用 `malloc()``free()` 时就是在操作堆中的内存。对于堆来说,释放工作由程序员控制,容易产生 memory leak
堆是用于存放除了栈里的东西之外所有其他东西的内存区域,有动态内存分配器负责维护。分配器将堆视为一组不同大小的块block的集合来维护每个块就是一个连续的虚拟内存器片chunk当使用 `malloc()``free()` 时就是在操作堆中的内存。对于堆来说,释放工作由程序员控制,容易产生内存泄露
堆是向高地址扩展的数据结构,是不连续的内存区域。这是由于系统是用链表来存储的空闲内存地址的,而链表的遍历方向是由低地址向高地址。堆的大小受限于计算机系统中有效的虚拟内存。由此可见,堆获得的空间比较灵活,也比较大。
如果每次申请内存时都直接使用系统调用,会严重影响程序的性能。通常情况下,运行库先向操作系统“批发”一块较大的堆空间,然后“零售”给程序使用。当全部“售完”之后或者剩余空间不能满足程序的需求时,再根据情况向操作系统“进货”。
#### 进程堆管理
Linux 提供了两种堆空间分配的方式,一个是 `brk()` 系统调用,另一个是 `mmap()` 系统调用。可以使用 `man brk`、`man mmap` 查看。
`brk()` 的声明如下:
```c
#include <unistd.h>
int brk(void *addr);
void *sbrk(intptr_t increment);
```
参数 `*addr` 是进程数据段的结束地址,`brk()` 通过改变该地址来改变数据段的大小,当结束地址向高地址移动,进程内存空间增大,当结束地址向低地址移动,进程内存空间减小。`brk()`调用成功时返回 0失败时返回 -1。 `sbrk()``brk()` 类似,但是参数 `increment` 表示增量,即增加或减少的空间大小,调用成功时返回增加后减小后数据段的结束地址,失败时返回 -1。
`mmap()` 的声明如下:
```c
#include <sys/mman.h>
void *mmap(void *addr, size_t len, int prot, int flags,
int fildes, off_t off);
```
`mmap()` 函数用于创建新的虚拟内存区域并将对象映射到这些区域中当它不将地址空间映射到某个文件时我们称这块空间为匿名Anonymous空间匿名空间可以用来作为堆空间。`mmap()` 函数要求内核创建一个从地址 `addr` 开始的新虚拟内存区域,并将文件描述符 `fildes` 指定的对象的一个连续的片chunk映射到这个新区域。连续的对象片大小为 `len` 字节,从距文件开始处偏移量为 `off` 字节的地方开始。`prot` 描述虚拟内存区域的访问权限位,`flags` 描述被映射对象类型的位组成。
`munmap()` 则用于删除虚拟内存区域:
```c
#include <sys/mman.h>
int munmap(void *addr, size_t len);
```
C 标准库提供了一个叫做 `malloc` 的分配器,程序通过调用 `malloc()` 函数来从堆中分配块,声明如下:
```c
#include <stdlib.h>
void *malloc(size_t size);
void free(void *ptr);
void *calloc(size_t nmemb, size_t size);
void *realloc(void *ptr, size_t size);
```
示例:
```
#include<stdio.h>
#include<malloc.h>
void foo(int n) {
int *p;
p = (int *)malloc(n * sizeof(int));
for (int i=0; i<n; i++) {
p[i] = i;
printf("%d ", p[i]);
}
printf("\n");
free(p);
}
void main() {
int n;
scanf("%d", &n);
foo(n);
}
```
运行结果:
```text
$ ./malloc
4
0 1 2 3
$ ./malloc
8
0 1 2 3 4 5 6 7
$ ./malloc
16
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
```
使用 gdb 查看反汇编代码:
```text
gdb-peda$ disassemble foo
Dump of assembler code for function foo:
0x0000066d <+0>: push ebp
0x0000066e <+1>: mov ebp,esp
0x00000670 <+3>: push ebx
0x00000671 <+4>: sub esp,0x14
0x00000674 <+7>: call 0x570 <__x86.get_pc_thunk.bx>
0x00000679 <+12>: add ebx,0x1987
0x0000067f <+18>: mov eax,DWORD PTR [ebp+0x8]
0x00000682 <+21>: shl eax,0x2
0x00000685 <+24>: sub esp,0xc
0x00000688 <+27>: push eax
0x00000689 <+28>: call 0x4e0 <malloc@plt>
0x0000068e <+33>: add esp,0x10
0x00000691 <+36>: mov DWORD PTR [ebp-0xc],eax
0x00000694 <+39>: mov DWORD PTR [ebp-0x10],0x0
0x0000069b <+46>: jmp 0x6d9 <foo+108>
0x0000069d <+48>: mov eax,DWORD PTR [ebp-0x10]
0x000006a0 <+51>: lea edx,[eax*4+0x0]
0x000006a7 <+58>: mov eax,DWORD PTR [ebp-0xc]
0x000006aa <+61>: add edx,eax
0x000006ac <+63>: mov eax,DWORD PTR [ebp-0x10]
0x000006af <+66>: mov DWORD PTR [edx],eax
0x000006b1 <+68>: mov eax,DWORD PTR [ebp-0x10]
0x000006b4 <+71>: lea edx,[eax*4+0x0]
0x000006bb <+78>: mov eax,DWORD PTR [ebp-0xc]
0x000006be <+81>: add eax,edx
0x000006c0 <+83>: mov eax,DWORD PTR [eax]
0x000006c2 <+85>: sub esp,0x8
0x000006c5 <+88>: push eax
0x000006c6 <+89>: lea eax,[ebx-0x17e0]
0x000006cc <+95>: push eax
0x000006cd <+96>: call 0x4b0 <printf@plt>
0x000006d2 <+101>: add esp,0x10
0x000006d5 <+104>: add DWORD PTR [ebp-0x10],0x1
0x000006d9 <+108>: mov eax,DWORD PTR [ebp-0x10]
0x000006dc <+111>: cmp eax,DWORD PTR [ebp+0x8]
0x000006df <+114>: jl 0x69d <foo+48>
0x000006e1 <+116>: sub esp,0xc
0x000006e4 <+119>: push 0xa
0x000006e6 <+121>: call 0x500 <putchar@plt>
0x000006eb <+126>: add esp,0x10
0x000006ee <+129>: sub esp,0xc
0x000006f1 <+132>: push DWORD PTR [ebp-0xc]
0x000006f4 <+135>: call 0x4c0 <free@plt>
0x000006f9 <+140>: add esp,0x10
0x000006fc <+143>: nop
0x000006fd <+144>: mov ebx,DWORD PTR [ebp-0x4]
0x00000700 <+147>: leave
0x00000701 <+148>: ret
End of assembler dump.
```
关于 glibc 中的 malloc 实现是一个很重要的话题,我们会在后面的章节详细介绍。

View File

@ -0,0 +1 @@
# glibc malloc

View File

@ -12,5 +12,6 @@
- [1.5.5 静态链接](1.5.5_static_link.md)
- [1.5.6 动态链接](1.5.6_dynamic_link.md)
- [1.5.7 内存管理](1.5.7_memory.md)
- [1.5.8 glibc malloc](doc/glibc_malloc.md)
- [1.6 密码学基础](1.6_crypto_basic.md)
- [1.7 Android 安全基础](1.7_android_basic.md)

1
doc/4.3_gcc.md Normal file
View File

@ -0,0 +1 @@
# GCC 安全编译参数

View File

@ -2,3 +2,4 @@
- [4.1 AWD模式](4.1_AWD.md)
- [4.2 Linux 命令行技巧](4.2_Linux_terminal_tips.md)
- [4.3 GCC 安全编译参数](4.3_gcc.md)

View File

@ -3,3 +3,4 @@
- [5.1 Fuzz 测试](5.1_fuzz.md)
- [5.2 Pin 动态二进制插桩](5.2_pin.md)
- [5.3 angr 二进制自动化分析](5.3_angr.md)
- [5.4 反调试技术](5.4_antidbg.md)