Exemplo n.º 1
0
def go(f, daddr, tags):
  e = ELFFile(f)
  for seg in e.iter_segments():
    dat = seg.data()
    print seg.header
    for c in range(len(dat)):
      daddr[seg['p_vaddr']+c] = ord(dat[c])
  for sec in e.iter_sections():
    print sec.name, sec.header
    if sec['sh_flags'] & 4:
      dat = sec.data()
      for op in distorm3.DecomposeGenerator(sec['sh_addr'], dat, distorm3.Decode32Bits):
        p = "\\t{\\o{"+op.mnemonic+"}}"
        f = False
        for i in op.operands:
          if f == False:
            f = True
          else:
            p += ", "
          if i.type == "Immediate":
            p += "\\i{"+str(i.value)+"}"
          else:
            p += str(i)
          print i.type, dir(i)
        tags[op.address]['len'] = str(op.size)
        tags[op.address]['parsed'] = str(p)
        tags[op.address]['endian'] = 'little'
        print op.mnemonic, op.flowControl, op.size
        print dir(op)
  return hex(e.header['e_entry'])
Exemplo n.º 2
0
    def disasm_around(self, trace, starting_addr, size):
        '''
    returns the disassembly starting at addr for size instructions.
    
    @type  trace: vtrace
    @param trace: instance of vtrace
    @type  addr: int
    @param addr: address where to begin disassembly
    @type  size: int
    @param size: number of instructions to disassemble
    '''
        disasm = []
        try:
            code = trace.readMemory(starting_addr, size)
        except:
            raise Exception("unable to read memory for disasm")

        if self.arch == '32':
            asm_arch = distorm3.Decode32Bits
        elif self.arch == '64':
            asm_arch = distorm3.Decode64Bits
        elif self.arch == '16':
            asm_arch = distorm3.Decode16Bits

        for inst in distorm3.DecomposeGenerator(starting_addr, code, asm_arch):
            if not inst.valid:
                return disasm
            else:
                disasm.append(inst)
        return disasm
Exemplo n.º 3
0
def print_valid_code(code):
    offset = 0
    while offset < len(code):
        for insn in distorm3.DecomposeGenerator(
                offset, code[offset:], distorm3.Decode64Bits,
                distorm3.DF_STOP_ON_FLOW_CONTROL):
            print offset, " : ", insn
            offset += insn.size
Exemplo n.º 4
0
def call_scan(data_vr_address, data, start_limit=None, end_limit=None):
    """Disassemble a block of data and yield possible 
    calls to imported functions. We're looking for 
    instructions such as these:
    x86:
    CALL DWORD [0x1000400]
    JMP  DWORD [0x1000400]
    We also capture indirect call where the API address is moved into
    a register and the regsiter is called:
    MOV ECX [0x9400c]
    CALL ECX Register
    """
    # Call scan has two options based on the limit settings
    # if there are no limits then only potential IAT pointers 
    # to inside the scanned data will be kept. This is useful 
    # if you are scanning a data blob and are not able to resolve 
    # outside the blob.
    #
    # If the limits are set then any potential IAT pointers to
    # inside the limits are kept. This is useful if you are 
    # scanning the code segment of a PE file but your IAT may
    # be located in another segment in the PE file. Set the 
    # limits to be the start and end of the mapped PE.
    #
    if start_limit == None:
        start_limit = data_vr_address
    if end_limit ==None:
        end_limit = data_vr_address + len(data)

    iat_ptrs=[]
    reg_redirect = {"EAX":0x0, "EBX":0x0, "ECX":0x0, "EDX":0x0}
    mode = distorm3.Decode32Bits
    for op in distorm3.DecomposeGenerator(data_vr_address, data, mode):
        if not op.valid:
            continue
        iat_loc = None
        if (_call_or_unc_jmp(op) and op.operands[0].type == 'AbsoluteMemoryAddress'):
            iat_loc = (op.operands[0].disp) & 0xffffffff
        
        if op.mnemonic == "MOV" and op.operands[0].type == 'Register' and op.operands[1].type == 'AbsoluteMemory':
            #print "MOV %s %s %s" % (op.operands[0], op.operands[1], op.operands[1].type)
            reg_redirect[str(op.operands[0])] = op.address + op.operands[1].disp
        if op.mnemonic == "MOV" and op.operands[0].type == 'Register' and op.operands[1].type == 'AbsoluteMemoryAddress':
            #print "MOV %s %s %s" % (op.operands[0], op.operands[1], op.operands[1].type)
            reg_redirect[str(op.operands[0])] =op.operands[1].disp
        if op.mnemonic == "CALL" and op.operands[0].type == 'Register':
            #print "CALL %s %s" % (op.operands[0], op.operands[0].type)
            iat_loc = reg_redirect[str(op.operands[0])]
        if (not iat_loc or (iat_loc < start_limit) or (iat_loc > end_limit)):
            continue
        # resolve iat_loc to API
        #print iat_loc
        if iat_loc not in iat_ptrs:
            iat_ptrs.append(iat_loc)
    return iat_ptrs
Exemplo n.º 5
0
def build_code_dict(code, section, dwarfinfo):
    # Credit: https://github.com/HexHive/SMoTherSpectre
    s_off = section['sh_offset']

    ## Create a dictionary of valid instructions at all offsets
    for offset in tqdm(range(len(code))):
        if code_dict.has_key(offset): continue
        for insn in distorm3.DecomposeGenerator(
                s_off + offset, code[offset:], distorm3.Decode64Bits,
                distorm3.DF_STOP_ON_FLOW_CONTROL):
            if insn.valid:
                code_dict[offset] = insn
            offset += insn.size
Exemplo n.º 6
0
def build_code_dict(code, section, dwarfinfo):
    s_off = section['sh_offset']
    # print_valid_code(code)

    print hex(len(code))
    ## Create a dictionary of valid instructions at all offsets
    for offset in range(len(code)):
        if offset & 0xfff == 0:
            print hex(offset)
        if code_dict.has_key(offset): continue
        for insn in distorm3.DecomposeGenerator(
                s_off + offset, code[offset:], distorm3.Decode64Bits,
                distorm3.DF_STOP_ON_FLOW_CONTROL):
            if insn.valid:
                code_dict[offset] = insn
            offset += insn.size
Exemplo n.º 7
0
 def check(self, addr):
     max_mem_addr = (2**32
                     if self.mode == distorm3.Decode32Bits else 2**64) - 1
     max_gadget_size = min(MAX_GADGET_SIZE, max_mem_addr - addr)
     if max_gadget_size == 0:
         return False
     code = self.addrspace.zread(addr, max_gadget_size)
     for op in distorm3.DecomposeGenerator(
             addr, code, self.mode, features=distorm3.DF_RETURN_FC_ONLY):
         if not op.valid:
             continue
         if self.rop_size > 0 and op.flowControl == 'FC_RET':
             self.rop_size = addr - op.address
             return True
         else:
             return False
     return False
