6장의 실습 목표는 코드 구조를 분석해 프로그램의 전반적인 기능을 이해하고자 하는 데 있다. 각 실습은 5장을 토대로 하고, 네 개의 구조로 이뤄진 하나의 복잡한 악성코드 조각을 분석해본다.
실습 6-1)
1. main이 호출하는 서브루틴만으로 발견한 주요 코드 구조는 무엇인가?
- main의 서브루틴인 sub_401000으로 들어오면 위 사진과 같이 InternetGetConnectedState 함수의 실행결과에 따라 분기가 나뉘는 것을 볼 수 있다. InternetGetConnectedState 함수는 인터넷이 연결되었는지 확인해서 연결될 경우에는 TRUE(1), 아닐 경우에는 FALSE(0)를 반환한다.
위 구조는 if 구조로 "cmp [ebp+var_4], 0"에서 반환값이 TRUE인지 FALSE인지 확인한 뒤, 만약 반환값이 TRUE일 경우에는 왼쪽 분기로, FALSE일 경우에는 오른쪽 분기로 넘어간다.
2. 0x40105F에 위치한 서브루틴은 무엇인가?
- 1번 질문의 if 구조의 각 분기로 가면 다른 문자열을 push하고 동일하게 sub_40105F를 호출한다. sub_40105F 내부로 들어가면 위 사진처럼 _stbuf, _ftbuf를 호출하는 걸 볼 수 있는데, 검색해보니 printf 함수에서 사용되기도 하는 함수라고 한다.
sub_40105F의 인자로 문자열이 넘어왔으니 이것도 printf 함수가 아닐까 추측이 되지만, 혹시 모르니 sub_401282 함수는 무슨 기능을 하는지 살펴보았다.
위 사진에서 왼쪽 아래의 구조를 보면 알 수 있듯이, 직접 보면 너무 복잡한 구조라서 그래프 기능을 사용해 어떤 함수를 호출하는지 확인했다. 문자를 처리하는 함수들을 여럿 호출하고 WriteFile 함수를 호출하는 것을 볼 수 있었다. 이 사실들을 종합했을 때 sub_40105F 함수는 printf와 동일하거나 유사하게 문자열을 출력하는 함수로 보인다.
3. 이 프로그램의 목적은 무엇인가?
- 1번 질문과 2번 질문을 답하는 과정에서 알아낸 이 프로그램의 목적은, 단순하게 인터넷에 연결되어 있는지 상태를 확인한 후 상태 여부를 출력하는 것으로 보인다.
실습 6-2)
1. main 함수가 호출하는 첫 번째 서브루틴은 무슨 오퍼레이션을 수행하는가?
- main 함수에서 호출하는 첫 번째 서브루틴(sub_401000)은 분석을 해보면 실습 6-1)에서 보았던 구조와 동일한 것을 알 수 있다. 해당 서브루틴에서는 인터넷 연결 상태를 확인한다.
2. 0x40117F에 위치한 서브루틴은 무엇인가?
- 이 질문에 대한 답변 역시 실습 6-1) 에서 볼 수 있다. 인자로 전달받은 문자열을 출력하는 역할을 하고 있다.
3. main 함수가 호출하는 두 번째 서브루틴은 무엇인가?
- 1번 질문에 사용된 첫 번째 사진을 보면, sub_401000 함수 실행 결과에 따라 분기가 나뉘는 것을 볼 수 있다. sub_401000 함수는 인터넷 연결 상태를 확인하여 연결되어있다면 1을, 그렇지 않다면 0을 반환한다.
sub_401000 함수 실행 후 반환된 값이 1일 경우(인터넷이 연결되어 있을 경우)에 비로소 오른쪽 분기(loc_401148)로 넘어간다. 해당 분기에서 두 번째 서브루틴(sub_401040)을 호출한다. 해당 서브루틴을 살펴보자.
- 위 사진은 sub_401040의 일부 영역을 캡처했다. 이 함수에서 사용된 주요 함수는 InternetOpenUrlA, InternetReadFile로 각각 특정 주소를 연결하고, 파일을 읽어오는 함수다. 이를 봤을 때 해당 함수는 인터넷을 연결하여 읽어온 파일을 이용해 어떠한 작업을 하는 함수로 보인다. InternetReadFile까지 성공적으로 실행됐을 때의 동작을 살펴보자.
- InternetReadFile 함수를 실행하여 불러온 결과는 버퍼([ebp+buffer])에 저장된다. 파일을 잘 읽어온 경우에는 위 사진의 경로를 따라가는데, 버퍼에 "<!--" 라는 문자열이 있는지 한 글자씩 비교한다. 하나라도 일치하지 않을 경우에는 우측 하단에 보이는 "Error 2.3: Fail to get command\n" 문자열을 출력하게 되고, 전부 일치한다면 어떤 값(var_20c)을 반환하게 된다. 이 값을 이용해 sub_401000에서 이후 작업들을 수행한다.
+) IDA는 Buffer 변수의 크기가 512임을 알지 못해서 var_20c 라는 지역 변수를 출력한다고 한다. 즉, 위에서 반환하는 값은 버퍼의 값이 되겠다.
4. 이 서브루틴에서 사용한 코드 구조는 어떤 유형인가?
- 3번 질문에 답할 때 간단하게 설명했는데, 이 구조 역시 반환 값이 일치하는지, 특정 문자("<", "!", "-", "-")가 맞는지 확인하여 분기가 달라지는 if 구조를 사용하고 있다.
+) HTML 주석을 파싱하는 것으로 볼 수 있다.
5. 이 프로그램에서 네트워크 기반의 행위(indicator)가 존재하는가?
- 3번 질문의 답변 과정에서 살짝 볼 수 있다. InternetOpenUrlA의 인자로 사용된 "http://www.practicalmalwareanalysis.com/cc.htm"을 네트워크 기반의 행위로 볼 수 있다.
+) User-Agent인 Internet Explorer 7.5/pma도 indicator로 볼 수 있따.
6. 이 악성코드의 목적은 무엇인가?
- 위의 답변들을 통해 알 수 있는 프로그램의 동작과정을 다시 한 번 정리하겠다.
해당 프로그램은 (sub_401000에서)처음에 인터넷에 연결되어 있는지를 확인한다. 연결되어 있을 경우, (sub_401040에서)특정 인터넷 주소("http://www.practicalmalwareanalysis.com/cc.htm")에 접근하여 파일(cc.htm)을 읽어온다. html에서 주석을 사용할 때 쓰는 "<!--" 문자열이 해당 파일의 첫부분에 있는지 확인한 후, 만약 일치한다면 그 이후에 어떤 값을 읽어온다.
위 과정을 거쳐서 만약 불러온 값이 있을 경우에는 우측 하단 분기로 넘어가 "Success: Parsed command is (불러온 값)\n"을 출력하고, 0xEA60(60,000)ms 만큼 Sleep한다.
- 위 과정을 보았을 때, 악성코드의 목적은 특정 주소의 파일에 접근해 주석("<!--") 뒷부분의 명령어를 읽어와서 수행하는 것으로 보인다.
+) HTML 주석에 명령어를 숨기는 기법은 사용자가 정상적인 웹 페이지에 접근하는 것처럼 보이게끔 공격자가 악성코드로 명령어를 보낼 때 자주 사용한다고 한다.
실습 6-3)
1. main 함수 호출과 실습 6-2의 main 함수와 비교하라. main이 호출한 새로운 함수는 무엇인가?
- 6-3의 main 함수와 6-2 함수의 main 함수를 비교해보니, 위 사진의 빨간 선 영역이 새로 추가된 것을 볼 수 있었다. 새로 추가된 함수는 sub_401130으로, 다음 질문들을 해결하며 확인해보자.
2. 새로운 함수는 어떤 인자를 갖는가?
- 위 사진을 보면 sub_401130 함수를 호출하기 전에 2개의 인자를 스택에 push 한 것을 볼 수 있다. 하나는 [ebp+argv]로 argv는 프로그램을 실행할 때 옵션 값으로 입력한 문자열을 나타낸다. IDA에서 자동으로 lpExistingFileName 이라는 주석을 달아준 것을 보아, 옵션 값으로 입력하는 문자열이 파일의 이름이 아닐까 추측된다.
다른 하나는 [ebp+var_8]로 사진에는 담기지 않았지만, 이 함수를 실행하기 전에 실행하는 sub_401040함수(접속한 인터넷 파일에서 가져온 문자)의 반환 값이 담겨있다. 이 두 인자를 sub_401130 함수로 사용한다.
3. 이 함수가 가지는 주요 코드 구조는 무엇인가?
- sub_401130 함수에서 사용한 주요 구조는 위 사진과 같다. 왼쪽의 그래프 뷰를 보면 동그라미친 작은 지점을 기준으로 분기가 나뉘는 것을 볼 수 있다. 그리고 분기가 나뉘는 조건은 형광펜으로 칠한 구문이다.
- 위의 배열에 저장된 값 중 edx([ebp+var_8])의 값에 해당하는 지점(분기)으로 넘어가 작업을 수행한다. 이 구문은 switch 구문으로 볼 수 있다. [ebp+var_8]에 어떤 값이 할당되는지는 다음 질문들을 보면서 알아보자.
4. 이 함수는 무슨 일을 하는가?
- 3번 질문에서 보았던 [ebp+var_8]에 최초로는 sub_401130 함수에 인자로 넘어온 "인터넷 파일에서 가져온 문자"가 담긴다. 가져온 값이 문자이기 때문에 이를 숫자처럼 활용하기 위해서, "가져온 문자" - "a"를 아스키코드 값으로 계산한 값을 최종적으로 [ebp+var_8]에 저장한다.
이 값을 4랑 비교해서 분기가 나뉘는데 4보다 작거나 같을 경우에는 위에서 본 switch문으로 넘어가게 되고, 4보다 클 경우에는 올바르지 않은 명령어라고 출력하는 구문으로 넘어간다.
switch 문으로 넘어간 경우에는 "입력된 문자"에 따라 총 5가지의 동작을 한다.
1) 입력된 문자가 'a' 일 때
- C드라이브에 Temp라는 디렉토리를 생성한다.
2) 입력된 문자가 'b' 일 때
- 2번 문제에서 언급된 인자들 중 하나인 argv로 저장된 파일을 C:\Temp 폴더의 cc.exe 파일로 복사한다.
3) 입력된 문자가 'c' 일 때
- C:\Temp 폴더의 cc.exe 파일을 삭제한다.
4) 입력된 문자가 'd' 일 때
- "HKLM\Microsoft\Windows\CurrentVersion\Run" 레지스트리 값을 열어서 Malware 라는 이름의 레지스트리를 등록한다. 해당 레지스트리의 내용은 C:\temp\cc.exe 이다. 해당 레지스트리는 윈도우 시작 시 자동으로 실행하는 프로그램을 설정할 때 사용하는 값으로, 이 프로그램은 cc.exe를 윈도우 시작 시 자동으로 실행하도록 한 것이다.
5) 입력된 문자가 'e' 일 때
- 0x186A0(100,000)ms만큼 Sleep 한다.
5. 이 악성코드에서 호스트 기반의 행위(indicator)가 존재하는가?
- 4번 질문의 풀이 과정에서 볼 수 있었던 "cc.exe" 파일명과 조작되었던 레지스트리 값("HKLM\Microsoft\Windows\CurrentVersion\Run\Malware" -> C:\temp\cc.exe)을 호스트 기반의 행위로 볼 수 있겠다.
6. 이 악성코드의 목적은 무엇인가?
- 프로그램의 동작 과정을 정리해보면 다음과 같다.
1. 인터넷에 연결되어 있는지 확인한다.
2. 연결되어 있을 경우 "http://www.practicalmalwareanalysis.com/cc.htm"에 접근하여 파일을 읽어온다.
3. 읽어온 파일에서 "<!--"를 확인하고, 문자를 받아온다. (HTML 주석 파싱)
4. 읽어온 문자의 값에 따라 다양하게 동작한다. (Temp 폴더 생성, cc.exe 생성, cc.exe 삭제, 레지스트리 등록, Sleep)
- 이 동작 과정을 보았을 때 해당 악성코드는 인터넷의 파일을 확인해, 여러가지 악성 행위를 수행하는 것이 목적으로 보인다.
실습 6-4)
1. 실습 6-3과 6-4의 main 함수에서 호출한 함수 간의 차이점은 무엇인가?
- 비교해본 결과 main 함수에서 호출한 서브루틴의 함수들이 달라진 것은 없다. 하지만 달라진 것이 있다면 main 함수가 돌아가는 구조가 조금 달라졌다. 이는 2번 질문에서 답하겠다.
2. 어떤 새로운 코드 구조가 main 함수에 추가됐는가?
- 6-3까지의 실습과는 다르게 [ebp+var_C]를 카운터 변수로 사용하는 for문 구조를 사용하는 것을 볼 수 있었다. 이 for문 안에 인터넷에 접속하여 파일을 읽어오는 함수(sub_401040), 읽어온 문자에 따라 여러가지 행위를 수행하는 함수(sub_401150)들이 포함되어 있다.
3. 이 실습의 HTML 함수 파싱이 기존 실습과 차이점은 무엇인가?
- 왼쪽 사진을 보면 for문의 카운터변수로 사용되는 [ebp+var_C]가 sub_401040의 인자로 사용되는 걸 볼 수 있는데, 이 값은 오른쪽 사진에서 보면 szAgent에 "Internet Explorer 7.50/pma(카운터변수)"로 사용되는 것을 볼 수 있다.
여기서 저장된 szAgent는 InternetOpenA에서 lpszAgent로 사용되는데, lpszAgent는 HTTP 프로토콜로 통신할 때 User-Agent의 이름으로 사용된다고 한다. 즉, User-Agent의 이름이 실행한 횟수에 따라 달라지는 점이 있다.
4. 프로그램이 얼마나 오래 동작하는가?(인터넷에 연결돼 있다고 가정함)
- 만일 sub_401150 함수 내에서 Sleep을 하는 명령어가 실행되지 않는다면, 기본적으로 위 사진에 나온 0xEA60(60,000)ms 만큼을 Sleep하게 된다. 여기에 앞에서 말했듯, 이번 프로그램은 반복문을 도는데 질문 3의 왼쪽 사진을 보면 총 0x5A0(1,440)번을 반복하는 것을 알 수 있다. 즉 기본적으로 60초 x 1,440번(24시간)만큼 동작한다.
- 하지만 만약 Sleep하는 명령어가 매번 실행된다면, 한 반복문 당 추가로 0x186A0(100,000)ms 만큼을 Sleep하게 된다. 이 경우에는 최종적으로 (100초+60초) x 1,440번(60시간)에 해당하는 시간만큼 동작한다.
5. 이 악성코드에서 네트워크 기반의 행위(indicator)가 존재하는가?
- 이전 실습과 다르게 새로 추가된 네트워크 기반의 행위로는, 질문 3번에서 보았던 "Internet Explorer 7.50/pma(카운터변수)"가 될 수 있을 것 같다.
6. 이 악성코드의 목적은 무엇인가?
- 기본적으로는 실습 6-3)과 동일하며, 오랜 시간(최소 24시간)동안 돌아가도록 하는 기능이 추가되었다.
'악성코드 분석 > Practical Malware Analysis 실습' 카테고리의 다른 글
[Practical Malware Analysis] Lab 07-03 (0) | 2023.05.21 |
---|---|
[Practical Malware Analysis] Lab 07-01, 02 (0) | 2023.05.14 |
[Practical Malware Analysis] Lab 05 (0) | 2023.05.06 |
[Practical Malware Analysis] Lab 03 (0) | 2023.05.06 |
[Practical Malware Analysis] Lab 01 (0) | 2023.05.01 |