翻译《The Old New Thing》- Stupid debugger tricks: Calling functions and methods

Stupid debugger tricks: Calling functions and methods - The Old New Thing (microsoft.com)icon-default.png?t=N7T8https://devblogs.microsoft.com/oldnewthing/20070427-00/?p=27083

Raymond Chen 2007年04月27日


一个比较笨的调试技巧:调用函数和方法

        在过去,如果你想在调试器中调用一个函数,你必须手动进行:保存寄存器,将参数推送到栈上(如果函数使用fastcallthiscall,则将参数放入寄存器),将ntdll!DbgBreakPoint函数的地址推送到栈上,将指令指针移动到你想要调用的函数的开始位置,然后按“g”键恢复执行。函数运行后返回到ntdll!DbgBreakPoint,调试器重新获得控制权,你可以查看结果。然后恢复寄存器(包括原始的指令指针)并继续调试。

        那一段只是快速回顾;我假设你已经知道了。

        现在,Windows符号调试引擎(ntsdcdbwindbg背后的调试引擎)可以自动化这个过程。

        假设你想调用这个函数:

int DoSomething(int i, int j);

         你可以让调试器做所有繁重的工作:

0:001> .call ABC!DoSomething(1,2)
线程已设置为调用,'g'将执行。
警告:这可能会产生严重的副作用,包括死锁和调试程序的损坏。
0:001> r
eax=7ffde000 ebx=00000001 ecx=00000001 edx=00000003 esi=00000004 edi=00000005
eip=10250132 esp=00a7ffbc ebp=00a7fff4 iopl=0         nv up ei pl zr na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=0038  gs=0000             efl=00000246
ABC!DoSomething:
10250132 55               push    ebp
0:001> dd esp
00a7ffbc  00a7ffc8 00000001 00000002 ccfdebcc

        注意,调试器巧妙地将参数推送到栈上,并为你设置了eip寄存器。你只需要按“g”,DoSomething函数就会运行。一旦它返回,调试器将恢复原始状态。

        这种技术甚至适用于C++方法:

// 假设我们知道0x00131320是一个IStream指针
0:001> .dvalloc 1000
从00a80000开始分配了1000字节
0:001> .call ABC!CAlphaStream::Read(0x00131320, 0xa80000, 0x1000, 0)
线程已设置为调用,'g'将执行。
警告:这可能会产生严重的副作用,包括死锁和调试程序的损坏。

        注意,当调用非静态C++方法时,你必须将“this”参数作为显式的第一个参数传递。调试器知道使用哪种调用约定,并将寄存器放置在正确的位置。在这种情况下,它知道CAlphaStream::Read使用stdcall调用约定,因此所有参数都已推送到栈上。

        那么那个.dvalloc命令是做什么的?这是另一个调试器辅助函数,它在被调试进程的地址空间中分配一些内存。在这里,我们用它来分配一个我们想要读取的缓冲区。

        但是,如果你想调用一个接口上的方法,而你没有实现源代码怎么办?例如,你想从一个外部组件传递给你的流中读取。嗯,你可以玩一个小把戏。你可以假装调用一个你有源代码的函数,该函数具有相同的函数签名,然后将eip寄存器移动到所需的入口点。

// 假设我们知道0x00131320是一个IStream指针
0:000>  dp 131320 l1
00131320  77f6b5e8 // vtable
0:000> dps 77f6b5e8 l4
77f6b5e8  77fbff0e SHLWAPI!CFileStream::QueryInterface
77f6b5ec  77fb34ed SHLWAPI!CAssocW2k::AddRef
77f6b5f0  77f6b670 SHLWAPI!CFileStream::Release
77f6b5f4  77f77474 SHLWAPI!CFileStream::Read
0:000> .call SHLWAPI!CFileStream::Read(0x00131320, 0xa80000, 0x1000, 0)^ 符号在'.call SHLWAPI!CFileStream::Read'中不是函数

        那个错误消息是调试器有点令人困惑的方式,意思是“我没有足够的信息来执行那个函数调用。”但没关系,因为我们有一个“足够接近”的函数,即CAlphaStream::Read

0:001> .call ABC!CAlphaStream::Read(0x00131320, 0xa80000, 0x1000, 0)
线程已设置为调用,'g'将执行。
警告:这可能会产生严重的副作用,包括死锁和调试程序的损坏。
0:000> r eip=SHLWAPI!CFileStream::Read
0:000> r
eax=00131320 ebx=0007d628 ecx=00130000 edx=0013239e esi=00000000 edi=00000003
eip=77f77474 esp=0007d384 ebp=0007d3b0 iopl=0         nv up ei pl zr na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
SHLWAPI!CFileStream::Read:
77f77474 8bff             mov     edi,edi

        哇哦!

        我们让ABC!CAlphaStream::Read为我们推送了所有参数,然后调用我们交换了那个函数,并将CFileStream::Read插入到它的位置。现在你可以按“g”来执行CFileStream::Read调用。

        这只是.call命令所能做的表面。将一些C++表达式求值等功能混合在一起,你就拥有了一个相当巧妙的“伪即时模式”表达式求值器。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/707285.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

