样本文件MD5: 42f43edc9937e4aa5f985773f5ea9daa
这个样本有点老了,之前分析了一下他的命令执行部分,数据流程一直没有弄明白,现在记录一下。这个样本一上来会通过注册一个临时的 protocol driver (ndis 5.0, 差别多在xp 时代) ;注册成功后会返回一个ndis_handle 指针,然后通过这个指针加上硬编码的偏移找到 tcp/ip protocol driver 的 ndis_handle ,再挂钩(hook) 该结构中的receive 等回调函数;最后可以卸载临时的protocol driver,等待接收特定的网络包并解析。
hook 的 收包函数原型如下:
NDIS_STATUS OnReceiveStub(IN NDIS_HANDLE ProtocolBindingContext, /* our open structure */
IN NDIS_HANDLE MacReceiveContext,
IN PVOID HeaderBuffer, /* ethernet header */
IN UINT HeaderBufferSize,
IN PVOID LookAheadBuffer, /* it is possible to have entire packet in here */
IN UINT LookaheadBufferSize,
UINT PacketSize )
在hook 处理函数中对 HeadBuffer(相当于ethernet header),LookAheadBuffer (相当于ip+tcp/udp header+data )参数进行分析。
先判断ethernet 报文的长度是否为 14字节,在判断 ethernet frame 。分析ethernet header,如下图
从后续 ip ,tcp header ,及data 部分确认是否是特定包。先从ip header 中确定是否是tcp 协议,之后从 tcp 数据部分 的前16字节计算校验和;如果与硬编码值相等,则保留数据以进行下一步解析。 相关代码如下:
.text:00012490 GetRemoteAddress proc near ; CODE XREF: HandleIpAndTcpHeader+A↓p
.text:00012490 push esi
.text:00012491 mov esi, ecx
.text:00012493 cmp esi, 14h
.text:00012496 jnb short loc_1249C
.text:00012498
.text:00012498 loc_12498: ; CODE XREF: GetRemoteAddress+16↓j
.text:00012498 ; GetRemoteAddress+1C↓j
.text:00012498 xor eax, eax
.text:0001249A pop esi
.text:0001249B retn
.text:0001249C ; ---------------------------------------------------------------------------
.text:0001249C
.text:0001249C loc_1249C: ; CODE XREF: GetRemoteAddress+6↑j
.text:0001249C mov cl, [eax]
.text:0001249E mov dl, cl
.text:000124A0 and dl, 0F0h
.text:000124A3 cmp dl, 40h ; '@'
.text:000124A6 jnz short loc_12498
.text:000124A8 cmp byte ptr [eax+9], 6 ; 6 --->tcp
.text:000124AC jnz short loc_12498
.text:000124AE push edi
.text:000124AF mov edi, [eax+0Ch] ; ip->SourceAddress
.text:000124B2 test edi, edi
.text:000124B4 jz short loc_124BE
.text:000124B6 cmp edi, RemoteAddress
.text:000124BC jz short loc_1251D
.text:000124BE
.text:000124BE loc_124BE: ; CODE XREF: GetRemoteAddress+24↑j
.text:000124BE xor edx, edx
.text:000124C0 mov dh, [eax+6] ;get flags
.text:000124C3 mov dl, [eax+7]
.text:000124C6 movzx edx, dx ;it should be 0x4000
.text:000124C9 test dx, 3FFFh
.text:000124CE jz short loc_124D7
.text:000124D0 test dx, 1FFFh
.text:000124D5 jnz short loc_1251D
.text:000124D7
.text:000124D7 loc_124D7: ; CODE XREF: GetRemoteAddress+3E↑j
.text:000124D7 and ecx, 0Fh
.text:000124DA lea edx, [eax+ecx*4]
.text:000124DD movzx eax, byte ptr [edx+0Ch] ;get tcp header length from tcp header.
.text:000124E1 shr eax, 4
.text:000124E4 add ecx, eax;ip header length + tcp header length.
.text:000124E6 shl ecx, 2
.text:000124E9 sub esi, ecx
.text:000124EB cmp esi, 10h; tcp data length should be 0x10 bytes.
.text:000124EE jb short loc_1251D
.text:000124F0 lea eax, [edx+eax*4] ; get the data pointer.
.text:000124F3 mov ecx, [eax+8]
.text:000124F6 xor ecx, [eax];(*(data+0x0))^(*(data+0x8))
.text:000124F8 cmp ecx, 45AB8C01h ; compute the data checksums
.text:000124FE jnz short loc_1251D
.text:00012500 mov ecx, [eax+0Ch]
.text:00012503 xor ecx, [eax+4];(*(data+0x4))^(*(data+0xc))
.text:00012506 cmp ecx, 24601E69h
.text:0001250C jnz short loc_1251D
.text:0001250E test edi, edi
.text:00012510 jz short loc_1251D
.text:00012512 xor eax, eax
.text:00012514 mov RemoteAddress, edi
.text:0001251A inc eax
.text:0001251B jmp short loc_1251F
.text:0001251D ; ---------------------------------------------------------------------------
.text:0001251D
.text:0001251D loc_1251D: ; CODE XREF: GetRemoteAddress+2C↑j
.text:0001251D ; GetRemoteAddress+45↑j ...
.text:0001251D xor eax, eax
.text:0001251F
.text:0001251F loc_1251F: ; CODE XREF: GetRemoteAddress+8B↑j
.text:0001251F pop edi
.text:00012520 pop esi
.text:00012521 retn
.text:00012521 GetRemoteAddress endp
最后数据回发:样本执行命令产生的数据都会保存在内存中,当数据长度超过0xfa000 时,会根据之前获取的ip/port 构造网络包 经 tcp/ip protoncol driver 的 SendHandler 函数发走。