尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

patchkit源码剖析一:ELF段手术的秘密——如何为可执行文件添加RWX与JIT段

patchkit源码剖析一:ELF段手术的秘密——如何为可执行文件添加RWX与JIT段 patchkit源码剖析一ELF段手术的秘密——如何为可执行文件添加RWX与JIT段【免费下载链接】patchkitbinary patching from Python项目地址: https://gitcode.com/gh_mirrors/pa/patchkitpatchkit 是一个binary patching from Python的开源二进制补丁工具你用几个简单的 Python 脚本就能给 ELF 可执行文件打补丁——注入汇编、替换函数、Hook 入口点。本文是源码剖析系列的第一篇带你钻进 patchkit 最核心的一刀ELF 段手术看它是如何为一个可执行文件凭空添加 RWX 段、JIT 段让注入的代码有家可住。一、为什么二进制补丁工具都要动段普通可执行文件的代码段.text是只读的而且空间塞得满满当当。当你想往二进制里塞一段新代码时会撞上三堵墙难题后果代码段只读直接覆写会崩溃没有空闲空间注入的代码无处安放C 函数需要符号解析编译出来的函数互相调用找不到地址patchkit 的答案非常干脆在程序的虚拟地址空间末尾预先圈地添加四个全新的可加载段PT_LOAD。这就是本文要解剖的手术。二、手术核心new_segment() 一次创建 RWX 段一切发生在Binary类的初始化里。patchkit 先倒序扫描所有可加载段找出整个镜像的末尾地址end见 core/binary.pyfor ph in reversed(self.elf.progs): if ph.isload: start min(start, ph.vaddr) end max(ph.vaddr ph.vsize, end)然后用一个new_segment(addr)闭包完成手术core/binary.py关键动作只有五步页对齐vaddr (addr 0xFFF) ~0xFFF把段起始地址向上取整到 4KB 页边界类型ph.type PT[PT_LOAD]告诉操作系统的加载器这块要映射进内存权限ph.flags 7即PF_R | PF_W | PF_X—— 可读、可写、可执行的RWX 段权限位定义见 util/elffile.py初始为空memsz filesz 0段先挂空挡后面用到才填充登记self.elf.progs.append(ph)塞进程序头表。短短十几行一个 RWX 段就长在了原文件的虚拟地址空间之后。三、段四件套patch / nx / link / jit真正精彩的是紧接着的四连击core/binary.pyself.patch new_segment(end) self.nxpatch new_segment(end 0x800000) self.nxpatch.flags 6 self.linkpatch new_segment(end 0x1600000) self.jitpatch new_segment(end 0x2400000) 四个段各守一块独立地址区间互不干扰段名起点相对 end权限用途patch0RWX (7)默认注入区汇编、钩子代码的停车场nxpatch8 MB (0x800000)RW (6)不可执行的数据区存放运行时被读写的字节linkpatch22 MB (0x1600000)RWX (7)链接器编译出的 C 函数落地区jitpatch36 MB (0x2400000)RWX (7)JIT 段留给运行时动态改写代码的专属区设计思路值得借鉴先圈好带权限的地盘按用途分区。_seg()方法把用户友好的名字映射到具体段core/binary.pypatch、nx、link、jit四个名字从此贯穿整个 API。四、代码如何住进段里next_alloc 与 alloc有了地盘注入就是登记入住。Binary提供两个极简接口core/binary.pynext_alloc(target)返回段当前末尾地址vend vaddr memsz定义在 util/elffile.py即下一个空闲位置alloc(size, target)在段数据尾部追加size个零字节同时累加memsz和filesz段长高。补丁脚本里的一句pt.inject(asmmov eax, 1; ret)底层正是这条链路inject()按target参数默认patch取地址 → 编译 →alloc()预留空间 →elf.write()把机器码写进段数据core/context.py。写入时 ELF 层会自动定位该虚拟地址落在哪个 PT_LOAD 段内util/elffile.py保证绝不越界。 顺带一提patchkit 还能做微创make_writable()会在打补丁前临时给原代码段加上写权限位core/context.py打完补丁权限留在文件里由加载器执行——同样是改段标志位但动的是原有段。五、JIT 段给活代码留的后门为什么专门留一个jitpatch普通注入的代码在落盘后就不再变化而自修改代码、动态解密、运行时生成的代码需要程序跑起来之后还能改写它——这正是 RWX 属性的意义。JIT 段就为此而生targetjit的注入与分配全部落在 36 MB 偏移的独立区间与默认 patch 区物理隔离运行时改写互不污染。CGC 混淆样本 samples/cgc/obfuscate/01_jit_xor.py 展示了这类玩法把每个函数用 XOR 加密、函数头换成跳板程序运行时先解密再跳回原函数——自修改代码的需求最终都指向 RWX 段的存在。六、保存时刻裁剪段、收紧权限手术做完落盘前还有两个收口动作core/binary.py去执行位self.nxpatch.flags ~1nxpatch 段强制保持不可执行多一道保险裁掉空段遍历四个新段凡filesz 0从没注入过东西的直接从程序头表移除——你没用的段不会出现在最终文件里输出二进制保持精瘦。随后调用elf.save(path)落盘。elffile 库打包时重排整个文件布局文件头 → 各段数据 → 段数据 → 段头并为每个新段计算文件偏移严格满足offset % align vaddr % align的 ELF 对齐约束util/elffile.py。最后chmod 0755补丁完成。七、一分钟上手体验git clone https://gitcode.com/gh_mirrors/pa/patchkit cd patchkit ./deps.sh # 自动安装 Capstone / Keystone / Unicorn然后参照 README.md 的用法patch binary patchdir|file补丁目录里的每个.py文件按字母序执行其中每个顶层函数都会收到一个pt补丁上下文pt.inject()、pt.patch()、pt.hook()三板斧随便使驱动逻辑见 core/patcher.py。总结patchkit 的 ELF 段手术可以浓缩成一句话在原镜像末尾圈出 patch / nx / link / jit 四块独立地盘按需填充、用完即裁。RWX 段解决代码住哪NX 段解决数据存哪JIT 段解决运行时改写——麻雀虽小权限设计俱全。下一篇我们将拆解注入与 Hook 的完整链路inject()的双级驱逐机制以及 Linker 如何把 C 函数链接进二进制。【免费下载链接】patchkitbinary patching from Python项目地址: https://gitcode.com/gh_mirrors/pa/patchkit创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表