当ELF文件被压缩至57字节

· 2026-09-03 23:39 · 5 阅读

原创 黑鸟 2026-09-03 23:39 广东

在信息安全和逆向工程的圈子里,有一本名叫tmp.0ut的杂志(tmpout.sh),它不登广告,不搞付费墙,全部内容由社区志愿者无偿撰写,主题只有一个,就是把计算机最底层的二进制文件玩出花来。

2026年8月23日,这本杂志发布了第五期,一共收录了21篇技术文章,从Unix先驱Doug McIlroy的独家访谈,到只有57字节的最小ELF可执行文件,再到440字节的变形病毒,内容跨度极大但全部围绕同一个核心,就是理解和操控程序在计算机里最原始的形态。

tmp.0ut这个名字本身就是一个梗,在Linux系统里/tmp是临时目录,0ut谐音out,合起来就是临时输出的意思,暗示这本杂志的内容都是些实验性的、不那么正经但技术含量极高的东西。杂志的排版也极具特色,全部用ASCII艺术字制作标题和目录,在终端里打开就能阅读,这种复古极客风格在2026年显得格外另类。

这一期的作者团队包括bane、blotter、busescanfly、cmex、elfmaster、matheuz、netspooky、qkumba、rqu、sblip、TMZ等十几位社区成员,每个人负责不同的技术方向,有专门研究ELF加载器的,有痴迷于代码混淆的,有做rootkit的,还有负责画ASCII艺术和做混音带的,整体氛围更像是一个技术艺术集体而不是传统意义上的出版物。

这期最重磅的内容之一,是对Doug McIlroy的深度访谈。McIlroy是贝尔实验室的传奇工程师,Unix操作系统的核心贡献者之一,今天每个程序员都在用的管道(pipe)就是他发明的。他在1964年就加入了贝尔实验室,比Unix诞生还早五年,后来还担任了计算机科学研究中心的主任。

访谈中最经典的一个例子,是McIlroy用一行Unix命令统计文本中出现频率最高的单词,这行命令至今仍被当作Unix哲学的典范:

tr -cs A-Za-z "\n" | tr A-Z a-z | sort | uniq -c | sort -rn | sed ${1}q

这行命令的意思是把文本里的单词一个个拆出来,转成小写,排序,统计每个词出现的次数,再按次数倒序排列,最后取前N个。整个过程没有写一行循环或者变量声明,全靠把几个小工具用管道串起来,这就是McIlroy倡导的Unix哲学,每个工具只做一件事但做到极致,然后用管道把它们组合起来完成复杂任务。

对于今天的程序员来说,McIlroy的观点依然有很强的现实意义。他强调简单性和组合性的价值,反对过度设计和复杂框架,这种思想在容器化和微服务盛行的今天反而显得更加珍贵。

只有57字节的x86-64 Linux ELF

ELF是Linux系统下可执行文件的标准格式,一个正常的Hello World程序编译出来至少有十几KB,因为里面包含了ELF头、程序头、动态链接信息、C运行库初始化代码等等。但这篇文章的作者h4x.cz做到了一件极端的事,他手工构造了一个只有57字节的ELF可执行文件,并且能在x86-64 Linux上正常运行。

要理解这有多难,得先知道ELF头本身就有64字节,光一个标准ELF头就已经超过了57字节。作者的做法是重新理解Linux内核加载ELF的实际逻辑,发现内核并不严格校验所有字段,很多字段可以和程序头重叠,甚至可以把代码直接塞进ELF头的空隙里。通过精心布局每一个字节,让ELF头和程序头共享部分空间,同时把机器码嵌入头部保留区域,最终造出了这个理论上最小的可执行文件。

这种探索的价值不在于真的有人需要57字节的程序,而在于它揭示了操作系统加载器的真实行为边界。很多安全产品依赖对ELF格式的标准化理解来检测恶意文件,当攻击者掌握了这些边界知识后,就可以构造出标准解析器无法正确处理但内核却能正常加载的畸形ELF,从而绕过检测。

