当前位置: 首页 > news >正文

【无标题】buuctf-re3

1.[羊城杯 2020]login

是python语言,把exe文件变成.pyc文件,之后转成py文件

PyInstaller Extractor WEB

在线Python pyc文件编译与反编译

login.pyc文件

# Visit https://www.lddgo.net/string/pyc-compile-decompile for more information
# Version : Python 3.6import sys
input1 = input('input something:')
if len(input1) != 14:print('Wrong length!')sys.exit()
code = []
for i in range(13):code.append(ord(input1[i]) ^ ord(input1[i + 1]))code.append(ord(input1[13]))
a1 = code[2]
a2 = code[1]
a3 = code[0]
a4 = code[3]
a5 = code[4]
a6 = code[5]
a7 = code[6]
a8 = code[7]
a9 = code[9]
a10 = code[8]
a11 = code[10]
a12 = code[11]
a13 = code[12]
a14 = code[13]
if ((((a1 * 88 + a2 * 67 + a3 * 65 - a4 * 5) + a5 * 43 + a6 * 89 + a7 * 25 + a8 * 13 - a9 * 36) + a10 * 15 + a11 * 11 + a12 * 47 - a13 * 60) + a14 * 29 == 22748) & ((((a1 * 89 + a2 * 7 + a3 * 12 - a4 * 25) + a5 * 41 + a6 * 23 + a7 * 20 - a8 * 66) + a9 * 31 + a10 * 8 + a11 * 2 - a12 * 41 - a13 * 39) + a14 * 17 == 7258) & ((((a1 * 28 + a2 * 35 + a3 * 16 - a4 * 65) + a5 * 53 + a6 * 39 + a7 * 27 + a8 * 15 - a9 * 33) + a10 * 13 + a11 * 101 + a12 * 90 - a13 * 34) + a14 * 23 == 26190) & ((((a1 * 23 + a2 * 34 + a3 * 35 - a4 * 59) + a5 * 49 + a6 * 81 + a7 * 25 + (a8 << 7) - a9 * 32) + a10 * 75 + a11 * 81 + a12 * 47 - a13 * 60) + a14 * 29 == 37136) & (((a1 * 38 + a2 * 97 + a3 * 35 - a4 * 52) + a5 * 42 + a6 * 79 + a7 * 90 + a8 * 23 - a9 * 36) + a10 * 57 + a11 * 81 + a12 * 42 - a13 * 62 - a14 * 11 == 27915) & ((((a1 * 22 + a2 * 27 + a3 * 35 - a4 * 45) + a5 * 47 + a6 * 49 + a7 * 29 + a8 * 18 - a9 * 26) + a10 * 35 + a11 * 41 + a12 * 40 - a13 * 61) + a14 * 28 == 17298) & ((((a1 * 12 + a2 * 45 + a3 * 35 - a4 * 9 - a5 * 42) + a6 * 86 + a7 * 23 + a8 * 85 - a9 * 47) + a10 * 34 + a11 * 76 + a12 * 43 - a13 * 44) + a14 * 65 == 19875) & (((a1 * 79 + a2 * 62 + a3 * 35 - a4 * 85) + a5 * 33 + a6 * 79 + a7 * 86 + a8 * 14 - a9 * 30) + a10 * 25 + a11 * 11 + a12 * 57 - a13 * 50 - a14 * 9 == 22784) & ((((a1 * 8 + a2 * 6 + a3 * 64 - a4 * 85) + a5 * 73 + a6 * 29 + a7 * 2 + a8 * 23 - a9 * 36) + a10 * 5 + a11 * 2 + a12 * 47 - a13 * 64) + a14 * 27 == 9710) & (((((a1 * 67 - a2 * 68) + a3 * 68 - a4 * 51 - a5 * 43) + a6 * 81 + a7 * 22 - a8 * 12 - a9 * 38) + a10 * 75 + a11 * 41 + a12 * 27 - a13 * 52) + a14 * 31 == 13376) & ((((a1 * 85 + a2 * 63 + a3 * 5 - a4 * 51) + a5 * 44 + a6 * 36 + a7 * 28 + a8 * 15 - a9 * 6) + a10 * 45 + a11 * 31 + a12 * 7 - a13 * 67) + a14 * 78 == 24065) & ((((a1 * 47 + a2 * 64 + a3 * 66 - a4 * 5) + a5 * 43 + a6 * 112 + a7 * 25 + a8 * 13 - a9 * 35) + a10 * 95 + a11 * 21 + a12 * 43 - a13 * 61) + a14 * 20 == 27687) & (((a1 * 89 + a2 * 67 + a3 * 85 - a4 * 25) + a5 * 49 + a6 * 89 + a7 * 23 + a8 * 56 - a9 * 92) + a10 * 14 + a11 * 89 + a12 * 47 - a13 * 61 - a14 * 29 == 29250) & (((a1 * 95 + a2 * 34 + a3 * 62 - a4 * 9 - a5 * 43) + a6 * 83 + a7 * 25 + a8 * 12 - a9 * 36) + a10 * 16 + a11 * 51 + a12 * 47 - a13 * 60 - a14 * 24 == 15317):print('flag is GWHT{md5(your_input)}')print('Congratulations and have fun!')
else:print('Sorry,plz try again...')

