关于python:LyScript-内存交换与差异对比

40次阅读

共计 7466 个字符,预计需要花费 19 分钟才能阅读完成。

LyScript 针对内存读写函数的封装性能并不多,只提供了内存读取和内存写入函数的封装,本篇文章将持续对 API 进行封装,实现一些在软件逆向剖析中十分实用的性能,例如内存替换,内存区域比照,磁盘与内存镜像比拟,特色码检索等性能。

  • 插件地址:https://github.com/lyshark/Ly…

内存区域替换: 实现被加载程序内特定一块内存区域的替换,该办法实现原理就是两个变量之间的替换,只是在替换时须要一一字节进行,调用 read_memory_byte() 函数实现起了很容易。

from LyScript32 import MyDebug

# 替换两个内存区域
def memory_xchage(dbg,memory_ptr_x,memory_ptr_y,bytes):
    ref = False
    for index in range(0,bytes):
        # 读取两个内存区域
        read_byte_x = dbg.read_memory_byte(memory_ptr_x + index)
        read_byte_y = dbg.read_memory_byte(memory_ptr_y + index)

        # 替换内存
        ref = dbg.write_memory_byte(memory_ptr_x + index,read_byte_y)
        ref = dbg.write_memory_byte(memory_ptr_y + index, read_byte_x)
    return ref

if __name__ == "__main__":
    dbg = MyDebug()
    dbg.connect()

    eip = dbg.get_register("eip")

    # 内存替换
    flag = memory_xchage(dbg, 6815744,6815776,4)
    print("内存替换状态: {}".format(flag))
    dbg.close()

PE 文件头节点替换后如下:

内存区域比照: 可用于比照该过程内存中的特定一块区域的差别,返回是列表中的字典模式,别离传入比照内存 x,y 以及须要比照的内存长度,此处倡议不要超过 1024 字节。

from LyScript32 import MyDebug

# 比照两个内存区域
def memory_cmp(dbg,memory_ptr_x,memory_ptr_y,bytes):
    cmp_memory = []
    for index in range(0,bytes):

        item = {"addr":0, "x": 0, "y": 0}

        # 读取两个内存区域
        read_byte_x = dbg.read_memory_byte(memory_ptr_x + index)
        read_byte_y = dbg.read_memory_byte(memory_ptr_y + index)

        if read_byte_x != read_byte_y:
            item["addr"] = memory_ptr_x + index
            item["x"] = read_byte_x
            item["y"] = read_byte_y
            cmp_memory.append(item)
    return cmp_memory

if __name__ == "__main__":
    dbg = MyDebug()
    dbg.connect()

    eip = dbg.get_register("eip")

    # 内存比照
    cmp_ref = memory_cmp(dbg, 6815744,6815776,4)
    for index in range(0,len(cmp_ref)):
        print("地址: 0x{:08X} -> X: 0x{:02x} -> y: 0x{:02x}".format(cmp_ref[index].get("addr"),cmp_ref[index].get("x"),cmp_ref[index].get("y")))

    dbg.close()

比照特定内存区域,返回差别字节地址:

内存与磁盘机器码比拟: 通过调用 read_memory_byte() 函数,或者 open() 关上文件,等就能够失去程序磁盘与内存中特定地位的机器码参数,而后通过对每一个列表中的字节进行比拟,就可失去特定地位下磁盘与内存中的数据是否统一的判断。

#coding: utf-8
import binascii,os,sys
from LyScript32 import MyDebug

# 失去程序的内存镜像中的机器码
def get_memory_hex_ascii(address,offset,len):
    count = 0
    ref_memory_list = []
    for index in range(offset,len):
        # 读出数据
        char = dbg.read_memory_byte(address + index)
        count = count + 1

        if count % 16 == 0:
            if (char) < 16:
                print("0" + hex((char))[2:])
                ref_memory_list.append("0" + hex((char))[2:])
            else:
                print(hex((char))[2:])
                ref_memory_list.append(hex((char))[2:])
        else:
            if (char) < 16:
                print("0" + hex((char))[2:] + "",end="")
                ref_memory_list.append("0" + hex((char))[2:])
            else:
                print(hex((char))[2:] + "",end="")
                ref_memory_list.append(hex((char))[2:])
    return ref_memory_list

