crackMe

crackMe

  1. 首先查壳,发现无壳,且为exe32位程序
  2. 拖入IDA,F5反编译
int wmain()
{
  FILE *v0; // eax
  FILE *v1; // eax
  char v3; // [esp+3h] [ebp-405h]
  char v4; // [esp+4h] [ebp-404h] BYREF
  char v5[255]; // [esp+5h] [ebp-403h] BYREF
  char Format; // [esp+104h] [ebp-304h] BYREF
  char v7[255]; // [esp+105h] [ebp-303h] BYREF
  char v8; // [esp+204h] [ebp-204h] BYREF
  char v9[255]; // [esp+205h] [ebp-203h] BYREF
  char v10; // [esp+304h] [ebp-104h] BYREF
  char v11[255]; // [esp+305h] [ebp-103h] BYREF

  printf("Come one! Crack Me~~~\n");
  v10 = 0;
  memset(v11, 0, sizeof(v11));
  v8 = 0;
  memset(v9, 0, sizeof(v9));
  while ( 1 )
  {
    do
    {
      do
      {
        printf("user(6-16 letters or numbers):");
        scanf("%s", &v10);
        v0 = (FILE *)sub_4024BE();  //返回指向数据off_414000的指针给v0
        fflush(v0);
      }
      while ( !(unsigned __int8)sub_401000(&v10) );
      printf("password(6-16 letters or numbers):");
      scanf("%s", &v8);
      v1 = (FILE *)sub_4024BE();  //返回指向数据off_414000的指针给v1
      fflush(v1);
    }
    while ( !(unsigned __int8)sub_401000(&v8) );
    sub_401090(&v10);
    Format = 0;
    memset(v7, 0, sizeof(v7));
    v4 = 0;
    memset(v5, 0, sizeof(v5));
    v3 = ((int (__cdecl *)(char *, char *))loc_4011A0)(&Format, &v4);
    if ( (unsigned __int8)sub_401830(&v10, &v8) )
    {
      if ( v3 )
        break;
    }
    printf(&v4);
  }
  printf(&Format);
  return 0;
}
  1. 函数首先定义了许多变量,然后将用户输入的user放入char变量v10中,将password放入v8中,进入sub_401000函数,发现其他函数,这几个函数应该是检查字母和数字的
char __cdecl sub_401000(const char *a1)
{
  signed int v2; // [esp+8h] [ebp-10h]
  signed int i; // [esp+Ch] [ebp-Ch]

  v2 = strlen(a1);
  for ( i = 0; i < v2; ++i )
  {
    if ( !isalnum(a1[i]) )
      return 0;
  }
  return 1;
}
  1. 观察sub_401090函数,应该是对byte_416050进行赋值
BYTE *__cdecl sub_401090(_BYTE *a1)
{
  _BYTE *result; // eax
  int v2; // [esp+Ch] [ebp-18h]
  int v3; // [esp+10h] [ebp-14h]
  _BYTE *v4; // [esp+14h] [ebp-10h]
  int i; // [esp+18h] [ebp-Ch]
  char v7; // [esp+20h] [ebp-4h]
  char v8; // [esp+22h] [ebp-2h]
  unsigned __int8 v9; // [esp+23h] [ebp-1h]

  for ( i = 0; i < 256; ++i )
    byte_416050[i] = i;
  v2 = 0;
  v9 = 0;
  v3 = 0;
  result = a1;
  v4 = a1;
  do
    LOBYTE(result) = *v4;
  while ( *v4++ );
  while ( v2 < 256 )
  {
    v8 = byte_416050[v2];
    v9 += v8 + a1[v3];
    v7 = byte_416050[v9];
    ++v3;
    byte_416050[v9] = v8;
    byte_416050[v2] = v7;
    result = (_BYTE *)v3;
    if ( v3 >= v4 - (a1 + 1) )
      v3 = 0;
    ++v2;
  }
  return result;
}
  1. 观察sub_401830函数,
