4.3 x64dbg 搜索内存可利用指令

本文涉及的产品
公网NAT网关,每月750个小时 15CU
简介: 发现漏洞的第一步则是需要寻找到可利用的反汇编指令片段,在某些时候远程缓冲区溢出需要通过类似于`jmp esp`等特定的反汇编指令实现跳转功能,并以此来执行布置好的`ShellCode`恶意代码片段,`LyScript`插件则可以很好的完成对当前进程内存中特定函数的检索工作。在远程缓冲区溢出攻击中,攻击者也可以利用汇编指令`jmp esp`来实现对攻击代码的执行。该指令允许攻击者跳转到堆栈中的任意位置,并从那里执行恶意代码。

发现漏洞的第一步则是需要寻找到可利用的反汇编指令片段,在某些时候远程缓冲区溢出需要通过类似于jmp esp等特定的反汇编指令实现跳转功能,并以此来执行布置好的ShellCode恶意代码片段,LyScript插件则可以很好的完成对当前进程内存中特定函数的检索工作。

一般而言远程缓冲区溢出攻击通常利用的是一些具有缓冲区溢出漏洞的函数或是特定的汇编指令片段,如:

  • strcpy:该函数将一个字符串复制到另一个字符串缓冲区中,但不会检查缓冲区的大小,因此很容易导致缓冲区溢出。
  • gets:该函数将用户输入的数据读入字符串缓冲区中,但不会检查缓冲区的大小,因此很容易导致缓冲区溢出。
  • sprintf:该函数将一个字符串格式化到字符串缓冲区中,但不会检查缓冲区的大小,因此很容易导致缓冲区溢出。

在远程缓冲区溢出攻击中,攻击者也可以利用汇编指令jmp esp来实现对攻击代码的执行。该指令允许攻击者跳转到堆栈中的任意位置,并从那里执行恶意代码。

4.3.1 搜索可利用汇编指令集

在默认情况下,LyScript插件并不具备搜索连续指令的能力,虽然提供了get_disasm_code()系列的反汇编函数,但此类函数通常仅仅只能实现简单的反汇编功能,读者如果需要实现其他附加功能,含需要自行动手去实现,首先我们自行实现一个简单的汇编指令检索功能,用于寻找可利用的指令片段"pop esp","jmp esp","jmp eax","pop ecx"等指令集。

这段代码实现的机制可总结为如下步骤;

  • 1.调用connect函数来连接到要调试的程序,并使用get_local_baseget_local_size函数获取程序的内存范围。
  • 2.定义一个名为search_asm的列表,该列表包含要搜索的汇编指令。
  • 3.使用一个while循环来遍历内存范围中的每一个地址,并调用get_disasm_one_code函数获取该地址处的反汇编代码。
  • 4.使用另一个for循环来遍历search_asm列表中的每一个指令,并检查当前反汇编代码是否与列表中的指令匹配。如果匹配,则输出该地址和反汇编代码。

代码很容易被理解和实现,本质上仅仅只是提取所内存中所有的汇编指令集,并依次枚举对比是否符合列表中的条件,其最终实现代码如下所示;

from LyScript32 import MyDebug

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

    local_base_start = dbg.get_local_base()
    local_base_end = local_base_start + dbg.get_local_size()
    print("开始地址: {} --> 结束地址: {}".format(hex(local_base_start),hex(local_base_end)))

    search_asm = ["pop esp","jmp esp","jmp eax","pop ecx"]

    while local_base_start <= local_base_end:
        disasm = dbg.get_disasm_one_code(local_base_start)
        # print("地址: 0x{:08x} --> 反汇编: {}".format(local_base_start,disasm))

        # 寻找指令
        for index in range(0, len(search_asm)):
            if disasm == search_asm[index]:
                print("地址: {} --> 反汇编: {}".format(hex(local_base_start), disasm))

        # 递增计数器
        local_base_start = local_base_start + dbg.get_disasm_operand_size(local_base_start)

    dbg.close()

如上代码被运行后,则会输出当前进程内所有可被利用的指令片段,其输出效果图如下图所示;

4.3.2 搜索可利用机器码

机器码的搜索与汇编指令集的搜索方式基本保持一致,但庆幸的是搜索指令集可使用scan_memory_all()这个官方函数,该函数可用于扫描当前EIP所处位置,也就是当前EIP所在模块的所有符合条件的机器码,需要注意的是,在搜索具有漏洞函数时,通常我们会搜索进程内的完整模块,则此时应该先得到该模块的入口地址,并通过set_register()设置到该模块所在内存,然后再次对该内存区域进行搜索,代码中opcode用于指定一段机器码序列,此处读者可指定搜索多种机器码,并将搜索结果放入到该列表内进行存储。

这段代码的实现原理可总结为如下所示的步骤;

  • 定义一个名为opcode的列表,该列表包含要搜索的机器码。
  • 然后使用一个for循环来遍历每个模块,并调用get_all_module函数获取程序中的模块列表。对于每个模块,它将eip寄存器设置为该模块的入口点,然后调用scan_memory_all函数搜索该模块中是否存在要搜索的机器码。
  • 如果找到了指定的机器码,则输出模块名称、匹配个数以及机器码,并输出该机器码所在的地址。

