再提供一些资料,也许用得着
摘自 "VxD技术及其在实时反病毒中的应用"---贺 朝 晖
一.关 键 技 术-FileHooking
---- 应 用 程 序 通 过 使 用 动 态 加 载 的VxD, 间 接 获 得 了 对Windows 9x 系
统 的 控 制 权, 但 要 实 现 对 系 统 中 所 有 文 件I/O 操 作 的 实 时 监 视,
还 要 用 到 另 一 种 关 键 技 术-FileHooking, 通 过 挂 接 一 个 处 理 函 数,
截 获 所 有 与 文 件I/O 操 作 有 关 的 系 统 调 用。Windows 9x 使 用32 位 保 护
模 式 可 安 装 文 件 系 统(IFS), 由 可 安 装 文 件 系 统 管 理 器(IFS Manager)
协 调 对 文 件 系 统 和 设 备 的 访 问, 它 接 收 以Win32 API 函 数 调 用 形 式
向 系 统 发 出 的 文 件I/O 请 求, 再 将 请 求 转 给 文 件 系 统 驱 动 程 序FSD,
由 它 调 用 低 级 别 的IOS 系 统 实 现 最 终 访 问。 每 个 文 件I/O API 调 用 都
有 一 个 特 定 的FSD 函 数 与 之 对 应,IFS Manager 负 责 完 成 由API 到FSD 的
参 数 装 配 工 作, 在 完 成 文 件I/O API 函 数 参 数 的 装 配 之 后 转 相 应FSD
执 行 之 前, 它 会 调 用 一 个 称 为FileSystemApiHookFunction 的Hooker 函 数。
通 过 安 装 自 己 的Hooker 函 数, 就 可 以 截 获 系 统 内 所 有 对 文 件I/O 的API
调 用, 并 适 时 对 相 关 文 件 进 行 病 毒 检 查, 从 而 实 现 实 时 监 控。
---- 上 述 过 程 由 用 户VxD 调 用 系 统VxD IFSMgr 提 供 的 服 务 完 成, 该VxD 提
供 了 丰 富 的 底 层 文 件 操 作 功 能: IFSMgr_InstallSyatemApiHook 函 数 用 来
安 装FileSystemApiHookFunction,IFSMgr_RemoveSystemApiHook 用 来 卸 除Hooker,
IFSMgr_Ring0_FileIO 用 来 对 文 件 和 磁 盘 扇 区 进 行 读 写 访 问 等 等。 当 由
IFS Manager 转 入SystemApiHookFunction 时, 带 有6 个 参 数:
FileSystemApiHookFunction(
pIFSFunc FSDFnAddr, //对应FSD服务函数地址
int FunctionNum, //与API对应的FSD服务功能号(详见下面)
int Drive, //驱动器代号(1=A, 2=B, 3=C ...)
int ResourceFlags, //资源标志(详见下面)
int CodePage, //代码页(0=ANSI,1=OEM)
pioreq pir//指向IOREQ结构的指针
)
---- 参 数 中 比 较 重 要 的 是FSD 功 能 号、 驱 动 器 号 和IOREQ 结 构 指 针3 项。
如 需 截 获 某 个 文 件I/O API 调 用, 只 需 在Hooker 中 对 相 应FSD 功 能 号 进
行 处 理, 这 些 功 能 号 的 含 义 为:
IFSFN_READ equ 0; read a file
IFSFN_WRITEequ1; write a file
IFSFN_FINDNEXT equ2; LFN handle based Find Next
IFSFN_FCNNEXT equ 3; Find Next Change Notify
IFSFN_SEEK equ10; Seek file handle
IFSFN_CLOSEequ11; close handle
IFSFN_COMMITequ12; commit buffered data for handle
IFSFN_FILELOCKS equ13; lock/unlock byte range
IFSFN_FILETIMES equ14; get/set file modification time
IFSFN_PIPEREQUESTequ 15; named pipe operations
IFSFN_HANDLEINFOequ 16; get/set file information
IFSFN_ENUMHANDLEequ 17; enum file handle information
IFSFN_FINDCLOSE equ18; LFN find close
IFSFN_FCNCLOSE equ19; Find Change Notify Close
IFSFN_CONNECT equ30; connect or mount a resource
IFSFN_DELETEequ31; file delete
IFSFN_DIRequ 32; directory manipulation
IFSFN_FILEATTRIBequ33; DOS file attribute manipulation
IFSFN_FLUSHequ34; flush volume
IFSFN_GETDISKINFOequ35; query volume free space
IFSFN_OPENequ36; open/create file
IFSFN_RENAMEequ37; rename path
IFSFN_SEARCHequ38; search for names
IFSFN_QUERYequ39; query resource info (network only)
IFSFN_DISCONNECTequ40; disconnect from resource (net only)
IFSFN_UNCPIPEREQequ41; UNC path based named pipe operations
IFSFN_IOCTL16DRIVEequ42; drive based 16 bit IOCTL requests
IFSFN_GETDISKPARMS equ43; get DPB
IFSFN_FINDOPENequ44; openan LFN file search
IFSFN_DASDIOequ45; direct volume access
参数资源类型定义为:
IFSFH_RES_UNCequ001h; UNC resource
IFSFH_RES_NETWORKequ008h; Network drive connection
IFSFH_RES_LOCALequ010h; Local drive
IFSFH_RES_CFSDequ080h; Character FSD
参数IOREQ结构包含了文件名等大量信息,定义为:
struct ioreq {
unsigned intir_length,/* +00h,length of user buffer (eCX) */
unsigned charir_flags,/* +04h,misc。 status flags (AL) */
uid_tir_user,/* +05h,user ID for this request */
sfn_tir_sfn,/* +06h,System File Number of file handle */
pid_tir_pid,/* +08h,process ID of requesting task */
path_tir_ppath,/* +0Ch,unicode pathname */
aux_tir_aux1,/* +10h,secondary user data buffer (CurDTA) */
ubuffer_tir_data,/* +14h,ptr to user data buffer (DS:eDX) */
unsigned shortir_options,/* +18h,request handling options */
shortir_error,/* +1ah,error code (0 if OK) */
rh_tir_rh,/* +1Ch,resource handle */
fh_tir_fh,/* +20h,file (or find) handle */
pos_tir_pos,/* +24h,file position for request */
aux_tir_aux2,/* +28h,misc。 extra API parameters */
aux_tir_aux3,/* +2Ch,misc。 extra API parameters */
peventir_pev,/* +30h,ptr to IFSMgr event for async requests */
fsdwork_tir_fsd,/* +34h,Provider work space */
};
其中path_t结构定义为:
typedef ParsedPathname *path_t;
struct ParsedPathname{
Unsigned short pp_TotalLength; //结构总长度(字节数)
Unsigned short pp_PrefixLength;//前导长度(从结构开始至下一成员)
struct PathElement pp_Elements[1];//Unicode文件名
}
---- 系 统 中 可 挂 接 多 个Hooker, 形 成 一 条 链。IFSMgr_InstallFileSystemApiHook
安 装Hooker 成 功 时 返 回 前 一 个Hooker 地 址, 每 个Hooker 在 做 特 定 处 理
后 总 应 调 用 前 一 个Hooker, 最 后 被 安 装 的Hooker 最 先 被 调 用。 在VxD 中
调 用 其 他VxD 服 务 采 用INT 20h 指 令 后 跟 一 个 双 字 的 特 殊 格 式, 其 中
高 字 为 被 调 用VxD 的ID 号( 系 统VxD 的ID 固 定), 低 字 为 该 VxD 之 服 务 号,
这 一 形 式 称 为VxDcall, 如:
int 20h
dd 00400043h;VxDCallIFSMgr_InstallSystemApiHook
int 20h
dd 00400044h;VxDCallIFSMgr_RemoveSystemApiHook
二. 应 用 实 例: 一 个 小 巧 的 病 毒 防 火 墙
---- 顾 名 思 义, 病 毒 防 火 墙 的 目 的 是 将 病 毒 隔 离 在 系 统 之 外,
它 采 用 动 态 防 御 手 段, 把 守 文 件 系 统 的 各 个 入 口, 将 病 毒 消
灭 在 入 侵 阶 段, 体 现 了“ 防 胜 于 杀" 这 一 实 时 反 病 毒 思 想。 下
面 结 合 一 个 简 单 的 例 子, 讨 论 构 筑 病 毒 防 火 墙 的 设 计 思 想 和
实 现 方 法。
---- 通 过 在VxD 中 使 用FileHooking 技 术, 反 病 毒 软 件 能 够 截 获 所 有
对 文 件I/O 的API 调 用, 实 现 对 病 毒 的 实 时 检 测 和 清 除。 具 体 来 说
, 就 是 在Hooker 函 数 中 对 某 些FSD 功 能 进 行 处 理, 记 录 被 访 问 的 文
件 名, 对 其 进 行 病 毒 检 查。 那 么, 应 该 处 理 哪 些FSD 功 能 呢 ? 无
论 病 毒 源 在 何 处, 病 毒 对 系 统 的 入 侵 途 径 不 外 乎 两 种:(1) 执 行
带 毒 文 件, 导 致 感 染 系 统 或 文 件, 直 接 危 害 系 统 ( 2) 拷 贝 带 毒
文 件, 在 系 统 内 创 建 新 的 带 毒 文 件, 形 成 对 系 统 的 潜 在 危 害。
两 种 方 式 都 需 要 访 问 文 件 的 内 容, 而 这 首 先 要 打 开 或 创 建 文 件,
因 此, 只 要 监 视FSD 功 能24h, 就 能 截 获 系 统 中 所 有 文 件 打 开、 拷 贝、
存 盘、 运 行 等 操 作,Hooker 能 够 从IOREQ 结 构 中 得 到 将 被 打 开 或 创 建
的 文 件 名, 随 后 对 它 们 进 行 检 查。 软 盘 是Windows 9x 系 统 使 用 的
一 种 重 要 介 质, 软 盘 引 导 区 带 毒 对 系 统 构 成 潜 在 威 胁,Hooker 还
需 进 行 对 软 盘 的 检 测, 可 截 获FSD 功 能 号1Eh, 这 样 每 当 系 统 将 软
盘 装 入 时,Hooker 可 得 知 将 被 访 问 的 软 盘, 随 后 检 查 其 引 导 区。
---- VxD 截 获 文 件API 调 用 后 有 两 种 处 理 方 法, 一 是 立 即 由VxD 对 相
关 文 件 或 软 盘 进 行 病 毒 检 查 和 清 除, 二 是 先 记 下 文 件 名 或 软 盘
号, 随 后 由 运 行 在 后 台Ring3 保 护 级 的 应 用 程 序 去 检 查 清 除。 第
一 种 方 法 实 时 性 强, 但 需 要 一 个 包 含 查 毒 杀 毒 代 码 的 庞 大 的VxD,
而 且 只 能 调 用 系 统 低 级 服 务 实 现 对 文 件 的 访 问, 比 较 复 杂;
第 二 种 方 法 虽 然 实 时 性 稍 差, 但 将 大 量 工 作 交Ring3 程 序 去 做,VxD
很 小, 易 于 实 现, 本 文 讨 论 的 病 毒 防 火 墙 使 用 这 种 方 法,VxD 被 设
计 成 支 持IOCTL 接 口, 这 样 无 须 提 供4 种 服 务, 应 用 程 序 通 过 调 用API
函 数DeviceIoControl 就 可 简 单 实 现 对VxD 的 控 制。
---- VxD 的 特 性 决 定 了 它 只 能 被 动 地 为 应 用 程 序 提 供 服 务,Hooker
函 数 记 录 文 件 名 或 软 盘 号 后, 无 法 主 动 将 结 果 送 给 应 用 程 序,
因 此Hooker 需 将 记 录 结 果 暂 时 保 存 起 来, 再 由 应 用 程 序 在 某 个 时
候 主 动 调 用DeviceIoControl 取 回。 暂 存 的 次 数 不 定 但 每 次 内 容 相 同,
可 用 系 统 链 接 表(Linked List) 达 到 这 一 目 的,VxD 每 次 为 链 接 表 分
配 一 个 新 结 点 记 录 文 件 名 或 软 盘 号, 应 用 程 序 取 回 使 用 完 毕 后
再 通 知VxD 释 放 该 结 点。 病 毒 防 火 墙 设 置 一 活 动 标 记, 避 免Ring 3
反 病 毒 程 序 调 用 文 件I/O API 查 杀 病 毒 时 再 次 被VxD 截 获, 也 方 便 用
户 暂 时 关 闭 防 火 墙。 这 样, 控 制 过 程 共 需 使 用4 种 控 制 码。 VxD 各
部 分 处 理 如 下:
---- (1) 动 态 初 始 化 处 理, 安 装Hooker 函 数
vxd_dynamic_init_handle:
push ecx
push esi
mov eax,create flags
mov ecx,NODESIZE
VxDCallList_Create ;创建链接表List1
mov save_list1,esi
mov eax,create flags
mov ecx,NODESIZE
VxDCallList_Create ;创建链接表List2
mov save_list2,esi
popecx
popesi
jb exit_init;创建失败,退出
push FileSystemApiHookFunction ;Hooker函数地址
VxDCallIFSMgr_InstallFileSystemApiHook;挂接Hooker函数
addesp,04h
or eax,eax ;eax返回前一个Hooker地址
jz exit_init
mov eax,[eax]
mov save_prevhooker,eax ;保存待用
clc
ret
exit_init:
stc
ret
---- (2) 动 态 卸 出 处 理, 移 去Hooker 函 数
vxd_dynamic_exit_ handle:
push FileSystemApiHookFunction
VxDCallIFSMgr_RemoveFileSystemApiHook;移去Hooker
addesp,04h
movesi,save_list1
VxDCallList_Destroy; 删除链接表List1
movesi,save_list2
VxDCallList_Destroy; 删除链接表List2
clc
ret
---- (3)对DeviceIoControl 调 用 所 带 控 制 码 的 处 理
a. 系统预定义的两个控制码
DIOC_CLOSEHANDLE(-1)
xoreax, eax;不作处理
ret
DIOC_CLOSEHANDLE(0)
xoreax, eax ;返回eax=0,支持IOCTL接口
ret
b.自定义控制码1
;设置监视标志为1,打开监视
mov byte ptr active_flag, 1
ret
c.自定义控制码2
;设置监视标志为0,关闭监视
mov byte ptr active_flag, 0
ret
d.自定义控制码=3
;从链表List2取一个结点,地址送应用程序
mov edi,[esi+18h]
;DIOCParams+18h=输出缓冲区
mov esi,save_list2
mov eax,[esi+00h]
cmp eax,00;结点地址,0=链表空
jz no_node
mov [edi],eax
;结点地址填写输出缓冲区
VxDCallList_Remove
;从List2上移去该结点(但仍属List2)
jmp ok
no_node:
xor eax,eax
mov [edi],eax
;List2为空,以0填写输出缓冲区
ok:
xor eax,eax
ret
e.自定义控制码4
;应用程序处理结点完毕,释放该结点
pushebp
pushesi
movesi,[esi+10]
;DIOCParams+10h=输入缓冲区,存放结点地址
moveax,[esi]
movesi,save_list2
;结点属于List2
VxDCall List_Deallocate
;释放该结点
xor eax,eax
pop esi
pop ebp
ret
---- (4)新 的Hooker 函 数 框 架
FileSystemApiHookFunction: ;6个参数均在堆栈中
push all registers
cmp active_flag,0;预处理,比较活动标记
jz cont ;(0=未激活)
mov edx,参数2;FSD功能号
cmp edx, 1Eh ;1Eh= mount软盘
jz fsd_mountfloppy ;登记软盘号
cmp edx, 24h ;24h=IFSFN_OPEN,打开/创建文件
jz fsd_fileopencreate;预处理
cont:
restore all registers
pushdword ptr参数 6;ioreq结构地址
pushdword ptr参数5 ;代码页
pushdword ptr参数4 ;资源类型
pushdword ptr参数3 ;驱动器号(1=A,2=B,3=C...)
pushdword ptr参数2 ;FSD功能号
pushdword ptr参数1 ;FSD函数地址
call save_prevhooker;调用前一个Hooker
cmp active_flag,0 ;后处理,比较活动标记
jz exit_hooker
pushad
cmp dword ptr参数2,24h;FSD功能号,24h=打开/创建文件
jnzcmp_0bh
mov esi,参数6 ;ioreq结构指针
在结点中保存[esi+1ah]之返回码
在结点中保存[esi+20h]之被打开/创建文件句柄
jmp exit_hooker
cmp_0bh:
cmp dword ptr参数2,0bh;0Bh=IFSFN_CLOSE,关闭文件
jnzexit_hooker
mov edi,参数6 ;ioreq结构指针
mov关闭句柄,[edi+20h] ;ioreq+20=文件句柄
mov esi,save_list1 ;List1
mov eax,[esi+00h] ;eax=结点地址,0=链表空
cmp eax,00
jz exit
next:;以句柄为索引,找到打开/创建文件时
cmp关闭句柄,结点句柄 ;所建立的那个List1结点
jz equal
VxDCallList_Get_Next;比较下一个结点
jz exit
jmp next
equal:
VxDCallList_Remove;从List1中移去该结点
mov esi,save_list2
VxDCallList_Attach_Tail ;加入链表List2
exit_hooker:
popad
ret
fsd_mountfloppy:
pushesi
movesi,save_list1
VxDCall List_Allocate;为链表List1分配一结点
VxDCall List_Attach ;放在链表头部
pop esi
记录软盘及运行环境信息
jmp cont ;调用前一个Hooker
fsd_fileopencreate:
pushesi
movesi,save_list1
VxDCall List_Allocate;为链表List1分配一结点
VxDCall List_Attach ;放在链表头部
pop esi
记录文件及运行环境信息
jmp cont ;调用前一个Hooker