'Search for ASM instructions in memory
Args:
- start: start address (Int)
- end: end address (Int)
- asmcode: assembly instruction (String)
+ multiple instructions are separated by ";"
+ wildcard ? supported, will be replaced by registers or multi-bytes
Returns:
- list of (address(Int), hexbyte(String))'

@memoized
def search_asm(self, start, end, asmcode, rop=0):

    wildcard = asmcode.count('?')
    magic_bytes = ['0x00', '0xff', '0xdead', '0xdeadbeef', '0xdeadbeefdeadbeef']
    ops = [x for x in asmcode.split(';') if x]
    def buildcode(code='', pos=0, depth=0):
        if ((depth == wildcard) and (pos == len(ops))):
            (yield code)
            return
        c = ops[pos].count('?')
        if (c > 2):
            return
        elif (c == 0):
            asm = self.assemble(ops[pos])
            if asm:
                for code in buildcode((code + asm), (pos + 1), depth):
                    (yield code)
        else:
            save = ops[pos]
            for regs in REGISTERS.values():
                for reg in regs:
                    ops[pos] = save.replace('?', reg, 1)
                    for asmcode_reg in buildcode(code, pos, (depth + 1)):
                        (yield asmcode_reg)
            for byte in magic_bytes:
                ops[pos] = save.replace('?', byte, 1)
                for asmcode_mem in buildcode(code, pos, (depth + 1)):
                    (yield asmcode_mem)
            ops[pos] = save
    searches = []
    def decode_hex_escape(str_):
        'Decode    string    as    hex    and    escape    for    regex'
        return re.escape(codecs.decode(str_, 'hex'))
    for machine_code in buildcode():
        search = re.escape(machine_code)
        search = search.replace(decode_hex_escape('dead'), '..').replace(decode_hex_escape('beef'), '..').replace(decode_hex_escape('00'), '.').replace(decode_hex_escape('ff'), '.')
        if (rop and ('ret' not in asmcode)):
            search += '.{0,24}\\xc3'
        searches.append(search)
    if (not searches):
        warning_msg(("invalid    asmcode:    '%s'" % asmcode))
        return []
    search = (('(?=(' + '|'.join(searches)) + '))')
    candidates = self.searchmem(start, end, search)
    if rop:
        result = {}
        for (a, v) in candidates:
            gadget = self._verify_rop_gadget(a, ((a + (len(v) // 2)) - 1))
            if (gadget != []):
                blen = ((gadget[(-1)][0] - gadget[0][0]) + 1)
                bytes = v[:(2 * blen)]
                asmcode_rs = ';    '.join([c for (_, c) in gadget])
                if (re.search(re.escape(asmcode).replace('\\    ', '.*').replace('\\?', '.*'), asmcode_rs) and (a not in result)):
                    result[a] = (bytes, asmcode_rs)
        result = list(result.items())
    else:
        result = []
        for (a, v) in candidates:
            asmcode = self.execute_redirect(('disassemble    0x%x,    0x%x' % (a, (a + (len(v) // 2)))))
            if asmcode:
                asmcode = '\n'.join(asmcode.splitlines()[1:(-1)])
                matches = re.findall('.*:([^\n]*)', asmcode)
                result += [(a, (v, ';'.join(matches).strip()))]
    return result
