我的问题是我不懂一行代码
当这个envp参数出现在main上时,我正在反向工程一个crackme,然后程序开始使用它,这使我不明白如何解决crackme的第二部分(我使用c反编译程序来分析crackme的密码)。我仍然用修补二进制代码解决了crackme问题,但我不明白这一行的意思,它正在困扰我。。。。

int __cdecl main(int argc, const char **argv, const char **envp){
  char *Format; // [esp+0h] [ebp-98h]
  char v5; // [esp+20h] [ebp-78h]

  _alloca((size_t)Format);
  __main();
  printf("IOLI Crackme Level 0x06\n");
  printf("Password: ");
  scanf("%s", &v5);
  check(&v5, (int)envp);
  return 0;
}

int __cdecl check(char *Str, int a2){
  size_t v2; // eax
  char Src; // [esp+1Bh] [ebp-Dh]
  unsigned int i; // [esp+1Ch] [ebp-Ch]
  int v6; // [esp+20h] [ebp-8h]
  int v7; // [esp+24h] [ebp-4h]

  v6 = 0;
  for ( i = 0; ; ++i ){
    v2 = strlen(Str);
    if ( i >= v2 )
      break;
    Src = Str[i];
    sscanf(&Src, "%d", &v7);
    v6 += v7;
    if ( v6 == 16 )
      parell(Str, a2);}
  return printf("Password Incorrect!\n");
}

int *__cdecl parell(char *Src, int a2){
  int *result; // eax
  int i; // [esp+10h] [ebp-8h]
  int v4; // [esp+14h] [ebp-4h]

  sscanf(Src, "%d", &v4);
  result = (int *)dummy(v4, a2);
  if ( result )
  {
    for ( i = 0; i <= 9; ++i ){
      if ( !(v4 & 1) ){
        printf("Password OK!\n");
        exit(0);
      }
      result = &i;
    }
  }
  return result;
}

signed int __cdecl dummy(int a1, int a2)
{
  int v2; // ecx
  int v5; // [esp+14h] [ebp-4h]

  v5 = 0;
  while ( *(_DWORD *)(4 * v5 + a2) )            // 1 == True
  {
    v2 = 4 * v5++;                              //  4 or 0
    if ( !strncmp(*(const char **)(v2 + a2), "LOLO", 3u) )
      return 1;
  }
  return 0;
}

它从main到check再到parallel(如果条件完全正确,然后是dummy,这将创建一个无限循环,除了:if//!strncmp(*(const char**)(v2+a2),“LOLO”,3u)==1,问题是我//main中的这个envp变量a2意味着什么
这是解的暗示,正如我所说,我被困在第二个条件(无限循环)上:
级别0x06:与5中的算法相同,但envp LOLO=1

最佳答案

const char**envp应该做什么?
正如@Vlad在评论中告诉您的,它envp类似于argv,但它不是程序参数,而是将进程的环境变量传递给它。这些是相同的键/值对,可以通过getenv()函数访问或通过putenv()函数设置。进程从其父进程接收它们,通常只需继承其父环境的副本。贝壳有一个操作这些界面的用户界面,例如,在bash中,可以使用命令LOLO=1将一个名为“洛洛”的环境变量设置为“1”。Windows外壳对同一件事有不同的语法。
如果您分析您所呈现的代码,您将看到envp只是通过几个级别的函数传递(作为int),直到最终在dummy()中使用(仅限)。您将进一步注意到dummy()没有使用它的其他参数——它所做的只是分析它的第二个参数(转换回指针)指向的数据。特别是,它看起来像是在扫描整个环境,寻找任何名称以“LOL”开头的环境变量——如果找到一个,则返回1,否则返回0。这就解释了您所询问的提示:不足以确定密码;除非将适当的环境变量设置为任何值,否则不接受密码。”“LOLO”将是这样一个变量的名称。
实际的密码检查是在checkparell函数中进行的。前者对密码字符串中的十进制数字执行预检查,将数字相加为16。如果这是满意的(即使这发生在密码结束之前),那么它将把整个密码交给函数parell进行进一步的测试。这里是执行环境检查的位置,如果通过,则密码的前十进制数字将转换为一个数字,只要该数字是偶数,则接受密码。
假设反编译程序正确地完成了工作,那么只要设置了环境变量,就可以接受许多密码:

88
4444
23452

包括利用checkparell执行的解析中的一些怪癖,例如
0d79
2pwned!!

另外,在main()中输入的密码可能会受到缓冲区溢出的影响,因此您可以从完全不同的方向着手解决问题。

关于c - const char ** envp应该做什么?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/57009937/

10-12 00:35