DMCTF 2020 re1
名字叫来点简单的算法题……Peid
查壳查算法,没查出来,进IDA
。
定位main
函数,重命名,一气呵成:
盲猜sub_485D1A
里面嵌套了strlen
,跟进去看看,应该差不多,flag
长度要求20
.
那就再进sub_4849EC
看看;
美化一下:
瞬间舒服多了……目测凯撒,直接上他:
ans=[]
a=[0x73,0x65,0x6D,0x66]
a=a[::-1]
for i in a:
ans.append(i)
a=[0x6D,0x75,0x7B,0x68]
a=a[::-1]
for i in a:
ans.append(i)
a=[0x76,0x5F,0x63,0x6B]
a=a[::-1]
for i in a:
ans.append(i)
a=[0x5F,0x6E,0x72,0x6C]
a=a[::-1]
for i in a:
ans.append(i)
a=[0x7D,0x68,0x6C,0x67]
a=a[::-1]
for i in a:
ans.append(i)
# ans=[102, 109, 101, 115, 104, 123, 117, 109, 107, 99, 95, 118, 108, 114, 110, 95, 103, 108, 104, 125]
for i in ans:
if i>=ord('a') and i<=ord('k'):
print(chr(i-2),end='')
elif i>=ord('o') and i<=ord('y'):
print(chr(i+1),end='')
elif i==ord('l') or i==ord('m'):
print("(",chr(i-2),chr(i),")",end='')
elif i==ord('n'):
print("(",chr(i),chr(i+1),")",end='')
else:
print(chr(i),end='')
# d( k m )ctf{v( k m )ia_w( j l )s( n o )_e( j l )f}
这个题貌似就是多解……经RX
验证……
DMCTF 2020 re4
DIE
查壳……没结果,拖进IDA
,查看字符串,定位main
函数:
根据红框框,盲猜地图题。 扣地图:
1 0 0 0 0 1 1 0 0 0 1 1 0 0 0 1 1 1 0 0 0 1 0 0 0 1 0 1 0 0 0 1 1 1 1 1 0 1 0 0 0 0 0 0 1 1 0 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 1
看逻辑:
手动走迷宫:
sdssdddsdwwwwdsdsssssdssds 20220002033330202222202202
执行一下:
GWCTF 2019 xxor
DIE
查一下,没什么……拖进IDA64
,woc
惊喜!没扣符号表!!!
找到main
函数,美化一下:
__int64 __fastcall main(int a1, char **a2, char **a3)
{
int i; // [rsp+8h] [rbp-68h]
int j; // [rsp+Ch] [rbp-64h]
__int64 v6[6]; // [rsp+10h] [rbp-60h] BYREF
__int64 v7[6]; // [rsp+40h] [rbp-30h] BYREF
v7[5] = __readfsqword(0x28u);
puts("Let us play a game?");
puts("you have six chances to input");
puts("Come on!");
v6[0] = 0LL;
v6[1] = 0LL;
v6[2] = 0LL;
v6[3] = 0LL;
v6[4] = 0LL;
for ( i = 0; i <= 5; ++i )
{
printf("%s", "input: ");
a2 = (char **)((char *)v6 + 4 * i);
__isoc99_scanf("%d", a2);
}
v7[0] = 0LL;
v7[1] = 0LL;
v7[2] = 0LL;
v7[3] = 0LL;
v7[4] = 0LL;
for ( j = 0; j <= 2; ++j )
{
dword_601078 = v6[j];
dword_60107C = HIDWORD(v6[j]);
a2 = (char **)&unk_601060;
sub_400686(&dword_601078, &unk_601060);
LODWORD(v7[j]) = dword_601078;
HIDWORD(v7[j]) = dword_60107C;
}
if ( (unsigned int)sub_400770(v7, a2) != 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");
return 0LL;
}__int64 __fastcall main(__int64 a1, char **a2, char **a3)
{
signed int i; // [rsp+8h] [rbp-68h]
signed int j; // [rsp+Ch] [rbp-64h]
__int64 input[5]; // [rsp+10h] [rbp-60h]
__int64 flag_enc[5]; // [rsp+40h] [rbp-30h]
unsigned __int64 v8; // [rsp+68h] [rbp-8h]
v8 = __readfsqword(0x28u);
puts("Let us play a game?");
puts("you have six chances to input");
puts("Come on!");
input[0] = 0LL;
input[1] = 0LL;
input[2] = 0LL;
input[3] = 0LL;
input[4] = 0LL;
for ( i = 0; i <= 5; ++i )
{
printf("%s", "input: ", (unsigned int)i);
__isoc99_scanf("%d", (char *)input + 4 * i);
}
flag_enc[0] = 0LL;
flag_enc[1] = 0LL;
flag_enc[2] = 0LL;
flag_enc[3] = 0LL;
flag_enc[4] = 0LL;
for ( j = 0; j <= 2; ++j )
{
tmp_0_ = input[j];
tmp_1_ = *((_DWORD *)input + j * 2 + 1);
//这里的tmp_0和tmp_1本身以为是两个毫不相干的变量,但是在后面的change函数那里,因为传入的是指针,所以发现对tmp_1也进行了处理,所以这里应该处理成为一个数组
change((unsigned int *)&tmp_0_, &table);
LODWORD(flag_enc[j]) = tmp_0_;
*((_DWORD *)flag_enc + j * 2 + 1) = tmp_1_;
}
if ( (unsigned int)check(flag_enc) != 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");
return 0LL;
}
思路比较清晰,输入以后change
函数处理,check
函数比较,出结果。
我们先来看看check
函数,美化:
signed __int64 __fastcall check(_DWORD *a1)
{
signed __int64 result; // rax
if ( a1[2] - a1[3] != 0x84A236FFLL || a1[3] + a1[4] != 0xFA6CB703LL || a1[2] - a1[4] != 0x42D731A8LL )
{
puts("Wrong!");
result = 0LL;
}
else if ( *a1 != 0xDF48EF7E || a1[5] != 0x84F30420 || a1[1] != 0x20CAACF4 )
{
puts("Wrong!");
result = 0LL;
}
else
{
puts("good!");
result = 1LL;
}
return result;
}
根据提示,z3
解方程:
from z3 import *
s=Solver()
x0 = Int('x0')
x1 = Int('x1')
x2 = Int('x2')
x3 = Int('x3')
x4 = Int('x4')
x5 = Int('x5')
s.add(x0==0xDF48EF7E)
s.add(x5==0x84F30420)
s.add(x1==0x20CAACF4)
s.add(x2-x3==0x84A236FF)
s.add(x3+x4==0xFA6CB703)
s.add(x2-x4==0x42D731A8)
if s.check() == sat:
m = s.model()
print(m)
'''
[x2 = 3774025685,
x3 = 1548802262,
x4 = 2652626477,
x1 = 550153460,
x5 = 2230518816,
x0 = 3746099070]
'''
那么相当于知道了flag_enc
,再看change
函数:
__int64 __fastcall change(unsigned int *ini, _DWORD *tables)
{
__int64 result; // rax
unsigned int var; // [rsp+1Ch] [rbp-24h]
unsigned int var_1; // [rsp+20h] [rbp-20h]
int tmp; // [rsp+24h] [rbp-1Ch]
unsigned int i; // [rsp+28h] [rbp-18h]
var = *ini;
var_1 = ini[1];
tmp = 0;
for ( i = 0; i <= 63; ++i )
{
tmp += 0x458BCD42;
var += (var_1 + tmp + 11) ^ ((var_1 << 6) + *tables) ^ ((var_1 >> 9) + tables[1]) ^ 0x20;
var_1 += (var + tmp + 20) ^ ((var << 6) + tables[2]) ^ ((var >> 9) + tables[3]) ^ 0x10;
}
*ini = var;
result = var_1;
ini[1] = var_1;
return result;
}
对change
函数的三行关键代码进行分析,发现var_1
的处理只与此时var
的值有关,其余都是常量;var
的处理只与此时var_1
值有关,其余都是常量。所以直接把加号变成减号就ok
了。
然后还有一点需要注意的就是在IDA
里面你的数据数据类型是什么,你在写exp
的时候数据就用什么数据类型,否则可能会出锅。
#include<bits/stdc++.h>
using namespace std;
int main(){
unsigned int flag_enc[5],flag[5];
flag_enc[0]=3746099070;flag_enc[1]=550153460;flag_enc[2]=3774025685;flag_enc[3]=1548802262;flag_enc[4]=2652626477;flag_enc[5]=2230518816;
unsigned int var[3];
unsigned int tables[4]={2,2,3,4};
for(int i=0;i<5;i+=2){
int tmp = 0x458BCD42*64;
var[0]=flag_enc[i];
var[1]=flag_enc[i+1];
for(int j=0;j<=0x3F;j++){
var[1] -= (var[0] + tmp + 20) ^ ((var[0] << 6) + tables[2]) ^ ((var[0] >> 9) + tables[3]) ^ 0x10;
var[0] -= (var[1] + tmp + 11) ^ ((var[1] << 6) + tables[0]) ^ ((var[1] >> 9) + tables[1]) ^ 0x20;
tmp-=0x458BCD42;
}
flag[i]=var[0];
flag[i+1]=var[1];
}
for(int i=0;i<6;i++)
printf("0x%x\n",flag[i]);
}
/*
0x666c61
0x677b72
0x655f69
0x735f67
0x726561
0x74217d
*/
再用sublime
处理一下,用python
稍微跑一下:
flag=[0x66,0x6c,0x61,0x67,0x7b,0x72,0x65,0x5f,0x69,0x73,0x5f,0x67,0x72,0x65,0x61,0x74,0x21,0x7d]
for i in flag:
print(chr(i),end='')
# flag{re_is_great!}