进去,逻辑是输入14位字符,让后每一位和后一位进行异或存入code中之后打乱存入ai中最后方程式验证,所以我们可以z3约束器解一下,让后反着写出对应代码即可

z3,(注意把第三行的(a8 << 7))变成了(a8 *128)

from z3 import *# 定义变量
a1 = Int('a1')
a2 = Int('a2')
a3 = Int('a3')
a4 = Int('a4')
a5 = Int('a5')
a6 = Int('a6')
a7 = Int('a7')
a8 = Int('a8')
a9 = Int('a9')
a10 = Int('a10')
a11 = Int('a11')
a12 = Int('a12')
a13 = Int('a13')
a14 = Int('a14')# 定义约束条件
s = Solver()
s.add((((a1 * 89 + a2 * 7 + a3 * 12 - a4 * 25) + a5 * 41 + a6 * 23 + a7 * 20 - a8 * 66) + a9 * 31 + a10 * 8 + a11 * 2 - a12 * 41 - a13 * 39) + a14 * 17 == 7258)
s.add((((a1 * 28 + a2 * 35 + a3 * 16 - a4 * 65) + a5 * 53 + a6 * 39 + a7 * 27 + a8 * 15 - a9 * 33) + a10 * 13 + a11 * 101 + a12 * 90 - a13 * 34) + a14 * 23 == 26190)
s.add((((a1 * 23 + a2 * 34 + a3 * 35 - a4 * 59) + a5 * 49 + a6 * 81 + a7 * 25 + (a8 *128) - a9 * 32) + a10 * 75 + a11 * 81 + a12 * 47 - a13 * 60) + a14 * 29 == 37136)
s.add(((a1 * 38 + a2 * 97 + a3 * 35 - a4 * 52) + a5 * 42 + a6 * 79 + a7 * 90 + a8 * 23 - a9 * 36) + a10 * 57 + a11 * 81 + a12 * 42 - a13 * 62 - a14 * 11 == 27915)
s.add((((a1 * 22 + a2 * 27 + a3 * 35 - a4 * 45) + a5 * 47 + a6 * 49 + a7 * 29 + a8 * 18 - a9 * 26) + a10 * 35 + a11 * 41 + a12 * 40 - a13 * 61) + a14 * 28 == 17298)
s.add((((a1 * 12 + a2 * 45 + a3 * 35 - a4 * 9 - a5 * 42) + a6 * 86 + a7 * 23 + a8 * 85 - a9 * 47) + a10 * 34 + a11 * 76 + a12 * 43 - a13 * 44) + a14 * 65 == 19875)
s.add(((a1 * 79 + a2 * 62 + a3 * 35 - a4 * 85) + a5 * 33 + a6 * 79 + a7 * 86 + a8 * 14 - a9 * 30) + a10 * 25 + a11 * 11 + a12 * 57 - a13 * 50 - a14 * 9 == 22784)
s.add((((a1 * 8 + a2 * 6 + a3 * 64 - a4 * 85) + a5 * 73 + a6 * 29 + a7 * 2 + a8 * 23 - a9 * 36) + a10 * 5 + a11 * 2 + a12 * 47 - a13 * 64) + a14 * 27 == 9710)
s.add(((((a1 * 67 - a2 * 68) + a3 * 68 - a4 * 51 - a5 * 43) + a6 * 81 + a7 * 22 - a8 * 12 - a9 * 38) + a10 * 75 + a11 * 41 + a12 * 27 - a13 * 52) + a14 * 31 == 13376)
s.add((((a1 * 85 + a2 * 63 + a3 * 5 - a4 * 51) + a5 * 44 + a6 * 36 + a7 * 28 + a8 * 15 - a9 * 6) + a10 * 45 + a11 * 31 + a12 * 7 - a13 * 67) + a14 * 78 == 24065)
s.add((((a1 * 47 + a2 * 64 + a3 * 66 - a4 * 5) + a5 * 43 + a6 * 112 + a7 * 25 + a8 * 13 - a9 * 35) + a10 * 95 + a11 * 21 + a12 * 43 - a13 * 61) + a14 * 20 == 27687)
s.add(((a1 * 89 + a2 * 67 + a3 * 85 - a4 * 25) + a5 * 49 + a6 * 89 + a7 * 23 + a8 * 56 - a9 * 92) + a10 * 14 + a11 * 89 + a12 * 47 - a13 * 61 - a14 * 29 == 29250)
s.add(((a1 * 95 + a2 * 34 + a3 * 62 - a4 * 9 - a5 * 43) + a6 * 83 + a7 * 25 + a8 * 12 - a9 * 36) + a10 * 16 + a11 * 51 + a12 * 47 - a13 * 60 - a14 * 24 == 15317)# 检查是否有解
if s.check() == sat:m = s.model()for i in range(1, 15):print(f"a{i} = {m[eval(f'a{i}')]}")
else:print("No solution")

