代码之家  ›  专栏  ›  技术社区  ›  aston am

如何理解这个反编译代码中的for循环?

  •  0
  • aston am  · 技术社区  · 2 年前
      int v0[6]; // [esp+1h] [ebp-37h] BYREF
      char v1[23]; // [esp+19h] [ebp-1Fh] BYREF
    
      qmemcpy(v0, "VMPZB^I[f)*+.){*~yyx", 20);
      v0[5] = 2133096749;
      strcpy(v1, "%-){$y-y+-.x)~y)*`");
      for ( *(_DWORD *)&v1[19] = 0; *(_DWORD *)&v1[19] <= 42u; ++*(_DWORD *)&v1[19] )
        *((_BYTE *)v0 + *(_DWORD *)&v1[19]) ^= 29u;
      puts(v0);
      exit(0);
    }
    

    到目前为止,我的理解是:

    #include <string.h>
    #include<iostream>
    
    using namespace std;
    
    int main () {
       int v0[6];
       char v1[23];
       memcpy(v0, "VMPZB^I[f)*+.){*~yyx", 20);
       v0[5] = 2133096749;
       strcpy(v1, "%-){$y-y+-.x)~y)*`");
       for (int i = 19; i <= 42; ++i) {
        *((unsigned char *)v0 + *(unsigned int *)&v1[i]) ^= 29;
    }
       cout<<v0<<'\n'<<v1;
    }
    

    我无法理解for循环,它很可能是错误的。有人能帮我理解吗?

    我曾经提到过stackoverflow的类似问题,也许我对指针没有正确的理解,但for循环让我很困惑。

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

    反编译代码中的for循环有点难以理解,因为它涉及指针算术和逐位操作。

    1. 它初始化指向 v1 大堆这是由 *(_DWORD *)&v1[19] = 0; _DWORD 是表示双字(32位)的数据类型,相当于C++中的无符号int。所以,这条线相当于 unsigned int *ptr = (unsigned int *)&v1[19]; *ptr = 0; 在C++中。它正在创建一个指向 v1 并且将该位置处的值设置为0。
    2. for循环的条件检查指针指向的位置处的值是否小于或等于42。这是由 *(_DWORD *)&v1[19] <= 42u;
    3. 在循环的每次迭代中,它都会在指针指向的位置增加值。这是由 ++*(_DWORD *)&v1[19];
    4. 在循环中,它对 v0 大堆要“异或”的元素的索引由指针指向的位置处的值确定。这是由 *((_BYTE *)v0 + *(_DWORD *)&v1[19]) ^= 29u; _BYTE 是表示字节(8位)的数据类型,相当于C++中的无符号字符。所以,这条线相当于 v0[*ptr] ^= 29; 在C++中。

    for循环的等效C++代码为:

    unsigned int *ptr = (unsigned int *)&v1[19];
    *ptr = 0;
    for (; *ptr <= 42; ++(*ptr)) {
        v0[*ptr] ^= 29;
    }
    

    此代码可能会导致分段故障,因为它访问 v0 数组超出其边界。这个 v0 数组只有6个元素,但循环尝试访问第42个元素。这是C++中未定义的行为。反编译的代码可能不正确,或者可能被故意混淆。