REVERSE-COMPETITION-0xGame2021
- Signin: User Friendly
- Installer
- Our Compilation Story
- Packet
- Random Chaos
- Neverland
- Roundabout
- Despacito
- Secret Base
- Maze
- Zero Three
- Mirror
- Thread_TLS
- 茶谈室
- Junkertown
Signin: User Friendly
64位exe,ida打开,在main函数中直接看到flag
Installer
.pyc文件,用uncompyle6反编译一下
from flag import *
length = len(flag)
arr = []
enc = [238, 257, 150, 137, 167, 169, 184, 193, 210, 147, 219, 128, 140, 135, 185, 242, 204, 128, 132, 159, 222, 173, 226, 159, 207, 169, 154, 156, 216, 139, 168, 187, 220, 237, 207, 187, 218, 138, 218, 178, 246, 239, 246, 241]
for i in range(length):arr.append(ord(flag[i]))for i in range(0, 16):for j in range(0, length):arr[j] += enc[j]enc[j] += enc[j]enc = enc[::-1]print(arr)
直接写逆脚本即可得到flag
res=[15728448, 16362025, 13718731, 13740602, 11425044, 13216326, 10048823, 13740603, 12757531, 12255100, 15138636, 12408061, 11228430, 10289095, 10114289, 14723575, 11272070, 9524519, 10267251, 12517282, 11796345, 13653174, 12495389, 13172636, 11468724, 9458930, 8956506, 12320680, 15291551, 11119205, 9568155, 10201663, 10398270, 14745427, 10944395, 13260012, 13194479, 11053619, 12145871, 11184688, 11359448, 11774503, 16602251, 15662990]
enc=[238, 257, 150, 137, 167, 169, 184, 193, 210, 147, 219, 128, 140, 135, 185, 242, 204, 128, 132, 159, 222, 173, 226, 159, 207, 169, 154, 156, 216, 139, 168, 187, 220, 237, 207, 187, 218, 138, 218, 178, 246, 239, 246, 241]
for i in range(0,16):for j in range(0,len(res)):res[j]-=enc[j]enc[j]+=enc[j]enc=enc[::-1]
print("".join(chr(i) for i in res))
# 0xGame{b373edd6-2cea-11ec-8d3d-0242ac130003}
Our Compilation Story
py文件,主要逻辑相当于,res=“qwq”,res+=chr(ord(res[0])^ord(flag[0])),写逆脚本即可得到flag
res=[21,44,45,104,31,30,26,121,65,125,23,112,77,46,47,126,89,112,7,109,7,88,10,105,104,59,54,91,83,98,32,54,15,65,113,119,113]
res=res[::-1]
flag=[]
for i in range(0,len(res)-3):flag.append(res[i]^res[i+3])
print("".join(chr(i) for i in flag))
# 0xGame{Th3_10ng_w4y_w3_901ng_fr33}
Packet
32位exe,upx脱壳,ida打开
main函数中,验证输入长度是否为40,对输入进行变换,最后与enc数据比较
写爆破脚本可得到flag
enc=[0x91,0x77,0xfb,0xe,0xb7,0xcc,0xe4,0x38,0x11,0x94,0xfd,0x85,0x5c,0x91,0x84,0x5c,0x7d,0x67,0x27,0x134,0x135,0xa,0xd8,0x23,0xd,0x30,0x65,0x3e,0x13,0x45,0x54,0x52,0x51,0x3e,0xb0,0xd9,0x13,0x33,0xc3,0xff]
check=[0xa1,0xf,0xbc,0x6f,0xda,0xa9,0x9f,0x5e,0x29,0xf6,0xc5,0xe4,0x6e,0xf2,0xb1,0x38,0x1b,0x1,0x11,0x100,0x100,0x32,0xe9,0x41,0x68,0x2,0x4,0x6,0x2a,0x70,0x37,0x6b,0x30,0x5d,0x82,0xe8,0x25,0x57,0xf2,0x82]
flag=[0]*len(enc)
for i in range(len(flag)):for j in range(48,128):if check[i] & ~j | j & ~check[i]==enc[i]:flag[i]=jbreak
print("".join(chr(i) for i in flag))
# 0xGame{f8b8a2c5dff64581be2a895c9ac216d1}
Random Chaos
64位exe,ida打开
main函数中,设置随机数种子为固定的8225,验证输入长度是否为40,输入与随机数异或后与enc数据比较
写c代码得到固定随机数种子生成的随机数
#include<stdio.h>
#include<stdlib.h>
int main()
{srand(8225);unsigned __int8 rand_num;for (int i = 0; i < 40; i++){rand_num = rand();printf("%d,", rand_num);}return 0;
}
//18,178,64,120,149,158,83,249,40,227,205,240,83,117,33,22,186,246,183,68,161,45,143,136,175,180,40,120,242,240,160,198,36,70,28,21,45,140,106,11
写enc数据与随机数异或脚本即可得到flag
arr=[0x22, 0xCA, 0x07, 0x19, 0xF8, 0xFB, 0x28, 0x9D, 0x1E, 0x80,0xAC, 0xC9, 0x60, 0x46, 0x18, 0x21, 0xDF, 0x95, 0xD5, 0x70,0xC5, 0x19, 0xEA, 0xB0, 0x9C, 0x83, 0x11, 0x4A, 0x93, 0xC7,0x91, 0xF6, 0x14, 0x71, 0x2F, 0x22, 0x14, 0xBF, 0x58, 0x76]
rand_num=[18,178,64,120,149,158,83,249,40,227,205,240,83,117,33,22,186,246,183,68,161,45,143,136,175,180,40,120,242,240,160,198,36,70,28,21,45,140,106,11]
for i in range(len(arr)):arr[i]^=rand_num[i]
print("".join(chr(i) for i in arr))
# 0xGame{d6ca93397ecb4d4e83792a7100737932}
Neverland
64位exe,运行后会自动打印部分flag,ida打开
main函数,for循环中,i为下标,idx[i]作为参数传入func函数,返回值存入v3,然后v3与enc数据的最低字节异或,异或的结果即为打印出的flag
主要是得到每次循环中v3的值,进入func函数,发现是递归调用
idx中的前10个数传入func,都能很快返回到v3,打印出"0xGame{1e6"
后面的数传入func,需要一段时间才能返回
动态调试一下,观察每次循环中v3的值,是否存在某种规律
断点下在xor运算前,此时eax为enc中的数据,为0xBFFCC,只看最低字节,为0xCC
ecx为func返回的值,即v3,v3是个char类型的变量,所以我们只看ecx最低字节即可,此时为0xFC
多进行几次循环,依次记录下前10组eax和ecx的最低字节,可找到某种规律
比如,v3的值大多是0xFC,0x04等
enc中以0xC,0x8,0x9开头的数都对应v3为0xFC
enc中以0x4,0x6,0x3开头的数都对应v3为0x04
enc中其他没有规律的数找对应的特定v3即可
于是可以按上述规律手动填充完整v3,与enc异或即可得到flag
enc=[0xcc,0x84,0x43,0xdd,0x59,0x61,0x87,0x35,0x99,0x32,0x36,0xc9,0x98,0x30,0x9f,0xcc,0xc8,0x62,0x99,0x30,0xc8,0x9a,0xc5,0x9e,0x32,0xc4,0xc8,0x60,0x3d,0x35,0x3d,0xcb,0x34,0x3c,0x9f,0x65,0x65,0x33,0x66,0x79]
v3_=[0xfc,0xfc,0x04,0xbc,0x34,0x04,0xfc,0x04,0xfc,0x04,0x04,0xfc,0xfc,0x04,0xfc,0xfc,0xfc,0x04,0xfc,0x04,0xfc,0xfc,0xfc,0xfc,0x04,0xfc,0xfc,0x04,0x04,0x04,0x04,0xfc,0x04,0x04,0xfc,0x04,0x04,0x04,0x04,0x04]
#idx=[0x9,0xf,0xc,0x3,0x2,0x10,0xb,0xe,0x7,0xa,0x2e,0x2d,0x2b,0x2e,0x2f,0x2d,0x2f,0x28,0x31,0x3a,0x31,0x33,0x33,0x2b,0x32,0x37,0x37,0x38,0x3c,0x30,0xffffffce,0xffffff93,0xffffffd8,0xfffffff2,0xffffffdf,0xffffff70,0xffffff72,0xffffffd0,0xffffffa6,0xffffff9a]
flag=[]
for i in range(len(v3_)):flag.append(enc[i]^v3_[i])
print("".join(chr(i) for i in flag))
# 0xGame{1e625d4c04fe44f9b684d919708caa7b}
Roundabout
32位exe,upx脱壳,ida打开
main函数中,验证输入的长度是否为42,然后是简单的异或运算
取出str和res,写逆运算脚本即可得到flag
s="this_is_not_flag"
res=[0x44,0x10,0x2e,0x12,0x32,0xc,0x8,0x3d,0x56,0xa,0x10,0x67,0x0,0x41,0x0,0x1,0x46,0x5a,0x44,0x42,0x6e,0xc,0x44,0x72,0xc,0xd,0x40,0x3e,0x4b,0x5f,0x2,0x1,0x4c,0x5e,0x5b,0x17,0x6e,0xc,0x16,0x68,0x5b,0x12]
flag=""
for i in range(len(res)):flag+=chr(ord(s[i%16])^res[i])
print(flag)
# 0xGame{b8ed8f-af22-11e7-bb4a-3cf862d1ee75}
Despacito
64位exe,ida打开
从main函数中得知,主要逻辑为,将cipher.txt的数据作为密文,"0xgame21"作为密钥,解密DES,得到明文plain,对明文进行md5散列即为flag
写DES解密脚本并对明文进行md5散列即可得到flag
from Crypto.Cipher import DES
from Crypto.Util.number import long_to_bytes
import hashlib
cipher_hex=0x16806B89C3CEF86C4F62207B9B20D95820769C2A978A15D7EEEDE0B15E3318595E11BC840D5DA7971CB27C7EBA0BE155D1F0FB878227E959B5CD740DB9E56BE69F88B0B2BF27F83DE8B3C46EAD999A5B76E37D98418DEFE5D1A416DF4BB88D92
cipher_str=long_to_bytes(cipher_hex)
key_str="0xgame21"
des=DES.new(key_str,DES.MODE_ECB)
m=des.decrypt(cipher_str)
print(m)
# m==wLpGWGNJYVvBwLBCVzgatsuGZaAzbBUHPXjoUqdahnPzeLdZrKntUcYwPHFHxtrVgzyWwdUtYvgiQuLyqwQPFVaWQLaGuupA
h=hashlib.md5()
h.update(m.encode(encoding='utf-8'))
print("0xGame{"+h.hexdigest()+"}")
# 0xGame{83b9879f334340ef42dbb9f40468fc84}
Secret Base
32位exe,ida打开
main函数,encrypt对输入进行变表base64变换,结果放入res中,最后res和enc比较
直接解变表base64字符串即可得到flag
Maze
64位exe,ida打开
main函数中,先输入两个数,确定起始点为"S",再输入迷宫路线,终点为"E",只能沿着"."走,wsad分别为上下左右
maze为24*16大小的迷宫,起始点"S"下标为(2,4),按规则走完迷宫即可
# ************************
# **********..........****
# ****S......********.****
# *******************.****
# *******************.****
# ****E***********....****
# ****.****........*******
# ****.****.**************
# ****.****.**************
# ****.****........*******
# ****.***********.*******
# ****.***********.*******
# ****.***********...*****
# ****.*************.*****
# ****...............*****
# ************************
#
# route:
# ddddddwdddddddddssssaaasaaaaaaasssdddddddsssddssaaaaaaaaaaaaaawwwwwwwww
再次运行exe,先输入2和4,再输入route,即可得到flag
Zero Three
64位exe,ida打开
main函数中,验证输入的长度是否为32,将输入每四个字节为一组,组成一个32位的unsigned int数
例如,输入为"abcdefgh",则得到的两个32位数为0xdcba和0xhgfe
输入的32字节分成8个unsigned int数存入num,然后用方程组来验证输入是否正确
利用python的z3库解方程组,得到正确的8个unsigned int数,再转为字符串形式即为正确的输入,包上"0xGame{}"即为flag
需要注意的是,方程组等式右边的值需要在ida中按h化成有符号十进制数再用z3计算
from z3 import *
num=[Int("num[%d]"%i) for i in range(8)]
s=Solver()
s.add(-22827 * num[4] + 21984 * num[1] + -38534 * num[5] - 32344 * num[0] == -98460819657603)
s.add(-38215 * num[2] + -37324 * num[4] + -8436 * num[5] + 15405 * num[0] == -131665436206262)
s.add(10926 * num[7] + -28942 * num[1] + -34572 * num[3] - 10538 * num[5] == -121891239772992)
s.add(-30117 * num[6] + -22990 * num[2] + -20471 * num[5] + 34494 * num[7] == -57089882568260)
s.add(-33112 * num[5] + -19335 * num[4] + 34348 * num[1] + 31445 * num[2] == 56335531538050)
s.add(-13566 * num[5] + 14758 * num[0] + -19814 * num[2] - 26447 * num[4] == -81105980248303)
s.add(25898 * num[5] + -15817 * num[1] + 20463 * num[7] - 33578 * num[0] == -28860618440412)
s.add(-35429 * num[7] + 36594 * num[2] + -28801 * num[6] - 14952 * num[3] == -45384029412201)
flag=""
if s.check()==sat:m=s.model()for i in range(8):res=eval(str(m.eval(num[i])))res=hex(res)[2:]for j in range(len(res)-2,-2,-2):flag+=chr(int(res[j:j+2],16))
print("0xGame{"+flag+"}")
# 0xGame{udydYCBxUB6vqsAt5VCs6LKDRqXLUhSW}
Mirror
64位exe,upx脱壳,ida打开
main函数,signin和encrypt都须返回1才能调用checkflag验证
跟进signin函数,输入两个整型的数input_0和input_1,调用两次calc,参数分别为0和1
一次calc相当于一个方程,两次calc则为两个方程
两个方程(两次calc),两个未知数(input_0和input_1,其他都可通过调试得到),可求解input_0和input_1
利用python的z3库解方程组,得到input_0和input_1
from z3 import *
input_0=Int("input_0")
input_1=Int("input_1")
s=Solver()
s.add(0x7563560E*0x7563560E+0x6C81E68B==0x136*(0x136*0x136+input_0)+input_1)
s.add(0xB0A47B8D*0xB0A47B8D+0x6681A442==0x2C0*(0x2C0*0x2C0+input_0)+input_1)
if s.check()==sat:print(s.model())
# [input_0 = 12446785179114514, input_1 = 20207707034304107]
跟进encrypt函数,flag长度为44,for循环中,flag与v2异或,调试得到每次循环时v2的值
写逆脚本即可得到flag
enc=[0x30, 0x78, 0x47, 0x61, 0x6D, 0x65, 0x7B, 0x5F, 0x5F, 0x5B,0x1F, 0x1C, 0x36, 0x25, 0x35, 0x51, 0x5D, 0x19, 0x74, 0x34,0x34, 0x19, 0x14, 0x2D, 0x76, 0x30, 0x64, 0x1F, 0x1C, 0x65,0x7F, 0x68, 0x51, 0x0A, 0x1A, 0x33, 0x69, 0x7F, 0x19, 0x44,0x6C, 0x1A, 0x34, 0x7D]
v2=[0xC,0x2C,0x43,0x55,0x11,0x5B,0xE,0x33,0x2A,0x2,0x7,0x46,0x46,0x22,0x1E,0x29,0x7]
for i in range(0,16+1):enc[i+9]^=v2[i]enc[i+26]^=v2[i]
print("".join(chr(i) for i in enc))
# 0xGame{__W3_c4n_n3v3r_63_7h3_0n3_901n9_fr33}
Thread_TLS
32位exe,ida打开
main函数,验证输入的长度是否为33,对输入进行异或运算,然后启动一个新线程,调用StartAddress函数
跟进StartAddress函数,input和enc比较,验证输入
对input按x进行交叉引用,发现在TlsCallback_1_0函数中对input有读写(r/w)
来到TlsCallback_1_0函数,发现是典型的RC4算法,input在第48行被加密了
现在知道RC4的密文为StartAddress函数中的enc,但是不知道密钥
继续对TlsCallback_1_0交叉引用,发现在TlsCallback_0_0函数中,对字符串"0xgame2021"进行变表base64变换,放入Source,而Source就是在TlsCallback_1_0函数中充当RC4密钥的作用
于是逆向思路为:调试得到经变表base64变换后的Source,也即RC4密钥,对enc解密RC4,再异或main函数中的byte_41B221即可得到flag
笔者记得当时按照上述逆向思路没有解出来,好像是RC4有点问题
我们知道RC4加密过程实际上就是让明文去异或一个值,而去异或的那个值是由密钥决定的
于是我们可以构造一个长度为33的任意字符串作为输入,让程序对这个字符串进行RC4加密,通过调试取出密文,让明文与密文异或,即可得到明文在RC4过程中去异或的那些值
然后让真正的密文enc与那些值异或,即可得到flag
例如,调试时的输入为"abcdefghijklmnopqrstuvwxyz0123456",在经过程序的RC4加密后得到密文
按照上述思路将真正的密文enc解RC4后,再对enc进行main函数中异或的逆运算,即可得到flag
# coding:utf-8 -*-
#s,任意字符串作为输入
s="abcdefghijklmnopqrstuvwxyz0123456"
arr=[ord(c) for c in s]
for i in range(len(arr)-1):arr[i]^=arr[i+1]
#arr_res,s经程序RC4后的密文
arr_res=[0x82, 0x40, 0xB8, 0x16, 0x84, 0x6F, 0xAE, 0x19, 0x77, 0x2C,0x0E, 0x6C, 0x9D, 0xA0, 0xE9, 0x1E, 0x2F, 0xE8, 0x2D, 0x52,0x32, 0x8F, 0x17, 0xBA, 0xB2, 0x71, 0x8E, 0x83, 0x6F, 0xB1,0x37, 0x53, 0x0A]
#xor_num,s在程序RC4过程中去异或的那些值
xor_num=[]
for i in range(len(arr)):xor_num.append(arr[i]^arr_res[i])
#enc,真正的密文
enc=[0xC9, 0x7E, 0x99, 0x1B, 0x8F, 0x70, 0xAE, 0x04, 0x2D, 0x6F,0x25, 0x03, 0xDC, 0x8D, 0xC8, 0x21, 0x40, 0xEE, 0x6D, 0x59,0x17, 0xA5, 0x00, 0xA4, 0x9D, 0x16, 0xCC, 0xD6, 0x61, 0xAA,0x7D, 0x12, 0x41]
#解密RC4
for i in range(len(enc)):enc[i]^=xor_num[i]
#main函数中的异或的逆运算
for i in range(len(enc)-2,-1,-1):enc[i]^=enc[i+1]
print("".join(chr(i) for i in enc))
# 0xGame{th1s_1s_a_34sy_tls_r1ght?}
茶谈室
apk文件,jadx-jui打开,MainActivity中,典型的TEA加密算法,iArr为密文,iArr2为密钥
解密TEA即可得到flag
#include <stdio.h>
#include <stdint.h>//加密函数
void encrypt(uint32_t* v, uint32_t* k) {uint32_t v0 = v[0], v1 = v[1], sum = 0, i; /* set up */uint32_t delta = 0x9e3779b9; /* a key schedule constant */uint32_t k0 = k[0], k1 = k[1], k2 = k[2], k3 = k[3]; /* cache key */for (i = 0; i < 32; i++) { /* basic cycle start */sum += delta;v0 += ((v1 << 4) + k0) ^ (v1 + sum) ^ ((v1 >> 5) + k1);v1 += ((v0 << 4) + k2) ^ (v0 + sum) ^ ((v0 >> 5) + k3);} /* end cycle */v[0] = v0; v[1] = v1;
}
//解密函数
void decrypt(uint32_t* v, uint32_t* k) {uint32_t v0 = v[0], v1 = v[1], sum = 0xC6EF3720, i; /* set up */uint32_t delta = 0x9e3779b9; /* a key schedule constant */uint32_t k0 = k[0], k1 = k[1], k2 = k[2], k3 = k[3]; /* cache key */for (i = 0; i<32; i++) { /* basic cycle start */v1 -= ((v0 << 4) + k2) ^ (v0 + sum) ^ ((v0 >> 5) + k3);v0 -= ((v1 << 4) + k0) ^ (v1 + sum) ^ ((v1 >> 5) + k1);sum -= delta;} /* end cycle */v[0] = v0; v[1] = v1;
}int main()
{uint32_t v[2] = { 1336390846, -560752372 };//0xGame{c//uint32_t v[2] = { 286770520, -1746160592 };//a5088de1//uint32_t v[2] = { 1494863960, 1998635107 };//0c64b61a//uint32_t v[2] = { -1598646557, 420086226 };//c1ef47a9//uint32_t v[2] = { 2098399929, 898703653 };//d5f51da}uint32_t k[4] = { 1489485296, 1094338644, -1085167593, 524527081 };int n = sizeof(v) / sizeof(uint32_t);decrypt(v, k);for (int i = 0; i < n; i++){for (int j = 3; j >= 0; j--){printf("%c", (v[i] >> (j * 8)) & 0xFF);}}printf("\n");return 0;
}
//0xGame{ca5088de10c64b61ac1ef47a9d5f51da}
Junkertown
32位exe,ida打开,main函数没有被分析出来,原因是加了花指令
如图所示,0x00401101的jz要跳转到loc_401103+1即loc_401104处
而ida从loc_401103处开始的机器码0xE8开始分析,反汇编成了一条call指令,从而造成ida分析main函数不成功,同时也反映出0xE8为垃圾指令,需要nop掉
main函数中其他未分析出的地方也是加了上述形式的垃圾指令,全部nop掉即可对main创建函数及反编译,反编译后的伪代码如下所示
int __cdecl main(int argc, const char **argv, const char **envp)
{int v3; // eaxsigned int v4; // kr00_4signed int i; // esisigned int v6; // eaxsigned int v7; // edxsigned int v8; // kr04_4int v9; // esiint v10; // ediconst char *base_str; // ebxint v12; // ecxint v13; // eaxconst char *v14; // esichar *v15; // ebxunsigned int v16; // ediunsigned int v17; // ecxunsigned int v18; // edxint v19; // eaxunsigned int v20; // ecxint v21; // ediint v22; // edxint j; // esiint v24; // ecxint v25; // ebxchar v27; // [esp-10h] [ebp-6Ch]char v28; // [esp-Ch] [ebp-68h]char v29; // [esp-4h] [ebp-60h]char v30; // [esp+0h] [ebp-5Ch]int v31; // [esp+Ch] [ebp-50h]const char *v32; // [esp+10h] [ebp-4Ch]char input[60]; // [esp+1Ch] [ebp-40h] BYREFmemset(input, 0, sizeof(input));sub_401040("Welcome to 0xgame2021!\n", v28);sub_401040("please input your flag:\n", v27);sub_401070("%s", (char)input);if ( &input[strlen(input) + 1] - &input[1] != 44 )goto LABEL_2;v3 = 256;do--v3;while ( v3 );v4 = strlen(input);for ( i = 0; i < v4; ++i )input[i] = 16 * input[i] + ((input[i] >> 4) & 0xF);// 输入中每字节的高四位和低四位交换v6 = 0;v7 = v4 - 1;if ( v4 - 1 > 0 ){if ( (unsigned int)v7 >= 0x40 ){do{*(__m128i *)&input[v6] = _mm_xor_si128(*(__m128i *)&input[v6 + 1], *(__m128i *)&input[v6]);*(__m128i *)&input[v6 + 16] = _mm_xor_si128(*(__m128i *)&input[v6 + 17], *(__m128i *)&input[v6 + 16]);*(__m128i *)&input[v6 + 32] = _mm_xor_si128(*(__m128i *)&input[v6 + 33], *(__m128i *)&input[v6 + 32]);*(__m128i *)&input[v6 + 48] = _mm_xor_si128(*(__m128i *)&input[v6 + 49], *(__m128i *)&input[v6 + 48]);v6 += 64;}while ( v6 < v7 - v7 % 64 );}for ( ; v6 < v7; ++v6 )input[v6] ^= input[v6 + 1]; // 输入前一位和后一位异或}v8 = strlen(input);v9 = 4 * (v8 / 3);v10 = v8 % 3;if ( v8 % 3 )v9 += 4;base_str = (const char *)malloc(__CFADD__(v9, 16) ? -1 : v9 + 16);v12 = v9 - 2;v32 = base_str;v13 = 0;base_str[v9] = 0;if ( v9 - 2 > 0 ){v14 = base_str + 2;v15 = &input[1];v16 = ((unsigned int)(v12 - 1) >> 2) + 1;v31 = 4 * v16;do // 输入经过标准base64变换{v17 = (unsigned __int8)*(v15 - 1);v15 += 3;v18 = (unsigned __int8)*(v15 - 3);v14 += 4;*((_BYTE *)v14 - 6) = byte_403110[v17 >> 2];v19 = (16 * (v17 & 3)) | (v18 >> 4);v20 = (unsigned __int8)*(v15 - 2);*((_BYTE *)v14 - 5) = byte_403110[v19];*((_BYTE *)v14 - 4) = byte_403110[(4 * (v18 & 0xF)) | (v20 >> 6)];*((_BYTE *)v14 - 3) = byte_403110[v20 & 0x3F];--v16;}while ( v16 );v10 = v8 % 3;base_str = v32;v13 = v31;}v21 = v10 - 1;if ( v21 ){if ( v21 == 1 )base_str[v13 - 1] = '=';}else{*(_WORD *)&base_str[v13 - 2] = '==';}v22 = strlen(base_str);for ( j = 0; j < v22; ++j )base_str[j] = 16 * base_str[j] + ((base_str[j] >> 4) & 0xF);// 经标准base64变换的输入每字节高四位和低四位交换v24 = 0;if ( v22 > 0 ){v25 = base_str - enc;while ( enc[v24 + v25] == enc[v24] ){if ( ++v24 >= v22 )goto LABEL_28;}
LABEL_2:puts("Wrong flag!!");exit(0);}
LABEL_28:sub_401040("Congratulation to you!!\n", v30);sub_401040("This is a right flag", v29);return 0;
}
对输入进行处理的逻辑为,输入每字节的高四位和低四位交换,输入前一位和后一位异或,输入经标准base64变换,变换后的数据每字节高四位和低四位交换
写逆运算脚本即可得到flag
import base64
enc=[0x86, 0x05, 0xE4, 0x96, 0x77, 0x94, 0x44, 0x86, 0x76, 0x16,0x75, 0x13, 0xD4, 0x74, 0x55, 0x77, 0x77, 0xA4, 0x44, 0x24,0x87, 0x64, 0x65, 0x14, 0x15, 0xA4, 0x74, 0x25, 0x65, 0x85,0x85, 0x77, 0x15, 0x36, 0x15, 0x65, 0xB6, 0xA4, 0x44, 0x25,0xF6, 0x45, 0x24, 0x14, 0xE4, 0x16, 0x75, 0x13, 0xA5, 0x15,0x65, 0x15, 0x55, 0x84, 0x55, 0x64, 0x43, 0x46, 0x36, 0xD3]
for i in range(len(enc)):enc[i]=((enc[i]&0x0f)<<4)|((enc[i]&0xf0)>>4)
s="".join(chr(i) for i in enc)
s=base64.b64decode(s)
arr=[ord(c) for c in s]
for i in range(len(arr)-2,-1,-1):arr[i]^=arr[i+1]
for i in range(len(arr)):arr[i] = ((arr[i] & 0x0f) << 4) | ((arr[i] & 0xf0) >> 4)
flag="".join(chr(i) for i in arr)
print(flag)
# 0xGame{c9ba7481-a404-4a69-a090-740c9b4dad3c}