[컴][디버그] windows 에서 thread 의 context 를 가져오는 법 - snapshot

디버깅을 위한 winapi / windows 에서 thread context 얻기 / thread register 가져오기 / register 값 얻어오기 / how to retrieve thread context / winapi for debugging

소스 설명

  1. process id 를 가지고 snapshot 을 얻는다.
  2. snapshot 에서 thread id 를 얻는다.
  3. thread id 를 이용해서 handle 을 얻는다.
  4. 이 handle 을 이용해서 context 를 얻는다.
source from : Gray hat python
edited by namh


thread_entry = THREADENTRY32()
thread_list = []

# http://msdn.microsoft.com/en-us/library/windows/desktop/ms682489(v=vs.85).aspx
snapshot = kernel32.CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, self.pid)
if snapshot is not None:
    thread_entry.dwSize = sizeof(thread_entry)
    success = kernel32.Thread32First(snapshot, byref(thread_entry))

    while success:

        if thread_entry.th32OwnerProcessID == self.pid:
            thread_id = thread_entry.th32ThreadID
            thread_list.append(thread_entry.th32ThreadID)
            
            # Get a thread context
            context = CONTEXT()
            context.ContextFlags = CONTEXT_FULL | CONTEXT_DEBUG_REGISTERS


            h_thread = kernel32.OpenThread(THREAD_ALL_ACCESS, None, thread_id)
            if kernel32.GetThreadContext(h_thread, byref(context)):
                kernel32.CloseHandle(h_thread)
                return context
            else:
                return False
        success = kernel32.Thread32Next(snapshot, byref(thread_entry))
        

    kernel32.CloseHandle(snapshot)
    return thread_list
else:
    return False



Process



CreateProcess()


BOOL WINAPI CreateProcess(
  _In_opt_     LPCTSTR lpApplicationName,
  _Inout_opt_  LPTSTR lpCommandLine,
  _In_opt_     LPSECURITY_ATTRIBUTES lpProcessAttributes,
  _In_opt_     LPSECURITY_ATTRIBUTES lpThreadAttributes,
  _In_         BOOL bInheritHandles,
  _In_         DWORD dwCreationFlags,
  _In_opt_     LPVOID lpEnvironment,
  _In_opt_     LPCTSTR lpCurrentDirectory,
  _In_         LPSTARTUPINFO lpStartupInfo,
  _Out_        LPPROCESS_INFORMATION lpProcessInformation
);
    을 입힌 parameter 가 우리가 관심을 가져야 할 녀석들이다.
  1. lpApplicationName : 실행할 application, 즉, 실행될 녀석의 path
  2. lpCommandLine : 실행할 command line
  3. dwCreateionFlags : 이 flag 로 priority class 와 process 의 생성을 control 할 수 있다.
    이 flag로 실행할 process 를 debugged process 로 설정할 수 있다.(DEBUG_PROCESS 0x00000001)


OpenProcess

HANDLE WINAPI OpenProcess(
  _In_  DWORD dwDesiredAccess,
  _In_  BOOL bInheritHandle,
  _In_  DWORD dwProcessId
);

OpenProcess 는 이미 존재하고 있는 process 에 특정권한으로 접근하겠다고 요청하면 그에 해당하는 handle 를 돌려준다.
  1. dwDesiredAccess : 열려고 하는 process 에 대해서 얻고 싶은 권한을 명시해 주면 된다.
    debugging 을 위해서는 PROCESS_ALL_ACCESS 로 설정해야 한다.
  2. dwProcessId : 우리가 handle을 얻고 싶어하는 process 의 PID

handle 은 WinNT.h 에 아래와 같이 정의되어 있다.[ref. 3]
typedef PVOID HANDLE;




thread

Traversing the Thread List 을 보면 아래 함수들을 어떻게 사용하는지에 대해 이해가 쉬울 것이다.


ThreadCotext 얻기

  1. thread_id 얻기 : thread 을 traversing 하면서 thread_id 를 얻을 수 있다.
  2. thread_handle 얻기 : 여기서 얻은 thread_id 를 가지고 OpenThread 를 하면, thread 의 handle 을 얻을 수 있다.
  3. context 얻기 : 이 handle 을 가지고 GetThreadContext() 를 이용해서 Thread 와 관련된 값들(register 값들) 을 얻을 수 있다.


