KillDisk 해체: BlackEnergy 파괴적 컴포넌트의 리버스 엔지니어링

[post-views]
2월 29, 2016 · 8 분 읽기
KillDisk 해체: BlackEnergy 파괴적 컴포넌트의 리버스 엔지니어링

BlackEnergy 위협에 대한 긴 소개는 생략하고 “ololo.exe”라는 악성코드 구성요소를 연구하는 것으로 곧바로 들어갑니다. KillDisk는 BlackEnergy 프레임워크의 모듈로, 데이터 파괴와 APT 작업 중 혼란 및 주의를 산만하게 하는 목적을 가지고 있습니다.

https://www.virustotal.com/en/file/11b7b8a7965b52ebb213b023b6772dd2c76c66893fc96a18a9a33c8cf125af80/analysis/오늘 분석에 사용된 주요 도구는 Process Monitor SysInternals 유틸리티의 일부로 Mark Russinovich가 제공하며 IDA Pro Disassembler입니다. 모든 작업은 Windows XP 운영 체제를 기반으로 한 가상 환경에서 수행됩니다. 테스트 VM의 간단한 초기 설정을 만들고, 머신을 켜고 “Before infection”이라는 스냅샷을 생성하는 것부터 시작합니다. 시작합시다!

연구의 주제와 관련된 모든 이벤트를 추적하기 위해 Process Monitor 을(를) 실행하고 화면에 표시되도록 합니다:BlackEnergy-killdisk-1그리고 필요한 프로세스를 추적하는지 확인합니다:

BlackEnergy-killdisk-2다음으로, 바이러스를 IDA Pro Disassembler 에 로드하고 다음과 같은 화면을 확인합니다.이는 WinMain 함수, 즉 메인 함수로, 이 분석을 시작해 그 함수가 첫 번째(그리고 유일한) 작업으로 수행하는 것이 sub_40E070:

 BlackEnergy-killdisk-3
이라는 절차 호출임을 알 수 있습니다. 따라서 해당 절차로 곧바로 이동해 보겠습니다. 여기에서 메모리로 파일 확장자를 추출하는 책임을 진 절차들과 이들 바로 뒤에 흥미로운 것을 호출하는 절차인 sub_40E080:

BlackEnergy-killdisk-4을 발견할 수 있습니다. 그 내용을 자세히 살펴보겠습니다:BlackEnergy-killdisk-5그 내부에는 흥미로운 시스템 호출 CreateFile 이(가) 포함되어 있으며 몇 가지 절차 sub_40C390 and sub_40C400이(가) 있습니다. 이제 가상 실험실의 스냅샷을 찍고 여정을 계속할 때입니다!

함수 호출을 검토하고 CreateFile에 중단점을 설정하고 연구 샘플을 실행합니다: BreakPoint on it and execute our study sample:

BlackEnergy-killdisk-6이 함수에 대한 작은 힌트:

CreateFile 함수는 파일 또는 I/O 장치를 생성하거나 엽니다. 가장 일반적으로 사용되는 I/O 장치는 파일, 파일 스트림, 디렉터리, 물리 디스크, 볼륨, 콘솔 버퍼(CONIN$ or CONOUT$), 테이프 드라이브, 통신 리소스, 메일슬롯 및 네임드 파이프입니다. 이 함수는 플래그와 속성에 따라 파일이나 장치에 대한 다양한 유형의 I/O에 접근할 수 있는 핸들을 반환합니다.

대부분의 컴파일러는 함수를 호출할 때 인수를 스택을 통해 전달하며, 우리가 C로 작성된 샘플을 다루고 있는 만큼, C 지시에 따라 함수를 호출할 때의 인수는 스택에 오른쪽에서 왼쪽으로 푸시됩니다. 스택 에서 오른쪽에서 왼쪽 으로 첫 번째 함수 인수가 마지막으로 스택에 푸시되어 스택의 맨 위에 있는 첫 번째 요소가 됩니다. [1].

There is a special register for working with the stack – ESP (Extended Stack Pointer). The ESP, by definition, always points to the top of the stack:

BlackEnergy-killdisk-41스택을 살펴봅시다:BlackEnergy-killdisk-7스택에 푸시된 마지막 인수(맨 위에 있는 것)가 함수에서 수락한 첫 번째 인수입니다( CreateFile 함수의 구문에 따르면) 이번 경우 그것은 파일 이름이 포함되어 있습니다 \.PHYSICALDRIVE0, 따라서 목표는 첫 번째 물리 드라이브입니다.BlackEnergy-killdisk-8이제 우리는 스택에서 해당 값들을 가져와 함수에 전달된 다른 인수를 분석합니다:BlackEnergy-killdisk-9몇 가지 결론:

  • lpFileName – 열거나 생성 중인 파일의 이름(경로)을 포함하는 ASCIIZ 문자열 포인터(이미 확인했습니다);
  • dwDesiredAccess – 파일에 대한 액세스 유형: 이 경우 값은 0C0000000h 으로, 이는 GENERIC_READ+GENERIC_WRITE or 읽기-쓰기 액세스를 의미합니다;
  • DwShareMode – 파일을 다른 프로세스와 공유할 수 있는 모드로, 이 파라미터는 다른 값을 가질 수 있으며 이 경우 00000003b 값은FILE_SHARE_READ+FILE_SHARE_WRITE 또는 다른 프로세스에서 파일을 읽고 쓰기 위해 열 수 있음;
  • IpSecurityAttributes – 커널 파일 객체와 관련된 보안 설정을 정의하는 SecurityAttributes 구조체(file winbase.h)에 대한 포인터로, 보안이 설정되지 않은 경우 NULL 값이 사용됩니다;
  • dwCreationDistribution – 파일이 존재하거나 존재하지 않을 때 수행할 작업을 결정하는 역할을 하며, 이 경우의 값은 3 을 의미하며, OPEN_EXISTING or 존재할 경우 파일을 열고 존재하지 않을 경우 오류를 반환;
  • DwFlagsAndAttributes – 플래그와 속성; 이 파라미터는 생성된 파일의 특성을 설정하는 데 사용되며 읽기 모드에서는 무시됩니다 0.
  • hTemplateFile – 새 파일이 생성될 때만 사용되는 파라미터 0.
  • 성공 시 함수는 새 파일 핸들러를 을 반환합니다 ЕАХ 그리고 함수가 실패하면 NULL 가 기록됩니다 ЕАХ 레지스터에.

좋습니다, CreateFile 을 호출한 후 EAX에 비제로 값이 표시됩니다. 이는 요청된 파일의 핸들러가 포함되었음을 의미합니다, 예를 들어 \.PHYSICALDRIVE0:

BlackEnergy-killdisk-26핸들러를 얻었으니 다음 호출로 진행해 봅시다, sub_40C390:

BlackEnergy-killdisk-10이전과 마찬가지로 절차 내부를 살펴보면 또 다른 흥미로운 호출이 나타납니다:BlackEnergy-killdisk-11함수 힌트:

DeviceIoControl 함수는 지정된 장치 드라이버로 직접 제어 코드를 보내어 해당 장치가 해당 작업을 수행하게 합니다.

함수 호출 직전 스택을 살펴봅니다:BlackEnergy-killdisk-11결론:

  • hDevice – 장치 설명자 (익숙한 친구를 알아봅니다) \.PHYSICALDRIVE0);
  • dwIoControlCode – 작업 코드. 이 경우 값은 0x70000h 으로, 이는 이거나 디스크 기하학 정보(실린더 수, 미디어 유형, 실린더당 트랙, 트랙당 섹터, 섹터당 바이트)를 검색하는 것입니다; or retrieval of the information regarding disks geometry (amount of cylinders, type of media, tracks on cylinder, sectors per track, bytes per sector);
  • lpInBuffer – 입력 데이터가 있는 버퍼. 입력 데이터는 필요하지 않으므로 NULL 로 설정됩니다;
  • nInBufferSize – 바이트 단위의 입력 버퍼 크기이며, 우리의 경우 0 ;
  • lpOutBuffer – 출력 버퍼에 대한 포인터. 그 유형은 dwIoControlCode 파라미터로 설정됩니다 0x0011FCA8h;
  • nOutBufferSize – 바이트 단위의 출력 버퍼 크기 0x18h (24);
  • lpBytesReturned – 출력에 기록된 바이트 수를 포함하는 변수에 대한 포인터 0x0011FCA4h;
  • lpOverlapped – 구조체 OVERLAPPED 에 대한 포인터;
  • 이 호출이 처리되면 버퍼를 검사합니다(인수로 전달된 주소에서 시작하여 lpOutBuffer 정확히 0x0011FCA8h):

