LyScript 插件中默认提供了多种内存特征扫描函数,每一种扫描函数用法各不相同,在使用扫描函数时应首先搞清楚不同函数之间的差异,本章内容将分别详细介绍每一种内存扫描函数是如何灵活运用,并实现一种内存查壳脚本,可快速定位目标程序加了什么壳以及寻找被加壳程序的入口点。

计算机中的壳定义

加壳通常指对可执行文件或者动态链接库等二进制文件进行加密或压缩等处理,以使得这些文件难以被反汇编或破解。通常情况下,加壳会增加二进制文件的大小,并在程序运行时增加一定的开销。加壳技术通常被用于保护软件的知识产权和防止软件被盗版。通过加壳,软件开发者可以使得软件更难被破解和复制,从而保护自己的商业利益。

计算机中查壳的原理

软件查壳的实现原理可以分为静态分析和动态分析两种方式。静态分析是指在不运行被加壳程序的情况下,通过对程序的二进制代码进行解析,识别出程序是否被加壳,以及加壳的种类和方法。动态分析是指通过运行被加壳程序,并观察程序运行时的行为,识别程序是否被加壳,以及加壳的种类和方法。

静态分析的实现原理通常包括以下几个步骤:

  • 提取被分析程序的二进制代码;
  • 识别程序的文件格式,并解析文件头等元数据信息;
  • 根据文件格式,从程序代码中提取节区、导入表、导出表等重要信息;
  • 分析程序的代码段,并检查代码中是否存在加壳相关的特征,如代码的执行流程、加密算法等;
  • 根据分析结果,判断程序是否被加壳,以及加壳的种类和方法。

静态分析的优点是分析速度快,不需要运行程序,可以有效地识别出程序中的加壳。但是它也有一些缺点,例如无法识别动态加载的加壳、易受代码混淆和反调试等技术的影响。

动态分析的实现原理通常包括以下几个步骤:

  • 启动被分析程序,并在程序运行期间捕捉程序的行为;
  • 跟踪程序的执行流程,并分析程序的内存、寄存器、堆栈等状态信息;
  • 检查程序的内存中是否存在加壳相关的特征,如解密函数、加壳程序等;
  • 根据分析结果,判断程序是否被加壳,以及加壳的种类和方法。

动态分析的优点是可以识别动态加载的加壳,并且可以有效地避免代码混淆和反调试等技术的影响。但是它也有一些缺点,例如需要运行被分析程序,因此可能会影响程序的性能和稳定性,并且可能会被加壳程序的反调试技术所绕过。

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

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

例如在程序被载入后,其EIP指针默认会停留在ntdll.dll模块上,需要注意的是,函数scan_memory_one用于扫描并返回第一段符合条件的内存,函数scan_memory_all则用于扫描并输出当前所有符合条件的内存地址;

>>> from LyScript32 import MyDebug
>>>
>>> dbg = MyDebug()
>>> conn = dbg.connect()
>>>
>>> ref_one = dbg.scan_memory_one("55 8b ec")
>>> ref_one
1995793090
>>>
>>> ref_all = dbg.scan_memory_all("55 8b ec")
>>> ref_all
[1995793090, 1995793298, 1995793455, 1995793799, 1995794214]

而有时,我们需要指定扫描某个模块,例如扫描进程内的msvcr120.dll模块里面的特征,则此时读者可调用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,"55 8b ec ??")
if ref != False:
print("找到内存: {}".format(hex(ref)))
dbg.close()

运行如上所示的代码片段,则默认会扫描进程内第一个模块也就是主程序模块内的,特征55 8b ec ??指令集,当找到后会输出如下图所示的提示信息;

如上代码中的内存扫描方法如果能被读者理解,那么查壳这个功能就变得很简单了,市面上的查壳软件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()

当运行上述代码片段,则将会寻找特定指令集,如果找到则说明采用的是特定的加壳程序或特定编译器编译生成的,输出效果图如下所示;

通过运用scan_memory_one()函数,读者何以很容易的实现对特定内存区域的寻找,以32为代码为例,通过get_register函数获取到当前EIP的内存地址,并通过read_memory_word读入前四个字节的数据,当前四个字节的数据为0xBE60此时说明是UPX壳的开头,通过scan_memory_one("83 EC ?? E9")匹配特征码,当找到后顺势在此处set_breakpoint(patternAddr)下一个断点,程序通过不断地运行,最终即可定位到程序真正的入口地址;