根据上述流程可总结为如下所示的代码片段;

from LyScript32 import MyDebug
import time

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

    # 需要搜索的指令集片段
    opcode = ['ff 25','ff 55 fc','8b fe']

    # 循环搜索指令集内存地址
    for index,entry in zip(range(0,len(opcode)), dbg.get_all_module()):
        eip = entry.get("entry")
        base_name = entry.get("name")
        if eip != 0:
            dbg.set_register("eip",eip)
            search_address = dbg.scan_memory_all(opcode[index])

            if search_address != False:
                print("搜索模块: {} --> 匹配个数: {} --> 机器码: {}"
            .format(base_name,len(search_address),opcode[index]))
                # 输出地址
                for search_index in search_address:
                    print("[*] {}".format(hex(search_index)))

        time.sleep(0.3)
    dbg.close()

strcpy函数为例,读者只需要搜索特征['57 8b 7c 24 08 eb 6e','ff 55 fc','8b fe']即可定位到当前模块内所有调用该函数机器其他函数的内存地址。

运行后即可输出当前模块内所有被调用机器码的详细地址,输出效果如下图所示;

原文地址

https://www.lyshark.com/post/af00a46a.html

相关实践学习
每个IT人都想学的“Web应用上云经典架构”实战
基于阿里云,构建一个企业web应用上云经典架构,让IT从业者体验企业级架构的实战训练。
高可用应用架构
欢迎来到“高可用应用架构”课程,本课程是“弹性计算Clouder系列认证“中的阶段四课程。本课程重点向您阐述了云服务器ECS的高可用部署方案,包含了弹性公网IP和负载均衡的概念及操作,通过本课程的学习您将了解在平时工作中,如何利用负载均衡和多台云服务器组建高可用应用架构,并通过弹性公网IP的方式对外提供稳定的互联网接入,使得您的网站更加稳定的同时可以接受更多人访问,掌握在阿里云上构建企业级大流量网站场景的方法。 学习完本课程后,您将能够: 理解高可用架构的含义并掌握基本实现方法 理解弹性公网IP的概念、功能以及应用场景 理解负载均衡的概念、功能以及应用场景 掌握网站高并发时如何处理的基本思路 完成多台Web服务器的负载均衡,从而实现高可用、高并发流量架构
目录
相关文章
|
3月前
|
Linux
|
3月前
|
编译器 C++
理解内存序,指令重排与内存模型
理解内存序,指令重排与内存模型
44 0
|
4月前
|
存储 Java
百度搜索:蓝易云【Java语言之float、double内存存储方式】
由于使用IEEE 754标准进行存储,float和double类型可以表示非常大或非常小的浮点数,并且具有一定的精度。然而,由于浮点数的特性,它们在进行精确计算时可能会存在舍入误差。在编写Java程序时,需要注意使
59 0
|
6月前
|
存储 缓存
百度搜索:蓝易云 ,CPU、内存、缓存的关系详细解释!
总结起来,CPU、内存和缓存之间的关系可以概括为:CPU是计算机的处理器,内存是用于存储数据的设备,缓存则是位于CPU和内存之间的高速存储器,用于提高数据的读取速度。它们共同协作,以提供高效的计算机性能。
79 0
|
3月前
|
存储 程序员 数据处理
【汇编】mov和add指令、确定物理地址的方法、内存分段表示法
【汇编】mov和add指令、确定物理地址的方法、内存分段表示法
124 1
【汇编】mov和add指令、确定物理地址的方法、内存分段表示法
|
3月前
|
缓存 Linux
百度搜索:蓝易云【Linux系统中查看内存信息的方法有哪些?】
这些是在Linux系统中查看内存信息的常见方法。根据您的需求和具体环境,您可以选择适合您的方法来查看内存信息。
81 0
|
6月前
|
缓存 Linux
百度搜索:蓝易云【检查 Linux 系统内存使用量是否耗尽?这5个命令堪称绝了!详解!】
通过使用以上这五个命令,你可以全面了解Linux系统的内存使用情况,从而判断是否存在内存耗尽的问题。这些命令提供了不同层次和角度的内存信息,帮助你定位和解决与内存相关的性能问题。
91 0
|
8月前
|
缓存 安全 Java
volatile底层的实现原理:volatile关键字的作用、内存模型、JMM规范和CPU指令
volatile底层的实现原理:volatile关键字的作用、内存模型、JMM规范和CPU指令
122 0
|
9月前
持久内存指令(PMDK)简介
持久内存指令(PMDK)简介
158 0
|
11月前
|
存储 缓存 索引
通过地址和索引实现数组、CPU指令执行过程、内存概述及内存物理结构
通过地址和索引实现数组、CPU指令执行过程、内存概述及内存物理结构
64 0