Exemplo n.º 8
0
def call_scan(data_vr_address, data, start_limit=None, end_limit=None):
    """Disassemble a block of data and yield possible 
    calls to imported functions. We're looking for 
    instructions such as these:
    x86:
    CALL DWORD [0x1000400]
    JMP  DWORD [0x1000400]
    """
    # Call scan has two options based on the limit settings
    # if there are no limits then only potential IAT pointers
    # to inside the scanned data will be kept. This is useful
    # if you are scanning a data blob and are not able to resolve
    # outside the blob.
    #
    # If the limits are set then any potential IAT pointers to
    # inside the limits are kept. This is useful if you are
    # scanning the code segment of a PE file but your IAT may
    # be located in another segment in the PE file. Set the
    # limits to be the start and end of the mapped PE.
    #
    if start_limit == None:
        start_limit = data_vr_address
    if end_limit == None:
        end_limit = data_vr_address + len(data)

    iat_ptrs = []
    mode = distorm3.Decode32Bits
    for op in distorm3.DecomposeGenerator(data_vr_address, data, mode):
        if not op.valid:
            continue
        iat_loc = None
        if (_call_or_unc_jmp(op)
                and op.operands[0].type == 'AbsoluteMemoryAddress'):
            iat_loc = (op.operands[0].disp) & 0xffffffff
        if (not iat_loc or (iat_loc < start_limit) or (iat_loc > end_limit)):
            continue
        # resolve iat_loc to API
        #print iat_loc
        if iat_loc not in iat_ptrs:
            iat_ptrs.append(iat_loc)
    return iat_ptrs
Exemplo n.º 9
0
    def _parseCodeAddress(self, rva, raw_offset, queue):
        for instr in distorm3.DecomposeGenerator(rva, self.raw[raw_offset:],
                                                 distorm3.Decode32Bits):
            # we have already analyzed this address
            if self.parsed[raw_offset]: break
            self.parsed[raw_offset] = True

            # this is not executable memory
            if not self.rva_is_executable(rva): break

            print hex(instr.address)[:-1], instr, instr.size
            raw_offset += instr.size
            rva += instr.size

            # jump to or call an address?
            if instr.flowControl in ['FC_CALL', 'FC_UNC_BRANCH',
                    'FC_CND_BRANCH'] and \
                    instr.operands[0].type == distorm3.OPERAND_IMMEDIATE:
                queue.append(instr.operands[0].value)

            # stop disassembling..
            if instr.mnemonic.lower() in ['retn', 'jmp']:
                break
Exemplo n.º 10
0
    def call_scan(self, addr_space, base_address, data):
        """Disassemble a block of data and yield possible 
        calls to imported functions. We're looking for 
        instructions such as these:

        x86:
        CALL DWORD [0x1000400]
        JMP  DWORD [0x1000400]
        
        x64:
        CALL QWORD [RIP+0x989d]

        On x86, the 0x1000400 address is an entry in the 
        IAT or call table. It stores a DWORD which is the 
        location of the API function being called. 

        On x64, the 0x989d is a relative offset from the
        current instruction (RIP). 

        @param addr_space: an AS to scan with
        @param base_address: memory base address
        @param data: buffer of data found at base_address 
        """

        end_address = base_address + len(data)

        memory_model = addr_space.profile.metadata.get('memory_model', '32bit')

        if memory_model == '32bit':
            mode = distorm3.Decode32Bits
        else:
            mode = distorm3.Decode64Bits

        for op in distorm3.DecomposeGenerator(base_address, data, mode):

            if not op.valid:
                continue

            iat_loc = None

            if memory_model == '32bit':
                if (self._call_or_unc_jmp(op)
                        and op.operands[0].type == 'AbsoluteMemoryAddress'):
                    iat_loc = (op.operands[0].disp) & 0xffffffff
            else:
                if (self._call_or_unc_jmp(op)
                        and 'FLAG_RIP_RELATIVE' in op.flags
                        and op.operands[0].type == 'AbsoluteMemory'):
                    iat_loc = op.address + op.size + op.operands[0].disp

            if (not iat_loc or (iat_loc < base_address)
                    or (iat_loc > end_address)):
                continue

            # This is the address being called
            call_dest = obj.Object("address", offset=iat_loc, vm=addr_space)

            if call_dest == None:
                continue

            yield op.address, iat_loc, int(call_dest)
Exemplo n.º 11
0
def find_tables(start_addr, vm):
    """
    This function finds the RVAs to KeServiceDescriptorTable
    and KeServiceDescriptorTableShadow in the NT module. 

    @param start_addr: virtual address of KeAddSystemServiceTable
    @param vm: kernel address space 

    We're looking for two instructions like this:

    //if (KeServiceDescriptorTable[i].Base)
    4B 83 BC 1A 40 88 2A 00 00    cmp qword ptr [r10+r11+2A8840h], 0 
    //if (KeServiceDescriptorTableShadow[i].Base)
    4B 83 BC 1A 80 88 2A 00 00    cmp qword ptr [r10+r11+2A8880h], 0

    In the example, 2A8840h is the RVA of KeServiceDescriptorTable 
    and 2A8880h is the RVA of KeServiceDescriptorTableShadow. The
    exported KeAddSystemServiceTable is a very small function (about
    120 bytes at the most) and the two instructions appear very 
    early, which reduces the possibility of false positives. 

    If distorm3 is installed, we use it to decompose instructions 
    in x64 format. If distorm3 is not available, we use Volatility's
    object model as a very simple and generic instruction parser. 
    """
    service_tables = []

    try:
        import distorm3
        use_distorm = True
    except ImportError:
        use_distorm = False

    function_size = 120

    if use_distorm:
        data = vm.zread(start_addr, function_size)
        for op in distorm3.DecomposeGenerator(start_addr, data,
                                              distorm3.Decode64Bits):
            # Stop decomposing if we reach the function end
            if op.flowControl == 'FC_RET':
                break
            # Looking for a 9-byte CMP instruction whose first operand
            # has a 32-bit displacement and second operand is zero
            if op.mnemonic == 'CMP' and op.size == 9 and op.operands[
                    0].dispSize == 32 and op.operands[0].value == 0:
                # The displacement is the RVA we want
                service_tables.append(op.operands[0].disp)
            elif op.mnemonic == 'LEA' and op.size == 7 and op.operands[
                    1].dispSize == 32 and op.operands[1].disp > 0:
                service_tables.append(op.operands[1].disp)
    else:
        vm.profile.add_types({
            '_INSTRUCTION': [
                9, {
                    'opcode': [0, ['String', dict(length=4)]],
                    'disp': [4, ['int']],
                    'value': [8, ['unsigned char']],
                }
            ]
        })
        # The variations assume (which happens to be correct on all OS)
        # that volatile registers are used in the CMP QWORD instruction.
        # All combinations of volatile registers (rax, rcx, rdx, r8-r11)
        # will result in one of the variations in this list.
        ops_list = [
            "\x4B\x83\xBC",  # r10, r11
            "\x48\x83\xBC",  # rax, rcx
            "\x4A\x83\xBC",  # rax, r8
            "\x48\x8D\x8B",  # win8x64 LEA RCX, [EBX+??????]
        ]
        for i in range(function_size):
            op = obj.Object("_INSTRUCTION", offset=start_addr + i, vm=vm)
            if op.value == 0:
                for s in ops_list:
                    if op.opcode.v().startswith(s):
                        service_tables.append(op.disp)

    return service_tables