# 读取程序中的磁盘镜像中的机器码
def get_file_hex_ascii(path,offset,len):
    count = 0
    ref_file_list = []

    with open(path, "rb") as fp:
        # file_size = os.path.getsize(path)
        fp.seek(offset)

        for item in range(offset,offset + len):
            char = fp.read(1)
            count = count + 1
            if count % 16 == 0:
                if ord(char) < 16:
                    print("0" + hex(ord(char))[2:])
                    ref_file_list.append("0" + hex(ord(char))[2:])
                else:
                    print(hex(ord(char))[2:])
                    ref_file_list.append(hex(ord(char))[2:])
            else:
                if ord(char) < 16:
                    print("0" + hex(ord(char))[2:] + "", end="")
                    ref_file_list.append("0" + hex(ord(char))[2:])
                else:
                    print(hex(ord(char))[2:] + "", end="")
                    ref_file_list.append(hex(ord(char))[2:])
    return ref_file_list

if __name__ == "__main__":
    dbg = MyDebug()

    connect_flag = dbg.connect()
    print("连贯状态: {}".format(connect_flag))

    module_base = dbg.get_base_from_address(dbg.get_local_base())
    print("模块基地址: {}".format(hex(module_base)))

    # 失去内存机器码
    memory_hex_byte = get_memory_hex_ascii(module_base,0,100)

    # 失去磁盘机器码
    file_hex_byte = get_file_hex_ascii("d://Win32Project1.exe",0,100)

    # 输入机器码
    print("\n 内存机器码:",memory_hex_byte)
    print("\n 磁盘机器码:",file_hex_byte)

    dbg.close()

读取后输入时会默认十六个字符一次换行,输入成果如下。

咱们持续减少磁盘与内存比照过程,而后就能实现对特定内存区域与磁盘区域字节码一致性的判断。

#coding: utf-8
import binascii,os,sys
from LyScript32 import MyDebug

# 失去程序的内存镜像中的机器码
def get_memory_hex_ascii(address,offset,len):
    count = 0
    ref_memory_list = []
    for index in range(offset,len):
        # 读出数据
        char = dbg.read_memory_byte(address + index)
        count = count + 1

        if count % 16 == 0:
            if (char) < 16:
                print("0" + hex((char))[2:])
                ref_memory_list.append("0" + hex((char))[2:])
            else:
                print(hex((char))[2:])
                ref_memory_list.append(hex((char))[2:])
        else:
            if (char) < 16:
                print("0" + hex((char))[2:] + "",end="")
                ref_memory_list.append("0" + hex((char))[2:])
            else:
                print(hex((char))[2:] + "",end="")
                ref_memory_list.append(hex((char))[2:])
    return ref_memory_list

# 读取程序中的磁盘镜像中的机器码
def get_file_hex_ascii(path,offset,len):
    count = 0
    ref_file_list = []

    with open(path, "rb") as fp:
        # file_size = os.path.getsize(path)
        fp.seek(offset)

        for item in range(offset,offset + len):
            char = fp.read(1)
            count = count + 1
            if count % 16 == 0:
                if ord(char) < 16:
                    print("0" + hex(ord(char))[2:])
                    ref_file_list.append("0" + hex(ord(char))[2:])
                else:
                    print(hex(ord(char))[2:])
                    ref_file_list.append(hex(ord(char))[2:])
            else:
                if ord(char) < 16:
                    print("0" + hex(ord(char))[2:] + "", end="")
                    ref_file_list.append("0" + hex(ord(char))[2:])
                else:
                    print(hex(ord(char))[2:] + "", end="")
                    ref_file_list.append(hex(ord(char))[2:])
    return ref_file_list

if __name__ == "__main__":
    dbg = MyDebug()

    connect_flag = dbg.connect()
    print("连贯状态: {}".format(connect_flag))

    module_base = dbg.get_base_from_address(dbg.get_local_base())
    print("模块基地址: {}".format(hex(module_base)))

    # 失去内存机器码
    memory_hex_byte = get_memory_hex_ascii(module_base,0,1024)

    # 失去磁盘机器码
    file_hex_byte = get_file_hex_ascii("d://Win32Project1.exe",0,1024)

    # 输入机器码
    for index in range(0,len(memory_hex_byte)):
        # 比拟磁盘与内存是否存在差别
        if memory_hex_byte[index] != file_hex_byte[index]:
            # 存在差别则输入
            print("\n 绝对地位: [{}] --> 磁盘字节: 0x{} --> 内存字节: 0x{}".
                  format(index,memory_hex_byte[index],file_hex_byte[index]))
    dbg.close()

