소프트 브레이크 포인트를 설정하려면 프로세스의 메모리를 읽고 쓸 수 있어야 하는데,
이를 위해 ReadProcessMemory() 함수와 WriteProcessMemory() 함수를 이용한다.
아래는 두 함수의 프로토 타입이다.
BOOL WINAPI ReadProcessMemory( HANDLE hProcess , LPCVOID lpBaseAddress, LPVOID lpBuffer‘, SIZE_T nSize, SIZE_T* lpNumber‘OfBytesRead ); BOOL WINAPI riteProcessMemory( HANDLE hProcess , LPCVOID lpBaseAddress , LPCVOID lpBuffer, SIZE_T nSize, SIZE_T* lpNumber OfBytes itten );
이 두 함수를 이용하면 디버깅할 프로세스의 메모리를 읽거나 쓸 수 있다.
lpBaseAddress 인자는 읽거나 쓰기 위한 메모리 영역의 시작 주소를 뜻한다.
lpBuffer 인자는 데이터를 읽거나 쓰기 위해 사용하는 버퍼에 대한 포인터이며, nSize 파라미터는 읽거나 쓸 데이터의 바이트 수.
이 두 함수를 이용, 소프트 브레이크 포인트를 구현할 수 있다.
my_debugger.py 를 소프트 브레이크 포인트에 맞게 수정하고, (소스파일 참조)
이제 어느 곳에 소프트 브레이크 포인트를 설정할 것인지만 설정하면 된다.
일반적으로 함수 호출 부분에 브레이크 포인트를 설정한다. 여기서는 printf() 함수에 브레이크 포인트를 설정하는데,
GetProcAddress() 라는 함수를 이용해 printf 함수의 가상 메모리 주소를 알아낼 것이다.
이 함수는 kernel32.dll 에서 지원한다.
GetProcAddress()를 호출하려면 해당 함수가 속한 모듈(여기서는 kernel32.dll. 보통 dll 이나 exe 파일) 의 핸들이 필요하다.
이 핸들은 GetModuleHandle() 함수를 이용해 얻어올 것이다.
이 두 함수의 프로토 타입을 보자면,
FARPROC WINAPI GetProcAddress( HMODULE hModule, LPCSTR lpProcName ); HMODULE WINAPI GetModuleHandle( LPCSTR lpModuleName );
함수의 종류가 많아 헷갈릴 수는 있지만, 그 절차는 그리 복잡하지 않다.
1. 모듈의 핸들을 구하고
2. 함수의 주소를 구해
3. 브레이크 포인트를 건다
my_debugger.py 에
class debugger(): def resolve_func(self,dll,function): handle = kernel32.GetModuleHandleA(dll) address = kernel32.GetProcAddress(handle,function) kernel32.CloseHandle(handle) return address
resolve_func 함수를 추가한다.
(원래 책에서는 func_resolve 함수라고 되어 있지만, 어째서인지 함수명을 책과 똑같이 했을 때 오류가 났다.
원래 함수명은 통일만 해주면 되므로 무엇으로 하던지 오류와는 상관이 없다.)
이제 소프트 브레이크 포인트 테스트를 위해 루프를 돌며 printf()를 호출하는 프로그램을 작성한다.
from cytpes import * import time msvcrt = cdll.msvcrt counter = 0 while 1: msvcrt.printf("Loop interation %d!\n" % counter) time.sleep(2) counter += 1
위 바로가기의 글에서 my_test.py 처럼 소스파일을 변경한다.
원래 책에서는 printf_loop.py 를 먼저 실행시키고 my_test.py 를 실행시켜 PID를 붙이는 방식으로 진행했지만,
약간 소스를 바꿔
printf_loop.py 실행시 스스로의 PID를 구해 pid.txt 로 저장하고,
그후 my_test.py 를 실행시키면 pid.txt 를 읽어와 자동으로 프로세스에 붙는다.
또한 이벤트 코드에 따른 설명도 출력되게 해놓았다.
( 딕셔너리를 통한 C 의 switch case~ 방식)
[ *] Address of printf: 0x77c4186a
[ *] Setting breakpoint at : 0x77c4186a
Event Code: 3 Thread ID: 3148
Event Code: 6 Thread ID: 3148
Event Code: 6 Thread ID : 3148
Event Code: 6 Thread ID: 3148
Event Code : 6 Thread ID : 3148
Event Code: 6 Thread ID: 3148
Event Code : 6 Thread ID : 3148
Event Code: 6 Thread ID: 3148
Event Code: 6 Thread ID: 3148
Event Code : 6 Thread ID : 3148
Event Code : 6 Thread ID : 3148
Event Code : 6 Thread ID : 3148
Event Code: 6 Thread ID : 3148
Event Code : 6 Thread ID : 3148
Event Code : 6 Thread ID : 3148
Event Code: 6 Thread ID: 3148
Event Code : 6 Thread ID : 3148
Event Code : 2 Thread ID : 3620
Event Code : 1 Thread ID : 3620
[*] Exception address : 0x7c901230
[*] Hit the first breakpoint.
Event Code : 4 Thread ID : 3620
Event Code: 1 Thread ID : 3148
[ *] Exception address: 0x77c4186a
[ *] Hit user defined breakpoint.
처음 발생한 예외는 윈도우가 처리하는 것이다.
두번째로 발생한 예외는 printf() 함수의 주소와 똑같은 주소의 0x77c4186a 이다.
따라서 두 번째 발생한 예외는 테스트 프로그램이 설정한 소프트 브레이크 포인트에 의해 발생한 것임을 알 수 있다.
브레이크 포인트가 처리되면 프로세스는 또다시 루프를 돌면서 실행을 계속한다.
'스터디 > 파이썬 해킹 프로그래밍' 카테고리의 다른 글
Memory Breakpoint 이론, 함수 정리 (0) | 2015.01.18 |
---|---|
Hardware Breakpoint 까지 이론, 함수 정리 (0) | 2015.01.18 |
파이썬 해킹 프로그래밍 서적 오류 수정 (0) | 2015.01.17 |
디버거 이벤트 헨들러 구현 (0) | 2015.01.15 |
디버거와 프로세스를 연결하는 방법, CPU 레지스터 값을 출력하는 방법 (0) | 2015.01.15 |