Exemplo n.º 12
0
class ApiHooks(procdump.ProcExeDump):
    """Detect API hooks in process and kernel memory"""
    def __init__(self, config, *args, **kwargs):
        procdump.ProcExeDump.__init__(self, config, *args, **kwargs)
        config.remove_option("DUMP-DIR")

        config.add_option("NO-WHITELIST",
                          short_option='N',
                          default=False,
                          action='store_true',
                          help='No whitelist (show all hooks, can be verbose)')

        config.add_option("SKIP-KERNEL",
                          short_option='R',
                          default=False,
                          action='store_true',
                          help='Skip kernel mode checks')

        config.add_option("SKIP-PROCESS",
                          short_option='P',
                          default=False,
                          action='store_true',
                          help='Skip process checks')

        config.add_option(
            "QUICK",
            short_option='Q',
            default=False,
            action='store_true',
            help='Work faster by only analyzing critical processes and dlls')

        self.compiled_rules = self.compile()

        # When the --quick option is set, we only scan the processes
        # and dlls in these lists. Feel free to adjust them for
        # your own purposes.
        self.critical_process = [
            "explorer.exe", "svchost.exe", "lsass.exe", "services.exe",
            "winlogon.exe", "csrss.exe", "smss.exe", "wininit.exe",
            "iexplore.exe", "firefox.exe", "spoolsv.exe"
        ]

        self.critical_dlls = [
            "ntdll.dll", "kernel32.dll", "ws2_32.dll", "advapi32.dll",
            "secur32.dll", "crypt32.dll", "user32.dll", "gdi32.dll",
            "shell32.dll", "shlwapi.dll", "lsasrv.dll", "cryptdll.dll",
            "wsock32.dll", "mswsock.dll", "urlmon.dll", "csrsrv.dll",
            "winsrv.dll", "wininet.dll"
        ]

        # When scanning for calls to unknown code pages (UCP), only
        # analyze the following drivers. This is based on an analysis of
        # the modules rootkits are most likely to infect, but feel free
        # to adjust it for your own purposes.
        self.ucpscan_modules = [
            "tcpip.sys", "ntfs.sys", "fastfast.sys", "wanarp.sys", "ndis.sys",
            "atapi.sys", "ntoskrnl.exe", "ntkrnlpa.exe", "ntkrnlmp.exe"
        ]

    @staticmethod
    def is_valid_profile(profile):
        return (profile.metadata.get('os', 'unknown') == 'windows'
                and profile.metadata.get('memory_model', '32bit') == '32bit')

    def compile(self):
        """
        Precompile the regular expression rules. Its quicker 
        if we do this once per plugin run, rather than once per 
        API hook that needs checking. 
        """
        ret = dict()
        for key, rules in whitelist_rules.items():
            for rule in rules:
                ruleset = ((
                    re.compile(rule[0], re.I),  # Process name
                    re.compile(rule[1], re.I),  # Source module 
                    re.compile(rule[2], re.I),  # Destination module 
                    re.compile(rule[3], re.I),  # Function name
                ))
                if ret.has_key(key):
                    ret[key].append(ruleset)
                else:
                    ret[key] = [ruleset]
        return ret

    def whitelist(self, rule_key, process, src_mod, dst_mod, function):
        """Check if an API hook should be ignored due to whitelisting. 

        @param rule_key: a key from the whitelist_rules dictionary which
            describes the type of hook (i.e. Usermode IAT or Kernel Inline).

        @param process: name of the suspected victim process. 

        @param src_mod: name of the source module whose function has been
            hooked. this varies depending on whether we're dealing with IAT
            EAT, inline, etc. 

        @param dst_mod: name of the module that is the destination of the 
            hook pointer. this is usually the rootkit dll, exe, or sys, 
            however, in many cases there is no module name since the rootkit
            is trying to be stealthy. 

        @param function: name of the function that has been hooked. 
        """
        # There are no whitelist rules for this hook type
        if rule_key not in self.compiled_rules:
            return False

        for rule in self.compiled_rules[rule_key]:
            if (rule[0].search(process) != None
                    and rule[1].search(src_mod) != None
                    and rule[2].search(dst_mod) != None
                    and rule[3].search(function) != None):
                return True

        return False

    @staticmethod
    def check_syscall(addr_space, module, module_group):
        """
        Enumerate syscall hooks in ntdll.dll. A syscall hook is one 
        that modifies the function prologue of an NT API function 
        (i.e. ntdll!NtCreateFile) or swaps the location of the sysenter 
        with a malicious address. 

        @param addr_space: a process AS for the process containing the
        ntdll.dll module.

        @param module: the _LDR_DATA_TABLE_ENTRY for ntdll.dll

        @param module_group: a ModuleGroup instance for the process. 
        """

        # Resolve the real location of KiFastSystem Call for comparison
        KiFastSystemCall = module.getprocaddress("KiFastSystemCall")
        KiIntSystemCall = module.getprocaddress("KiIntSystemCall")

        if not KiFastSystemCall or not KiIntSystemCall:
            #debug.debug("Abort check_syscall, can't find KiFastSystemCall")
            return

        # Add the RVA to make it absolute
        KiFastSystemCall += module.DllBase
        KiIntSystemCall += module.DllBase

        # Check each exported function if its an NT syscall
        for _, f, n in module.exports():

            # Ignore forwarded exports
            if not f:
                #debug.debug("Skipping forwarded export {0}".format(n or ''))
                continue

            function_address = module.DllBase + f

            if not addr_space.is_valid_address(function_address):
                #debug.debug("Function address {0:#x} for {1} is paged".format(
                #    function_address, n or ''))
                continue

            # Read enough of the function prologue for two instructions
            data = addr_space.zread(function_address, 24)

            instructions = []

            for op in distorm3.Decompose(function_address, data,
                                         distorm3.Decode32Bits):
                if not op.valid:
                    break
                if len(instructions) == 3:
                    break
                instructions.append(op)

            i0 = instructions[0]
            i1 = instructions[1]
            i2 = instructions[2]

            # They both must be properly decomposed and have two operands
            if (not i0 or not i0.valid or len(i0.operands) != 2 or not i1
                    or not i1.valid or len(i1.operands) != 2):
                #debug.debug("Error decomposing prologue for {0} at {1:#x}".format(
                #    n or '', function_address))
                continue

            # Now check the instruction and operand types
            if (i0.mnemonic == "MOV" and i0.operands[0].type == 'Register'
                    and i0.operands[0].name == 'EAX'
                    and i0.operands[1].type == 'Immediate'
                    and i1.mnemonic == "MOV"
                    and i1.operands[0].type == 'Register'
                    and i1.operands[0].name == 'EDX'
                    and i0.operands[1].type == 'Immediate'):

                if i2.operands[0].type == "Register":
                    # KiFastSystemCall is already in the register
                    syscall_address = i1.operands[1].value
                else:
                    # Pointer to where KiFastSystemCall is stored
                    syscall_address = obj.Object('address',
                                                 offset=i1.operands[1].value,
                                                 vm=addr_space)

                if syscall_address not in [KiFastSystemCall, KiIntSystemCall]:
                    hook_module = module_group.find_module(syscall_address)
                    hook = Hook(
                        hook_type=HOOKTYPE_NT_SYSCALL,
                        hook_mode=HOOK_MODE_USER,
                        function_name=n or '',
                        function_address=function_address,
                        hook_address=syscall_address,
                        hook_module=hook_module,
                        victim_module=module,
                    )
                    # Add the bytes that will later be disassembled in the
                    # output to show exactly how the hook works. The first
                    # hop is the ntdll!Nt* API and the next hop is the rootkit.
                    hook.add_hop_chunk(function_address, data)
                    hook.add_hop_chunk(syscall_address,
                                       addr_space.zread(syscall_address, 24))
                    yield hook

    def check_ucpcall(self, addr_space, module, module_group):
        """Scan for calls to unknown code pages. 

        @param addr_space: a kernel AS

        @param module: the _LDR_DATA_TABLE_ENTRY to scan

        @param module_group: a ModuleGroup instance for the process. 
        """

        try:
            dos_header = obj.Object("_IMAGE_DOS_HEADER",
                                    offset=module.DllBase,
                                    vm=addr_space)

            nt_header = dos_header.get_nt_header()
        except (ValueError, exceptions.SanityCheckException), _why:
            #debug.debug('get_nt_header() failed: {0}'.format(why))
            return

        # Parse the PE sections for this driver
        for sec in nt_header.get_sections(self._config.UNSAFE):

            # Only check executable sections
            if not sec.Characteristics & 0x20000000:
                continue

            # Calculate the virtual address of this PE section in memory
            sec_va = module.DllBase + sec.VirtualAddress

            # Extract the section's data and make sure its not all zeros
            data = addr_space.zread(sec_va, sec.Misc.VirtualSize)

            if data == "\x00" * len(data):
                continue

            # Disassemble instructions in the section
            for op in distorm3.DecomposeGenerator(sec_va, data,
                                                  distorm3.Decode32Bits):

                if (op.valid and
                    ((op.flowControl == 'FC_CALL' and op.mnemonic == "CALL") or
                     (op.flowControl == 'FC_UNC_BRANCH'
                      and op.mnemonic == "JMP"))
                        and op.operands[0].type == 'AbsoluteMemoryAddress'):

                    # This is ADDR, which is the IAT location
                    const = op.operands[0].disp & 0xFFFFFFFF

                    # Abort if ADDR is not a valid address
                    if not addr_space.is_valid_address(const):
                        continue

                    # This is what [ADDR] points to - the absolute destination
                    call_dest = obj.Object("address",
                                           offset=const,
                                           vm=addr_space)

                    # Abort if [ADDR] is not a valid address
                    if not addr_space.is_valid_address(call_dest):
                        continue

                    check1 = module_group.find_module(const)
                    check2 = module_group.find_module(call_dest)

                    # If ADDR or [ADDR] point to an unknown code page
                    if not check1 or not check2:
                        hook = Hook(
                            hook_type=HOOKTYPE_CODEPAGE_KERNEL,
                            hook_mode=HOOK_MODE_KERNEL,
                            function_name="",
                            function_address=op.address,
                            hook_address=call_dest,
                        )
                        # Add the location we found the call
                        hook.add_hop_chunk(
                            op.address,
                            data[op.address - sec_va:op.address - sec_va + 24])

                        # Add the rootkit stub
                        hook.add_hop_chunk(call_dest,
                                           addr_space.zread(call_dest, 24))
                        yield hook
