欢迎来到 嗅灵易学

零基础也能上手的脚本技术课,一对一答疑带你入门

[原创]Immunity Debugger内存搜素python脚本

[原创]Immunity Debugger内存搜素python脚本

近日使用Immunity Debugger工具调试程序,发现它的内存搜索方面不太好,不知道是不是我找错地方了。于是自己写了个用于内存搜索的脚本。核心功能是search_code_string函数,它在内存中搜索一段内存数据,实现了简单的模糊查询。
比如搜索:
FF00*0104EEAAeeaa  
其中*号表示 后面的02 和04是个范围的上下限,表示不确定数据的范围为[1,4]。于是FF 00 ** EE AA EE AA和FF 00 ** ** EE AA EE AA 、FF 00 ** ** ** ** EE AA EE AA 均能被搜索。
FF00-03AA
其中的-表示这个范围固定后面的03是个值,只能搜索 FF 00 -- -- -- AA
注意这个范围上下限和固定值必须是两位数,个位数就凑成两位数吧。而且数值是16机制的。也就是*1a2b 是可以的,表示范围[26, 43]
自己随便定义的。 * 和 -是可以自定义的。。通过RD_CHAR = "*"  FD_CHAR ="-" 两个变量定义。
search_code_Long、search_code_short、search_code_byte、search_data_str等函数都是转换一下,然后调用search_code_string函数 来搜索的
search_asmcode函数也支持简单的替换 R32表示32位的寄存器,R16表示16为寄存器,R8表示8为寄存器。注意搜索的汇编语句中,只能有两个 寄存器未知,比如mov R8, byte ptr ds:[R32+0x10]可以被搜索,但是mov R8, byte ptr ds:[R32+R32+10]就有错误了,不想搞那么复杂。
如果两未知寄存器均为32位,则分别以R32和R_32表示。(R8 R_8 和 R16 R_16 同理)
原理就是一顿替换。。。。
search_asmcode_infun函数需要提供函数地址,它在函数调用了search_asmcode函数。具体看脚本吧。
change_special函数是查找汇编代码中的16进制值 转换为带0x 比如fa-->0xfa
之所以这么做是因为op.getDisasm() 返回的 十六进制值没有带0x。在调用imm.assemble 时会出错。
代码中的变量命名命得不好,大家凑合着看吧。。不对。。。是 凑合着用吧。。。
Immunity Debugger可以用的资料太少了,但是很喜欢这个Debugger 因为可以用python。。


import struct

import math

import libanalyze

RD_CHAR = "*"

FD_CHAR ="-"

#get max end function

def func_max_end(imm, addr):

    fun = libanalyze.Function(imm, addr)

    end1 = fun.getFunctionEnd()

    if len(end1) == 0:

        return 0

    end_max = end1[0]

    for e in end1:

        if e>end_max:

            end_max = e

    return end_max            

#search asmcode in function

#["mov byte ptr ss:[R32+100], R8", 3,"mov byte ptr ss:[R32+101], R8"] R32 R_32 R16  R_16 R8 R_8

#ret []

def search_asmcode_infun(imm, fun_begin_addr, c_list):

    end_max = func_max_end(imm, fun_begin_addr)

    if end_max==0 :

        return []

    ret_addr = []

    space = -1

    begin_addr = fun_begin_addr

    imm.log("")

    imm.log("start to search asm !", highlight = 1)

    imm.log("-----------------------------------------------------")

    for c in c_list:

        if type(c)== type(1):

            space = c

        else:

            s_ret = search_asmcode(imm, begin_addr, end_max, c, space)

            if len(s_ret) !=0:

                begin_addr = s_ret[0]

                imm.log("get address at 0x%x" % begin_addr)

                ret_addr.append(begin_addr)

                space = -1

    imm.log("-----------------------------------------------------")

    return ret_addr

#"lea eax, dword ptr ds:[ecx+edx-FA]" -->  "lea eax, dword ptr ds:[ecx+edx-0xFA]"

