본문 바로가기

[REVERSING]/▶악성코드분석

[악성코드]3월20일 방송사 및 금융권 악성코드 ApcCmdRun.exe

 

※ 주의사항

아래 공격 코드는 연구 목적으로 작성된 것이며, 허가 받지 않은 공간에서는 테스트를 절대 금지합니다.

악의 적인 목적으로 이용할 시 발생할 수 있는 법적 책임은 자신한테 있습니다. 이는 해당 글을 열람할 때 동의하였다는 것을 의미합니다.

해당 문서의 저작권은 해당 프로젝트 참여 저자들에게 모두 있습니다. 외부에 공개시 법적 조치가 가해질 수 있습니다. 


개요

악성코드 개요

3월20일 대란으로 유명한 darkseoul 샘플 입니다.

MBR을 파괴하고 나서 물리드라이버(하드디스크)까지 파괴를 시키는 악성코드입니다. 


생성파일 정보 요약

 

 

감영증상 요약

MBR과 HDD를 파괴하고 강제로 리부팅하여 시스템을 파괴합니다.

VirusTotal 점검 내역

https://www.virustotal.com/ko/file/1fbecec5da37b9a6e6dd63add4988fe7e2c4249aada883f58bcb794020455b77/analysis/



 

상세 분석 내용

[ ApcCmdRun.exe]

[그림.1]

401000 ~ 401039 까지는 각각 401000[EBP-2C][EBP-24], 402499[EBP-C], 4026E9[EBP-8], 402755[EBP-14]의 값을 EBP에 저장합니다.

그리고 40103F ~ 30106E LOOP문이 나오는데 00401063에 있는 값을 ECX값과 더하여 401052에서 4026E9[EBP-8] 빈공간에 ECX값 401000값을 시작으로 순차적으로 저장합니다.

루프의 반복횟수는 402755에서 마지막 데이터가 있는 곳까지 27(1B)이며 이 값만큼 그림.1의 우측상단 헥사창과 같이 순차적으로 저장합니다.

 

 

 

 

[그림.2]

00401099 와 004010CB에서 Loadlibrary, GetProcAddress를 Kernel32.dll에서 가저온다.

 

[그림.3]

그림3에서 00401166 주소에서 함수를 호출하여 advapi32.dll,kernel32.dll,ntdll.dll,msvcrt.dll,user32.dll에서 사용 할 함수들의 주소를 뽑아온다.

뽑아오는 방식은 ApcRunCmd의 0040286D의 주소값을 이용하여 dll의 함수주소를 구하고 구한 주소값을 004027C1부터 차례로 저장한다.

각각의 DLL에서 뽑아오는 함수들은 다음과 같다.


advapi32.dll
OpenProcessToken 처음 4027c1에 저장
LookuPprivilegeValuea
AdjustTokenPriVileges


kernel32.dll
OpenFileMappingA
GetwindowsDirectory
InitializeCriticalSection
CreateThread
WaitForSingleObject
GetVersionEx
Sleep
GetDriveTypeA
FindFirstFileA
RemoveDirectory
FindNextFile
FindClose
CreateFile
WriteFile
CloseHandle
DeleteFileA
SetFilePoiner
GetSystemDirectoryA
GetDiskFreeSpaceA
GetDiskFreeSpaceExA
ReadFile
WinExec
GetCurrentProcess
LoadLibraryA
GetProcAddress

 

ntdll.dll
RtlLeaveCriticalSection
RtlGetLastWin32Error


shlwapi.dll
PathFileExistsA


user32.dll
ExitWindowsEx

 

 

[그림.4] 

 

004011D7와  에서  이름으로 OpenFileMapping을 시도한다.

실패시 에서 CreateFileMappingA함수로 JO840112-CRAS8468-11150923-PCI8273V이름으로 파일맵핑객체를 생성한다.

 

[그림.5]

 

[그림.6]

 

OpenFileMapping 함수 호출시 JO840112-CRAS8468-11150923-PCI8273V객체 이름과 4를 인자로 함수를 호출하게되는데. 4의 값을 visualstudio에서 WinNT.h헤더파일에서 확인한 것이다. 4의 값은 SECTION_MAP_READ로 읽기전용으로 함수를 호출한다.

그리고 다시 그림.4에서 00401200에서 GetWindowsDirectoryA함수로 windows디렉토리 경로를 얻고 00401214에서 strcat함수로 windows\Temp\~v3.log와같이 문자열을 결합한다.

그리고 00401223에서 PathFileExistsA함수로 windows\Temp\~v3.log 경로에 파일이 있는지 확인하기위해 함수를 호출한다.

즉 안랩V3가 해당PC에 설치 되어있으면 루틴을 실행하지않고 종료하게된다.

분석중인 가상시스템에는 V3가 설치되어있지 않으므로 이어서 루틴을 실행한다.

 

[그림.7]

 

40122E에서 함수를 호출하는데 함수 내부로 들어가면  pasvc.exe, clisvc.exe를 taskkill /F /IM 명령으로 각각 강제종료 합니다.

 

[그림.8]

004012B9에서 94비트만큼 메모리공간을 0으로 세팅합니다.

그리고 그 공간에 GetVersionExA함수로 현재 시스템의 버전을 얻고 특정 값들을 저장합니다.

 

 

[그림.9]

 

00401274에서 00402991(JO840112-CRAS8468-11150923-PCI8273V...)의 시작주소를 인자로 CreateThread함수를 호출합니다.
 

 

[그림.10]

 

함수내부로 들어가면 Kernel32.dll의 CreateRemoteThread의 함수 루틴의 주소로 이동하여 함수를 실행합니다.

