BUUCTF逆向题练习记录(wp) --(2)

注:常规处理,如upx脱壳不注明。

[GWCTF 2019]xxor

主要代码1:

  for ( i = 0; i <= 5; ++i )
  {
    printf("%s", "input: ", (unsigned int)i);
    __isoc99_scanf("%d", (char *)&v6 + 4 * i);  // 每个存四个字符
  }
  v11 = 0LL;
  v12 = 0LL;
  v13 = 0LL;
  v14 = 0LL;
  v15 = 0LL;
  for ( j = 0; j <= 4; j += 2 )
  {
    dword_601078 = *((_DWORD *)&v6 + j);        // 每4个字符进行运算
    dword_60107C = *((_DWORD *)&v6 + j + 1);    // 每次两组
    sub_400686((unsigned int *)&dword_601078, &unk_601060);// unk_601060:2,3,4
    *((_DWORD *)&v11 + j) = dword_601078;
    *((_DWORD *)&v11 + j + 1) = dword_60107C;
  }
  if ( (unsigned int)sub_400770(&v11) != 1 )
  {
    puts("NO NO NO~ ");
    exit(0);
  }
  puts("Congratulation!\n");
  puts("You seccess half\n");
  puts("Do not forget to change input to hex and combine~\n");
  puts("ByeBye");

通过代码阅读可知,这里将输入拆成了6次,每次输入一个DWORD长度(unsigned int)然后以DWORD为单位进行运算。
那么根据逻辑可推sub400770这个位置的函数是check函数,进去看看:

signed __int64 __fastcall sub_400770(_DWORD *a1)
{
  signed __int64 result; // rax

  if ( a1[2] - a1[3] != 2225223423LL || a1[3] + a1[4] != 4201428739LL || a1[2] - a1[4] != 1121399208LL )
  {
    puts("Wrong!");
    result = 0LL;
  }
  else if ( *a1 != 0xDF48EF7E || a1[5] != 0x84F30420 || a1[1] != 550153460 )
  {
    puts("Wrong!");
    result = 0LL;
  }
  else
  {
    puts("good!");
    result = 1LL;
  }
  return result;
}

将结果仍python里,z3约束求解:

from z3 import*

x = Int('x')
y = Int('y')
z = Int('z')
solve(x-y==0x84A236FF,y+z==0xFA6CB703,x-z==0x42D731A8)
#[x = 3237154773, y = 1011931350, z = 3189497389]
#0xDF48EF7E,0x20CAACF4,3774025685,1548802262,2652626477,0x84F30420

而易得在check函数上面的函数sub_400686是变换函数,进去查看:

__int64 __fastcall sub_400686(unsigned int *a1, _DWORD *a2)
{
  __int64 result; // rax
  unsigned int v3; // [rsp+1Ch] [rbp-24h]
  unsigned int v4; // [rsp+20h] [rbp-20h]
  int v5; // [rsp+24h] [rbp-1Ch]
  unsigned int i; // [rsp+28h] [rbp-18h]

  v3 = *a1;
  v4 = a1[1];
  v5 = 0;
  for ( i = 0; i <= 0x3F; ++i )
  {
    v5 += 0x458BCD42;                           // 正:v5+=0x458bcd42
                                                // a1[0]+=(a1[1]+=11)^((a1[1]<<6)+2)^((a1[1]>>9)+2)^0x20
                                                // a1[1]+=(a1[0]+=11)^((a1[0]<<6)+3)^((a1[0]>>9)+4)^0x10
                                                // 
    v3 += (v4 + v5 + 11) ^ ((v4 << 6) + *a2) ^ ((v4 >> 9) + a2[1]) ^ 0x20;// 可抓1和0,可逆推v4->v3->v5->,,,,
    v4 += (v3 + v5 + 20) ^ ((v3 << 6) + a2[2]) ^ ((v3 >> 9) + a2[3]) ^ 0x10;
  }
  *a1 = v3;
  result = v4;
  a1[1] = v4;
  return result;
}

读变换逻辑逆推即可,脚本如下:

#include<stdio.h>
#include<iostream>
using namespace std;
int main()
{
	__int64 sum[6] = {3746099070, 550153460, 3774025685, 1548802262, 2652626477, 2230518816}; 
    unsigned int v3, v4;
	for(int count = 0; count <6; count+=2)
    {   
        int v5 = 1166789954*0x40;
        v3 = sum[count];
        v4 = sum[count+1];
    	for(int i = 0; i <=0x3f; ++i)
    	{
    		v4 -= (v3+v5+20)^((v3<<6)+3)^((v3>>9)+4)^0x10;
            v3 -= (v4+v5+11)^((v4<<6)+2)^((v4>>9)+2)^0x20;
		    v5 -= 1166789954;
		}
		sum[count] = v3;
		sum[count+1] = v4;
		printf("%x %x ",sum[count],sum[count+1]);
	}
	for (int i = 0; i < 6; ++i) {
       cout << *((char*)&sum[i] + 2) << *((char*)&sum[i] + 1) <<  * ((char*)&sum[i]);
    }
 }  