Exemplo n.º 13
0
def rebuild_iat(pid, pe_data, base_address, oep, newimpdir="newimpdir", newiat="newiat", loadfrommem=True):
    """Rebuild the import address table for the pe_data that was passed.
    @param pid: process ID for winappdbg to attach to and dump IAT offsets
    @param pe_data: full PE file read in as a binary string
    @param base_address: base address of PE (this override the base addres set in the pe_data)
    @param oep: original entry point of the PE (this override the base addres set in the pe_data)
    @param newimpdir: name for new section that will contain imports
    @param newiat: name for new section that will contain new IAT
    @param loadfrommem: pe data is mapped or unmapped (default mapped)
    """

    pf = pe_init.PE(loadfrommem=loadfrommem, pestr=pe_data)

    pf.NThdr.ImageBase = base_address

    # get offset to oep
    rva_oep = oep - base_address

    pf.Opthdr.AddressOfEntryPoint = rva_oep

    # clear the existing import table
    # there are two different versions of elfesteem one that uses an extra .l[] object
    # and one that does not. If we get the wrong one, just catch the error and continue.
    try:
        pf.DirImport.impdesc.l=[]
    except:
        pf.DirImport.impdesc =[]
    ######################################################################


    pdata = None 
    data_vr_addr = None
    data_rva = None
    # locate section that contains OEP 
    for tmp_sec in pf.SHList:
        tmp_start = tmp_sec.addr
        tmp_end = tmp_start + tmp_sec.size
        if (rva_oep >= tmp_start) and (rva_oep <= tmp_end):
            try:
                pdata = pf._rva.get(tmp_start,tmp_end)
            except AttributeError as e:
                raise AttributeError("You are using the wrong version of elfesteem, don't use pip instead install from https://github.com/serpilliere/elfesteem")
            data_vr_addr = base_address + tmp_start
            data_rva = tmp_start
            break

    # make sure we have found the correct section
    # WARNING! if the pdata section is not the same as the one loaded in memory the IAT extraction will
    #          fail because the addresses and offsets will be wrong.
    assert pdata != None, "Unable to locate rva_oep: 0x%x in sections: %s" % (rva_oep, pf.SHList)

    # find all call/jmp to possible IAT function pointers
    # iat_ptrs is a list of all the addresses that are potential IAT pointers
    iat_ptrs = call_scan(data_vr_addr, pdata, start_limit=base_address, end_limit=base_address+len(pe_data))
    assert len(iat_ptrs) != 0, "Unable to find IAT pointer candidates in code!"

    imp_table = reslove_iat_pointers(pid, iat_ptrs)

    

    # Create a table with module names as the keys and all the functions assigned accordingly
    #[module]:[func1, func2, ...]
    mod_table = {}
    for iat_ptr in imp_table.keys():
        # TODO: it is possbile some module names may end with somethin other than .dll
        tmp_mod = imp_table[iat_ptr][0]+".dll"
        tmp_fn = imp_table[iat_ptr][1]
        if tmp_mod in mod_table.keys():
            f_arr = mod_table[tmp_mod]
            # Only add function name if it isn't already assigned
            if tmp_fn not in f_arr:
                f_arr.append(tmp_fn)
                mod_table[tmp_mod] = f_arr
        else:
            mod_table[tmp_mod] = [tmp_fn]

    newiat_rawsize = (( (len(imp_table.keys()) * 4 ) / 0x1000) + 1) * 0x1000
    # Create new section to hold new IAT 
    s_newiat = pf.SHList.add_section(name=newiat, rawsize=newiat_rawsize)

    ######################################################################
    #
    # elfesteem.PE has a special format for describing the IAT directory
    # We are converting the mod_table into that format...
    #
    ######################################################################
    new_dll=[({"name": mod_table.keys()[0],"firstthunk": s_newiat.addr}, mod_table[mod_table.keys()[0]])]
    for mod in mod_table.keys()[1:]:
        tmp_entry = ({"name": mod,"firstthunk": None}, mod_table[mod])
        new_dll.append(tmp_entry)

    ######################################################################
    #
    # Add the new imports table directory to PE file
    #
    ######################################################################
    pf.DirImport.add_dlldesc(new_dll)
    newimpdir_rawsize = ((len(pf.DirImport) / 0x1000) + 1) * 0x1000
    s_newimpdir = pf.SHList.add_section(name=newimpdir, rawsize=newimpdir_rawsize)
    pf.SHList.align_sections(0x1000, 0x1000)
    pf.DirImport.set_rva(s_newimpdir.addr)
    

    ######################################################################
    #
    # Create a mapping from the old IAT pointers to the new ones
    # iat_map[ <old_pointer> ] = <new_pointer>
    #
    # TODO: handle import by ordinal 
    #
    ######################################################################
    iat_map ={}
    for iat_ptr in imp_table.keys():
        if imp_table[iat_ptr][1] == None:
            continue
        tmp_mod = imp_table[iat_ptr][0]+".dll"
        tmp_fn = imp_table[iat_ptr][1]
        try:
            iat_map[iat_ptr] = pf.DirImport.get_funcvirt(tmp_mod, tmp_fn)
        except:
            continue

    # If there is some error building the module map stop!
    assert iat_map != {}, "The iat_map is empty, we are unable to find the new IAT pointers for the old pointers in imp_table."


    ######################################################################
    #
    # Patch the code section in the PE and replace all references to the 
    # old IAT pointers with references to the new pointers.
    #
    ######################################################################
    # Make a copy of the code data to work on
    odata = pdata

    mode = distorm3.Decode32Bits
    for op in distorm3.DecomposeGenerator(data_vr_addr, pdata, mode):
        if not op.valid:
            continue
        iat_loc = None
        if _iat_candidate(op):
            for operand in op.operands:
                test_operand = operand.disp & 0xffffffff
                if test_operand in iat_map.keys():
                    #print "Fixing IAT pointer for: %s" % op
                    #op_ptr = op.address - base_address
                    #TODO: is this right??
                    op_ptr = op.address - data_vr_addr
                    op_size = op.size
                    orig_op = odata[op_ptr:op_ptr+op_size]
                    orig_operand = struct.pack('<I',test_operand)
                    new_operand = struct.pack('<I',iat_map[test_operand])
                    new_op = orig_op.replace(orig_operand, new_operand)
                    odata = odata[:op_ptr] + new_op + odata[op_ptr+op_size:]
                    #stop testing operands
                    break

    # Copy the patched section back to the PE
    pf._rva.set(data_rva,odata)

    # Disable rebase, since addresses are absolute any rebase will make this explode
    pf.NThdr.dllcharacteristics = 0x0
    return str(pf)