a1 = 119
a2 = 24
a3 = 10
a4 = 7
a5 = 104
a6 = 43
a7 = 28
a8 = 91
a9 = 52
a10 = 108
a11 = 88
a12 = 74
a13 = 88
a14 = 33

#include<stdio.h>int main(){int code[14]={10,24,119,7,104,43,28,91,108,52,88,74,88,33};int i;for(i=12;i>=0;i--){code[i]=code[i]^code[i+1];}for(i=0;i<14;i++){printf("%c",code[i]);}//U_G07_th3_k3y!return 0;
}

最后找一下md5即可flag{58964088b637e50d3a22b9510c1d1ef8}

2[GXYCTF2019]simple CPP

c++代码,直接分析代码

int __fastcall main(int argc, const char **argv, const char **envp)
{bool v3; // si__int64 v4; // rax__int64 v5; // r8__int64 v6; // r8unsigned __int8 *v7; // raxunsigned __int8 *v8; // rbxint v9; // r10d__int64 v10; // r11void **v11; // r9void **v12; // r8__int64 v13; // rdi__int64 v14; // r15__int64 v15; // r12__int64 v16; // rbpint v17; // ecxunsigned __int8 *v18; // rdx__int64 v19; // rdi__int64 *v20; // r14__int64 v21; // rbp__int64 v22; // r13__int64 *v23; // rdi__int64 v24; // r8__int64 v25; // r12__int64 v26; // r15__int64 v27; // rbp__int64 v28; // rdx__int64 v29; // rbp__int64 v30; // rbp__int64 v31; // r10__int64 v32; // rdi__int64 v33; // r8bool v34; // dl__int64 v35; // raxvoid **v36; // rdx__int64 v37; // rax__int64 v38; // r8__int64 v39; // raxvoid *v40; // rcx__int64 v42; // [rsp+20h] [rbp-68h]void *Block[2]; // [rsp+30h] [rbp-58h] BYREFunsigned __int64 v44; // [rsp+40h] [rbp-48h]unsigned __int64 v45; // [rsp+48h] [rbp-40h]v3 = 0;v44 = 0i64;v45 = 15i64;LOBYTE(Block[0]) = 0;v4 = sub_1400019C0(std::cout, "I'm a first timer of Logic algebra , how about you?", envp);std::ostream::operator<<(v4, sub_140001B90);sub_1400019C0(std::cout, "Let's start our game,Please input your flag:", v5);sub_140001DE0(std::cin, Block);std::ostream::operator<<(std::cout, sub_140001B90);if ( v44 - 5 > 25 ){v39 = sub_1400019C0(std::cout, "Wrong input ,no GXY{} in input words", v6);std::ostream::operator<<(v39, sub_140001B90);goto LABEL_43;}v7 = operator new(0x20ui64);v8 = v7;if ( v7 ){*v7 = 0i64;*(v7 + 1) = 0i64;*(v7 + 2) = 0i64;*(v7 + 3) = 0i64;}else{v8 = 0i64;}v9 = 0;if ( v44 ){v10 = 0i64;do{v11 = Block;if ( v45 >= 0x10 )v11 = Block[0];v12 = &qword_140006048;if ( qword_140006060 >= 16 )v12 = qword_140006048;v8[v10] = *(v11 + v10) ^ *(v12 + v9 % 27);++v9;++v10;}while ( v9 < v44 );}v13 = 0i64;v14 = 0i64;v15 = 0i64;v16 = 0i64;if ( v44 > 30 )goto LABEL_27;v17 = 0;if ( v44 <= 0 )goto LABEL_27;v18 = v8;do{v19 = *v18 + v13;++v17;++v18;switch ( v17 ){case 8:v16 = v19;goto LABEL_23;case 16:v15 = v19;goto LABEL_23;case 24:v14 = v19;
LABEL_23:v19 = 0i64;break;case 32:sub_1400019C0(std::cout, "ERRO,out of range", v44);exit(1);}v13 = v19 << 8;}while ( v17 < v44 );if ( v16 ){v20 = operator new(0x20ui64);*v20 = v16;v20[1] = v15;v20[2] = v14;v20[3] = v13;goto LABEL_28;}
LABEL_27:v20 = 0i64;
LABEL_28:v42 = v20[2];v21 = v20[1];v22 = *v20;v23 = operator new(0x20ui64);if ( IsDebuggerPresent() ){sub_1400019C0(std::cout, "Hi , DO not debug me !", v24);Sleep(0x7D0u);exit(0);}v25 = v21 & v22;*v23 = v21 & v22;v26 = v42 & ~v22;v23[1] = v26;v27 = ~v21;v28 = v42 & v27;v23[2] = v42 & v27;v29 = v22 & v27;v23[3] = v29;if ( v26 != 0x11204161012i64 ){v23[1] = 0i64;v26 = 0i64;}v30 = v26 | v25 | v28 | v29;v31 = v20[1];v32 = v20[2];v33 = v28 & *v20 | v32 & (v25 | v31 & ~*v20 | ~(v31 | *v20));v34 = 0;if ( v33 == 0x8020717153E3013i64 )v34 = v30 == 0x3E3A4717373E7F1Fi64;if ( (v30 ^ v20[3]) == 0x3E3A4717050F791Fi64 )v3 = v34;if ( (v26 | v25 | v31 & v32) == (~*v20 & v32 | 0xC00020130082C0Ci64) && v3 ){v35 = sub_1400019C0(std::cout, "Congratulations!flag is GXY{", v33);v36 = Block;if ( v45 >= 0x10 )v36 = Block[0];v37 = sub_140001FD0(v35, v36, v44);sub_1400019C0(v37, "}", v38);j_j_free(v8);}else{sub_1400019C0(std::cout, "Wrong answer!try again", v33);j_j_free(v8);}
LABEL_43:if ( v45 >= 0x10 ){v40 = Block[0];if ( v45 + 1 >= 0x1000 ){v40 = *(Block[0] - 1);if ( (Block[0] - v40 - 8) > 0x1F )invalid_parameter_noinfo_noreturn();}j_j_free(v40);}return 0;
}