代码运行后即可输入,存在差别的绝对地位:

内存 ASCII 码解析: 通过封装的 get_memory_hex_ascii 失去内存机器码,而后再应用如下过程实现输入该内存中的机器码所对应的 ASCII 码。

from LyScript32 import MyDebug
import os,sys

# 转为 ascii
def to_ascii(h):
    list_s = []
    for i in range(0, len(h), 2):
        list_s.append(chr(int(h[i:i+2], 16)))
    return ''.join(list_s)

# 转为 16 进制
def to_hex(s):
    list_h = []
    for c in s:
        list_h.append(hex(ord(c))[2:])
    return ''.join(list_h)

# 失去程序的内存镜像中的机器码
def get_memory_hex_ascii(address,offset,len):
    count = 0
    ref_memory_list = []
    for index in range(offset,len):
        # 读出数据
        char = dbg.read_memory_byte(address + index)
        count = count + 1

        if count % 16 == 0:
            if (char) < 16:
                ref_memory_list.append("0" + hex((char))[2:])
            else:
                ref_memory_list.append(hex((char))[2:])
        else:
            if (char) < 16:
                ref_memory_list.append("0" + hex((char))[2:])
            else:
                ref_memory_list.append(hex((char))[2:])
    return ref_memory_list


if __name__ == "__main__":
    dbg = MyDebug()
    dbg.connect()

    eip = dbg.get_register("eip")

    # 失去模块基地址
    module_base = dbg.get_base_from_address(dbg.get_local_base())

    # 失去指定区域内存机器码
    ref_memory_list = get_memory_hex_ascii(module_base,0,1024)

    # 解析 ascii 码
    break_count = 1
    for index in ref_memory_list:
        if break_count %32 == 0:
            print(to_ascii(hex(int(index, 16))[2:]))
        else:
            print(to_ascii(hex(int(index, 16))[2:]),end="")
        break_count = break_count + 1

    dbg.close()

输入成果如下,如果换成中文,那就是一个中文搜索引擎了。

内存特色码匹配: 通过二次封装 get_memory_hex_ascii() 实现扫描内存特色码性能,如果存在则返回 True 否则返回 False。

from LyScript32 import MyDebug
import os,sys

# 失去程序的内存镜像中的机器码
def get_memory_hex_ascii(address,offset,len):
    count = 0
    ref_memory_list = []
    for index in range(offset,len):
        # 读出数据
        char = dbg.read_memory_byte(address + index)
        count = count + 1

        if count % 16 == 0:
            if (char) < 16:
                ref_memory_list.append("0" + hex((char))[2:])
            else:
                ref_memory_list.append(hex((char))[2:])
        else:
            if (char) < 16:
                ref_memory_list.append("0" + hex((char))[2:])
            else:
                ref_memory_list.append(hex((char))[2:])
    return ref_memory_list


# 在指定区域内搜寻特定的机器码, 如果齐全匹配则返回
def search_hex_ascii(address,offset,len,hex_array):
    # 失去指定区域内存机器码
    ref_memory_list = get_memory_hex_ascii(address,offset,len)

    array = []

    # 循环输入字节
    for index in range(0,len + len(hex_array)):

        # 如果有则持续装
        if len(hex_array) != len(array):
            array.append(ref_memory_list[offset + index])

        else:
            for y in range(0,len(array)):
                if array[y] != ref_memory_list[offset + index + y]:
                    return False

        array.clear()
    return False

if __name__ == "__main__":
    dbg = MyDebug()
    dbg.connect()

    eip = dbg.get_register("eip")

    # 失去模块基地址
    module_base = dbg.get_base_from_address(dbg.get_local_base())
    
    re = search_hex_ascii(module_base,0,100,hex_array=["0x4d","0x5a"])
    
    dbg.close()

特色码扫描个别不须要本人写,本人写的麻烦,而且不反对通配符,能够间接调用咱们 API 中封装好的 scan_memory_one() 它能够反对 ?? 通配符含糊匹配,且效率要高许多。

正文完
 0