Exemplo n.º 14
0
    def check_ucpcall(self, addr_space, module, module_group):
        """Scan for calls to unknown code pages.

        @param addr_space: a kernel AS

        @param module: the _LDR_DATA_TABLE_ENTRY to scan

        @param module_group: a ModuleGroup instance for the process.
        """

        try:
            dos_header = obj.Object("_IMAGE_DOS_HEADER",
                                    offset=module.DllBase,
                                    vm=addr_space)

            nt_header = dos_header.get_nt_header()
        except (ValueError, exceptions.SanityCheckException) as _why:
            # debug.debug('get_nt_header() failed: {0}'.format(why))
            return

        # Parse the PE sections for this driver
        for sec in nt_header.get_sections(self._config.UNSAFE):

            # Only check executable sections
            if not sec.Characteristics & 0x20000000:
                continue

            # Calculate the virtual address of this PE section in memory
            sec_va = module.DllBase + sec.VirtualAddress

            # Extract the section's data and make sure its not all zeros
            data = addr_space.zread(sec_va, sec.Misc.VirtualSize)

            if data == b'\x00' * len(data):
                continue

            # Disassemble instructions in the section
            for op in distorm3.DecomposeGenerator(sec_va, data,
                                                  distorm3.Decode32Bits):

                if (op.valid and
                    ((op.flowControl == 'FC_CALL' and op.mnemonic == "CALL") or
                     (op.flowControl == 'FC_UNC_BRANCH'
                      and op.mnemonic == "JMP"))
                        and op.operands[0].type == 'AbsoluteMemoryAddress'):

                    # This is ADDR, which is the IAT location
                    const = op.operands[0].disp & 0xFFFFFFFF

                    # Abort if ADDR is not a valid address
                    if not addr_space.is_valid_address(const):
                        continue

                    # This is what [ADDR] points to - the absolute destination
                    call_dest = obj.Object("address",
                                           offset=const,
                                           vm=addr_space)

                    # Abort if [ADDR] is not a valid address
                    if not addr_space.is_valid_address(call_dest):
                        continue

                    check1 = module_group.find_module(const)
                    check2 = module_group.find_module(call_dest)

                    # If ADDR or [ADDR] point to an unknown code page
                    if not check1 or not check2:
                        hook = Hook(
                            hook_type=HOOKTYPE_CODEPAGE_KERNEL,
                            hook_mode=HOOK_MODE_KERNEL,
                            function_name="",
                            function_address=op.address,
                            hook_address=call_dest,
                        )
                        # Add the location we found the call
                        hook.add_hop_chunk(
                            op.address,
                            data[op.address - sec_va:op.address - sec_va + 24],
                        )

                        # Add the rootkit stub
                        hook.add_hop_chunk(call_dest,
                                           addr_space.zread(call_dest, 24))
                        yield hook
