악성코드 분석

NotPetya 분석 보고서

grze0 2026. 2. 18. 13:14

학습용으로 악성코드분석을 하고있습니다. 틀린 내용이 있거나 문장이 이상한 부분 그냥 이건 쫌 이상한테 하는 부분은 언제든지 말해주시면 감사하겠습니다. 많이 배우겠습니다.

 

Petya 랜섬웨어의 변종

md5 : 5b7e6e352bacc93f7b80bc968b6ea493

sha1 : e686139d5ed8528117ba6ca68fe415e4fb02f2be

sha256 : 63545fa195488ff51955f09833332b9660d18f8afb16bdf579134661962e548a

정적분석

파일을 만들고 그 파일에 주소에 있는 값을 넣고 동작을 종료하는것으로 보인다. 우선 sub_401000함수를 확인해보겠다.

%SystemRoot%는 윈도우 C:\Windows 경로이다.

sub_401000함수이고 우산적으로 lpSrc에 값이 없으면 return 0;으로 종료된다. 하지만 이전 함수에서 문자열으로 넘겨줬기 때문에 값이 존재한다고 추측한다.

그 후 GetProcessHeap함수를 이용하여 힙 메모리를 사용할 수 있는 핸들을 지정한다. 그 후 HeapAlloc 함수를 통해 0x104만큼의 힙 메모리를 할당하고 0x8은 아래 https://learn.microsoft.com/ko-kr/windows/win32/api/heapapi/nf-heapapi-heapalloc 해당 링크에서 가져온 표를 참고하자 그러면 해당 함수로 0x104만큼의 힙 메모리를 할당하고 해당 메모리를 0으로 초기화 시켰다. 그 후 v3에 메모리 블럭에 대한 포인터 값이 들어간다.

값 의미

HEAP_GENERATE_EXCEPTIONS0x00000004 시스템은 NULL을 반환하는 대신 메모리 부족 조건과 같은 함수 오류를 나타내는 예외를 발생합니다. 이 함수에 대한 모든 호출에 대해 예외가 생성되도록 하려면 HeapCreate 호출에서 HEAP_GENERATE_EXCEPTIONS 지정합니다. 이 경우 이 함수 호출에서 HEAP_GENERATE_EXCEPTIONS 추가로 지정할 필요가 없습니다.
HEAP_NO_SERIALIZE0x00000001 직렬화된 액세스는 이 할당에 사용되지 않습니다.자세한 내용은 설명 부분을 참조하세요. 이 함수에 대한 모든 호출에 대해 직렬화된 액세스를 사용하지 않도록 설정하려면 HeapCreate 호출에서 HEAP_NO_SERIALIZE 지정합니다. 이 경우 이 함수 호출에서 HEAP_NO_SERIALIZE 추가로 지정할 필요는 없습니다. 프로세스의 기본 힙에 액세스할 때 이 값을 지정하면 안 됩니다. 시스템은 프로세스의 기본 힙에 동시에 액세스하는 Ctrl+C 처리기와 같은 애플리케이션 프로세스 내에 추가 스레드를 만들 수 있습니다.
HEAP_ZERO_MEMORY0x00000008 할당된 메모리가 0으로 초기화됩니다. 그렇지 않으면 메모리가 0으로 초기화되지 않습니다.

 

 

그리고 해당 ExpandEnvironmentStringsA함수는 일전에 입력받은 환경변수인 “%SystemRoot%\perfc.dat”을 실제 환경변수로 치환해주는 함수이다 앞전에 설명했던 “%SystemRoot%는 윈도우 C:\Windows 경로이다.” 와 동일하게 된다. 최종적으로는 “C:\Windows\perfc.dat”이 라는 경로가 v3에 저장된다.

그 후 GetFullPathNameA 함수를 통해 v3가 가르키는 문자열 “C:\Windows\perfc.dat”을 통해 생성한 문자열을 v5에다가 문자열을 기록한다. 그 후 v5의 문자열 주소값을 return한다.

 

 

그럼 다시 돌아와서 해당 함수는 문자열을 환경변수 치환을 통해 실제 경로로 바꿔주는 함수임을 알 수 있다.

CreateFileA 함수를 통해 일전에 얻었단 문자열인 “C:\Windows\perfc.dat”에 대한 File handle을 얻는다 해당 핸들은 파일을 읽고 쓰기가 가능하고 해당 파일이 없으면 새로 만드는 인자값을 가지고있다.

