注:常规处理,如upx脱壳不注明。
主要代码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
#include
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!}
shift+f12摸进主函数
极其耿直的硬算,算完结束
#include
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}
源码如下:
<html>
<head>
<title>FLARE On 2017title>
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 ("[email protected]" == 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
int main()
{//ABCDEFGHIZKLM
char a[] = "[email protected]";
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{[email protected]}
无脑异或嗷
#include
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{[email protected]}