Exemplo n.º 15
0
def ssexy_win32(fname):
    import pefile

    # load the pe file
    pe = pefile.PE(fname)

    # make a addr: value dictionary for all imports
    imports = dict((x.address, x.name or (e.dll.lower(), x.ordinal))
                   for e in pe.DIRECTORY_ENTRY_IMPORT for x in e.imports)

    # apply config to the imports, if its not in the configuration, just
    # prepend the api with an underscore, the way gcc likes it.
    imports = dict(
        (k, config.apis[v] if v in config.apis else config.Api('_' + v))
        for k, v in imports.items())

    # dictionary with addr: value where addr is the address of the
    # `jmp dword [thunk address]' and value the name of this import.
    iat_label = {}

    # a set of all relocations
    relocs = set([(pe.OPTIONAL_HEADER.ImageBase + y.rva)
                  for x in pe.DIRECTORY_ENTRY_BASERELOC for y in x.entries])

    # a list of addresses that were used.
    addresses = []

    # a list of all m128 values we use
    m128s = []

    # a list of all dword values we use
    m32s = []

    instructions = pyasm2.block()

    # walk each section, find those that are executable and disassemble those
    for section in filter(lambda x: x.IMAGE_SCN_MEM_EXECUTE, pe.sections):
        g = distorm3.DecomposeGenerator(
            pe.OPTIONAL_HEADER.ImageBase + section.VirtualAddress,
            section.get_data(), distorm3.Decode32Bits)
        for instr in g:
            # useless instruction?
            if str(instr) in ('NOP', 'ADD [EAX], AL', 'LEA ESI, [ESI]',
                              'INT 3') or str(instr)[:2] == 'DB':
                continue

            # a jump to one of the imports?
            #if instr.mnemonic == 'JMP' and instr.operands[0].type == \
            #        distorm3.OPERAND_ABSOLUTE_ADDRESS and \
            #        instr.operands[0].disp in imports:
            #    iat_label[instr.address] = imports[instr.operands[0].disp]
            #    continue

            # quite hackery, but when the jumps with thunk address have been
            # processed, we can be fairly sure that there will be no (legit)
            # code anymore.
            #if len(iat_label):
            #    break

            #print str(instr)

            #print str(instr)

            # convert the instruction from distorm3 format to pyasm2 format.
            instr = distorm3_to_pyasm2(instr)

            # we create the block already here, otherwise our `labelnr' is
            # not defined.
            #block = pyasm2.block(pyasm2.Label('%08x' % instr.address), instr)
            offset_flat = None
            addr = instr.address

            # now we check if this instruction has a relocation inside it
            # not a very efficient way, but oke.
            reloc = instr.length > 4 and relocs.intersection(
                range(instr.address, instr.address + instr.length - 3))
            if reloc:
                # make an immediate with `addr' set to True
                enable_addr = lambda x: Immediate(int(x), addr=True)

                # TODO support for two relocations in one instruction
                # (displacement *and* immediate)
                reloc = reloc.pop()
                # there is only one operand, that's easy
                if not instr.op2:
                    #sys.stderr.write('reloc in op1 %s??\n' % instr.op1)
                    if isinstance(instr.op1, pyasm2.MemoryAddress):
                        # special occassion, this memory addres is an import
                        if instr.op1.reg1 is None and \
                                instr.op1.reg2 is None and \
                                int(instr.op1.disp) in imports:
                            instr.op1 = imports[int(instr.op1.disp)]
                        else:
                            addresses.append(int(instr.op1.disp))
                            # change the displacement to a label
                            #instr.op1 = str(instr.op1).replace('0x',
                            #    '__lbl_00')
                            instr.op1 = enable_addr(instr.op1)
                    elif isinstance(instr.op1, pyasm2.Immediate):
                        addresses.append(int(instr.op1))
                        offset_flat = int(instr.op1)
                        #instr.op1 = str(instr.op1).replace('0x',
                        #    'offset flat:__lbl_00')
                # if the second operand is an immediate and the relocation is
                # in the last four bytes of the instruction, then this
                # immediate is the reloc. Otherwise, if the second operand is
                # a memory address, then it's the displacement.
                elif isinstance(instr.op2, pyasm2.Immediate) and reloc == \
                        instr.address + instr.length - 4:
                    # keep this address
                    addresses.append(int(instr.op2))
                    # make a label from this address
                    # TODO: fix this horrible hack
                    offset_flat = int(instr.op2)
                    #instr.op2 = pyasm2.Label('offset flat:__lbl_%08x' %
                    #    int(instr.op2), prepend=False)
                elif isinstance(instr.op2, pyasm2.MemoryAddress) and \
                        reloc == instr.address + instr.length - 4:
                    addresses.append(int(instr.op2.disp))
                    # change the displacement to a label
                    instr.op2 = enable_addr(instr.op2)
                    #instr.op2 = str(instr.op2).replace('0x', '__lbl_00')
                    #sys.stderr.write('reloc in op2 memaddr %s\n' %
                    #    str(instr.op2))
                # the relocation is not inside the second operand, it must be
                # inside the first operand after all.
                elif isinstance(instr.op1, pyasm2.MemoryAddress):
                    addresses.append(int(instr.op1.disp))
                    instr.op1 = enable_addr(instr.op1)
                    #instr.op1 = str(instr.op1).replace('0x', '__lbl_00')
                    #sys.stderr.write('reloc in op1 memaddr %s\n' %
                    #    str(instr.op1))
                elif isinstance(instr.op1, pyasm2.Immediate):
                    addresses.append(int(instr.op1))
                    instr.op1 = enable_addr(instr.op1)
                    #instr.op1 = '__lbl_%08x' % int(instr.op1)
                    #sys.stderr.write('reloc in op1 imm %s\n' % instr.op1)
                else:
                    sys.stderr.write('Invalid Relocation!\n')

            instr = translate.Translater(instr, m128s, m32s).translate()
            if offset_flat:
                encode_offset_flat = lambda x: str(x).replace(
                    '0x', 'offset flat:__lbl_') if isinstance(
                        x, (int, long, pyasm2.imm
                            )) and int(x) == offset_flat or isinstance(
                                x, pyasm2.mem) and x.disp == offset_flat else x

                if isinstance(instr, pyasm2.block):
                    for x in instr.instructions:
                        x.op1 = encode_offset_flat(x.op1)
                        x.op2 = encode_offset_flat(x.op2)
                else:
                    x.op1 = encode_offset_flat(x.op1)
                    x.op2 = encode_offset_flat(x.op2)

            instructions += pyasm2.block(pyasm2.Label('%08x' % addr), instr)

        # remove any addresses that are from within the current section
        newlist = addresses[:]
        for i in xrange(len(addresses)):
            if addresses[i] >= pe.OPTIONAL_HEADER.ImageBase + \
                    section.VirtualAddress and addresses[i] < \
                    pe.OPTIONAL_HEADER.ImageBase + section.VirtualAddress + \
                    len(section.get_data()):
                newlist[i] = None
        addresses = filter(lambda x: x is not None, newlist)

    # walk over each instruction, if it has references, we update them
    for instr in instructions.instructions:
        # we can skip labels
        if isinstance(instr, pyasm2.Label):
            continue

        # check for references to imports
        if isinstance(instr, pyasm2.RelativeJump):
            # not very good, but for now (instead of checking relocs) we check
            # if the index is in the iat tabel..
            if int(instr.lbl.index, 16) in iat_label:
                instr.lbl.index = iat_label[int(instr.lbl.index, 16)]
                instr.lbl.prepend = False
            continue

    program = ['.file "ssexy.c"', '.intel_syntax noprefix']

    # we walk over each section, if a reference to this section has been found
    # then we will dump the entire section as bytecode.. with matching labels
    for section in pe.sections:
        base = pe.OPTIONAL_HEADER.ImageBase + section.VirtualAddress
        data = section.get_data()
        addr = set(range(base, base + len(data))).intersection(addresses)
        if addr:
            # create a header for this section
            program.append('.section %s,"dr"' % section.Name.strip('\x00'))

            # for now we do it the easy way.. one line and label per byte, lol
            for addr in xrange(len(data)):
                program.append('__lbl_%08x: .byte 0x%02x' %
                               (base + addr, ord(data[addr])))

            # empty line..
            program.append('')
        # if there is memory left
        for left in xrange(section.Misc_VirtualSize - len(data)):
            program.append(
                '.lcomm __lbl_%08x, 1, 32' %
                (pe.OPTIONAL_HEADER.ImageBase + section.VirtualAddress + left))

    # now we define all xmm's etc we gathered
    program.append('.align 4')
    program += m32s
    program.append('.align 16')
    program += m128s

    # time to define 'main'
    program.append('.globl _main')

    OEP = pe.OPTIONAL_HEADER.ImageBase + pe.OPTIONAL_HEADER.AddressOfEntryPoint

    # append each instruction
    for instr in instructions.instructions:
        # if this is an label, we want a colon as postfix
        if isinstance(instr, pyasm2.Label):
            program.append(str(instr) + ':')

            # if OEP is at this address, we will also add the `_main' label
            if str(instr) == '__lbl_%08x' % OEP:
                program.append('_main:')

                # we have to initialize the stack register, so..
                # for now we assume esp gpr is stored as first gpr in xmm7
                program.append('movd xmm7, esp')
        else:
            # TODO: fix this terrible hack as well
            program.append(
                str(instr).replace('byte', 'byte ptr').replace(
                    'word', 'word ptr').replace('retn', 'ret').replace(
                        '__lbl_00400000', '0x400000').replace('oword ptr', ''))

    print '\n'.join(program)