def change_special(asm_code):

    def change_list_chrsp(st, chr_sp):

        st_tmp = st

        for chr_elt in chr_sp:

            l_flt = change_hex(st_tmp, chr_elt)

            st_tmp= l_flt

        return st_tmp

    def change_hex(st, chr_sp):

        l = st.split(chr_sp)

        xx = []

        for ii in l:

            try:

                xx.append("0x%x" %int(ii, 16))

            except (ValueError, TypeError):

                xx.append("%s" % ii)

        return chr_sp.join(xx)

    fit = asm_code.find("[")

    sec = asm_code.find("]")

    aft = ""

    if (fit!=-1) and (sec !=-1) and (sec>fit):

        ll = asm_code[fit+1: sec]

        aft += change_list_chrsp(ll, "+-*")

        asm_code = asm_code.replace(asm_code[fit+1: sec], aft)

    asm_code = change_list_chrsp(asm_code, ", ")

    if asm_code.startswith("0x"):

        asm_code = asm_code[2:]

    return asm_code

def search_asmcode(imm, start_addr, end_addr, asmcode, space = -1):

    imm.log("asmreg to search: %s  space: %d  addr: 0x%x" % (asmcode, space, start_addr), highlight = 1)

    register_32 = ["EAX", "EBX", "ECX", "EDX", "EBP", "ESI", "EDI", "ESP"]

    register_16 = ["AX", "BX", "CX", "DX", "BP", "SI", "DI", "SP"]

    register_8 = ["AH", "AL", "BH", "BL", "CL", "CH", "DL", "DH"]

    ret_list = []

    ret_list.append(asmcode)

    ret_list.extend([xx.replace("R32", r) for r in register_32 for xx in ret_list if (xx.find("R32")!= -1)])

    ret_list.extend([xx.replace("R_32", r) for r in register_32  for xx in ret_list if (xx.find("R_32")!= -1)])

    ret_list.extend([xx.replace("R16", r) for r in register_16  for xx in ret_list if (xx.find("R16")!= -1)])

    ret_list.extend([xx.replace("R_16", r) for r in register_16  for xx in ret_list if (xx.find("R_16")!= -1)])

    ret_list.extend([xx.replace("R_8", r) for r in register_8  for xx in ret_list if (xx.find("R_8")!= -1)])

    ret_list.extend([xx.replace("R8", r) for r in register_8  for xx in ret_list if (xx.find("R8")!= -1)])

    ret_list = [r for r in ret_list if ((r.find("R32")==-1) and (r.find("R_32")==-1) and (r.find("R16")==-1) \

                                        and (r.find("R_16")==-1) and (r.find("R8")==-1) and (r.find("R_8")==-1))]

    code = ""

    for r in ret_list :

        code += imm.assemble(change_special(r)) # get code list

    cnt = 0

    while True:

        op = imm.disasm(start_addr)

        start_addr = start_addr + op.getSize()

        new_asm = change_special(op.getDisasm())

        this_code = imm.assemble(new_asm)

        if (this_code in code) and (cnt<=space if space>0 else True):

            imm.log("hit addr 0x%x   asm:%s"%(op.getAddress(), op.getDisasm()), highlight = 1)

            return [op.getAddress(), op.getDisasm()]            

        if start_addr > end_addr:

            break

        cnt = cnt +1

    return []

#list[0x12345678, 0x12345678]

def search_code_Long(imm, begin, end, code_list, min, max):

    st = ""

    if (min<0) or (min>max):

        return []

    if type(code_list) != type([]):

        return []

    for i in range(len(code_list)-1):

        st += "%02X%02X%02X%02X"%(code_list[i]&0xff, (code_list[i]>>0x8)&0xff, (code_list[i]>>0x10)&0xff, (code_list[i]>>0x18)&0xff)

        st += "%s%02x%02x" % (RD_CHAR, min, max) if max>0 else ""

    last_num = code_list[len(code_list)-1]

    st += "%02X%02X%02X%02X"%(last_num&0xff, (last_num>>0x8)&0xff, (last_num>>0x10)&0xff, (last_num>>0x18)&0xff)

    return search_code_string(imm, begin, end, st)

