본문 바로가기
파이썬 스터디 과제/파이썬 해킹 프로그래밍

3장-4 브레이크포인트-1 (소프트브레이크포인트)

by laoching 2015. 1. 16.
728x90
반응형

브레이크포인트

소프트 브레이크 포인트

프로세스의 메모리를 읽고 쓸 수 있어야 한다.

이를 위해 ReadProcessMemory() 함수와 WriteProcessMemory()함수를 이용한다.

두 함수의 프로토타입. 순서대로

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

BOOL WINAPI ReadProcessMemory(

HANDLE hProcess,

LPCVOID lpBaseAddress,

LPVOID lqBuffer,

SIZE_T nSize,

SIZE_T* lpNumberOfBytesRead

);


BOOL WINAPID WriteProcessMemory(

HANDLE hProcess,

LPCVOID lpBaseAddress,

LPCVOID lpBuffer,

SIZE_T nSize,

SIZE_T* lpNumberOfBytesWritten

);

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

이 두함수를 이용하면 디버깅 대상 프로세스의 메모리를 조사하거나 변경할 수 있다.

lpBaseAddress 파라미터는 읽거나 쓰기 위한 메모리 영역의 시작 주소를 나타낸다.

lpBuffer 파라미터는 데이터를 읽거나 쓰기 위해 사용하는 버퍼에 대한 포인터며, nSize 파라미터는 읽거나 쓸 데이터의 바이트 수를 나타낸다.

my_debugger.py가 소프트 브레이크포인트를 지원하게 변경해보자.

my_debugger.py

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

def __init__(self):
        self.h_process       =     None
        self.pid             =     None
        self.debugger_active =     False
        self.h_thread        =     None
        self.context         =     None
        self.breakpoints    = {}    << 이것만 추가

.....

def read_process_memory(self,address,length):
        data = ""
        read_buf = create_string_buffer(length)
        count = c_long(0)

        if not kernel32.ReadProcessMemory(self.h_process,
                                          address,
                                          read_buf,
                                          length,
                                          byref(count)):
            return False
        else:
            data += read_buf.raw
            return data
    def write_process_memory(self,address,data):
        count = c_long(0)
        length = len(data)
        c_data = c_char_p(data[count.value:])
       
        if not kernel32.WriteProcessMemory(self,h_process,
                                           address,
                                           c_data,
                                           length,
                                           byref(count)):
            return False
        else:
            return True
    def bp_set(self,address):

        if not self.breakpoints.has_key(address):
            try:
                original_byte=self.read_process_memory(address,1)
                self.write_process_memory(address,"\xCC")
                self.breakpoints[address] = (original_byte)
            except:
                return False
        return True

을 추가해야 한다.

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

이제 소프트 브레이크포인트를 설정할 수 있게 되었다.

어느 곳에 브레이크포인트를 설정할 것인지만 결정하면 된다.

여기서는 printf() 함수에 브레이크포인트를 설정해 볼 것이다.

GetProcAddress() 윈도우 디버그 API를 사용하면 특정 함수의 가상 메모리 주소를 쉽게 알아낼 수 있다.

이 함수는 kernel32.dll이 익스포트 하는 함수다.

GetProcAddress()함수를 호출하려면 해당 함수가 속한 모듈의 핸들이 필요하다.

이 핸들은 GetModuleHandle() 함수를 이용해 얻을 수 있다.

다음은 두 개의 함수의 프로토 타입이다.

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

FARPROC WINAPI GetProcAddress(

HMODULE hModule,

LPCSTR lqProcName

);


HMODULE WINAPI GetModuleHandle(

LPCSTR lpModuleName

);

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

과정은 매우 단순하다.

모듈의 핸들을 구하고 해당 모듈에서 브레이크 포인트를 설정할 익스포트의 함수의 주소를 구하는 것이다.

my_debugger.py 파일에서 브레이크포인트를 설정할 함수의 주소를 구하는 기능을 추가하자.

my_debugger.py

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

def func_resolve(self,dll,function):
        handle=kernel32.GetModuleHandleA(dll)
        address =kernel32.GetProcAddress(handle,function)
        kernel32.CloseHandle(handle)

        return address

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

위의 소스에 저 소스를 추가한다.


이제는 테스트를 위해 루프를 돌며 printf() 함수를 호출하는 테스트 프로그램을 작성하자.

printf() 함수의 주소를 구하고 그 곳에 소프트 브레이크포인트를 설정한다.

printf() 함수가 호출돼 브레이크포인트가 발생하면 그에 따른 내용을 출력하고 프로세스는 루프를 도는 작업을 계속 수행할 것이다.

print_loop.py라는 파일을 새로 만들자

pritn_loop.py

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

from ctypes import *
import time

msvcrt = cdll.msvcrt
counter=0

while 1:
    msvcrt.printf("loop iteration %d! \n" %counter)
    time.sleep(2)
    counter +=1

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

다음은 printf()함수에 대한 브레이크포인트를 테스트할 수 있게 변경한 테스트 프로그램이다.

my.test.py

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

import my_debugger
debugger = my_debugger.debugger()
pid = raw_input("enter the PID of the process to attach to : ")
debugger.attach(int(pid))
printf_address = debugger.func_resolve("msvcrt.dll","printf")
print"[*] address of printf : 0x%08x" % printf_address
debugger.bp_set(printf_address)
debugger.run()
input()

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

먼저 printf_loop.py 를 커맨드라인에서 실행시키고 작업관리자를 통해 python.exe 프로세스의 PID를 구한다.

그 후 테스트 프로그램인 my_test.py스크립트를 실행시켜 python.exe의 PID를 입력한다.

실행화면(소스는 공개를 안할것이다)

728x90
반응형

댓글