代码之家  ›  专栏  ›  技术社区  ›  yed

如何根据这个反向代码编写c++代码?

  •  -1
  • yed  · 技术社区  · 2 年前

    我用IDA7反编译了一些二进制文件,得到了这样的结果。

    伪代码:

    int A::start(){
        int (__fastcall *v3)(B *const); // x2
        unsigned int fd; // w0
        int (__fastcall *v5)(A *const, int); // x3
        int v6; // w20
    
        v3 = *(this->_vptr.B + 6);    //pointing to getFD (the sixth function of ref_B)
        if ( v3 != B::getFD )
        {
            fd = v3(&this->B);
            v5 = *(this->_vptr.B + 7);
            if ( v5 == B::listen )
                goto LABEL_4;
        LABEL_9:
            v6 = v5(this, fb);
            if ( v6 )
                goto LABEL_10;
            goto LABEL_4;
    
        }
        fd = this->mFd;
        v5 = *(this->_vptr.B + 7);
        if ( v5 != B::listen )    //major problem here, A doesn't overwrite listen, 
                                  //so "v5 != B::listen" never true, 
                                  //so we can't just place this->listen(fb) here
            goto LABEL_9;
    
        LABEL_4:
        if ( evutil_socketpair(1, 1, 0, fd) ) // this one comes from event2
        {
            fd = -1LL;
            return -1;
        }
        LABEL_10:
        return 0;
    }
    

    而A的构造函数看起来像:

    伪代码:

    void A::A(A *const this)
    {
        B::B(&this->B);
        this->_vptr.B = ref_B;
    }
    

    ref_B看起来像:

    .data.rel.ro:000000555644D8D8                 DCQ _ZTI1A ; `typeinfo for'A
    .data.rel.ro:000000555644D8E0 ref_B           DCQ _ZThn8_N1AD1Ev ; `non-virtual thunk to'A::~A()
    .data.rel.ro:000000555644D8E8                 DCQ _ZThn8_N1AD0Ev ; `non-virtual thunk to'A::~A()
    .data.rel.ro:000000555644D8F0                 DCQ _ZThn8_N1A4openE8TYPE ; `non-virtual thunk to'A::open(TYPE)
    .data.rel.ro:000000555644D8F8                 DCQ _ZThn8_N1A5closeEv ; `non-virtual thunk to'A::close(void)
    .data.rel.ro:000000555644D900                 DCQ _ZN1B9get******Ev ; B::get******(void)
    .data.rel.ro:000000555644D908                 DCQ _ZN1B9write****EPKcm ; B::write****(char const*,ulong)
    .data.rel.ro:000000555644D910                 DCQ _ZN1B5getFDEv ; B::getFD(void)
    .data.rel.ro:000000555644D918                 DCQ _ZN1B6listenEi ; `non-virtual thunk to'B::listen(int)
    

    结构(类)A看起来像:

    struct __cppobj A : B
    {
        pthread_mutex_t mMutex;
    };
    

    结构(类)B看起来像:

    struct B
    {
        int (**_vptr.B)(...);//this is generated by IDA7, and I think
                             // it's pretty much equal to _vptr_B (so dose all '_vptr.B' above)
        int mFd;
    };
    

    我的问题是什么样的源代码会产生类似A::start的代码。我仔细检查了A::start的汇编代码,我确信IDA翻译了正确的伪代码。

    我试图理解代码的行为。看起来A::start想要判断来自它的vtable的getFD是否来自ref_B。(如果某些类X从A派生并覆盖getFD,但不覆盖start,则调用X.start将调用其getFD,而不是使用类B中的mFd)。但我只是不知道如何实现源代码。有人能帮我吗?

    0 回复  |  直到 2 年前
        1
  •  2
  •   Botje    2 年前

    我认为您强调的代码只是编译器乐观地内联了一个虚拟函数,该函数的返回路径很慢。

    原始源代码可能只是

    fd = getFD();
    

    哪里 getFD 在中声明 B 作为:

    virtual int getFD() { return this->mFd; }
    

    编译器无法知道是否 A 而不是用的重写进行子类化 获取FD ,因此它必须保留较慢的虚拟调用作为备份。

        2
  •  0
  •   yed    2 年前

    我终于得到了一个奇怪的答案。它非常扭曲,但我决定把它放在那里,这样它就可以被同样情况下的伴侣拿走。

    可以替换“

    v3 = *(this->_vptr.B + 6);
    if ( v3 != B::getFD )
    {
        fd = v3(&this->B);
        v5 = *(this->_vptr.B + 7);
        if ( v5 == B::listen )
            goto LABEL_4;
    LABEL_9:
        v6 = v5(this, fd);
        if ( v6 )
            goto LABEL_10;
        goto LABEL_4;
    
    }
    fd = this->mFd;
    v5 = *(this->_vptr.B + 7);
    if ( v5 != B::listen ) 
        goto LABEL_9;
    

    " 部分是 "

    offset = VTableIndex<B>(&B::getFD);
    v3 = (int ( *)(B *const)) *((long*)*(long*)((B *)this)+offset);
    if ((void*)v3 != (void*)&B::getFD) {
      fb = v3((B *)this);
    
      offset = VTableIndex<A>(&A::listen);
      v5 = (int ( *)(A *const, int)) *((long*)*(long*)(this)+offset);
      if ( (void*)v5 == (void*)&A::listen )
        goto LABEL_4;
    LABEL_9:
      v6 = v5(this, fd);
      if ( v6 )
        goto LABEL_10;
      goto LABEL_4;
    }
    fb = this->mFd;
    offset = VTableIndex<A>(&A::listen);
    v5 = (int ( *)(A *const, int)) *((long*)*(long*)(this)+offset);
    if ( (void*)v5 != (void*)&A::listen )
      goto LABEL_9;
    

    "

    ,其中我从中获得了“VTableIndex” https://stackoverflow.com/questions/5635212/detect-the-the-vtable-index-ordinal-of-a-specific-virtual-function-using-visual/5699897#5699897。

    使用这种替换,我可以无意识地将伪代码直接重写到C++源代码中,并很容易地破坏其他代码的结果。

    无论如何,感谢参与帮助我的合作伙伴。这是我第一次使用StackOverflow,所以如果有问题,请纠正我。