NSSCTF Round#X Basic RE专场个人wp
总体做下来感觉挺简单的,就是我太菜了呜呜呜
Real Ezcheck
摸了个2血
ida打开,直奔string找abab.bin,顺利找到主函数
简单逆一下各个函数命个名
a2的四个值就是time64()>> 8的值
核心check:tea函数
函数的执行流很易懂,最普通的tea函数,但是输入只有两个数字和key
动态调试可以发现,a1就是输入的俩值
题目给的2月15日时候的值是:9811af0d 8df137f
而在运行流中
int a1[] = {0x9811af0d,0x8df137f};
int a2[] = {time,time,time,time};
python简单看一下现在的时间
import time
print(0x641e63 << 8)
print(time.time())
print(time.localtime(0x641e63 << 8))
a = time.strptime("2023-02-15 00:00:00", "%Y-%m-%d %H:%M:%S")
print(hex(int(time.mktime(a)) >> 8))
# 0x63ebb0
a = time.strptime("2023-02-16 00:00:00", "%Y-%m-%d %H:%M:%S")
print(hex(int(time.mktime(a)) >> 8))
# 0x63ed01
然后我还浪费了点时间写tea的解密,写到一半反应过来,那么小的范围,爆破就行了
于是exp如下,基本上源码照搬就行。
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<conio.h>
#include<time.h>
#include <stdbool.h>
#include <io.h>
#include <stdint.h>
#include <stdbool.h>
#include <zconf.h>
#include <ctype.h>
#include "ida.h"
int __fastcall file_decode(const char *a1, const char *a2, int *a3, unsigned __int64 a4)
{
FILE *Stream; // [rsp+28h] [rbp+8h]
FILE *v6; // [rsp+48h] [rbp+28h]
unsigned __int64 i; // [rsp+68h] [rbp+48h]
int v8; // [rsp+84h] [rbp+64h]
Stream = fopen(a1, "rb");
v6 = fopen(a2, "wb");
if ( !Stream || !v6 )
return puts("Error opening input/output files.\n");
for ( i = 0; ; i = (i + 1) % a4 )
{
v8 = fgetc(Stream);
if ( v8 == -1 )
break;
fputc(a3[i] ^ v8, v6);
}
fclose(Stream);
return fclose(v6);
}
__int64 __fastcall hex2int10(unsigned int a1, int *a2, int len)
{
int i; // [rsp+24h] [rbp+4h]
for ( i = len - 1; a1 && i >= 0; --i ) {
a2[i] = a1 % 0xA;
a1 /= 0xAu;
}
while ( i >= 0 ) {
a2[i] = 0;
--i;
}
return 0;
}
int decode_tea(__int32 key_get, unsigned int *a1){
__int32 key[4] = {key_get,key_get,key_get,key_get};
unsigned int tea_sum;
unsigned int v3; // [rsp+24h] [rbp+4h]
unsigned int v4; // [rsp+44h] [rbp+24h]
v3 = *a1;
v4 = a1[1];
tea_sum = 0;
for (int i = 0; i < 0x20; ++i ){
tea_sum -= 0x61C88647;
v3 += (key[1] + (v4 >> 5)) ^ (tea_sum + v4) ^ (key[0] + 16 * v4);
v4 += (key[3] + (v3 >> 5)) ^ (tea_sum + v3) ^ (key[2] + 16 * v3);
}
*a1 = v3;
a1[1] = v4;
return 0;
}
int encode_tea(__int32 key_get, unsigned int *a1){
__int32 key[4] = {key_get,key_get,key_get,key_get};
unsigned int tea_sum;
unsigned int v3; // [rsp+24h] [rbp+4h]
unsigned int v4; // [rsp+44h] [rbp+24h]
v3 = *a1;
v4 = a1[1];
tea_sum = 0xC6EF3720;
for (int i = 0; i < 0x20; ++i ){
v4 -= (key[3] + (v3 >> 5)) ^ (tea_sum + v3) ^ (key[2] + 16 * v3);
v3 -= (key[1] + (v4 >> 5)) ^ (tea_sum + v4) ^ (*key + 16 * v4);
tea_sum += 0x61C88647;
}
*a1 = v3;
a1[1] = v4;
return 0;
}
int run() {
__int32 key_min = 0x63ebb0;
__int32 key_max = 0x63ed01;
HMODULE hModule;
__int64 (*flag)(void);
for (int i = key_min; i < key_max; ++i) {
unsigned int a1[2] = {0x9811af0d, 0x8df137f};
int a3[15];
hModule = LoadLibraryW(L"Dll2.dll");
if ( hModule )
{
flag = GetProcAddress(hModule, "flag");
if ( flag )
{
printf("NSSCTF{");
flag();
printf("}");
FreeLibrary(hModule);
break;
}
FreeLibrary(hModule);
}
encode_tea(i,a1);
printf("%u,%u\n",a1[0],a1[1]);
hex2int10(a1[0] + a1[1], a3, 10);
file_decode("abab.bin",
"Dll2.dll",
a3, 0xAu);
}
return 0;
}
int main(){
run();
return 0;
}
得到flag:NSSCTF{WOw_u_cr4ck_1t}
ez_z3
这题如题所示,就是个简单的z3规约,会写z3的代码就行
出题人给了个hint:ez_z3 小余的专属魔改壳,当然要到16进制工具里改回去啦
代码中也是很明显的UPX壳痕迹,直接拖进kali upx -d 搞定看源码
全部有用的变量、函数都补上了易懂的命名(对我来说)
先看到对输入flag的check1
看起来只是个平方循环计算,也许可以用z3(一开始我的沙雕想法),后来是用爆破解的,数字很小
z3计算的就不截图了,放代码在这让大家体会一下多长就行(z3 yyds!)
from z3 import *
a1 = [Int('n%s' % i) for i in range(20)]
x = Solver() # 2、初始化一个Solver类
x.add((20 * a1[19] * 19 * a1[18]
+ 14 * a1[13]
+ 13 * a1[12]
+ 11 * a1[10] * 10 * a1[9]
+ 30 * a1[5]
+ 5 * a1[4]
+ a1[0]
+ 2 * a1[1]
- 3 * a1[2]
- 4 * a1[3]
- 7 * a1[6]
+ 8 * a1[7]
- 9 * a1[8]
- 12 * a1[11]
- 16 * a1[15] * 15 * a1[14]
- 17 * a1[16]
- 18 * a1[17]) == 2582239)
x.add((20 * a1[19] * 19 * a1[18]
+ 14 * a1[13]
+ 13 * a1[12]
+ 11 * a1[10] * 10 * a1[9]
+ 30 * a1[5]
- 7 * a1[6]
+ 8 * a1[7]
- 9 * a1[8]
+ 5 * a1[4]
+ 3 * a1[2]
+ 2 * a1[1] * a1[0]
- 4 * a1[3]
- 12 * a1[11]
- 16 * a1[15] * 15 * a1[14]
- (18 * a1[17]
+ 17 * a1[16])) == 2602741)
x.add((19 * a1[18]
+ 18 * a1[17]
+ 14 * a1[13] * 13 * a1[12]
+ 12 * a1[11] * 11 * a1[10]
+ 9 * a1[8]
+ 7 * a1[6] * 30 * a1[5]
+ a1[0]
- 2 * a1[1]
- 4 * a1[3] * 3 * a1[2]
- 5 * a1[4]
+ 8 * a1[7]
- 10 * a1[9]
- 15 * a1[14]
- 17 * a1[16] * 16 * a1[15]
- 20 * a1[19]) == 2668123)
x.add((20 * a1[19] * 19 * a1[18]
+ 14 * a1[13]
+ (13 * a1[12] + 11 * a1[10] - 12 * a1[11]) * 10 * a1[9]
+ 30 * a1[5]
+ 5 * a1[4]
+ a1[0]
+ 2 * a1[1]
- 3 * a1[2]
- 4 * a1[3]
- 7 * a1[6]
+ 8 * a1[7]
- 9 * a1[8]
- 16 * a1[15] * 15 * a1[14]
- 17 * a1[16]
- 18 * a1[17]) == 2520193)
x.add((18 * a1[17]
+ 17 * a1[16]
+ 15 * a1[14]
+ 13 * a1[12] * 12 * a1[11]
+ 10 * a1[9]
+ 9 * a1[8] * 8 * a1[7]
+ 3 * a1[2] * 2 * a1[1] * a1[0]
- 4 * a1[3]
- 5 * a1[4]
- 30 * a1[5]
- 7 * a1[6]
- 11 * a1[10]
- 14 * a1[13]
- 16 * a1[15]
- 19 * a1[18]
- 20 * a1[19]) == 8904587)
x.add((18 * a1[17]
+ 7 * a1[6] * 30 * a1[5] * 5 * a1[4]
+ 4 * a1[3]
+ 8 * a1[7]
+ a1[0]
- 2 * a1[1]
- 3 * a1[2]
- 9 * a1[8]
- 11 * a1[10] * 10 * a1[9]
- 16 * a1[15] * (13 * a1[12] + 12 * a1[11] - 14 * a1[13] - 15 * a1[14])
- 17 * a1[16]
- 19 * a1[18]
- 20 * a1[19]) == 1227620874)
x.add((20 * a1[19] * 19 * a1[18]
+ 17 * a1[16]
+ 14 * a1[13]
+ 13 * a1[12]
+ 12 * a1[11] * 11 * a1[10] * 10 * a1[9]
+ 7 * a1[6] * 30 * a1[5]
+ 5 * a1[4]
+ 3 * a1[2]
+ a1[0]
+ 2 * a1[1]
+ 4 * a1[3]
+ 8 * a1[7]
- 9 * a1[8]
- 16 * a1[15] * 15 * a1[14]
- 18 * a1[17]) == 1836606059)
x.add((20 * a1[19] * 19 * a1[18]
+ 16 * a1[15] * 15 * a1[14]
+ 14 * a1[13]
+ 13 * a1[12]
+ 12 * a1[11]
+ 7 * a1[6] * 30 * a1[5]
+ 5 * a1[4]
+ 2 * a1[1] * a1[0]
- 3 * a1[2]
+ 4 * a1[3]
+ 8 * a1[7]
- 9 * a1[8]
- 10 * a1[9]
- 11 * a1[10]
- 17 * a1[16]
- 18 * a1[17]) == 8720560)
x.add((20 * a1[19] * 19 * a1[18]
+ 14 * a1[13]
+ 13 * a1[12]
+ 11 * a1[10] * (10 * a1[9] + 30 * a1[5] + 5 * a1[4] + 4 * a1[3] - 7 * a1[6] + 8 * a1[7] - 9 * a1[8])
+ a1[0]
+ 2 * a1[1]
- 3 * a1[2]
- 12 * a1[11]
- (16 * a1[15] - 17 * a1[16] - 18 * a1[17]) * 15 * a1[14]) == 11387045)
x.add((20 * a1[19] * 19 * a1[18]
+ 16 * a1[15] * 15 * a1[14]
+ 14 * a1[13]
+ 11 * a1[10] * 10 * a1[9]
+ 9 * a1[8]
+ 3 * a1[2]
+ a1[0]
- 2 * a1[1]
+ 4 * a1[3]
- 5 * a1[4]
- 30 * a1[5]
- 7 * a1[6]
+ 8 * a1[7]
- 12 * a1[11]
- 13 * a1[12]
- 17 * a1[16]
- 18 * a1[17]) == 7660269)
x.add((20 * a1[19] * 19 * a1[18]
+ 14 * a1[13]
+ 13 * a1[12]
+ 11 * a1[10] * 10 * a1[9]
- 12 * a1[11]
+ a1[0]
+ 2 * a1[1]
- (4 * a1[3] * 3 * a1[2]
- 5 * a1[4]
- 30 * a1[5])
- 7 * a1[6]
+ 8 * a1[7]
- 9 * a1[8]
- 16 * a1[15] * 15 * a1[14]
- 17 * a1[16]
- 18 * a1[17]) == 2461883)
x.add((14 * a1[13]
+ 11 * a1[10] * 10 * a1[9]
+ 9 * a1[8] * 8 * a1[7]
+ 7 * a1[6]
+ 2 * a1[1] * a1[0]
- 4 * a1[3] * 3 * a1[2]
- 5 * a1[4]
- 30 * a1[5]
- 12 * a1[11]
- 13 * a1[12]
- 15 * a1[14]
- 17 * a1[16] * 16 * a1[15]
- 18 * a1[17]
- 19 * a1[18]
- 20 * a1[19]) == -966296)
x.add((14 * a1[13]
+ 13 * a1[12]
+ (11 * a1[10] * 10 * a1[9] + 30 * a1[5] + 5 * a1[4] + 3 * a1[2] + 4 * a1[3] - 7 * a1[6] + 8 * a1[7] - 9 * a1[8])
* 2
* a1[1]
+ a1[0]
- 12 * a1[11]
- 15 * a1[14]
- 16 * a1[15]
- 17 * a1[16]
- 18 * a1[17]
- 20 * a1[19] * 19 * a1[18]) == 254500223)
x.add((16 * a1[15] * 15 * a1[14]
+ 14 * a1[13]
+ 11 * a1[10] * 10 * a1[9]
+ 7 * a1[6] * 30 * a1[5]
+ a1[0]
- 2 * a1[1]
- 3 * a1[2]
- 5 * a1[4] * 4 * a1[3]
+ 8 * a1[7]
- 9 * a1[8]
- 12 * a1[11]
- 13 * a1[12]
- 17 * a1[16]
- 18 * a1[17]
- 19 * a1[18]
- 20 * a1[19]) == 6022286)
x.add((18 * a1[17]
+ 16 * a1[15]
- 17 * a1[16]
+ 14 * a1[13]
+ 12 * a1[11]
+ 11 * a1[10] * 10 * a1[9]
+ 30 * a1[5]
+ 5 * a1[4]
+ 4 * a1[3] * 3 * a1[2]
+ 2 * a1[1] * a1[0]
- 9 * a1[8] * 8 * a1[7] * 7 * a1[6]
- 13 * a1[12]
- 15 * a1[14]
- 19 * a1[18]
- 20 * a1[19]) == -636956022)
x.add((20 * a1[19] * 19 * a1[18]
+ 13 * a1[12]
+ 12 * a1[11]
+ 11 * a1[10] * 10 * a1[9]
+ 7 * a1[6]
+ 30 * a1[5]
+ 5 * a1[4]
+ 3 * a1[2] * 2 * a1[1] * a1[0]
- 4 * a1[3]
- 9 * a1[8] * 8 * a1[7]
- 14 * a1[13]
- 15 * a1[14]
- 16 * a1[15]
- 17 * a1[16]
- 18 * a1[17]) == 10631829)
x.add((20 * a1[19] * 19 * a1[18]
+ 16 * a1[15]
- 17 * a1[16]
- 18 * a1[17]
+ 15 * a1[14] * 14 * a1[13]
+ 13 * a1[12]
+ 11 * a1[10] * 10 * a1[9]
- 12 * a1[11]
+ 7 * a1[6]
+ (4 * a1[3] - 5 * a1[4] - 30 * a1[5]) * 3 * a1[2]
+ a1[0]
+ 2 * a1[1]
+ 8 * a1[7]
- 9 * a1[8]) == 6191333)
x.add((14 * a1[13]
+ 10 * a1[9] * 9 * a1[8] * 8 * a1[7]
+ 5 * a1[4]
+ 4 * a1[3] * 3 * a1[2]
+ 2 * a1[1] * a1[0]
- 7 * a1[6] * 30 * a1[5]
- 11 * a1[10]
- 13 * a1[12] * 12 * a1[11]
- 16 * a1[15] * 15 * a1[14]
- 18 * a1[17] * 17 * a1[16]
- 20 * a1[19] * 19 * a1[18]) == 890415359)
x.add((20 * a1[19]
+ 19 * a1[18]
+ 18 * a1[17]
+ 16 * a1[15]
- 17 * a1[16]
+ 12 * a1[11]
+ 11 * a1[10]
+ 10 * a1[9]
+ 9 * a1[8]
+ 30 * a1[5]
+ a1[0]
+ 4 * a1[3] * 3 * a1[2] * 2 * a1[1]
- 5 * a1[4]
- 7 * a1[6]
+ 8 * a1[7]
- 13 * a1[12]
- 14 * a1[13]
- 15 * a1[14]) == 23493664)
x.add((20 * a1[19] * 19 * a1[18]
+ 13 * a1[12]
+ 12 * a1[11]
+ 10 * a1[9]
+ 3 * a1[2] * 2 * a1[1]
+ a1[0]
- 4 * a1[3]
- 5 * a1[4]
+ 8 * a1[7] * 7 * a1[6] * 30 * a1[5]
- 9 * a1[8]
- 11 * a1[10]
- 14 * a1[13]
- 16 * a1[15] * 15 * a1[14]
- 17 * a1[16]
- 18 * a1[17]) == 1967260144)
for i in a1:
x.add(i >= 0)
x.add(i <= 0xff)
if x.check() == z3.sat:
# model() 返回最后一个 check() 的 model
# decls() 返回 model 包含了所有符号的列表
tmp = x.model()
print(tmp)
最后跑出来的是这样的
[n5 = 97,
n11 = 115,
n12 = 102,
n17 = 108,
n13 = 97,
n9 = 115,
n10 = 105,
n18 = 97,
n2 = 104,
n15 = 107,
n4 = 104,
n0 = 104,
n16 = 102,
n14 = 99,
n8 = 105,
n7 = 104,
n6 = 116,
n3 = 97,
n1 = 97,
n19 = 103]
然后看下一个函数是怎么调这些内容的
一个简单的倒序xor
结合一下写最后的解码如下:
n_list = [n0, n1, n2, n3, n4, n5, n6, n7, n8, n9, n10, n11, n12, n13, n14, n15, n16, n17, n18, n19]
data_list1 = [2937, 121, 25875, 39673, 30651, 2375, 14193, 113544, 19649, 109032, 95,
25875, 19649, 2375, 601, 107848, 95, 20301, 19649, 4704][::-1]
check_list_1 = [7, 7, 7, 9, 5, 6, 7, 7, 7, 9, 7, 7, 5, 7, 7, 7, 5, 7, 9, 7]
flag = []
for i in range(20):
for k in range(128):
a2 = check_list_1[i]
k1 = k
sum = 1
while a2:
if a2 & 1 != 0:
sum *= k1
k1 = k1 * k1 % 1000
a2 >>= 2
if sum == data_list1[i]:
flag.append(chr(k))
break
print("".join(flag))
最后的flag:NSSCTF{T1e_z3_1s_v1r9_3asy!}
绝世欧皇
这题比赛的时候没解出来
没想到是我3.7的python没法完整的拆开3.8的exe
装好3.8之后也就花了一个小时不到就解出来了
ida截图略,看string很容易就能猜到是个python编译出来的exe
python pyinstxtractor.py wisher.exe
解开exe,看到一堆文件
先分析app.pyc,010都能看出来倒了wisher开头的一个包,于是在wisher.exe_extracted\PYZ-00.pyz_extracted里找到这个pyc
用pycdc把他反编译回py文件,注意到还导入了libwisher这个包,一样反编译回py方便读
wisher_GUI.py
libwisher.py
这几个函数名………………
原来你也玩……
可以看出是个很繁杂的混合调用,其实引用跟一下就能发现角色之间的顺序是固定的
那不就之间调一下引用传递逻辑,直接贪心一下min概率不就好了?
然后就完美撞坑惹出题人专门防了一手贪心算法,要写一下动态规划
把原本的调用逻辑改为
a = sorted(Impact)
for i in a[:3]:
Traveler = Impact.index(i)
Genshin[Traveler](f'''{coupon}{current_coupon[Traveler]}''', rarity * Impact[Traveler])
# 然后改一下结束条件
def wish_end(coupon, rarity):
global rarity_min
if rarity <= rarity_min:
yydz = wish_checker(rarity)
wish_flag = f'''NSSCTF{{{coupon[:8]}-{coupon[8:12]}-{coupon[12:16]}-{coupon[16:20]}-{coupon[20:]}}}'''
print(wish_flag, yydz)
# exit(0)
rarity_min = rarity
return wish_flag, yydz
就可以等着慢慢跑了
最后还是有很多欧皇的(为什么我次次大保底!)
前面整的很好的是因为我之前每次都循环完16个概率,太慢了太闲了
后面整的很乱是我改成只循环最小的3个概率,一下就跑完了
# NSSCTF{3ec75ddc-d6f0-6ebc-e6f2-d57f361032db} 终极欧皇 2.6253350738478736e-22
# NSSCTF{3ec75ddc-d6f0-6ebc-e6f2-d57fee90ec27} 终极欧皇 2.5741542907205376e-22
# NSSCTF{3ec75ddc-d6f0-6ebc-e6f2-d57f78dc32db} 终极欧皇 2.487089740094928e-22
# NSSCTF{3ec75ddc-d6f0-6ebc-e6f2-d57f78dcec27} 终极欧皇 2.2592055824995987e-22
# NSSCTF{3ec75ddc-d6f0-6ebc-b7fa-4cf1037f9355} 终极欧皇 2.2207900882275277e-22
# NSSCTF{3ec75ddc-d6f0-6ebc-b76e-dc9478dc32db} 终极欧皇 2.146601660945794e-22
# NSSCTF{3ec75ddc-d6f0-6ebc-b76e-dc9478dcec27} 终极欧皇 1.9499153478983617e-22
# NSSCTF{3ec75ddc-87ab-58bc-b7fa-4cf1037f9355} 终极欧皇 1.948992897367505e-22
# 1.5e-22 1.948992897367505e-22
# NSSCTF{3ec75ddc-87ab-58bc-b7fa-4cf1037f9355} 终极欧皇
# 1.5e-22 1.8838842143787544e-22
# NSSCTF{3ec75ddc-87ab-58bc-b76e-dc9478dc32db} 终极欧皇
# 1.5e-22 1.711269869073926e-22
# NSSCTF{3ec75ddc-87ab-58bc-b76e-dc9478dcec27} 终极欧皇
# 1.5e-22 1.665601509891341e-22
# NSSCTF{3ec75ddc-87c4-f88e-4dcb-a59c037f9355} 终极欧皇
# 1.5e-22 1.606289808481659e-22
# NSSCTF{3ec75ddc-87c4-ac7b-d5df-e2c29e5a9355} 终极欧皇
# 1.5e-22 1.5939996063202282e-22
# NSSCTF{3ec75ddc-87c4-ac7b-d5df-e2c29e5aec27} 终极欧皇
# 1.5e-22 1.5591611993590989e-22
# NSSCTF{3ec75ddc-87c4-ac7b-d5df-8e4f232bec27} 终极欧皇
# 1.5e-22 1.5115701895595864e-22
# NSSCTF{9ee35ddc-87c4-ac7b-d5df-e2c29e5a9355} 终极欧皇
# 1.5e-22 1.5000047154385495e-22
# NSSCTF{9ee35ddc-87c4-ac7b-d5df-e2c29e5aec27} 终极欧皇
# 1.5e-22 1.4672206579564412e-22
# 绝世欧皇
# NSSCTF{9ee35ddc-87c4-ac7b-d5df-8e4f232bec27} 绝世欧皇
最终flag:NSSCTF{9ee35ddc-87c4-ac7b-d5df-8e4f232bec27}