memory breakpoint using page fault on windwos
아직 부정확한 부분이 있어서, 정리차원으로 적어놓는다. PyDbg 부분에 대한 분석 이후에 update 를 해야 할 듯 하다.
Procedure
- page size 를 알아내고,
- page 에 permission 을 설정해서 guard page 처럼 작동하도록 한다.
- GUARD_PAGE_EXCEPTION 이 발생한다.
- exception handler 에서 다시 page 의 permission 을 돌려놓고(이 부분은 OS가 해준다.[ref. 1]), execution 을 계속 이어나간다.
Page Size
우리가 다룰 page 의 정확한 사이즈를 구하기 위해서, Operating System(OS) 에 default page size 를 물어봐야 한다. GetSystemInfo() 로 할 수 있다. 이 함수에서 SYSTEM_INFO structure 를 채워주는데 이 structure 가 dwPageSize 를 가지고 있다. 이 값이 default page size 가 된다.
Permission
page 정보
page permission 을 조정해 보자. 그러기 위해서 먼저 우리가 breakpoint 를 걸고 싶은 주소에 해당하는 page 의 정보를 가져오자. VirtualQueryEx() 로 가능하다. 이 함수에서 MEMORY_BASIC_INFORMATION structure 에 값이 채워지는데, 이 structure 가 가지고 있는 정보가 memory page 에 대한 정보를 가지고 있다.
permission 설정
여기에 있는 BaseAddress 정보가 시작점이 된다. permission 을 설정하는 함수는 VirtualProtectEx() 인데, 여기 2번째 인자로 들어가는 주소로 BaseAddress 를 넣어주면 된다.
guar page 에 access 를 해서 exception 이 발생하면 OS 가 메모리에 있는 그 page 의 exception 을 알아서 제거해 준다. 그래서 굳이 permission 을 제거하는 루틴을 짜지 않아도 괜찮다.
Demo
# source from Gray Hat Python
# edited by namh
memory_breakpoints = {}
creation_flags = DEBUG_PROCESS
# instantiate the structs
startupinfo = STARTUPINFO()
process_information = PROCESS_INFORMATION()
startupinfo.dwFlags = 0x1
startupinfo.wShowWindow = 0x0
startupinfo.cb = sizeof(startupinfo)
kernel32.CreateProcessA(path_to_exe,
None,
None,
None,
None,
creation_flags,
None,
None,
byref(startupinfo),
byref(process_information)):
pid = process_information.dwProcessId
h_process = kernel32.OpenProcess(PROCESS_ALL_ACCESS,False,pid)
system_info = SYSTEM_INFO()
kernel32.GetSystemInfo(byref(system_info))
page_size = system_info.dwPageSize
mbi = MEMORY_BASIC_INFORMATION()
# Attempt to discover the base address of the memory page
if kernel32.VirtualQueryEx(\
h_process, address, byref(mbi), sizeof(mbi)) < sizeof(mbi):
return False
current_page = mbi.BaseAddress
# We will set the permissions on all pages that are
# affected by our memory breakpoint.
while current_page <= address + size:
# Add the page to the list, this will
# differentiate our guarded pages from those
# that were set by the OS or the debuggee process
guarded_pages.append(current_page)
old_protection = c_ulong(0)
if not kernel32.VirtualProtectEx(\
h_process, current_page, size,\
mbi.Protect | PAGE_GUARD, byref(old_protection)):
return False
# Increase our range by the size of the
# default system memory page size
current_page += self.page_size
# Add the memory breakpoint to our global list
memory_breakpoints[address] = (address, size, mbi)
return True
References
- Chapter 3, Gray Hat Python
- http://www.codeproject.com/Articles/186230/Extending-windbg-with-Page-Fault-Breakpoints
댓글 없음:
댓글 쓰기