main()

int __cdecl main(int argc, const char **argv, const char **envp)
{
  char s[24]; // [rsp+0h] [rbp-20h] BYREF
  int v5; // [rsp+18h] [rbp-8h]
  int i; // [rsp+1Ch] [rbp-4h]

  for ( i = 0; i <= 181; ++i )
    judge[i] ^= 0xCu;
  printf("Please input flag:");
  __isoc99_scanf("%20s", s);
  v5 = strlen(s);
  if ( v5 == 14 && (*judge)(s) )
    puts("Right!");
  else
    puts("Wrong!");
  return 0;
}

分析代码得知:

  • 程序开始时对judge函数执行了异或操作。
  • flag的长度为14。

关键是要获取judge函数的内容,它在运行时会进行自解密操作,静态分析无法窥探其真正内容。

SMC(self-Modifying Code),就是在真正执行某一段代码时,程序会对自身的该段代码进行自修改,只有在修改后的代码才是可汇编,可执行的。在程序未对该段代码进行修改以前,在静态分析状态下,均是不可读的字节码,IDA之类的反汇编器没法识别程序的正常逻辑。是一种反调试代码技术。

返回值函数名参数操作
voidPatchBytelong addr, long val设置虚拟地址addr处的一个字节值

和程序开头一样,也对其执行异或操作:

from idc_bc695 import * 

s = 0x600b00
for i in range(182):
	PatchByte(s+i,Byte(s+i)^0xC)

将有红色报错的代码按U(取消原来定义),再按 C(重新生成汇编代码),选中600B00-600BB5(judge 的起止位置)按P(重新生成 function)。

judge内容如下:

__int64 __fastcall judge(__int64 a1)
{
  char v2[5]; // [rsp+8h] [rbp-20h] BYREF
  char v3[9]; // [rsp+Dh] [rbp-1Bh] BYREF
  int i; // [rsp+24h] [rbp-4h]

  qmemcpy(v2, "fmcd", 4);
  v2[4] = 127;
  qmemcpy(v3, "k7d;V`;np", sizeof(v3));
  for ( i = 0; i <= 13; ++i )
    *(_BYTE *)(i + a1) ^= i;
  for ( i = 0; i <= 13; ++i )
  {
    if ( *(_BYTE *)(i + a1) != v2[i] )
      return 0LL;
  }
  return 1LL;
}

解密:

strr = [0x66,0x6D,0x63,0x64,0x7F,0x6B,0x37,0x64,0x3B,0x56,0x60,0x3B,0x6E,0x70]
for i in range(14):
    flag = chr(strr[i]^i)
    print(flag,end="")