from LyScript32 import MyDebug

if __name__ == "__main__":
# 初始化
dbg = MyDebug() # 连接到调试器
connect_flag = dbg.connect()
print("连接状态: {}".format(connect_flag)) # 检测套接字是否还在
ref = dbg.is_connect()
print("是否在连接: ", ref) is_64 = False # 判断是否时64位数
if is_64 == False:
currentIP = dbg.get_register("eip") if dbg.read_memory_word(currentIP) != int(0xBE60):
print("[-] 可能不是UPX")
dbg.close() patternAddr = dbg.scan_memory_one("83 EC ?? E9")
print("匹配到的地址: {}".format(hex(patternAddr))) dbg.set_breakpoint(patternAddr)
dbg.set_debug("Run")
dbg.set_debug("Wait")
dbg.delete_breakpoint(patternAddr) dbg.set_debug("StepOver")
dbg.set_debug("StepOver")
print("[+] 程序OEP = 0x{:x}".format(dbg.get_register("eip"))) else:
currentIP = dbg.get_register("rip") if dbg.read_memory_dword(currentIP) != int(0x55575653):
print("[-] 可能不是UPX")
dbg.close() patternAddr = dbg.scan_memory_one("48 83 EC ?? E9")
print("匹配到的地址: {}".format(hex(patternAddr))) dbg.set_breakpoint(patternAddr)
dbg.set_debug("Run")
dbg.set_debug("Wait")
dbg.delete_breakpoint(patternAddr) dbg.set_debug("StepOver")
dbg.set_debug("StepOver")
print("[+] 程序OEP = 0x{:x}".format(dbg.get_register("eip"))) dbg.close()

运行上述代码片段,则会看到如下图所示的输出效果,并以自动跳转到了程序的真正入口位置0x40153e,此时用户只需要脱壳转存即可;

4.6 x64dbg 内存扫描与查壳实现的更多相关文章

  1. LyScript 内存扫描与查壳实现

    LyScript 中提供了多种内存特征扫描函数,每一种扫描函数用法各不相同,在使用扫描函数时应首先搞清楚他们之间的差异,如下将分别详细介绍每一种内存扫描函数是如何灵活运用的,最后将实现一个简易版内存查 ...

  2. .net 查壳工具

    请问大神.NET查壳工具都有哪些? 已知的有DotNet Id    除了这个还有别的吗?脱MAXTOCODE发现是双壳.脱掉第一层还有一层,DotNet Id检测没壳了,但是反编译还是加密状态. 用 ...

  3. 标记下 'net 查壳/脱壳/加壳' 工具

    net查壳工具 DotNet Id v1.0.0.3 该net程序集被“MaxToCode”加壳了(也不能完全相信). 加壳工具就是列表中列出的了. de4Net.exe脱壳工具版本de4dot-v3 ...

  4. C/C++ 导入表与IAT内存修正

    本章教程中,使用的工具是上次制作的PE结构解析器,如果还不会使用请先看前一篇文章中对该工具的介绍,本章节内容主要复习导入表结构的基础知识点,并通过前面编写的一些小案例,实现对内存的转储与导入表的脱壳修 ...

  5. 病毒木马查杀实战第016篇:U盘病毒之逆向分析

    比对脱壳前后的程序 我们这次所要研究的是经过上次的脱壳操作之后,所获取的无壳病毒样本.其实我们这里可以先进行一下对比,看看有壳与无壳的反汇编代码的区别.首先用IDA Pro载入原始病毒样本: 图1 可 ...

  6. Web漏洞扫描工具(批量脱壳、反序列化、CMS)

    一.什么是Web漏洞扫描工具 即是指“扫描Web应用以查找安全漏洞(如跨站脚本,SQL注入,命令执行,目录遍历和不安全服务器配置)的自动化工具”,其中许多可能是由不安全或不正确的编码和设计.另一方面, ...

  7. [原创]K8_C段旁注工具6.0 新增SMB漏洞扫描

    工具: K8_C段旁注工具6.0_0510[K.8]编译: 自己查壳组织: K8搞基大队[K8team]作者: K8拉登哥哥博客: http://qqhack8.blog.163.com发布: 201 ...

  8. 手动脱WinUpack 壳实战

    作者:Fly2015 吾爱破解培训第一课选修作业第6个练习演示样例程序.不得不反复那句话,没见过这样的壳,该壳是压缩壳的一种,相对于压缩壳,加密壳的难度要大一些.特别是IAT表的修复问题上. 首先分别 ...

  9. 手动脱NsPacK壳实战

    作者:Fly2015 这里脱壳的程序是吾爱破解培训的作业2,相较于作业1略微要强一点,可是仅仅要掌握了脱壳的ESP定律,脱这个Nspack壳并不难.只是还是蛮有意思的. 1.使用查壳软件对加壳的程序进 ...

  10. 手脱ASProtect v1.23 RC1(有Stolen Code)之以壳解壳

    1.载入PEID ASProtect v1.23 RC1 2.载入OD,不勾选内存访问异常,其他异常全部勾选 > 01C06D00 push SoWorker.006DC001 ; //入口点 ...