输入处理

sub_140001DE0(std::cin, Block);
  • 读取用户输入到 Block
  • 要求输入格式为 GXY{...},且长度在 5 < len < 32 之间。

异或加密

v8[v10] = Block[v10] ^ qword_140006060[v9 % 27];
  • 将输入的每个字符与固定密钥 qword_140006060 循环异或。
  • 密钥长度为 27 字节。

这里的密钥需要动态调试查看数据

分组处理

v16 = v19;  // 前 8 字节
v15 = v19;  // 中 8 字节
v14 = v19;  // 后 8 字节
v13 = v19;  // 最后 8 字节
  • 将异或后的数据按 8 字节一组分成 4 部分,存入 v20[0]~v20[3]

逻辑运算校验

v25 = v21 & v22;
v26 = v42 & ~v22;
v28 = v42 & ~v21;
v29 = v22 & ~v21;
  • v20 中的数据进行复杂的逻辑运算(AND、OR、NOT、XOR)。

  • 校验以下等式是否成立:

    1. v26 == 0x11204161012
    2. v30 == 0x3E3A4717373E7F1F
    3. (v30 ^ v20[3]) == 0x3E3A4717050F791F
    4. (v26 | v25 | v31 & v32) == (~v20[0] & v32 | 0xC00020130082C0C)

    这里可以用z3求解器,无非是前面的四组数据的变换

反调试

if (IsDebuggerPresent()) {std::cout << "Hi, DO not debug me!";Sleep(2000);exit(0);
}
  • 如果检测到调试器,直接退出。

我们可以在动态调试的时候修改代码逻辑

输出结果

  • 如果所有校验通过,输出 Congratulations!flag is GXY{...}
  • 否则输出 Wrong answer!try again

所以先找到对应的数据,让后动态调试拿到密钥,之后逐位异或即可

输入数据拿到密钥,ida这里的是dq是8位的,我们需要一位的db字符,可以
在这里插入图片描述

  • db(1 字节)
  • dw(2 字节)
  • dd(4 字节)
  • dq(8 字节)

按一下键盘上的 d 是一个 循环切换数据定义大小 的快捷键,可以在这几个数据的定义方式之间切换,也可以跟进查看具体的数据,其结果是

