2019 GXY_Re部分_WriteUp

赛题下载地址:https://www.lanzous.com/b07r91skd

0x01 lucky_guy

IDA打开

进入patch_me

进入get_flag

随机产生5个数字,每产生一个进入下面switch进行处理

 

 

代码分析

分析得到处理顺序

1中得到f2的初始值"icug`of ",2可能执行多次,3中f1为 "GXY{do_not_",因此可以写出C++代码模拟过程。

 

程序解密

#include <iostream>

using namespace std;
/* run this program using the console pauser or add your own getch, system("pause") or input loop */

int main(int argc, char** argv) {
    char v1;
    char f2[] = "icug`of ";
    cout << f2 << endl;
    for (int i = 0; i < 4; ++i) {
        for (int j = 0; j <= 7; ++j) {
            if (j % 2 == 1)
                v1 = f2[j] - 2;
            else
                v1 = f2[j] - 1;
            f2[j] = v1;
        }
        cout << f2 << endl;
    }

    return 0;
}

得到后半部分,"hate_me}"

组合起来就是GXY{do_not_hate_me}

 

get flag!

GXY{do_not_hate_me}

 

0x02 simple_CPP

IDA打开

将代码整体分为了三个部分

 1 if ( v37 > 0 )
 2   {
 3     v5 = 0i64;
 4     do
 5     {
 6       v6 = &Memory;                             // v6为输入
 7       if ( v38 >= 0x10 )
 8         v6 = Memory;
 9       v7 = &Dst;                                // Dst=i_will_check_is_debug_or_not
10       if ( (unsigned __int64)qword_140006060 >= 0x10 )
11         v7 = (void **)Dst;
12       v3[v5] = v6[v5] ^ *((_BYTE *)v7 + v4++ % 27);// 输入进行变换
13       ++v5;
14     }
15     while ( v4 < v37 );
16   }
 1   do
 2   {
 3     v14 = *v13 + v8;                            // 对输入变换后的字符串再进行变换
 4     ++v12;
 5     ++v13;
 6     switch ( v12 )
 7     {
 8       case 8:                                   // v11=第8位的
 9         v11 = v14;
10         goto LABEL_24;
11       case 16:
12         v10 = v14;                              // v11第16位的
13         goto LABEL_24;
14       case 24:                                  // v11=第24位
15         v9 = v14;
16 LABEL_24:
17         v14 = 0i64;
18         break;
19       case 32:
20         sub_1400019C0(std::cout, "ERRO,out of range");
21         exit(1);
22         break;
23     }
24     v8 = v14 << 8;
25   }
26   while ( v12 < (signed int)v37 );
 1   v35 = v15[2];                                 // 1-2
 2   v16 = v15[1];
 3   v17 = *v15;                                   // 1-2
 4   v18 = sub_14000223C(0x20ui64);
 5   if ( IsDebuggerPresent() )
 6   {
 7     sub_1400019C0(std::cout, "Hi , DO not debug me !");
 8     Sleep(0x7D0u);
 9     exit(0);
10   }
11   v19 = v16 & v17;
12   *v18 = v16 & v17;
13   v20 = v35 & ~v17;                             // 1-1
14   v18[1] = v20;
15   v21 = ~v16;
16   v22 = v35 & v21;
17   v18[2] = v35 & v21;
18   v23 = v17 & v21;
19   v18[3] = v23;
20   if ( v20 != 1176889593874i64 )
21   {
22     v18[1] = 0i64;
23     v20 = 0i64;
24   }
25   v24 = v20 | v19 | v22 | v23;
26   v25 = v15[1];
27   v26 = v15[2];
28   v27 = v22 & *v15 | v26 & (v19 | v25 & ~*v15 | ~(v25 | *v15));
29   v28 = 0;
30   if ( v27 == 577031497978884115i64 )
31     v28 = v24 == 4483974544037412639i64;
32   if ( (v24 ^ v15[3]) == 4483974543195470111i64 )
33     v0 = v28;
34   if ( (v20 | v19 | v25 & v26) != (~*v15 & v26 | 864693332579200012i64) || v0 != 1 )
35   {
36     sub_1400019C0(std::cout, "Wrong answer!try again");
37     j_j_free(v3);
38   }
39   else
40   {
41     v29 = sub_1400019C0(std::cout, "Congratulations!flag is GXY{");
42     v30 = &Memory;
43     if ( v38 >= 0x10 )
44       v30 = Memory;
45     v31 = sub_140001FD0(v29, v30, v37);
46     sub_1400019C0(v31, "}");
47     j_j_free(v3);
48   }

