X`NUCA 2022 unravelmfc

发布时间 2023-09-18 23:00:33作者: 浮小云
这应该是第八周第三道题,我记录一下我的做题过程,虽然有很多疑问
首先查壳
![Image description](https://bbs.xdsec.org/assets/files/2023-04-10/1681115143-134913-image.png)
Unknown EXE,不知道是个啥写的,010看一下吧,没发现有python这样的字符存在,那就ida打开
然后shift+f12先找字符串
有一个个`i_will_not_be_found`,一看就是出题人放的,果断双击后x交叉引用
```
int sub_599C80()
{
  int v0; // eax
  int v1; // eax
  int v2; // eax
  int v3; // eax
  unsigned int i; // [esp+118h] [ebp-54h]
  size_t v6; // [esp+124h] [ebp-48h]
  char *Str; // [esp+130h] [ebp-3Ch]
  char v8[32]; // [esp+13Ch] [ebp-30h] BYREF
  int v9; // [esp+168h] [ebp-4h]

  v0 = sub_579EA4("i_will_not_be_found");
  v1 = sub_5736A8(v0);
  sub_5761A0(v1);
  v9 = 0;
  if ( !NtCurrentPeb()->BeingDebugged )
  {
    v2 = sub_579EA4("you_can_not_find_me");
    v3 = sub_5736A8(v2);
    sub_56DE0B(v3);
  }
  Str = (char *)sub_577203(v8);
  v6 = j__strlen(Str);
  for ( i = 0; i < 0x292; ++i )
    byte_875188[i] ^= Str[i % v6];//SMC
  v9 = -1;
  sub_571628(v8);
  return 0;
}
```
好像是个SMC?先不管,交叉引用byte_875188看看谁调用了它![Image description](https://bbs.xdsec.org/assets/files/2023-04-10/1681115868-707561-image.png)
果然有,第二个双击跟进
```
bool __cdecl sub_599540(char *a1, unsigned int a2)
{
  size_t v2; // eax
  char v4; // [esp+Fh] [ebp-141h]
  char Buf1[68]; // [esp+D4h] [ebp-7Ch] BYREF
  unsigned int i; // [esp+118h] [ebp-38h]
  int v7[8]; // [esp+124h] [ebp-2Ch] BYREF
  __int16 v8; // [esp+144h] [ebp-Ch]
  char v9; // [esp+146h] [ebp-Ah]

  memset(v7, 0, sizeof(v7));
  v8 = 0;
  v9 = 0;
  for ( i = 0; i < a2; ++i )
  {
    v4 = *a1++;
    *((_BYTE *)v7 + i) = v4;
  }
  sub_57971F(v7, a2);
  ((void (__fastcall *)(char *, int *, unsigned int))byte_875188)(Buf1, v7, a2);
  v2 = j__strlen(Str);
  return j__memcmp(Buf1, Str, v2) == 0;
}
```
emmmm,return了一个比较函数的返回值,看样子是Buf1只要和Str相等返回值就为1了,emm,看看返回值有啥用,sub_599540交叉引用一下,来到这里
```
void __thiscall sub_5A1080(CWnd *this)
{
  void *v1; // esp
  int v2; // eax
  int v3; // eax
  const WCHAR *v4; // eax
  LPCWSTR lpText; // [esp+18h] [ebp-18Ch]
  char *lpCaption; // [esp+1Ch] [ebp-188h]
  const WCHAR *lpCaptiona; // [esp+1Ch] [ebp-188h]
  CHAR v8[4]; // [esp+20h] [ebp-184h] BYREF
  _RTC_ALLOCA_NODE *PAllocaInfoList; // [esp+12Ch] [ebp-78h]
  unsigned int v10; // [esp+138h] [ebp-6Ch]
  char *Str; // [esp+144h] [ebp-60h]
  int v12; // [esp+150h] [ebp-54h]
  wchar_t *String; // [esp+15Ch] [ebp-48h]
  UINT CodePage; // [esp+168h] [ebp-3Ch]
  int v15; // [esp+174h] [ebp-30h]
  char v16[12]; // [esp+180h] [ebp-24h] BYREF
  CWnd *v17; // [esp+18Ch] [ebp-18h]
  int v18; // [esp+1A0h] [ebp-4h]

  v17 = this;
  PAllocaInfoList = 0;
  if ( NtCurrentPeb()->BeingDebugged )
    sub_56F206();
  sub_57BDA8(4u);
  sub_573856(v16);
  v18 = 0;
  CWnd::GetDlgItem(v17, 1000);
  CWnd::GetWindowTextW(v16);
  v15 = 0;
  CodePage = sub_573608();
  v12 = 0;
  String = (wchar_t *)sub_5773F2(v16);
  if ( String )
  {
    v15 = j__wcslen(String) + 1;
    if ( v15 <= 0x3FFFFFFF )
    {
      v1 = alloca(2 * v15 + 36);
      lpText = (LPCWSTR)sub_5717A9(v8, String, 2 * v15, CodePage);
    }
    else
    {
      lpText = 0;
    }
    lpCaption = (char *)lpText;
  }
  else
  {
    lpCaption = 0;
  }
  Str = lpCaption;
  v10 = j__strlen(lpCaption) >> 1;
  if ( sub_57378E(lpCaption, v10) && (unsigned __int8)sub_56D4B0(&Str[v10], v10) )
  {
    v2 = sub_5768A8(&unk_87989C);
    lpCaptiona = (const WCHAR *)sub_57007A(v2);
    v3 = sub_57086D(aFlag);
    v4 = (const WCHAR *)sub_5782F2(v3);
    sub_579328(v4, lpCaptiona, 0);
  }
  v18 = -1;
  sub_57A8E5(v16);
}
```
我们刚刚的返回值就在最后那个if里,返回值为1才会执行里面的操作,if里的第三行好像就显示falg正确(aflag里存的是flag正确),那现在我们要做的就是,分析sub_57378E()和sub_56D4B0()这两个函数就行
(看样子是把字符串分成两部分了,v10>>1
先分析第一部分:
```
bool __cdecl sub_599540(char *a1, unsigned int a2)
{
  size_t v2; // eax
  char v4; // [esp+Fh] [ebp-141h]
  char Buf1[68]; // [esp+D4h] [ebp-7Ch] BYREF
  unsigned int i; // [esp+118h] [ebp-38h]
  int v7[8]; // [esp+124h] [ebp-2Ch] BYREF
  __int16 v8; // [esp+144h] [ebp-Ch]
  char v9; // [esp+146h] [ebp-Ah]

  memset(v7, 0, sizeof(v7));
  v8 = 0;
  v9 = 0;
  for ( i = 0; i < a2; ++i )
  {
    v4 = *a1++;
    *((_BYTE *)v7 + i) = v4;
  }
  RC4((int)v7, a2);
  ((void (__fastcall *)(char *, int *, unsigned int))byte_875188)(Buf1, v7, a2);
  v2 = j__strlen(Str);
  return j__memcmp(Buf1, Str, v2) == 0;
}
```
经分析对密钥是有一个类似RC4操作的,密钥是`sorry_you_are_wrong`,然后先把这个SMC解了吧(
```
int sub_599C80()
{
  int v0; // eax
  int v1; // eax
  int v2; // eax
  int v3; // eax
  unsigned int i; // [esp+118h] [ebp-54h]
  size_t v6; // [esp+124h] [ebp-48h]
  char *Str; // [esp+130h] [ebp-3Ch]
  char v8[32]; // [esp+13Ch] [ebp-30h] BYREF
  int v9; // [esp+168h] [ebp-4h]

  v0 = sub_579EA4("i_will_not_be_found");
  v1 = sub_5736A8(v0);
  sub_5761A0(v1);
  v9 = 0;
  if ( !NtCurrentPeb()->BeingDebugged )
  {
    v2 = sub_579EA4("you_can_not_find_me");
    v3 = sub_5736A8(v2);
    sub_56DE0B(v3);
  }
  Str = (char *)sub_577203(v8);
  v6 = j__strlen(Str);
  for ( i = 0; i < 0x292; ++i )
    byte_875188[i] ^= Str[i % v6];
  v9 = -1;
  sub_571628(v8);
  return 0;
}
```
```
from ida_bytes import *
addr =0x875188
key="you_can_not_find_me"
for i in range(0x292):
    patch_byte(addr+i,get_byte(addr+i)^ord(key[i%len(key)]))
