C ++ COM对象热补丁? [英] C++ COM Object Hotpatching?

查看:217
本文介绍了C ++ COM对象热补丁?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

背景:



我在Windows COM对象上挂钩。



使用的方法是vtable修改。假设我们有一个名为实例接口A 实例,它在界面中包含 oldmethod ,替换为 newmethod 。不过,在我的新方法中,我需要知道 oldmethod 的地址,以便在做自己的事情后可以致电 oldmethod



oldmethod 的地址存储在全局变量中是不安全的,因为接口后面可能会有多个实现A ,假设有两种实施方式, A1类 A2类。因此,我的新方法需要同时存储 A1-> oldmethod A2-> oldmethod ,并根据实例类型调用相应的函数。一个方法来实现这一点是我保存一个地图,它存储(地址vtable - > oldmethod)。因为vtable的地址可以充当A1类和A2类的区分器。在我的新方法中,会检查地图是否有正确的旧方法。但是,这将使程序每次检查地图,这会增加成本,并且地图上的线程安全性会增加成本。


  • 做一个闭包,我分配一块可执行内存,并写入我的 newmethod 二进制代码(可以减小到最小大小,所以大小不是问题)。我在每个实例的二进制代码中修改 oldmethod 的地址。




  • 问题1



    第二种方式是做到这一点的安全方式,还是第一种方式更好?



    问题2

    >第二种方式,我创建的闭包包含类特定的数据,这是oldmethod指针。如果我需要在我的新方法中存储实例特定的数据是否有任何策略,而不是保持(这个指针 - >数据)映射?

    解决方案

    你可能没有类A1的来源,控制何时被实例化(通过新,CoCreateInstance或一些其他工厂函数)?如果是这样,那么只需实现一个实现接口A的类,并将接口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)\\\
    ,x,y); return _pInner-> M2(x,y); }
    virtual int M3(){return _pInner-> M3();}

    //未显示 - addRef,release,queryinterface
    };


    //示例实例化
    hr = CoCreateInstance(CLSID_A1,NULL,CLXCTX_ALL,IID_InterfaceA,(void **)& pInterfaceA);

    //现在做换行
    pInterfaceA = new CMyWrapperClass(pInterfaceA);

    如果你不能控制你试图热添加的类的实例化,有代码共享为此。但它是无意的有点更复杂。如果这不工作,我会发布另一个直接与hotvatch一个COM vtable相关的答案。


    Background:

    I'm hooking on windows COM object.

    The method used is vtable modification. say we have an instance of interface A named instance, it contains oldmethod in the interface, I replaced with newmethod. However, in my newmethod I need to know the address of oldmethod so that I can call oldmethod after doing my own thing.

    It is not safe to store the address of oldmethod in a global variable, since there might be more than one implementation behind interface A, let's say there are two implementations, class A1 and class A2. Thus my newmethod needs to store both A1->oldmethod and A2->oldmethod, and call appropriate function based on the instance type.

    • One way to accomplish this is that I keep a map, which stores the (address of vtable -> oldmethod). Since the address of vtable can act as a distinguisher of class A1 and class A2. In my newmethod, the map is checked for the correct oldmethod for current instance. However, this will make the program check the map every time, which imposes a cost, and thread safety on the map will increase the cost.

    • Another way is to make a closure, I allocate a chunk of executable memory, and write the binary code of my newmethod inside(which can be reduced to the minimum size, so size is not a problem). I modify the address of oldmethod in the binary code for each instance. In this case there is no searching on the map cost.

    Question 1:

    Is the second way a safe way to do this, or is the first way better? Is there any potential safety problems in either of them?

    Question 2:

    In the second way, the closure I created contains class specific data, which is the oldmethod pointer. If I need to store instance specific data in my newmethod is there any strategy other than keeping a (this pointer -> data) map? I tried my best and couldn't find a way.

    解决方案

    You may not have the source to class A1, but do you control when it gets instantiated (either by "new", CoCreateInstance, or some other factory function)? If so, then just implement a class that implements interface A and just forwards all the calls on interface A to the real object and intercept the method(s) you care about.

    In the example below, we show an example of replacing

    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);
    

    If you don't have control of the instantiation of the class you are trying to hotpatch, I do have code to share for that. But it's obivously a bit more complicated. If this doesn't work, I'll post another answer directly related to hotpatching a COM vtable.

    这篇关于C ++ COM对象热补丁?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

    查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