#list[0x1234, 0x1234]    

def search_code_short(imm, begin, end, code_list, min, max):

    st = ""

    if (min<0) or (min>max):

        return []

    if type(code_list) != type([]):

        return []

    for i in range(len(code_list)-1):

        st += "%02X%02X"%(code_list[i]&0xff, (code_list[i]>>0x8)&0xff)

        st += "%s%02x%02x" % (RD_CHAR, min, max) if max>0 else ""

    last_num = code_list[len(code_list)-1]

    st += "%02X%02X"%(last_num&0xff, (last_num>>0x8)&0xff)

    return search_code_string(imm, begin, end, st)

#list[0x34, 0x34]

def search_code_byte(imm, begin, end, code_list, min, max):

    st = ""

    if (min<0) or (min>max):

        return []

    if type(code_list) != type([]):

        return []

    for i in range(len(code_list)-1):

        st += "%02X"%(code_list[i]&0xff)

        st += "%s%02x%02x" % (RD_CHAR, min, max) if max>0 else ""

    last_num = code_list[len(code_list)-1]

    st += "%02X"%(last_num&0xff)

    return search_code_string(imm, begin, end, st)

#str  "GUOJICHONGYUN" "\xff\xff\xff\xff"

def search_data_str(imm, begin, end, str_search, min, max):

    st = ""

    if (min<0) or (min>max):

        return []

    if type(str_search) != type(""):

        return []

    for i in range(len(str_search)-1):

        st += "%02X"%(ord(str_search[i]))

        st += "%s%02x%02x"%(RD_CHAR, min, max) if max>0 else ""

    st += "%02X"%(ord(str_search[len(str_search)-1]))

    return search_code_string(imm, begin, end, st)

#search code string

#ef00*0209EabA*0304eeaa  FF00-04AA 53f966*0000E000008ab70183C40899F7*00007C24

def search_code_string(imm, begin, end, code_str):

    st1 = code_str.upper()

    ret_error = 0

    ret = []

    imm.log("the code to search:%s"%st1, highlight = 1)

    start = 0

    x = 0

    for aa in st1:

        if (aa ==RD_CHAR) or (aa == FD_CHAR):

            break

        else:

            x += 1

    y = 0

    min_n = []

    max_n = []

    s1 = []

    s2 = []

    if x == len(st1):

        s1.append(st1)

    else:

        count_ = 0

        while True:

            count_ = 0

            if st1[x] == FD_CHAR:

                min_max_tmp = int(st1[x+1:x+3], 16)

                min_n.append(min_max_tmp*2)

                max_n.append(min_max_tmp*2)

                count_ = 3

            else:

                min_tmp = int(st1[x+1:x+3], 16)

                max_tmp = int(st1[x+3:x+5], 16)

                if (min_tmp>max_tmp) or (min_tmp<0):

                    return []

                min_n.append(min_tmp*2)

                max_n.append(max_tmp*2)

                count_ = 5

            if start != x:

                s1.append(st1[start:x])

            y = 0

            for aa in st1[x+count_:]:

                if (aa ==RD_CHAR) or (aa == FD_CHAR):

                    break

                else:

                    y += 1

            if y == len(st1[x+count_:]):

                s2.append(st1[x+count_:])

                break

            else:

                s2.append(st1[x+count_:y+x+count_])

                x = y + x + count_

                start = x

    #'''

    imm.log("min_n  %s " % min_n, highlight = 1)

    imm.log("max_n  %s " % max_n, highlight = 1)

    imm.log("s1     %s " % s1, highlight = 1)    

    imm.log("s2     %s " % s2, highlight = 1) #'''

    len1 = len(s1[0])

    mun1_str = ""

    for i in range(len1/2):

        x = ((int(s1[0][2*i])) if s1[0][2*i].isdigit() else (int(s1[0][2*i], 16)))*math.pow(16, 1)

        x += ((int(s1[0][2*i+1])) if s1[0][2*i+1].isdigit() else (int(s1[0][2*i+1], 16)))*math.pow(16, 0)

        mun1_str += struct.pack("B", x)

    first_ = imm.search(mun1_str)

    byte_num = 0

    for i in max_n:

        byte_num += i

    for si in s2:

        byte_num += len(si)

    for fx in first_:

        if (fx<begin) or (fx>end):

            continue

        buf = imm.readMemory(fx, byte_num)

        mem_read_str = ''.join(['%02X' % ord(x) for x in buf[0:]])

        imm.log("addr 0x%x  mem_read_str %s" %(fx, mem_read_str), highlight = 1)

        start = len(s1[0])

        i = 0

        flag = 0

        for s2_tmp in s2:

            y = mem_read_str[start:].find(s2_tmp)

            if y == -1:

                flag = 0

                break

            elif (y>=min_n[i]) and (y<=max_n[i]):

                flag += 1

                start = start + y + len(s2_tmp)

            else:

                break

            i = i +1

            #imm.log("flag %d len1 %d  i %d"%(flag, len1, i))

        #imm.log("flag %d len1%d"%(flag, len1))

        if flag == len(min_n):

            ret.append(fx)

    return ret

    

   
