[BUUCTF]-RE 刮开有奖wp

借鉴:BUUCTF 刮开有奖(特别详细了,尽自己全力理解所写)_别害怕我在的博客-CSDN博客_buuctf 刮开有奖title: BUUCTF 刮开有奖date: 2021年8月13日 15点23分tags: BUUCTFcategories: BUUCTF自己的心声(痛骂wp抄袭狗)这道题,其实有点坑,对于目前的我来说,还是有点难度的。在复盘之前,我想对网上一些直接抄袭别人文章的人说,可真tm不要脸啊。你若跟着别人的wp,把题做出来了,自己跟着软件啥的,实验成功之后,写一篇wp啊,抄袭别人的。主要tm一个字不改,也不说是抄袭的。本来做题没思路了,做不下去了,想看一篇高质量的wp,跟着大佬学一学,百度一下.https://blog.csdn.net/afanzcf/article/details/119682630

本题给的是一个exe文件,不管怎样先点开看看

得到的是这样一个弹窗,点击没有反应,也没有输入框,但一按回车就直接闪退

1.用exeinfope看看有没有壳

 OK,一眼看过去是一个32位用c++写的程序

2.打开ida看看

INT_PTR __stdcall DialogFunc(HWND hDlg, UINT a2, WPARAM a3, LPARAM a4)
{
  const char *v4; // esi
  const char *v5; // edi
  int v7[2]; // [esp+8h] [ebp-20030h] BYREF
  int v8; // [esp+10h] [ebp-20028h]
  int v9; // [esp+14h] [ebp-20024h]
  int v10; // [esp+18h] [ebp-20020h]
  int v11; // [esp+1Ch] [ebp-2001Ch]
  int v12; // [esp+20h] [ebp-20018h]
  int v13; // [esp+24h] [ebp-20014h]
  int v14; // [esp+28h] [ebp-20010h]
  int v15; // [esp+2Ch] [ebp-2000Ch]
  int v16; // [esp+30h] [ebp-20008h]
  CHAR String[65536]; // [esp+34h] [ebp-20004h] BYREF
  char v18[65536]; // [esp+10034h] [ebp-10004h] BYREF

  if ( a2 == 272 )
    return 1;
  if ( a2 != 273 )
    return 0;
  if ( (_WORD)a3 == 1001 )
  {
    memset(String, 0, 0xFFFFu);
    GetDlgItemTextA(hDlg, 1000, String, 0xFFFF);
    if ( strlen(String) == 8 )
    {
      v7[0] = 90;
      v7[1] = 74;
      v8 = 83;
      v9 = 69;
      v10 = 67;
      v11 = 97;
      v12 = 78;
      v13 = 72;
      v14 = 51;
      v15 = 110;
      v16 = 103;
      sub_4010F0(v7, 0, 10);
      memset(v18, 0, 0xFFFFu);
      v18[0] = String[5];
      v18[2] = String[7];
      v18[1] = String[6];
      v4 = (const char *)sub_401000(v18, strlen(v18));
      memset(v18, 0, 0xFFFFu);
      v18[1] = String[3];
      v18[0] = String[2];
      v18[2] = String[4];
      v5 = (const char *)sub_401000(v18, strlen(v18));
      if ( String[0] == v7[0] + 34
        && String[1] == v10
        && 4 * String[2] - 141 == 3 * v8
        && String[3] / 4 == 2 * (v13 / 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);
  return 1;
}

简单看下来string应该就是我们要的flag

并且strlen(string) == 8我们可以得知flag是八位

看到一个叫sub_4010F0的函数点进去看看

int __cdecl sub_4010F0(int 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 = 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;
}

不出意外这是一个给v7重定义的函数,对其进行逆向得

在这里,将伪代码转变为c语言的时候有类似于*(_DWORD *)(a1 + 4 * result)这样一段不知道该如何改写成C,查询过后这里直接借用 @别害怕我在 大佬wp中的解释

nt占四个字节,所以需要*4.如果是char类型,就不需要.

在这里,我也是找到一点资料。百度一下数组寻址公式

从这里,我们知道a1+4*i,也就是a1【i】,a1+4 * result,也就是a1【result】。

将伪代码的寻址方式改为数组寻址,然后将*(_DWORD*) 删掉,因为这是汇编的表示。

所以伪代码变成了C语言代码。

#include<stdio.h>
int gkyj(char* a1,int a2,int a3){
	int result,i,v5,v6;
		result = a3;
		for(i = a2;i<=a3;a2 = i){
			v5 = 4*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 = 4*i;
						a1[result] = a1[i];
					}
					--result;
				}while(i<result);
			}
			LABEL_13:
				a1[result] = v6;
				gkyj(a1,a2,i-1);
				result = a3;
				++i;	
		}
		return result;
}

int main()
{
	char str[] = "ZJSECaNH3ng";
	gkyj(str,0,10);
	printf("%s",str);
	
	return 0;
}

 由此可以得到v7被改写为“3CEHJNSZagn”

memset(v18, 0, 0xFFFFu);
v18[0] = String[5];
v18[2] = String[7];
v18[1] = String[6];
v4 = (const char *)sub_401000(v18, strlen(v18));
memset(v18, 0, 0xFFFFu);
v18[1] = String[3];
v18[0] = String[2];
v18[2] = String[4];
v5 = (const char *)sub_401000(v18, strlen(v18));

这看着是一个给v4和v5定义的过程

最后是一个if函数,通过对这个if逆向我们应该就能得到flag了

if ( String[0] == v7[0] + 34
        && String[1] == v10
        && 4 * String[2] - 141 == 3 * v8
        && String[3] / 4 == 2 * (v13 / 9)
        && !strcmp(v4, "ak1w")
        && !strcmp(v5, "V1Ax") )
      {

3.看看String里有没有什么线索

看到了熟悉的base64加密的特征

结合上面v4和v5的定义以及最后if对v4和v5的比较,我们可以得知v4,v5定义的过程是一个base64加密的过程。通过在线base64解密:BASE64加密解密,我们可以得到加密前的v4和v5

即v4 = “jMp”,v5 = "WP1"

到这里,可以总结归纳一下我们现在有的东西

v7 = "3CEHJNSZagn"

v4 = "jMp"

v5 = "WP1"

String是我们要求的

所以通过最后的if函数,我们来求string的内容

第一句:String[0] == v7[0] + 34

这里的v7【0】,就是上面10个字符的第一个字符,我们通过加密函数之后,v7【0】由一开始的Z变成了3.

3的ASCII码是51,51 + 34 = 85,85的ASCII码对应的是大写的 U,所以String【0】对应U。

第二句:String[1] == v10

v10在之前没加密的时候,是排第五位,我们看看加密之后的第五位是谁,3CEHJNSZagn,可以看到,加密之后的第五位是 J,所以String【1】是J。

第三句:4 * String[2] - 141 == 3 * v8,v8在没加密之前,是排第三位,先看看加密之后的第三位是谁,可以看到是E,E的ASCII码是69,所以3*69 + 141 / 4 = 87 ,ASCII为W,String【2】是E。

第四句:String[3] / 4 == 2 * (v13 / 9),看到v13没加密之前排到数第四位,看看加密之后的到数第四位是谁,是Z,Z的ASCII是90,所以2*(90/9)*4 = 80 ,ASCII为P,String【3】是Z。

后面四个字符,就是base64加密的那几个,可以看到第三第四字符已经是WP了,说明,WP1在前,jMp在后。

将他们拼接在一起,得到,UJWP1jMp。

带上flag{},得到flag{UJWP1jMp}。
 

  • 4
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值