LyScript 中提供了多种内存特征扫描函数,每一种扫描函数用法各不相同,在使用扫描函数时应首先搞清楚他们之间的差异,如下将分别详细介绍每一种内存扫描函数是如何灵活运用的,最后将实现一个简易版内存查壳脚本,可快速定位目标程序加了什么壳。
插件地址:https://github.com/lyshark/LyScript
先来了解第一个函数scan_memory_all()
的特点,该函数用来扫描当前进程内EIP所指向位置处整个内存段中符合条件的特征,如果找到了则返回一个列表,如果没有找到则返回False,该函数与scan_memory_one()
函数原理是一致的,唯一的不同是all以列表形式返回所有匹配到的行,one则只返回匹配到的第一条记录,这两个函数都支持??
模糊匹配。
如果载入一个程序,默认停留在系统领空,则调用该函数你所能得到的特征记录只能是系统领空特定dll内的特征集。
例如扫描ntdll.dll
模块内的所有特征字段是55 8b ec 83 e4
的记录,代码是这样的。
from LyScript32 import MyDebugif __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()
运行效果如下:
有时我们需要指定扫描某个模块,例如扫描进程内的msvcr120.dll
模块,里面的特征值。
此时需要想得到该模块的入口地址,然后将EIP切换过去,此时在调用scan_memory_all()
来完成搜索,当然最好先备份原始EIP位置,这样扫描完以后可以直接切回去。
from LyScript32 import MyDebugif __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()
输出结果如下:
当然为了使扫描效率更高一些,新版插件中新增了scan_memory_any()
函数,该函数无需切换到模块入口处即可实现扫描特定模块内的特征,不过该函数只能返回找到的第一条记录,且需要传入扫描起始位置以及扫描长度,不过得到这些参数并不难。
from LyScript32 import MyDebugif __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()
扫描结果如下:
如上内存扫描方法如果可以搞明白,那么查壳这个功能就变得很简单了,市面上的查壳软件PEID等基本都是采用特征码定位的方式,所以我们想要实现查壳以及检测编译器特征可以采用特征码扫描法,如下代码即可实现查壳功能。
from LyScript32 import MyDebugdef scan (dbg, string ): local_module = dbg.get_all_module()[0 ] module_base = local_module.get("base" ) module_size = local_module.get("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加壳软件输出为
vs2013编译器特征输出