From 10a803e9c90eca8091bf84a784f1cbdfaf72a1e7 Mon Sep 17 00:00:00 2001 From: Clement Rouault Date: Mon, 2 May 2016 18:21:09 +0200 Subject: [PATCH] Add shr/shl + small fix simple_x64 Imm8 + execute_64bits_code_from_syswow able to return ULONG64 --- windows/native_exec/simple_x64.py | 10 +++++++++- windows/native_exec/simple_x86.py | 9 +++++++++ windows/native_exec/test_simple_x64.py | 6 ++++++ windows/native_exec/test_simple_x86.py | 14 ++++++++++++-- windows/syswow64.py | 15 +++++---------- 5 files changed, 41 insertions(+), 13 deletions(-) diff --git a/windows/native_exec/simple_x64.py b/windows/native_exec/simple_x64.py index a1b8b37..e02333c 100644 --- a/windows/native_exec/simple_x64.py +++ b/windows/native_exec/simple_x64.py @@ -329,7 +329,7 @@ class Imm8(object): except (ValueError, TypeError): return None, None, None try: - imm8 = accept_as_16immediat(x) + imm8 = accept_as_8immediat(x) except ImmediatOverflow: return None, None, None return (1, BitArray.from_string(imm8), None) @@ -886,6 +886,14 @@ class Xor(Instruction): encoding = [(RawBits.from_int(8, 0x31), ModRM([ModRM_REG__REG, ModRM_REG64__MEM]))] +class Shr(Instruction): + default_32_bits = True + encoding = [(RawBits.from_int(8, 0xC1), Slash(5), Imm8())] + +class Shl(Instruction): + default_32_bits = True + encoding = [(RawBits.from_int(8, 0xC1), Slash(4), Imm8())] + class Nop(Instruction): encoding = [(RawBits.from_int(8, 0x90),)] diff --git a/windows/native_exec/simple_x86.py b/windows/native_exec/simple_x86.py index 301633a..3de81ae 100644 --- a/windows/native_exec/simple_x86.py +++ b/windows/native_exec/simple_x86.py @@ -705,8 +705,17 @@ class Xchg(Instruction): encoding = [(RawBits.from_int(5, 0x90 >> 3), RegisterEax(), X86RegisterSelector()), (RawBits.from_int(5, 0x90 >> 3), X86RegisterSelector(), RegisterEax())] +class Rol(Instruction): + encoding = [(RawBits.from_int(8, 0xC1), Slash(0), Imm8())] +class Ror(Instruction): + encoding = [(RawBits.from_int(8, 0xC1), Slash(1), Imm8())] +class Shr(Instruction): + encoding = [(RawBits.from_int(8, 0xC1), Slash(5), Imm8())] + +class Shl(Instruction): + encoding = [(RawBits.from_int(8, 0xC1), Slash(4), Imm8())] class Cpuid(Instruction): encoding = [(RawBits.from_int(16, 0x0fa2),)] diff --git a/windows/native_exec/test_simple_x64.py b/windows/native_exec/test_simple_x64.py index 3592548..c152638 100644 --- a/windows/native_exec/test_simple_x64.py +++ b/windows/native_exec/test_simple_x64.py @@ -47,6 +47,7 @@ class TestInstr(object): else: raise AssertionError("Expected result <{0}> got <{1}>".format(self.expected_result, "{0} {1}".format(capres.mnemonic, capres.op_str))) if len(res) != len(capres.bytes): + print("<{0}> vs <{1}>".format(repr(res), repr(capres.bytes))) raise AssertionError("Not all bytes have been used by the disassembler") self.compare_mnemo(capres) self.compare_args(args, capres) @@ -150,6 +151,11 @@ TestInstr(Or)(mem('[RAX + 1]'), 'R8') TestInstr(Or)(mem('[EAX + 1]'), 'R8') TestInstr(Or)(mem('[RAX + 1]'), 'EAX') +TestInstr(Shr)('RAX', 8) +TestInstr(Shr)('R15', 0x12) +TestInstr(Shl)('RAX', 8) +TestInstr(Shl)('R15', 0x12) + # I really don't know why it's the inverse # But I don't care, it's Test dude.. TestInstr(Test, expected_result="test r11, rax")('RAX', 'R11') diff --git a/windows/native_exec/test_simple_x86.py b/windows/native_exec/test_simple_x86.py index 8ecf67e..e3b74d9 100644 --- a/windows/native_exec/test_simple_x86.py +++ b/windows/native_exec/test_simple_x86.py @@ -132,6 +132,13 @@ TestInstr(Movsb, expected_result='movsb byte ptr es:[edi], byte ptr [esi]')() TestInstr(Movsd, expected_result='movsd dword ptr es:[edi], dword ptr [esi]')() TestInstr(Xchg)('EAX', 'ESP') +TestInstr(Rol)('EAX', 7) +TestInstr(Rol)('ECX', 0) + +TestInstr(Ror)('ECX', 0) +TestInstr(Ror)('EDI', 7) +TestInstr(Ror)('EDI', -128) + TestInstr(And)('ECX', 'EBX') TestInstr(And)('EAX', 0x11223344) TestInstr(And)('EAX', mem('[EAX + 1]')) @@ -142,6 +149,11 @@ TestInstr(Or)('EAX', 0x11223344) TestInstr(Or)('EAX', mem('[EAX + 1]')) TestInstr(Or)(mem('[EAX + EAX]'), 'EDX') +TestInstr(Shr)('EAX', 8) +TestInstr(Shr)('EDX', 0x12) +TestInstr(Shl)('EAX', 8) +TestInstr(Shl)('EDX', 0x12) + TestInstr(Not)('EAX') TestInstr(Not)(mem('[EAX]')) @@ -160,8 +172,6 @@ TestInstr(Test, expected_result="test edi, ecx")('ECX', 'EDI') TestInstr(Test)(mem('[ECX + 0x100]'), 'ECX') assert Test(mem('[ECX + 0x100]'), 'ECX').get_code() == Test('ECX', mem('[ECX + 0x100]')).get_code() - - assert Xchg('EAX', 'ECX').get_code() == Xchg('ECX', 'EAX').get_code() code = MultipleInstr() diff --git a/windows/syswow64.py b/windows/syswow64.py index 01f520d..30ca21d 100644 --- a/windows/syswow64.py +++ b/windows/syswow64.py @@ -18,6 +18,8 @@ CS_64bits = 0x33 def genere_return_32bits_stub(ret_addr): ret_32b = x64.MultipleInstr() + ret_32b += x64.Mov("RDX", "RAX") + ret_32b += x64.Shr("RDX", 32) ret_32b += x64.Mov('RCX', (CS_32bits << 32) + ret_addr) ret_32b += x64.Push('RCX') ret_32b += x64.Retf32() # 32 bits return addr @@ -49,7 +51,7 @@ def execute_64bits_code_from_syswow(shellcode): current_process.write_memory(jump_addr, jump) current_process.write_memory(shell_code_addr, shellcode) # Execute - exec_stub = ctypes.CFUNCTYPE(HRESULT)(jump_addr) + exec_stub = ctypes.CFUNCTYPE(ULONG64)(jump_addr) return exec_stub() @@ -169,15 +171,8 @@ def try_generate_stub_target(shellcode, argument_buffer, target): def get_current_process_syswow_peb_addr(): - current_process = windows.current_process - dest = current_process.allocator.reserve_size(8) - get_peb_64_code = x64.MultipleInstr() - get_peb_64_code += x64.Mov('RAX', x64.mem('gs:[0x60]')) - get_peb_64_code += x64.Mov(x64.create_displacement(disp=dest), 'RAX') - current_process.write_memory(dest, "\x00" * 8) - execute_64bits_code_from_syswow(get_peb_64_code.get_code()) - peb_addr = struct.unpack("