PHC/Python2012.04.02 00:39

access_violation_handler.py


buffer_overflow.py




이번에는 접근 위반 핸들러 프로그래밍을 해보겠습니다.

접근 위반(Access Violation) 이란 ?

접근할 권한이 없는 메모리에 접근하려고 하거나 허용되지 않는 특별한 방법으로 메모리에 접근하려고 할때

발생하는 예외입니다.

프로그램적인 결함에 의해 발생하는 접근위반의 종류로는 버퍼 오버플로우가 발생햇을때, 널 포인터를 잘못사용하는경우 등

다양합니다.

디버깅 대상 프로세스에서 접근위반 이 발생한다면 디버거가 그것을 처리해야 합니다.

예외가 발생햇을때 디버거는 스택 프레임,레지스터,예외를 발생시킨 명령 등 모든 정보를 추적할수 있습니다.

이런 정보를 기반으로 취약점 공격 코드를 작성하거나 바이너리 패치를 만들어낼수 있습니다.

PyDbg를 이용하면 예외와 관련된 모든 정보를 쉽게 얻을수 있는 유틸리티 함수를 사용할수도 있으며

예외처리 핸들러를 쉽게 설치할수도 있습니다.

지금부터 버퍼 오버플로우를 발생시키는 프로그램을 하나 작성하고

그 프로그램을 디버거에 붙이도록 합니다.

여기서 중요한점!! 디버깅 대상 프로세스에 디버거를 붙이기전에 버퍼 오버플로우가 발생되면

안된다는점~!! 그러기 위해서 입력을 받는 소스를 추가해서 디버거에 붙이고난 뒤에 버퍼 오버플로우를 발생시키도록 하겠습니다.

 

 
# -*- coding: cp949 -*-
# buffer_overflow.py

from ctypes import *

msvcrt = cdll.msvcrt 

# 디버거가 붙을 시간을 주기 위해 대기한다.
# 디버거가 붙으면 아무 키나 누른다.

raw_input('Once the debugger is attach, press any. ')

# 5바이트 크기의 버퍼를 만든다.
buffer = c_char_p('AAAAA')

# 오버플로우에 사용될 문자열을 만든다.
overflow = 'A' * 100

# 오버플로우 시킨다.
msvcrt.strcpy(buffer,overflow)

 

 

다음에는 access_violation_handler.py 를 작성해봅시다.

이 파일은 접근위반 예외를 처리하는 핸들러가 있는 파일입니다.

 

 
# -*- coding: cp949 -*-
# access_violation_handler.py

from pydbg import *
from pydbg.defines import *

# Utility libraries included with PyDbg
import utils # utils 모듈을 import 시킨다.

# 접근 위반 예외 핸들러
def check_accessv(dbg):
    # 첫번째 예외는 건너뛴다.
    if dbg.dbg.u.Exception.dwFirstChance: #첫번째 발생한 예외라면 
        return DBG_EXCEPTION_NOT_HANDLED # 건너뛴다.
    # 건너뛰는 이유는 첫번째 예외는 운영체제에서 발생하는 예외이기 때문이다.

    crash_bin = utils.crash_binning.crash_binning()  
    crash_bin.record_crash(dbg) #
       # record_crash (self, pydbg, extra=None):
       # utils.crash_binning 에 관한 설명을 paimei 에서 가져왔습니다.
       # Given a PyDbg instantiation that at the current time is assumed to have "crashed" (access violation for example)
       # record various details such as the disassemly around the violating address, the ID of the offending thread, the
       # call stack and the SEH unwind. Store the recorded data in an internal dictionary, binning them by the exception
       # address.
       # 제가 허졉한 실력으로 번역해보자면.. 현재 예외가 발생한 PyDbg 인스턴스를 건내주면 예외가 발생한 주소 주변의 디스어셈블 코드같은
       # 자세하고 다양한 레코드를 저장해준다고 합니다..
       
    print crash_bin.crash_synopsis() # 발생한 예외에 대한 정보 출력 
    # crash_synopsis (self, crash=None)
    # For the supplied crash, generate and return a report containing the disassemly around the violating address,
    # the ID of the offending thread, the call stack and the SEH unwind. If not crash is specified, then call through
    # to last_crash_synopsis() which returns the same information for the last recorded crash.
    # 쉽게 생각해서 발생한 예외에 대한 정보를 출력한다고 생각하시면 됩니다.
    # disassemly around the violation addeess, the ID of the offending thread , the call stack 같은 정보를 출력해줍니다~
    # 출력된 정보에 대해서는 따로 설명 드리겠습니다.

    dbg.terminate_process() # 예외가 발생한 프로세스를 종료 

    return DBG_EXCEPTION_NOT_HANDLED

    # ContinueDebugEvent() API 의 마지막 파라미터인 dwContinueStatus 는
    # DBG_CONTINUE 또는 DBG_EXCEPTION_NOT_HANDLED 중에서 하나의 값을 가질 수 있습니다.
    # 정상적으로 처리된 경우 DBG_CONTINUE 로 세팅 하고,
    # 처리하지 못했거나 어플리케이션의 SEH(Structured Exception Handler) 에서
    # 처리하길 원할 때는 DBG_EXCEPTION_NOT_HANDLED 로 세팅합니다.




pid = raw_input('Enter the Process ID: ')

dbg = pydbg() # pydbg 인스턴스화
dbg.attach(int(pid)) # 입력받은 PID 값을 가지고 있는 프로세스에 디버거를 붙인다.
dbg.set_callback(EXCEPTION_ACCESS_VIOLATION,check_accessv) # 콜백함수를 지정한다.
# EXCEPTION_ACCESS_VIOLATION = 접근위반 예외가 발생했을경우
# check_accessv = check_accessv 함수를 호출한다.
dbg.run() 
    

 

버퍼 오버플로우를 발생시키는 buffer_overflow.py를  실행합니다.

실행후 입력을 하기전 access_violation_handlet.py를 실행합니다.

실행후 buffer_overflow 의 PID 를 입력하게되면 다음과 같은 출력결과가 나오게 됩니다.

 






첫번째 사진은 접근 위반이 발생한 지점의 명령어와 그 명령어가 속한 모듈에 대한 정보를 출력한 모습입니다.

두번째 사진은 접근 위반이 발생햇을때 모든 레지스터 컨텍스트에 대한 정보를 나타냅니다.

EAX 값이 지금 41414141 로 되있는데 0x41은 16진수 A입니다. 현재 EAX 레지스터에는 A값으로 전부 꽉 차있다는

의미입니다. A라는 문자열 데이터로 버퍼 오버플로우를 시켰으니 당연한 결과입니다.

ESP + 08에도 A값으로 전부 꽉 차있내요..이유는 ESP+ 08 은 스택포인터에서 8바이트만큼 떨어져있는 위치인데

보통 이 위치에는 함수의 매개변수가 전달되기때문에 A로 꽉차있는 상태입니다.

세번째 사진은 접근 위반이 발생한 주변에 있는 명령어들을 디스어셈블해서 보여준 모습입니다.

네번째 사진은 예외가 발생했을때 등록되는 SEH 핸들러 리스트에 대한 목록을 출력해준 모습입니다.



지금까지 PyDbg 를 이용하면 너무나도 쉽게 예외 핸들러를 설정해서 처리할수 있다는걸 배웠습니다.

다음에는 PyDbg의 또다른 강력한 기능!!  프로세스 스냅샷에 대한 주제로 찾아오게습니다~^^ 

Posted by 케데