2018. 7. 19. 23:36 악성코드 분석

GCC 사용법

1. 개요

2. 실행 파일

.... 2.1 간략한 부분

.... 2.2 실제 예제

3. 라이브러리

.... 3.1 정적 라이브러리

.... 3.2 동적 라이브러리





1. 개요

  gcc의 옵션은 매우 다양하지만 여기서는 악성코드 분석에 도움이 될 정도의 내용만 적기로 한다. 즉 자세한 내용은 생략하며 필요한 부분의 경우에는 실제 예제와 함께 설명하도록 한다.


  전체적인 구성은 옵션을 따로 정리한다던가 하지 않고 간단한 것부터 시작해서 하나 하나 추가해 나갈 것이다. 옵션만 따로 정리하는 방식 자체도 중요하겠지만 개발 위주가 아니므로 간략한 개발 및 필요한 부분에 대한 빠른 복붙을 목적으로 하겠다.


  하지만 언제 필요할지 모르므로 간략한 배경지식은 언급하기로 한다. GCC의 경우 간단한 컴파일러로 생각할 수 있지만 사실 순서대로 다음의 명령을 호출하는 역할을 담당하는 프로그램이라고 생각하면 된다. 가장 먼저 전처리기인 cpp0가 사용되며 이를 통해 전처리 단계가 진행된다. 이후 실제 컴파일러인 cc1이 컴파일 과정을 담당한다. 그리고 어셈블러인 as가 어셈블 단계를 진행하고 이에 따라 목적 파일이 생성된다. "gcc -c" 옵션을 사용하는 경우 어셈블 단계까지만 진행되고 이후 .o 파일이 생성된다. 마지막으로 링크 단계인데 이것은 링커인 ld가 맡는다.





2. 실행 파일

2.1 간략한 부분


$ gcc hello.c

  c 소스 코드인 hello.c를 컴파일하여 실행 파일인 "a.out"이 생성된다. 생성되는 파일 이름을 지정해주지 않았기 때문에 디폴트로 "a.out"이라는 실행 파일이 생성되는 것이다.


$ gcc -o hello hello.c

  구체적으로 생성되는 파일명 즉 "hello"를 지정해 준다.


$ gcc -c main.c func1.c func2.c

$ gcc -o hello main.o func1.o func2.o

  이것은 위에서 설명했듯이 -c 옵션을 이용해 목적 파일인 .o 파일들을 생성한다. 이후 목적 파일들을 모두 링크하는 방식이다.


  참고로 헤더 파일을 인클루드할 때 다음과 같이 두 가지의 방식이 사용된다.

#include "sum.h"

#include <stdio.h>

  여기서 ""는 현재 폴더에서, <>는 표준 include 디렉터리에서 헤더 파일을 찾으라는 것을 의미한다. -l 옵션을 이용하면 구체적으로 찾을 위치를 명시할 수 있다.

$ gcc -I/home/sanser/include -o hello hello.c



2.2 실제 예제

2.2.1 mirai의 loader

