mirror of
https://github.com/hakril/PythonForWindows
synced 2026-06-08 14:31:45 +00:00
Add WMI create-process sample + improved some sample feature/doc
This commit is contained in:
+29
-10
@@ -2,28 +2,40 @@ import windows.rpc
|
||||
from windows.rpc import ndr
|
||||
|
||||
|
||||
# Ndr stuff
|
||||
class NdrContext(ndr.NdrStructure):
|
||||
MEMBERS = [ndr.NdrLong, ndr.NdrLong, ndr.NdrLong, ndr.NdrLong, ndr.NdrLong]
|
||||
|
||||
|
||||
class PLSAPR_OBJECT_ATTRIBUTES(ndr.NdrStructure):
|
||||
MEMBERS = [ndr.NdrLong,
|
||||
ndr.NdrUniquePTR(ndr.NdrWString),
|
||||
ndr.NdrUniquePTR(ndr.NdrLong), # We dont care if the subtype as we will pass None
|
||||
ndr.NdrUniquePTR(ndr.NdrLong), # We dont care of the subtype as we will pass None
|
||||
ndr.NdrLong,
|
||||
ndr.NdrUniquePTR(ndr.NdrLong), # We dont care if the subtype as we will pass None
|
||||
ndr.NdrUniquePTR(ndr.NdrLong)] # We dont care if the subtype as we will pass None
|
||||
ndr.NdrUniquePTR(ndr.NdrLong), # We dont care of the subtype as we will pass None
|
||||
ndr.NdrUniquePTR(ndr.NdrLong)] # We dont care of the subtype as we will pass None
|
||||
|
||||
## From: RPCVIEW
|
||||
# long Proc44_LsarOpenPolicy2(
|
||||
# [in][unique][string] wchar_t* arg_0,
|
||||
# [in]struct Struct_364_t* arg_1,
|
||||
# [in]long arg_2,
|
||||
# [out][context_handle] void** arg_3);
|
||||
|
||||
# This function has a [out][context_handle] meaning it return a context_handle
|
||||
# Context handle are represented by 5 NdrLong where the first one is always 0
|
||||
# PythonForWindows represent context_handle using NdrContextHandle
|
||||
class LsarOpenPolicy2Parameter(ndr.NdrParameters):
|
||||
MEMBERS = [ndr.NdrUniquePTR(ndr.NdrWString),
|
||||
PLSAPR_OBJECT_ATTRIBUTES,
|
||||
ndr.NdrLong]
|
||||
|
||||
## From: RPCVIEW
|
||||
# long Proc2_LsarEnumeratePrivileges(
|
||||
# [in][context_handle] void* arg_0,
|
||||
# [in][out]long *arg_1,
|
||||
# [out]struct Struct_110_t* arg_2,
|
||||
# [in]long arg_3);
|
||||
|
||||
# This function has a [in][context_handle] meaning it expect a context_handle
|
||||
# We can pass the NdrContextHandle returned by Proc44_LsarOpenPolicy2
|
||||
class LsarEnumeratePrivilegesParameter(ndr.NdrParameters):
|
||||
MEMBERS = [NdrContext,
|
||||
MEMBERS = [ndr.NdrContextHandle,
|
||||
ndr.NdrLong,
|
||||
ndr.NdrLong]
|
||||
|
||||
@@ -72,12 +84,19 @@ iid = client.bind('12345778-1234-abcd-ef00-0123456789ab', version=(0,0))
|
||||
params = LsarOpenPolicy2Parameter.pack([None, (0, None, None, 0, None, None), 0x20000000])
|
||||
res = client.call(iid, 44, params)
|
||||
## Unpack the resulting handle
|
||||
handle = NdrContext.unpack(ndr.NdrStream(res))
|
||||
handle = ndr.NdrContextHandle.unpack(ndr.NdrStream(res))
|
||||
|
||||
# As context_handle have 4 NdrLong of effective data
|
||||
# We can represent them as GUID
|
||||
# NdrContextHandle is just a wrapper packing/unpacking GUID and taking
|
||||
# care of the leading NdrLong(0) in the actual ndr representation of context_handle
|
||||
print("Context Handle is: {0}\n".format(handle))
|
||||
|
||||
## Craft parameters and call 'LsarEnumeratePrivileges'
|
||||
x = LsarEnumeratePrivilegesParameter.pack([handle, 0, 10000]);
|
||||
res = client.call(iid, 2, x)
|
||||
|
||||
print("Privileges:")
|
||||
## Unpack the resulting 'LSAPR_PRIVILEGE_ENUM_BUFFER'
|
||||
priviledges = LSAPR_PRIVILEGE_ENUM_BUFFER.unpack(ndr.NdrStream(res))
|
||||
for priv in priviledges:
|
||||
|
||||
+43
-7
@@ -51,16 +51,20 @@ def hexdump(string, start_addr=0):
|
||||
result += linebuf+"\n"
|
||||
return result
|
||||
|
||||
class StartStepBP(dbg.breakpoints.HXBreakpoint):
|
||||
def trigger(self, dbg, exc):
|
||||
dbg.del_bp(self)
|
||||
dbg.on_single_step(exc) # Trigger single step processing
|
||||
|
||||
class CodeTesteur(dbg.Debugger):
|
||||
def __init__(self, process, code, register_start={}):
|
||||
def __init__(self, process, code, register_start={}, steps=False):
|
||||
super(CodeTesteur, self).__init__(process)
|
||||
|
||||
self.initial_code = code
|
||||
code += "\xcc"
|
||||
|
||||
code_addr = self.write_code_in_target(process, code)
|
||||
register_start["pc"] = code_addr
|
||||
self.code_addr = self.write_code_in_target(process, code)
|
||||
register_start["pc"] = self.code_addr
|
||||
self.thread_exec = process.threads[0]
|
||||
self.context_exec = self.thread_exec.context
|
||||
self.setup_target_context(self.context_exec, register_start)
|
||||
@@ -71,6 +75,12 @@ class CodeTesteur(dbg.Debugger):
|
||||
self.thread_exec.set_context(self.context_exec)
|
||||
self.thread_exec.resume()
|
||||
self.init_breakpoint = False
|
||||
# Test code
|
||||
if steps:
|
||||
self.steps = True
|
||||
self.add_bp(StartStepBP(self.code_addr))
|
||||
self.last_context = self.context_exec
|
||||
self.last_code = self.initial_code
|
||||
|
||||
def write_code_in_target(self, process, code):
|
||||
addr = process.virtual_alloc(len(code))
|
||||
@@ -83,6 +93,15 @@ class CodeTesteur(dbg.Debugger):
|
||||
raise ValueError("Unknown register to setup <{0}>".format(name))
|
||||
setattr(ctx, name, value)
|
||||
|
||||
def on_single_step(self, x):
|
||||
print("* New step !")
|
||||
# print("EIP = {0:#x}".format(self.current_thread.context.pc))
|
||||
self.report_ctx_diff(self.last_context, self.current_thread.context)
|
||||
self.last_context = self.current_thread.context
|
||||
self.last_code = self.report_code_diff(self.last_code)
|
||||
self.single_step()
|
||||
print ("")
|
||||
|
||||
def on_exception(self, x):
|
||||
exc_code = x.ExceptionRecord.ExceptionCode
|
||||
exc_addr = x.ExceptionRecord.ExceptionAddress
|
||||
@@ -97,12 +116,18 @@ class CodeTesteur(dbg.Debugger):
|
||||
print("<Normal terminaison>")
|
||||
else:
|
||||
print("<{0}> at <{1:#x}>".format(exc_code, exc_addr))
|
||||
if exc_code == EXCEPTION_ACCESS_VIOLATION:
|
||||
exc_infos = x.ExceptionRecord.ExceptionInformation
|
||||
read_write = "write" if exc_infos[0] else "read"
|
||||
target_addr = exc_infos[1]
|
||||
print(" * Access of type <{0}> at address <{1:#x}>".format(read_write, target_addr))
|
||||
self.report_ctx_diff(self.context_exec, ctx)
|
||||
self.report_code_diff(self.initial_code)
|
||||
self.current_process.exit()
|
||||
return
|
||||
|
||||
def report_ctx_diff(self, start, now):
|
||||
print("==DIFF==")
|
||||
print("== DIFF ==")
|
||||
for name, start_value in start.regs():
|
||||
now_value = getattr(now, name)
|
||||
if start_value != now_value:
|
||||
@@ -113,8 +138,19 @@ class CodeTesteur(dbg.Debugger):
|
||||
data = self.current_process.read_memory(now.sp, start.sp - now.sp)
|
||||
print(hexdump(data, start.sp))
|
||||
|
||||
def report_code_diff(self, initial_code):
|
||||
code_size = len(initial_code)
|
||||
final_code = self.current_process.read_memory(self.code_addr, code_size)
|
||||
if final_code == initial_code:
|
||||
return initial_code
|
||||
print("== Executable code DIFF == ")
|
||||
print("Before:")
|
||||
print(hexdump(initial_code, self.code_addr))
|
||||
print("After:")
|
||||
print(hexdump(final_code, self.code_addr))
|
||||
return final_code
|
||||
|
||||
def test_code_x86(code, regs=None, raw=False, **kwargs):
|
||||
def test_code_x86(code, regs=None, raw=False, steps=False, **kwargs):
|
||||
print("Testing x86 code")
|
||||
process = windows.test.pop_proc_32(dwCreationFlags=DEBUG_PROCESS)
|
||||
if raw:
|
||||
@@ -133,7 +169,7 @@ def test_code_x86(code, regs=None, raw=False, **kwargs):
|
||||
start_register[name] = value
|
||||
|
||||
|
||||
x = CodeTesteur(process, code, start_register)
|
||||
x = CodeTesteur(process, code, start_register, steps)
|
||||
x.loop()
|
||||
|
||||
def test_code_x64(code, regs=None, raw=False, **kwargs):
|
||||
@@ -156,7 +192,6 @@ def test_code_x64(code, regs=None, raw=False, **kwargs):
|
||||
value = int(value.strip(), 0)
|
||||
start_register[name] = value
|
||||
|
||||
|
||||
x = CodeTesteur(process, code, start_register)
|
||||
x.loop()
|
||||
|
||||
@@ -165,6 +200,7 @@ parser = argparse.ArgumentParser(prog=__file__)
|
||||
|
||||
parser.add_argument('--x64', action='store_const', dest="func", const=test_code_x64, default=test_code_x86, help='Code is x64')
|
||||
parser.add_argument('--raw', action='store_true', help='argument is raw assembled code (in hex)')
|
||||
parser.add_argument('--steps', action='store_true', help='Get all step info')
|
||||
parser.add_argument('code', help='The code to execute')
|
||||
parser.add_argument('regs', nargs="?", help='The default values of the registers')
|
||||
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
import windows
|
||||
import windows.com
|
||||
import windows.generated_def as gdef
|
||||
|
||||
def bstr_variant(s):
|
||||
v = windows.com.Variant()
|
||||
v.vt = gdef.VT_BSTR
|
||||
v._VARIANT_NAME_3.bstrVal = s
|
||||
return v
|
||||
|
||||
|
||||
wmireq = windows.system.wmi["root\\cimv2"]
|
||||
proc_class = wmireq.get_object("Win32_process")
|
||||
|
||||
# # Method 1
|
||||
inparam = proc_class.get_method("Create").inparam.spawn_instance()
|
||||
inparam["CommandLine"] = r"c:\windows\system32\notepad.exe trolol.exe"
|
||||
# Create a test checking return value
|
||||
xx = wmireq.exec_method(proc_class, "Create", inparam)
|
||||
print(xx)
|
||||
print(xx.as_dict())
|
||||
|
||||
## Method2
|
||||
|
||||
# class MyResult(gdef.IWbemCallResult):
|
||||
# def result(self):
|
||||
# res = type(proc_class)()
|
||||
# self.GetResultObject(gdef.WBEM_INFINITE, res)
|
||||
# return res
|
||||
|
||||
|
||||
# proc = proc_class.spawn()
|
||||
# cmdline = bstr_variant(r"c:\windows\system32\notepad.exe")
|
||||
# proc.put_variant("CommandLine", cmdline)
|
||||
# res = wmireq.put_instance(proc)
|
||||
|
||||
@@ -59,13 +59,6 @@ class TestCurrentProcessWithCheckGarbage(object):
|
||||
sections[0].start
|
||||
sections[0].size
|
||||
|
||||
def test_token_info(self):
|
||||
token = windows.current_process.token
|
||||
assert isinstance(token.computername, basestring)
|
||||
assert isinstance(token.username, basestring)
|
||||
assert isinstance(token.integrity, (int, long))
|
||||
assert isinstance(token.is_elevated, (bool))
|
||||
|
||||
def test_local_ProcessParameters_LSA_UNICODE_STRING(self):
|
||||
image_path_from_process_params = windows.current_process.peb.ProcessParameters.contents.ImagePathName.str.lower()
|
||||
image_path_from_module = windows.current_process.peb.modules[0].fullname.lower()
|
||||
@@ -418,18 +411,6 @@ class TestProcessWithCheckGarbage(object):
|
||||
image_path_from_module = proc32_64.peb.modules[0].fullname.lower()
|
||||
assert image_path_from_process_params == image_path_from_module
|
||||
|
||||
def test_lower_integrity(self, proc32):
|
||||
# Lowering the integrity in remote process
|
||||
# Because we don't want to mess with the token of our testing process
|
||||
|
||||
proc32.execute_python("import windows")
|
||||
# We stock the handle becase lowering the integrity
|
||||
# will mess with token retrieval
|
||||
proc32.execute_python("token = windows.current_process.token")
|
||||
proc32.execute_python("token.integrity = 123")
|
||||
# execute_python will raise this in our own process :)
|
||||
proc32.execute_python("assert token.integrity == 123")
|
||||
|
||||
def test_remote_assertion_error(self, proc32):
|
||||
proc32.execute_python("assert 1 == 1")
|
||||
with pytest.raises(windows.injection.RemotePythonError):
|
||||
|
||||
+1
-13
@@ -21,19 +21,7 @@ class TestSystemWithCheckGarbage(object):
|
||||
return windows.system.logicaldrives
|
||||
|
||||
def test_wmi(self):
|
||||
# Well, pytest initialize COM with its own parameters
|
||||
# It might make our own com.init() in WMI fail and therefore not call
|
||||
# CoInitializeSecurity. But looks like pytest/default COM-security parameters
|
||||
# does not allow to perform the request we want..
|
||||
# So we try & do it ourself here.
|
||||
|
||||
# Do co-reinit in conftest.py ?
|
||||
try:
|
||||
if windows.com.init(): # if init fail. Call CoInitializeSecurity ourself
|
||||
windows.com.initsecurity()
|
||||
except Exception as e:
|
||||
pass
|
||||
return windows.system.wmi.select("Win32_Process", "*")
|
||||
return windows.system.wmi
|
||||
|
||||
def test_handles(self):
|
||||
return windows.system.handles
|
||||
|
||||
+12
-2
@@ -12,6 +12,18 @@ from pfwtest import *
|
||||
# does not allow to perform the request we want..
|
||||
# So we try & do it ourself here.
|
||||
|
||||
|
||||
pytestmark = pytest.mark.usefixtures("init_com_security")
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def init_com_security():
|
||||
# Init com security if not done
|
||||
try:
|
||||
return windows.com.initsecurity()
|
||||
except WindowsError:
|
||||
pass
|
||||
|
||||
|
||||
wmimanager = windows.system.wmi
|
||||
|
||||
@pytest.mark.parametrize("name, expected_cls", [
|
||||
@@ -27,7 +39,6 @@ def test_wmimanager_getnamespace(name, expected_cls):
|
||||
def test_wmimanager_subnamespaces():
|
||||
subnamespaces = wmimanager.get_subnamespaces("root")
|
||||
subnamespaces = [x.lower() for x in subnamespaces]
|
||||
|
||||
assert "cimv2" in subnamespaces
|
||||
assert "security" in subnamespaces
|
||||
assert "subscription" in subnamespaces
|
||||
@@ -74,7 +85,6 @@ def test_get_object(name, cls):
|
||||
|
||||
# Todo: test
|
||||
# - put_instance
|
||||
# - exec_method
|
||||
|
||||
@pytest.mark.parametrize("cmdline", [r"c:\windows\notepad.exe trolol.exe"])
|
||||
def test_exec_method_Win32_Process_create(cmdline):
|
||||
|
||||
Reference in New Issue
Block a user