본문 바로가기
정상을향해/Program Analysis

Python Hacking Programming (1)

by 사이테일 2013. 11. 10.

파이썬 해킹 프로그래밍 (Python Hacking Programming)


저자 : 저스틴 지이츠

출판사 : 에이콘



3장. 윈도우 디버거 개발

[3.1] 윈도우 디버거 개발

[3.2] CPU 레지스터 상태 얻기


my_debugger.py


my_debugger_defines.py


my_test.py



소스코드 입니다.


역시 소스코드에 오타가 좀 있었군요 . . .


 


[3.1 윈도우 디버거 개발]

프로세스를 디버깅하려면 어떤 식으로든 먼저 해당 프로세스를 디버거와 연결해야 한다.


그래서 디버깅할 프로세스를 실행시키거나, 이미 실행돼 있는 프로세스에 attach를 해야 한다.



프로세스를 실행시키는 경우는 디버거가 실행 바이너리를 직접 실행하는 것인데,


이 경우 해당 프로세스의 코드가 실행되기 전에 제어를 할 수 있다는 장점이 있다.


윈도우에서는 프로세스를 실행시킬 때 CreateProcess() 함수를 호출한다.


BOOL CreateProcess(
  LPCWSTR pszImageName,    // 실행시킬 실행 바이너리 경로
  LPCWSTR pszCmdLine,    // 커맨드라인 인자 전달
  LPSECURITY_ATTRIBUTES psaProcess,
  LPSECURITY_ATTRIBUTES psaThread,
  BOOL fInheritHandles,
  DWORD fdwCreate,    // 해당프로세스가 디버깅 목적으로 실행된다는 점 명시
  LPVOID pvEnvironment,
  LPWSTR pszCurDir,
  LPSTARTUPINFOW psiStartInfo,    // STARTUPINFO 포인터
  LPPROCESS_INFORMATION pProcInfo // PROCESS_INFORMATION 포인터
); 


fdwCreate에 특별한 값을 전달함으로써 해당 프로세스를 디버깅 목적으로 실행시킬 수 있다.




실행중인 프로세스를 디버거에 붙이기 위해서는 일단 해당 프로세스에 대한 핸들을 구해야 한다.


이는 attach에 직접 쓰이지는 않지만


여기서 사용하는 대부분의 함수가 프로세스 핸들을 필요로 하기 때문에 미리 구해놓는 것이다.


이 때 OpenProcess() 함수에 핸들을 얻고자하는 PID를 넘겨주면 구할 수 있다.


그리고 PID를 DebugActiveProcess()함수에 넘겨주면 해당 프로세스를 attach할 수 있다.



[3.2 CPU 레지스터 상태 얻기]

CPU 레지스터 상태를 얻기 위해서는 실행중인 스레드의 핸들을 얻어야 한다.


위에서 다룬 OpenProcess()함수와 유사한 OpenThread() 함수를 이용하면 된다.


이 때 TID값을 인자로 넘겨주어야 하는데 현재는 TID값을 알 수가 없다.


이를 알아내기 위해서는 프로세스 내부에서 실행중인 모든 스레드 리스트를 구해야 한다.



스레드 리스트를 알아내기 위해서 우리는 CreateToolhelp32Snapshot()이라는 강력한 함수를 이용하면 된다.


HANDLE WINAPI CreateToolhelp32Snapshot(
  DWORD dwFlags,
  DWORD th32ProcessID 
);


dwFlags에 구할 정보의 종류(스레드, 프로세스, 모듈, 힙)를 전달해준다.


스레드 리스트를 얻기 위해서는 TH32CS_SNAPTHREAD(0X00000004)를 전달한다.


th32ProcessID는 스냅샷을 구하고자 하는 프로세스의 PID를 의미하지만 이것은 특정모드에서만 사용된다.


따라서 우리는 구한 스레드가 어느 프로세스에 속한 것인지를 추가적으로 판단해야 한다.



BOOL WINAPI Thread32First(
  HANDLE hSnapshot,
  LPTHREADENTRY32 lpte 
); 


hSnapshot에는 CreateToolhelp32Snapshot() 함수가 반환한 핸들을 전달하고,


lpte에는 THREADENTRY32 구조체의 포인터를 전달한다.


Thread32First() 함수가 성공하면 첫 번째 스레드에 대한 정보가 lpte를 통해 전달된다.



typedef struct tagTHREADENTRY32 { 
  DWORD dwSize; 
  DWORD cntUsage; 
  DWORD th32ThreadID; 
  DWORD th32OwnerProcessID; 
  LONG tpBasePri; 
  LONG tpDeltaPri; 
  DWORD dwFlags;
  DWORD th32AccessKey;
  DWORD th32CurrentProcessID;
  } THREADENTRY32; 
  typedef THREADENTRY32* PTHREADENTRY32;  
typedef THREADENTRY32* LPTHREADENTRY32; 


th32ThreadID를 통해 TID값을 얻을 수 있다. (이는 앞서 설명한 OpenThread()함수의 인자로 전달된다.)


그리고 th32OwnerProcessID를 통해 스레드가 속한 프로세스의 PID를 얻을 수 있다.


이를 이용해 현재 구한 스레드가 디버깅 대상 프로세스에 속하는 것인지 판단할 수 있다.



그리고 구한 스레드 핸들을 GetThreadContext() 함수에 넘겨주면


해당 레지스터 값이 CONTEXT 구조체에 저장된다.






여기까지 디버거와 프로세스를 연결하는 방법과


CPU 레지스터 값을 출력하는 방법을 알아보았다.



'정상을향해 > Program Analysis' 카테고리의 다른 글

Mac OS에 Metasploit Framework 설치 방법  (0) 2016.12.26
Python Hacking Programming (3)  (0) 2013.11.10
Python Hacking Programming (2)  (0) 2013.11.10
PE File Format (4)  (0) 2013.11.10
PE File Format (3)  (0) 2013.11.10
PE File Format (2)  (0) 2013.11.10