From 56b8264ffd81abeefed2d0bf35ebeac201d514f5 Mon Sep 17 00:00:00 2001 From: Clement Rouault Date: Tue, 28 Jun 2016 11:31:53 +0200 Subject: [PATCH] Add x64.assemble + sample test_code --- CHANGELOG | 4 +- samples/test_code.py | 68 +++++++++++++++++++++++-------- windows/native_exec/simple_x64.py | 35 ++++++++++++++++ windows/winobject/exception.py | 11 +++++ 4 files changed, 99 insertions(+), 19 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 8a36c61..b0dad72 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -13,4 +13,6 @@ Since 0.2: * You can have multiple execute_python_unsafe at the same time in the same process (didn't know: consequence of new injection code) * WinProcess.execute_python does not regenerate/reinject the python_exec_shellcode for each execution * generate.py cleaned with class and stuff / usable for extern project (cc lkd) - * Added COMImplementation to com interface \ No newline at end of file + * Added COMImplementation to com interface + * fix x86.assemble + add x64.assemble | fix some enconding problem in x64 + * Add test_code.py sample \ No newline at end of file diff --git a/samples/test_code.py b/samples/test_code.py index 7842cd0..abb5810 100644 --- a/samples/test_code.py +++ b/samples/test_code.py @@ -4,6 +4,7 @@ import windows import windows.test import windows.debug as dbg import windows.native_exec.simple_x86 as x86 +import windows.native_exec.simple_x64 as x64 from windows.generated_def import * def hexdump(string, start_addr=0): @@ -84,6 +85,7 @@ class CodeTesteur(dbg.Debugger): exc_code = x.ExceptionRecord.ExceptionCode exc_addr = x.ExceptionRecord.ExceptionAddress if not self.init_breakpoint and exc_code == EXCEPTION_BREAKPOINT: + print("Init breakpoint") self.init_breakpoint = True return ctx = self.current_thread.context @@ -91,7 +93,7 @@ class CodeTesteur(dbg.Debugger): ctx.dump() print(ctx.EEFlags) if exc_code == EXCEPTION_BREAKPOINT and exc_addr == self.context_exec.pc + len(self.initial_code): - print("Normal terminaison") + print("") else: print("<{0}> at <{1:#x}>".format(exc_code, exc_addr)) self.report_ctx_diff(self.context_exec, ctx) @@ -105,34 +107,64 @@ class CodeTesteur(dbg.Debugger): if start_value != now_value: diff = now_value - start_value print("{0}: {1:#x} -> {2:#x} ({3:+#x})".format(name, start_value, now_value, diff)) - if start.Esp > now.Esp: + if start.sp > now.sp: print("Negative Stack: dumping:") - data = self.current_process.read_memory(now.Esp, start.Esp - now.Esp) - print(hexdump(data, start.Esp)) + data = self.current_process.read_memory(now.sp, start.sp - now.sp) + print(hexdump(data, start.sp)) +def test_code_x86(): + print("Testing x86 code") + process = windows.test.pop_calc_32(dwCreationFlags=DEBUG_PROCESS) + code = x86.assemble(sys.argv[1]) + + start_register = {} + if len(sys.argv) > 2: + for name_value in sys.argv[2].split(";"): + name, value = name_value.split("=") + name = name.strip().capitalize() + if name == "Eflags": + name = "EFlags" + value = int(value.strip(), 0) + start_register[name] = value + + + x = CodeTesteur(process, code, start_register) + x.loop() + +def test_code_x64(): + print("Testing x64 code") + if windows.current_process.bitness == 32: + raise ValueError("Cannot debug a 64b process from 32b python") + process = windows.test.pop_calc_64(dwCreationFlags=DEBUG_PROCESS) + code = x64.assemble(sys.argv[1]) + + start_register = {} + if len(sys.argv) > 2: + for name_value in sys.argv[2].split(";"): + name, value = name_value.split("=") + name = name.strip().capitalize() + if name == "Eflags": + name = "EFlags" + value = int(value.strip(), 0) + start_register[name] = value + + + x = CodeTesteur(process, code, start_register) + x.loop() import sys if len(sys.argv) < 2: print("Need x86 code to exec as first argument") exit(1) -process = windows.test.pop_calc_32(dwCreationFlags=DEBUG_PROCESS) -code = x86.assemble(sys.argv[1]) - -start_register = {} -if len(sys.argv) > 2: - for name_value in sys.argv[2].split(";"): - name, value = name_value.split("=") - name = name.strip().capitalize() - if name == "Eflags": - name = "EFlags" - value = int(value.strip(), 0) - start_register[name] = value +if sys.argv[1] == "-x64": + sys.argv.remove("-x64") + test_code_x64() +else: + test_code_x86() -x = CodeTesteur(process, code, start_register) -x.loop() diff --git a/windows/native_exec/simple_x64.py b/windows/native_exec/simple_x64.py index 7129dbd..33fa3cf 100644 --- a/windows/native_exec/simple_x64.py +++ b/windows/native_exec/simple_x64.py @@ -1148,6 +1148,41 @@ class MultipleInstr(object): return self +def split_in_instruction(str): + for line in str.split("\n"): + if not line: + continue + for instr in line.split(";"): + if not instr: + continue + yield instr.strip() + +def assemble(str): + """Play test""" + shellcode = MultipleInstr() + for instr in split_in_instruction(str): + data = instr.split(" ", 1) + mnemo, args_raw = data[0], data[1:] + try: + instr_object = globals()[mnemo.capitalize()] + except: + raise ValueError("Unknow mnemonic <{0}>".format(mnemo)) + + args = [] + if args_raw: + for arg in args_raw[0].split(","): + arg = arg.strip() + if (arg[0] == "[" or arg[2:4] == ":[") and arg[-1] == "]": + arg = mem(arg) + else: + try: + arg = int(arg, 0) + except ValueError: + pass + args.append(arg) + shellcode += instr_object(*args) + return shellcode.get_code() + # import windows.native_exec.simple_x64 as x64 try: import midap diff --git a/windows/winobject/exception.py b/windows/winobject/exception.py index 18dbb94..1446666 100644 --- a/windows/winobject/exception.py +++ b/windows/winobject/exception.py @@ -183,6 +183,7 @@ class ECONTEXTBase(object): """DAT CONTEXT""" default_dump = () pc_reg = '' + sp_reg = '' special_reg_type = {} @@ -213,7 +214,14 @@ class ECONTEXTBase(object): def set_pc(self, value): return setattr(self, self.pc_reg, value) + def get_sp(self): + return getattr(self, self.sp_reg) + + def set_sp(self, value): + return setattr(self, self.sp_reg, value) + pc = property(get_pc, set_pc, None, "Program Counter register (EIP or RIP)") + sp = property(get_sp, set_sp, None, "Stack Pointer register (ESP or RSP)") @property def EEFlags(self): @@ -240,12 +248,14 @@ class ECONTEXTBase(object): class ECONTEXT32(ECONTEXTBase, CONTEXT32): default_dump = ('Eip', 'Esp', 'Eax', 'Ebx', 'Ecx', 'Edx', 'Ebp', 'Edi', 'Esi', 'EFlags') pc_reg = 'Eip' + sp_reg = 'Esp' fields = [f[0] for f in CONTEXT32._fields_] """The fields of the structure""" class ECONTEXTWOW64(ECONTEXTBase, WOW64_CONTEXT): default_dump = ('Eip', 'Esp', 'Eax', 'Ebx', 'Ecx', 'Edx', 'Ebp', 'Edi', 'Esi', 'EFlags') pc_reg = 'Eip' + sp_reg = 'Esp' fields = [f[0] for f in WOW64_CONTEXT._fields_] """The fields of the structure""" @@ -254,6 +264,7 @@ class ECONTEXT64(ECONTEXTBase, CONTEXT64): default_dump = ('Rip', 'Rsp', 'Rax', 'Rbx', 'Rcx', 'Rdx', 'Rbp', 'Rdi', 'Rsi', 'R9', 'R10', 'R11', 'R12', 'R13', 'R14', 'R15', 'EFlags') pc_reg = 'Rip' + sp_reg = 'Rsp' fields = [f[0] for f in CONTEXT64._fields_] """The fields of the structure"""