从用户模式 win32 应用程序中可靠地查找当前进程的 _write() 函数的地址

Reliably find the address of the current process' _write() function from a user mode win32 application

本文关键字:进程 write 地址 函数 查找 win32 模式 用户 应用程序      更新时间:2023-10-16

我正在编写一个应用程序,它可以从系统上的任何用户模式进程捕获stdout/stderr和调试消息,并将其打印到其控制台。在过去的几个情况下,我一直在编写程序,由于程序的性质,可能是GUI, windows服务等。因为没有控制台,所以无法看到控制台输出。解决这个问题的明显方法是将打印语句更改为调试打印语句,如OutputDebugString(),然后附加一个调试器并查看输出。有时,设置调试器并查看所需的输出可能会很棘手,特别是在内核模式调试中。

理想情况下,我正在编写的这个应用程序将允许您指定一个PID(最终将处理驱动程序,现在不用担心)-并且无需将应用程序附加为调试器,它将显示用于调试器,标准输出或标准错误的所有输出。

为了做到这一点,我创建了一个应用程序,它将注入一个DLL到系统上的任何进程。从DLL中,我将一个蹦床钩子插入_write()过程中,从cout、cerr、wcout、wcerr、printf和fprintf捕获用于stdout和stderr的数据。我现在的问题是_write()过程的地址在每次运行目标应用程序时都会发生变化。目前,我正在windbg中运行目标应用程序,并执行x program!_write以查找地址,对其进行硬编码并测试我的钩子。

TLDR

当我运行x program!_write命令时,Windbg如何找到_write()的地址?我如何从注入到没有符号的目标进程的DLL做同样的事情?

任何帮助都将非常感激。我当前进度的源代码可以在这里找到:https://github.com/vix597/StJude

也如果有一个更好的方法来重定向stdout/stderr从一个注入DLL的目标进程,我洗耳恭听。我尝试过freopen,但唯一得到重定向的输出是来自注入的DLL本身的输出,而不是注入DLL的应用程序。我是在我无法控制目标应用程序源代码的假设下工作的。我也没有验证_write()在没有控制台时被调用。

在问这个问题之前,我的测试程序是在静态库中使用MFC编译的。当使用标准的windows库时,Windbg在MSVCR120中找到_write()。对于那些试图回答这个问题的人来说,这可能会导致一些混乱,以便更清楚:

无论目标应用程序中的c++运行时是如何编译的,也无论使用的是什么版本的c++运行时环境,我如何找到_write()方法的地址?

我想要这样写:

LPVOID fnWrite = GetProcAddress(GetModuleHandle(L"<module_name>"),"_write");

关于你关于Windbg如何做到这一点的问题,它使用了Windows的调试API。有了它,你可以插入断点等。具体来说,要在程序中拥有函数的地址,您需要使用dbghelp DLL(您需要有PDB才能工作)。

但是对于您的使用,有一个更简单的解决方案,只要应用程序将运行时作为DLL使用:在该入口点上放置一个钩子。