测试代码(以window xp的记事本程序为例):

import immlib

import libanalyze

from libhook import *

import z_search

import struct

imm = immlib.Debugger()

def main(agrs):

    #x = z_search.search_code_Long(imm, 0x01012000, 0x01022000, [0x03, 0x0a], 2, 9)

    #-->"03000000*02090a000000"

    #x = z_search.search_code_string(imm, 0x01012000, 0x01022000, "03000000-080a000000")

    #x = z_search.search_code_string(imm, 0x01012000, 0x01022000, "03000000-080a000000*02050a0b")

    #搜索是可以分为N段的

    #x = z_search.search_code_short(imm, 0x01012000, 0x01022000, [0x58, 0x025c], 02, 02) 

    #-->"5800*0202025c" == "5800-02025c"

    #x = z_search.search_code_byte(imm, 0x01012000, 0x01022000, [0x53, 0x63, 0x69, 0x43], 0,3)

    #-->53*000363*000369*000343

    #x = z_search.search_data_str(imm, 0x01012000, 0x01022000, "\x53\x63\x69\x43", 0,1)

    #-->-->53*000163*000169*000143

    #010127E3  |.  8D6C24 10     lea     ebp, dword ptr ss:[esp+10]   sub     esp, eax

    #x = z_search.search_asmcode_infun(imm, 0x010127c8, ["lea ebp, dword ptr ss:[esp+0x10]","sub  esp,eax"])

    #x = z_search.search_asmcode_infun(imm, 0x010127c8, ["lea ebp, dword ptr ss:[esp+0x10]", 6, "mov eax, dword ptr ss:[ebp-0x8]"])

    x = z_search.search_asmcode_infun(imm, 0x010127c8, ["lea R32, dword ptr ss:[R_32+0x10]", 6, "mov R32, dword ptr ss:[R_32-0x8]"])

    #6表示两条汇编指令间 间隔的指令数少于6

    imm.log("hit number:%d"%len(x))

    for x_t in x:

        imm.log("hit address:0x%08x"%x_t)

    return "sccuess"

#!z_search_test

上传的附件 z_search.rar

注意:上传附件及图片大小不得大于30M。

⚠️ 版权声明:
本博客所有内容(含教程、源码、工具)仅供个人技术学习与研究交流使用,严禁商用、倒卖、二次分发及非法用途。
未经作者书面授权,任何组织或个人不得转载、复制或用于其他平台,违者将追究相关责任。

0 0 0 举报
复制成功