그 후 WriteFile을 통해 &unk_407830에 있는 값을 0x58778만큼의 사이즈로 “C:\Windows\perfc.dat”에 write한다. 그 후 해당 파일 핸들을 닫는다.

그 후 ShellExecuteA함수로 rundll32.exe를 통해 “C:\Windows\perfc.dat”를 실행시킨다.

이제 알아 볼것은 &unk_407830이 뭔지 알아볼 차례다. 해당 영역으로 가보자

MZ 시그니처가 있는것을 보니 실행파일임을 추측할 수 있다. rdata영역은 read만 허용된 영역이다. only read

그러면 저 걸 추출 하기 위해 idapython을 사용했다.

추출을 할려면 우선 정확한 크기를 알아야 한다. 이전 WriteFile 함수에서 사용된 값은 0x58778u이다.그렇다면

import ida_bytes
open("C:\\dump.bin","wb").write(ida_bytes.get_bytes(0x00407830, 0x58778)

해당 코드는 특정 주소부터 원하는 바이트까지 읽어 저장하는 코드다.

성공적으로 추출한것을 볼 수 있다. 이제 해당 바이너리 파일을 ida로 분석해볼 차례이다.

md5:71b6a493388e7d0b40c83ce903bc6b04

SHA-1:34f917aaba5684fbe56d3c57d48ef2a1aa7cf06d

SHA-256:027cc450ef5f8c5f653329641ec1fed91f694e0d229928963b30f6b0d7d3a745

해당 파일은 dll 파일로 추측된다.(rundll32.exe을 사용한것으로도 추측이 가능한거같다.)

우선 perfc_1함수부터(처음에는 그냥 이름이 붙어있어서 봤는데 export를 보니까 얘가 있네요) 보겠다. 현재는 이름을 붙혀놓은 Privilege_elevation함수를 보면

이런식으로 되어있다. Set_Privileges 함수의 역할을 해당 문자열에 맞는 권한을 AdjustTokenPrivileges함수를 통해 부여하는 함수이다. 해당 decompile code에서 보이는 SeShutdownPrivilege, SeDebugPrivilege, SeTcbPrivilege는 각각 로컬 시스팀을 종료하는데 사용 , 프로그램 디버그, 운영체제 일부로 작동하게 할 수 있는 권한들이다.

https://learn.microsoft.com/ko-kr/windows/win32/secauthz/privilege-constants

다음으로는 WSAStartup함수를 사용하여 socket 통신을 준비하는거라 볼 수 있다. 해당 내용은 뒤에 실제로 socket통신을 하는지 확인해봐야한다.

해당 함수를 보면 하드코딩된 공개키를 확인할 수 있고 각 드라이브별로 쓰레드를 생성하여 쓰레드에 해당 공개키를 전달한다.

랜섬노트인 readme.txt 파일을 생성하는 함수가 보인다.

해당 함수는 확장자를 검사하여 해당 확장자가 위 확장자와 동일할 시 파일을 암호화하는 로직을 가지고있다.

해당 로직은 파일을 암호화 할때 사용하는 key를 생성하는 로직이다. CryptGenKey함수를 통해 Key를 생성한다.

해당 로직은 파일을 직접 메모리에 매핑해서 파일을 암호화 시키는 로직이다. 암호화 할때 사용한 키 핸들은 이전에 나왔던 공개키 문자열이다.

암호화가 다 끝난 이후 “wevtutil cl Setup & wevtutil cl System & wevtutil cl Security & wevtutil cl Application & fsutil usn deletejournal /D %c:”” 해당 명령어를 통해서 이벤트로그 및 journal파일을 모두 지우는 안티 포렌식 기능이 실행된다. (해당 값은 sub_100083BD함수로 전달되어 실행되고 아래 어셈블리를 보면 값이 실제로 전달되는것을 알 수 있다.)

(처음에는 전달이 안되는줄 알았는데 이후 코드의 파라미터값을 보니 eax로 전달된것을 확인하였다.)

이후 InitiateSystemShutdownExW 함수를 통해 호스트 PC를 재부팅 시키고 마지막 인자값을 통해서 재부팅 로그에는 “계획된 종료” 라는 로그를 남긴다.

 

추가로 socket 기능도 존재한다.

'악성코드 분석' 카테고리의 다른 글

ZPHP 분석 보고서  (0) 2026.02.18