$ gcc -static -O3 -lpthread -pthread src/*.c -o loader


  미라이의 loader는 컴파일 시 위와 같은 옵션이 사용된다. "-static" 옵션은 정적으로 컴파일하라는 옵션이다. 이 옵션이 없으면 디폴트로 동적으로 컴파일 된다. -O 옵션의 경우 0부터 4까지 존재하며 숫자가 커질수록 더 강한 최적화가 진행된다. 


  마지막으로 "-lpthread", "-pthread" 옵션이 있다. pthread 관련 헤더를 소스 코드 상에서 include하였음에도 불구하고 이러한 옵션이 사용되는 이유는 컴파일 시에 해당 라이브러리가 사용되었다는 것을 알 수 있지만 링커에게도 pthread 라이브러리가 사용되었다는 사실을 알려야 하기 때문이다. 문제는 l 유무의 차이이다. 사실 위에서 -l이 헤더 파일의 위치를 지정할 때 사용된 적이 있었다. 하지만 여기서는 조금 다른 의미인 것 같다. 그냥 -pthread만 사용할 시에는 컴파일러와 링커에게 모두 알리는 것이며, -lpthread를 사용하면 링커에게만 알리는 것이라고 한다. 사실 정확히 구체적으로 둘 중 무엇을 언제 사용해야 하는지나 장단점, 그리고 여기에서 사용되었듯이 두 개를 모두 사용하는 이유 등은 파악하지 못했다. 참고로 -include 옵션도 헤더 파일 경로를 지정하는데 사용된다고 한다.



2.2.2 mirai의 bot

  자동화를 위해 함수로 구현되어 있다. 그래서 $1, $2, $3을 인자로 받는다. 여기서는 디버그 옵션 말고 릴리즈 옵션 기준으로 설명하겠다.


$ gcc -std=c99 $3 bot/*.c -O3 -fomit-frame-pointer -fdata-sections -ffunction-sections -Wl,--gc-sections -o release/"$2" -DMIRAI_BOT_ARCH=\""$1"\"


  $3은 소스 코드를 봤을 때 "-DMIRAI_TELNET -DKILLER_REBIND_SSH -static" 또는 "-DMIRAI_SSH -DKILLER_REBIND_SSH -static"를 의미한다. 옵션은 "-D"이며 뒤에 붙은 문자열은 #define 값이다. 즉 소스 코드에서 "#ifdef MIRAI_SSH  ....  #else  ....  #endif" 같은 #define 구문을 사용되었을 때 gcc의 경우 커맨드 라인으로 #define을 지정할 수 있는 것이다.


  "-static"이나 "-O3", "-o release/"$2"" 부분은 위에서 언급하였다. 함수로 구현되어 있기 때문에 $2에는 컴파일 결과 바이너리의 이름을 인자로 넣는다. "-std=c99"는 C언어의 C99 표준을 의미한다. "-fomit-frame-pointer"는 프레임 포인터가 필요하지 않은 함수에서까지 프레임 포인터 레지스터를 사용하지 않겠다는 의미이다. 일반적으로 우리가 보는 함수들은 스택 프레임을 설정하는데 예를들어 "push ebp", "mov ebp, esp"를 이용해 시작하는 것이 그것이다. 이것을 사용할 경우 디버깅이 쉽거나 하지만 작은 함수에서는 스택 프레임이 꼭 필요하지 않으며 이러한 경우처럼 항상 스택 프레임을 만들지 않겠다는 의미이다.


  "-fdata-sections" 옵션과 "-ffunction-sections" 옵션은 컴파일러에게 함수나(코드) 데이터를 해당 섹션에 위치시키라는 의미이다. 이 옵션을 사용하지 않는 경우에는 임의의 섹션에 코드나 데이터가 들어갈 수 있다. 하지만 이 옵션을 이용해 해당 섹션에 강제로 위치시킬 수 있다. 이것은 다음에 나오는 링커 옵션과 연관시켜 설명하겠다.


  "-Wl" 옵션은 이후 링커에게 옵션을 주겠다는 의미이다. 즉 다음에 나오는 "--gc-sections" 옵션이 링커가 받는 옵션이다. 이 옵션은 사용되지 않는 섹션을 만들지 마라는 의미이다. 앞에서 나온 "-fdata-sections" 옵션과 "-ffunction-sections" 옵션으로 코드와 데이터를 임의의 섹션에 위치할 가능성을 없애고 이 옵션을 사용함으로써 안전하게 사용되지 않는 섹션을 제거하는 것이다. 앞에서 정적으로 링크함에 따라 크기가 커지는데 이 옵션을 통해 최대한 크기를 줄이는 목적을 가지고 있다.



2.2.3 strip

  gcc 관련 내용이지만 악성코드 분석에는 strip 또한 중요하므로 여기에서 언급하기로 한다. mirai의 bot은 컴파일 이후 strip 명령 또한 사용한다. 약간 수정하면 다음과 같다.


$ strip release/"$2" -S --strip-unneeded --remove-section=.note.gnu.gold-version --remove-section=.comment --remove-section=.note --remove-section=.note.gnu.build-id --remove-section=.note.ABI-tag --remove-section=.jcr --remove-section=.got.plt --remove-section=.eh_frame --remove-section=.eh_frame_ptr --remove-section=.eh_frame_hdr


  반복되는 내용이 많으므로 실제로 볼 것은 몇 개 없다. 먼저 "-S" 옵션은 디버그 심볼을 삭제하는 옵션이다. 참고로 모든 심볼을 삭제하는 옵션은 "-s"이며 링커 옵션으로 "-s" 옵션이 존재하는데 이것도 실행 파일에서 심볼 테이블을 제거하라는 의미이다. "--remove-unneeded"는 이름과 같이 사용되지 않는 심볼을 삭제하라는 명령이다. "--remove-section="은 섹션 자체를 삭제하는 옵션이다. 정적으로 컴파일한 경우 용량이 상당히 커지기 때문에 앞의 gcc 옵션부터 시작해서 크기 관련한 최적화에 상당히 공을 들인 것으로 보인다.





3. 라이브러리

  윈도우와 마찬가지로 리눅스도 정적 라이브러리와 동적 (공유) 라이브러리가 존재한다. 정적 라이브러리의 경우 윈도우는 ".lib" 확장자를 갖으며 리눅스에서는 통상 이름 앞에는 "lib"을, 뒤에는 ".a"를 붙인다. 동적 라이브러리의 경우 윈도우는 ".dll" 확장자를 갖으며 리눅스에서는 이름 앞에는 "lib"을, 뒤에는 ".so"를 붙인다.



3.1 정적 라이브러리

  앞에서도 언급하였듯이 정적 라이브러리는 libxxx.a라는 형태를 가진다. 일반적으로 다음과 같이 사용한다.


$ gcc -c test1.c test2.c

// test1.o, test2.o 생성

$ ar rc libtest.a test1.o test2.o

// test1.o, test2.o 목적 파일을 가지고 libtest.a라는 정적 라이브러리를 만든다. 정적 라이브러리를 만들 때는 gcc가 아닌 ar이라는 프로그램을 사용한다. r은 이 라이브러리 아카이브에 새로운 오브젝트를 추가할 것이라는 옵션이고 c는 아카이브가 존재하지 않을 경우 생성하라는 옵션이다.

$ gcc -o hello hello.c -L./ -llibtest.a

// 만든 라이브러리를 링크하려면 해당 라이브러리의 위치를 가르쳐줘야 하는데, -L로 디렉토리의 위치를, -l로 라이브러리의 이름을 명시해야 한다.

$ ar t libtest.a

// t는 해당 라이브러리가 어떤 오브젝트 파일을 포함하고 있는지를 보여준다.



3.2 동적 라이브러리

  앞에서도 언급하였듯이 동적 라이브러리는 libxxx.so라는 형태를 가진다. 일반적으로 다음과 같이 사용한다.


$ gcc -fPIC -c test1.c test2.c

// test.o를 생성하는데 위치 독립적인 코드를 만들기 위해 -fPIC 옵션을 준다.

$ gcc -shared -o libtest.so test1.o test2.o

// test1.o, test2.o를 이용해 litest.so 파일을 생성하며, 동적 라이브러리를 만들 때는 gcc에 옵션으로 -shared를 준다. 

$ gcc -o hello hello.c -L./ -ltest

// 동적 라이브러리의 경우 -l 뒤에 "test" 같이 이름만 붙이나 보다.


  참고로 라이브러리를 사용할 때 에러가 뜰 수 있는데 이 때는 etc/ld.so.conf에 경로를 설정한 후 ldconfig로 캐시를 갱신하면 된다. 이 설정 파일은 "include ld.so.conf.d/*.conf"라고 되어 있는데 저 디렉토리에 test.conf라는 파일을 만들고 그냥 내가 만든 라이브러리의 경로만 적어주면 된다. 또는 LD_LIBRARY_PATH 환경변수를 이용하여 설정할 수 있다. export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/me/ 이런 식으로 해주면 된다. 아니면 심볼릭링크를 걸어서 해도 된다.





* 라이브러리 관련 환경 변수

  리눅스에서 공유 라이브러리는 /usr/lib 또는 /usr/lib64에 저장된다. 이곳에 libc.so.6 같은 파일들이 저장되어 있다. 참고로 라이브러리는 관례 상 접두어 lib와 이름 그리고 .so, 마지막으로 버전 번호로 이루어진다. 공유 라이브러리를 호출하기 위해서는 PATH를 지정해야 한다. 로더는 LD_LIBRARY_PATH 환경 변수 또는 ld.so.conf에 명시된 디렉토리에서 라이브러리를 찾아서 로드한다. ldconfig 명령어는 /etc/ld.so.conf 파일에 설정된 동적 라이브러리 정보를 /etc/ld.so.cache 파일로 만들어 주는 일을 하는데 이것은 로더가 ld.so.cache 정보를 가지고 더 빠르게 라이브러리를 찾을 수 있게 한다.


Posted by SanseoLab

블로그 이미지
Malware Analyst
SanseoLab

태그목록

공지사항

Yesterday
Today
Total

달력

 « |  » 2024.4
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30

최근에 올라온 글

최근에 달린 댓글

글 보관함