buuctf 刮开有奖 wp

是个EXE文件首先打开看一下,只有一个带有刮开有奖的消息框,没有什么线索然后老套路拉进Exeinfo PE查看是32位的文件在这里插入图片描述拉进IDApro x86 看到 WinMain 当然毫不犹豫的进去看一下,然后F5查看一下伪代码,

在这里插入图片描述看到了GetDlgItemTextA函数,发现它在DialogFunc中,我们用F5载入它看看,

BOOL __stdcall DialogFunc(HWND hDlg, UINT a2, WPARAM a3, LPARAM a4)
{
  const char *v4; // esi@5
  const char *v5; // edi@5
  BOOL result; // eax@14
  int v7; // [sp+8h] [bp-20030h]@5
  int v8; // [sp+Ch] [bp-2002Ch]@5
  int v9; // [sp+10h] [bp-20028h]@5
  int v10; // [sp+14h] [bp-20024h]@5
  int v11; // [sp+18h] [bp-20020h]@5
  int v12; // [sp+1Ch] [bp-2001Ch]@5
  int v13; // [sp+20h] [bp-20018h]@5
  int v14; // [sp+24h] [bp-20014h]@5
  int v15; // [sp+28h] [bp-20010h]@5
  int v16; // [sp+2Ch] [bp-2000Ch]@5
  int v17; // [sp+30h] [bp-20008h]@5
  CHAR String; // [sp+34h] [bp-20004h]@4
  char v19; // [sp+35h] [bp-20003h]@6
  char v20; // [sp+36h] [bp-20002h]@5
  char v21; // [sp+37h] [bp-20001h]@5
  char v22; // [sp+38h] [bp-20000h]@5
  char v23; // [sp+39h] [bp-1FFFFh]@5
  char v24; // [sp+3Ah] [bp-1FFFEh]@5
  char v25; // [sp+3Bh] [bp-1FFFDh]@5
  char &Str; // [sp+10034h] [bp-10004h]@5
  char v27; // [sp+10035h] [bp-10003h]@5
  char v28; // [sp+10036h] [bp-10002h]@5

  if ( a2 == 272 )
  {
    result = 1;
  }
  else
  {
    if ( a2 != 273 )
      return 0;
    if ( (_WORD)a3 == 1001 )
    {
      memset(&String, 0, 0xFFFFu);
      GetDlgItemTextA(hDlg, 1000, &String, 0xFFFF);
      if ( strlen(&String) == 8 )
      {
        v7 = 90;
        v8 = 74;
        v9 = 83;
        v10 = 69;
        v11 = 67;
        v12 = 97;
        v13 = 78;
        v14 = 72;
        v15 = 51;
        v16 = 110;
        v17 = 103;
        sub_4010F0((int)&v7, 0, 10);
        memset(&&Str, 0, 0xFFFFu);
        &Str = v23;
        v28 = v25;
        v27 = v24;
        v4 = sub_401000((int)&&Str, strlen(&&Str));
        memset(&&Str, 0, 0xFFFFu);
        v27 = v21;
        &Str = v20;
        v28 = v22;
        v5 = sub_401000((int)&&Str, strlen(&&Str));
        if ( String == v7 + 34
          && v19 == v11
          && 4 * v20 - 141 == 3 * v9
          && v21 / 4 == 2 * (v14 / 9)
          && !strcmp(v4, "ak1w")
          && !strcmp(v5, "V1Ax") )
        {
          MessageBoxA(hDlg, "U g3t 1T!", "@_@", 0);
        }
      }
      return 0;
    }
    if ( (_WORD)a3 != 1 && (_WORD)a3 != 2 )
      return 0;
    EndDialog(hDlg, (unsigned __int16)a3);
    result = 1;
  }
  return result;
}

粗略的看一下我们可以知道我们要找的flag应该是string,长度为8;`

      memset(&String, 0, 0xFFFFu);
      GetDlgItemTextA(hDlg, 1000, &String, 0xFFFF);
      if ( strlen(&String) == 8

然后看第51行函数sub_4010F0在对v7~v17进行某种操作,进入sub_4010F0函数

int __cdecl sub_4010F0(int a1, int a2, int a3)
{
  int result; // eax@1
  int i; // esi@1
  int v5; // ecx@2
  int v6; // edx@2

  result = a3;
  for ( i = a2; i <= a3; a2 = i )
  {
    v5 = 4 * i;
    v6 = *(_DWORD *)(4 * i + a1);
    if ( a2 < result && i < result )
    {
      do
      {
        if ( v6 > *(_DWORD *)(a1 + 4 * result) )
        {
          if ( i >= result )
            break;
          ++i;
          *(_DWORD *)(v5 + a1) = *(_DWORD *)(a1 + 4 * result);
          if ( i >= result )
            break;
          while ( *(_DWORD *)(a1 + 4 * i) <= v6 )
          {
            if ( ++i >= result )
              goto LABEL_13;
          }
          if ( i >= result )
            break;
          v5 = 4 * i;
          *(_DWORD *)(a1 + 4 * result) = *(_DWORD *)(4 * i + a1);
        }
        --result;
      }
      while ( i < result );
    }
LABEL_13:
    *(_DWORD *)(a1 + 4 * result) = v6;
    sub_4010F0(a1, a2, i - 1);
    result = a3;
    ++i;
  }
  return result;
}

一步步分析这个有点太复杂了,我们将其转换成可执行c语言代码运行一下,记得把*(_DWORD*) 删掉,因为这是汇编的表示,然后将各种基址+偏移的表示也换成数组的寻址,如下

#include <stdio.h>
#include <string.h>

int  sub_4010F0(char* a1, int a2, int a3)
{
    int result; // eax
    int i; // esi
    int v5; // ecx
    int v6; // edx

    result = a3;                                 
    for (i = a2; i <= a3; a2 = i)
    {
        v5 = i;
        v6 = a1[i];
        if (a2 < result && i < result)
        {
            do
            {
                if (v6 > a1[result])
                {
                    if (i >= result)
                        break;
                    ++i;
                    a1[v5] = a1[result];
                    if (i >= result)
                        break;
                    while (a1[i] <= v6)
                    {
                        if (++i >= result)
                            goto LABEL_13;
                    }
                    if (i >= result)
                        break;
                    v5 = i;
                    a1[result] = a1[i];
                }
                --result;
            } while (i < result);
        }
    LABEL_13:
        a1[result] = v6;
        sub_4010F0(a1, a2, i - 1);
        result = a3;
        ++i;
    }
    return result;
}
int main(void)
{
    char str[] = "ZJSECaNH3ng";
    sub_4010F0(str,0,10);
    printf("%s", str);
	return 0;
}

执行后的结果为3CEHJNSZagn
这就是v7~v17执行后的所对应的字符串
回到DialogFunc函数,通过观察变量v7到v25定义时的地址(或者双击变量名),我们知道它们在地址中是相邻的`
在这里插入图片描述通过观察代码

  sub_4010F0((int)&v7, 0, 10);
        memset(&&Str, 0, 0xFFFFu);
        &Str = v23;
        v28 = v25;
        v27 = v24;
        v4 = sub_401000((int)&&Str, strlen(&&Str));
        memset(&&Str, 0, 0xFFFFu);
        v27 = v21;
        &Str = v20;
        v28 = v22;
        v5 = sub_401000((int)&&Str, strlen(&&Str));