bool __cdecl sub_401830(int a1, const char *a2)
{
  int v3; // [esp+18h] [ebp-22Ch]
  int v4; // [esp+1Ch] [ebp-228h]
  int v5; // [esp+28h] [ebp-21Ch]
  unsigned int v6; // [esp+30h] [ebp-214h]
  char v7; // [esp+36h] [ebp-20Eh]
  char v8; // [esp+37h] [ebp-20Dh]
  char v9; // [esp+38h] [ebp-20Ch]
  unsigned __int8 v10; // [esp+39h] [ebp-20Bh]
  unsigned __int8 v11; // [esp+3Ah] [ebp-20Ah]
  char v12; // [esp+3Bh] [ebp-209h]
  int v13; // [esp+3Ch] [ebp-208h] BYREF
  char v14; // [esp+40h] [ebp-204h] BYREF
  char v15[255]; // [esp+41h] [ebp-203h] BYREF
  char v16; // [esp+140h] [ebp-104h] BYREF
  char v17[255]; // [esp+141h] [ebp-103h] BYREF

  v4 = 0;
  v5 = 0;
  v11 = 0;
  v10 = 0;
  v16 = 0;
  memset(v17, 0, sizeof(v17));
  v14 = 0;
  memset(v15, 0, sizeof(v15));
  v9 = 0;
  v6 = 0;
  v3 = 0;
  while ( v6 < strlen(a2) )
  {
    if ( isdigit(a2[v6]) )
    {
      v8 = a2[v6] - 48;
    }
    else if ( isxdigit(a2[v6]) )
    {
      if ( *((_DWORD *)NtCurrentPeb()->SubSystemData + 3) != 2 )
        a2[v6] = 34;
      v8 = (a2[v6] | 0x20) - 87;
    }
    else
    {
      v8 = ((a2[v6] | 0x20) - 97) % 6 + 10;
    }
    __rdtsc();
    __rdtsc();
    v9 = v8 + 16 * v9;
    if ( !((int)(v6 + 1) % 2) )
    {
      *(&v14 + v3++) = v9;
      v9 = 0;
    }
    ++v6;
  }
  while ( v5 < 8 )
  {
    v10 += byte_416050[++v11];
    v12 = byte_416050[v11];
    v7 = byte_416050[v10];
    byte_416050[v10] = v12;
    byte_416050[v11] = v7;
    if ( ((int)NtCurrentPeb()->UnicodeCaseTableData & 0x70) != 0 )
      v12 = v10 + v11;
    *(&v16 + v5) = byte_416050[(unsigned __int8)(v7 + v12)] ^ *(&v14 + v4);
    if ( (unsigned __int8)*(_DWORD *)&NtCurrentPeb()->BeingDebugged )
    {
      v10 = -83;
      v11 = 43;
    }
    sub_401710(&v16, a1, v5++);
    v4 = v5;
    if ( v5 >= (unsigned int)(&v14 + strlen(&v14) + 1 - v15) )
      v4 = 0;
  }
  v13 = 0;
  sub_401470(&v16, &v13);
  return v13 == 0xAB94;
}

IDA中各种前缀:https://www.jianshu.com/p/c0afd9186610

sub_ 指令和子函数起点
locret_ 返回指令 
loc_ 指令
off_ 数据,包含偏移量
seg_ 数据,包含段地址值
asc_ 数据,ASCII字符串
byte_ 数据,字节(或字节数组)
word_ 数据,16位数据(或字数组)
dword_ 数据,32位数据(或双字数组)
qword_ 数据,64位数据(或4字数组)
flt_ 浮点数据,32位(或浮点数组)
dbl_ 浮点数,64位(或双精度数组)
tbyte_ 浮点数,80位(或扩展精度浮点数)
stru_ 结构体(或结构体数组)
algn_ 对齐指示
unk_ 未处理字节

IDA Pro7.0使用技巧总结:https://xz.aliyun.com/t/4205
C语言fflush()函数:清空文件缓冲区(或标准输入输出缓冲区)

posted @ 2021-09-25 22:24  超级想睡觉  阅读(218)  评论(0)    收藏  举报