pwn_21前置知识延迟绑定程序里可能会定义了很多库函数但是实际运行的时候只用到一部分但是如果程序已启动就将所有的函数地址解析出来会拖慢启动速度延迟绑定只解析真正用到的函数让程序启动的更快。库函数的真实地址在不同系统、不同 libc 版本里可能不一样延迟绑定让程序在运行时自动适配当前环境的库地址不用重新编译Partial RELRO部分保护GNU_RELRO是 Linux 下RELRORelocation Read-Only重定位只读保护机制的具体实现当程序第一次调用函数的时候动态链接器要把解析好的真实地址写入.got.plt因为如果是只读的那么第一次调用程序的时候动态链接器基于没有办法往里面写入地址程序就会崩溃。所以就把.got此乃全局地址启动时就解析完之后就永不修改设为只读把.got.plt存函数地址运行时修改为可写。同时呢Partial RELRO会「重排敏感节」链接器会把.got、.dynamic这类敏感的重定位 / 链接器数据节重排到.data、.bss这类普通可写数据段的前面。防止缓冲区溢出直接覆盖.got。readelf工具readelf 是 Linux 下专门解析 ELF 文件可执行文件、动态库.so、静态库.a、目标文件.o的工具-S参数看「节Sections」小模块节readelf -S pwn输出.got/.got.plt 的地址、权限WA/R—— 判断是否可写用于 GOT 劫持。-l参数看「程序头Segments」内存块也就是段read -l pwn输出代码段 / 数据段的加载地址、权限R E/R W—— 判断内存块的基础权限。这里下面的编号mapping是与上面的块程序头对应的所以可以通过这个看权限有时候会遇到一个节被分在不同的段中此时选择权限较为少的为依据就像一个可读可写一个可读就认为是可读-h参数查看ELF基础信息-s参数看「符号表」找函数 / 变量地址-d参数看动态链接信息readelf的过滤 grep-E支持多关键词用|分隔、扩展正则-i忽略大小写比如匹配Got/GOT都能命中-A n显示匹配行后 n 行比如找映射表时用-B n显示匹配行前 n 行比如找段权限时用-w精确匹配单词避免匹配到.got.plt时带出.got无关行场景一过滤关键 Section找 .got/.plt/.text 等目标从readelf -S输出里只看.got/.got.plt/.plt/.text快速找地址 / 权限# 方法1多关键词过滤推荐 readelf -S pwn | grep -E got|plt|text ​ # 方法2精确匹配 .got.plt避免带出 .got readelf -S pwn | grep -w .got.plt场景 2过滤 Segment 权限找 LOAD/GNU_RELRO/GNU_STACK目标从readelf -l输出里只看核心段的权限R/W/E# 过滤 LOAD 段代码段/数据段 GNU_RELRO GNU_STACK readelf -l pwn | grep -E LOAD|GNU_RELRO|GNU_STACK等等。。。段与节节编译器 / 链接器对 ELF 文件的「逻辑小模块划分」属于编译器gcc/ld是 “开发者视角” 的划分粒度细一个 ELF 有几十甚至上百个 Section比如.text/.plt/.got都是独立 Section段操作系统加载 ELF 时的「内存大区块划分」属于操作系统内核 / 动态链接器是 “执行器视角” 的划分粒度粗一个 ELF 只有几个 Segment通常 8~10 个比如 LOAD/RELRO/STACK 等解题通过上面的讲解相信你已经发现了端倪上两图就是题中截图。为什么当开了 Partial RELRO 之后查看节是是可读可写但是呢查看段却发现是 可读不可写。这是因为熬我大彻大悟了所以你之前也说程序内存什么的只认识段而不认识节节是编译的产物但是的段是真实寄存器什么识别的他们是靠这个区别程序的每一部分然后呢这个GNU_RELRO也就是改的段然后导致我们看节时可读可写的然后呢看段时只读的。那我们看节还有用吗关键就只是看段了有用当然有用看节可以准确的定位带.got.plt和.got的这些节的具体位置用来分析文件结构比如.rodata只读常量比如字符串RELR.data初始化全局变量.bss未初始化全局变量文件里不占空间运行时分配这些都是 Section 层面的信息Segment 只会把它们打包成 “数据段”不会告诉你细节。pwn_22前置知识Full RELRO全保护在 Full RELRO 模式下程序放弃了延迟绑定转而使用立即绑定。在程序加载的一瞬间动态链接器会强制把所有外部函数的真实地址全部找齐并填入 GOT 表。填完之后立即将整个 GOT 区域的内存属性改为只读。若是强行写入数据会使程序崩溃。在这种模式下.got.plt通常会被合并到.got中或者直接标记为不可写解题readelf -S pwn发现.got.plt被写入到.got里了readelf -l pwn果然没有没有写入权限pwn_23前置知识C语言基础signal(11hander)函数注册一个处理函数这里的参数11就是要捕捉的信号这个信号是SIGSEGV段错误第二个参数是一个函数指针指向预先处理好的hander函数。这样的话当程序发生 段错误 的时候就会暂停当前代码跳转至hander,而不是内核直接杀死程序。这里的信号本身并没有特别的意思他只是一个编号他代之的是“段错误”SIGSEGV这一特定事件。通知编号 2 (SIGINT)意味着“用户按了 CtrlC请中断”。通知编号 9 (SIGKILL)意味着“立刻结束进程不得有误”。通知编号 11 (SIGSEGV)意味着“进程访问了非法内存地址发生了段错误”main函数的参数argc和argv在 C 语言中main函数的标准原型通常是int main(int argc, char *argv[]);argc表示命令行中参数的数量包括程序本身的名字比如说./pwn hello world那么此时argc就等于3argv是一个字符串数组存储每个参数的内容。argv[0]此时就是程序的名字那么argv[1]就是第一个参数argv[argc]是NULL给main()函数传参的时候就直接加在程序后面就可以了strcpy()危险函数strcpy(dest, src)strcpy是 C 语言标准库中的一个函数讲src字符串复制到dest字符串。strcpy函数不会检查目标缓冲区的大小它会一直复制直到遇到源字符串的结尾\0。它不接收目标缓冲区长度参数完全依赖源字符串的结束符。就极易造成缓冲区溢出进而导致程序崩溃或被利用执行任意代码解题讲程序拖入ida中后阅读代码这里阅读了之后很容易就明白了我们要传一个很大很大的参数参数要大过dest数组还有EBP的4个字节然后这个时候就可以覆盖到返回地址此时就会引发程序的崩溃。所以传入一个大大大大大大大大的参数./pwn aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa得到flag师承一只枷锁如有错误希望多多指教