.call(调用函数)

.call 命令会促使目标进程执行函数。

.call [/v] Function( Arguments ) 
.call /s Prototype Function( Arguments ) 
.call /c 
.call /C 

参数

/v
将显示有关调用及其参数的详细信息。

/s 原型
允许调用 Function 指定的函数,即使没有正确的符号也是如此。 在这种情况下,必须具有与尝试调用的函数相同的调用原型的另一个函数的符号。 Prototype 参数是此原型函数的名称。

功能
指定要调用的函数。 这可以是函数的名称(最好是用模块名称限定),也可以是计算结果为函数地址的任何其他表达式。 如果需要调用构造函数或析构函数,则必须提供地址,否则使用 C++ 表达式计算运算符的命名语法(有关详细信息,请参阅数值表达式语法)。

参数
指定传递给函数的参数。 如果要调用方法,则第一个参数必须是 this,所有其他参数都放在其后面。 参数应用逗号分隔,并且应与通常的参数语法匹配。 支持可变长度参数列表。 参数中的表达式由 C++ 表达式计算器解析;有关详细信息,请参阅 C++ 数字和运算符。 不能输入文字字符串作为参数,但可以使用指向字符串的指针,或者目标进程可访问的任何其他内存。

/c
清除当前线程上的任何现有调用。

/C
清除当前线程上的任何现有调用,并将当前线程的上下文重置为未完成调用存储的上下文。

环境

模式

仅限用户模式

目标

仅限实时调试

平台

仅限 x86 和 x64

注解

指定的函数由当前进程的当前线程调用。

仅支持 cdeclstdcallfastcallthiscall 调用约定。 此命令无法调用托管代码。

使用 .call 后,调试器将更新堆栈,将指令指针更改为指向所调用函数的开头,然后停止。 使用 g(执行)继续执行,或者使用 ~. g 仅执行发出调用的线程。

函数返回时,将发生中断,并且调试器将显示函数的返回值。 返回值也存储在 $callret 伪寄存器中,后者获取返回值的类型。

如果已使用 CTRL+C 或 CTRL+BREAK 进入目标,则当前线程是创建用于处理进入的附加线程。 如果此时发出 .call 命令,则额外线程将用于调用的函数。

如果已到达预定义断点,则没有额外的进入线程。 如果在用户模式下的断点处使用 .call,则可以使用 g 来执行整个进程,或者使用 ~. g 仅执行当前线程。 使用 g 可能会扭曲程序的行为,因为已采用一个线程并将其转移到此新函数。 另一方面,此线程仍将具有其锁定和其他属性,因此 ~. g 可能会有死锁的风险。

使用 .call 的最安全方法是在代码中设置断点,在该位置可以安全调用特定函数。 命中该断点时,如果需要运行该函数,则可以使用 .call。 如果在无法正常调用此函数时使用 .call,则可能会导致死锁或目标损坏。

将额外的函数添加到源代码中可能很有用,其中这些函数不是由现有代码调用的,而是将由调试器调用。 例如,可以添加用于调查代码及其环境的当前状态的函数,并将有关状态的信息存储在已知内存位置。 确保不要优化代码,否则编译器可能会删除这些函数。 仅将此技术用作最后手段,因为在调试转储文件时,如果应用程序崩溃,.call 将不可用。

仅在尝试使用 .call 失败,或在输入 g 命令之前改变主意时,才应使用 .call /c.call /C 命令。 不应随意使用这些值,因为放弃未完成的调用可能会导致目标状态损坏。

下面的代码示例演示如何使用 .call /s 命令。

.call /s KnownFunction UnknownFunction( 1 )

在此示例中,有 KnownFunction 的私有符号,该符号采用整数作为其唯一参数并返回指向数组的指针等。 没有符号,或者可能只有 UnknownFunction 的公共符号,但知道它采用整数作为其唯一参数,并返回指向数组的指针。 通过使用 /s 选项,可以指定 UnknownFunction 的工作方式与 KnownFunction 的工作方式相同。 因此,可以成功生成对 UnknownFunction 的调用。