目录
基本编译链接流程
- 编译并输出汇编代码
- g++ -S lib.cpp -o lib.s
- 打包成ELF可重定位文件 ELF TYPE= ET_REL 即.o文件
- g++ -c lib.s -o lib.o
- 链接到动态库或者可执行文件
- g++ lib.o -o a.out
- g++ -shared lib.o -o a.out
我总觉得对你的爱很美
-rdynamic
-fpic (position-independent code) 编译选项和链接选项
-fPIC 编译选项和链接选项
-fpic与-fpie的差别很细微,当使用-fpie时编译器知道当前的编译会生成一个PIC模式的 main executable(也就是有main入口的可执行文件),这样对于内部定义的global符号,就不 要考虑全局符号介入(global symbol interpose)的问题,对于这样的globals直接产生 PC-relative方式的代码而不需要通过GOT/PLT. –Ian Lance Taylor
-fPIE 编译选项
-pie 链接器选项
其他备注
-no-pie 新版本g++比如6版本 默认启用pie 如不需要则要显式去除
-fno-plt
-fno-jump-tables
动态库查找路径
–static 组织在链接时使用动态库
–shared 生成动态库
–static-libgcc 链接静态libgcc库
–shared-libgcc 链接动态libgcc库
-static和-shared可以同时存在 这样会创建共享库 但该共享库引用的其他库会静态地链接到该共享库中
dlopen动态load共享库
- [使用elf hash获取符号所在的偏移地址](#使用elf-hash获取符号所在的偏移地址)
- [结论](#结论)
ELF的哈希表提供了对符号表的访问
组织结构如下:
labels |
---|
nbucket |
nchain |
bucket[0] |
… |
bucket[nbucket-1] |
chain[0] |
… |
chain[nchain-1] |
(Executable and Linking Format) (可执行可链接格式) 文件
可重定位文件 (relocatable file)
共享目标文件(shared object file),即动态连接库文件 它在以下两种情况下被使用
可执行文件(executable file),经过连接的,可以执行的程序文件。
coredump文件 核心转储
top命令
sar 系统活动情况报告 追溯统计数据 从最近的0点0分开始显示数据
df 查看当前硬盘存储
IPC资源查询
ulimit -a 配置位置 /etc/security/limits.conf
全局线程总数
单个进程最大线程数 PTHREAD_THREADS_MAX 新的NPTL实现中不存在该限制
whereis 查看命令所在位置
lsof [文件/路径] 查看占用该文件/该目录下文件的进程
lsof -i 查看当前活动的网络连接 包括TCP / UDP
lsof -p [pid] 查看当前进程所有打开的文件/设备
ulimit -s 栈大小
64位下的linux地址空间虽然看起来虽然庞大2^64 但是实际上进行内核与用户空间的划分后, 包括ASLR以及PIE等机制的启用, 实际留给mmap和brk的可分配区域远远小于这个值, 大约是42T的可用地址空间. 本文根据内核代码的默认宏定义进行了X86-64下的布局分析, 给基于共享内存的用户空间选址给予一定的参考.
针对X86-64内核代码的分析
- | - |
---|---|
内核地址空间范围 | [0XFFFF 0000 0000 0000, 0XFFFF FFFF FFFF FFFF] |
用户地址空间 | [0X0000 7FFF FFFF F000, 0X0000 0000 0000 0000] |
不规范地址空间 | 不属于内核或者用户的地址空间属于不规范地址空间 |
用户空间的大小由宏定义TASK_SIZE决定, 在X86-64下这个大小默认为2^47-4096(128T) 对应十六进制数为: 0X0000 7FFF FFFF F000 .
- 用户空间布局 - |
---|
0x0 |
保留区 |
代码段(PLT代码表部分) |
代码段 |
数据段(GOT) 只读 |
数据段(.got.plt) 惰性加载机制 |
数据段(Data) |
数据段(BSS) |
堆空间(Heap) |
↓ |
未分配区域 |
↑ |
内存映射区域(mmap) |
栈空间(进程栈) |
TASK_SIZE |
地址空间配置随机加载(英语:Address space layout randomization,缩写ASLR,又称地址空间配置随机化、地址空间布局随机化)是一种防范内存损坏漏洞被利用的计算机安全技术。
ASLR通过随机放置进程关键数据区域的地址空间来防止攻击者能可靠地跳转到内存的特定位置来利用函数。现代操作系统一般都加设这一机制,以防范恶意程序对已知地址进行Return-to-libc攻击。
这些数据区域一般包括代码段 数据段 堆区 栈区 mmap 动态库等, 其中涉及代码段的随机一般需要代码位置无关化的支持(PIC PIE机制)
不同版本的操作系统和内核版本, 在ASLR的实现上会有细节的不同, 这里主要是根据目前的生产环境做的分析, 用于确认ASLR的在地址空间中对内存布局带来的扰动范围.
LINUX下常见的设置或关闭有方式:
随机化虚拟地址空间的配置说明如下:
1 | /proc/sys/kernel/randomize_va_space |
echo 0 > /proc/sys/kernel/randomize_va_space
1 |
|
sysctl -w kernel.randomize_va_space=0
1 |
|
关闭ASLR:
set disable-randomization on
开启ASLR:
set disable-randomization off
查看:
show disable-randomization
1 |
|
2^47-4096 => 0x7fff ffff f000 约为128T
1 | gdb调试程序默认会关闭aslr, 我们通过gdb运行一个程序, 然后对齐pmap可以得到如下内存分布: |
00007ffff7ffc000 4K r—- ld-2.27.so
00007ffff7ffd000 4K rw— ld-2.27.so
00007ffff7ffe000 4K rw— [ anon ]
00007ffffffde000 132K rw— [ stack ]
ffffffffff600000 4K r-x– [ anon ]
1 |
|
随机值大小为17G = 0x3fffff000
代码位置如下:
load_elf_binary -> setup_arg_page
1 | retval = setup_arg_pages(bprm, randomize_stack_top(STACK_TOP), |
1 | #define __STACK_RND_MASK(is32bit) ((is32bit) ? 0x7ff : 0x3fffff) |
1 | load_elf_binary -> setup_new_exec -> arch_pick_mmap_layout ->arch_pick_mmap_base |
mmap的起始计算为:
STACK_TOP - 栈最大长度 - 间隙 - 随机值
栈最小长度为128M
随机位数配置在/proc/sys/vm/mmap_rnd_bits default=28
默认随机最大值为 0xFFFFFFF000 大约为1T
用户空间起始地址0x7FFFFFFFF000
1 |
|
ELF文件如果是普通的EXEC类型则会使用指定的入口地址下面讨论PIE编译出的DYN可执行文件
其加载地址为 DEFAULT_MAP_WINDOW /32上增加一个arch_mmap_rnd随机值
DEFAULT_MAP_WINDOW /32 = 0x555555554AAA
同mmap一样为 0x00FFFFFFF000 约1个T大小
代码段起始位置约为84T 随机值 1T
代码段数据段等整体随机
1 | if (interpreter) { |
1 | loc->elf_ex.e_entry += load_bias; |
brk从BSS结束地址开始, 会有一个额外的随机arch_randomize_brk
为固定的大小范围0x02000000, 大约为33M
1 | if ((current->flags & PF_RANDOMIZE) && (randomize_va_space > 1)) { |
1 | unsigned long arch_randomize_brk(struct mm_struct *mm) |
假定编译出来的是PIE类型的ELF并且全开ASLR设置
那么在mmap和heap之间的地址空间大小大约是
128T - 17G - 1T - 84T - 1T -33M = 42T
mmap最小起始地址略小于0x0000 7F00 0000 0000
brk起始地址最大略大于 0x0000 5655 5555 5555
这个是以T为单位的粗略计算, 考虑到计算时忽略了一些小的单位(GB级别或者更小), 包括间隙 小的随机值, 以及动态库 数据段代码段本身占用的空间, 这里可以做一个进一步的保守计算来使用这个空间.
计算这个空间的意义在于, 例如我们对共享内存使用一个固定的地址时, 需要避免和系统本身的动态分配的地址空间相冲突, 而计算出来的地址空间的确定可以保证这一点, 例如可以用这两个地址做一个中值计算, 把这个中值作为安全的绝对地址使用.
1 | 0000000000400000 4K r-x-- a.out (deleted) |
1 | 00005640b5092000 4K r-x-- a.out |
在认知心理学中, 问题解决的思维过程被描述为: 在问题空间下, 经过思考与推理, 达到目的的心理历程.
该过程分为四个阶段
其中问题空间(问题域)是指问题解决者对所要解决的问题的一切可能的认识状态, 包括对问题的初始状态和目标状态的认识, 以及如何从初始状态转化为目标状态的认知操作等.
问题的解决就是对问题空间进行搜索, 找到一条从问题的初始状态到达目标状态的通路.
在这个过程中, 每个过程的推进都可能会伴随对其前向的阶段所做的处理发起修正, 在此过程中我们会不断的逼近’真正的问题’的问题定义, 以及’真正的问题解决’的结果, 从而采用形式化的方法寻找到最优的解决路径
空间K维划分, 用来快速寻找距离最近的障碍(指定数量) 优化RVO的资源消耗.
DIJKSTRA 最短路径 等寻路方法
VO RVO ORCA等Obstacle Avoidance避障算法
这个是一个简单的KDTREE实现 用来寻找距离最近的障碍(指定数量) 优化RVO的资源消耗.
核心思想: 只要在未来有可能会发生碰撞的速度 都排除在外
抖动现象: 两个位移单位存在可能会发生路径碰撞的情况下会同时采取保守的避让速度,导致新速度偏离过大又大幅度回归,从而产生震荡.
核心思想: 优化VO思想, 假定对方也会采取避障行为, 缩小(average VO)速度.
核心思想: 优化RVO, 额外考虑速度大小, 求解过程使用线性规划,更高效简洁.