这个非虚函数反编译后怎么回事?

Posted

技术标签:

【中文标题】这个非虚函数反编译后怎么回事?【英文标题】:Whats up with this non virtual function after it gets decompiled? 【发布时间】:2021-06-04 16:05:16 【问题描述】:

所以我决定尝试使用 Ghidra 反编译/反汇编一个带有虚函数和非虚函数的简单 c++ 类。然而;反编译让我有点困惑。下面是我的源代码和我的反编译。我不明白为什么对非虚函数的调用由诸如打印字符串和其他 3 个奇怪的参数之类的参数组成。这些其他参数是什么?我只能假设其中一个是“This”指针?如果有,另外两个是什么?

在 Visual Studio 2k17 x64 版本上编译,没有 pdb

来源

#include <iostream>
#include <stdio.h>

class Person

public:
    Person(int val)
    
        myval = val;
    

    void PersonFunction()
    
        printf("this is a person func/n");
    

    virtual void PersonFunction2()
    
        printf("this is a person func2/n");
    

protected:
    int myval = 5;
;

int main(int argc, char** argv)

    Person * person = new Person(10);
    std::cout << "Hello World!\n";
    person->PersonFunction();
    person->PersonFunction2();


反编译

undefined8
FUN_140001080(undefined8 param_1,undefined8 param_2,undefined8 param_3,undefined8 param_4)


  code **ppcVar1;
  
  ppcVar1 = (code **)operator_new(0x10);
  *ppcVar1 = (code *)Person::vftable;
  *(undefined4 *)(ppcVar1 + 1) = 10;
  FUN_1400010e0((longlong *)cout_exref);
  FUN_140001010("this is a person func/n",param_2,param_3,param_4); #what is going on here.. why 3 params?
  (**(code **)*ppcVar1)(ppcVar1); # this, i assume is the virtual function call passing in this ptr
  return 0;


// furthermore inside FUN140001010
void FUN_140001010(undefined8 param_1,undefined8 param_2,undefined8 param_3,undefined8 param_4)


  undefined8 uVar1;
  undefined8 *puVar2;
  undefined8 local_res10;
  undefined8 local_res18;
  undefined8 local_res20;
  
  local_res10 = param_2;
  local_res18 = param_3;
  local_res20 = param_4;
  uVar1 = __acrt_iob_func(1);
  puVar2 = (undefined8 *)FUN_140001000();
  __stdio_common_vfprintf(*puVar2,uVar1,param_1,0,&local_res10);
  return;

谁能解释接受我的字符串和三个参数的函数发生了什么?参数是什么?为什么要传递字符串?

【问题讨论】:

你是怎么编译的? visual studio 2k17 - 发布 x64,无 pdb 使用Person 类的代码是什么样的?该反编译输出似乎与您显示的代码不匹配,因此我怀疑它属于您尚未显示的其他代码。 x64 calling convention 通过寄存器传递前 4 个参数。与 x86 代码不同,其中参数被主动压入堆栈,x64 代码中没有任何内容可以提示 Ghidra 确定这 4 个寄存器是否是函数的参数。在编译到 x86 时尝试您的实验,事情看起来会更加正常。 或者,从FUN_140001010(可能是虚函数)开始返回。它仅使用param_1,因此您可以通过删除剩余的参数来调整其函数签名。一旦你提交了这个,更改应该开始回溯到FUN_140001080。我不确定 Ghidra 是否会自动更新此签名,但肯定会通过不再传递所有 4 个参数而仅传递第一个参数来调整函数调用。 【参考方案1】:

所以看起来 MSVC++ 编译器刚刚优化并将 printf 直接内联到 main 中。 这就是 printf 使用 vaargs 时的样子:

_Check_return_opt_
_CRT_STDIO_INLINE int __CRTDECL printf(
    _In_z_ _Printf_format_string_ char const* const _Format,
    ...)
#if defined _NO_CRT_STDIO_INLINE
;
#else

    int _Result;
    va_list _ArgList;
    __crt_va_start(_ArgList, _Format);
    _Result = _vfprintf_l(stdout, _Format, NULL, _ArgList);
    __crt_va_end(_ArgList);
    return _Result;

#endif

_Check_return_opt_
_CRT_STDIO_INLINE int __CRTDECL _vfprintf_l(
    _Inout_  FILE*       const _Stream,
    _In_z_   char const* const _Format,
    _In_opt_ _locale_t   const _Locale,
             va_list           _ArgList
    )
#if defined _NO_CRT_STDIO_INLINE
;
#else

    return __stdio_common_vfprintf(_CRT_INTERNAL_LOCAL_PRINTF_OPTIONS, _Stream, _Format, _Locale, _ArgList);

#endif

【讨论】:

这没有回答所提出的问题:“这三个其他奇怪的参数”是什么

以上是关于这个非虚函数反编译后怎么回事?的主要内容,如果未能解决你的问题,请参考以下文章

重载重写隐藏

Item 36:不要重写继承来的非虚函数

52)多态的原理(过程)

非虚接口

Effective C++ 6.继承与面向对象设计

Java – 虚函数抽象函数抽象类接口