개요
분석을 시작하면 Win32 PE 파일을 가장 많이 분석한다곤 하지만, 이 PE 파일도 컴파일러나 프레임워크에 따라 정말 세분화 되어있습니다. 당장 생각나는 것만 해도 VB, dotNet, C, C++, MFC, Delphi 까지… 풀스택 분석가의 길은 정말이지 멀고도 험하기만 합니다. ELF는 언제 하나요…?
어셈블리어만 볼 줄 알면 분석하는거 아닌가? 하는 접신의 경지에 오른 분석가분들도 계시지만 전 하찮은 미물일 뿐인지라 분석 도구의 도움이 필수적입니다. 이번 글에서는 델파이로 작성된 프로그램을 좀 더 빠르고 쉽게 분석하기 위한 방법에 대해 다룹니다.
언제 그렇듯이 피드백은 환영합니다.
Delphi 언어는…
Delphi(이하 델파이) 는 파스칼 기반 객체지향 프로그래밍 언어입니다. C++ 을 분석하는 것과 매우 유사한 방식으로 분석할 수 있습니다. 다시 말하자면 클래스를 쫓아 대입해주는 아주 귀찮은 과정을 거쳐야 한다는 말이죠.
델파이 바이너리 특징
델파이 동작에 필요한 라이브러리(Delphi RTL, Run Time Library) 은 보통 컴파일 단계에서 해당 실행파일에 정적으로 박혀있습니다. 이로 인해 델파이로 작성된 실행파일은 대게 실행바이너리 치곤 많은 함수와 큰 크기를 갖습니다. 컴포넌트 코드는 보통 컴파일러에 의해 실행코드 앞단에 자리하고, 유저코드(사용자가 작성한 코드)가 뒤에 따라옵니다. 이런 컴포넌트 코드에 이름을 잘 붙이는 것이 분석의 핵심이고, 이걸 잘 해야 시간을 아낄 수 있습니다. 만약 IDA를 사용한다면, 적절한 FLIRT 시그니처가 적용됐는지 꼭 확인하세요.
RTL 에 관한 정보는 Embarcadero 웹사이트에 잘 문서화되어 있습니다. 일종의 MSDN 이라 생각하면 됩니다.1
IDR 소개
IDR2 또한 고유의 시그니처를 갖고있고, 어쩔땐 클래스이름이나 디컴파일된 코드 등 분석에 매우 유용한 정보를 제공해줍니다. IDR의 정보를 익스포트해 IDC로 만들고, 이를 다시 IDA에 로드시켜 IDA 에서 쉽게 분석하는 것 또한 가능합니다.
함수호출규약
델파이는 fastcall 호출규약을 따르지만 주의할점은 Windows 의 fastcall 과는 약간 다릅니다. 파라미터는 아래의 순서로 전달됩니다.
EAX, EDX, ECX, 그 외 스택
클래스의 경우 this
포인터는 EAX 로 전달됩니다. 생성자가 호출되면 EAX로 클래스 구조가 전달되고, this
포인터가 EAX로 리턴됩니다. 생성자는 System::ClassCreate()
를 호출하는 것으로 알아볼 수 있습니다. 3
델파이, 문자열 컨트롤
대게 빠른 분석을 위해 의심가는 문자열을 Xref 하여 참조하는 부분을 찾곤 합니다. 델파이는 문자열의 길이가 해당 문자열의 제일 앞에 명시되는 파스칼 스타일의 문자열을 사용합니다. 하지만 바이너리 안에 저장할 때는 C 스타일 포맷으로 저장되기에 이를 사용하기 위해선 LStrAsg
메소드 호출이 선행돼야합니다. 마찬가지 이유로 바이너리 안의 문자열을 직접 Xref 한다고 해서 원하는 위치로 바로 점프하진 못할것입니다. 따라서 문자열을 참조하는 곳을 알고 싶다면, 바로 이 문자열 변환하는 부분을 잡아야 하는데, 보통 이런 형태를 띄니 눈에 익혀두는것이 좋습니다.
mov eax, ds:off_497050 ; Pascal string
mov edx, offset a1_37 ; C-style string "1.37"
call @System@@LStrAsg$qqrpvpxv ; System::LStrAsg(void*,void*)
How to analyze
서론이 길었습니다. 아무튼, 그래서, 어떡해야 쉽고 빠르게 분석할 수 있을까요. 앞서 짧게 설명했지만 결론은 IDR 의 도움을 받아 IDA로 분석한다 고 보면 되겠습니다. 여기서부터는 이 글을 참고했습니다.
먼저 IDA 는 여러 Windows 기반 컴파일러 외에도 추가적으로 다른 OS 기반 컴파일도 제공한다는 걸 여러분은 이미 알고 계실 겁니다. IDA 에서 실행 바이너리를 열면, IDA는 해당 바이너리에 어떤 컴파일러를 적용해야 할지 결정하고, 성공적으로 결정했다면, 해당 컴파일러 라이브러리와 상호작용하는 시그니처 파일들을 로드해 나머지 코드에 적용할 것입니다.
IDA 와 함께 제공되는 시그니처는 대부분 MS의 Visual C++ 및 Borland Delphi 와 같은 독점적(?) 컴파일러와 관련돼있습니다. 그러나 아주 정확한 패턴 매칭을 위해선 각기 다른 버전의 라이브러리에 대해 시그니처 파일을 일치시킬 필요가 있습니다.4
이런 이유로 Hex-Rays 는 정적 라이브러리에서 고유한 시그니처를 생성할 수 있는 도구를 제공합니다. 1~4까지의 절차는 복잡해보이지만, 대부분의 FLIRT 는 IDA 에 내장돼 제공되기에 사실 이를 활용할 일은 잘 없습니다.
- Get the copy of the static library
- Utilize FLIRT parser to create a pattern file
- Run sigmake.exe to convert the pattern file into signiture file
- Install new signature file by coping to IDADIR/sig directory
이 시그니처 파일을 적용하기위해 File->Load File->FLIRT Signature File
을 선택합니다. 그럼 %IDADIR%\sig directory
에 미리 복사해둔 모든 시그니처가 있는 팝업창이 뜰 것입니다. 원하는 시그니처를 선택하면 됩니다. 자세한 사항은 여기를 참고하세요.
예시
따라 해봅시다. 먼저 델파이 버전을 정확히 아는것이 중요합니다. 구버전의 PEid나 Detect It Easy 등을 사용한다면 정확한 결과가 나오지 않을 수 있으므로, 반드시 최신버전의 PE identifier 를 사용합니다.
DIE 를 통해 나온 결과로 IDA에서 FLIRT를 적용해줍니다. 일단 아래 과정만 마치면 IDA로 분석할 준비는 끝난 것입니다.
하지만 아직 unknown_libname_ 접두어로 시작하는 함수가 많이 남아있음을 알 수 있습니다. IDR 의 도움을 받으면 이런 메쏘드들에도 이름을 좀 더 붙여줄 수 있습니다.
IDR 자체도 굉장히 훌륭한 디스어셈블러지만, 아무래도 IDA 사용이 익숙하기에 IDR의 분석정보를 IDA에 가져와 보겠습니다. IDR은 여기 서 받을 수 있습니다. Main executable file 과 Auxiliary files 는 프로그램 구동에 필요한 필수 파일이고, 나머지 Knowledge base 를 디컴파일 할 델파이 바이너리 버전에 맞게 다운받아 같은 폴더에 넣고 실행하면 됩니다.
실행하면 위와 같은 창이 나타납니다. 이제 원하는 델파이 바이너리를 디컴파일 하고, MAP 파일을 생성해 줍니다. 올리와 IDA 를 많이 다뤄보신 분은 올리에 MAP 파일을 올려 함수명을 보기 쉽게 바꿔본 경험이 있으실 겁니다. IDA에서도 플러그인을 활용해 같은 일을 할 수 있습니다.
먼저 IDR 에서 Tools->MAP Generator
로 MAP 파일을 만듭니다. 그리고 이 MAP 파일을 IDA로 불러옵니다. 저는 이를 위해 LoadMAP 플러그인을 사용했습니다. IDA SDK 6.2 에 맞춰 개발했다고 하나 현재 제가 사용하는 IDA 6.5에서 정상적으로 동작하는 것을 확인했습니다. 아래는 MAP 파일을 불러오기 전과 후의 모습니다.
여기까지 왔다면 사용자정의 클래스·함수 외에 거의 모든 내장 함수에 이름이 붙어있을 것입니다. 나머진 객체지향언어를 분석하는 분석가의 몫이겠죠. 이번 예시에 사용한 샘플은 ed4037b035896f36fce543e772b912e3 입니다. 이번에도 누군가에겐 도움이 되었길 바라며… 피드백은 언제나 환영합니다.
블로깅 하신 내용이 많은 도움이 되었습니다.
자주 들러 공부하도록 할게요.
응원드립니다!!
도움이 되었다니 다행입니다