5

LyScript 内存扫描与查壳实现 - lyshark

 2 years ago
source link: https://www.cnblogs.com/LyShark/p/16671876.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

LyScript 内存扫描与查壳实现

LyScript 中提供了多种内存特征扫描函数,每一种扫描函数用法各不相同,在使用扫描函数时应首先搞清楚他们之间的差异,如下将分别详细介绍每一种内存扫描函数是如何灵活运用的,最后将实现一个简易版内存查壳脚本,可快速定位目标程序加了什么壳。

先来了解第一个函数scan_memory_all()的特点,该函数用来扫描当前进程内EIP所指向位置处整个内存段中符合条件的特征,如果找到了则返回一个列表,如果没有找到则返回False,该函数与scan_memory_one()函数原理是一致的,唯一的不同是all以列表形式返回所有匹配到的行,one则只返回匹配到的第一条记录,这两个函数都支持??模糊匹配。

如果载入一个程序,默认停留在系统领空,则调用该函数你所能得到的特征记录只能是系统领空特定dll内的特征集。

1379525-20220909103044270-1201421190.png

例如扫描ntdll.dll模块内的所有特征字段是55 8b ec 83 e4的记录,代码是这样的。

from LyScript32 import MyDebug

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

    ref_one = dbg.scan_memory_one("55 8b ec 83 e4")
    print("扫描一行: {}".format(hex(ref_one)))

    ref_all = dbg.scan_memory_all("55 8b ec 83 e4")
    for index in range(0, len(ref_all)):
        print("记录: {} 地址: {}".format(index,hex(ref_all[index])))

    dbg.close()

运行效果如下:

1379525-20220909103129120-154967251.png

有时我们需要指定扫描某个模块,例如扫描进程内的msvcr120.dll模块,里面的特征值。

1379525-20220909103610916-599045117.png

此时需要想得到该模块的入口地址,然后将EIP切换过去,此时在调用scan_memory_all()来完成搜索,当然最好先备份原始EIP位置,这样扫描完以后可以直接切回去。

from LyScript32 import MyDebug

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

    # 得到所有模块
    local_module_base = dbg.get_all_module()

    for index in local_module_base:
        # 找到需要的模块
        if index.get("name") == "msvcr120.dll":
            entry = index.get("entry")
            print("扫描入口: {}".format(hex(entry)))
            # 切过去
            dbg.set_register("eip",entry)

            # 开始搜索特征
            scan_ref = dbg.scan_memory_all("5d c2 0c 00 55 8b ec")
            for x in scan_ref:
                print("扫描到: {}".format(hex(x)))
    dbg.close()

输出结果如下:

1379525-20220909104320721-242154489.png

当然为了使扫描效率更高一些,新版插件中新增了scan_memory_any()函数,该函数无需切换到模块入口处即可实现扫描特定模块内的特征,不过该函数只能返回找到的第一条记录,且需要传入扫描起始位置以及扫描长度,不过得到这些参数并不难。

from LyScript32 import MyDebug

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

    # 得到进程模块
    local_module = dbg.get_all_module()[0]

    # 得到模块参数
    module_base = local_module.get("base")
    module_size = local_module.get("size")
    print("基地址: {} 长度: {} 结束地址: {}".format(hex(module_base),hex(module_size),hex(module_base+module_size)))

    # 扫描内存
    ref = dbg.scan_memory_any(module_base,module_size,"51 5c a8 f8 4c 34 33")
    if ref != False:
        print("找到内存: {}".format(hex(ref)))
    dbg.close()

扫描结果如下:

1379525-20220909105854153-329823464.png

如上内存扫描方法如果可以搞明白,那么查壳这个功能就变得很简单了,市面上的查壳软件PEID等基本都是采用特征码定位的方式,所以我们想要实现查壳以及检测编译器特征可以采用特征码扫描法,如下代码即可实现查壳功能。

from LyScript32 import MyDebug

# 查壳功能
def scan(dbg, string):
    # 得到进程模块
    local_module = dbg.get_all_module()[0]

    # 得到模块参数
    module_base = local_module.get("base")
    module_size = local_module.get("size")
    # print("基地址: {} 长度: {} 结束地址: {}".format(hex(module_base),hex(module_size),hex(module_base+module_size)))

    # 扫描内存
    ref = dbg.scan_memory_any(module_base,module_size,string)
    if ref != False:
        return True
    return False

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

    # 存储特征码
    signs = [
        {"key": "Microsoft Visual C++ 2013", "value": "e8 ?? ?? ?? ?? e9 ?? ?? ?? ?? 55 8b ec"},
        {"key": "UPX 3.96w", "value": "60 be ?? ?? ?? ?? 8d be 00 90 ff ff 57"}
    ]

    for index in signs:
        check = scan(dbg, index.get("value"))
        if check == True:
            print("编译特征: {}".format(index.get("key")))

    dbg.close()

分别检测后输出结果如下:

upx加壳软件输出为

1379525-20220909111035007-1554143840.png

vs2013编译器特征输出

1379525-20220909111115216-1621868663.png

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK