12. Samples of code¶
12.1. windows.current_process¶
import sys
import os.path
sys.path.append(os.path.abspath(__file__ + "\..\.."))
import windows
import windows.native_exec.simple_x86 as x86
import windows.native_exec.simple_x64 as x64
# Here is our current process
cp = windows.current_process
print("current process is {cp}".format(cp=windows.current_process))
print("current process is a <{cp.bitness}> bits process".format(cp=cp))
print("current process is a SysWow64 process ? <{cp.is_wow_64}>".format(cp=cp))
print("current process pid <{cp.pid}> and ppid <{cp.ppid}>".format(cp=cp))
print("Here are the current process threads: <{cp.threads}>".format(cp=cp))
print("Let's execute some native code ! (0x41 + 1)")
if windows.current_process.bitness == 32:
# Let's generate some native code
code = x86.MultipleInstr()
code += x86.Mov("Eax", 0x41)
code += x86.Inc("EAX")
code += x86.Ret()
else:
code = x64.MultipleInstr()
code += x64.Mov("RAX", 0x41)
code += x64.Inc("RAX")
code += x64.Ret()
native_code = code.get_code()
v = windows.current_process.execute(native_code)
print("Native code returned <{0}>".format(hex(v)))
print("Allocating memory in current process")
addr = cp.virtual_alloc(0x1000) # Default alloc is RWX (so secure !)
print("Allocated memory is at <{0}>".format(hex(addr)))
print("Writing 'SOME STUFF' in allocation memory")
cp.write_memory(addr, "SOME STUFF")
print("Reading memory : <{0}>".format(repr(cp.read_memory(addr, 20))))
Output:
(cmd λ) python32.exe current_process.py
current process is <windows.winobject.process.CurrentProcess object at 0x030A2590>
current process is a <32> bits process
current process is a SysWow64 process ? <True>
current process pid <8264> and ppid <4100>
Here are the current process threads: <[<WinThread 13540 owner "python.exe" at 0x32d3210>]>
Let's execute some native code ! (0x41 + 1)
Native code returned <0x42>
Allocating memory in current process
Allocated memory is at <0xd60000>
Writing 'SOME STUFF' in allocation memory
Reading memory : <'SOME STUFF\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'>
12.2. Remote process : WinProcess¶
import sys
import os.path
sys.path.append(os.path.abspath(__file__ + "\..\.."))
import windows
import windows.native_exec.simple_x86 as x86
import windows.native_exec.simple_x64 as x64
print("Creating a calc")
calc = windows.utils.create_process(r"C:\windows\system32\calc.exe")
# You don't need to do that in our case, but it's useful to now
print("Looking for calcs in the processes")
all_calcs = [proc for proc in windows.system.processes if proc.name == "calc.exe"]
print("They are currently <{0}> calcs running on the system".format(len(all_calcs)))
print("Let's play with our calc: <{calc}>".format(calc=calc))
print("Our calc pid is {calc.pid}".format(calc=calc))
print("Our calc is a <{calc.bitness}> bits process".format(calc=calc))
print("Our calc is a SysWow64 process ? <{calc.is_wow_64}>".format(calc=calc))
print("Our calc have threads ! <{calc.threads}>".format(calc=calc))
# PEB STUFF
peb = calc.peb
print("Exploring our calc PEB ! {peb}".format(peb=peb))
print("Command line is {peb.commandline}".format(peb=peb))
modules = peb.modules
print("Here are 3 loaded modules: {0}".format(modules[:3]))
# See iat_hook.py for module exploration
# Remote alloc / read / write
print("Allocating memory in our calc")
addr = calc.virtual_alloc(0x1000)
print("Allocated memory is at <{0}>".format(hex(addr)))
print("Writing 'SOME STUFF' in allocated memory")
calc.write_memory(addr, "SOME STUFF")
print("Reading allocated memory : <{0}>".format(repr(calc.read_memory(addr, 20))))
# Remote Execution
print("Execution some native code in our calc (write 0x424242 at allocated address + return 0x1337)")
if calc.bitness == 32:
# Let's generate some native code
code = x86.MultipleInstr()
code += x86.Mov(x86.deref(addr), 0x42424242)
code += x86.Mov("EAX", 0x1337)
code += x86.Ret()
else:
code = x64.MultipleInstr()
code += x64.Mov('RAX', addr)
code += x64.Mov(x64.mem("[RAX]"), 0x42424242)
code += x64.Mov("RAX", 0x1337)
code += x64.Ret()
print("Executing native code !")
t = calc.execute(code.get_code())
t.wait()
print("Return code = {0}".format(hex(t.exit_code)))
print("Reading allocated memory : <{0}>".format(repr(calc.read_memory(addr, 20))))
print("Executing python code !")
# Make 'windows' importable in remote python
calc.execute_python("import sys; sys.path.append(r'{0}')".format(sys.path[-1]))
calc.execute_python("import windows")
# Let's write in the calc 'current_process' memory :)
calc.execute_python("addr = {addr}; windows.current_process.write_memory(addr, 'HELLO FROM CALC')".format(addr=addr))
print("Reading allocated memory : <{0}>".format(repr(calc.read_memory(addr, 20))))
# python_execute is 'safe':
# - it waits for the thread completion
# - it raise an error if remote code raised some
try:
print("Trying to import in remote module 'FAKE_MODULE'")
calc.execute_python("def func():\n import FAKE_MODULE\nfunc()")
except windows.injection.RemotePythonError as e:
print("Remote ERROR !")
print(e)
print("That's all ! killing the calc")
calc.exit()
Output:
(cmd λ) python.exe remote_calc.py
Creating a calc
Looking for calcs in the processes
They are currently <1> calcs running on the system
Let's play with our calc: <<WinProcess "calc.exe" pid 8052 at 0x27bd5d0>>
Our calc pid is 8052
Our calc is a <32> bits process
Our calc is a SysWow64 process ? <True>
Our calc have threads ! <[<WinThread 8552 owner "calc.exe" at 0x27f7f30>, <WinThread 3464 owner "calc.exe" at 0x27f7f80>, <WinThread 3840 owner "calc.exe" at 0x27fa030>]>
Exploring our calc PEB ! <windows.winobject.RemotePEB object at 0x026DDD00>
Command line is <RemoteWinUnicodeString ""C:\windows\system32\calc.exe"" at 0x26ddee0>
Here are 3 loaded modules: [<RemoteLoadedModule "calc.exe" at 0x26dde40>, <RemoteLoadedModule "ntdll.dll" at 0x26ddf30>, <RemoteLoadedModule "kernel32.dll" at 0x26ddc60>]
Allocating memory in our calc
Allocated memory is at <0x5c90000>
Writing 'SOME STUFF' in allocated memory
Reading allocated memory : <'SOME STUFF\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'>
Execution some native code in our calc (write 0x424242 at allocated address + return 0x1337
Executing native code !
Return code = 0x1337L
Reading allocated memory : <'BBBB STUFF\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'>
Executing python code !
Reading allocated memory : <'HELLO FROM CALC\x00\x00\x00\x00\x00'>
Trying to import in remote module 'FAKE_MODULE'
Remote ERROR !
Traceback (most recent call last):
File "<string>", line 3, in <module>
File "<string>", line 2, in func
ImportError: No module named FAKE_MODULE
That's all ! killing the calc
12.3. PEB exploration¶
import sys
import os.path
sys.path.append(os.path.abspath(__file__ + "\..\.."))
import windows
print("Exploring the current process PEB")
peb = windows.current_process.peb
print("PEB is <{0}>".format(peb))
commandline = peb.commandline
print("Commandline object is {0}".format(commandline))
print("Commandline string is {0}".format(repr(commandline.Buffer)))
imagepath = peb.imagepath
print("Imagepath {0}".format(imagepath))
modules = peb.modules
print("Printing some modules: {0}".format("\n".join(str(m) for m in modules[:6])))
print("=== K32 ===")
print("Looking for kernel32.dll")
k32 = [m for m in modules if m.name == "kernel32.dll"][0]
print("Kernel32 module: {0}".format(k32))
print("Module name = <{0}> | Fullname = <{1}>".format(k32.name, k32.fullname))
print("Kernel32 is loaded at address {0}".format(hex(k32.baseaddr)))
print("=== K32 PE ===")
k32pe = k32.pe
print("PE Representation of k32: {0}".format(k32pe))
exports = k32pe.exports
some_exports = dict((k,v) for k,v in exports.items() if k in [0, 42, "VirtualAlloc", "CreateFileA"])
print("Here are some exports {0}".format(some_exports))
imports = k32pe.imports
print("Import DLL dependancies are (without api-*): {0}".format([x for x in imports.keys() if not x.startswith("api-")]))
NtCreateFile_iat = [x for x in imports["ntdll.dll"] if x.name == "NtCreateFile"][0]
print("IAT Entry for ntdll!NtCreateFile = {0} | addr = {1}".format(NtCreateFile_iat, hex(NtCreateFile_iat.addr)))
print("Sections: {0}".format(k32pe.sections))
Output:
(cmd λ) python.exe peb.py
Exploring the current process PEB
PEB is <<windows.winobject.PEB object at 0x02649B70>>
Commandline object is <WinUnicodeString "python.exe peb.py " at 0x2649c60>
Commandline string is u'python.exe peb.py '
Imagepath <WinUnicodeString "C:\Python27\python.exe" at 0x2649d50>
Printing some modules: <LoadedModule "python.exe" at 0x272a030>
<LoadedModule "ntdll.dll" at 0x272a080>
<LoadedModule "kernel32.dll" at 0x272acb0>
<LoadedModule "kernelbase.dll" at 0x272ad00>
<LoadedModule "python27.dll" at 0x272ad50>
<LoadedModule "msvcr90.dll" at 0x272ada0>
=== K32 ===
Looking for kernel32.dll
Kernel32 module: <LoadedModule "kernel32.dll" at 0x272acb0>
Module name = <kernel32.dll> | Fullname = <C:\Windows\SYSTEM32\KERNEL32.DLL>
Kernel32 is loaded at address 0x774c0000
=== K32 PE ===
PE Representation of k32: <windows.pe_parse.PEFile object at 0x0272D350>
Here are some exports {0: 2001566688L, u'CreateFileA': 2001635616L, 42: 2001647872L, u'VirtualAlloc': 2001570704L}
Import DLL dependancies are (without api-*): [u'ntdll.dll', u'kernelbase.dll']
IAT Entry for ntdll!NtCreateFile = <IATEntry "NtCreateFile" ordinal 253> | addr = 0x77541128L
Sections: [<PESection ".text">, <PESection ".rdata">, <PESection ".data">, <PESection ".rsrc">, <PESection ".reloc">]
12.4. windows.system¶
import sys
import os.path
sys.path.append(os.path.abspath(__file__ + "\..\.."))
import windows
system = windows.system
print("Basic system infos:")
print(" version = {0}".format(system.version))
print(" bitness = {0}".format(system.bitness))
print(" computer_name = {0}".format(system.computer_name))
print(" product_type = {0}".format(system.product_type))
print(" version_name = {0}".format(system.version_name))
print("")
print("There is {0} processes".format(len(system.processes)))
print("There is {0} threads".format(len(system.threads)))
print("")
print("Dumping first logical drive:")
drive = system.logicaldrives[0]
print(" " + str(drive))
print((" " * 8) + "name = {0}".format(drive.name))
print((" " * 8) + "type = {0}".format(drive.type))
print((" " * 8) + "path = {0}".format(drive.path))
print("")
print("Dumping first service:")
serv = windows.system.services[0]
print(" " + str(serv))
print((" " * 8) + "name = {0}".format(serv.name))
print((" " * 8) + "description = {0}".format(serv.description))
print((" " * 8) + "status = {0}".format(serv.status))
print((" " * 8) + "process = {0}".format(repr(serv.process)))
print("")
print("Finding a service in a user process:")
serv = [s for s in windows.system.services if s.process][0]
print(" " + str(serv))
print((" " * 8) + "name = {0}".format(serv.name))
print((" " * 8) + "description = {0}".format(serv.description))
print((" " * 8) + "status = {0}".format(serv.status))
print((" " * 8) + "process = {0}".format(repr(serv.process)))
print("")
print("Enumerating handles:")
handles = system.handles
print(" There are {0} handles:".format(len(handles)))
print(" First handle is: " + str(handles[0]))
print(" Enumerating handles of the current process:")
cp_handles = [h for h in system.handles if h.dwProcessId == windows.current_process.pid]
print(" There are {0} handles for this process".format(len(cp_handles)))
print(" Looking for a File handle:")
file_h = [h for h in cp_handles if h.type == "File"][0]
print(" Handle is {0}".format(file_h))
print(" Name is <{0}>".format(file_h.name))
Output:
(cmd λ) python system.py
Basic system infos:
version = (6, 3)
bitness = 64
computer_name = HAKRIL-PC
product_type = VER_NT_WORKSTATION(0x1L)
version_name = Windows 8.1
There is 117 processes
There is 1246 threads
Dumping first logical drive:
<LogicalDrive "C:\" (DRIVE_FIXED)>
name = C:\
type = DRIVE_FIXED(0x3L)
path = \Device\HarddiskVolume2
Dumping first service:
<ServiceA "ACPI">
name = ACPI
description = Microsoft ACPI Driver
status = ServiceStatus(type=SERVICE_KERNEL_DRIVER(0x1L), state=SERVICE_RUNNING(0x4L), control_accepted=1L, flags=0L)
process = None
Finding a service in a user process:
<ServiceA "Appinfo">
name = Appinfo
description = Application Information
status = ServiceStatus(type=SERVICE_WIN32_SHARE_PROCESS(0x20L), state=SERVICE_RUNNING(0x4L), control_accepted=129L, flags=0L)
process = <WinProcess "svchost.exe" pid 988 at 0x2e64750>
Enumerating handles:
There are 40664 handles:
First handle is: <Handle value=<0x4> in process pid=4>
Enumerating handles of the current process:
There are 255 handles for this process
Looking for a File handle:
Handle is <Handle value=<0x4> in process pid=14340>
Name is <\Device\ConDrv>
12.5. IAT hooking¶
import sys
import os.path
sys.path.append(os.path.abspath(__file__ + "\..\.."))
import _winreg
import windows
# Here is a demo of IAT hooking in python
# We will hook the 'RegOpenKeyExA' entry of Python27.dll because it is easy to trigger !
# First: let's create our hook
# windows.hooks.RegOpenKeyExACallback is generated based on windows.generated_def.winfuncs
@windows.hooks.RegOpenKeyExACallback
def open_reg_hook(hKey, lpSubKey, ulOptions, samDesired, phkResult, real_function):
print("<in hook> Hook called | hKey = {0} | lpSubKey = <{1}>".format(hex(hKey), lpSubKey.value))
# Our hook can choose to call the real_function or not
if "SECRET" in lpSubKey.value:
print("<in hook> Secret key asked, returning magic handle 0x12345678")
# We must respect the hooked method return-value interface
phkResult[0] = 0x12345678
return 0
if "FAIL" in lpSubKey.value:
print("<in hook> Asked for a failing key: returning 0x2a")
return 42
print("<in hook> Non-secret key : calling normal function")
return real_function()
# Get the peb of our process
peb = windows.current_process.peb
# Get the pythonxx.dll module
pythondll_module = [m for m in peb.modules if m.name.startswith("python") and m.name.endswith(".dll")][0]
# Get the iat entries for DLL advapi32.dll
adv_imports = pythondll_module.pe.imports['advapi32.dll']
# Get RegOpenKeyExA iat entry
RegOpenKeyExA_iat = [n for n in adv_imports if n.name == "RegOpenKeyExA"][0]
# Setup our hook
RegOpenKeyExA_iat.set_hook(open_reg_hook)
# Use python native module _winreg that call 'RegOpenKeyExA'
print("Asking for <MY_SECRET_KEY>")
v = _winreg.OpenKey(1234567, "MY_SECRET_KEY")
print("Result = " + hex(v.handle))
print("")
print("Asking for <MY_FAIL_KEY>")
try:
v = _winreg.OpenKey(1234567, "MY_FAIL_KEY")
print("Result = " + hex(v.handle))
except WindowsError as e:
print(repr(e))
print("")
print("Asking for <HKEY_CURRENT_USER/Software>")
try:
v = _winreg.OpenKey(_winreg.HKEY_CURRENT_USER, "Software")
print("Result = " + hex(v.handle))
except WindowsError as e:
print(repr(e))
Output:
(cmd λ) python iat_hook.py
Asking for <MY_SECRET_KEY>
<in hook> Hook called | hKey = 0x12d687 | lpSubKey = <MY_SECRET_KEY>
<in hook> Secret key asked, returning magic handle 0x12345678
Result = 0x12345678
Asking for <MY_FAIL_KEY>
<in hook> Hook called | hKey = 0x12d687 | lpSubKey = <MY_FAIL_KEY>
<in hook> Asked for a failing key: returning 0x2a
WindowsError(42, 'Windows Error 0x2A')
Asking for <HKEY_CURRENT_USER/Software>
<in hook> Hook called | hKey = 0x80000001L | lpSubKey = <Software>
<in hook> Non-secret key : calling normal function
Result = 0x108
12.6. Network - socket exploration¶
import sys
import os.path
import socket
sys.path.append(os.path.abspath(__file__ + "\..\.."))
import windows
if not windows.utils.check_is_elevated():
print("!!! Demo will fail because closing a connection require elevated process !!!")
print("Working on ipv4")
conns = windows.system.network.ipv4
print("== Listening ==")
print("Some listening connections: {0}".format([c for c in conns if not c.established][:3]))
print("Listening ports are : {0}".format([c.local_port for c in conns if not c.established]))
print("== Established ==")
print("Some established connections: {0}".format([c for c in conns if c.established][:3]))
TARGET_HOST = "localhost"
TARGET_PORT = 80
print("== connection to {0}:{1} ==".format(TARGET_HOST, TARGET_PORT))
s = socket.create_connection((TARGET_HOST, TARGET_PORT))
our_connection = [c for c in windows.system.network.ipv4 if c.established and c.remote_port == TARGET_PORT and c.remote_addr == s.getpeername()[0]]
print("Our connection is {0}".format(our_connection))
print("Sending YOP")
s.send("YOP")
print("Closing socket")
our_connection[0].close()
print("Sending LAIT")
s.send("LAIT")
Output:
(cmd λ) python.exe network.py
Working on ipv4
== Listening ==
Some listening connections: [<TCP IPV4 Listening socket on 0.0.0.0:80>, <TCP IPV4 Listening socket on 0.0.0.0:135>, <TCP IPV4 Listening socket on 0.0.0.0:443>]
Listening ports are : [80, 135, 443, 445, 902, 912, 5357, 49152, 49153, 49154, 49155, 49157, 49159, 8307, 25340, 139, 139]
== Established ==
Some established connections: [<TCP IPV4 Connection 127.0.0.1:25340 -> 127.0.0.1:49472>, <TCP IPV4 Connection 127.0.0.1:49173 -> 127.0.0.1:49174>, <TCP IPV4 Connection 127.0.0.1:49174 -> 127.0.0.1:49173>]
== connection to localhost:80 ==
Our connection is [<TCP IPV4 Connection 127.0.0.1:49616 -> 127.0.0.1:80>]
Sending YOP
Closing socket
Sending LAIT
Traceback (most recent call last):
File ".\network.py", line 45, in <module>
s.send("LAIT")
socket.error: [Errno 10054] An existing connection was forcibly closed by the remote host
12.7. Registry¶
import sys
import os.path
import pprint
sys.path.append(os.path.abspath(__file__ + "\..\.."))
import windows
registry = windows.system.registry
print("Registry is <{0}>".format(registry))
current_user = registry("HKEY_CURRENT_USER")
print("HKEY_CURRENT_USER is <{0}>".format(current_user))
subkeys_name = [s.name for s in current_user.subkeys]
print("HKEY_CURRENT_USER subkeys names are:")
pprint.pprint(subkeys_name)
print("Opening 'Software' in HKEY_CURRENT_USER: {0}".format(current_user("Software")))
print("We can also open it in one access: {0}".format(registry(r"HKEY_CURRENT_USER\Sofware")))
print("Looking at CurrentVersion")
windows_info = registry("HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion")
print("Key is {0}".format(windows_info))
print("values are:")
pprint.pprint(windows_info.values)
registered_owner = windows_info["RegisteredOwner"]
print("registered owner = <{0}>".format(registered_owner))
Output:
(cmd λ) python.exe registry.py
Registry is <<windows.registry.Registry object at 0x02941290>>
HKEY_CURRENT_USER is <<PyHKey "HKEY_CURRENT_USER">>
HKEY_CURRENT_USER subkeys names are:
['AppEvents',
'AppXBackupContentType',
'Console',
'Control Panel',
'Environment',
'EUDC',
'Identities',
'Keyboard Layout',
'Network',
'Printers',
'Software',
'System',
'Volatile Environment']
Opening 'Software' in HKEY_CURRENT_USER: <PyHKey "HKEY_CURRENT_USER\Software">
We can also open it in one access: <PyHKey "HKEY_CURRENT_USER\Sofware">
Looking at CurrentVersion
Key is <PyHKey "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion">
values are:
[KeyValue(name='SoftwareType', value=u'System', type=1),
KeyValue(name='RegisteredOwner', value=u'hakril', type=1),
KeyValue(name='InstallDate', value=0, type=4),
...
KeyValue(name='PathName', value=u'C:\\Windows', type=1)]
registered owner = <KeyValue(name='RegisteredOwner', value=u'hakril', type=1)>
12.8. windows.wintrust¶
import sys
import os.path
sys.path.append(os.path.abspath(__file__ + "\..\.."))
import windows.wintrust
TARGET_FILE = r"C:\windows\system32\ntdll.dll"
print("Checking signature of <{0}>".format(TARGET_FILE))
print(" is_signed: <{0}>".format(windows.wintrust.is_signed(TARGET_FILE)))
print(" check_signature: <{0}>".format(windows.wintrust.check_signature(TARGET_FILE)))
sign_info = windows.wintrust.full_signature_information(TARGET_FILE)
print(" full_signature_information:")
print(" * signed <{0}>".format(sign_info.signed))
print(" * catalog <{0}>".format(sign_info.catalog))
print(" * catalogsigned <{0}>".format(sign_info.catalogsigned))
print(" * additionalinfo <{0}>".format(sign_info.additionalinfo))
print("Checking signature of some loaded DLL")
for module in windows.current_process.peb.modules[:5]:
path = module.fullname
is_signed = windows.wintrust.is_signed(path)
if is_signed:
print("<{0}> : {1}".format(path, is_signed))
else:
sign_info = windows.wintrust.full_signature_information(path)
print("<{0}> : {1} ({2})".format(path, is_signed, sign_info[3]))
Output:
(cmd λ) python .\wintrust.py
Checking signature of <C:\windows\system32\ntdll.dll>
is_signed: <True>
check_signature: <0>
full_signature_information:
* signed <True>
* catalog <C:\Windows\system32\CatRoot\{F750E6C3-38EE-11D1-85E5-00C04FC295EE}\Package_35_for_KB3128650~31bf3856ad364e35~amd64~~6.3.1.2.cat>
* catalogsigned <True>
* additionalinfo <0>
Checking signature of some loaded DLL
<c:\python27\python.exe> : False (TRUST_E_NOSIGNATURE(0x800b0100L))
<c:\windows\system32\ntdll.dll> : True
<c:\windows\system32\kernel32.dll> : True
<c:\windows\system32\kernelbase.dll> : True
<c:\windows\system32\python27.dll> : False (TRUST_E_NOSIGNATURE(0x800b0100L))
12.9. VectoredException()¶
12.9.1. In local process¶
import sys
import os.path
import pprint
sys.path.append(os.path.abspath(__file__ + "\..\.."))
import ctypes
import windows
from windows.winobject.exception import VectoredException
import windows.generated_def.windef as windef
from windows.generated_def.winstructs import *
@VectoredException
def handler(exc):
print("==Entry of VEH handler==")
if exc[0].ExceptionRecord[0].ExceptionCode == EXCEPTION_ACCESS_VIOLATION:
target_addr = ctypes.cast(exc[0].ExceptionRecord[0].ExceptionInformation[1], ctypes.c_void_p).value
print("Instr at {0} accessed to addr {1}".format(hex(exc[0].ExceptionRecord[0].ExceptionAddress), hex(target_addr)))
print("Resetting page protection to <PAGE_READWRITE>")
windows.winproxy.VirtualProtect(target_page, 0x1000, windef.PAGE_READWRITE)
exc[0].ContextRecord[0].EEFlags.TF = 1
return windef.EXCEPTION_CONTINUE_EXECUTION
else:
print("Exception of type {0}".format(exc[0].ExceptionRecord[0].ExceptionCode))
print("Resetting page protection to <PAGE_NOACCESS>")
windows.winproxy.VirtualProtect(target_page, 0x1000, windef.PAGE_NOACCESS)
return windef.EXCEPTION_CONTINUE_EXECUTION
windows.winproxy.AddVectoredExceptionHandler(0, handler)
target_page = windows.current_process.virtual_alloc(0x1000)
print("Protected page is at <{0}>".format(hex(target_page)))
print("Setting page protection to <PAGE_NOACCESS>")
windows.winproxy.VirtualProtect(target_page, 0x1000, windef.PAGE_NOACCESS)
print("")
v = ctypes.c_uint.from_address(target_page).value
print("Value 1 read")
print("")
v = ctypes.c_uint.from_address(target_page + 0x10).value
print("Value 2 read")
Output:
(cmd λ) python.exe veh_segv.py
Protected page is at <0x1db0000>
Setting page protection to <PAGE_NOACCESS>
==Entry of VEH handler==
Instr at 0x1d1ab574 accessed to addr 0x1db0000
Resetting page protection to <PAGE_READWRITE>
==Entry of VEH handler==
Exception of type EXCEPTION_SINGLE_STEP(0x80000004L)
Resetting page protection to <PAGE_NOACCESS>
Value 1 read
==Entry of VEH handler==
Instr at 0x1d1ab574 accessed to addr 0x1db0010
Resetting page protection to <PAGE_READWRITE>
==Entry of VEH handler==
Exception of type EXCEPTION_SINGLE_STEP(0x80000004L)
Resetting page protection to <PAGE_NOACCESS>
Value 2 read
12.9.2. In remote process¶
import sys
import os.path
import pprint
sys.path.append(os.path.abspath(__file__ + "\..\.."))
import windows
import windows.test
from windows.generated_def.winstructs import *
python_code = """
import windows
import ctypes
import windows
from windows.winobject.exception import VectoredException
import windows.generated_def.windef as windef
from windows.generated_def.winstructs import *
windows.utils.create_console()
module_to_trace = "gdi32.dll"
nb_repeat = [5]
@VectoredException
def handler(exc):
if exc[0].ExceptionRecord[0].ExceptionCode == EXCEPTION_ACCESS_VIOLATION:
print("")
target_addr = ctypes.cast(exc[0].ExceptionRecord[0].ExceptionInformation[1], ctypes.c_void_p).value
print("Instr at {0} accessed to addr {1} ({2})".format(hex(exc[0].ExceptionRecord[0].ExceptionAddress), hex(target_addr), module_to_trace))
windows.winproxy.VirtualProtect(target_page, code_size, windef.PAGE_EXECUTE_READWRITE)
nb_repeat[0] -= 1
if nb_repeat[0]:
exc[0].ContextRecord[0].EEFlags.TF = 1
else:
print("No more tracing !")
return windef.EXCEPTION_CONTINUE_EXECUTION
else:
print("Exception of type {0}".format(exc[0].ExceptionRecord[0].ExceptionCode))
print("Resetting page protection to <PAGE_READWRITE>")
windows.winproxy.VirtualProtect(target_page, code_size, windef.PAGE_READWRITE)
return windef.EXCEPTION_CONTINUE_EXECUTION
windows.winproxy.AddVectoredExceptionHandler(0, handler)
print("Tracing execution in module: <{0}>".format(module_to_trace))
module = [x for x in windows.current_process.peb.modules if x.name == module_to_trace][0]
target_page = module.baseaddr
code_size = module.pe.get_OptionalHeader().SizeOfCode
print("Protected page is at {0}".format(hex(target_page)))
windows.winproxy.VirtualProtect(target_page, code_size, windef.PAGE_READWRITE)
"""
c = windows.test.pop_calc_64(dwCreationFlags=CREATE_SUSPENDED)
x = c.execute_python(python_code)
c.threads[0].resume()
import time
time.sleep(0.1)
for t in c.threads:
t.suspend()
time.sleep(1)
c.exit()
Output:
(cmd λ) python .exe.\samples\remote_veh_segv.py
(In another console)
Tracing execution in module: <gdi32.dll>
Protected page is at 0x7ffa3c700000L
Instr at 0x7ffa3c70f0f0L accessed to addr 0x7ffa3c70f0f0L (gdi32.dll)
Exception of type EXCEPTION_SINGLE_STEP(0x80000004L)
Resetting page protection to <PAGE_READWRITE>
Instr at 0x7ffa3c70f0f5L accessed to addr 0x7ffa3c70f0f5L (gdi32.dll)
Exception of type EXCEPTION_SINGLE_STEP(0x80000004L)
Resetting page protection to <PAGE_READWRITE>
Instr at 0x7ffa3c70f0faL accessed to addr 0x7ffa3c70f0faL (gdi32.dll)
Exception of type EXCEPTION_SINGLE_STEP(0x80000004L)
Resetting page protection to <PAGE_READWRITE>
Instr at 0x7ffa3c70f0ffL accessed to addr 0x7ffa3c70f0ffL (gdi32.dll)
Exception of type EXCEPTION_SINGLE_STEP(0x80000004L)
Resetting page protection to <PAGE_READWRITE>
Instr at 0x7ffa3c70f100L accessed to addr 0x7ffa3c70f100L (gdi32.dll)
No more tracing !
12.10. Debugging¶
12.10.1. Debugger¶
import sys
import os.path
import pprint
sys.path.append(os.path.abspath(__file__ + "\..\.."))
import windows
import windows.test
import windows.debug
from windows.generated_def.winstructs import *
class MyDebugger(windows.debug.Debugger):
def on_exception(self, exception):
code = exception.ExceptionRecord.ExceptionCode
addr = exception.ExceptionRecord.ExceptionAddress
print("Got exception {0} at 0x{1:x}".format(code, addr))
class PrintUnicodeString(windows.debug.Breakpoint):
def __init__(self, addr, argument_position):
super(PrintUnicodeString, self).__init__(addr)
self.arg_pos = argument_position
def trigger(self, dbg, exc):
p = dbg.current_process
t = dbg.current_thread
esp = t.context.Esp
unicode_string_addr = p.read_ptr(esp + (self.arg_pos + 1) * 4)
wstring_addr = p.read_ptr(unicode_string_addr + 4)
dll_loaded = p.read_wstring(wstring_addr)
print("Loading <{0}>".format(dll_loaded))
if dll_loaded.endswith("ole32.dll"):
print("Ask to load <ole32.dll>: exiting process")
dbg.current_process.exit()
calc = windows.test.pop_calc_32(dwCreationFlags=DEBUG_PROCESS)
d = MyDebugger(calc)
d.add_bp(PrintUnicodeString("ntdll!LdrLoadDll", argument_position=2))
d.loop()
Ouput:
(cmd λ) python.exe .\samples\debugger_print_LdrLoaddll.py
Loading <KERNEL32.DLL>
Got exception EXCEPTION_BREAKPOINT(0x80000003L) at 0x77a73bad
Loading <C:\Windows\system32\IMM32.DLL>
Loading <C:\Windows\system32\uxtheme.dll>
Loading <C:\Windows\system32\uxtheme.dll>
Loading <C:\Windows\system32\uxtheme.dll>
Loading <C:\Windows\system32\uxtheme.dll>
Loading <kernel32.dll>
Loading <C:\Windows\WinSxS\x86_microsoft.windows.gdiplus_6595b64144ccf1df_1.1.9600.17415_none_dad8722c5bcc2d8f\gdiplus.dll>
Loading <comctl32.dll>
Loading <comctl32.dll>
Loading <comctl32.dll>
Loading <C:\Windows\system32\shell32.dll>
Loading <C:\Windows\SYSTEM32\WINMM.dll>
Loading <C:\Windows\system32\ole32.dll>
Ask to load <ole32.dll>: exiting process
12.10.1.1. Single stepping¶
import sys
import os.path
import pprint
sys.path.append(os.path.abspath(__file__ + "\..\.."))
import windows
import windows.test
import windows.debug
import windows.native_exec.simple_x86 as x86
from windows.generated_def.winstructs import *
class MyDebugger(windows.debug.Debugger):
def __init__(self, *args, **kwargs):
super(MyDebugger, self).__init__(*args, **kwargs)
self.single_step_counter = 0
def on_exception(self, exception):
code = exception.ExceptionRecord.ExceptionCode
addr = exception.ExceptionRecord.ExceptionAddress
print("Got exception {0} at 0x{1:x}".format(code, addr))
def on_single_step(self, exception):
code = exception.ExceptionRecord.ExceptionCode
addr = exception.ExceptionRecord.ExceptionAddress
print("Got single_step {0} at 0x{1:x}".format(code, addr))
self.single_step_counter -= 1
if self.single_step_counter > 0:
return self.single_step()
else:
print("No more single step: exiting")
self.current_process.exit()
class SingleStepOnWrite(windows.debug.MemoryBreakpoint):
"""Check that BP/dbg can trigger single step and that instruction follows"""
def trigger(self, dbg, exc):
fault_addr = exc.ExceptionRecord.ExceptionInformation[1]
import pdb;pdb.set_trace()
eip = dbg.current_thread.context.pc
print("Instruction at <{0:#x}> wrote at <{1:#x}>".format(eip, fault_addr))
dbg.single_step_counter = 4
return dbg.single_step()
calc = windows.test.pop_calc_32(dwCreationFlags=DEBUG_PROCESS)
d = MyDebugger(calc)
code = calc.virtual_alloc(0x1000)
data = calc.virtual_alloc(0x1000)
injected = x86.MultipleInstr()
injected += x86.Mov("EAX", 0)
injected += x86.Mov(x86.deref(data), "EAX")
injected += x86.Add("EAX", 4)
injected += x86.Mov(x86.deref(data + 4), "EAX")
injected += x86.Add("EAX", 8)
injected += x86.Mov(x86.deref(data + 8), "EAX")
injected += x86.Nop()
injected += x86.Nop()
injected += x86.Ret()
calc.write_memory(code, injected.get_code())
d.add_bp(SingleStepOnWrite(data, size=8, events="W"))
calc.create_thread(code, 0)
d.loop()
Ouput:
(cmd λ) python.exe .\samples\debugger_membp_singlestep.py
Got exception EXCEPTION_BREAKPOINT(0x80000003L) at 0x77ae3c7d
Instruction at <0x8d0006> wrote at <0x8e0000>
Got single_step EXCEPTION_SINGLE_STEP(0x80000004L) at 0x8d000c
Got single_step EXCEPTION_SINGLE_STEP(0x80000004L) at 0x8d0011
Instruction at <0x8d0011> wrote at <0x8e0004>
Got single_step EXCEPTION_SINGLE_STEP(0x80000004L) at 0x8d0017
Got single_step EXCEPTION_SINGLE_STEP(0x80000004L) at 0x8d001c
Got single_step EXCEPTION_SINGLE_STEP(0x80000004L) at 0x8d0022
Got single_step EXCEPTION_SINGLE_STEP(0x80000004L) at 0x8d0023
No more single step: exiting
12.10.1.2. windows.debug.FunctionBP¶
import sys
import os.path
import pprint
sys.path.append(os.path.abspath(__file__ + "\..\.."))
import windows
import windows.test
import windows.debug
from windows.generated_def.winstructs import *
class MyFunctionBP(windows.debug.FunctionBP):
def __init__(self, target, addr=None):
super(MyFunctionBP, self).__init__(target, addr)
self.target_name = target.target_func
self.counter = 3
def trigger(self, dbg, exc):
if not self.counter:
print("Exiting process")
dbg.current_process.exit()
return
params = self.extract_arguments(dbg.current_process, dbg.current_thread)
filename = params["ObjectAttributes"].contents.ObjectName.contents.Buffer
handle_addr = params["FileHandle"].value
self.data = (filename, handle_addr)
self.break_on_ret(dbg, exc)
def ret_trigger(self, dbg, exc):
filename, handle_addr = self.data
ret_value = dbg.current_thread.context.func_result # EAX / RAX depending of bitness
handle_value = dbg.current_process.read_ptr(handle_addr)
if ret_value:
print("NtCreateFile of <{0}> FAILED (result={1:#x})".format(filename, ret_value))
return
print("NtCreateFile of <{0}>: handle = {1:#x}".format(filename, handle_value))
# Manual verification
fhandle = [h for h in windows.system.handles if h.dwProcessId == dbg.current_process.pid and h.wValue == handle_value]
if not fhandle:
raise ValueError("handle not found!")
fhandle = fhandle[0]
print("Handle manually found! typename=<{0}>, name=<{1}>".format(fhandle.type, fhandle.name))
print("")
self.counter -= 1
calc = windows.test.pop_calc_32(dwCreationFlags=DEBUG_PROCESS)
d = windows.debug.Debugger(calc)
d.add_bp(MyFunctionBP(windows.winproxy.NtCreateFile))
d.loop()
Ouput:
NtCreateFile of <\??\C:\Windows\syswow64\en-US\calc.exe.mui>: handle = 0xac
Handle manually found! typename=<File>, name=<\Device\HarddiskVolume2\Windows\SysWOW64\en-US\calc.exe.mui>
NtCreateFile of <\Device\DeviceApi\CMApi>: handle = 0x108
Handle manually found! typename=<File>, name=<\Device\DeviceApi>
NtCreateFile of <\??\C:\Windows\Fonts\staticcache.dat>: handle = 0x154
Handle manually found! typename=<File>, name=<\Device\HarddiskVolume2\Windows\Fonts\StaticCache.dat>
Exiting process
12.10.2. LocalDebugger¶
import sys
import os.path
import pprint
sys.path.append(os.path.abspath(__file__ + "\..\.."))
import windows
from windows.generated_def.winstructs import *
import windows.native_exec.simple_x86 as x86
class SingleSteppingDebugger(windows.debug.LocalDebugger):
SINGLE_STEP_COUNT = 4
def on_exception(self, exc):
code = self.get_exception_code()
context = self.get_exception_context()
print("EXCEPTION !!!! Got a {0} at 0x{1:x}".format(code, context.pc))
self.SINGLE_STEP_COUNT -= 1
if self.SINGLE_STEP_COUNT:
return self.single_step()
return EXCEPTION_CONTINUE_EXECUTION
class RewriteBreakpoint(windows.debug.HXBreakpoint):
def trigger(self, dbg, exc):
context = dbg.get_exception_context()
print("GOT AN HXBP at 0x{0:x}".format(context.pc))
# Rewrite the infinite loop with 2 nop
windows.current_process.write_memory(self.addr, "\x90\x90")
# Ask for a single stepping
return dbg.single_step()
d = SingleSteppingDebugger()
# Infinite loop + nop + ret
code = x86.assemble("label :begin; jmp :begin; nop; ret")
func = windows.native_exec.create_function(code, [PVOID])
print("Code addr = 0x{0:x}".format(func.code_addr))
# Create a thread that will infinite loop
t = windows.current_process.create_thread(func.code_addr, 0)
# Add a breakpoint on the infitine loop
d.add_bp(RewriteBreakpoint(func.code_addr))
t.wait()
print("Done!")
Ouput:
(cmd λ) python.exe .\samples\local_debugger.py
Code addr = 0xcf0002
GOT AN HXBP at 0xcf0002
EXCEPTION !!!! Got a EXCEPTION_SINGLE_STEP(0x80000004L) at 0xcf0003
EXCEPTION !!!! Got a EXCEPTION_SINGLE_STEP(0x80000004L) at 0xcf0004
EXCEPTION !!!! Got a EXCEPTION_SINGLE_STEP(0x80000004L) at 0xcf0005
EXCEPTION !!!! Got a EXCEPTION_SINGLE_STEP(0x80000004L) at 0x770d7c04
Done!
import sys
import os.path
import pprint
sys.path.append(os.path.abspath(__file__ + "\..\.."))
import ctypes
import windows
import windows.test
from windows.generated_def.winstructs import *
remote_code = """
import windows
from windows.generated_def.winstructs import *
windows.utils.create_console()
class YOLOHXBP(windows.debug.HXBreakpoint):
def trigger(self, dbg, exc):
p = windows.current_process
arg_pos = 2
context = dbg.get_exception_context()
esp = context.Esp
unicode_string_addr = p.read_ptr(esp + (arg_pos + 1) * 4)
wstring_addr = p.read_ptr(unicode_string_addr + 4)
dll_loaded = p.read_wstring(wstring_addr)
print("I AM LOADING <{0}>".format(dll_loaded))
d = windows.debug.LocalDebugger()
exp = windows.current_process.peb.modules[1].pe.exports
#windows.utils.FixedInteractiveConsole(locals()).interact()
ldr = exp["LdrLoadDll"]
d.add_bp(YOLOHXBP(ldr))
"""
c = windows.test.pop_calc_32(dwCreationFlags=CREATE_SUSPENDED)
c.execute_python(remote_code)
c.threads[0].resume()
import time
time.sleep(2)
c.exit()
Ouput:
(cmd λ) python.exe .\samples\local_debugger_remote_process.py
(In another console)
I AM LOADING <C:\Windows\system32\uxtheme.dll>
I AM LOADING <C:\Windows\system32\uxtheme.dll>
I AM LOADING <C:\Windows\system32\uxtheme.dll>
I AM LOADING <C:\Windows\system32\uxtheme.dll>
I AM LOADING <kernel32.dll>
I AM LOADING <C:\Windows\WinSxS\x86_microsoft.windows.gdiplus_6595b64144ccf1df_1.1.9600.17415_none_dad8722c5bcc2d8f\gdiplus.dll>
I AM LOADING <comctl32.dll>
I AM LOADING <comctl32.dll>
I AM LOADING <comctl32.dll>
I AM LOADING <comctl32.dll>
I AM LOADING <comctl32.dll>
I AM LOADING <comctl32>
I AM LOADING <C:\Windows\SysWOW64\oleacc.dll>
I AM LOADING <OLEAUT32.DLL>
I AM LOADING <C:\Windows\system32\ole32.dll>
I AM LOADING <C:\Windows\system32\MSCTF.dll>
I AM LOADING <C:\Windows\SysWOW64\msxml6.dll>
I AM LOADING <C:\Windows\system32\shell32.dll>
I AM LOADING <C:\Windows\SYSTEM32\WINMM.dll>
I AM LOADING <C:\Windows\system32\ole32.dll>
12.10.3. Make WMI requests¶
import sys
import os.path
import pprint
sys.path.append(os.path.abspath(__file__ + "\..\.."))
import windows
print("WMI requester is {0}".format(windows.system.wmi))
print("Selecting * from 'Win32_Process'")
result = windows.system.wmi.select("Win32_Process")
print("They are <{0}> processes".format(len(result)))
print("Looking for ourself via pid")
us = [p for p in result if int(p["ProcessId"]) == windows.current_process.pid][0]
print("Some info about our process:")
print(" * {0} -> {1}".format("Name", us["Name"]))
print(" * {0} -> {1}".format("ProcessId", us["ProcessId"]))
print(" * {0} -> {1}".format("OSName", us["OSName"]))
print(" * {0} -> {1}".format("UserModeTime", us["UserModeTime"]))
print(" * {0} -> {1}".format("WindowsVersion", us["WindowsVersion"]))
print(" * {0} -> {1}".format("CommandLine", us["CommandLine"]))
print("<Select Caption,FileSystem,FreeSpace from Win32_LogicalDisk>:")
for vol in windows.system.wmi.select("Win32_LogicalDisk", ["Caption", "FileSystem", "FreeSpace"]):
print(" * " + str(vol))
Ouput:
(cmd λ) python .\samples\wmi_request.py
WMI requester is <windows.winobject.wmi.WmiRequester object at 0x02B37EF0>
Selecting * from 'Win32_Process'
They are <92> processes
Looking for ourself via pid
Some info about our process:
* Name -> python.exe
* ProcessId -> 7968
* OSName -> Microsoft Windows 8.1 Pro|C:\Windows|\Device\Harddisk0\Partition2
* UserModeTime -> 2812500
* WindowsVersion -> 6.3.9600
* CommandLine -> python.exe .\samples\wmi_request.py
<Select Caption,FileSystem,FreeSpace from Win32_LogicalDisk>:
* {'Caption': u'C:', 'FreeSpace': u'43991547904', 'FileSystem': u'NTFS'}
* {'Caption': u'E:', 'FreeSpace': u'82776027136', 'FileSystem': u'NTFS'}
* {'Caption': u'F:', 'FreeSpace': u'5711265792', 'FileSystem': u'FAT32'}
* {'Caption': u'G:', 'FreeSpace': None, 'FileSystem': None}
12.10.4. using COM: INetFwPolicy2¶
import sys
import os.path
import pprint
sys.path.append(os.path.abspath(__file__ + "\..\.."))
import windows
import windows.generated_def as gdef
from windows.generated_def import interfaces
# This code is a simple version of the firewall code in windows.winoject.network
print("Initialisation of COM")
windows.com.init()
print("Creating INetFwPolicy2 variable")
firewall = interfaces.INetFwPolicy2()
print("{0} (value = {1})".format(firewall, firewall.value))
print("")
print("Generating CLSID")
NetFwPolicy2CLSID = windows.com.IID.from_string("E2B3C97F-6AE1-41AC-817A-F6F92166D7DD")
print(NetFwPolicy2CLSID)
print("")
print("Creating COM instance")
windows.com.create_instance(NetFwPolicy2CLSID, firewall)
print("{0} (value = 0x{1:0})".format(firewall, firewall.value))
print("")
print("Checking for enabled profiles")
for profile in [gdef.NET_FW_PROFILE2_DOMAIN, gdef.NET_FW_PROFILE2_PRIVATE, gdef.NET_FW_PROFILE2_PUBLIC]:
enabled = gdef.VARIANT_BOOL()
firewall.get_FirewallEnabled(profile, enabled)
print(" * {0} -> {1}".format(profile, enabled.value))
Output:
(cmd λ) python .\samples\com_inetfwpolicy2.py
Initialisation of COM
Creating INetFwPolicy2 variable
<INetFwPolicy2 object at 0x02DC8210> (value = None)
Generating CLSID
<IID "E2B3C97F-6AE1-41AC-817A-F6F92166D7DD">
Creating COM instance
<INetFwPolicy2 object at 0x02DC8210> (value = 0x8984848)
Checking for enabled profiles
* NET_FW_PROFILE2_DOMAIN(0x1L) -> True
* NET_FW_PROFILE2_PRIVATE(0x2L) -> True
* NET_FW_PROFILE2_PUBLIC(0x4L) -> True