这里比较有意思的是位数都被砍了两位,最后其实是6组每组3位的字符。
然后我变换内输出那一段对我来说其实有点诡异。。。。输出第二个东西的时候不管设什么输出的都是0,但如果到循环外设置输出整个数组时又正常了。
flag{re_is_great!}

[GUET-CTF2019]re

shift+f12摸进主函数
极其耿直的硬算,算完结束

#include<stdio.h>

int main()
{
	int a[32] = {0x18db80,0x675390,0x383280,0x9f2a18,0x3cb070,0x4e67a0,	0x72eeda,0x54b610,0x340740,0xc692a6,0x5ce85d,0x784f77,0x8879b5,	0x4f529a,0x455806,0x37a0a0,0x9a58d0,0x9383b0,0x51dae2,0xcd73dc,	0x53bf30,0xdcf08c,0x627276,0x5f6820,0x7675a4,0x6fce58,0x856290,0x875fc4	,0x3e5bc0,0x8f0ac0,0x57e094};
	int b[32] = {0x9E77500,0x2B9740C0,0x154B2280,0x4009EFA8,0x1D28C5D0,	0x1EEEE220 , 0x183E61FC ,0x1189B150,0xa917900,0x26c8a46c,0x11c879cd,	0x170735c7,0x1a1f4ba5,0xedf7ce0,0x1a8bb24c,0xa6e1e00,0x3a7ba6d0,	0x1d633c10,0xf590a60,0x2dbecbfc,0x12a591b0,0x53b7250c,0x12d7e896,	0x24e54460,0x16360ec0,0x16461b88,0x1db2f210,0x1af8140c,0xc6c4740,0x1ebb4f40	,0x2ae8a844};
	for (int i = 0; i < 31; i++)
	{
		printf("%c",b[i]/a[i]);
	}
	printf("%c",a[])
 }
 //flag{e65421110b0a3099a1c039337} 
 //flag{e65421110b0a3099a1c039337}
 //flag{e165421110ba03099a1c039337}

欸还没结束呢(虚晃一枪)
因为根据校验函数读出来flag第六位缺少,手动爆破一波。
flag{e165421110ba03099a1c039337}

[FlareOn4]login

源码如下:


<!DOCTYPE Html />
<html>
    <head>
        <title>FLARE On 2017</title>
    </head>
    <body>
        <input type="text" name="flag" id="flag" value="Enter the flag" />
        <input type="button" id="prompt" value="Click to check the flag" />
        <script type="text/javascript">
            document.getElementById("prompt").onclick = function () {
                var flag = document.getElementById("flag").value;
                var rotFlag = flag.replace(/[a-zA-Z]/g, function(c){return String.fromCharCode((c <= "Z" ? 90 : 122) >= (c = c.charCodeAt(0) + 13) ? c : c - 26);});
                if ("PyvragFvqrYbtvafNerRnfl@syner-ba.pbz" == rotFlag) {
                    alert("Correct flag!");
                } else {
                    alert("Incorrect flag, rot again");
                }
            }
        </script>
    </body>
</html>

这里就是考一个基础的代码逻辑能力,第一个三目判断这个字符是大写还是小写,然后第二个三目在字母表中在前13还是后13(<=m,>m),并且注意这里字符无论是在前表还是后表,都已经先被+13了,于是第二个三目的结果:c,c-26可得是c+13,c-13。即,该字符若是在前表则其+13到后表,若是后表则其-13到前表。
写脚本逆向即可:

#include<stdio.h>

int main()
{//ABCDEFGHIZKLM
	char a[] = "PyvragFvqrYbtvafNerRnfl@syner-ba.pbz";
	for(int i = 0 ; i < 36; i++)
	{
	    if((a[i]>'M')&&(a[i]<='Z'))
	    	a[i] -= 13;
		else if((a[i]>'m')&&(a[i]<='z'))
			a[i] -= 13;
		else if((a[i]>='A')&&(a[i]<='Z')||(a[i]>='a')&&(a[i]<='z'))
	a[i] += 13;
	}
	printf("%s",a);
}

flag{ClientSideLoginsAreEasy@flare-on.com}

[FlareOn4]IgniteMe

无脑异或嗷

#include<stdio.h>

int main()
{
	int byte1[0x28] = {0xd,0x26,0x49,0x45,0x2a,0x17,0x78,0x44,0x2b,0x6c,0x5d,
	0x5e,0x45,0x12,0x2f,0x17,0x2b,0x44,0x6f,0x6e,0x56,0x9,0x5f,0x45,0x47,
	0x73,0x26,0xa,0xd,0x13,0x17,0x48,0x42,0x1,0x40,0x4d,0xc,2,0x69,0};
	int v1 = 4;
	char byte2[0x32];
	for(int i = 0x26; i >= 0; i--)
	{
		byte2[i]=byte1[i]^v1;
		v1 = byte1[i]^v1;
	}
	printf("%s",byte2);
}

flag{R_y0u_H0t_3n0ugH_t0_1gn1t3@flare-on.com}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值