i_will_check_is_debug_or_not

之后修改一下变量名

在这里插入图片描述

a = v18[2];
b = v18[1];
c = *v18;
d = operator new(0x20ui64);

v22 = b & c;
*d = b & c;
v23 = a & ~c;
d[1] = v23;
v24 = ~b;
v25 = a & v24;
d[2] = a & v24;
v26 = c & v24;
d[3] = v26;
v23 == 0x11204161012i64
v27 = v23 | v22 | v25 | v26;
v28 = v18[1];
v29 = v18[2];
v30 = v25 & *v18 | v29 & (v22 | v28 & ~*v18 | ~(v28 | *v18));
v31 = 0;
v30 == 0x8020717153E3013i64
v31 = v27 == 0x3E3A4717373E7F1Fi64;
(v27 ^ v18[3]) == 0x3E3A4717050F791Fi64
v3 = v31;
(v23 | v22 | v28 & v29) == (~*v18 & v29 | 0xC00020130082C0Ci64)

最终得到这几个方程式,z3跑一下

a & ~c == 0x11204161012
(a & ~b) & c | a & (b & c | b & ~c | ~(b | c)) == 0x8020717153E3013
a & ~c | b & c | a & ~b | c & ~b == 0x3E3A4717373E7F1F
((a & ~c | b & c | a & ~b | c & ~b) ^ d) == 0x3E3A4717050F791F
(a & ~c | b & c | b & a) == (~c & a | 0xC00020130082C0Ci64)

这里需要用BitVec类型是符号位向量类型,用于表示固定长度的二进制整数数据

from z3 import *# 定义变量
a,b,c,d=BitVecs("a b c d",64)# 定义约束条件
s = Solver()
s.add(a & ~c == 0x11204161012)
s.add((a & ~b) & c | a & (b & c | b & ~c | ~(b | c)) == 0x8020717153E3013)
s.add(a & ~c | b & c | a & ~b | c & ~b == 0x3E3A4717373E7F1F)
s.add(((a & ~c | b & c | a & ~b | c & ~b) ^ d) == 0x3E3A4717050F791F)
s.add((a & ~c | b & c | b & a) == (~c & a | 0xC00020130082C0C) )# 检查是否有解
if s.check() == sat:print(s.model())
else:print("No solution")

[c = 4483973367147818765,
a = 577031497978884115,
b = 864693332579200012,
d = 842073600]

我这里是把a和c的顺序搞反了,细节!
在这里插入图片描述

之后拼接成字符串让后逐位异或即可

nums = [4483973367147818765,864693332579200012,577031497978884115,842073600
]flag = []for num in nums:hex_str = f"{num:X}"               # 转十六进制大写字符串hex_str = hex_str.zfill(len(hex_str) + len(hex_str) % 2)  # 保证偶数位flag += [f"0x{hex_str[i:i+2]}" for i in range(0, len(hex_str), 2)]# 截取前 27 字节(因为 flag 长度是 27)
flag = flag[:27]print("flag = [" + ", ".join(flag) + "]")
flag = [0x3E, 0x3A, 0x46, 0x05, 0x33, 0x28, 0x6F, 0x0D, 0x0C, 0x00, 0x02, 0x01, 0x30, 0x08, 0x2C, 0x0C, 0x08, 0x02, 0x07, 0x17, 0x15, 0x3E, 0x30, 0x13, 0x32, 0x31, 0x06]
key="i_will_check_is_debug_or_not"
for i in range(27):print(chr(ord(key[i]) ^ flag[i]),end='')

flag = [0x3E, 0x3A, 0x46, 0x05, 0x33, 0x28, 0x6F, 0x0D, 0x0C, 0x00, 0x02, 0x01, 0x30, 0x08, 0x2C, 0x0C, 0x08, 0x02, 0x07, 0x17, 0x15, 0x3E, 0x30, 0x13, 0x32, 0x31, 0x06]
We1l_D0ndeajoa_Slgebra_am_i

由于出题的原因,

最后的答案是flag{We1l_D0ne!P0or_algebra_am_i}

3.[2019红帽杯]xx

[buuctf–2019红帽杯]xx_buuctf [2019红帽杯]xx-CSDN博客

c++代码,下断点跑一下程序

输入长度为19

    __int64 input_len = 0;while (*(Code + input_len)) ++input_len;if (input_len != 19){sub_7FF7BB451620(std::cout, "error\n");_exit(Code);}

字符检查,确保输入的前四位字符是在Code当中的数据

注意区分浅色的Code是我们输入的flag,变量名Code才是验证用的Code

qwertyuiopasdfghjklzxcvbnm1234567890