BlackEnergy-killdisk-12답을 해석해 봅시다:

  • 주소 0x0011FCA4h 에 예정대로 출력 버퍼에 작성된 바이트 수가 반환되었습니다(초록색으로 표시됨). 요청한 대로 24개의 기호를 얻었습니다.
  • 주소 0x0011FCA8h 첫 번째 물리 디스크의 기하 정보를 얻었습니다 (\.PHYSICALDRIVE0):
    • 실린더 수 – 0x519h (1305)
    • 미디어 유형 – 0x0Ch (12) 고정 하드 디스크를 의미합니다.
    • 실린더 당 트랙 – 0x0FFh (255)
    • 트랙 당 섹터 – 0x3Fh (63)
    • 섹터 당 바이트 – 0x200 (512)

이제 세 번째 절차로 이동해 봅시다, sub_40C400:

BlackEnergy-killdisk-13절차 내부에서 두 가지 호출이 즉시 우리의 주의를 끌었습니다, 특히 SetFilePointerExWriteFile:

BlackEnergy-killdisk-14함수에 대한 힌트:

SetFilePointerEx 함수는 지정된 열린 파일의 파일 포인터를 이동합니다.

관행에 따라 함수 호출 스택을 검사합니다:BlackEnergy-killdisk-15

  • hfile – 우리가 친숙한 장치 설명자 \.PHYSICALDRIVE0;
  • liDustanceToMove – 쓰기를 시작할 초기 위치 0;
  • lpNewFilePointer – 파일에서 새 위치 포인터를 검색하는 변수에 대한 포인터 0x0011FCA8h. 매개변수가 EMPTY (NULL)일 경우 새 포인터는 파일에서 반환되지 않습니다;
  • dwMoveMethod – 바이트 단위의 입력 버퍼 크기입니다. 저희의 경우 0x200h (512) – 섹터 내 바이트 수입니다;

이제 우리의 “짐승”이 WriteFile 함수를 사용하여 이미 직접적이고 신뢰할 수 있는 접근을 수립한 파일을 0으로 채웁니다.

함수 힌트:

A WriteFile 함수는 파일 또는 I/O 장치에 데이터를 작성하고, 파일에 지정된 위치에서 시작하여 작성합니다. 이 함수는 동기식 및 비동기 작업 모두를 위해 설계되었습니다.

함수 인수 목록:BlackEnergy-killdisk-16좋습니다, 흥미로운 것을 놓치지 않기 위해 대시보드를 살펴보고 모든 것을 확인합니다. 스택:BlackEnergy-killdisk-17모든 작업 준비 완료:

  • 1 – 함수 호출에 대기 중 WriteFile
  • 2 – Process Monitor 가 우리의 “짐승”의 근육 저마다의 움직임을 신경질적으로 기다리고 있습니다
  • 3 – 레지스터에서 스택으로 인수가 푸시되었습니다
  • 4 – 그리고, 스택 자체
  • Hex View-EBP 창에서 두 번째 함수 인수(데이터 버퍼)가 주로 사용되는 지역에 전용 사각형을 표시했습니다. 제 말을 믿으셔도 됩니다 – 그것은 정확히 0x200h (512)의 0으로 가득 차 있습니다.

명령어를 F8 키로 실행하고 변화를 관찰합니다:BlackEnergy-killdisk-18기대했던 대로 Process Monitor 의 예리한 상황 보고는 적중했고 0 위치에서 512바이트 쓰기를 기록했습니다.

그 후 절차는 종료되고 다시 호출되지만 이번에는 다른 값으로:BlackEnergy-killdisk-19이번에는 이전에 파란색 프레임으로 표시한 인수 스택이 특히 0x200에 잘 드러났습니다BlackEnergy-killdisk-20

This merry-go-round goes on until the check of 0x40C865h 주소에서 확인한 EBX 레지스터 값이 로 표시되는 것은 (255 회 ):

BlackEnergy-killdisk-21확실히 하기 위해 “파괴”의 악순환에 이은 명령어에 중단점을 설정합니다:

BlackEnergy-killdisk-22256 의 재작성 작업을 받습니다:BlackEnergy-killdisk-23기본적으로 종료하며, “짐승”은 수행 중인 중요 파일 핸들를 만지는 함수 CloseHandle 함수를 호출합니다.

함수 힌트:

A CloseHandle 함수는 열린 객체의 핸들을 닫습니다.

함수 인수:

BlackEnergy-killdisk-24스택 준비의 전통적인 모습:

BlackEnergy-killdisk-25그리고 ESI 레지스터에 무엇이 있습니까? BlackEnergy-killdisk-26기대했던 대로 우리의 익숙한 설명자가 0x44h 형태로 함수를 위해 전송되었습니다.

우리는 함수에서 EAX 레지스터에 반환된 값을 봅니다: BlackEnergy-killdisk-27함수가 성공적으로 끝날 경우 반환된 값은 비널입니다.

