C ++ COM对象热修补?(C++ COM Object Hotpatching?)

2019-08-17 00:45发布

背景:

我钩住窗户COM对象。

所用的方法是虚函数表的修改。 说我们有命名实例 接口A的一个实例,它包含oldmethod在界面上,我替换newmethod。 然而,在我newmethod我需要知道oldmethod的地址,以便我可以做我自己的事情后打电话oldmethod。

它是不是安全的oldmethod地址存储在一个全局变量,因为有可能是一个界面背后不止一个实现,比方说有两种实现方式,A1级A2级 。 因此,我newmethod需要同时存储A1-> oldmethodA2-> oldmethod,并调用基于实例类型相应的功能。

  • 做到这一点的方法之一是,我一直在地图上,存储(虚表的地址 - > oldmethod)。 由于虚函数表的地址可以作为类A1和A2级的区分器起作用。 在我newmethod,地图检查的正确oldmethod当前实例。 然而,这将使程序查地图每一次,这带来成本和线程在地图上安全性会增加成本。

  • 另一种方式是使封闭的,我分配可执行存储器的块,和写我newmethod内的二进制码(可以被减小到最小尺寸,所以大小是没有问题的)。 我修改的oldmethod地址在每个实例的二进制代码。 在这种情况下,是在地图上的成本无觅处。

问题1:

是第二个办法做到这一点安全的方式,或者是第一种方式更好? 是否有任何人任何潜在的安全问题?

问题2:

在第二种方式中,我创建封闭包含类特定的数据,这是oldmethod指针。 如果我需要存储在我的newmethod特定实例数据有什么策略比保持(this指针- >数据)其他地图? 我尽我所能,无法找到一种方法。

Answer 1:

您可能没有源A1级,但是当它被实例化(通过“新”,CoCreateInstance的,或其他一些工厂函数),你控制? 如果是这样,那么就实现实现了接口A类,只是在界面中的所有调用转发给真实对象和拦截你关心的方法(一个或多个)。

在下面的例子中,我们替换的例子

class InterfaceA : public IUnknown
{
public:

    virtual int M1() = 0;
    virtual int M2(int x, int y) = 0;
    virtual int M3() = 0;
};


class CMyWrapperClass : public InterfaceA
{
public:

    int _refcount;
    InterfaceA* _pInner;

    CSomeClass2(InterfaceA* pInner)
    {
        _pInner = pInner;
        _pInner->AddRef();
        _refcount = 1;
    }

    ~CSomeClass2()
    {
        _pInner->Release();
    }

    virtual int M1() {return _pInner->M1();}
    virtual int M2(int x, int y)  {printf("CSomeClass2::M2(x=%d, y=%d)\n", x, y); return _pInner->M2(x,y);  }
    virtual int M3() {return _pInner->M3();}

    // not shown - addRef, release, queryinterface
};


   // example instantiation
   hr = CoCreateInstance(CLSID_A1, NULL, CLXCTX_ALL, IID_InterfaceA, (void**)&pInterfaceA);

   // now do the wrap
   pInterfaceA = new CMyWrapperClass(pInterfaceA);

如果你没有你想的hotpatch类的实例化的控制,我有代码共享为。 但它是obivously有点复杂。 如果这也不行,我会发布另一个答案直接关系到一个热修补功能COM虚函数表。



Answer 2:

我花了一段时间来理解这个问题。 其实我写出来的代码块好,我认为来演示如何修补虚函数表,然后调用的包装类的原始方法。 修补虚函数表很容易。

然后我发现你指的是这个问题。 那就是当打补丁的vtable方法称为(newmethod),即使它在另一个类中定义的,“本”是原来的对象,你没有这些被调用实例的任何方面。 所以,你不能轻易地只是参考的一个成员变量要回了“oldmethod”你救了。

所以经过一番思考,我认为全球地图是这样做的最安全的方法。 您可能只需要一个锁(CRITICAL_SECTION)守卫插入,删除,或查找地图中的函数指针。 你可能不会需要在调用旧方法你已经安全地从地图上检索后,持有该锁。 因此,这样的操作的运行时开销是非常微不足道的。



文章来源: C++ COM Object Hotpatching?