03 DLL 디스어셈블러 만들기

원문 : http://kkamagui.springnote.com/pages/388049

 

들어가기 전에...

 

 항상 분석을 하면 노가다가 많고 일일이 손으로 클릭을 해가면서 또는 눈으로 찾아가면서 분석을 해야 했다. 내가 원체 UI에 별로 관심이 없다보니 UI의 수준은 당연 극악의 콘솔형태... 물론 생긴건 GUI다.(그만큼 UI가 엉망이라는.... ㅡ_ㅡ;;;). 언젠가 한번 DLL 분석 툴을 파이썬으로 만들면 재미있겠다고 생각했는데... 파이썬용 디스어셈블러 자료는 찾아놓고 실제로 DLL을 파이썬으로 당겨야 하는데 엄두가 나지 않았다.

 오늘 잠시 짬을 내서 일하다 잠도 안자고 해봤는데, 의외로 C 함수를 쓰는게 간단하다.

 

DLL 및 C 타입의 변수 등등의 사용

 DLL을 로드해서 사용하는 코드를 C로 만들면 LoadLibrary() 함수를 호출하고 다시 GetProcAddress()를 호출하면 된다. 파이썬에서는 이것을 어떻게 할까? 블로그를 찾아보고 파이썬 마을을 둘러봤더니 ctypes라는 것이 보였다. Python 2.5 버전에서 표준 라이브러리에 포함되어있는 라이브러리라는데, 상당히 C 스타일 적이다.(아래는 Python 문서에 포함된 예제이다.)

  1. >>> from ctypes import *
    >>> print windll.kernel32
  2. <WinDLL 'kernel32', handle ... at ...>
    >>> print cdll.msvcrt
  3. <CDLL 'msvcrt', handle ... at ...>
    >>> libc = cdll.msvcrt

 windll에 보면 kernel32.dll, gdi32.dll 등등의 DLL의 정보를 포함하는 모듈이 들어있음을 알 수 있다. C 런타임 라이브러리도 사용할 수 있는데, cdll.msvcrt를 모듈을 이용하면 C 라이브러리를 사용할 수 있다.

  1. >>> from ctypes import *
    >>> libc.printf
    <_FuncPtr object at 0x...>
    >>> print windll.kernel32.GetModuleHandleA
  2. <_FuncPtr object at 0x...>

 재미있는 부분은 포인터도 사용할 수 있다는 것이다.(크아... 이제 완전 게임 끝났다.. @0@)/~ 이렇게 좋을 수가.. ㅜ_ㅜ)

  1. >>> from ctypes import *
    >>> i = c_int(42)
    >>> pi = pointer(i)
    >>> pi.contents
    c_long(42)

 더 자세한 사항은 파이썬 도움말을 참고하도록 하자.

 

디스어셈블러(Disassember) 모듈

 디스어셈블러 모듈은 파이썬 용으로 따로 개발된게 있다.(어찌나 다행인지.. ㅡ_ㅡ;;; 내가 가지고 있는걸로 파이썬에 붙일려고 했는데, 이렇게 되면 기절한다... ㅡ_ㅡ;;;)

 http://www.ragestorm.net/distorm/ 사이트에 가면 파이썬용 모듈을 받을 수 있고 간단히 pyd파일을 받아서 파이썬이 설치된 Lib 폴더에 넣기만 하면 편하게 사용할 수 있다. 아래는 위 홈페이지에서 설명해 놓은 사용 예제이다.

  1. Note: Save the file in %PYTHONDIR%\Lib\site-packages\
    from distorm import Decode, Decode16Bits, Decode32Bits, Decode64Bits
    l = Decode(0x100, open("file.com", "rb").read(), Decode16Bits)
    for i in l:
     print "0x%08x (%02x) %-20s %s" % (i[0],  i[1],  i[3],  i[2])

 

 

디스어셈블러 작성

 이제 디스어셈블러를 작성할 준비가 모두 끝났다. 이제 이 모듈들을 이용하여 kernel32.dll에 있는 OpenProcess 함수를 디스어셈블리해보자.

  1. # -*- coding: cp949 -*-
    from distorm import Decode, Decode16Bits, Decode32Bits, Decode64Bits
    # c관련 함수를 사용하기위해 처리
    from ctypes import *
    import ctypes
  2. # c 런타임 라이브러리를 가지고 있음
    libc = cdll.msvcrt;
    # kernel32.dll을 여는 여러 방법
    #kernel32 = windll.kernel32;
    kernel32 = windll.LoadLibrary( 'kernel32.dll' );
  3. # OpenProcess를 얻는다.
    openProcessAddress = kernel32.GetProcAddress( kernel32._handle, "OpenProcess" );
  4. # 버퍼를 할당해서 디스어셈블리를 하기위해 버퍼에 넣는다.
    buf = ctypes.c_buffer( 4096 );
    libc.memcpy( buf, openProcessAddress, 4096 );
    #libc.memcpy( buf, 0x7c809b96, 4096 );
  5. l = Decode(openProcessAddress, buf, Decode32Bits)
    for i in l:
        # 아래와 같은 형식으로 출력된다.
        # 0x7c8309e1 (02) 8bff                 MOV EDI, EDI
        print "0x%08X (%02X) %-20s %s" % (i[0],  i[1],  i[3].upper(),  i[2])

 

 소스 코드는 위와 같이 아주 간단하다. 출력 결과는 아래와 같이 깔끔하게 나온다.

0x7C8309E1 (02) 8BFF                 MOV EDI, EDI
0x7C8309E3 (01) 55                   PUSH EBP
0x7C8309E4 (02) 8BEC                 MOV EBP, ESP
0x7C8309E6 (03) 83EC 20              SUB ESP, 0x20
0x7C8309E9 (03) 8B45 10              MOV EAX, [EBP+0x10]
0x7C8309EC (03) 8945 F8              MOV [EBP-0x8], EAX
0x7C8309EF (03) 8B45 0C              MOV EAX, [EBP+0xc]
0x7C8309F2 (01) 56                   PUSH ESI

 

 정말 멋지다.. ㅜ_ㅜ... 이렇게 몇줄 작성하지 않았는데 이런 결과가 나오다니... ㅡ_ㅜ... 정말 환상적이지 않을 수 없다. ㅜ_ㅜ...

 파이썬 만쉐이.. ㅜ_ㅜ...

 

첨부

 

 

TODO

  • 코드 내부에 있는 Jump 및 Call 관련 루틴을 따라가서 분석하는 기능 추가하기

이 글은 스프링노트에서 작성되었습니다.

+ Recent posts