지금 유지보수하고 있는 드라이버 파일이 특정 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
혹시나 드라이버가 잘 로딩되지 않으면 이러한 부분도 체크해보시길…
최근 답글