随机推荐

  1. ViewGroup的TouchTarget设计思维

    TouchTarget需要创建的时候先看下池子里面有没有被回收上来的,如果没有可以利用的就给你创建一个新的,否则就从池子里面把头部的那个可以利用的给你,你把你的东西放进去就行了.回收的时候就是把你放在 ...

  2. 这样也行,在lambda表达式中优雅的处理checked exception

    目录 简介 lambda表达式中的checked exception lambda中的unchecked exception 对lambda的最终改造 总结 简介 最近发现很多小伙伴还不知道如何在la ...

  3. 用Abp实现找回密码和密码强制过期策略

    @ 目录 重置密码 找回密码 发送验证码 校验验证码 发送重置密码链接 创建接口 密码强制过期策略 改写接口 Vue网页端开发 重置密码页面 忘记密码控件 密码过期提示 项目地址 用户找回密码,确切地 ...

  4. C++ 基于Capstone实现反汇编器

    Capstone是一个反汇编框架,提供了一个简单.轻量级的API接口,可透明地处理大多数流行的指令体系,包括x86/x86-64.ARM及MIPS等.Capstone支持C/C++和Python,并且 ...

  5. 第3章. markdown语法

    常用语法 1. 文字格式 1.1 给文字添加引用 在文字的两侧,使用 ` 符号包裹起来 怒发冲冠,凭栏处,潇潇雨歇. 1.2 设置文字样式为斜体 在文字的两侧,使用 * 符号包裹起来 抬望眼,仰天长啸 ...

  6. Pillow + pytesseract + tesseract-ocr 破解简单的图形验证码

    前言: 我们在做WEB UI自动化测试时,会遇到一些图形验证码,今天就来简单介绍下,如何来识别简单的图形验证码. 一.安装 ◇ Pillow pip3 install Pillow ◇ pytesse ...

  7. LeetCode 654:最大二叉树

    先立个flag吧,坚持每日刷题的小目标,希望自己能坚持下来,如果有需要一起打卡的uu,可以一起监督哈,在菜鸡的路上慢慢变好 题目:最大二叉树 给定一个不重复的整数数组 nums . 最大二叉树 可以用 ...

  8. Kubernetes Gateway API 深入解读和落地指南

    背景 Kubernetes Gateway API 是 Kubernetes 1.18 版本引入的一种新的 API 规范,是 Kubernetes 官方正在开发的新的 API,Ingress 是 Ku ...

  9. Vite-WeGPT聊天AI实例|vue3+pinia仿ChatGPT聊天界面

    基于vue3.x+vite4+pinia2仿chatgpt聊天模拟实例Vue3-WeGPT. 基于Vite4.x+Vue3+Pinia2+VEPlus+Vue3-Markdown等技术实现仿ChatG ...

  10. vue3 + vite 多项目多模块打包

    vue3 + vite 多项目多模块打包 本示例基于vite-plugin-html插件,实现多个独立项目共存,共享组件和依赖,运行.打包互不干扰. npm create vite@latest 兼容 ...