1 개요
과제 주제
악성코드 자동 실행 메커니즘 구현 및 분석 |
[표 1-1 프로젝트 주제]
과제 추진 배경 및 목표
악성코드는 기본 목적을 달성하기 위해 공격 대상 시스템에서 생존 하는 것이 중요하다. 이번 과제에서는 악성코드 종류 중 하나인 백도어에 대하여 Windows 운영체제(OS, Operation System)상에서 자동 실행 메커니즘 구현 및 분석을 한다. |
[표1-2 과제 추진 배경 및 목표]
과제 요약
1. 악성코드 자동 실행 메커니즘의 이해 |
2. Windows OS의 Registry 를 이용한 자동실행 메커니즘 구현 및 분석 |
3. 백도어(Backdoor) 오픈소스를 활용한 자동실행 메커니즘 구현 및 분석 |
[표 1-3 과제 요약]
대상 독자
API의 기능과 쓰임새를 알고 싶은 독자 |
[표1‑4 대상 독자]
1 서론
악성코드에서 자동 실행 메커니즘이 갖는 의의
악성코드는 악의적인 행동을 위해 만들어진 소프트웨어다. 악성코드는 침입한 시스템에서 특정한 목적을 수행하기 위하여 일정 시간 이상 생존할 필요가 있다. 이를 달성하기 위하여 운영체제(OS, Operation System)가 제공하는 서비스를 이용해 생명주기를 늘려 악의적인 행위를 계속해 나간다. 이를 위하여 Windows OS에서 Registry와 Service를 이용한다. 이번 과제에서는 Registry를 이용한 자동 실행 메커니즘을 알아보도록 한다.
2 본론
Windows의 Registry
Windows의 Registry란?
Windows OS에서 사용되는 Registry는 윈도우 32/64비트 버전에서 운영 체제의 설정과 선택 항목을 담고 있는 데이터베이스이다. 이전에 윈도우 프로그램에 대한 구성 설정을 각 프로그램마다 INI 파일을 사용하였지만 파일들이 시스템 여러 곳에 퍼짐으로써 찾기가 쉽지않아 Registry가 도입 되었다.
Registry의 구조
키, 값
레지스트리는 키와 값이라는 두가지 기본 요소를 포함하고 있다.
레지스트리 키는 폴더와 비슷하다. 폴더의 하위 폴더 개념과 같이 하위 키를 가질 수 있다.
레지스트리 값은 키 안에 들어 있는 이름/자료이다. 값은 여러 키로부터 따로 참조할 수 있다.
레지스트리 값을 찾아서 이용하는 윈도우 API 명령어는 부모 키를 정의하는 핸들과 값 이름을 키 경로로 부터 별도로 가져온다.
레지스트리 값 주요 종류 |
||
0 |
REG_NONE |
종류 없음 |
1 |
REG_SZ |
문자열 값 |
2 |
REG_EXPAND_SZ |
확장할 수 있는 문자열 값. 환경 변수를 포함할 수 있다. |
3 |
REG_BINARY |
이진 값 (임의의 데이터) |
[표 2-1 Windows Registry 값 주요 종류]
하이브
레지스트리는 수많은 논리를 구분하는 "하이브"(hive)로 나눌 수 있다. 하이브는 모두 HKEY로 시작하며, 윈도우 API 정의로 이름이 지정되어 있는 것이 보통이다. HK로 시작하는 이 이름들은 HKCU, HKLM과 같이 짧은 3~4개의 이름을 줄인 것이다.
하이브의 주요 종류 |
|
HKEY_CURRENT_USER (HKCU) |
현재 로그인한 사용자의 설정을 담고 있다. |
HKEY_LOCAL_MACHINE (HKLM) |
컴퓨터의 모든 사용자의 설정을 담고 있다. |
HKEY_USERS (HKU) |
컴퓨터에서 사용 중인 각 사용자 프로파일에 대한 HKEY_CURRENT_USER 키에 일치하는 서브키를 담고 있다. |
[표 2-2 하이브의 주요 종류]
Windows OS의 Registry를 이용한 자동실행 원리
Windows OS에서 사용되는 자동실행 메커니즘 중 하나인 Regisry를 이용한 방법이 있다. 그것을 Run and RunOnce registry keys라고 한다. [표 2-3]의 키에 자동실행을 원하는 키 값을 작성하여 등록한다.
HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Run |
HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run |
HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\RunOnce |
HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\RunOnce |
[표 2-3 Run and RunOnce Registry keys 종류]
HKEY_LOCAL_MACHINE은 컴퓨터의 모든 사용자의 Run, RunOnce 키 값을 가지고 있다.
HKEY_CURRENT_USER는 현재 로그인한 사용자에 대한 Run, RunOnce 키 값을 가지고 있다.
즉, 자동 실행하는 키 값은 컴퓨터의 모든 사용자에 대하여 설정할 수 있거나 특정 사용자 별로 설정 할 수 있다
Run
[그림 2-1]은 레지스트리 편집기로 본 키의 트리 구조(왼쪽)에서 Run키를 선택하여 오른쪽에서 키에 등록된 값들을 볼 수 있다. 해당 값들은 시작시 실행되는 프로그램들이 등록 되어 있는 모습이다. 기본 값을 제외한 총 3개의 프로그램이 Run에 등록된 것을 볼 수 있다.
RunOnce
레지스트리 키 트리의 바로 아래에는 RunOnce라고 하는 키가 위치해 있다. RunOnce 키는 Run 키와는 다르게 부팅시 등록된 값을 1회 실행 후 값을 삭제 한다. 현재는 기본값을 제외한 나머지 값은 없는 상태이다.
즉, Run 레지스트리 키에 있는 값들은 항상 값이 유지가 되며 RunOnce에 있는 레지스트리 키의 값은 부팅 후 한번 실행되고 나면 삭제가 된다.
Windows OS의 Registry를 이용한 자동실행 구현 및 분석
함수 RegADD(파라미터 A,파라미터 B) |
|
파라미터A -> regName |
키의 값 이름을 지정한다 |
파라미터B -> argv[0] |
현재 프로그램의 경로와 이름을 반환한다. |
[표 2-4 함수 RegADD의 주요기능]
HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run쓰기 모드로 연다 |
함수 RegSetValueEx |
위의 함수에서 읽은 키에서 파라미터를 받아 값을 작성한다 |
[표 2-5 함수 RegOpenKeyEx 와 RegSetValuEx의 주요기능]
파라미터 B인 argv[0] 내용을 출력한 모습이다. 파일의 현재경로와 현재이름을 담고있다.
Run키에 TwoIceFish라는 새로운 값이 생성 되었으며 데이터는 현재 프로그램이 실행된 경로로 바뀌었다.
연속해서 다른 디렉토리에서 프로그램 이름을 바꾸어 실행한 결과이다Run키의 TwoIceFish 데이터가 C\temp경로로 바뀌었고 실행 프로그램의 이름이 바뀌었다.
Argv[0]의 값을 받아 실행 프로그램의 동작하는 위치 또는 프로그램 이름이 바뀌어도 실행시마다 동적으로 바꿀 수 있음으로 프로그램의 생존 지속성을 높일 수 있다.
백도어(Backdoor) 오픈소스를 활용한 자동실행 메커니즘 구현 및 분석
앞서 작성한 레지스트리 자동 등록 소스를 포함하여 백도어 오픈소스에 추가하여 총 4단계의 분석 과정을 실시 한다.
기본 정적 분석, 기본 동적 분석, 고급 정적 분석, 그리고 고급 동적 분석 순서대로 진행한다.
기본 정적 분석
파일을 실행하지 않고 주요 기능을 탐색하는 방법이다.
Exeinfo
해당 프로그램의 제작 언어와 패킹유무 파일 진입 점 크기 등을 알 수 있다.
현재 C++로 만들어졌고 패킹은 안되어 있는 것으로 파악이 된다
PEview
PEview는 파일의 구조를 트리화 하여 구성해 정적상태에서 분석할 수 있는 프로그램 이다.
ACVAPI32.dll
ACVAPI32.dll |
|
RegSetValueExA |
레지스트리 값을 쓸 때 사용하는 함수이다 |
RegOpenKeyExA |
레지스트리 키에 접근 할 때 쓰는 함수이다. |
[표 2-6 ACVAPI32.dll의 의심되는 함수들]
해당 dll에서 레지스트리에 접근하여 값을 수정 할 수 있는 가능성이 있다.
KERNEL.dll
KERNEL.dll |
|
CreateMutexA |
뮤텍스를 만든다 |
ReleaseMutex |
뮤텍스를 해제한다 |
CreatePipe |
파이프를 만든다. |
PeekNamedPipe |
파이프로부터 데이터를 읽는다 |
ReadFile |
오브젝트에 데이터를 읽는다 |
WriteFile |
오브젝트에 데이터를 쓴다 |
[표 2-7 KERNEL.dll의 의심되는 함수들]
KERNEL.dll에서 의심이 가는 함수의 내용은 두 가지로 분류 될 수 있다. Mutex와 Pipe이다.
Mutex는 프로그램을 중복실행 방지를 하여 프로그램 충돌을 예방할 때 쓰인다.
Pipe는 프로세스끼리 통신을 할 때 쓰이는 함수이며 파이프에 데이터를 넣고 꺼내며 확인한다.
USER32.dll
USER32.dll |
|
ShowWindow |
창의 표시유무 |
[표 2-8 USER32.dll의 의심되는 함수들]
USER32.dll에서 ShowWindow가 쓰인 것으로 보아 프로그램 은폐의 가능성이 있다.
기본 동적 분석
Regshot
기본 정적 분석의 결과 레지스트리 함수가 발견되어 레지스트리 변경 가능성이 있다고 판단 하여 이 툴을 사용한다.
Regshot은 레지스트리의 프로그램 실행 기점으로 변경사항을 알려준다
프로그램 실행 전 1st shot을 눌러 레지스트리 값을 저장하고 프로그램 실행 후 2nd shot을 누르면 레지스트리 변동사항을 자동 분석한다.
앞서 추측한 내용대로 레지스트리 Run키에 접근을 하여 자동실행 레지스트리를 등록했다고 알 수 있다.
실제 경로를 따라가 확인해보니 TwoIceFish라는 값이 생성된 것을 확인 할 수 있다.
SysAnalyZer
분석하고자 하는 파일의 행동을 분석 수집 하는 프로그램이다. Registry와 Pipe관련 함수가 사용 된 것으로 보아 레지스트리 접근 및 파일의 송 수신 가능성을 염두 해 분석을 진행한다.
해당 프로그램은 1338 포트를 이용하는 것으로 나타났다.
정적 분석에서 판단한 것과 같이 레지스트리를 읽고 값을 쓰는 모습을 볼 수 있다.
포트번호 1337 또는 1338을 통해 통신을 시도하는 모습이다.
Mutex를 생성해 프로그램 중복 방지를 한다.
Pipe를 생성하여 통신을 하는 것으로 파악된다.
고급 정적 분석
앞서 분석한 내용들을 바탕으로 더욱 심도 있게 파악하는 과정이다
IDA
프로그램의 흐름을 시각적으로 표현해주는 프로그램이며 분기점을 한눈에 파악 할 수 있는 것이 장점이다
Registry 함수
RegOpenKeyExA, RegSetValueExA 와 RegCloseKey 함수가 쓰이고 있으며 레지스트 키를 열어 값을 설정 후 레지스트리 키를 닫는 내용이다.
ShowWindow 함수
GetConsoleWindow로 콘솔기반의 윈도우를 생성하고 ShowWindow로 표시할지 안 할지 선택한다.
Socket 함수
소켓통신을 준비하기위해 WSAStartup 함수가 등장한 것을 알 수 있다.
Bind 분기점
포트와 바인딩을 실패 시 건너는 분기점으로써 다시 바인딩을 시도한다.
539h 는 10진수로 1337이다 즉 포트번호 1337에 바인딩을 하는 부분이다
Listening 분기점
바인딩이 성공적으로 끝나고 Listening을 한다. 실패 시 좌측에서 소켓을 초기화하고 리턴하고 성공적으로 수행 시 오른쪽을 따라 내려간다
Accept 함수
소켓에 대한 클라이언트 요청이 들어왔을 때 Accept 발생 한다. 이 함수가 호출 되는 것은 클라이언트와 연결이 되었다 라고 판단 할 수 있다. 클라이언트에 대한 통신을 CreateThread로 넘겨준다.
고급 동적 분석
Ollydbg
명령어를 한 줄 씩 실행해 행위를 분석할 수 있는 도구
RegOpenKeyExA
401000은 프로그램의 메인 함수 EP이다.
40101F에서 argv[0] 값을 ESI에 옮기고 있다.
레지스트 ESI 값에 argv[0]값이 들어가 있으며 저장위치는 364AC0이다.
주소 00364AC0에 문자열이 저장 되어 있다.
프로그램은 순차적으로 실행이 되며 RegOpenKeyExA 와 lstrlenA 함수를 실행 한다.
401039 |
RegOpenKeyExA |
레지스트리 키를 여는 함수 |
401040 |
lstrlenA |
멀티 바이트 문자 열 길이를 구하는 함수 |
[표 2-9 RegOpenKeyExA , lstrlenA 함수 설명]
lstrlenA 함수 내부
7C80BE74~7C80BE79 는 루프이며 글자를 하나 읽을 때마다 EAX를 증가시킨다 EDX는 원본 문자열이 들어있다. 최종 읽은 바이트만큼 EAX값이 증가한 값을 EDX와 빼기 비교를 해 문자열 길이를 얻는다.
연산 결과 EAX에 46(Hex)가 들어있다. 10진수로 문자열길이는 70이다.
RegSetValueExA
lstrlenA 함수에서 얻은 결과가 있는 EAX를 Bufsiz의 인자로 넣는다
ESI는 argv[0] 에서 얻은 문자열이 저장되어 있는 주소를 스택에 넣는다
함수에 필요한 인자들을 스택에 역순으로 넣는다.
스택에 있는 인자들을 역순으로 꺼내면 다음 과 같다
RegSetVAlueExA( 40 , ”TwoIceFish” ,0 , REG_EZ , 주소00364AC0 , 46 ) |
이러한 방법으로 인자를 받아 RegSetValueExA 함수가 동작을 하게 된다.
RegCloseKey
RegCloseKey함수를 이용하여 키를 닫는다.
GetConsoleWindow , ShowWindow
콘솔기반 윈도우를 띄우며 윈도우창을 보여줄 것인지 결정하는 함수이다
GetConsoleWindow로 EAX값을 구하여 ShowWindow(EAX,EDI) 로 인자를 넘긴다
0이 의미하는 것은 창을 숨기는 것이다.
Bind
539(Hex)는 10진수로 1337로 포트를 바인딩하고있다.
Select
소켓 상태를 판정하는 함수이다
통신 상태 체크 분기점
현재 Select 함수 결과 소켓상태 확인후 연결이 안되어 있다고 판단 하면 Select 함수를 다시 호출한다. 정상적인 경우 Accept함수가 소켓에 들어오는 연결 시도를 허용하며 스레드를 생성한다.
3 결론
함수의 흐름을 요약하면 다음과 같다.
Registry 작성 -> Window창 보임 여부 -> mutex 생성 -> 소켓 생성 ->소켓 바인딩 ->리스닝 -> 스레드 생성
4 참고 문헌
사이트
MSDN-Run and RunOnce Registry Keys
https://msdn.microsoft.com/ko-kr/library/windows/desktop/aa376977(v=vs.85).aspx
MSDN-Accept
https://msdn.microsoft.com/en-us/library/windows/desktop/ms737526(v=vs.85).aspx