함수를 빠저나오면 WaitForSingleObjectEx 함수로 INFINITE 파라미터와 CreateRemoteThread함수를 호출하여 얻은 핸들값 00000058인자로 주어 실행합니다.

WaitForSingleObjectEx함수는 동기화에 쓰이는 함수이며 INFINITE를 파라미터로 넘겨주었기 때문에 하나의 쓰레드가 완전히 종료될때까지 다른스레드가 접근하는것을 방지합니다.

즉 스레드1과 스레드2가 있을경우 스레드1을 INFINITE로 주었을때 스레드2는 스레드1이 작업이 모두종료되기 전까지 무한대기하게 됩니다.

  

 [그림.11]

 

00401DCF 에서 CreateFile 함수로 PhysicalDrive0(MBR)을 오픈한다.

 

[그림.12]

그림11의 00401DDE에서 ReadFile 함수로 MBR을 읽어 들인다.

 

 

 [그림.13]

 

00402017주소에서 memset함수 호출로 009EFCCC에 0A(10)만큼 0으로 메모리를 세팅한다. 

그리고 0040202F에서 009EFCCC의 빈 메모리 공간에 "PRICPES" 문자열을 저장한다.

마지막으로 00402042에서 009EFACC MBR영역에 512바이트만큼 0으로세팅한다.

 

 

[그림.14]

 

00402052에서 strlen 함수로 PRINCPES 문자열길이를 반환하고 반환된 길이만큼 PRINCPES문자열을 00402065의 memcpy함수로 그림13에서 0으로 세팅된 MBR영역의 주소에 복사한다.

그리고 이 문자들을 총 3Ch(60)회 반복한다.

 

 

[그림.15]

 

그림11~그림14까지의 과정을 총 10번하면서 물리드라이브를 0~10까지 찾아서 "PRICPES"문자열을 복사한다.

hexview로 mbr을 확인하면 그림15와같은 형태로 MBR이 변경되어있다.

 

 

[그림.16]

그리고 00401B2C에서 GetDriveType함수를 호출하며 결과값이 3과 2인지 확인한다.

3은 고정형드라이브 2는 이동식드라이브를 뜻하며 드라이브 알파벳을 증가시켜가며 체크한다.

드라이브 타입이 3.고정형드라이브일 경우 00401B53주소에서 CreateThread를 호출시킨다.

 

[그림.17]

 

스레드 내부로 진입하게되면 GetDiskFreeSpaceA함수와 GetDiskFreeSpaceEx함수로 현재 시스템의 전체저장공간에서 남은용량(00AEF78)과 전체 저장공간의 용량(00AEFF70)을 각각 구하게 됩니다.

 

 

[그림.18]

그리고 CreateFile 함수로 c:\를 READ/WRITE권한으로 OPEN하고 다른프로세스에서 파일을 READ/WRITE할수있는 권한 그리고 파일이있을때만 OPEN할수 있는 권한인 OPEN_EXISTING과 마지막으로 파일의 속성을 읽기전용과 숨김상태로 지정합니다.

다음으로 malloc 함수를 200h(512)만큼 Heap을 생성하고 생성된 힙의주소 00383AA9까지 총 200h의 크기만큼 루프를 돌면서 PRINCIPES문자열을 입력합니다.

 

[그림.19]

 

00401D0B에서 SetFilePointer 함수를 호출하여 C:\의 파일포인터를 0으로 세팅합니다.

그리고 WriteFile함수로 200h(512)까지 PRINCIPES문자열을 쓰게됩니다.

이렇게 1회전이되면 다음 파일포인터를 계산하게 되는데 00501D42주소를 보면 00F63000 + 000C8000 = 00102B000와같이 계산을하고 다시 파일포인터를 00102B000부터 200h(512)까지 문자열을 쓰며 반복합니다. 총반복횟수계산은 00501d50의 CMP를 보면 1회전일때 EAX값이 0000102Bh값입니다. 비교대상은 003C1E54입니다.

2회전일때 EAX값은 00002056이됩니다.

그렇다면 간단하게 3C1E54 / 102B = 3B7(951) 의 값이 나오는데 결론으로 951번 루프를돌며 문자열을 입력하여 하드디스크를 파괴합니다.

 

[그림.20]

 

지금까지 첫번째 스레드와 두번째 스레드를 분석했는데 각각의 스레드가 하는 역할을 정리해보면 다음과 같습니다.

첫번쨰 스레드는 MBR영역을 찾고 찾은 영역을 파괴합니다. 그리고 두번쨰 스레드는 물리드라이브를 찾고 파괴하는 역할을합니다.

이제 마지막으로 스레드를 빠저나오고 나면 00402134의 함수로 진입하게 됩니다.

함수 내부로 들어가게 되면 "shutdown -r -t 0" 를 인자로 WinExec함수를 호출하여 시스템을 강제로 리부팅하게 합니다.

 

 

[그림.21]

리부팅을하면 Operating System not found로 OS로 부팅을 하지 못하게됩니다.

결론으로 ApcCmdRun.exe 악성코드는 1차적으로 MBR을 파괴한 후 2차적으로 하드디스크를 파괴합니다.

 

 

 

 

 

##여기 루프문에서 JB문 뒤로 브포걸고 F9하면 브포가 걸리지않고 스레드가 종료해버린다.

해결방법은 스레드내의 모든 브포를 제가한후 스레드진입함수 밖으로 빠저나와 스레드진입함수 브포도 제거하고나서 스레드 다음의 함수에 브포를 걸고 F9를 해야 종료되지않는다.

 

 

 

참고 URL

- OOO 참고 : www.test.co.kr