记两道源代码逆向题

最近遇到了两个源代码逆向题(太菜了所以只能做简单题

b01lersCTF2023-Quine

源代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
              #include/*firt*/<stdio.h>
#define/*ah*/ p/**/putchar
#define/*??*/ c/*cal*/char
#define/*to*/ Q(q)int*P,u\
/*why...*/=0, M[99999],*C\
=M,*S=M+293;c *Q=#q/*am*/\
,H[99999],*D= H;/*i*/int(\
main)(int*a,c **b){q;}/**/
/*quine*/Q(int*B=M+549;int/*ahhh*/l=strlen(b[1]);p(47);
p(47);for(;*Q;Q++){if(*Q==124)*C++=10;else/*haaa*/if(*Q
==126)*C++=32;else/*wtf_is_this*/if(*Q==33)*C++=34;else
/*woeira*/if(*Q>34)*C++=*Q;*D++=*Q==32?'\n':*Q;}for(int
u=-0;u<l*4;)p(-b[1][u/4]+S[u++]-S[u++]+(S[u++]^S[u++])?
88:79);p(10);/*weird___*/for(int*d=B;d<M+1280;)p(*d++);
printf("%s)",/*progra*/H+304);return/*UwU*/0**"^O{(u4X"
"z}e(tiIh.p+}Kj<&eb]0@sHecW^[.xroBCW=N3nG+r.]rGEs.UJw^"
"y'tn_Qv(y;Ed')#@q@xI1N:wH<X1aT)NtMvNlcY0;+x[cQ4j9>Qi2"
"#Yq&fR#os=ELTjS^/deJZ;EuY`#IQwKL)w<N<Zh,;W9X=&t0zX&E0"
"e<_3SVaLs(pXk6z-XGHTx8T/?-^`h[K0h}`dD6kX:vEeC,mI5fR9k"
"]{;yfO0Wg/1-Z^=WyUqN5XY1g25K1sJgKzfG.~~~~~~~~~~~~~~#i"
"nclude/*firt*/<stdio.h>|~~~~~~~~~~~#define/*ah*/~~~~~"
"~p/**/putchar|~~~~~~~~~#define/*??*/~~~~~~~~~c/*cal*/"
"char|~~~~~~~~#define/*to*/~~~~~~~~~~~Q(q)int*P,u\|~~~"
"~~~~~/*why...*/=0,~~~~~~~~~~~M[99999],*C\|~~~~~~~~=M,"
"*S=M+293;c~~~~~~~~~~~*Q=#q/*am*/\|~~~~~~~~,H[99999],*"
"D=~~~~~~~~~~~H;/*i*/int(\|~~~~~~~~main)(int*a,c~~~~~~"
"~~~~~**b){q;}/**/|/*quine*/Q(int*B=M+549;int/*ahhh*/l"
"=strlen(b[1]);p(47);|p(47);for(;*Q;Q++){if(*Q==124)*C"
"++=10;else/*haaa*/if(*Q|==126)*C++=32;else/*wtf_is_th"
"is*/if(*Q==33)*C++=34;else|/*woeira*/if(*Q>34)*C++=*Q"
";*D++=*Q==32?'\n':*Q;}for(int|u=-0;u<l*4;)p(-b[1][u/4"
"]+S[u++]-S[u++]+(S[u++]^S[u++])?|88:79);p(10);/*weird"
"___*/for(int*d=B;d<M+1280;)p(*d++);|printf(!%s)!,/*pr"
"ogra*/H+304);return/*UwU*//*quine*/Q(/*random_stuf*/")

代码太乱了,题目好像描述是IOCCC,看着确实挺像。从题目名字能看出一些东西。

Quine是指能够输出自身源代码的计算机程序。简单来说,Quine程序就是一个能够输出自己的代码的程序。

手动整理代码…还是算了,让gpt帮我整理一下,顺便把ascii码换成字符

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
#include<stdio.h>
#define p putchar
#define c char
#define Q(q) int *P,u=0,M[99999],*C=M,*S=M+293;c *Q=#q,H[99999],*D=H;int(main)(int* a,c **b){q;}
Q(
int *B = M + 549;int l = strlen(b[1]);
p('/');
p('/');
for (; *Q; Q++) {
if (*Q == '|'){
*C++ = '\n';
} else if (*Q == '~'){
*C++ = ' ';
} else if (*Q == '!'){
*C++ = '"';
} else if (*Q > '"'){
*C++ = *Q;
}
*D++ = *Q == ' ' ? '\n' : *Q;
}
for (int u = -0; u < l * 4;) {
p(-b[1][u / 4] + S[u++] - S[u++] + (S[u++] ^ S[u++]) ? 'X' : 'O');
}
p(10);
for (int *d = B; d < M + 1280;){
p(*d++);
}
printf("%s)",/*progra*/H + 304);
return 0 * *"^O{(u4X"
"z}e(tiIh.p+}Kj<&eb]0@sHecW^[.xroBCW=N3nG+r.]rGEs.UJw^"
"y'tn_Qv(y;Ed')#@q@xI1N:wH<X1aT)NtMvNlcY0;+x[cQ4j9>Qi2"
"#Yq&fR#os=ELTjS^/deJZ;EuY`#IQwKL)w<N<Zh,;W9X=&t0zX&E0"
"e<_3SVaLs(pXk6z-XGHTx8T/?-^`h[K0h}`dD6kX:vEeC,mI5fR9k"
"]{;yfO0Wg/1-Z^=WyUqN5XY1g25K1sJgKzfG.~~~~~~~~~~~~~~#i"
"nclude/*firt*/<stdio.h>|~~~~~~~~~~~#define/*ah*/~~~~~"
"~p/**/putchar|~~~~~~~~~#define/*??*/~~~~~~~~~c/*cal*/"
"char|~~~~~~~~#define/*to*/~~~~~~~~~~~Q(q)int*P,u\|~~~"
"~~~~~/*why...*/=0,~~~~~~~~~~~M[99999],*C\|~~~~~~~~=M,"
"*S=M+293;c~~~~~~~~~~~*Q=#q/*am*/\|~~~~~~~~,H[99999],*"
"D=~~~~~~~~~~~H;/*i*/int(\|~~~~~~~~main)(int*a,c~~~~~~"
"~~~~~**b){q;}/**/|/*quine*/Q(int*B=M+549;int/*ahhh*/l"
"=strlen(b[1]);p(47);|p(47);for(;*Q;Q++){if(*Q==124)*C"
"++=10;else/*haaa*/if(*Q|==126)*C++=32;else/*wtf_is_th"
"is*/if(*Q==33)*C++=34;else|/*woeira*/if(*Q>34)*C++=*Q"
";*D++=*Q==32?'\n':*Q;}for(int|u=-0;u<l*4;)p(-b[1][u/4"
"]+S[u++]-S[u++]+(S[u++]^S[u++])?|88:79);p(10);/*weird"
"___*/for(int*d=B;d<M+1280;)p(*d++);|printf(!%s)!,/*pr"
"ogra*/H+304);return/*UwU*//*quine*/Q(/*random_stuf*/")

整完后就开始硬看了,但是这题当时有师傅已经做出来了,我对着解密脚本一点一点分析,发现自己的C语言也有好多不懂的地方,但还是大致把逻辑猜出来了

字符串化运算符

一元运算符 # 常称为字符串化运算符(stringify operator 或 stringizing operator),因为它会把宏调用时的实参转换为字符串。# 的操作数必须是宏替换文本中的形参。当形参名称出现在替换文本中,并且具有前缀 # 字符时,预处理器会把与该形参对应的实参放到一对双引号中,形成一个字符串字面量。

代码含义

#define 指令是用于创建预处理器宏的。它使用给定的名称 Q 来定义一个宏,该宏后面跟着一些代码。当代码中使用 Q(arg) 这个宏时,会自动被替换成 int*P, u=0, M[99999],*C =M,*S=M+293; c *arg=#arg ,H[99999],*D=H; int(main)(int* a,c **b) {arg;} 这段代码。

在这个宏展开后的代码中,int(main) 实际上是定义了一个函数,这是程序的入口点。函数使用了指针 int* ac b 作为参数,其中 int\* a 代表一个指向整数类型的指针,c b 代表一个指向字符指针的指针。

在函数体中,宏 Q 中的 arg 会被替换成传递给 Q 宏的实际参数,在这里就是 #q,即宏定义时使用的字符串参数。

主要逻辑

因此逻辑部分就在这里,很明显b是main函数的参数,通过命令行传递的字符串参数,采用了-b与后面的S进行加减运算,这里的S可以在上面定义中发现是M+293,因此,S数组是从程序最后的字符串”^O{(u4X”开始的,如果等于0,那么就是O(X可以理解为错,O可以理解为对)因此只用编写解密脚本如下

1
2
3
4
5
6
7
8
9
10
11
#include<stdio.h>
#include<string.h>
int main(int argc, char const *argv[])
{
char s[] = "^O{(u4Xz}e(tiIh.p+}Kj<&eb]0@sHecW^[.xroBCW=N3nG+r.]rGEs.UJw^y'tn_Qv(y;Ed')#@q@xI1N:wH<X1aT)NtMvNlcY0;+x[cQ4j9>Qi2#Yq&fR#os=ELTjS^/deJZ;EuY`#IQwKL)w<N<Zh,;W9X=&t0zX&E0e<_3SVaLs(pXk6z-XGHTx8T/?-^`h[K0h}`dD6kX:vEeC,mI5fR9k]{;yfO0Wg/1-Z^=WyUqN5XY1g25K1sJgKzfG.";
for(int i = 0;i<strlen(s)/4;++i){
printf("%c",(s[i*4+2] ^ s[i*4+3]) + s[i*4] - s[i*4+1]);
}
return 0;
}
//bctf{qu1n3_1s_4ll_ab0ut_r3p371t10n_4nD_m4n1pul4710n_OwO_OuO_UwU}

后记

分析过程基本上都是靠解密脚本边分析边猜的,现在发现看源代码也好痛苦)之后看到有师傅说编译后放IDA里做的,我当时是真滴没想到,分析过程是猜的,所以如果有错欢迎指正~

MidnightSunCTFQuals2023-Open Source Software

第一次比赛中交题目,还是挺有意义的。我太菜了当时坐了差不多4个小时,从开始拿到代码手动整(信不过gpt)这次有经验就编译丢IDA里看了,主要把变量命名搞定就好了,然后扔IDA里看猜是用z3去解。然后就开始让gpt帮我把C代码转python,但没给我整出来,转用newbing。chatgpt?不行X,newbing行!差不多2-3h的时候z3脚本已经写完了,但改了一堆条件还无解,我就开始怀疑自我了。最后BMK师傅贴了个脚本好像也无解,我仔细对着看了下发现,我脚本里函数里if没加约束……之后改完就出来了

源代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
#include <stdio.h>
#include <string.h>

#ifndef FLAG
#error "FLAG is not defined."
#endif

#define Z3K(R2K) (((R2K)/*&||*/<<4)|((R2K)/*&=|=*/>>4))
#define X1M(A9W,B8X) (((A9W)/*|=*/^(B8X))&/*~*/0xff)
#define Y2G(A9W,B8X) ((A9W)/*>>*/&0x55)|(((B8X)&/*<<*/0xaa)>>1)
#define W4U(A9W,B8X) ((((A9W)/*%*/*(B8X))%/*&=|=*/1257)&0xff)
#define V5H(T3S) (((T3S)/*>>*/<<1)|((T3S)/*|*/>>7))
#define S6E(T3S) (((T3S)/*^*/<<3)^((T3S)/*&*/>>5))
#define D7F(A9W,B8X) (((A9W)/*<*/<<4)^/*~*/(B8X))
#define A1C(P6F,Q5G,R4H,S3I) Z3K(W4U(V5H(Z3K(Y2G(V5H(X1M(/*&||*/P6F,Q5G)),V5H(X1M(R4H,S3I))))),Q5G)) /* Function W */
#define B2D(P6F,Q5G) V5H(Z3K(X1M(P6F,Q5G)))
#define C3E(P6F,Q5G) D7F(Q5G,Z3K(X1M(P6F,Q5G)))
#define D4F(P6F,Q5G) ((P6F)/*&|*/^(Q5G))
#define E1I(K2L,M1N) (W4U(V5H(Z3K(K2L)),q1s)/*|*/==(M1N)?(++q1s):(q1s=q1s))
#define F2J(K2L,M1N) (V5H(Z3K(K2L))==(M1N)?(++r8w):(r8w=r8w))
#define G3K(K2L,M1N) (S6E(K2L)==(M1N)?(++s9r):(s9r=s9r))
typedef unsigned int T6R;
T6R q1s=1,r8w=1,s9r=1;
int main(void){
const char x0f[]=FLAG;T6R N = strlen(x0f);/* TODO: REMOVE
T6R h8m[]={A1C(x0f[19],x0f[15],x0f[11],x0f[4]),A1C(x0f[3],
x0f[20],x0f[10],x0f[14]),A1C(x0f[0],x0f[6],x0f[1],x0f[8]),
A1C(x0f[17],x0f[13],x0f[9],x0f[23]),};T6R g7k[]={D4F(C3E(x0f[4],
x0f[23]),C3E(x0f[11],x0f[18])),D4F(C3E(x0f[17],x0f[10]),C3E(x0f[12],
x0f[7])),D4F(C3E(x0f[15],x0f[6]),C3E(x0f[20],x0f[1])),D4F(C3E(x0f[22],
x0f[14]),C3E(x0f[5],x0f[3])),D4F(C3E(x0f[9],x0f[0]),C3E(x0f[13],
x0f[16])),D4F(C3E(x0f[8],x0f[19]),C3E(x0f[5],x0f[21])),};*/
T6R p5f[12]={0x10,0,010,20,0xe,014,0x12,02,0x16,012,6,4};T6R g7k[6]={0};
T6R h8m[6]={0};T6R j9n[12]={0};for(T6R a2z=0;a2z<N;a2z+=4){
if(a2z<12){j9n[p5f[a2z+3]/2]=B2D(x0f[p5f[a2z+3]],x0f[p5f[a2z+3]+1]);
g7k[a2z/4]=D4F(C3E(x0f[a2z*2],x0f[a2z*2+2]),C3E(x0f[a2z*2+4],x0f[a2z*2+6]));
if(a2z<4)h8m[a2z/4]=A1C(x0f[a2z],x0f[a2z+4],x0f[a2z+8],x0f[a2z+12]);
g7k[(a2z/4)+3]= D4F(C3E(x0f[a2z*2+1],x0f[a2z*2+3]),C3E(x0f[a2z*2+5],x0f[a2z*2+7]));
j9n[p5f[a2z+1]/2]=B2D(x0f[p5f[a2z+1]],x0f[p5f[a2z+1]+1]);
j9n[p5f[a2z+2]/2]=B2D(x0f[p5f[a2z+2]],x0f[p5f[a2z+2]+1]);
if(a2z==4)h8m[1]=A1C(x0f[16],x0f[20],x0f[1],x0f[5]);
j9n[p5f[a2z]/2]=B2D(x0f[p5f[a2z]],x0f[p5f[a2z]+1]);}else{
if(a2z<16){h8m[a2z/6]=A1C(x0f[a2z-3],x0f[a2z+1],x0f[a2z+5],x0f[a2z*2-3]);
h8m[3]=A1C(x0f[2],x0f[6],x0f[10],x0f[14]);}
G3K(g7k[0],0x202);G3K(g7k[1],0x1aa2);G3K(g7k[2],0x5a5);}}
h8m[4]=A1C(x0f[s9r*2-q1s-r8w],x0f[s9r*2+q1s+r8w],x0f[q1s*3],x0f[r8w*7]);
h8m[5]=A1C(x0f[s9r+q1s],x0f[s9r+5],x0f[s9r*2-r8w],x0f[s9r*2+3]);
E1I(h8m[0],0x5B);E1I(h8m[1],13);E1I(h8m[2],0x5D);
E1I(h8m[3],0244);E1I(h8m[4],52);E1I(h8m[5],0xDC);
F2J(j9n[0],0x1010);F2J(j9n[1],024050);F2J(j9n[2],034070);
F2J(j9n[3],28784);F2J(j9n[4],0x12d2d);F2J(j9n[5],0x10d0d);
F2J(j9n[6],042104);F2J(j9n[7],012024);F2J(j9n[8],0xc4c4);
F2J(j9n[9],0156334);F2J(j9n[10],0x16161);F2J(j9n[11],0270561);
F2J(B2D(x0f[20],x0f[23]),4112);F2J(B2D(x0f[14],x0f[0]),90465);
G3K(g7k[3],03417);G3K(g7k[4],0x3787);G3K(g7k[5],030421);
T6R s1d = 0;for (T6R a2z=0;a2z<N;a2z++)s1d=(s1d*251)^x0f[a2z];
printf((q1s==7)&&(r8w==15)&&(s9r==13)&&(s1d==0x4E6F76D0)?":)\n":":(\n");
return 0;
}

整理后的代码

我自己整的代码没保存,这是其他师傅整好的源代码,个人感觉编译后放IDA里分析比看源代码舒服

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
#include <stdio.h>
#include <string.h>

#define FLAG "flag{this_is_test_flag}"
#ifndef FLAG
#error "FLAG is not defined."
#endif

#define calc_1(x) (((x)<<4)|((x)>>4))
#define calc_2(x,y) (((x)^(y))&0xff)
#define calc_3(x,y) ((x)&0x55)|(((y)&0xaa)>>1)
#define calc_4(x,y) ((((x)*(y))%1257)&0xff)
#define calc_5(x) (((x)<<1)|((x)>>7))
#define calc_6(x) (((x)<<3)^((x)>>5))
#define calc_7(x,y) (((x)<<4)^(y))

#define fun_1(a,b,c,d) calc_1(calc_4(calc_5(calc_1(calc_3(calc_5(calc_2(a,b)),calc_5(calc_2(c,d))))),b))
#define fun_2(a,b) calc_5(calc_1(calc_2(a,b)))
#define fun_3(a,b) calc_7(b,calc_1(calc_2(a,b)))
#define fun_4(a,b) ((a)^(b))

#define check_a(a,b) (calc_4(calc_5(calc_1(a)),q1s)==(b)?(++q1s):(q1s=q1s))
#define check_b(a,b) (calc_5(calc_1(a))==(b)?(++r8w):(r8w=r8w))
#define check_c(a,b) (calc_6(a)==(b)?(++s9r):(s9r=s9r))

unsigned int q1s=1,r8w=1,s9r=1;
int main(void){
const char flag[]=FLAG;
unsigned int N = strlen(flag);
unsigned int index_arr[12]={0x10,0,010,20,0xe,014,0x12,02,0x16,012,6,4};
unsigned int data_1[6]={0};
unsigned int data_2[6]={0};
unsigned int data_3[12]={0};

for(unsigned int i=0;i<N;i+=4){
if(i<12){
data_3[index_arr[i+3]/2]=fun_2(flag[index_arr[i+3]],flag[index_arr[i+3]+1]);
data_1[i/4]=fun_4(fun_3(flag[i*2],flag[i*2+2]),fun_3(flag[i*2+4],flag[i*2+6]));
if(i<4)
data_2[i/4]=fun_1(flag[i],flag[i+4],flag[i+8],flag[i+12]);
data_1[(i/4)+3]= fun_4(fun_3(flag[i*2+1],flag[i*2+3]),fun_3(flag[i*2+5],flag[i*2+7]));
data_3[index_arr[i+1]/2]=fun_2(flag[index_arr[i+1]],flag[index_arr[i+1]+1]);
data_3[index_arr[i+2]/2]=fun_2(flag[index_arr[i+2]],flag[index_arr[i+2]+1]);
if(i==4)
data_2[1]=fun_1(flag[16],flag[20],flag[1],flag[5]);
data_3[index_arr[i]/2]=fun_2(flag[index_arr[i]],flag[index_arr[i]+1]);
}else{
if(i<16){
data_2[i/6]=fun_1(flag[i-3],flag[i+1],flag[i+5],flag[i*2-3]);
data_2[3]=fun_1(flag[2],flag[6],flag[10],flag[14]);
}
check_c(data_1[0],0x202);
check_c(data_1[1],0x1aa2);
check_c(data_1[2],0x5a5);
}
}

data_2[4]=fun_1(flag[s9r*2-q1s-r8w],flag[s9r*2+q1s+r8w],flag[q1s*3],flag[r8w*7]);
data_2[5]=fun_1(flag[s9r+q1s],flag[s9r+5],flag[s9r*2-r8w],flag[s9r*2+3]);

check_a(data_2[0],0x5B);
check_a(data_2[1],13);
check_a(data_2[2],0x5D);
check_a(data_2[3],0244);
check_a(data_2[4],52);
check_a(data_2[5],0xDC);

check_b(data_3[0],0x1010);
check_b(data_3[1],024050);
check_b(data_3[2],034070);
check_b(data_3[3],28784);
check_b(data_3[4],0x12d2d);
check_b(data_3[5],0x10d0d);
check_b(data_3[6],042104);
check_b(data_3[7],012024);
check_b(data_3[8],0xc4c4);
check_b(data_3[9],0156334);
check_b(data_3[10],0x16161);
check_b(data_3[11],0270561);
check_b(fun_2(flag[20],flag[23]),4112);
check_b(fun_2(flag[14],flag[0]),90465);

check_c(data_1[3],03417);
check_c(data_1[4],0x3787);
check_c(data_1[5],030421);

unsigned int s1d = 0;
for (unsigned int i=0;i<N;i++)
s1d=(s1d*251)^flag[i];

printf((q1s==7)&&(r8w==15)&&(s9r==13)&&(s1d==0x4E6F76D0)?":)\n":":(\n");
return 0;
}

z3求解

宏定义里是一些位运算,check函数和最后判断一些等式,猜测用z3

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
from z3 import*

apple = 1
banana = 1
cherry = 1

s = Solver()
data = [0x00000010, 0x00000000, 0x00000008, 0x00000014, 0x0000000E, 0x0000000C, 0x00000012, 0x00000002, 0x00000016, 0x0000000A, 0x00000006, 0x00000004]

flag = [BitVec('%d' % i,32)for i in range(24)]

for i in range(24):
s.add(flag[i] <127)
s.add(flag[i] >=32)

# midnight{}
# s.add(flag[0] == 0x6d)
# s.add(flag[1] == 0x69)
# s.add(flag[2] == 0x64)
# s.add(flag[3] == 0x6e)
# s.add(flag[4] == 0x69)
# s.add(flag[5] == 0x67)
# s.add(flag[6] == 0x68)
# s.add(flag[7] == 0x74)
# s.add(flag[8] == 0x7b)
# s.add(flag[23] == 0x7d)

def calc_1(x):
return ((x << 4) | (x >> 4))

def calc_2(x, y):
return ((x ^ y) & 0xff)

def calc_3(x, y):
return ((x & 0x55) | ((y & 0xaa) >> 1))

def calc_4(x, y):
return (((x * y) % 1257) & 0xff)

def calc_5(x):
return ((x << 1) | (x >> 7))

def calc_6(x):
return ((x << 3) ^ (x >> 5))

def calc_7(x, y):
return ((x << 4) ^ y)

def func_1(a, b, c, d):
return calc_1(calc_4(calc_5(calc_1(calc_3(calc_5(calc_2(a,b)),calc_5(calc_2(c,d))))),b))

def func_2(a, b):
return calc_5(calc_1(calc_2(a,b)))

def func_3(a, b):
return calc_7(b,calc_1(calc_2(a,b)))

def func_4(a, b):
return (a ^ b)

def check_a(a,b):
global apple
s.add(calc_4(calc_5(calc_1(a)),apple) == b)
apple += 1

def check_b(a,b):
global banana
s.add(calc_5(calc_1(a)) == b)
banana += 1

def check_c(a,b):
global cherry
s.add(calc_6(a) == b)
cherry += 1

if __name__ == '__main__':
input_len = 24
array_1st = [0] * 6
array_2nd = [0] * 6
array_3rd = [0] * 12
for i in range(0, input_len, 4):
if i < 12:
array_3rd[data[i + 3] // 2] = func_2(flag[data[i + 3]], flag[data[i + 3] + 1])
array_1st[i // 4] = func_4(func_3(flag[i * 2], flag[i * 2 + 2]), func_3(flag[i * 2 + 4], flag[i * 2 + 6]))
if i < 4:
array_2nd[i // 4] = func_1(flag[i], flag[i + 4], flag[i + 8], flag[i + 12])
array_1st[(i // 4) + 3] = func_4(func_3(flag[i * 2 + 1], flag[i * 2 + 3]), func_3(flag[i * 2 +5], flag[i *2+7]))
array_3rd[data[i+1]//2]=func_2(flag[data[i+1]],flag[data[i+1]+1])
array_3rd[data[i+2]//2]=func_2(flag[data[i+2]],flag[data[i+2]+1])
if i==4:
array_2nd[1]=func_1(flag[16],flag[20],flag[1],flag[5])
array_3rd[data[i]//2]=func_2(flag[data[i]],flag[data[i]+1])
else:
if i<16:
array_2nd[i//6]=func_1(flag[i-3],flag[i+1],flag[i+5],flag[i*2-3])
array_2nd[3]=func_1(flag[2],flag[6],flag[10],flag[14])
check_c(array_1st[0],0x202)
check_c(array_1st[1],0x1aa2)
check_c(array_1st[2],0x5a5)

array_2nd[4]=func_1(flag[cherry*2-apple-banana],flag[cherry*2+apple+banana],flag[apple*3],flag[banana*7])
array_2nd[5]=func_1(flag[cherry+apple],flag[cherry+5],flag[cherry*2-banana],flag[cherry*2+3])

check_a(array_2nd[0],0x5B)
check_a(array_2nd[1],0xD)
check_a(array_2nd[2],0x5D)
check_a(array_2nd[3],0XA4)
check_a(array_2nd[4],0X34)
check_a(array_2nd[5],0xDC)

check_b(array_3rd[0],0x1010)
check_b(array_3rd[1],0x2828)
check_b(array_3rd[2],0x3838)
check_b(array_3rd[3],0x7070)
check_b(array_3rd[4],0x12d2d)
check_b(array_3rd[5],0x10d0d)
check_b(array_3rd[6],0x4444)
check_b(array_3rd[7],0x1414)
check_b(array_3rd[8],0xc4c4)
check_b(array_3rd[9],0xDCDC)
check_b(array_3rd[10],0x16161)
check_b(array_3rd[11],0x17171)

check_b(func_2(flag[20],flag[23]),0x1010)
check_b(func_2(flag[14],flag[0]),0x16161)

check_c(array_1st[3],0x70F)
check_c(array_1st[4],0x3787)
check_c(array_1st[5],0x3111)

check = 0
for i in range(input_len):
check = (check * 251) ^ flag[i]

s.add(apple == 7)
s.add(banana == 15)
s.add(cherry == 13)
s.add(check == 0x4E6F76D0)

print(s.check())

if(s.check() == sat):
fin = s.model()
print(''.join([chr(fin[x].as_long()) for x in flag]))
else:
print("no ans")
#midnight{0p3N_50rCeRy!!}

感觉文章废话有些多了)以后改正

也争取以后能多出题

dog0

记两道源代码逆向题
https://beckaf.github.io/2023/04/13/code/
Author
Beck
Posted on
April 13, 2023
Licensed under
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明出处!