第三章 计算机病毒结构分析本章学习目标
掌握计算机病毒的结构
掌握计算机病毒的工作机制
了解引导型病毒原理
了解 COM,EXE,NE,PE可执行文件格式
掌握 COM文件病毒原理及实验
掌握 PE文件型病毒及实验总体概念
DOS是 VXer的乐园 (Aver)
9x病毒 ring3,ring0
2K病毒 主要是 ring3
Windows文件格式变迁:
– COM
– EXE:MZ->NE->PE
– Vxd,LE(16Bit,32Bit)
一,计算机病毒的结构和工作机制
四大模块:
– 感染模块
– 触发模块
– 破坏模块(表现模块)
– 引导模块(主控模块)
两个状态:
– 静态
– 动态工作机制动 态静 态引 导 模 块病 毒 感 染病 毒 破 坏触 发 模 块满 足 触 发 条 件满 足 破 坏 条 件携 毒 潜 伏 或 消 散携 毒 潜 伏 或 消 散满 足满 足不 满 足不 满 足引导模块
引导前 ——寄生
– 寄生位置:
引导区
可执行文件
– 寄生手段:
替代法(寄生在引导区中的病毒常用该法)
链接法(寄生在文件中的病毒常用该法)
引导过程
– 驻留内存
– 窃取系统控制权
– 恢复系统功能
引导区病毒引导过程
– 搬迁系统引导程序 -〉 替代为病毒引导程序
– 启动时 -〉 病毒引导模块 -〉 加载传染、破坏和触发模块到内存 -〉 使用常驻技术
– 最后,转向系统引导程序 -〉 引导系统
文件型病毒引导过程
– 修改入口指令 -〉 替代为跳转到病毒模块的指令
– 执行时 -〉 跳转到病毒引导模块 -〉 病毒引导模块 -〉 加载传染、破坏和触发模块到内存 -〉
使用常驻技术
– 最后,转向程序的正常执行指令 -〉 执行程序感染模块
病毒传染的条件
– 被动传染(静态时)
用户在进行拷贝磁盘或文件时,把一个病毒由一个载体复制到另一个载体上。或者是通过网络上的信息传递,把一个病毒程序从一方传递到另一方。这种传染方式叫做计算机病毒的被动传染。
– 主动传染(动态时)
以计算机系统的运行以及病毒程序处于激活状态为先决条件。
在病毒处于激活的状态下,只要传染条件满足,病毒程序能主动地把病毒自身传染给另一个载体或另一个系统。这种传染方式叫做计算机病毒的主动传染。
传染过程
– 系统(程序)运行 -〉 各种模块进入内存 -〉 按多种传染方式传染
传染方式
– 立即传染,即病毒在被执行的瞬间,抢在宿主程序开始执行前,立即感染磁盘上的其他程序,然后再执行宿主程序。
– 驻留内存并伺机传染,内存中的病毒检查当前系统环境,在执行一个程序、浏览一个网页时传染磁盘上的程序,驻留在系统内存中的病毒程序在宿主程序运行结束后,仍可活动,直至关闭计算机。
文件型病毒传染机理
– 首先根据病毒自己的特定标识来判断该文件是否已感染了该病毒;
– 当条件满足时,将病毒链接到文件的特定部位,并存入磁盘中;
– 完成传染后,继续监视系统的运行,试图寻找新的攻击目标。
文件型病毒传染途径
– 加载执行文件
– 浏览目录过程
– 创建文件过程破坏模块
破坏是 Vxer的追求,病毒魅力的体现
破坏模块的功能
– 破坏、破坏、还是破坏 ……
破坏对象
– 系统数据区、文件、内存、系统运行速度、磁盘,CMOS、主板和网络等。
破坏的程度触发模块
触发条件
– 计算机病毒在传染和发作之前,往往要判断某些特定条件是否满足,满足则传染或发作,否则不传染或不发作或只传染不发作,
这个条件就是计算机病毒的触发条件。
触发模块的目的是调节病毒的攻击性和潜伏性之间的平衡
– 大范围的感染行为、频繁的破坏行为可能给用户以重创,但是,
它们总是使系统或多或少地出现异常,容易使病毒暴露。
– 而不破坏、不感染又会使病毒失去其特性。
– 可触发性是病毒的攻击性和潜伏性之间的调整杠杆,可以控制病毒感染和破坏的频度,兼顾杀伤力和潜伏性。
病毒常用的触发条件
日期触发
时间触发
键盘触发
感染触发
– 例如,运行感染文件个数触发、感染序数触发、感染磁盘数触发、感染失败触发等。
启动触发
访问磁盘次数触发
CPU型号 /主板型号触发二,16位操作系统病毒编制技术
1 引导型病毒编制原理
2 COM,EXE,NE文件结构及运行原理
3 COM文件病毒原理
1 引导型病毒编制原理
PC引导流程加电 CPU\BIOS初始化 POST自检 引导区、分 区表检查 发现操作系统执行引导程序引导区病毒取得控制权的过程:
MBR和分区表装载
DOS引导区运行 DOS
引导程序加载 IO.sys
MSDOS.sys 加载DOS
1 正常的引导过程引导型病毒从软盘加载到内存寻找 DOS
引导区的位置将DOS引导区移动到别的位置病毒将自己写入原DOS引导区的位置
2 用被感染的软盘启动
MBR和分区表将病毒的引导程序加载入内存运行病毒引导程序病毒驻留内存原DOS引导程序执行并加载DOS系统
3 病毒在启动时获得控制权
2COM\EXE\NE文件结构及运行原理
COM格式
– 最简单的可执行文件就是 DOS下的以 COM(Copy Of
Memory)文件。
– COM格式文件最大 64KB,内含 16位程序的二进制代码映像,没有重定位信息。
– COM文件包含程序二进制代码的一个绝对映像,也就是说,为了运行程序准确的处理器指令和内存中的数据,DOS通过直接把该映像从文件拷贝到内存来加载 COM程序,系统不需要作重定位工作。
加载 COM程序
– DOS尝试分配内存。因为 COM程序必须位于一个 64K的段中,所以 COM文件的大小不能超过 65,024( 64K减去用于 PSP的 256字节和用于一个起始堆栈的至少 256字节)。
– 如果 DOS不能为程序、一个 PSP、一个起始堆栈分配足够内存,
则分配尝试失败。
– 否则,DOS分配尽可能多的内存(直至所有保留内存),即使
COM程序本身不能大于 64K。
– 在试图运行另一个程序或分配另外的内存之前,大部分 COM程序释放任何不需要的内存。
– 分配内存后,DOS在该内存的头 256字节建立一个 PSP( Program
Segment Prefix:程序段前缀)。
– 创建 PSP后,DOS在 PSP后立即开始(偏移 100H)加载 COM文件,它置 SS,DS和 ES为 PSP的段地址,接着创建一个堆栈。
– DOS通过把控制传递偏移 100H处的指令而启动程序。
程序设计者必须保证 COM文件的第一条指令是程序的入口点。
– 因为程序是在偏移 100H处加载,因此所有代码和数据偏移也必须相对于 100H。汇编语言程序设计者可通过置程序的初值为 100H而保证这一点(例如,通过在源代码的开始使用语句 org 100H)。
PSP结构
偏移大小 长度( Byte) 说 明
0000h 02 中断 20H
0002h 02 以节计算的内存大小(利用它可看出是否感染引导型病毒)
0004h 01 保留
0005h 05 至 DOS的长调用
000Ah 02 INT 22H 入口 IP
000Ch 02 INT 22H 入口 CS
000Eh 02 INT 23H 入口 IP
0010h 02 INT 23H 入口 CS
0012h 02 INT 24H 入口 IP
0014h 02 INT 24H 入口 CS
0016h 02 父进程的 PSP段值(可测知是否被跟踪)
0018h 14 存放 20个 SOFT号
002Ch 02 环境块段地址(从中可获知执行的程序名)
002Eh 04 存放用户栈地址指针
0032h 1E 保留
0050h 03 DOS调用( INT 21H / RETF)
0053h 02 保留
0055h 07 扩展的 FCB头
005Ch 10 格式化的 FCB1
006Ch 10 格式化的 FCB2
007Ch 04 保留
0080h 80 命令行参数长度
0081h 127 命令行参数
MZ格式
MZ格式,COM发展下去就是 MZ格式的可执行文件,这是
DOS中具有重定位功能的可执行文件格式。 MZ可执行文件内含 16位代码,在这些代码之前加了一个文件头,文件头中包括各种说明数据,例如,第一句可执行代码执行指令时所需要的文件入口点、堆栈的位置、重定位表等。
装载过程:
– 操作系统根据文件头的信息将代码部分装入内存,
– 然后根据重定位表修正代码,
– 最后在设置好堆栈后从文件头中指定的入口开始执行。
DOS可以把 MZ格式的程序放在任何它想要的地方。
MZ标志
MZ文件头其它信息重定位表的字节偏移量重定位表 重定位表可重定位程序映像 二进制代码
// MZ格式可执行程序文件头
struct HeadEXE
{
WORD wType; // 00H MZ标志
WORD wLastSecSize; // 02H 最后扇区被使用的大小
WORD wFileSize; // 04H 文件大小
WORD wRelocNum; // 06H 重定位项数
WORD wHeadSize; // 08H 文件头大小
WORD wReqMin; // 0AH 最小所需内存
WORD wReqMax; // 0CH 最大所需内存
WORD wInitSS; // 0EH SS初值
WORD wInitSP; // 10H SP初值
WORD wChkSum; // 12H 校验和
WORD wInitIP; // 14H IP初值
WORD wInitCS; // 16H CS初值
WORD wFirstReloc; // 18H 第一个重定位项位置
WORD wOverlap; // 1AH覆盖
WORD wReserved[0x20];//1CH 保留
WORD wNEOffset; // 3CH NE头位置
};
NE格式
为了保持对 DOS的兼容性并满足 Windows
的需要,Win3.x中出现的 NE格式的可执行文件中保留了 MZ格式的头,同时 NE文件又加了一个自己的头,之后才是可执行文件的可执行代码。 NE类型包括了 EXE,DLL、
DRV和 FON四种类型的文件。 NE格式的关键特性是:它把程序代码、数据、资源隔离在不同的可加载区中;藉由符号输入和输出,实现所谓的运行时动态链接。
NE装载
16位的 NE格式文件装载程序( NE Loader)读取部分磁盘文件,并生成一个完全不同的数据结构,
在内存中建立模块。
当代码或数据需要装入时,装载程序必须从全局内存中分配出一块,查找原始数据在文件的位置,
找到位置后再读取原始的数据,最后再进行一些修正。
每一个 16位的模块( Module)要负责记住现在使用的所有段选择符,该选择符表示该段是否已经被抛弃等信息。
MS-DOS头
DOS文件头保留区域
Windows头偏移
DOS Stub程序信息块
NE文件头段表资源表驻留名表模块引用表引入名字表入口表非驻留名表代码段和数据段程序区重定位表
3 COM文件病毒原理
感染过程:
– 将开始的 3个字节保存在 orgcode中.
– 将这 3个字节更改为 0E9H和 COM文件的实际大小的二进制编码。
– 将病毒写入原 COM文件的后边。
– 在病毒的返回部分,将 3个字节改为 0E9H和表达式(当前地址- COM文件的实际大小-病毒代码大小)的二进制编码,以便在执行完病毒后转向执行原程序。
E9 xx xx
Resume:
E9 XX XX
E9 AA AA
AA AA
XX XX
源代码,jump
源代码示例讲解三,32位操作系统病毒示例分析
1 PE文件结构及其运行原理
2 Win32文件型病毒编制技术
3从 ring3到 ring0概述
1 PE文件结构及其运行原理
( 1) PE文件格式总体结构? PE( Portable Executable:可移植的执行体)
– 是 Win32环境自身所带的可执行文件格式。
– 它的一些特性继承自 Unix的 Coff(Common Object File Format)文件格式。
– 可移植的执行体意味着此文件格式是跨 win32平台的,即使
Windows运行在非 Intel的 CPU上,任何 win32平台的 PE装载器都能识别和使用该文件格式。
– 当然,移植到不同的 CPU上 PE执行体必然得有一些改变。
除 VxD和 16位的 Dll外,所有 win32执行文件都使用 PE文件格式。因此,研究 PE文件格式是我们洞悉 Windows结构的良机。
PE文件结构总体层次分布
DOS MZ header ‘ MZ’格式头
DOS stub Dos桩程序
PE header PE文件头
Section table 节表
Section 1 第 1个节
Section 2 第 2个节
… …
Section n 第 n个节
– 所有 PE文件必须以一个简单的 DOS MZ header开始。
有了它,一旦程序在 DOS下执行,DOS就能识别出这是有效的执行体。
– DOS stub实际上是个有效的 EXE,在不支持 PE文件格式的操作系统中,它将简单显示一个错误提示,类似于字符串,该程序不能在 DOS模式下运行”或者程序员可根据自己的意图实现完整的 DOS代码。
– PE header是 PE相关结构 IMAGE_NT_HEADERS的简称,其中包含了许多 PE装载器用到的重要域。
– section table(节表) 是节的索引。
– PE文件的真正内容被划分成块,我们称之为 sections
(节)。
每节是一块拥有共同属性的数据,比如代码 /数据、读 /写等。
把 PE文件想象成一逻辑磁盘,PE header是磁盘的 boot扇区,而 sections就是各种文件,每种文件自然就有不同属性如只读、系统、隐藏、文档等等。其中节表就像目录。
值得我们注意的是 ——节的划分是基于各组数据的共同属性而不是逻辑概念。因此,我么不必关心节中类似于 data,
code或其他的逻辑概念。如果数据和代码拥有相同属性,
它们就可以被归入同一个节中。
节名称仅仅是个区别不同节的符号而已,类似于 data和
code等的节名称只为了便于识别,惟有节的属性设置决定了节的特性和功能。如果某块数据想作为只读属性,就可以将该块数据放入属性为只读的节中。
装载 PE文件的主要步骤
第一,当 PE文件被执行,PE装载器检查 DOS MZ
header里的 PE header偏移量。如果找到,则跳转到 PE header。
第二,PE装载器检查 PE header的有效性。如果有效,就跳转到 PE header的尾部。
第三,紧跟 PE header的是节表。 PE装载器读取其中的节索引信息,并采用文件映射方法将这些节映射到内存,同时附上节表里指定的节属性。
第四,PE文件映射入内存后,PE装载器将处理
PE文件中类似 import table(引入表)逻辑部分。
( 2)检验 PE文件的有效性
什么样的PE文件是有效的?
– 只要一些关键数据结构有效,我们就认为是有效的 PE文件了。
– 这个重要数据结构就是 PE header。从编程角度看,PE header实际就是一个
IMAGE_NT_HEADERS 结构。
– IMAGE_NT_HEADERS 结构的定义如下:
IMAGE_NT_HEADERS STRUCT
– Signature dd
– FileHeader IMAGE_FILE_HEADER
– OptionalHeader IMAGE_OPTIONAL_HEADER32
IMAGE_NT_HEADERS ENDS
Signature:该域为 PE标记,值为 50h,45h,00h,00h( PE\0\0)。
– IMAGE_DOS_SIGNATURE equ 5A4Dh
– IMAGE_OS2_SIGNATURE equ 454Eh
– IMAGE_OS2_SIGNATURE_LE equ 454Ch
– IMAGE_VXD_SIGNATURE equ 454Ch
– IMAGE_NT_SIGNATURE equ 4550h
FileHeader:该结构域包含了关于 PE文件物理分布的信息,比如节数目、文件执行机器等。
OptionalHeader:该结构域包含了关于 PE文件逻辑分布的信息。
定位 PE header
DOSMZ header( IMAGE_DOS_HEADER )包含了指向 PE header 的文件偏移量,即 e_lfanew。
定位步骤为,
– 第一,检验文件头部第一个字的值是否等于
IMAGE_DOS_SIGNATURE,是则 DOS MZ header有效。
– 第二,一旦证明文件的 DOS MZ header有效后,就可用 e_lfanew来定位 PE header了。
– 第三,比较 PE header的第一个字的值是否等于
IMAGE_NT_ SIGNATURE。如果前后两个值都匹配,
那我们就认为该文件是一个有效的 PE文件。
( 3)文件头( FileHeader)
文件头( FileHeader)是 IMAGE_NT_HEADERS的一个重要的域。文件头的表示结构为,
IMAGE_FILE_HEADER STRUCT
– Machine WORD
– NumberOfSections WORD
– TimeDateStamp dd
– PointerToSymbolTable dd
– NumberOfSymbols dd
– SizeOfOptionalHeader WORD
– Characteristics WORD
IMAGE_FILE_HEADER ENDS
域名 含义
Machine 该文件运行所要求的 CPU。对于 Intel平台,该值是 IMAGE_FILE_MACHINE_I386 (14Ch)。
NumberOfSections 文件的节数目。如果我们要在文件中增加或删除一个节,就需要修改这个值。
TimeDateStamp 文件创建日期和时间。要让它保持原样,不要变
PointerToSymbolTable 用于调试。
NumberOfSymbols 用于调试。
SizeOfOptionalHeader 指示紧随本结构之后的 OptionalHeader结构大小,
必须为有效值。
Characteristics 关于文件信息的标记,比如文件是 exe还是 dll。
注:
节、节表和 NumberOfSections的关系
节表数组边界确定
NumberOfSections
全0标示
(4) Optional Header
Optional Header是 PE header中最后,最大,也是最重要的成员,包含了 PE文件的逻辑分布信息。该结构共有 31个域。
虚拟地址 (VA——Virtual Address)
RVA( Relative Virtual Address,相对虚拟地址)
域名 含义
AddressOfEntryPoint PE装载器准备运行的 PE文件的第一个指令的 RVA。若您要改变整个执行的流程,可以将该值指定到新的 RVA,这样新 RVA处的指令首先被执行。
ImageBase PE文件的优先装载地址。比如,如果该值是 400000H,PE装载器将尝试把文件装到虚拟地址空间的 400000H处。若该地址区域已被其他模块占用,那 PE装载器会选用其他空闲地址。
SectionAlignment 内存中节对齐的粒度。例如,如果该值是 4096 (1000H),那么每节的起始地址必须是 4096的倍数。若第一节从 401000H开始且大小是
10个字节,则下一节必定从 402000H开始,即使 401000H和 402000H
之间还有很多空间没被使用。
FileAlignment 文件中节对齐的粒度。含义类似 SectionAlignment。
MajorSubsystemVersion
MinorSubsystemVersion
Win32系统版本。
SizeOfImage 内存中整个 PE映像体的尺寸。它是所有头和节经过节对齐处理后的大小。
SizeOfHeaders 所有头 +节表的大小,也就等于文件尺寸减去文件中所有节的尺寸。
可以以此值作为 PE文件第一节的文件偏移量。
Subsystem NT用来识别 PE文件属于哪个子系统。对于大多数 Win32程序,只有两类值,Windows GUI 和 Windows CUI (控制台 )。
DataDirectory IMAGE_DATA_DIRECTORY 结构数组。每个结构给出一个重要数据结构的 RVA,比如引入地址表等。
( 5)节表 (Section Table)
Section Table是用来索引节的数组结构,其详细表示为:
– IMAGE_SIZEOF_SHORT_NAME equ 8
– IMAGE_SECTION_HEADER STRUCT
Name db IMAGE_SIZEOF_SHORT_NAME dup(?)
union Misc
– PhysicalAddress dd
– VirtualSize dd
Ends
VirtualAddress dd
SizeOfRawData dd
PointerToRawData dd
PointerToRelocations dd
PointerToLinenumbers dd
NumberOfRelocations dw
NumberOfLinenumbers dw
Characteristics dd
– IMAGE_SECTION_HEADER ENDS
域名 含义
Name 节名长不超过 8字节。节名仅仅是个标记而已,可以选择任何名字甚至空着也行。节名不是一个 ASCII字符串,所以不用 null结尾。
VirtualAddress 本节的 RVA。 PE装载器将节映射至内存时会读取该值,
如果域值是 1000H,而 PE文件装在地址 400000H处,
那么本节就被装载到 401000H。
SizeOfRawData 经过文件对齐处理后的节尺寸。该域值代表需映射入内存的字节数。(假设一个文件的文件对齐尺寸是
0x200,如果 VirtualSize域指示本节长度是 0x388字节,
则本域值为 0x400,表示本节是 0x400字节长)。
PointerToRawData 节基于文件的偏移量。 PE装载器通过该值找到节数据在文件中的位置。
Characteristics 包含标记以指示节属性。节是否含有可执行代码、初始化数据、未初始数据,是否可写、可读等。
PE装载器的工作步骤,
第一,读取 IMAGE_FILE_HEADER的 NumberOfSections
域,获取文件的节数目;
第二,SizeOfHeaders域值作为节表的文件偏移量,并以此定位节表;
第三,遍历整个结构数组检查各成员值;
第四,对于每个结构,读取 PointerToRawData域值并定位到该文件偏移量。然后再读取 SizeOfRawData域值来决定映射内存的字节数。将 VirtualAddress域值加上
ImageBase域值等于节起始的虚拟地址。然后就准备把节映射进内存,并根据 Characteristics域值设置属性。
第五,遍历整个数组,直至所有节都已处理完毕。