如何将读取和写入重定向到变量

How to redirect reads and writes to a variable?

本文关键字:重定向 变量 读取      更新时间:2023-10-16

我有一个编译的32位Windows应用程序,它是用MSVC 6.0构建的。我想注入代码并将读取或写入重定向到变量。对于简单的情况,例如:

DWORD& dword_995344 = *(DWORD*)0x995344;

可以工作。但我也希望代码编译为自己的独立 exe。显然,这是行不通的,因为0x995344不太可能是一个有效的地址。例如,它也不会像char buffer[256]; // at address 0xdeadbeef那样用于此。

然后我想也许我可以想出一些模板包装器:

template<DWORD VarAddr, class VarType>
class Var
{
public:
    using VarTypePtr = VarType*;
    Var()
    {
        mVar = (VarTypePtr)VarAddr;
    }
    Var(const Var&) = delete;
    Var& operator = (const Var&) = delete;
    operator VarType()
    {
        return *mVar;
    }
    void operator = (VarType v)
    {
        *mVar = v;
    }

private:
    VarTypePtr mVar;
};
Var<0x00995344, DWORD> dword_995344_;
void Test()
{
    dword_995344_ = 7;
    DWORD y = dword_995344_;
}

但同样,处理所有类型和案例并不简单,或者在某些情况下可能也是不可能的。是否有其他技术(无论:)多么笨拙)可以捕获读取和写入,以便我可以执行以下操作:

DWORD dword_995344 = 0;
void InstallVarHooks()
{
   RedirectReadWrites(&dword_995344, 0x995344);
}

您可能会考虑检测源代码以收集所需的信息。 这可以通过程序转换系统来完成。

这样的工具可以让你编写模式,本质上说,

when you see <this>, replace it by <that>

以编译器精确的方式(不是字符串黑客攻击,它永远不会在真实代码上工作)。 在你的情况下,你会想说这样的话,

when you see a <write of varX>,
replace it by <store varX to known location, then do write varX>

如何做到这一点的灵感可以在我的技术论文中找到,Branch Coverage for Arbitrary Languages make Easy。

若要对C++执行此操作,请参阅 https://softwareengineering.stackexchange.com/a/257441/12135

我不确定我是否理解您的问题,您想在写入变量的那一刻拦截,如果是这样,则将写入重定向到其他内存位置,读取也是如此。这部分理论上可以用调试断点来补充,有一个项目 https://github.com/mmorearty/hardware-breakpoints 应该给你如何编译它的提示。它看起来很过时,但由于您想在VS6.0应用程序上使用它,因此它实际上可能会起作用。您必须使用 DLL 注入代码进入目标应用程序才能使用它。

这实际上只是一个工具,它应该允许您在读取/写入变量时拦截时刻,您仍然需要编写适当修改变量的代码。

无论如何,看起来像很多黑客攻击。

完全有可能引用数组,尽管语法很混乱:

char (&TheArray)[256] = *reinterpret_cast<char(*)[256]>(0xDEADBEEF);

在 C++11 中,您可以使用 auto,从而避免重复该类型两次:

auto &TheArray = *reinterpret_cast<char(*)[256]>(0xDEADBEEF);

还有一种更简单的方法,即只获取指向地址的指针:

char *TheArray = *reinterpret_cast<char*>(0xDEADBEEF);

由于指针的行为类似于 C 中的数组(因此也类似于 C++),因此上述内容将具有基本相同的效果。

因此,如果您需要的是任意地址对某个对象的引用,即使它是任意复杂的类型,这种方法也会起作用。

如果您要访问的变量不位于常量地址(现在很少有变量),则可以将常量0xDEADBEEF替换为任意复杂的表达式,该表达式可以计算出所述变量的地址,这可能涉及调用 GetModuleHandle ,以获取主可执行文件的地址。