함수가 오류로 끝날 경우 반환된 값은 NULL입니다.

이번 조치도 우리의 주의 깊은 눈을 피해가지 않았습니다 Process Monitor:

BlackEnergy-killdisk-28모든 것이 정상으로 진행되었습니다 (시스템 드라이브의 가장 중요한 부분을 파괴하는 것을 정상이라고 할 수 있다면) ) 그리고 파일이 닫혔습니다.

계속해 봅시다:BlackEnergy-killdisk-29좀더 편안하게 인식할 수 있도록 함수를 Eraser로 이름을 바꿨습니다. 성공적으로 데이터를 PhysicalDrive0에서 파괴한 후, ESI 레지스터에 위치한 카운터가 1)에 의해 증가되고, 값 0x0Ah (10와 검토되어 새로운 값을 사용하여 재작성 작업을 시작합니다:BlackEnergy-killdisk-30다음과 같이 10에 도달할 때까지 계속됩니다.

이와 같은 방식으로 이 “짐승”은 모든 물리 드라이브를 탐색하며 처음 512 * 255 = 128kb 를 삭제합니다(이는 “짐승”이 디스크의 기하를 알고 얻은 바이트 수에 따라 다릅니다).

이번에는 함수 CreateFileW 의 결과값이 다음과 같을 것입니다: BlackEnergy-killdisk-31이는 우리 “즉석 실험실”에 두 번째 물리 디스크(또는 0 이상의 시퀀스 번호를 가진 어떤 종류의 디스크도) 존재하지 않는다는 것을 의미하며, 이 주기가 재작성할 아무것도 없습니다.part1_op_en새롭게 얻은 지식을 바탕으로 우리가 방금 익힌 파괴적인 기능을 비활성화 시켜 보고, 코드를 수정하여 데이터 재작성을 우회할 수 있도록 해봅시다:

BlackEnergy-killdisk-33절차를 기억합시다 sub_40E080 이 포함된 CreateFileW함수 호출을 우리는 0xFFFFFFFFh 값이 CreateFileW 함수 완료 후 나타나는 경우 , 물리 드라이브가 존재하지 않는 경우에만 값이 나타납니다 주소에 위치한 조건 분기 명령어를 무조건적인 것으로 변경합시다: address to an unconditional one:

 BlackEnergy-killdisk-34
IDA Pro 멋진 도구이기 때문에 우리는 명령을 작성하기만 하면 됩니다.

우리가 고려해야 할 유일한 것은 명령의 크기입니다. 조건부 시퀀스로 사용되는 바이트 수를 확인해 봅시다:

BlackEnergy-killdisk-35우리가 볼 수 있듯이 조건부 분기 명령은 6 바이트와 같고, 무조건적 시퀀스는 5 바이트에 불과하므로 동등하게 하기 위해 다른 명령인 NOP를 추가해야 합니다:BlackEnergy-killdisk-36다음 명령은 이전에 무엇을 포함하고 있었든지 상관없이 NOP로 바꿉니다 (때로는 그곳에 0이 있는 것을 봅니다):

BlackEnergy-killdisk-37명령 주소가 다음 명령의 주소를 기준으로 동등하게 되었는지 이중 확인합니다:

BlackEnergy-killdisk-38그리고 취소를 누릅니다. 완료.

이 조작 후 절차는 간단해 보일 것입니다: 입장하고 나와서 빈 루프를 만듭니다 (프로그램의 다른 부분이 이에 연결될 수 있으므로 이런 상태로 둡니다).BlackEnergy-killdisk-39Process Monitor에 의해 발견된 최종 증거에 따르면 분해된 KillDisk의 실행 결과 물리적 드라이브가 손상되지 않았습니다:

BlackEnergy-killdisk-40악성 코드는 디스크에 대한 정보를 읽고, 이를 분석한 후에 다음 분석할 비즈니스를 계속 진행했습니다.

출처:

[1] – Hacker Disassembling Uncovered. Kris Kaspersky, 2009.

Andrii Bezverkhyi 원본에서 번역 | CEO SOC Prime

이 기사가 도움이 되었나요?

동료들과 좋아요를 누르고 공유하세요.
SOC Prime의 Detection as Code 플랫폼에 가입하세요 귀하의 비즈니스와 가장 관련 있는 위협에 대한 가시성을 향상시키세요. 시작하고 즉각적인 가치를 창출하기 위해 지금 SOC Prime 전문가와의 미팅을 예약하세요.