do
{v10 = *(v9 + Code - v5);  // 取出 Code 中的当前字符v11 = 0;*v9 = v10;                // 将字符复制到 v9 指向的位置v12 = 0i64;v13 = -1i64;do++v13;while (*(v6 + v13));       // 计算字符集的长度if (v13){do{if (v10 == *(v6 + v12))break;++v11;++v12;}while (v11 < v13);     // 检查字符是否在字符集中}v14 = -1i64;do++v14;while (*(v6 + v14));       // 再次计算字符集的长度if (v11 == v14)            // 如果字符不在字符集中_exit(v6);             // 退出程序v9 = (v9 + 1);             // 移动到下一个字符
}
while (v9 - v5 < 4);            // 检查前 4 个字符
*(v5 + 4) = 0;                  // 在第 5 个位置放一个终止符
do++v3;
while (*(Code + v3));  // 找到 Code 的长度
v15 = 0i64;
v30 = *v7;  // v30 是某个 16 字节缓冲区的起始地址
while (*(&v30 + v15))
{if (!*(&v30 + v15 + 1)){++v15;break;}if (!*(&v30 + v15 + 2)){v15 += 2i64;break;}if (!*(&v30 + v15 + 3)){v15 += 3i64;break;}v15 += 4i64;if (v15 >= 16)break;
}
for (i = v15 + 1; i < 16; ++i)*(&v30 + i) = 0;  // 将 v30 的剩余部分置零__int64 v17 = sub_7FF7BB451AB0(Code, v3, &v30, &Size);__int64 v18 = Size;_BYTE *v19 = (_BYTE *)v17;

加密函数sub_7FF7BB451AB0

有一个v30

  • v30 开始,逐个检查每个字节。
  • 如果当前字节不为零,且下一个字节为零,v15 增加 1。
  • 如果当前字节不为零,且下两个字节为零,v15 增加 2。
  • 如果当前字节不为零,且下三个字节为零,v15 增加 3。
  • 如果当前字节不为零,且下四个字节为零,v15 增加 4。
  • 如果 v15 达到 16,停止处理。

v30 的剩余部分(从 v15 + 1 到 16)置零。

由于题目中输入的格式是 flag{…}

所以v30结果是v30是输入的前4位,加后面的12个’0’

sub_7FF7BB451AB0Code做某种变换,返回结果v19,长度为 Size

_BYTE *__fastcall sub_7FF7BB451AB0(__int64 a1, unsigned __int64 a2, unsigned __int8 *a3, unsigned __int64 *a4)
{unsigned __int64 *v4; // r13__int64 v8; // rdisize_t v9; // rcx_DWORD *v10; // rax_DWORD *v11; // r15__int64 v12; // r14unsigned __int64 v13; // rdiunsigned __int64 i; // r9int v15; // edx_DWORD *v16; // r8char v17; // cl_DWORD *v18; // r12int v19; // ecxint v20; // eaxint v21; // ecxint v22; // eaxint v23; // ecxint v24; // eaxint v25; // ecxint v26; // eaxunsigned int v27; // ebp__int64 v28; // rcxunsigned int v29; // r10dunsigned int v30; // eax__int64 v31; // r9unsigned int *v32; // rbx__int64 v33; // r11_DWORD *v34; // rax__int64 v35; // rsi__int64 v36; // r14char v37; // r13unsigned int v38; // r8d__int64 v39; // rcxunsigned __int64 v40; // rbxsize_t v41; // rcx_BYTE *v42; // rax_BYTE *v43; // rsichar v45; // [rsp+20h] [rbp-58h]__int64 v46; // [rsp+28h] [rbp-50h]__int64 v47; // [rsp+30h] [rbp-48h]unsigned int v48; // [rsp+88h] [rbp+10h]v4 = a4;if ( !a2 )return 0i64;v8 = a2 >> 2;if ( (a2 & 3) != 0 )v8 = (a2 >> 2) + 1;v9 = v8 + 1;if ( v8 == -1 )v9 = -1i64;v10 = calloc(v9, 4ui64);v11 = v10;if ( !v10 )return 0i64;v12 = v8 + 1;v10[v8] = a2;v13 = 0i64;v47 = v12;for ( i = 0i64; i < a2; *v16 |= v15 << (8 * v17) ){v15 = *(i + a1);v16 = &v10[i >> 2];v17 = i++ & 3;}v18 = calloc(4ui64, 4ui64);if ( v18 ){v19 = a3[7] << 8;v20 = a3[6];*v18 |= *a3 | ((a3[1] | (*(a3 + 1) << 8)) << 8);v21 = a3[4] | ((a3[5] | ((v20 | v19) << 8)) << 8);v22 = a3[10];v18[1] |= v21;v23 = a3[8] | ((a3[9] | ((v22 | (a3[11] << 8)) << 8)) << 8);v24 = a3[14];v18[2] |= v23;v25 = a3[13] | ((v24 | (a3[15] << 8)) << 8);v26 = a3[12];v27 = 0;v18[3] |= v26 | (v25 << 8);v28 = (v12 - 1);v29 = v11[v28];v30 = 0x34 / v12 + 6;v31 = v28;v45 = v12 - 1;v46 = v28;if ( v12 != 1 && 0x34 / v12 != -6 ){do{v32 = v11 + 1;v27 -= 0x61C88647;v48 = v30 - 1;v33 = 0i64;v34 = v11;v35 = (v27 >> 2) & 3;v36 = v31;v37 = v28;do{v38 = *v32++;++v34;v39 = v35 ^ v33++ & 3;*(v34 - 1) += ((v27 ^ v38) + (v29 ^ v18[v39])) ^ (((16 * v29) ^ (v38 >> 3)) + ((v29 >> 5) ^ (4 * v38)));v29 = *(v34 - 1);--v36;}while ( v36 );v31 = v46;LOBYTE(v28) = v45;v30 = v48;v11[v46] += ((v27 ^ *v11) + (v29 ^ v18[v35 ^ v37 & 3])) ^ (((4 * *v11) ^ (v29 >> 5)) + ((*v11 >> 3) ^ (16 * v29)));v29 = v11[v46];}while ( v48 );v12 = v47;v4 = a4;}v40 = 4 * v12;v41 = 4 * v12 + 1;if ( 4 * v12 == -1 )v41 = -1i64;v42 = malloc(v41);v43 = v42;if ( v40 ){do{v42[v13] = v11[v13 >> 2] >> (8 * (v13 & 3));++v13;}while ( v13 < v40 );}v42[4 * v12] = 0;*v4 = v40;free(v11);free(v18);return v43;}else{free(v11);return 0i64;}
}
 v17 = sub_7FF7BB451AB0(Code, v3, &v30, &Size);

