[网鼎杯 2020 青龙组]jocker

查壳无壳,直接进入IDA看,主函数如下

image-20260325220805297

简而言之,就是输入24个字符,然后再进行下一步的比对,看看其他调用的函数

char *__cdecl wrong(char *Str)
{
  char *result; // eax
  int i; // [esp+Ch] [ebp-4h]

  for ( i = 0; i <= 23; ++i )
  {
    result = &Str[i];
    if ( (i & 1) != 0 )
      Str[i] -= i;
    else
      Str[i] ^= i;
  }
  return result;
}
int __cdecl omg(char *Str)
{
  _DWORD dst[24]; // [esp+18h] [ebp-80h] BYREF
  int i; // [esp+78h] [ebp-20h]
  int v4; // [esp+7Ch] [ebp-1Ch]

  v4 = 1;
  qmemcpy(dst, &src_, sizeof(dst));
  for ( i = 0; i <= 23; ++i )
  {
    if ( Str[i] != dst[i] )
      v4 = 0;
  }
  if ( v4 == 1 )
    return puts("hahahaha_do_you_find_me?");
  else
    return puts("wrong ~~ But seems a little program");
}

此处的encrypt函数静态分析下是不可反编译的

  if ( !VirtualProtect(encrypt, 0xC8u, 4u, &flOldProtect) )
    exit(1);

VirtualProtect函数的作用就是暂时更改encrypt函数的权限,提升为可写权限,从而实现代码自修改

image-20260325221344852

  for ( i = 0; i <= 186; ++i )
    *((_BYTE *)encrypt + i) ^= 0x41u;
  encrypt(Destination);
  finally(Destination);

这个亦或就是实现代码自修改的核心步骤
然后我们在IDA中动态调试起来,断点下在encrypt(Destination);

image-20260325221610424

看到上面这个情况,直接选中encrypt函数的区域按U取消定义恢复成最原始的十六进制数据,再按C转化为代码,最后按P创建函数

image-20260325222011497

修好后的代码如下

int __cdecl encrypt(char *Destination)
{
  _DWORD dst[19]; // [esp+1Ch] [ebp-6Ch] BYREF
  int v3; // [esp+68h] [ebp-20h]
  int i; // [esp+6Ch] [ebp-1Ch]

  v3 = 1;
  qmemcpy(dst, &src__0, sizeof(dst));
  for ( i = 0; i <= 18; ++i )
  {
    if ( (char)(Destination[i] ^ Buffer[i]) != dst[i] )
    {
      puts("wrong ~");
      v3 = 0;
      exit(0);
    }
  }
  puts("come here");
  return v3;
}
Buffer[] = "hahahaha_do_you_find_me?"
dst[] = [0xe, 0xd, 0x9, 0x6, 0x13, 0x5, 0x58, 0x56, 0x3e, 0x6, 0xc, 0x3c, 0x1f, 0x57, 0x14, 0x6b, 0x57, 0x59, 0xd]

得到一半flag:

flag{d07abccf8a410c

再找找另外一半flag

下面还有个finally函数,按照上面的步骤修复
修复后:

int __cdecl sub_40159A(char *Destination)
{
  __time32_t Seed; // eax
  char %tp&:[7]; // [esp+13h] [ebp-15h] BYREF
  __int16 v4; // [esp+1Ah] [ebp-Eh]
  int v5; // [esp+1Ch] [ebp-Ch]

  strcpy(%tp&:, "%tp&:");
  Seed = time(0);
  srand(Seed);
  v5 = rand() % 100;
  %tp&:[6] = 0;
  v4 = 0;
  if ( (%tp&:[(unsigned __int8)%tp&:[5]] != Destination[(unsigned __int8)%tp&:[5]]) == v5 )
    return puts("Really??? Did you find it?OMG!!!");
  else
    return puts("I hide the last part, you will not succeed!!!");
}

这函数多少有些离谱,于是开始猜谜时刻

由于 flag 结尾一定是 "}",所以盲猜 v3 与某个数异或得到剩下的 flag

然后 v3 最后一位是 ":" 也就是 58,58 ^ '}' = 71,大胆猜测每一位都与 71 异或
exp:

ls =[0xe, 0xd, 0x9, 0x6, 0x13, 0x5, 0x58, 0x56, 0x3e, 0x6, 0xc, 0x3c, 0x1f, 0x57, 0x14, 0x6b, 0x57, 0x59, 0xd]
str="hahahaha_do_you_find_me?"
for i in range(len(ls)):
    print(chr(ls[i]^ord(str[i])),end='')
str2="%tp&:"
for i in range(len(str2)):
    print(chr(ord(str2[i])^71),end='')

flag:

flag{d07abccf8a410cb37a}
posted @ 2026-03-25 22:32  StarRise  阅读(8)  评论(0)    收藏  举报