440字节的变形ELF-64病毒

如果说57字节ELF是对格式极限的探索,那这篇440字节变形病毒就是把这种知识用在了恶意技术上。作者ti3f写了一个只有440字节的ELF-64病毒,而且具备变形(metamorphic)能力,也就是说每次感染新文件时,病毒自身的代码都会发生变化,不会留下固定的字节特征,传统的基于特征码的杀毒软件很难检测到它。

病毒的核心逻辑非常精简,通过creat系统调用创建一个新文件,设置权限为0755,然后把自身代码写进去。整个感染过程不依赖任何外部库,全部用直接系统调用完成,这也是它能做到这么小的原因。变形能力则来自于每次感染时对指令序列的等价替换,比如把mov rax, 85换成不同但功能相同的指令组合,让病毒的字节特征每次都不一样。

这种技术在真实的恶意软件中已经被广泛使用,现代恶意软件几乎都具备某种形式的代码混淆或变形能力,目的就是逃避基于特征的检测。这篇文章展示了即使在440字节这样极端的空间限制下,依然可以实现变形感染,说明特征码检测在面对精心构造的攻击者时是多么脆弱。

PERL Stuff:用关键词洗牌实现的Perl病毒

这篇文章的作者genetix展示了一种非常巧妙的Perl病毒写法。Perl语言有一个特点,就是可以通过符号表在运行时动态调用函数,不需要写死函数名。作者利用这个特性,把Perl的关键字(print、if、else、for、open、close等)存到一个数组里,然后用一个自定义的洗牌函数把数组顺序打乱,再通过索引来引用这些关键字。

这样做的效果是,病毒源码里看不到任何正常的Perl关键字,全是$kw[6]、$kw[5]这样的数组引用,静态分析工具根本无法判断这段代码在做什么。只有在运行时,数组被填充和洗牌后,这些引用才会解析成真正的关键字,病毒逻辑才会显现出来。这种混淆方式利用了语言本身的动态特性,比简单的字符串加密更难检测。

XLAT is All You Need:一条指令搞定解密

XLAT是x86指令集里一条非常古老的指令,全称是translate,作用是用AL寄存器的值作为索引,从一个查找表里取出对应字节放回AL。这条指令在现代编程中几乎没人用了,但作者febnug发现它在代码混淆中有独特的价值。

传统的字符串解密通常用xor指令,decoded = encoded ^ key,这种模式很容易被反病毒软件的启发式检测识别。而用XLAT做解密,本质上是一个字节替换表,把每个加密字节映射到明文字节,从指令序列上看完全不像解密操作,更像是普通的查表操作,因此可以绕过很多针对xor解密模式的检测。

这篇文章的标题"XLAT is All You Need"是在调侃AI领域著名的"Attention is All You Need"论文,暗示在代码混淆这个领域,有时候最古老的指令反而是最有效的武器。

无状态控制流:用标志位、时序和重叠执行代替变量

这是本期最烧脑的文章之一。作者febnug探讨了一个问题,能不能在不使用任何显式状态变量的情况下实现有状态的控制流。答案是可以,通过三种机制的组合。

第一种是利用CPU标志位(FLAGS寄存器),比如用rdtsc指令读取时间戳计数器,取其高低位的异或结果作为随机位,根据这个位设置进位标志CF,然后用条件跳转根据CF的值走不同分支。整个过程不需要任何内存变量,状态完全存在于CPU的标志寄存器里。

第二种是利用时序,通过测量指令执行时间来传递状态信息。第三种是重叠执行,让两段代码在内存中部分重叠,从不同的偏移量开始执行会得到完全不同的指令序列,同一段字节既是代码A又是代码B,取决于CPU从哪个位置开始解码。

这种技术的意义在于,传统的逆向分析依赖于识别变量和状态转移,如果程序的状态完全隐藏在标志位、时序和代码重叠里,逆向工程师几乎无法用常规工具分析程序逻辑。这是一种非常高级的反逆向技术。

