2007. 11. 14. 17:56
     

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 관련 루틴을 따라가서 분석하는 기능 추가하기

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


Android App

Posted by 호기심 많은 kkamagui(까마귀, 한승훈)

댓글을 달아 주세요

  1. Favicon of http://blog.naver.com/kimmch696 BlogIcon 지쳐가는4학년 2011.11.02 10:38  댓글주소  수정/삭제  댓글쓰기

    여기서 많은 자료 얻어가고 공부해가는 학생입니다^^
    이번에 디스어셈블러를 만들어 볼까 해서 시작했습니다 ㅎ
    IA-32 메뉴얼을 열심히 구독하지만 꼬부랑 글씨들 번역기 돌리면 외계어네요 ㅋ 아는 용어 다 동원해서 의역하지만 감이 잘 잡히지 않습니다... 보니 파이썬으로 만들어진 모듈을 사용하셨더군요... 혹시!! 파이썬 이든 아니든 그러한 모듈을 직접 만들 방법은 없을까요 ㅎ? 감이라도 맛 볼 수 있었으면 합니다 ㅎ
    저번에 감을 못 잡아서 gg 쳤던 필터드라이버 처럼 중도에 때려치지만 않았으면 합니다 ㅎㅎㅎ

    • Favicon of https://kkamagui.tistory.com BlogIcon 호기심 많은 kkamagui(까마귀, 한승훈) 2011.11.04 00:50 신고  댓글주소  수정/삭제

      안녕하세요, 4학년님 ^^

      디스어셈블러도 당연히 만들 수 있습니다. ^^

      다만, 바이너리 데이터를 분석해서 역으로 어셈블리어 코드를 만드는 것이 좀 까다롭지요. ㅠㅠ

      인텔 아키텍쳐 메뉴얼 Volume 2를 보면, 어셈블리어 코드가 어떤 방식으로 바이너리 데이터로 바뀌는지에 대한 내용이 나와있습니다. 이 부분을 자세히 들여다보면 바이너리 데이터를 어떻게 해석해야할지 힌트를 얻을 수 있을 것 같네요. ^^

      그리고 NASM과 같은 어셈블러는 소스 코드가 공개되어 있고, 디스어셈블러도 포함하고 있으니 이 부분을 참고하시는 것도 좋을 것 같습니다. ^^

      그럼 화이팅입니다. ;)