看着像TEA,并且看到了0x61C88647数据是0x9E3779B9 的补码

最后证明是XXTEA

所以我们要知道密文v19和密钥v30,

重排字节,固定重排表

    _BYTE *v20 = (_BYTE *)operator new(Size);v20[0]  = v19[2];v20[1]  = v19[0];v20[2]  = v19[3];v20[3]  = v19[1];v20[4]  = v19[6];v20[5]  = v19[4];v20[6]  = v19[7];v20[7]  = v19[5];v20[8]  = v19[10];v20[9]  = v19[8];v20[10] = v19[11];v20[11] = v19[9];v20[12] = v19[14];v20[13] = v19[12];v20[14] = v19[15];v20[15] = v19[13];v20[16] = v19[18];v20[17] = v19[16];v20[18] = v19[19];v20[19] = v19[17];v20[20] = v19[22];v20[21] = v19[20];v20[22] = v19[23];v20[23] = v19[21];

异或混淆

v20 = (_BYTE *)operator new(Size);        // 已重排过的缓冲区
v20[0]  = v19[2];                         // 0 号字节不做任何处理
v20[1]  = v19[0];
...
v20[23] = v19[21];                        // 共 Size 字节(24)int v21 = 1;                              // 从第 1 字节开始
_BYTE *v22 = v20 + 1;                     // 指向 v20[1]while (v21 < Size)                        // 对 1..Size-1 做异或
{__int64 v23 = 0;if (v21 / 3 > 0)                      // 只有当 v21>=3 时才进入{char v24 = *v22;                  // 取出当前字节do{v24 ^= v20[v23++];            // 依次与 v20[0..v23-1] 异或*v22 = v24;                   // 写回}while (v23 < v21 / 3);            // 最多异或 k = floor(v21/3) 次}++v21;++v22;
}

这里的逻辑是v20与自身异或得到

def confuse(data: bytes) -> bytes:data = bytearray(data)v20 = data[:]              # 只读原始表for i in range(1, len(data)):k = i // 3if k:v24 = data[i]for j in range(k):v24 ^= v20[j]  # 始终与原始表异或data[i] = v24return bytes(data)

逆向代码

def deconfuse(data: bytes, v20: bytes) -> bytes:"""逆向:顺序完全倒过来"""data = bytearray(data)for i in range(len(data) - 1, 0, -1):k = i // 3if k:v24 = data[i]for j in range(k - 1, -1, -1):v24 ^= v20[j]data[i] = v24return bytes(data)

