Debugging Tools for Windows |
.call 命令使得目标进程执行一个函数。
.call /c
.call /C
.call /s Prototype Function( Arguments )
模式 | 仅用户模式 |
目标 | 仅活动调试 |
平台 | 仅x86和x64 |
指定函数是被当前进程的当前线程调用的。
只支持 cdecl、 stdcall、 fastcall和thiscall 调用约定。不能使用该方法调用托管代码。
使用.call 之后,调试器会刷新堆栈,将指令指针修改为指向被调用函数的开头,调用该函数,然后停止。使用g (Go)来恢复执行或者~. g 来执行刚才进行调用的线程。
函数返回时,会发生一次中断并且调试器显示函数的返回值。返回值也会保存在可以得到返回值类型的 $callret 伪寄存器中。
如果使用CTRL+C 或CTRL+BREAK来中断到目标中,当前线程是一个用来处理中断(breakin)的附加线程。 如果这时候使用.call命令,则会使用该额外线程来调用函数。
如果遇到了之前定义的断点,线程不会进行额外的中断。如果在用户模式断点中断时使用.call ,可以使用g来执行整个进程或者 ~. g来执行当前线程。使用g可能会造成程序行为的错误,因为已经将某个线程转移来执行新的函数了。另一方面,该线程还是保留它的锁和其他属性,所以~. g 也可能遇到死锁。
安全的使用.call的方法是,将断点设置到可以安全调用指定函数的代码位置。遇到该断点时,如果需要就可以使用.call来执行函数。如果在不能正常调用该函数的地方使用.call,则可能造成死锁或目标执行错误。
在代码中包含一些只由调试器调用而不由代码来调用的额外函数可能会很有用。例如,可以添加一些函数用来检查代码的当前状态、环境并且将这些状态信息保存到已知的内存位置。注意不能优化代码,否则这些函数会被编译器去除。这种技术应该当作最后的手段,因为如果程序崩溃,.call在调试dump文件时是不能使用的。
.call /c 和.call /C 命令应该仅在.call 失败,或者进入g命令前改变主意时使用。它们不能随便使用,因为放弃未完成的call会造成目标状态被破坏。
下面的例子说明了如何使用.call /s命令。
这里,如果拥有KnownFunction的私有符号,该函数唯一的参数是一个整型,返回值也是整型,如指针或者数组。没有UnknownFunction的符号或者只有共有符号,但是知道它也只有一个整型参数,并且返回一个数组的指针。通过使用/s选项,就可以指定让UnknownFunction按照KnownFunction同样的方式工作。这样就能成功调用UnknownFunction。