Add nativeutils.py with GetProcAddress64 + add instr to x86/x64 assembler + add merge of labels in multipleinstr (dummy function support)

This commit is contained in:
Clement Rouault
2016-01-28 15:13:49 +01:00
parent ec4862439f
commit 38a2298dee
6 changed files with 339 additions and 7 deletions
+49
View File
@@ -0,0 +1,49 @@
import windows
import windows.test
import windows.native_exec.simple_x64 as x64
import windows.native_exec.nativeutils
from windows.generated_def.winstructs import *
GetProcAddress64 = windows.native_exec.nativeutils.GetProcAddress64
dll = "KERNEL32.DLL\x00".encode("utf-16-le")
api = "LoadLibraryA\x00"
dll_to_load = "SUCE"
RemoteManualLoadLibray = x64.MultipleInstr()
c = RemoteManualLoadLibray
c += x64.Mov("R15", "RCX")
c += x64.Mov("RCX", x64.mem("[R15 + 0]"))
c += x64.Mov("RDX", x64.mem("[R15 + 8]"))
c += x64.Call(":FUNC_GETPROCADDRESS64")
c += x64.Mov("RCX", x64.mem("[R15 + 0x10]"))
c += x64.Push("RCX")
c += x64.Push("RCX")
c += x64.Push("RCX")
c += x64.Call("RAX")
c += x64.Pop("RCX")
c += x64.Pop("RCX")
c += x64.Pop("RCX")
c += x64.Ret()
RemoteManualLoadLibray += GetProcAddress64
calc= windows.test.pop_calc_64(dwCreationFlags=CREATE_SUSPENDED)
addr = calc.virtual_alloc(0x1000)
addr2 = addr + len(dll)
addr3 = addr2 + len(api)
addr4 = addr3 + len(dll_to_load)
calc.write_memory(addr, dll)
calc.write_memory(addr2, api)
calc.write_memory(addr3, dll_to_load)
calc.write_qword(addr4, addr)
calc.write_qword(addr4 + 8, addr2)
calc.write_qword(addr4 + 0x10, addr3)
calc.execute(RemoteManualLoadLibray.get_code(), addr4)
+138
View File
@@ -0,0 +1,138 @@
import windows
import windows.native_exec.simple_x64 as x64
from windows.generated_def.winstructs import *
StrlenW64 = x64.MultipleInstr()
StrlenW64 += x64.Label(":FUNC_STRLENW64")
StrlenW64 += x64.Push("RCX")
StrlenW64 += x64.Push("RDI")
StrlenW64 += x64.Mov("RDI", "RCX")
StrlenW64 += x64.Xor("RAX", "RAX")
StrlenW64 += x64.Xor("RCX", "RCX")
StrlenW64 += x64.Dec("RCX")
StrlenW64 += x64.Repne + x64.ScasW()
StrlenW64 += x64.Not("RCX")
StrlenW64 += x64.Dec("RCX")
StrlenW64 += x64.Mov("RAX", "RCX")
StrlenW64 += x64.Pop("RDI")
StrlenW64 += x64.Pop("RCX")
StrlenW64 += x64.Ret()
StrlenA64 = x64.MultipleInstr()
StrlenA64 += x64.Label(":FUNC_STRLENA64")
StrlenA64 += x64.Push("RCX")
StrlenA64 += x64.Push("RDI")
StrlenA64 += x64.Mov("RDI", "RCX")
StrlenA64 += x64.Xor("RAX", "rax")
StrlenA64 += x64.Xor("RCX", "RCX")
StrlenA64 += x64.Dec("RCX")
StrlenA64 += x64.Repne + x64.ScasB()
StrlenA64 += x64.Not("RCX")
StrlenA64 += x64.Dec("RCX")
StrlenA64 += x64.Mov("RAX", "RCX")
StrlenA64 += x64.Pop("RDI")
StrlenA64 += x64.Pop("RCX")
StrlenA64 += x64.Ret()
GetProcAddress64 = x64.MultipleInstr()
GetProcAddress64 += x64.Label(":FUNC_GETPROCADDRESS64")
GetProcAddress64 += x64.Push("RBX")
GetProcAddress64 += x64.Push("RCX")
GetProcAddress64 += x64.Push("RDX")
GetProcAddress64 += x64.Push("RSI")
GetProcAddress64 += x64.Push("RDI")
GetProcAddress64 += x64.Push("R8")
GetProcAddress64 += x64.Push("R9")
GetProcAddress64 += x64.Push("R10")
GetProcAddress64 += x64.Push("R11")
GetProcAddress64 += x64.Push("R12")
GetProcAddress64 += x64.Push("R13")
# Params : RCX -> libname
# Params : RDX -> API Name
GetProcAddress64 += x64.Mov("R11", "RCX")
GetProcAddress64 += x64.Mov("R12", "RDX")
GetProcAddress64 += x64.Mov("RAX", x64.mem("GS:[0x60]")) #PEB !
GetProcAddress64 += x64.Mov("RAX", x64.mem("[RAX + 24] ")) # ; RAX = ldr (+ 6 for 64 cause of 2 ptr)
GetProcAddress64 += x64.Mov("RAX", x64.mem("[RAX + 32]")) # ; RAX on the first elt of the list (first module)
GetProcAddress64 += x64.Mov("RDX", "RAX")
GetProcAddress64 += x64.Label(":a_dest")
GetProcAddress64 += x64.Mov("RAX", "RDX")
GetProcAddress64 += x64.Mov("RBX", x64.mem("[RAX + 32]")) # RBX : first base ! (base of current module)
#GetProcAddress64 += x64.Mov("RBX ", x64.mem("[RAX + 32]")) # RBX : first base ! (base of current module)
GetProcAddress64 += x64.Cmp("RBX", 0)
GetProcAddress64 += x64.Jz(":NOT_FOUND")
GetProcAddress64 += x64.Mov("RCX", x64.mem("[RAX + 80]")) # RCX = NAME (UNICODE_STRING.Buffer)
GetProcAddress64 += x64.Call(":FUNC_STRLENW64")
GetProcAddress64 += x64.Mov("RDI", "RCX")
GetProcAddress64 += x64.Mov("RCX", "RAX")
GetProcAddress64 += x64.Mov("RSI", "R11")
#GetProcAddress64 += x64.Int3()
GetProcAddress64 += x64.Rep + x64.CmpsW() #;cmp with current dll name (unicode)
GetProcAddress64 += x64.Test("RCX", "RCX")
GetProcAddress64 += x64.Jz(":DLL_FOUND")
GetProcAddress64 += x64.Mov("RDX", x64.mem("[RDX]"))
GetProcAddress64 += x64.Jmp(":a_dest")
GetProcAddress64 += x64.Label(":DLL_FOUND") # here rbx = base
GetProcAddress64 += x64.Mov("EAX", x64.mem("[RBX + 60]")) # rax = PEBASE RVA
GetProcAddress64 += x64.Add("RAX", "RBX") # RAX = PEBASE
GetProcAddress64 += x64.Add("RAX", 24) # ;OPTIONAL HEADER
GetProcAddress64 += x64.Mov("ECX", x64.mem("[rax + 112]")) # ;rcx = RVA export dir
GetProcAddress64 += x64.Add("RCX", "RBX") # ;rcx = export_dir
GetProcAddress64 += x64.Mov("RAX", "RCX") # ;RAX = export_dir
GetProcAddress64 += x64.Push("RAX") # ;Save it for after function search
# ; EBX = BASE | EAX = EXPORT DIR
GetProcAddress64 += x64.Mov("ECX", x64.mem("[RAX + 24] ")) # rax = PEBASE RVA
GetProcAddress64 += x64.Mov("R13", "RCX") # ;r13 = NB names
GetProcAddress64 += x64.Mov("EDX", x64.mem("[RAX + 32] ")) # EDX = names array RVA
GetProcAddress64 += x64.Add("RDX", "RBX") # RDX = names array
GetProcAddress64 += x64.Xor("RCX", "RCX")
GetProcAddress64 += x64.Label(":SEARCH_LOOP")
GetProcAddress64 += x64.Mov("ESI", x64.mem("[RDX + RCX * 4]")) # ;Get function name RVA
GetProcAddress64 += x64.Add("RSI", "RBX") # ;Get name addr
GetProcAddress64 += x64.Push("RCX") # ;Save current index (could use x64 register)
GetProcAddress64 += x64.Mov("RCX", "R12")
GetProcAddress64 += x64.Call(":FUNC_STRLENA64") # TODO: mov outside the loop :D
GetProcAddress64 += x64.Mov("RCX", "RAX")
GetProcAddress64 += x64.Mov("RDI", "R12")
GetProcAddress64 += x64.Rep + x64.CmpsB()
GetProcAddress64 += x64.Mov("EAX", "ECX")
GetProcAddress64 += x64.Pop("RCX")
GetProcAddress64 += x64.Inc("RCX")
GetProcAddress64 += x64.Test("RAX", "RAX")
GetProcAddress64 += x64.Jnz(":SEARCH_LOOP")
# Func FOUND !
GetProcAddress64 += x64.Dec("RCX")
GetProcAddress64 += x64.Pop("RAX") # ;Restore export_dir addr
GetProcAddress64 += x64.Mov("EDX", x64.mem("[RAX + 36]")) # ;EDX = AddressOfNameOrdinals RVX
GetProcAddress64 += x64.Add("RDX", "RBX")
GetProcAddress64 += x64.OperandSizeOverride + x64.Mov("ECX", x64.mem("[rdx + rcx * 2]")) # ; ecx = Ieme ordinal (short array)
GetProcAddress64 += x64.And('RCX', 0xffff)
GetProcAddress64 += x64.Mov("EDX", x64.mem("[RAX + 28]")) # ; AddressOfFunctions RVA
GetProcAddress64 += x64.Add("RDX", "RBX")
GetProcAddress64 += x64.Mov("EDX", x64.mem("[RDX + RCX * 4]"))
GetProcAddress64 += x64.Add("RDX", "RBX")
GetProcAddress64 += x64.Mov("RAX", "RDX")
GetProcAddress64 += x64.Pop("R13")
GetProcAddress64 += x64.Pop("R12")
GetProcAddress64 += x64.Pop("R11")
GetProcAddress64 += x64.Pop("R10")
GetProcAddress64 += x64.Pop("R9")
GetProcAddress64 += x64.Pop("R8")
GetProcAddress64 += x64.Pop("RDI")
GetProcAddress64 += x64.Pop("RSI")
GetProcAddress64 += x64.Pop("RDX")
GetProcAddress64 += x64.Pop("RCX")
GetProcAddress64 += x64.Pop("RBX")
GetProcAddress64 += x64.Ret()
GetProcAddress64 += x64.Label(":NOT_FOUND")
GetProcAddress64 += x64.Xor("RAX", "RAX")
GetProcAddress64 += x64.Ret()
# Ajout des dependances
GetProcAddress64 += StrlenW64
GetProcAddress64 += StrlenA64
+58 -4
View File
@@ -722,9 +722,6 @@ class Pop(Instruction):
encoding = [(RawBits.from_int(5, 0x58 >> 3), X64RegisterSelector())]
class Call(Instruction):
encoding = [(RawBits.from_int(8, 0xff), Slash(2))]
class Xchg(Instruction):
default_32_bits = True
@@ -820,6 +817,10 @@ class JmpImm8(JmpImm):
class JmpImm32(JmpImm):
accept_as_Ximmediat = staticmethod(accept_as_32immediat)
class Call(JmpType):
encoding = [(RawBits.from_int(8, 0xe8), JmpImm32(5)),
(RawBits.from_int(8, 0xff), Slash(2))]
class Jmp(JmpType):
encoding = [(RawBits.from_int(8, 0xeb), JmpImm8(2)),
@@ -867,10 +868,17 @@ class Mov(Instruction):
class Cmp(Instruction):
default_32_bits = True
encoding = [(RawBits.from_int(8, 0x3d), RegisterRax(), Imm32()),
(RawBits.from_int(8, 0x81), Slash(7), Imm32()),
(RawBits.from_int(8, 0x3b), ModRM([ModRM_REG__REG, ModRM_REG64__MEM]))]
class Test(Instruction):
default_32_bits = True
refuse_reverse = True
encoding = [(RawBits.from_int(8, 0xf7), Slash(7), Imm32()),
(RawBits.from_int(8, 0x85), ModRM([ModRM_REG__REG, ModRM_REG64__MEM], has_direction_bit=False))]
class Xor(Instruction):
default_32_bits = True
@@ -880,6 +888,47 @@ class Xor(Instruction):
class Nop(Instruction):
encoding = [(RawBits.from_int(8, 0x90),)]
class Not(Instruction):
default_32_bits = True
encoding = [(RawBits.from_int(8, 0xF7), Slash(2))]
class ScasB(Instruction):
default_32_bits = True
encoding = [(RawBits.from_int(8, 0xAE),)]
class ScasW(Instruction):
default_32_bits = True
encoding = [(RawBits.from_int(16, 0x66AF),)]
class ScasD(Instruction):
default_32_bits = True
encoding = [(RawBits.from_int(8, 0xAF),)]
class ScasQ(Instruction):
encoding = [(RawBits.from_int(16, 0x48AF),)]
class CmpsB(Instruction):
default_32_bits = True
encoding = [(RawBits.from_int(8, 0xa6),)]
class CmpsW(Instruction):
default_32_bits = True
encoding = [(RawBits.from_int(16, 0x66A7),)]
class CmpsD(Instruction):
default_32_bits = True
encoding = [(RawBits.from_int(8, 0xa7),)]
class CmpsQ(Instruction):
default_32_bits = True
encoding = [(RawBits.from_int(16, 0x48A7),)]
class Retf(Instruction):
default_32_bits = True
@@ -922,7 +971,7 @@ class MultipleInstr(object):
def get_code(self):
if self.expected_labels:
raise ValueError("Unresolved labels: {self.expected_labels}".format(self=self))
raise ValueError("Unresolved labels: {0}".format(self.expected_labels.keys()))
return b"".join([bytes(x[1].get_code()) for x in sorted(self.instrs.items())])
def add_instruction(self, instruction):
@@ -1036,7 +1085,12 @@ class MultipleInstr(object):
self.size -= 1
def merge_shellcode(self, other):
shared_labels = set(self.labels) & set(other.labels)
if shared_labels:
raise ValueError("Cannot merge shellcode: shared labels {0}".format(shared_labels))
for offset, instr in sorted(other.instrs.items()):
for label_name in [name for name, label_offset in other.labels.items() if label_offset == offset]:
self.add_instruction(Label(label_name))
self.add_instruction(instr)
def __iadd__(self, other):
+43 -2
View File
@@ -580,6 +580,11 @@ class JmpImm32(JmpImm):
# Instructions
class Call(JmpType):
encoding = [(RawBits.from_int(8, 0xe8), JmpImm32(5)),
(RawBits.from_int(8, 0xff), Slash(2))]
class Jmp(JmpType):
encoding = [(RawBits.from_int(8, 0xeb), JmpImm8(2)),
(RawBits.from_int(8, 0xe9), JmpImm32(5))]
@@ -674,6 +679,11 @@ class Cmp(Instruction):
(RawBits.from_int(8, 0x3b), ModRM([ModRM_REG__REG, ModRM_REG__MEM]))]
class Test(Instruction):
encoding = [(RawBits.from_int(8, 0xf7), Slash(7), Imm32()),
(RawBits.from_int(8, 0x85), ModRM([ModRM_REG__REG, ModRM_REG__MEM], has_direction_bit=False))]
class Out(Instruction):
encoding = [(RawBits.from_int(8, 0xee), FixedRegister('DX'), FixedRegister('AL')),
(RawBits.from_int(16, 0x66ef), FixedRegister('DX'), FixedRegister('AX')), # Fuck-it hardcoded prefix for now
@@ -694,8 +704,7 @@ class Xchg(Instruction):
encoding = [(RawBits.from_int(5, 0x90 >> 3), RegisterEax(), X86RegisterSelector()), (RawBits.from_int(5, 0x90 >> 3), X86RegisterSelector(), RegisterEax())]
class Call(Instruction):
encoding = [(RawBits.from_int(8, 0xff), Slash(2))]
class Cpuid(Instruction):
@@ -706,9 +715,36 @@ class Ret(Instruction):
encoding = [(RawBits.from_int(8, 0xc3),)]
class ScasB(Instruction):
encoding = [(RawBits.from_int(8, 0xAE),)]
class ScasW(Instruction):
encoding = [(RawBits.from_int(16, 0x66AF),)]
class ScasD(Instruction):
encoding = [(RawBits.from_int(8, 0xAF),)]
class CmpsB(Instruction):
default_32_bits = True
encoding = [(RawBits.from_int(8, 0xa6),)]
class CmpsW(Instruction):
default_32_bits = True
encoding = [(RawBits.from_int(16, 0x66A7),)]
class CmpsD(Instruction):
default_32_bits = True
encoding = [(RawBits.from_int(8, 0xa7),)]
class Nop(Instruction):
encoding = [(RawBits.from_int(8, 0x90),)]
class Not(Instruction):
encoding = [(RawBits.from_int(8, 0xF7), Slash(2))]
class Retf(Instruction):
encoding = [(RawBits.from_int(8, 0xcb),)]
@@ -866,7 +902,12 @@ class MultipleInstr(object):
self.size -= 1
def merge_shellcode(self, other):
shared_labels = set(self.labels) & set(other.labels)
if shared_labels:
raise ValueError("Cannot merge shellcode: shared labels {0}".format(shared_labels))
for offset, instr in sorted(other.instrs.items()):
for label_name in [name for name, label_offset in other.labels.items() if label_offset == offset]:
self.add_instruction(Label(label_name))
self.add_instruction(instr)
def __iadd__(self, other):
+32 -1
View File
@@ -13,9 +13,10 @@ mnemonic_name_exception = {'movabs': 'mov'}
class TestInstr(object):
def __init__(self, instr_to_test, immediat_accepted=None, must_fail=None, debug=False):
def __init__(self, instr_to_test, expected_result=None, immediat_accepted=None, must_fail=None, debug=False):
self.instr_to_test = instr_to_test
self.immediat_accepted = immediat_accepted
self.expected_result = expected_result
self.must_fail = must_fail
self.debug = debug
@@ -40,6 +41,11 @@ class TestInstr(object):
raise AssertionError("Trying to disas an instruction resulted in multiple disassembled instrs")
capres = capres_list[0]
print("{0} {1}".format(capres.mnemonic, capres.op_str))
if self.expected_result is not None:
if "{0} {1}".format(capres.mnemonic, capres.op_str) == self.expected_result:
return True
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):
raise AssertionError("Not all bytes have been used by the disassembler")
self.compare_mnemo(capres)
@@ -128,6 +134,7 @@ TestInstr(Mov, immediat_accepted=-1)('RCX', 0xffffffffffffffff)
TestInstr(Mov)(mem('gs:[0x1122334455667788]'), 'RAX')
TestInstr(Mov)(mem('[RAX]'), 0x11223344)
TestInstr(Mov)(mem('[EAX]'), 0x11223344)
TestInstr(Mov)(mem('[RBX]'), 0x11223344)
TestInstr(And)('RCX', 'RBX')
TestInstr(And)('RAX', 0x11223344)
@@ -143,6 +150,15 @@ TestInstr(Or)(mem('[RAX + 1]'), 'R8')
TestInstr(Or)(mem('[EAX + 1]'), 'R8')
TestInstr(Or)(mem('[RAX + 1]'), 'EAX')
# 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')
TestInstr(Test, expected_result="test edi, eax")('EAX', 'EDI')
TestInstr(Test)('RCX', 'RCX')
TestInstr(Test)(mem('[RDI + 0x100]'), 'RCX')
assert Test(mem('[RDI + 0x100]'), 'RCX').get_code() == Test('RCX', mem('[RDI + 0x100]')).get_code()
TestInstr(Push)('R15')
@@ -168,6 +184,21 @@ TestInstr(Mov)(mem('[RBX + RCX + 0x10]'), 'ECX')
TestInstr(Mov)(mem('[EBX + ECX + 0x10]'), 'ECX')
TestInstr(Mov)(mem('[EBX + ECX + 0x10]'), 'R8')
TestInstr(Not)('RAX')
TestInstr(Not)(mem('[RAX]'))
TestInstr(ScasB, expected_result="scasb al, byte ptr [rdi]")()
TestInstr(ScasW, expected_result="scasw ax, word ptr [rdi]")()
TestInstr(ScasD, expected_result="scasd eax, dword ptr [rdi]")()
TestInstr(ScasQ, expected_result="scasq rax, qword ptr [rdi]")()
TestInstr(CmpsB, expected_result="cmpsb byte ptr [rsi], byte ptr [rdi]")()
TestInstr(CmpsW, expected_result="cmpsw word ptr [rsi], word ptr [rdi]")()
TestInstr(CmpsD, expected_result="cmpsd dword ptr [rsi], dword ptr [rdi]")()
TestInstr(CmpsQ, expected_result="cmpsq qword ptr [rsi], qword ptr [rdi]")()
TestInstr(Mov, must_fail=True)('RCX', 'ECX')
TestInstr(Mov, must_fail=True)('RCX', mem('[ECX + RCX]'))
+19
View File
@@ -140,6 +140,25 @@ TestInstr(Or)('EAX', 0x11223344)
TestInstr(Or)('EAX', mem('[EAX + 1]'))
TestInstr(Or)(mem('[EAX + EAX]'), 'EDX')
TestInstr(Not)('EAX')
TestInstr(Not)(mem('[EAX]'))
TestInstr(ScasB, expected_result="scasb al, byte ptr es:[edi]")()
TestInstr(ScasW, expected_result="scasw ax, word ptr es:[edi]")()
TestInstr(ScasD, expected_result="scasd eax, dword ptr es:[edi]")()
TestInstr(CmpsB, expected_result="cmpsb byte ptr [esi], byte ptr es:[edi]")()
TestInstr(CmpsW, expected_result="cmpsw word ptr [esi], word ptr es:[edi]")()
TestInstr(CmpsD, expected_result="cmpsd dword ptr [esi], dword ptr es:[edi]")()
TestInstr(Test)('EAX', 'EAX')
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()