大模型时代,交换机技术演变、性能分析、衡量指标

OSI协议及在高性能计算中向RDMA的过渡 协议是为计算机网络内的数据交换而建立的一组规则、标准或协议。在法律层面,OSI七层协议被视为国际标准。该协议于20世纪80年代引入,旨在通过其七层网络模型标准化计算机间通信,以满足开放网络的要求。…

Lazyboy品牌发布会“球幕气膜”

Lazyboy品牌发布会“球幕气膜”为品牌活动提供了一个独特、现代化、环保的展示空间。这座球幕气膜不仅为发布会提供了一个视觉震撼的场地,也为与会嘉宾带来了全新的体验。作为轻空间(江苏)膜科技有限公司(以下简称“轻空间”&…

C++ 数据结构算法 学习笔记(25) - 图及其企业级应用

C 数据结构算法 学习笔记(25) - 图及其企业级应用 图的故事导入 故事情节 Jack 自从买车后,交通出行方便了,心自然就野了!身边的各种朋友自然就多了起来! 有一天晚上,一个年轻漂亮的女同事生日,Jack 受邀…

可用在vue自动导入的插件unplugin-auto-import

在大多数vue3开发中,基本所有页面都会引用vue3 componsition api,如下代码 想这种vue3 架构中自带的api,如果在全局配置一下的话,就可以减少一部分代码量,只是在代码编译的时候,会添加相应的引用&#xff…

ArcGIS arcpy代码工具——关于标识码的那些事(查找最大标识码、唯一性检查、重排序、空值赋值)

系列文章目录 ArcGIS arcpy代码工具——批量对MXD文件的页面布局设置修改 ArcGIS arcpy代码工具——数据驱动工具批量导出MXD文档并同步导出图片 ArcGIS arcpy代码工具——将要素属性表字段及要素截图插入word模板 ArcGIS arcpy代码工具——定制属性表字段输出表格 ArcGIS arc…

复制即用!纯htmlcss写的炫酷input输入框

一般我们写css样式都要用样式库,但是嫌麻烦,如果能找到现成的内容复制上去就很香了,下文是笔者觉得好看的纯html&css写的样式,可以直接复制到Vue等内,十分方便。 input组件 1) 下面这个很推荐&#…

C++的数据结构(九): 笛卡尔树

笛卡尔树(Cartesian Tree)是一种特殊的二叉树,其每个节点的键值(key)满足二叉搜索树的性质,即左子树上所有节点的键值小于根节点的键值,右子树上所有节点的键值大于根节点的键值。与此同时&…

C 深入指针(4)

目录 一、字符指针变量 1 初始化 2 与字符串数组的区别 二、数组指针变量 1 初始化 2 二维数组传参本质 三、函数指针变量 1 初始化 2 用法 四、typedef关键字 五、函数指针数组 一、字符指针变量 1 初始化 //VS2022 x64 #include <stdio.h> int main() {…

InnoDB 事务处理机制

文章目录 前言1. 事务处理挑战1.1 事务机制处理的问题1.2 并发事务带来的问题 2. InnodDB 和 ACID 模型2.1 Innodb Buffer Pool2.2 Redo log2.3 Undo log2.4 应用案例 3. 隔离级别和锁机制3.1 事务隔离级别3.1.1 READ UNCOMMITTED3.1.2 READ COMMITTED3.1.3 REPEATABLE READ3.1…

Linux下redis源码编译安装

华子目录 Redis介绍什么是RedisRedis能干什么Redis的特点Redis与memcached对比 redis源码编译安装下载源码包准备安装环境开始编译开始安装 前台启动后台启动redis开启systemctl启动redis测试redis相关知识 Redis介绍 什么是Redis 2008年&#xff0c;意大利的一家创业公司Mer…

xlrd.biffh.XLRDError: Excel xlsx file; not supported报错原因

xlrd库读取xlsx文件时报错 xlrd.biffh.XLRDError: Excel xlsx file; not supported报错原因&#xff1a; xlrd版本为2.1版本&#xff0c;需要读取xlsx文件需要安装xlrd低一些版本1.2.0版本&#xff0c;重新安装重试即可 更换xlrd版本 重新运行

数仓架构之为什么要进行数仓分层

数仓分层这个概念想必大家都很熟悉&#xff0c;不管是在实际的开发工作当中会用的&#xff0c;还是在面试官面试你的时候会问到&#xff1a;你之前的项目是按照什么分层的&#xff0c;分哪几层&#xff0c;数仓分层有什么好处&#xff0c;举个栗子说说。 简而言之&#xff0c;…