안녕하세요. 오늘은 windbg에는 없고 ollydbg에는 있는 메모리 영역 브레이크포인트에 대해 쓰려고 합니다.
windbg와 ollydbg에는 코드영역에 software breakpoint와 hardware breakpoint가 존재합니다.
그러나 ollydbg에는 메모리 영역 전체를 breakpoint 걸 수 있는 방법이 있으나, windbg에는 기능이 없죠.
어떻게 메모리 영역 브레이크포인트가 가능할까요?
+ 2780000 2781000 1000 MEM_MAPPED MEM_COMMIT PAGE_READONLY MappedFile "PageFile"
+ 2781000 2790000 f000 MEM_FREE PAGE_NOACCESS Free
+ 2790000 2796000 6000 MEM_PRIVATE MEM_COMMIT PAGE_READWRITE Heap [ID: 2; Handle: 02790000; Type: Segment]
2796000 279f000 9000 MEM_PRIVATE MEM_RESERVE Heap [ID: 2; Handle: 02790000; Type: Segment]
279f000 27a0000 1000 MEM_PRIVATE MEM_RESERVE <unknown>
+ 27a0000 289a000 fa000 MEM_PRIVATE MEM_RESERVE Stack [~4; 3b64.2adc]
289a000 289c000 2000 MEM_PRIVATE MEM_COMMIT PAGE_READWRITE|PAGE_GUARD Stack [~4; 3b64.2adc]
289c000 28a0000 4000 MEM_PRIVATE MEM_COMMIT PAGE_READWRITE Stack [~4; 3b64.2adc]
+ 28a0000 296f000 cf000 MEM_PRIVATE MEM_COMMIT PAGE_READWRITE Heap [ID: 0; Handle: 008c0000; Type: Segment]
296f000 2971000 2000 MEM_PRIVATE MEM_RESERVE Heap [ID: 0; Handle: 008c0000; Type: Segment]
2971000 299f000 2e000 MEM_PRIVATE MEM_COMMIT PAGE_READWRITE Heap [ID: 0; Handle: 008c0000; Type: Segment]
299f000 29a0000 1000 MEM_PRIVATE MEM_RESERVE <unknown>
+ 29a0000 2a41000 a1000 MEM_PRIVATE MEM_COMMIT PAGE_READWRITE <unknown> [.............s..]
2a41000 2aa0000 5f000 MEM_PRIVATE MEM_RESERVE <unknown>
+ 2aa0000 3010000 570000 MEM_PRIVATE MEM_COMMIT PAGE_READWRITE <unknown> [................]
3010000 4aa0000 1a90000 MEM_PRIVATE MEM_RESERVE <unknown>
+ 4aa0000 4aa1000 1000 MEM_MAPPED MEM_COMMIT PAGE_READONLY MappedFile "PageFile"
windbg에서 !address 명령을 사용하면 위와 같이 메모리 정보들을 가져올 수 있습니다.
메모리는 크게 힙메모리, 스택이 있으며 각각 용도에 맞는 권한들을 포함하고 있습니다.
보통 메모리는 READ(읽기), WRITE(쓰기) EXECUTE(실행) 권한 중 최소 하나를 가지게 됩니다.
자, 다시 본론으로 돌아와서 어떻게 ollydbg는 메모리 영역에 대해 브레이크포인트를 걸 수 있는 것 일까요?
그 정답은 방금 설명드린 메모리의 권한에 있습니다.
만약 어떤 메모리 영역에서 실행권한이 없는데 실행된다면 어떻게 될까요?
만약 실행권한이 없는 메모리영역이 실행되게 된다면 프로세스는 access violation 에러가 나면서 종료되게 됩니다.
그러나 디버깅 중이라면 프로세스가 종료되지 않고 디버거에서 access violation을 처리 할 수 있게 되고
해당 메모리가 실행되는 곳에서 멈추게 되는 것입니다.
위에서는 실행 브레이크 포인트에 대해서만 예를 들었지만
메모리 읽기, 쓰기 브레이크포인트도 똑같은 방식으로 동작합니다.
얼마 전 작성한 windbg 스크립트를 조금 바꾸면 메모리 영역 브레이크 포인트 스크립트를 만들 수 있습니다.
import sys
import pykd
import re
from ctypes import *
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('option')
parser.add_argument('address', help='memory address to set up breakpoint')
parser.add_argument('protection')
args = parser.parse_args()
PAGE_NOACCESS = 0x01
PAGE_READONLY = 0x02
PAGE_READWRITE = 0x04
PAGE_WRITECOPY = 0x08
PAGE_EXECUTE = 0x10
PAGE_EXECUTE_READ = 0x20
PAGE_EXECUTE_READWRITE = 0x40
PAGE_EXECUTE_WRITECOPY = 0x80
PAGE_GUARD = 0x100
PROCESS_VM_READ = 0x10
PROCESS_VM_WRITE = 0x20
PROCESS_ALL_ACCESS = 0x1F0FFF
breakPoints = dict()
def getProcessName():
moduleList = pykd.dbgCommand("!peb").split('Base TimeStamp Module')[1].strip().split('\n')
return moduleList[0].split(' ')[-1]
def getPid():
return int(pykd.dbgCommand("!teb").split("ClientId:")[1].split('\n')[0].strip().split(' . ')[0],16)
def getPageGuard():
heap = pykd.dbgCommand("!address").split("\n")
result = list()
for h in heap:
if( h.find("GUARD") >= 0):
result.append(h)
return result
def fixPageGuard(handle, addr, size, attribute):
org = pointer(c_int(0))
r = cdll.kernel32.VirtualProtectEx(handle, addr, size, PAGE_READWRITE, org)
if( r == 0 ):
print("VirtualProtectEx Error! %d" % cdll.kernel32.GetLastError())
return r
def fixAllPageGuards():
handle = openProcess()
pageGuard = getPageGuard()
for p in pageGuard:
print(p)
memory = re.sub("[\s]+", " ", p)[1:].split(' ')
address = int(memory[0],16)
size = int(memory[2], 16)
attribute = memory[5]
r = fixPageGuard(handle, address, size, attribute)
return
def openProcess():
handle = cdll.kernel32.OpenProcess(PROCESS_ALL_ACCESS, False, getPid())
if( handle == 0 ):
print('OpenProcess Error! %d' % cdll.kernel32.GetLastError())
return handle
def readProcessMemory(handle, addr, size):
result = c_char_p(size)
retSize = 0
ret = cdll.kernel32.ReadProcessMemory(handle, addr, result, size, retSzie)
if( ret == 0):
print('ReadProcessMemory Error! %d' % cdll.kernel32.GetLastError())
return result
def getMemoryInfo(address):
memory = pykd.dbgCommand("!address").split("\n")
for memInfo in memory[3:]:
memInfo = re.sub('[\s]+', ' ', memInfo)
memInfo = memInfo.split(' ')
addrInfo = int(memInfo[1], 16)
addrSize = int(memInfo[3], 16)
protection = memInfo[6]
if(address >= addrInfo and (address - addrInfo) < addrSize):
return (addrInfo, addrSize, memInfo, protection)
return None
def clearBreakPointOnMemory(address, verbose=True):
if( hex(address) in breakPoints):
mInfo = getMemoryInfo(address)
(addrInfo, addrSize, memInfo, protection) = mInfo
if( mInfo == None ):
if( verbose == True ):
print( "Memory address is not found !!")
return None
org = pointer(c_int(0))
handle = openProcess()
if( handle == 0):
return
ret = cdll.kernel32.VirtualProtectEx(handle, addrInfo, addrSize, breakPoints[hex(addrInfo)], org)
if( ret == 0 ):
print("VirtualProtectEx Error! %d" % cdll.kernel32.GetLastError())
cdll.kernel32.CloseHandle(handle)
return ret
if( verbose == True ):
print("Breakpoint is not found!!! %x" % address)
return None
def breakPointOnMemory(address, type="r"):
clearBreakPointOnMemory(address, False)
mInfo = getMemoryInfo(address)
if( mInfo == None ):
print( "Memory address is not found !!")
return None
(addrInfo, addrSize, memInfo, protection) = mInfo
prot = 0
toProtection = 0
org = pointer(c_int(0))
if( protection == 'PAGE_NOACCESS' ):
prot = PAGE_NOACCESS
elif( protection == 'PAGE_READONLY'):
prot = PAGE_READONLY
elif( protection == 'PAGE_READWRITE'):
prot = PAGE_READWRITE
elif( protection == 'PAGE_WRITECOPY'):
prot = PAGE_WRITECOPY
elif( protection == 'PAGE_EXECUTE'):
prot = PAGE_EXECUTE
elif( protection == 'PAGE_EXECUTE_READ'):
prot = PAGE_EXECUTE_READ
elif( protection == 'PAGE_EXECUTE_READWRITE'):
prot = PAGE_EXECUTE_READWRITE
elif( protection == 'PAGE_EXECUTE_WRITECOPY'):
prot = PAGE_EXECUTE_WRITECOPY
if( prot == PAGE_NOACCESS ):
return
if( type == 'r' ):
if( prot < 0x10 ):
toProtection = prot ^ PAGE_GUARD
else:
toProtection = PAGE_EXECUTE
if( type == 'w'):
if( prot < 0x10 ):
toProtection = PAGE_READONLY
else:
toProtection = PAGE_EXECUTE_READ
if( type == 'e'):
if( prot < 0x10 ):
return
else:
toProtection = prot >> 4
handle = openProcess()
if( handle == 0):
return
print( hex(addrInfo), hex(addrSize), hex(toProtection))
ret = cdll.kernel32.VirtualProtectEx(handle, addrInfo, addrSize, toProtection, org)
error = cdll.kernel32.GetLastError()
cdll.kernel32.CloseHandle(handle)
if( ret == 0 ):
print("VirtualProtectEx Error! %d" % error)
return
breakPoints[hex(addrInfo)] = prot
print("VirtualProtectEx Success !! %x" % addrInfo)
return ret
if( args.option == 'bp'):
breakPointOnMemory( int(args.address, 16), args.protection)
elif( args.option == 'bc'):
clearBreakPointOnMemory(int(args.address, 16))
특정 메모리 영역에 breakpoint를 거는 스크립트입니다.
사용방법은 처음 windbg를 attach하거나 프로세스를 열고
.load pykd 명령어 실행 후 !py script.py 주소 권한(r,w,e)를 넣으시면 됩니다.
성공 시 아래와 같이 나옵니다.
0:031> !py script.py bp 186e000 r
0x186e000 0x2000 0x104
VirtualProtectEx Success !! 186e000
'해킹' 카테고리의 다른 글
KISA 소프트웨어 취약점 보상 테이블 (0) | 2020.07.09 |
---|---|
취약점 신고 이력(2020-06-12 업데이트) (0) | 2020.06.12 |
해킹에 사용될 수 있는 크롬 확장 프로그램을 알아보자! (0) | 2020.05.10 |
웹해킹 XSS에 대해서 알아보자! (0) | 2020.05.09 |
취약점 분석에 필요한 windbg에 python을 연동해보자! (0) | 2020.05.08 |