```
奇怪,解出来是这样的
```
void __usercall sub_875231(int a1@<edx>, _BYTE *a2@<ecx>, int a3@<ebp>)
{
  unsigned int v3; // edi
  char v4; // bl
  char v5; // dl
  int v6; // ecx
  _BYTE *v7; // eax
  unsigned int v8; // ebx
  char v9; // cl
  unsigned int v10; // esi
  char v11; // dl
  char v12; // dl
  char v13; // cl
  char v14; // dl
  char v15; // cl

  v8 = *(_DWORD *)(a3 + 8);
  v7 = a2;
  v10 = 0;
  *(_DWORD *)(a3 - 4) = a1;
  v3 = v8 - 2;
  *(_DWORD *)(a3 - 8) = a2;
  if ( v8 != 2 )
  {
    do
    {
      v13 = *(_BYTE *)(a1 + v10);
      v12 = v13 & 3;
      v9 = (v13 >> 2) & 0x3F;
      v11 = 16 * v12;
      *v7 = v9 + 35;
      v15 = *(_BYTE *)(*(_DWORD *)(a3 - 4) + v10 + 1);
      v4 = v15 & 0xF;
      v5 = (v15 >> 4) & 0xF | v11;
      v6 = *(_DWORD *)(a3 - 4);
      v7[1] = v5 + 35;
      v14 = *(_BYTE *)(v6 + v10 + 2);
      v10 += 3;
      v7[2] = ((v14 >> 6) & 3 | (4 * v4)) + 35;
      v7[3] = (v14 & 0x3F) + 35;
      v7 += 4;
      a1 = *(_DWORD *)(a3 - 4);
    }
    while ( v10 < v3 );
    v8 = *(_DWORD *)(a3 + 8);
  }
  if ( v10 < v8 )
    JUMPOUT(0x87540C);
  JUMPOUT(0x875222);
}
```
怎么只对了前一部分,啊,抓狂,不会了(
分析第二个函数:
```
bool __cdecl sub_5996C0(char *a1, int a2)
{
  __int64 v3; // rax
  int v4; // [esp+10h] [ebp-144h]
  char v5; // [esp+13h] [ebp-141h]
  unsigned int j; // [esp+D8h] [ebp-7Ch]
  unsigned __int64 v7; // [esp+E4h] [ebp-70h]
  int v8; // [esp+ECh] [ebp-68h]
  int v9; // [esp+F0h] [ebp-64h]
  unsigned __int64 v10; // [esp+F4h] [ebp-60h]
  unsigned __int64 v11; // [esp+FCh] [ebp-58h]
  int v12[4]; // [esp+10Ch] [ebp-48h] BYREF
  unsigned int i; // [esp+11Ch] [ebp-38h]
  int v14[8]; // [esp+128h] [ebp-2Ch] BYREF
  __int16 v15; // [esp+148h] [ebp-Ch]
  char v16; // [esp+14Ah] [ebp-Ah]
  char *v17; // [esp+15Ch] [ebp+8h]

  v4 = *a1;
  v17 = a1 + 1;
  if ( v4 != 102 )
    return 0;
  memset(v14, 0, sizeof(v14));
  v15 = 0;
  v16 = 0;
  for ( i = 0; i < a2 - 1; ++i )
  {
    v5 = *v17++;
    *((_BYTE *)v14 + i) = v5;
  }
  for ( j = 0; j < 4; ++j )
  {
    sub_5751B5((int)&v14[2 * j], (int)v12);
    TEA((int)v12, (int)&dword_875048[4 * j]);
    *((_DWORD *)&v7 + 2 * j) = v12[0];
    *((_DWORD *)&v7 + 2 * j + 1) = 0;
    LODWORD(v3) = *((_DWORD *)&v7 + 2 * j);
    HIDWORD(v3) = *((_DWORD *)&v7 + 2 * j + 1);
    v3 <<= 32;
    *((_DWORD *)&v7 + 2 * j) = v3;
    *((_DWORD *)&v7 + 2 * j + 1) = HIDWORD(v3);
    HIDWORD(v3) = *((_DWORD *)&v7 + 2 * j + 1);
    *((_DWORD *)&v7 + 2 * j) |= v12[1];
    *((_DWORD *)&v7 + 2 * j + 1) = HIDWORD(v3);
  }
  return v8 == 798585087
      && v9 == -550095698
      && v7 < v10
      && v10 < v11
      && v10 - v7 == 4568540450738734457i64
      && v7 + v11 == 0x162F924623D2CAE0i64
      && v11 - v10 == 0x7C3C71F1B295D77Fi64;
}
```
这好像是个tea加密
```
unsigned int __fastcall sub_8754EF(unsigned int *a1, int *a2)
{
  unsigned int v2; // esi
  int v3; // ebx
  unsigned int v4; // eax
  int v5; // edi
  int v6; // edx
  unsigned int result; // eax
  int v8; // ecx
  unsigned int v9; // [esp-28h] [ebp-28h]
  int v11; // [esp-14h] [ebp-14h]
  int v12; // [esp-10h] [ebp-10h]
  int v13; // [esp-Ch] [ebp-Ch]
  int v14; // [esp-8h] [ebp-8h]

  v2 = *a1;
  v4 = a1[1];
  v14 = *a2;
  v8 = a2[1];
  v12 = a2[2];
  v3 = 32;
  v11 = v8;
  v13 = a2[3];
  v5 = 0;
  do
  {
    v5 += 607369562;
    v2 += (v5 + v4) ^ (v14 + 16 * v4) ^ (v8 + (v4 >> 5));
    v6 = (v5 + v2) ^ (v12 + 16 * v2) ^ (v13 + (v2 >> 5));
    v8 = v11;
    v9 = v6 + v4;
    --v3;
    v4 += v6;
  }
  while ( v3 );
  result = v9;
  *a1 = v2;
  a1[1] = v9;
  return result;
}
```
可以试着解出后半段的flag
```
#include<stdio.h>
#include<stdint.h>
int decrypto_Tea(uint32_t *a,uint32_t *key)
{
  uint32_t v2 =*a;
  uint32_t v4 =a[1],v14=*key,v8=key[1],v12=key[2],v13=key[3];
  int v3 =32;
  uint32_t v5 =0x86772b40;
  do{
      v3--;
      v4-=(v5 + v2) ^ (v12 + 16 * v2) ^ (v13 + (v2 >> 5));
       v2 -= (v5 + v4) ^ (v14 + 16 * v4) ^ (v8 + (v4 >> 5));
       v5 -= 0x2433B95A;
  }while(v3);
  *a=v2;
  a[1]=v4;
 
}
int main()
{
  uint32_t a[8]={0x2d46347f,0x5e79f6f4,0xDF3634AE,0x2F9970FF,0x6cacebd5,0x12c2fc6d,0xe8e95dc6,0xc558d3ec};
  uint32_t key[16] ={
    0xD9610D02, 0x2AADA57D, 0xA37537F1, 0xC29E3913, 0xD5942CE8, 0x608CCE66, 0x6D593422, 0x21E5D6F2,
    0xED3A9235, 0x9DAD62C4, 0x3856641B, 0x71F75B9D, 0xDCDEDAE8, 0xEAD2D1A0, 0xBAC4F564, 0xDA4772AC};
for(int i=0,j=0;i<8;i+=2,j+=4)
{
  decrypto_Tea(&a[i],&key[j]);
  printf("0x%x,",a[i]);
  printf("0x%x,",a[i+1]);
}
printf("\n");

puts(a);
return 0;
}
//f1cUlt_foR_THe_r0Ok1E_t0_REver5e
```