OpenThread

HANDLE WINAPI OpenThread(
  _In_  DWORD dwDesiredAccess,
  _In_  BOOL bInheritHandle,
  _In_  DWORD dwThreadId
);


CreateToolhelp32Snapshot function

HANDLE WINAPI CreateToolhelp32Snapshot(
  _In_  DWORD dwFlags,
  _In_  DWORD th32ProcessID
);

dwFlags 를 TH32CS_SNAPTHREAD(0x00000004) 로 하면 등록된 thread 의 snapshot 의 handle을 얻게 된다. 이 handle 이 Thread32First() 에 parameter 로 쓰인다.

아래 flag 에서만 th32ProcessID 가 사용된다. th32ProcessID 는 thread 를 가지고 있는 process 의 ID 를 적어준다.
  • TH32CS_SNAPMODULE
  • TH32CS_SNAPMODULE32
  • TH32CS_SNAPHEAPLIST
  • TH32CS_SNAPALL


Thread32First()

BOOL WINAPI Thread32First(
  _In_     HANDLE hSnapshot,
  _Inout_  LPTHREADENTRY32 lpte
);

thread 를 열거할 때 쓰이는 함수이다.(enumerate)
lpte 는 함수가 성공적으로 수행되면 값이 할당된다.



THREADENTRY32

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

parameters
  • dwSize : Thread32First() 를 수행하기 전에 sizeof(THREADENTRY32) 로 초기화 해야 한다.
  • th32ThreadID : thread 의 ID OpenThread() 로 얻은 thread 의 ID 를 사용하면 된다.
  • th32OwnerProcessID : thread 가 있는 process 의 ID


GetThreadContext

BOOL WINAPI GetThreadContext(
  _In_     HANDLE hThread,
  _Inout_  LPCONTEXT lpContext
);


SetThreadContext

BOOL WINAPI SetThreadContext(
  _In_  HANDLE hThread,
  _In_  const CONTEXT *lpContext
);


Context structure

typedef struct _CONTEXT {

//
// The flags values within this flag control the contents of
// a CONTEXT record.
//
// If the context record is used as an input parameter, then
// for each portion of the context record controlled by a flag
// whose value is set, it is assumed that that portion of the
// context record contains valid context. If the context record
// is being used to modify a threads context, then only that
// portion of the threads context will be modified.
//
// If the context record is used as an IN OUT parameter to capture
// the context of a thread, then only those portions of the thread's
// context corresponding to set flags will be returned.
//
// The context record is never used as an OUT only parameter.
//
DWORD ContextFlags;

//
// This section is specified/returned if CONTEXT_DEBUG_REGISTERS is
// set in ContextFlags. Note that CONTEXT_DEBUG_REGISTERS is NOT
// included in CONTEXT_FULL.
//
DWORD Dr0;
DWORD Dr1;
DWORD Dr2;
DWORD Dr3;
DWORD Dr6;
DWORD Dr7;

//
// This section is specified/returned if the
// ContextFlags word contians the flag CONTEXT_FLOATING_POINT.
//
FLOATING_SAVE_AREA FloatSave;

//
// This section is specified/returned if the
// ContextFlags word contians the flag CONTEXT_SEGMENTS.
//
DWORD SegGs;
DWORD SegFs;
DWORD SegEs;
DWORD SegDs;

//
// This section is specified/returned if the
// ContextFlags word contians the flag CONTEXT_INTEGER.
//
DWORD Edi;
DWORD Esi;
DWORD Ebx;
DWORD Edx;
DWORD Ecx;
DWORD Eax;

//
// This section is specified/returned if the
// ContextFlags word contians the flag CONTEXT_CONTROL.
//
DWORD Ebp;
DWORD Eip;
DWORD SegCs; // MUST BE SANITIZED
DWORD EFlags; // MUST BE SANITIZED
DWORD Esp;
DWORD SegSs;

//
// This section is specified/returned if the ContextFlags word
// contains the flag CONTEXT_EXTENDED_REGISTERS.
// The format and contexts are processor specific
//
BYTE ExtendedRegisters[MAXIMUM_SUPPORTED_EXTENSION];

} CONTEXT;
 


References

  1. Windows Data Types, MSDN
  2. OpenThread function, MSDN

댓글 없음:

댓글 쓰기