把Brainfuck变成ROP编译器,最荒诞的组合

Brainfuck是一门只有8个指令的极简编程语言,以难以阅读和编写著称,通常被当作编程界的行为艺术。ROP(Return-Oriented Programming,面向返回编程)则是一种高级漏洞利用技术,通过拼接程序中已有的代码片段(gadget)来执行任意操作,是绕过数据执行保护(DEP)的经典手段。

作者febnug把这两个看似毫不相干的东西结合在了一起,实现了一个用Brainfuck编写的ROP编译器。核心思路是Brainfuck的每个指令都对应一个特定的ROP gadget序列,比如比较指令对应cmp byte ptr [rbx], 0加上条件跳转,循环对应栈指针的调整。把Brainfuck程序编译成ROP链后,就可以在目标程序的内存中执行,而不需要注入任何新的可执行代码。

这种组合的荒诞之处在于,Brainfuck本身已经足够难写了,用它来写ROP链更是难上加难。但它证明了一个重要的原理,就是任何图灵完备的语言都可以作为ROP的中间表示,这为自动化漏洞利用工具的设计提供了新的思路。

Linux内核如何加载可执行文件的深度解析

这篇文章的作者dominikr深入分析了Linux内核加载ELF文件的完整过程,从execve系统调用开始,到ELF头解析、程序头遍历、内存映射、动态链接、最终跳转到入口点的每一个细节。

文章中一个有趣的发现是,很多标准工具(比如file命令)对ELF头的校验比内核严格得多。作者构造了一个ELF头字段全部非法的文件,file命令报告unknown class 176、illegal endian value 41、illegal version 94,但这个文件在Linux内核里却能正常运行。这说明内核加载器为了兼容性,对很多字段的校验非常宽松,这种差异正是很多反取证技术的基础。

理解内核加载的真实逻辑,对于编写加壳器、反取证工具和恶意软件来说至关重要,因为你可以利用内核和用户态工具之间的认知差异来隐藏文件的真实行为。

多语言ELF文件:既是ELF又是其他格式

polyglot(多语言文件)是指一个文件同时符合多种文件格式的规范,可以被不同的解析器当作不同类型的文件来处理。dominikr在这篇文章中展示了如何构造既是合法ELF可执行文件又是其他格式(比如图片、文档)的多语言文件。

构造的关键在于利用不同格式对文件偏移和字段的不同要求。ELF文件要求前4字节是0x7F"ELF",而很多其他格式的头部有自己的魔数,通过精心布局,可以让同一个文件在偏移0处满足ELF的要求,同时在其他偏移处满足另一种格式的要求。

这种技术在反取证中有广泛应用,攻击者可以把恶意ELF文件伪装成一张图片上传到目标系统,因为图片检查工具看到的是一张正常图片,但Linux内核却能把它当作可执行文件运行。

halfexec、halfshelf和phork:三个ELF加载器实验

这期有三篇文章来自作者TMZ,构成了一个关于自定义ELF加载器的系列。halfexec是一个完全用汇编写的x64 ELF Linux加载器,它不依赖系统的动态链接器,自己完成ELF文件的解析、映射和重定位。

halfexec加载器运行调试输出,作者TMZ

halfshelf则更进一步,探讨了一个极端场景,如果ELF文件的头部已经被覆盖或删除了,还能不能加载这个文件。答案是可以,只要你知道程序在内存中的布局信息,可以通过load_bias(加载基址)加上image_virtual_address(镜像虚拟地址)来计算运行时地址,从而在没有头部的情况下完成加载。

phork是这个系列的第三篇,解决的是把halfshelf加载的分散ELF片段重新打包回单个ELF文件的问题。它提供了一个mkpack工具,可以把存根ELF和输入的SHELF ELF打包成一个输出文件,支持对元数据和载荷进行XOR加密。这三个工具组合起来,构成了一套完整的自定义ELF加载、碎片化和重新打包的工具链。

