静态分析&&IDA


目标对象:2.crackme.exe

环境:windows

工具:IDA Pro(32bit) (带有F5插件)

目标:找到flag
在这里插入图片描述

程序功能描述:输入少于24个字符会提示需要24个字符并使得重新输入;如果输入正确的24个字符,即flag,输出成功;不正确的24个字符,则输出失败。

IDA分析目标程序

点击main函数 F5反汇编成C语言代码

main函数:

int __cdecl main(int argc, const char **argv, const char **envp)
{
  FILE *v3; // eax@3
  signed int i; // [sp+14h] [bp-44h]@4
  char v6[28]; // [sp+18h] [bp-40h]@1
  int v7; // [sp+34h] [bp-24h]@1
  char v8; // [sp+38h] [bp-20h]@1
  int v9; // [sp+39h] [bp-1Fh]@1
  int v10; // [sp+3Dh] [bp-1Bh]@1
  int v11; // [sp+41h] [bp-17h]@1
  int v12; // [sp+45h] [bp-13h]@1
  int v13; // [sp+49h] [bp-Fh]@1
  __int16 v14; // [sp+4Dh] [bp-Bh]@1
  char v15; // [sp+4Fh] [bp-9h]@1
  int v16; // [sp+50h] [bp-8h]@1
  int v17; // [sp+54h] [bp-4h]@1

  v8 = 0;
  v9 = 0;
  v10 = 0;
  v11 = 0;
  v12 = 0;
  v13 = 0;
  v14 = 0;
  v15 = 0;
  v7 = 3;
  v17 = 0;
  v16 = 0;
  printf_s("[*] To get the flag, you need to input a correct string.\n\n");
  scanf_s("%s", v6, 25);//输入字符串被读取到v6
  while ( strlen(v6) != 24 )//v6不为长度24,重新获取输入
  {
    v3 = (FILE *)sub_4017DA();
    fflush(v3);
    printf_s("\n[*] Please Input a string with 24 characters!\n\n");
    scanf_s("%s", v6, 25);
  }
//为长度24的处理
  for ( i = 0; i < 4; ++i )
	//将长度24的字符串截断为4组长度为6的,每次传入6个给sub处理,分别进行转换,得到对应v8字符串
    sub_401000((int)&v6[6 * i], (int)(&v8 + 6 * i));//关键转换函数sub
  while ( v16 < 24 )//逐长度24判断
  {
    switch ( *(&v8 + v16) )
    {//针对v8的每一个字符,变化v7或者v17(v7初始为3,v17初始为0)
      case 1:
        --v7;
        break;
      case 2:
        ++v7;
        break;
      case 3:
        --v17;
        break;
      case 4:
        ++v17;
        break;
      default:
        break;
    }
    if ( *(&byte_40E018[10 * v7] + v17) != 35 )//条件1
    {//由v7和v17索引的byte数组的位置为#,则可行,否则输入错误
      printf("\n[*] Sorry! Your input is wrong!\n\n");
      exit(0);//24个字符都要满足条件1,否则就退出
    }
    ++v16;
		
  }
  if ( v7 != 9 || v17 != 8 )//经过24次变化后最后的v7和v17需要满足该条件
    printf("\n[*] Sorry! Your input is wrong!\n\n");
  else
    printf("\n[*] Nice job! Here is the flag: flag{%s}\n\n", v6);//flag是v6
  return 0;
}

逻辑:

  • 由条件1得到每一次的v7或者v17的变化,进而得到v8。

将条件1的数组分割成10*10的,从初始位置索引3,0开始走完所有的#,最后到达9,8


**********
*####*****
*#**#*****
##*##*****
***#******
***#*#####
***###***#
*********#
*********#
********##

v8: 411444 221222 441444 422221

  • 通过关键函数sub,由v8逆推v6
//关键函数sub
int __cdecl sub_401000(int a1, int a2)
{//a2传入v8,a1传入v6
  int result; // eax@7
  signed int v3; // [sp+0h] [bp-8h]@1
  signed int i; // [sp+4h] [bp-4h]@1

  v3 = 0;
  for ( i = 0; i < 6; ++i )
  {
    while ( v3 < 4 )
    {
      if ( *(_BYTE *)(i + a1) == *(&byte_40E000[4 * i] + v3) )
      {
//如果六个一组的v6对应的值与数组被v3索引的值相等(每个v6对应数组的一行),则把v8对应位置设成v3+1
        *(_BYTE *)(i + a2) = v3 + 1;//v8对应的位置的值为v3+1
        break;
      }
      ++v3;
    }
    v3 = 0;
    result = i + 1;
  }
  return result;
}

数组分成4个一组,每组6个

0A1B
a2b3
4C5D
c6d7
8E9F
e0f1


通过v8的值推出v3,定位数组,得到v6

v6:Ba47F1 A24c8e B347F1 B2C6Ee

  • 推断过程的值还没有验证,但是逻辑是对的
  • 数组明文通过IDA的Hex View看到二进制

版权声明:本文为freedomDA原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。