Exemplo n.º 16
0
def ssexy_linux(fname, *eips):
    import elf32
    from construct import Struct, ULInt32, ULInt16, ULInt8, Array, CString
    from construct import OptionalGreedyRange

    # assume low-endian binary
    elf32_rel = Struct('elf32_rel', ULInt32('r_offset'), ULInt32('r_info'))
    ELF32_R_SYM = lambda x: x.r_info >> 8
    ELF32_R_TYPE = lambda x: x.r_info & 0xff
    R_386_PC32 = 2

    elf32_sym = Struct('elf32_sym', ULInt32('st_name'), ULInt32('st_value'),
                       ULInt32('st_size'), ULInt8('st_info'),
                       ULInt8('st_other'), ULInt16('st_shndx'))

    elf = elf32.elf32_file.parse_stream(file(fname, 'rb'))

    # retrieve section by name
    elf32_section = lambda elf, name: [
        x for x in elf.sections if x.name == name
    ][0]

    # for now we assume that all code is in the .text section
    code_section = [x for x in elf.sections if x.name == '.text']
    if not len(code_section):
        raise Exception('your binary doesn\'t have a .text section..')

    relocs = [x.data.value for x in elf.sections if x.name == '.rel.dyn']
    if not len(relocs):
        raise Exception('no relocs available, compile with -pie')

    # read all relocations
    relocs = Array(len(relocs[0]) / elf32_rel.sizeof(),
                   elf32_rel).parse(relocs[0])
    # now get the offsets of the relocations
    relocs = set([x.r_offset for x in relocs])

    imports = {}

    # a list of addresses that were used.
    addresses = []

    # a list of all m128 values we use
    m128s = []

    # a list of all dword values we use
    m32s = []

    instructions = pyasm2.block()

    # get string at offset
    dynstr = lambda x: CString(None).parse(
        elf32_section(elf, '.dynstr').data.value[x:])

    # read the symbol table
    imports = OptionalGreedyRange(elf32_sym).parse(
        elf32_section(elf, '.dynsym').data.value)

    # resolve relocations
    section = elf32_section(elf, '.rel.dyn')
    relocates = {}
    for x in xrange(0, section.size, elf32_rel.sizeof()):
        x = elf32_rel.parse(section.data.value[x:x + elf32_rel.sizeof()])
        # relocation to fixup addresses to imports
        if ELF32_R_TYPE(x) == R_386_PC32:
            relocates[x.r_offset] = dynstr(imports[ELF32_R_SYM(x)].st_name)

    # walk each section, find those that are executable and disassemble those
    section = elf32_section(elf, '.text')
    g = distorm3.DecomposeGenerator(section.addr, section.data.value,
                                    distorm3.Decode32Bits)
    for instr in g:
        # useless instruction?
        if str(instr) in ('NOP', 'ADD [EAX], AL', 'LEA ESI, [ESI]',
                          'INT 3') or str(instr)[:2] == 'DB':
            continue

        # a jump to one of the imports?
        #if instr.mnemonic == 'JMP' and instr.operands[0].type == \
        #        distorm3.OPERAND_ABSOLUTE_ADDRESS and \
        #        instr.operands[0].disp in imports:
        #    iat_label[instr.address] = imports[instr.operands[0].disp]
        #    continue

        # quite hackery, but when the jumps with thunk address have been
        # processed, we can be fairly sure that there will be no (legit)
        # code anymore.
        #if len(iat_label):
        #    break

        #print str(instr)

        #print str(instr)

        # convert the instruction from distorm3 format to pyasm2 format.
        instr = distorm3_to_pyasm2(instr)

        # we create the block already here, otherwise our `labelnr' is
        # not defined.
        #block = pyasm2.block(pyasm2.Label('%08x' % instr.address), instr)
        offset_flat = None
        addr = instr.address

        # now we check if this instruction has a relocation inside it
        # not a very efficient way, but oke.
        reloc = instr.length > 4 and relocs.intersection(
            range(instr.address, instr.address + instr.length - 3))
        if reloc:
            # make an immediate with `addr' set to True
            enable_addr = lambda x: Immediate(int(x), addr=True)

            # TODO support for two relocations in one instruction
            # (displacement *and* immediate)
            reloc = reloc.pop()
            if not hasattr(instr, 'op1'):
                instr.op1, instr.op2 = None, None
            # there is only one operand, that's easy
            if not instr.op2:
                #sys.stderr.write('reloc in op1 %s??\n' % instr.op1)
                if isinstance(instr.op1, pyasm2.MemoryAddress):
                    # special occassion, this memory addres is an import
                    if instr.op1.reg1 is None and \
                            instr.op1.reg2 is None and \
                            int(instr.op1.disp) in imports:
                        instr.op1 = imports[int(instr.op1.disp)]
                    else:
                        addresses.append(int(instr.op1.disp))
                        # change the displacement to a label
                        #instr.op1 = str(instr.op1).replace('0x',
                        #    '__lbl_00')
                        instr.op1 = enable_addr(instr.op1)
                elif isinstance(instr.op1, pyasm2.Immediate):
                    addresses.append(int(instr.op1))
                    offset_flat = int(instr.op1)
                    #instr.op1 = str(instr.op1).replace('0x',
                    #    'offset flat:__lbl_00')
            # if the second operand is an immediate and the relocation is
            # in the last four bytes of the instruction, then this
            # immediate is the reloc. Otherwise, if the second operand is
            # a memory address, then it's the displacement.
            elif isinstance(instr.op2, pyasm2.Immediate) and reloc == \
                    instr.address + instr.length - 4:
                # keep this address
                addresses.append(int(instr.op2))
                # make a label from this address
                # TODO: fix this horrible hack
                offset_flat = int(instr.op2)
                #instr.op2 = pyasm2.Label('offset flat:__lbl_%08x' %
                #    int(instr.op2), prepend=False)
            elif isinstance(instr.op2, pyasm2.MemoryAddress) and \
                    reloc == instr.address + instr.length - 4:
                addresses.append(int(instr.op2.disp))
                # change the displacement to a label
                instr.op2 = enable_addr(instr.op2)
                #instr.op2 = str(instr.op2).replace('0x', '__lbl_00')
                #sys.stderr.write('reloc in op2 memaddr %s\n' %
                #    str(instr.op2))
            # the relocation is not inside the second operand, it must be
            # inside the first operand after all.
            elif isinstance(instr.op1, pyasm2.MemoryAddress):
                addresses.append(int(instr.op1.disp))
                instr.op1 = enable_addr(instr.op1)
                #instr.op1 = str(instr.op1).replace('0x', '__lbl_00')
                #sys.stderr.write('reloc in op1 memaddr %s\n' %
                #    str(instr.op1))
            elif isinstance(instr.op1, pyasm2.Immediate):
                addresses.append(int(instr.op1))
                instr.op1 = enable_addr(instr.op1)
                #instr.op1 = '__lbl_%08x' % int(instr.op1)
                #sys.stderr.write('reloc in op1 imm %s\n' % instr.op1)
            else:
                sys.stderr.write('Invalid Relocation!\n')

        #print instr
        m32len = len(m32s)
        instr = translate.Translater(instr, m128s, m32s).translate()
        if offset_flat:
            encode_offset_flat = lambda x: str(x).replace(
                '0x', 'offset flat:__lbl_') if isinstance(
                    x, (int, long, pyasm2.imm
                        )) and int(x) == offset_flat or isinstance(
                            x, pyasm2.mem) and x.disp == offset_flat else x

            if isinstance(instr, pyasm2.block):
                for x in instr.instructions:
                    x.op1 = encode_offset_flat(x.op1)
                    x.op2 = encode_offset_flat(x.op2)
            else:
                x.op1 = encode_offset_flat(x.op1)
                x.op2 = encode_offset_flat(x.op2)

            # update stuff
            m32s = m32s[:m32len] + [
                x.replace('0x%08x' % offset_flat,
                          'offset flat:__lbl_%08x' % offset_flat)
                for x in m32s[m32len:]
            ]

        instructions += pyasm2.block(pyasm2.Label('%08x' % addr), instr)

    # remove any addresses that are from within the current section
    newlist = addresses[:]
    for i in xrange(len(addresses)):
        if addresses[i] >= code_section[0].addr and addresses[i] < \
                code_section[0].addr + code_section[0].size:
            newlist[i] = None
    addresses = filter(lambda x: x is not None, newlist)

    # walk over each instruction, if it has references, we update them
    for instr in instructions.instructions:
        # we can skip labels
        if isinstance(instr, pyasm2.Label):
            continue

        # check for references to imports
        if isinstance(instr, pyasm2.RelativeJump):
            # not very good, but for now (instead of checking relocs) we check
            # if the index is in the iat tabel..
            #if int(instr.lbl.index, 16) in iat_label:
            #instr.lbl.index = iat_label[int(instr.lbl.index, 16)]
            #instr.lbl.prepend = False
            continue

    program = ['.file "ssexy.c"', '.intel_syntax noprefix']

    # we walk over each section, if a reference to this section has been found
    # then we will dump the entire section as bytecode.. with matching labels
    for section in elf.sections:
        base = section.addr
        data = section.data.value
        addr = set(range(base, base + section.size)).intersection(addresses)
        if addr:
            # create a header for this section
            program.append('.section %s' % section.name)

            # for now we do it the easy way.. one line and label per byte, lol
            for addr in xrange(section.size):
                program.append('__lbl_%08x: .byte 0x%02x' %
                               (base + addr, ord(data[addr])))

            # empty line..
            program.append('')

    # now we define all xmm's etc we gathered
    program.append('.align 4')
    program += m32s
    program.append('.align 16')
    program += m128s

    # time to define 'main'
    program.append('.text')
    program.append('.globl Main')
    program.append('.type Main, @function')

    OEP = elf.entry

    # f****d up shit
    relocates = dict(
        ('jmp __lbl_%08x' % k, 'jmp ' + v) for k, v in relocates.items())

    eips = ['__lbl_%08x' % x for x in eips]

    # append each instruction
    for instr in instructions.instructions:
        # if this is an label, we want a colon as postfix
        if isinstance(instr, pyasm2.Label):
            program.append(str(instr) + ':')

            # if OEP is at this address, we will also add the `_main' label
            if str(instr) == '__lbl_%08x' % OEP:
                program.append('Main:')

                # we have to initialize the stack register, so..
                # for now we assume esp gpr is stored as first gpr in xmm7
                program.append('movd xmm7, esp')

            # if the label is in the list of addresses to which we have to add
            # an "movd xmm7, esp" instruction, then add it (e.g. callback
            # function for pthread_create)
            if str(instr) in eips:
                program.append('movd xmm7, esp')
        else:
            # TODO: fix this terrible hack as well
            program.append(
                str(instr).replace('byte', 'byte ptr').replace(
                    'word', 'word ptr').replace('retn', 'ret').replace(
                        '__lbl_00400000', '0x400000').replace('oword ptr', ''))
            if program[-1] in relocates:
                program[-1] = relocates[program[-1]]

    print '\n'.join(program)