phork工具的概念图,把SHELF打包回单个ELF,作者TMZ

基于可达性分析的自提取

作者r3s1stanc3在这篇文章中探讨了Java ClassFile格式下的自提取技术。核心思路是利用Java的Class-File API对类文件进行可达性分析,找出所有被实际引用的类和方法,然后只复制这些被引用的部分,去掉未使用的代码,从而实现一个最小化的自提取包。

这种技术和传统的加壳器不同,传统加壳器是把整个程序加密压缩后加一个解压存根,而可达性分析是在理解程序结构的基础上进行精简,提取出来的包更小,也更难被分析,因为它只包含运行时真正需要的代码路径。

代码虚拟化概述,最强大的反逆向技术

代码虚拟化(code virtualization)是目前商业软件保护中最强大的反逆向技术之一,VMProtect、Themida等商业保护壳的核心就是代码虚拟化。作者patate在这篇文章中从底层原理出发,详细解释了代码虚拟化是如何工作的。

虚拟化的基本思路是把原始的x86指令转换成一套自定义的虚拟机指令,然后在程序运行时由一个内嵌的虚拟机解释执行这些自定义指令。因为虚拟机指令集是每个保护壳私有的,而且每次保护生成的指令编码都不一样,逆向工程师无法用标准的反汇编工具来分析被虚拟化的代码,必须先逆向出整个虚拟机的指令集和解释器逻辑,这是一个极其耗时的过程。

文章展示了虚拟机上下文结构的汇编实现,包括保存所有通用寄存器(rax、rcx、rdx、rbx、rsp、rbp、rsi、rdi以及r8到r15)到VM上下文结构,保存标志寄存器,用fxsave指令保存XMM寄存器。这些细节展示了一个完整的虚拟机需要保存和管理多少CPU状态,也解释了为什么虚拟化后的代码运行速度会变慢,因为每条原始指令都要经过解释器的层层转换。

对于恶意软件来说,代码虚拟化是保护核心逻辑不被逆向分析的终极手段。很多高级恶意软件会对关键功能(比如C2通信协议、加密算法)进行虚拟化保护,使得安全研究人员需要花费数周甚至数月才能还原出原始逻辑。

侧信道检测系统调用钩子和细粒度ASLR

用侧信道检测系统调用钩子

系统调用钩子(syscall hooking)是rootkit和安全软件常用的技术,通过修改系统调用表来拦截和监控操作系统的系统调用。传统的检测方法是检查系统调用表的地址是否指向内核的合法区域,但现代rootkit会用更隐蔽的方式来挂钩,比如内联钩子(inline hook),直接修改系统调用函数的前几条指令,这种方法很难通过简单的地址检查发现。

作者PinkNoize提出了一种基于侧信道的检测方法。核心原理是CPU的指令缓存(instruction cache)行为可以泄露代码是否被修改过。当一段代码被执行过后,它会被加载到指令缓存中,如果之后这段代码被修改了(比如被内联钩子替换了前几条指令),再次执行时的缓存行为会和未修改时不同。通过精确测量执行时间,可以检测到这种缓存行为的差异,从而发现隐藏的系统调用钩子。

这种方法的巧妙之处在于它不直接检查代码内容,而是利用CPU微架构的副作用来检测篡改,对于那些会主动反制检测工具的rootkit来说,这种被动的侧信道检测更难被规避。

细粒度加载时ASLR

ASLR(Address Space Layout Randomization,地址空间布局随机化)是现代操作系统的基础安全防护机制,它通过随机化程序加载的基址来增加漏洞利用的难度。但传统的ASLR只随机化整个程序的加载基址,程序内部各个函数和数据之间的相对偏移是固定的,攻击者只要泄露一个地址就能推算出所有其他地址。

作者elfmaster开发了一个名叫shiva的工具,实现了细粒度的加载时ASLR。它在程序加载时对每个函数、每个数据段进行独立的随机化重排,使得程序内部的相对偏移也变得不可预测。这样即使攻击者泄露了一个函数的地址,也无法推算出其他函数的位置,大大增加了ROP攻击和代码重用攻击的难度。