最后得到的数据v20注意小段序,

0xCE, 0xBC, 0x40, 0x6B, 0x7C, 0x3A, 0x95, 0xC0,
0xEF, 0x9B, 0x20, 0x20, 0x91, 0xF7, 0x02, 0x35,
0x23, 0x18, 0x02, 0xC8, 0xE7, 0x56, 0x56, 0xFA

写代码解决

def confuse(data: bytes) -> bytes:data = bytearray(data)v20 = data[:]                    # 只读原始表for i in range(1, len(data)):k = i // 3if k:v24 = data[i]for j in range(k):v24 ^= v20[j]data[i] = v24return bytes(data)def deconfuse(data: bytes, v20: bytes) -> bytes:data = bytearray(data)for i in range(len(data) - 1, 0, -1):k = i // 3if k:v24 = data[i]for j in range(k - 1, -1, -1):v24 ^= v20[j]data[i] = v24return bytes(data)def de_shuffle(data: bytes) -> bytes:idx = [1, 3, 0, 2, 5, 7, 4, 6, 9, 11, 8, 10, 13, 15,12, 14, 17, 19, 16, 18, 21, 23, 20, 22]out = [0] * 24for i, j in enumerate(idx):out[i] = data[j]return bytes(out)# 已知
v20    = bytes(range(24))  # 原始 24 字节
conf   = bytes.fromhex('CEBC406B7C3A95C0EF9B202091F70235231802C8E75656FA')  # 混淆结果# 还原
orig = deconfuse(conf, v20)a=de_shuffle(orig)print(orig.hex())
print(a.hex())
#cebc406b7c3a94c1ee98232391f70231271c03c9e65151fd
#bc6bce403ac17c949823ee23f73191021cc9270351fde651# 将16进制字符串每两个字符一组,转换为十进制整数
b = [int(a[i:i+2], 16) for i in range(0, len(a), 2)]import xxteakey = 'flag' + '\x00' * 12
enc = bytes(b)dec = xxtea.decrypt(enc, key, padding=False)
print(dec)

C:\Users\21901\PycharmProjects\pythonProject.venv\Scripts\python.exe C:\Users\21901\PycharmProjects\pythonProject\222.py
[206, 188, 64, 165, 178, 244, 231, 178, 157, 169, 18, 18, 200, 174, 91, 16, 6, 61, 29, 215, 248, 220, 220, 112]
[188, 165, 206, 64, 244, 178, 178, 231, 169, 18, 157, 18, 174, 16, 200, 91, 61, 215, 6, 29, 220, 112, 248, 220]
flag
b’flag{CXX_and_++tea}\x00\x13\x00\x00\x00’

进程已结束,退出代码为 0

flag{CXX_and_++tea}

http://www.dtcms.com/a/291641.html

相关文章:

  • 解决pip指令超时问题
  • MCU中的总线桥是什么?
  • Windows PE文件内未用空间学习
  • Collection接口的详细介绍以及底层原理——包括数据结构红黑树、二叉树等,从0到彻底掌握Collection只需这篇文章
  • wed前端简单解析
  • wangEditor5添加键盘事件/实现定时保存功能
  • 【文献笔记】ARS: Automatic Routing Solver with Large Language Models
  • SpringMVC快速入门之启动配置流程
  • C语言基础:函数练习题
  • 【洛谷】用两个数组实现静态单链表、静态双向链表,排队顺序
  • C#初学知识点总结
  • 假发行业数字化突围,外贸ERP重构外协管理引擎,助力效率飞跃
  • 智联智造:国内新能源汽车品牌AGV小车无线控制系统创新实践
  • 面试题:sql题一
  • 前端项目启动后,只有localhost地址,没有ip地址
  • vs2017 c++ 使用sqlite3数据库
  • Java 邂逅 WebSocket:解锁实时通信的无限可能​
  • Flutter基础(前端教程①⑦-Column竖直-Row水平-Warp包裹-Stack堆叠)
  • 【计算机网络 篇】TCP基本认识和TCP三次握手相关问题
  • ArKTS: DAL,Model,BLL,Interface,Factory using SQLite
  • docker-desktop启动失败
  • 【电影剖析】千钧一发
  • 从 “能用“ 到 “好用“:中小制造企业数字化转型中的 IT 系统优化管理策略
  • 【openbmc6】entity-manager
  • C# 转换(is和as运算符)
  • 【人工智能99问】transformer的编码器和解码器是如何协同工作的?(15/99)
  • 【面经】实习经历
  • Thread 类
  • Java注解家族--`@ResponseBody`
  • 2025杭电多校赛(2)1006 半