“ZwProtectVirtualMemory” is an undocumented API that can be used to modify the memory protections schemes. This API is seen to be widely used by exploits to modify
the protection schemes of memory where the shellcode resides.
For experimenting purpose I wrote a Python script that looks hooks into "ZwProtectVirtualMemory" and verifies if the stack is pointing to
addresses > “09090909h” and the memory protection being modified to “RWX” –
that is “40h”. If the condition is satisfied it prints the 10 DWORDs of memory content of ESP along with the hex dump of possible shellcode. Useful in
cases for speedy analysis where “ZwProtectVirtualMemory” API in used to modify
the memory where the shellcode resides.
Script tested on IE11 - Windows 7 32 bit.
Script tested on IE11 - Windows 7 32 bit.
##
#ZwPVM_Hook.py
#Code checks for possible shellcode
#after ZwProtectVirtual function is executed
#
#Based on analysis of CVE-2014-0322 & CVE-2014-1776
#
#Author:binaryhax0r
##
from pydbg import *
from pydbg.defines import *
import struct
import utils
import sys
import os
from ctypes import *
global is_hooked
def ZwProtect(dbg, args):
esp_content = dbg.context.Esp
if (esp_content >= 0x09090909): #Arbitrary address!!!
access_protection_addr = esp_content + 0x10 #Protection Address
access_protection = dbg.read_process_memory(access_protection_addr, 4)
access_protection = struct.unpack("L", access_protection)[0]
if (access_protection == 0x40): #0x40 - RWX protection
print "=" * 50
print "[*] ESP CONTENT: 0x%08x" % esp_content
print "[*] ACCESS PROTECTION: 0x%08x" % access_protection
print "[*] ESP ADDRESS DUMP:"
print "*" * 50
temp = esp_content
for x in range(0, 10): #no of stack variables to print - 10
esp_addr_dump = dbg.read_process_memory(temp, 4)
esp_addr_dump = struct.unpack("L", esp_addr_dump)[0]
temp += 4
print hex(esp_addr_dump)
print "*" * 50
shellcode = ""
temp = int(esp_content)
temp = dbg.read_process_memory(temp, 4) #top of stack possibly point to shellcode location
temp = struct.unpack("L", temp)[0]
print "[*] POSSIBLE SHELLCODE ADDRESS: 0x%08x" % temp
shellcode = dbg.hex_dump(dbg.read(temp, 0x1000), temp)
print shellcode
print "=" * 50
return DBG_CONTINUE
def hook_ZwProtect (pydbg):
is_hooked = 0
hooks = utils.hook_container()
hook_address = pydbg.func_resolve_debuggee("ntdll.dll", "ZwProtectVirtualMemory") #API to hook
hook_address += 12
if (is_hooked != 1):
if hook_address:
res = hooks.add(pydbg, hook_address, 0, ZwProtect, None)
is_hooked = 1
print "[*] ZwProtectVirtualMemory hooked at: 0x%08x" % hook_address
else:
print "[*] Error: Couldn't resolve hook address."
return DBG_CONTINUE
dbg = pydbg()
dbg.set_callback(EXCEPTION_BREAKPOINT, hook_ZwProtect)
found_program = False
for (pid, name) in dbg.enumerate_processes():
if name.lower() == "iexplore.exe":
found_program = True
dbg.attach(pid)
if found_program:
dbg.run()
else:
dbg.detach()
Sample output during an exploit analysis.
No comments:
Post a Comment