那么可以理解,DialogFunc函数中,是把经过sub_4010F0处理后的字符串的倒数第3位到倒数第1位的值赋给v4,sub_401000是将倒数第6~倒数第4位赋给v5。

接下来就进入sub_401000看看了

代码如下

_BYTE *__cdecl sub_401000(int a1, signed int a2)
{
  int v2; // eax@1
  signed int v3; // esi@1
  size_t v4; // ebx@3
  _BYTE *v5; // eax@3
  _BYTE *v6; // edi@3
  signed int v7; // eax@5
  _BYTE *v8; // ebx@5
  int v9; // edi@8
  signed int v10; // edx@8
  signed int v11; // edi@11
  signed int v12; // eax@11
  signed int v13; // esi@11
  _BYTE *result; // eax@18
  _BYTE *v15; // [sp+Ch] [bp-10h]@3
  _BYTE *v16; // [sp+10h] [bp-Ch]@5
  signed int v17; // [sp+14h] [bp-8h]@11
  int v18; // [sp+18h] [bp-4h]@8

  v2 = a2 / 3;
  v3 = 0;
  if ( a2 % 3 > 0 )
    ++v2;
  v4 = 4 * v2 + 1;
  v5 = malloc(v4);
  v6 = v5;
  v15 = v5;
  if ( !v5 )
    exit(0);
  memset(v5, 0, v4);
  v7 = a2;
  v8 = v6;
  v16 = v6;
  if ( a2 > 0 )
  {
    while ( 1 )
    {
      v9 = 0;
      v10 = 0;
      v18 = 0;
      do
      {
        if ( v3 >= v7 )
          break;
        ++v10;
        v9 = *(_BYTE *)(v3++ + a1) | (v9 << 8);
      }
      while ( v10 < 3 );
      v11 = v9 << 8 * (3 - v10);
      v12 = 0;
      v17 = v3;
      v13 = 18;
      do
      {
        if ( v10 >= v12 )
        {
          *((_BYTE *)&v18 + v12) = (v11 >> v13) & 0x3F;
          v8 = v16;
        }
        else
        {
          *((_BYTE *)&v18 + v12) = 64;
        }
        *v8++ = byte_407830[*((_BYTE *)&v18 + v12)];
        v13 -= 6;
        ++v12;
        v16 = v8;
      }
      while ( v13 > -6 );
      v3 = v17;
      if ( v17 >= a2 )
        break;
      v7 = a2;
    }
    v6 = v15;
  }
  result = v6;
  *v8 = 0;
  return result;
}

同样是很复杂的代码,但是往下拉看见一个byte_407830,点进去看看,

在这里插入图片描述显而易见这是base64加密,
再次回到DialogFunc通过观察代码if判断语句判断完了就弹出一个MessageBoxA,这个 if 判断应该很关键,先是 v7 + 34,算一下,得到 U ( 51+34),String[0]便是U,然后 v19 == v11,V19排在String[1],所以String[1]是J,下面的两个strcmp应该是上面的base64加密后得到的结果与 ak1w 和 U1Ax 对比.

if ( String == v7 + 34
          && v19 == v11
          && 4 * v20 - 141 == 3 * v9
          && v21 / 4 == 2 * (v14 / 9)
          && !strcmp(v4, "ak1w")
          && !strcmp(v5, "V1Ax") )
        {
          MessageBoxA(hDlg, "U g3t 1T!", "@_@", 0);
        }

然后通过python脚本解密ak1w和V1Ax

import base64
str1 = 'ak1w'
str2 = 'V1Ax'
flag1 = base64.b64decode(str1)
flag2 = base64.b64decode(str2)
print(flag1)
print(flag2)

得到 jMp和WP1
然后就是谁前谁后的问题了,看if判断语句中的

&& 4 * v20 - 141 == 3 * v9
&& v21 / 4 == 2 * (v14 / 9)

应该是来验证的,我们算一下第一条,v9是’E’为69,j是106,W是87,一通计算下来,v20是W,那么就是WP1先.
再加上flag格式 即flag{UJWP1jMp}

  • 8
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值