这种细粒度随机化的代价是加载时间会变长,因为加载器需要对程序进行重新链接和重定位,但对于高安全需求的场景来说,这种性能开销是值得的。shiva的源码托管在GitHub上,地址是github.com/advanced-microcode-patching/shiva。

静态内核补丁、RDOFF病毒和二进制高尔夫

静态内核补丁Redux

作者bah在这篇文章中探讨了对Linux内核进行静态补丁的技术。静态补丁是指在内核镜像运行之前就修改其二进制内容,而不是在运行时动态挂钩。这种技术的好处是补丁更加持久,不容易被运行时检测发现,但难度也更大,因为需要直接修改内核的压缩镜像。

文章使用了vmlinux-to-elf工具,把压缩的bzImage内核镜像转换成可分析的ELF文件,然后在ELF层面进行补丁修改,最后再转换回去。这种方法可以用来在内核中植入后门、禁用安全机制或者添加自定义功能,是高级持续性威胁(APT)攻击中常见的技术。

复活RDOFF格式,第二部分:RDOFF病毒

RDOFF是一种非常古老的目标文件格式,曾经是NASM汇编器的默认输出格式,现在几乎已经被淘汰了。作者netspooky专门做了一个系列来复活这种格式,第一部分介绍了RDOFF的格式细节,这一期的第二部分则展示了如何编写一个感染RDOFF文件的病毒。

研究废弃格式的意义在于,很多安全工具和分析器已经不再支持这些格式,如果攻击者使用这些格式来分发恶意软件,大多数检测工具会直接忽略它们。这种利用安全盲区的策略在真实攻击中已经出现过,比如用非常古老的可执行格式来绕过现代防护。

BGGP6回顾:二进制高尔夫比赛

BGGP(Binary Golfing Grand Prix)是一个二进制高尔夫比赛,参赛者需要用尽可能少的字节来实现特定功能的程序。这篇文章回顾了第六届BGGP比赛的精彩作品,展示了各种令人惊叹的极限优化技巧。

文章中一个有趣的例子是用C语言的宏定义来实现数字,比如#define six (6),然后通过six的加减乘除来构造其他数字,最终用宏展开生成整个程序。这种写法完全是为了在源代码层面制造混淆,同时在编译后生成极小的二进制。

二进制高尔夫虽然看起来像是一种极客游戏,但它所发展的优化技巧和对程序格式的深入理解,直接推动了加壳器、反取证和恶意软件技术的进步。很多在比赛中诞生的技巧,几年后就会出现在真实的恶意软件中。

剩下的几篇和杂志文化

除了上面详细介绍的文章,这一期还有几篇值得一提。第16篇基于可达性分析的自提取我们已经在ELF加载部分介绍过了。第21篇是blotter制作的tmp.0ut 5混音带,这是一本技术杂志附赠的音乐合集,可以在SoundCloud上收听,风格偏向电子和实验音乐,体现了这本杂志的社区文化属性。

第1篇是编辑部引言,介绍了这一期的团队成员和制作过程。第5篇Perl病毒、第6篇XLAT解密、第7篇无状态控制流、第8篇Brainfuck ROP编译器都来自作者febnug,一个人贡献了四篇文章,是这一期最高产的作者,而且四篇文章都围绕代码混淆这个主题,形成了一个完整的技术体系。

整体来看,tmp.0ut第5期是一本技术密度极高的杂志,21篇文章覆盖了ELF格式、代码混淆、病毒技术、反向工程、内核安全、加载器设计等多个底层安全领域。对于安全从业者来说,这本杂志是了解最新地下技术趋势的重要参考;对于普通技术爱好者来说,它展示了计算机底层世界的无限可能性,让你意识到那些看似固定不变的文件格式和系统机制,其实充满了可以被探索和利用的边界。

跳转微信打开