代码分析

针对第三部分:

首先整理第三部分的各个运算式子

v19 = v15[1] & v17[0]
v20 = v15[2] & ~v15[0]
v20 = 1176889593874
v21 = ~v15[1]
v22 = v15[2] & ~v15[1]
v23 = v15[0] & ~v15[1]
v24 = (v15[2] & ~v15[0]) | (v15[1] & v15[0]) | (v15[2] & ~v15[1]) | (v15[0] & ~v15[1])
v24 = 4483974544037412639
v25 = v15[1]
v26 = v15[2]
v27 = (v15[2] & ~v15[1]) & v15[0] | v15[2] & ((v15[1] & v17[0]) | v15[1] &~v15[0] | ~(v15[1] | v15[0]))
v27 = 577031497978884115
v24 ^ v15[3] = 4483974543195470111
((v15[2] & ~v15[0]) | ( v15[1] & v17[0]) | v15[1] & v15[2]) == (~v15[0] & v15[2] | 864693332579200012)

使用z3解方程,得到v15[0]~v15[3]的解

# -*- coding:utf-8 -*-

from z3 import *

x,y,z,w=BitVecs('x y z w',64)

s=Solver()

s.add((~x)&z==1176889593874)
s.add(((z&~x)|(x&y)|(z&(~y))|(x&(~y)))^w==4483974543195470111)
s.add(((z&~y)&x|z&((x&y)|y&~x|~(y|x)))==577031497978884115)
s.add(((z&~x)|(x&y)|(z&~y)|(x&~y))==4483974544037412639)
s.add(((z&(~x)) | (x&y) | y & z) == (((~x)& z)|864693332579200012))

s.check()
m = s.model()
for i in m:
    print("%s = 0x%x"%(i,m[i].as_long()))

w = 0x32310600
z = 0x8020717153e3013
y = 0xc00020130082c0c
x = 0x3e3a460533286f0d

针对第二部分:

将x,y,z,w拼接起来,并将x,y,z补足为16位

li=[]
# 拼接
li.append(hex(m[x].as_long())[2:].rjust(16,"0"))
li.append(hex(m[y].as_long())[2:].rjust(16,"0"))
li.append(hex(m[z].as_long())[2:].rjust(16,"0"))
li.append(hex(m[w].as_long())[2:-2])
print(li)

['3e3a460533286f0d', '0c00020130082c0c', '08020717153e3013', '323106']

针对第一部分:

就是一个异或的表达式,通过动态调试可以得到Dst的值为"i_will_check_is_debug_or_not",即可得到v7,再将异或逆向就行。

脚本解密

# -*- coding:utf-8 -*-

from z3 import *

debug_str = "i_will_check_is_debug_or_not"
x,y,z,w=BitVecs('x y z w',64)

s=Solver()

s.add((~x)&z==1176889593874)
s.add(((z&~x)|(x&y)|(z&(~y))|(x&(~y)))^w==4483974543195470111)
s.add(((z&~y)&x|z&((x&y)|y&~x|~(y|x)))==577031497978884115)
s.add(((z&~x)|(x&y)|(z&~y)|(x&~y))==4483974544037412639)
s.add(((z&(~x)) | (x&y) | y & z) == (((~x)& z)|864693332579200012))

s.check()
m = s.model()
for i in m:
    print("%s = 0x%x"%(i,m[i].as_long()))
flag=""
li=[]
# 拼接
li.append(hex(m[x].as_long())[2:].rjust(16,"0"))
li.append(hex(m[y].as_long())[2:].rjust(16,"0"))
li.append(hex(m[z].as_long())[2:].rjust(16,"0"))
li.append(hex(m[w].as_long())[2:-2])
print(li)

v4=0
for i in li:
    for j in range(0,len(i),2):
        xx = i[j]+i[j+1]
        flag += chr(int(xx,16)^ord(debug_str[(v4)%27]))
        v4 += 1
    print(flag)

解出来得到的flag为

We1l_D0n
We1l_D0ndeajoa_S
We1l_D0ndeajoa_Slgebra_a
We1l_D0ndeajoa_Slgebra_am_i

get flag!

通过官方给的提示,第二部分有问题,给了第二部分的解“e!P0or_a”,替换掉我们得到的,得到正确的flag

GXY{We1l_D0ne!P0or_algebra_am_i}

完整WP:链接1链接2

原文地址:https://www.cnblogs.com/Mayfly-nymph/p/12099456.html