티스토리 뷰
디버거의 기능 열거
- 디버거 자체의 기능
- 디버거 내에서 프로세스를 실행, 실행된 프로세스를 디버거에 붙이기
- 디버거에 붙은 프로세스 실행, 종료, 브레이크 포인트 설정 - 디버거 발생 이벤트 처리
- Code Section의 바이너리에 대한 디스어셈블러
- CPU Register 값 파싱
- Memory 파싱
디버거에 대한 함수는 마이크로소프트의 Windows에서 이미 API로 제공한다. 디버거를 만드는데 필요한 함수는 잘 가져와서 사용하면 된다.
디버깅 구조체 목록
※ MSDN : https://msdn.microsoft.com/ko-kr/library/windows/desktop/ms679305(v=vs.85).aspx
디버거 기능 관련 함수
- CreateProcess() : Windows에서 프로세스 실행, 특정 플래그 값을 설정하면 디버깅 모드 실행 가능
※ MSDN : https://msdn.microsoft.com/en-us/library/windows/desktop/ms682425(v=vs.85).aspx
- 첫 번째(lpApplicationName) 인자 : 실행파일의 경로 입력
- 두 번째(lpCommandLine) 인자 : 파일 실행에 필요한 인자
- 여섯 번째(dwCreationFlags) 인자 : CREATE_NEW_CONSOLE | DEBUG_ONLY_THIS_PROCESS 입력!
- 아홉 번째(lpStartupInfo) 인자 : STARTUPINFO 구조체 포인터(MSDN 참고)
- 열 번째(lpProcessInformation) 인자 : PROCESS_INFORMATION 구조체 포인터(MSDN 참고)
- 나머지 인자는 NULL을 입력해도 충분 - OpenProcess() : 프로세스의 핸들을 얻기 위해 사용, 프로세스를 붙이기 위해서는 프로세스에 대한 핸들을 구할 필요가 있음
※ MSDN : https://msdn.microsoft.com/ko-kr/library/windows/desktop/ms684320(v=vs.85).aspx
- 첫 번째(dwDesiredAccess) 인자 : 원하는 접근 권한을 가진 프로세스 핸들 입력
- 두 번째(bInheritHandle) 인자 : 항상 False
- 세 번째(dwProcessId) 인자 : 핸들을 얻고자 하는 프로세스의 PID 입력 - DebugActiveProcess() : 프로세스에 붙일 때 사용
※ MSDN : https://msdn.microsoft.com/ko-kr/library/windows/desktop/ms679295(v=vs.85).aspx
- 첫 번째(dwProcessId) 인자 : 붙이고자 하는 프로세스의 PID - WaitForDebugEvent() : 디버그가 준비가 다 되었을 때 사용, 이를 통해 프로세스의 제어권을 받을 수 있음
※ MSDN : https://msdn.microsoft.com/ko-kr/library/windows/desktop/ms681423(v=vs.85).aspx
- 첫 번째(lpDebugEvent) 인자 : 디버그 이벤트를 설명해줄 DEBUG_EVENT 구조체의 포인터
- 두 번째(dwMilliseconds) 인자 : 디버그 이벤트를 기다리는 시간(TTL), INFINITE 상수 존재 - ContinueDebugEvent() : 디버그 이벤트 처리 후 프로세스를 이어서 실행
※ MSDN : https://msdn.microsoft.com/ko-kr/library/windows/desktop/ms679285(v=vs.85).aspx
- 첫 번째(dwProcessId) 인자 : 디버그 이벤트 발생 시 설정되는 DEBUG_EVENT 구조체의 프로세스 PID
- 두 번째(dwThreadId) 인자 : 디버그 이벤트 발생 시 설정되는 DEBUG_EVENT 구조체의 스레드 PID
- 세 번째(dwContinueStatus) 인자 : DBG_CONTINUE or DBG_EXCEPTION_NOT_HANDLED - DebugActiveProcessStop() : 붙였던 프로세스를 떼어낼 때 사용
※ MSDN : https://msdn.microsoft.com/ko-kr/library/windows/desktop/ms679296(v=vs.85).aspx
- 첫 번째(dwProcessId) 인자 : 떼어내고자 하는 프로세스의 PID - struct DEBUG_EVENT : 디버그 이벤트 구조체
※ MSDN : https://msdn.microsoft.com/ko-kr/library/windows/desktop/ms679308(v=vs.85).aspx
- 첫 번째(dwDebugEventCode) 내용 : 디버그의 특정 이벤트에 맞는 이벤트 코드 값이 들어가게 됨
CPU 레지스터 상태 파싱 관련 함수 : 레지스터의 상태 정보를 구하려면 해당 프로세스 내부에서 실행 중인 모든 스레드의 리스트는 필수
- OpenThread() : 현재 실행 중인 스레드의 핸들을 얻기 위해 사용
※ MSDN : https://msdn.microsoft.com/ko-kr/library/windows/desktop/ms684335(v=vs.85).aspx
- 첫 번째(dwDesiredAccess) 인자 : 원하는 접근 권한을 가진 프로세스 핸들 입력
- 두 번째(bInheritHandle) 인자 : 항상 False
- 세 번째(dwThreadId) 인자 : 핸들을 얻고자 하는 스레드의 TID 입력 - CreateToolhelp32Snapshot() : 스레드 리스트, 프로세스와, 프로세스의 힙 리스트, 프로세스에 로드된 모듈 리스트를 수집하고자 할 때 사용
※ MSDN : https://msdn.microsoft.com/ko-kr/library/windows/desktop/ms682489(v=vs.85).aspx
- 첫 번째(dwFlags) 인자 : 얻고자 하는 정보, 스레드 리스트는 TH32CS_SNAPTHREAD(0x04)
- 두 번째(th32ProcessID) 인자 : 원하는 정보를 뽑아낼 프로세스의 PID,
(두 번째 인자의 조건 : TH32CS_SNAPHEAPLIST, TH32CS_SNAPMODULE, TH32CS_SNAPMODULE32, TH32CS_SNAPALL 모드) - Thread32First() : 스레드의 리스트를 열거하기 위한 함수
※ MSDN : https://msdn.microsoft.com/ko-kr/library/windows/desktop/ms686728(v=vs.85).aspx
- 첫 번째(hSnapshot) 인자 : CreateToolhelp32Snapshot() 함수가 반환한 핸들값
- 두 번째(lpte) 인자 : THREADENTRY32 구조체의 포인터 - Thread32Next() : 스레드 리스트에서 다음 스레드의 엔트리 정보 수집을 위해 사용
※ MSDN : https://msdn.microsoft.com/ko-kr/library/windows/desktop/ms686731(v=vs.85).aspx
- 첫 번째(hSnapshot) 인자 : CreateToolhelp32Snapshot() 함수가 반환한 핸들값
- 두 번째(lpte) 인자 : THREADENTRY32 구조체의 포인터 - GetThreadContext() : 모든 레지스터의 내용을 수집
※ MSDN : https://msdn.microsoft.com/ko-kr/library/windows/desktop/ms679362(v=vs.85).aspx
- 첫 번째(hThread) 인자 : OpenThread() 함수를 통해 얻을 수 있는 스레드의 핸들값
- 두 번째(lpContext) 인자 : 모든 레지스터의 값을 담고 있는 CONTEXT 구조체 포인터
메모리 읽기 및 브레이크 포인트 관련 함수, 방법
- ReadProcessMemory() : 프로세스의 메모리를 읽어들임(소프트 브레이크 관련 함수)
※ MSDN : https://msdn.microsoft.com/ko-kr/library/windows/desktop/ms680553(v=vs.85).aspx
- 첫 번째(hProcess) 인자 : 읽어들일 프로세스의 핸들
- 두 번째(lpBaseAddress) 인자 : 메모리 영역에서 읽어들이기 시작할 시작 주소
- 세 번째(lpBuffer) 인자 : 읽어들인 메모리를 저장할 버퍼의 포인터
- 네 번째(nSize) 인자 : 읽고자 하는 메모리의 크기
- 다섯 번째(lpNumberOfBytesRead) 인자 : 지정한 버퍼에 전송된 바이트 크기를 저장할 변수의 포인터 - WriteProcessMemory() : 프로세스의 메모리를 씀(소프트 브레이크 관련 함수)
※ MSDN : https://msdn.microsoft.com/ko-kr/library/windows/desktop/ms681674(v=vs.85).aspx
- 첫 번째(hProcess) 인자 : 쓰고자 하는 프로세스의 핸들
- 두 번째(lpBaseAddress) 인자 : 쓰기 시작할 메모리 영역의 시작 주소
- 세 번째(lpBuffer) 인자 : 메모리에 쓰고자 하는 내용을 저장하고 있는 버퍼의 포인터
- 네 번째(nSize) 인자 : 메모리에 쓰기할 크기
- 다섯 번째(lpNumberOfBytesRead) 인자 : 지정한 버퍼에 전송된 바이트 크기를 저장할 변수의 포인터 - GetProcAddress() : 프로세스에서 특정 함수의 가상 메모리 주소를 알아냄(소프트 브레이크 관련 함수)
※ MSDN : https://msdn.microsoft.com/ko-kr/library/windows/desktop/ms683212(v=vs.85).aspx
- 첫 번째(hModule) 인자 : 특정 DLL 모듈의 핸들(LoadLibrary, GetModuleHandle 등과 같은 함수로 라이브러리를 로드하면 알아낼 수 있음)
- 두 번째(lpProcName) 인자 : 변수 또는 함수의 서수 값, 함수의 이름 입력 - GetModuleHandle() : 로드된 모듈의 핸들 값을 알아냄, 단순하게 모듈의 핸들 값을 알아내고 싶을 때 사용(소프트 브레이크 관련 함수)
※ MSDN : https://msdn.microsoft.com/ko-kr/library/windows/desktop/ms683199(v=vs.85).aspx
- 첫 번째(lpModuleName) 인자 : 로드된 모듈의 이름 - LoadLibrary() : 라이브러리를 로드할 때 사용, 지속적으로 모듈의 핸들 값이 필요할 때 사용(소프트 브레이크 관련 함수)
※ MSDN : https://msdn.microsoft.com/ko-kr/library/windows/desktop/ms684175(v=vs.85).aspx
- 첫 번째(lpFileName) 인자 : 로드할 파일의 이름 - GetSystemInfo() : 메모리 페이지의 크기를 구하기 위해 사용(메모리 브레이크 관련 함수)
※ MSDN : https://msdn.microsoft.com/ko-kr/library/windows/desktop/ms724381(v=vs.85).aspx
- 첫 번째(lpSystemInfo) 인자 : SYSTEM_INFO 구조체의 포인터 - VirtualQueryEx() : 메모리가 속해있는 페이지 정보를 알기 위해 사용(메모리 브레이크 관련 함수)
※ MSDN : https://msdn.microsoft.com/ko-kr/library/windows/desktop/aa366907(v=vs.85).aspx
- 첫 번째(hProcess) 인자 : 프로세스의 핸들
- 두 번째(lpAddress) 인자 : 얻고자하는 페이지가 속한 메모리의 시작 주소 포인터
- 세 번째(lpBuffer) 인자 : MEMORY_BASIC_INFORMATION 구조체의 포인터
- 네 번째(dwLength) 인자 : lpBuffer를 통해 가리키고 있는 버퍼의 크기 - VirtualProtectEx() : 페이지의 접근 권한 변경(메모리 브레이크 관련 함수)
※ MSDN : https://msdn.microsoft.com/ko-kr/library/windows/desktop/aa366899(v=vs.85).aspx
- 첫 번째(hProcess) 인자 : 프로세스의 핸들
- 두 번째(lpAddress) 인자 : 접근 권한을 변경할 페이지의 시작 주소
- 세 번째(dwSize) 인자 : 접근 권한을 변경할 페이지의 크기
- 네 번째(flNewProtect) 인자 : 새롭게 변경할 메모리 보호 옵션
- 다섯 번째(lpflOldProtect) 인자 : 변경하기 전의 메모리 보호권한을 저장할 포인터
소프트웨어 브레이크 포인터
- GetModulHandle() 함수를 통해 모듈의 핸들 값
- GetProcAddress()를 통해 특정 함수의 주소를 획득
- ReadProcessMemory()를 통해 특정 함수의 주소 + 오프셋의 opcode를 읽어와 저장
- WriteProcessMemory()를 통해 특정 함수의 주소 + 오프셋의 opcode를 0xCC로 변경
- WriteProcessMemory()를 통해 특정 함수의 주소 + 오프셋의 opcode를 본래의 opcode로 다시 돌려놓음
하드웨어 브레이크 포인터
- 모든 스레드의 리스트를 구함
- 각 스레드의 CPU 컨텍스트 레코드를 구함
- 모든 컨텍스트 레코드의 디버그 레지스터 중 하나에 브레이크포인트 주소 입력
- INT 1에 대한 인터럽트 처리 핸들러 추가
메모리 브레이크 포인터
- 브레이크 포인트를 설정할 메모리 영역의 주소와 크기를 구함
- 해당 영역의 접근 권한을 보호 페이지로 설정
- GUARD_PAGE_EXCEPTION 예외 발생 대기
- 예외 발생 시 예외처리 핸들러는 페이지 속성을 본래 권한으로 되돌림
'Project > Windows Debugger' 카테고리의 다른 글
디버거&디스어셈블러 제작 참고 자료 목록 (0) | 2016.10.15 |
---|---|
Simple PE Viewer (5) | 2016.10.07 |
Debugger 소스코드 (0) | 2016.10.05 |
Single Step 구현 (3) | 2016.09.30 |
브레이크 포인트(Break Point) (0) | 2016.09.19 |
댓글