如何根据这个反转的代码编写C++代码?

huangapple go评论72阅读模式
英文:

How to write a c++ code according to this reversed code?

问题

I used IDA7 to decompile some binary and got something like this.

Pseudocode:

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

And Constructor of A looks like:

Pseudocode:

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

ref_B looks like:

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

struct(class) A looks like:

struct __cppobj A : B {
    pthread_mutex_t mMutex;
};

struct(class) B looks like:

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

My problem is what kind of source code yields code like A::start. I double-checked the assembly code of A::start, and I'm quite sure IDA did the right pseudocode translation.

I tried to understand the code's behavior. It looks like A::start wants to judge whether getFD from its vtable is from ref_B. (If some class X derives from A and overwrites getFD but not overwrite start, then calling x.start will call its getFD instead of using mFd from class B.) But I just don't know how to achieve the source code. Will someone be so kind to help me out?

英文:

I used IDA7 to decompile some binary and got something like this.

Pseudocode:

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

And Constructor of A looks like:

Pseudocode:

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

ref_B looks like:

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

struct(class) A looks like:

struct __cppobj A : B
{
	pthread_mutex_t mMutex;
};

struct(class) B looks like:

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

My problem is what kind of source code yields code like A::start. I double checked the assemble code of A::start, and I'm quite sure IDA did the right Pseudocode translation.

I tried to understand the code's behaviour. It looks like A::start wants to judge whether getFD from it's vtable is from ref_B.(if Some class X derive from A and overwrite getFD, but not overwrite start, then calling x.start will calling its getFD instead of using mFd from class B). But I just don't know how to achieve the source code. Will some one so kind to help me out?

答案1

得分: 2

我认为你所强调的代码只是编译器乐观地内联一个带有慢路径回退的虚函数。

原始源代码可能只是

fd = getFD();

其中 getFD 在类 B 中声明为:

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

编译器无法知道是否会对 A 进行进一步的子类化以覆盖 getFD,因此必须保留较慢的虚拟调用作为备用。

英文:

I think the code you highlighted is just the compiler optimistically inlining a virtual function with a slow path to fall back to.

The original source code probably is just

fd = getFD();

where getFD is declared in B as:

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

The compiler cannot know whether A in turn is not subclassed with an override for getFD, so it must keep the slower virtual call as a backup.

答案2

得分: 0

我终于得到了一个非常扭曲的答案。但我决定将它发布出来,以便可以被处于相同情况的合作伙伴采纳。

可以替代

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;

使用这个替换,我可以毫不费力地将伪代码直接重写成C++源代码,并轻松地借鉴他人的成果。

不管怎样,感谢参与帮助我的合作伙伴。这是我第一次使用StackOverflow,如果有什么不对的地方,请指正。

英文:

I finally got a freakin' answer. It was very twisted, but I decided to put it out there so that it could be taken by a partner in the same situation.

The code that can replace the "

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;

"
part is
"

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;

"

, in which I got "VTableIndex" from https://stackoverflow.com/questions/5635212/detect-the-the-vtable-index-ordinal-of-a-specific-virtual-function-using-visual/5699897#5699897

Using this substitution, I can mindlessly rewrite the pseudocode directly into C++ source code and easily whore out the results of others.

Anyway, thanks to the partners who participated in helping me. This is my first time using StackOverflow, so please correct me if there is something wrong.

huangapple
  • 本文由 发表于 2023年6月15日 18:14:47
  • 转载请务必保留本文链接:https://go.coder-hub.com/76481477.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定