Hex-rays 反编译器不正确的逻辑

逆向工程 艾达 反编译 C++ 六线谱
2021-07-03 10:38:37

我正在 IDA 中练习逆向工程,我在 Visual C++ 中创建了一个示例应用程序来练习使用类/结构,反编译器输出似乎不正确 - 我想知道是否可以解决这个问题以更接近正确反编译结果或者这是否仅仅是反编译器的限制。

#include <iostream>
#include "exstruct.cpp"

int main()
{
    int x, y;
    std::cin >> x;
    std::cin >> y;
    calculator c(x, y);
    std::cout << c.multiply() << "\r\n";
}

我使用关闭优化的 Visual C++ 编译器进行编译,在定义函数和数据结构后,hex-rays 反编译器输出如下:

int __cdecl main(int argc, const char **argv, const char **envp)
{
  char *newline; // ST04_4
  int cout; // eax
  Calculator calculator; // [esp+4h] [ebp-18h]
  int x; // [esp+10h] [ebp-Ch]
  int y; // [esp+14h] [ebp-8h]

  std::basic_istream<char,std::char_traits<char>>::operator>>(std::cin, &x, calculator.x);
  std::basic_istream<char,std::char_traits<char>>::operator>>(std::cin, &y, calculator.y);
  Calculator_constructor(&calculator, x, y);
  calculator.x = (int)new_line_string;
  newline = (char *)Calculator_multiply(&calculator);
  cout = std::basic_ostream<char,std::char_traits<char>>::operator<<(std::cout);
  printf(cout, (int)newline);
  return 0;
}

这一切看起来相当不错,直到它分配新的线串\r\ncalculator.x,然后乘到的结果newline变量,这是错误的原因很明显。

我已经审查了程序集,这根本不是发生的事情。以下程序集的片段:

.text:00701088                 lea     ecx, [ebp+calculator] ; this
.text:0070108B                 call    Calculator_constructor
.text:00701090                 push    offset new_line_string ; this
.text:00701095                 lea     ecx, [ebp+calculator] ; this
.text:00701098                 call    Calculator_multiply
.text:0070109D                 push    eax
.text:0070109E                 mov     ecx, ds:?cout@std@@3V?$basic_ostream@DU?$char_traits@D@std@@@1@A ; std::basic_ostream<char,std::char_traits<char>> std::cout
.text:007010A4                 call    ds:??6?$basic_ostream@DU?$char_traits@D@std@@@std@@QAEAAV01@H@Z ; std::basic_ostream<char,std::char_traits<char>>::operator<<(int)
.text:007010AA                 push    eax
.text:007010AB                 call    printf

在我看来,反编译器很困惑,因为指向\r\n文字的指针push发生在multiply调用之前,使它看起来像一个实际上不是的参数。

无论如何我可以解决这个问题吗?

完整的组装在这里

exstruct.cpp 作为文本:

class calculator
{
public:
    int x;
    int y;
    int z;

    calculator(int x, int y)
    {
        this->x = x;
        this->y = y;
        this->z = x + y;
    }

    int multiply()
    {
        return this->x * this->y;
    }
};

构造函数和乘法源和反编译源:

这里.

笔记:

  • Hex-Rays 反编译器 v7.0.0.170914
  • 我手动增加了函数的大小,1C因为它最初没有被检测newline为一个字段
  • 我手动将\r\n内存中的位置定义为字符串
1个回答

我能够解决这个问题。

反编译没有检测为正确的调用参数计数>><<运营商cincout

例如:

int __thiscall std__basic_istream_char_std__char_traits_char____operator__(_DWORD, _DWORD, _DWORD)

是检测到的>>操作员签名

但是,查看C++ 参考,它应该更像这样:

int __thiscall std__basic_istream_char_std__char_traits_char____operator__(void *, int *)

其中第一个参数是cin对象,第二个参数是指向整数输出的指针。因为__thiscall如果参数计数错误,这些函数使用约定,那么反编译器假定该函数修改了错误数量的堆栈指针,这会导致各种问题。