很抱歉本次比赛给大家带来了不好的体验,本次比赛的本意是让大家学到更多的知识,所以大家就当做是学习资源,去复现这些题吧(不懂的地方可以私聊我) 签到 抱歉抱歉,给各位磕了,第一版附件难了,看第二版就行了! (其实就是加了一点点知识)
旧附件
无壳,32位
定位到关键的代码函数
1 2 for ( i = 0; i < strlen(Str); ++i ) Str[i] ^= (unsigned __int8)i ^ 2
这个str[i]^=i^2可以看成str[i]=str[i]^i^2
C语言基础的语法了属于是
然后密文在哪??额这波纯属是我套娃了,密文在一个定义的函数里面,函数嵌套了16层(闲得无聊弄得)
可以选择点击16次找到定义密文的函数,也可以shift+f12拿到密文
至于这个加密怎么逆呢,就……再异或一遍就行了
这就是异或的特征了,写脚本的时候这么写就行了,这里附上简单的python脚本:
1 2 3 4 5 6 7 8 9 10 flag = "SONT}Paii;eVZ?S\\#}eRBqKDVUMFGfXn_" flag_list = list (flag) new_flag_list = [] for i in range (len (flag_list)): flag_list[i] = ord (flag_list[i]) ^ i ^ 2 new_flag_list.append (chr (flag_list[i])) new_flag = '' .join (new_flag_list) print (new_flag)
当然由于大家最近在学c,我也顺便附上c的代码。其实本质上这些代码都差不多
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 #include <stdio.h > #include<string.h > int main ( ) { char flag[] = "SONT}Paii;eVZ?S\\#}eRBqKDVUMFGfXn_" ; char new_flag[strlen (flag)+1 ]; for (int i = 0 ; i < strlen (flag); i++) { flag[i] = flag[i] ^ i ^ 2 ; new_flag[i] = flag[i]; } new_flag[strlen (flag)] = '\0' ; printf ("%s\n" , new_flag); return 0 ; }
当然,GPT的话,就直接秒了……ε=(´ο`*)))唉
flag:QLNU{Welc0m_T0_Q1nuCTf_QLNU_YyDs} 上面的修改附件之后的题解,以下是新附件的wp:
新附件
改完附件之后题目简单了很多,之前是嵌套了很多层的函数嵌套然后就改成了一层,找到v5 = (const char *)&unk_41B000;点进去就是密文
可以shitf+e提取字符串,提取输出,然后看后面的加密是一个异或2,所以直接上脚本就秒了!
可以选择赛博厨子
至于为什么是2u,2是数据,u是代表这个2是十进制的2,所以用u来表示
原始人!!起洞!!!! 这个题是拿的newstar week2 的原题,个人觉得这个题是对于新手入门挺好的,所以就拿来用了,并且稍微改了改!希望出题人可以不要介意呜呜
安卓逆向题,安卓逆向的话,逆的是java代码,其实本质上和c差不多
反编译apk的工具很多,jeb,jadx,androidkiller都行,我个人喜欢jadx
先用模拟器打开一下看看吧!
原神的登录界面,各位可以去反编译找到登录的代码然后找到账号和密码
main函数一般是在com文件夹下,然后找找就找到了
代码看起来可能确实是吃力,但是,英文字母和简单的if语句应该能看的到
这里是判断,username是否等于genshinimpact
如果不是的话,就会有一个.show()的语句,意思大概是展示一个窗口,这里猜测就是账号错误的窗口提示吧
如果是的话才会继续走下面的函数,也就是所谓的加密密码的函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 if (!username.equals ("genshinimpact" )) { Toast .makeText (MainActivity .this , (int) bin.mt .plus .TranslationData .R .string .wrong1 , 0 ).show (); } int[] encode_table = {125 , 239 , 101 , 151 , 77 , 163 , 163 , 110 , 58 , 230 , 186 , 206 , 84 , 84 , 189 , 193 , 30 , 63 , 104 , 178 , 130 , 211 , 164 , 94 , 75 , 16 , 32 , 33 , 193 , 160 , 120 , 47 , 30 , 127 , 157 , 66 , 163 , 181 , 177 , 47 , 0 , 236 , 106 , 107 , 144 , 231 , 162 , 16 , 36 , 34 , 91 , 9 , 188 , 81 , 5 , 241 , 235 , 3 , 54 , 150 , 40 , 119 , 202 , 150 }; String retval = whatwhatme.encodee (username, encode_table); String result2 = whatme.encode (password.getBytes (), retval); if (!result2.equals ("VVwPUWsYcXEPW0MpN35gW0FwW1RxandgJTE8" )) { Toast .makeText (MainActivity .this , (int) bin.mt .plus .TranslationData .R .string .wrong2 , 0 ).show (); return ;
首先下面就出现了一个encode_table,并且后面有数据,可以大概猜测一下
1 int[] encode_table = {125 , 239 , 101 , 151 , 77 , 163 , 163 , 110 , 58 , 230 , 186 , 206 , 84 , 84 , 189 , 193 , 30 , 63 , 104 , 178 , 130 , 211 , 164 , 94 , 75 , 16 , 32 , 33 , 193 , 160 , 120 , 47 , 30 , 127 , 157 , 66 , 163 , 181 , 177 , 47 , 0 , 236 , 106 , 107 , 144 , 231 , 162 , 16 , 36 , 34 , 91 , 9 , 188 , 81 , 5 , 241 , 235 , 3 , 54 , 150 , 40 , 119 , 202 , 150 };
下面定义了一个retval的数值,然后调用了whatwahtme.encode()函数,并且导进去了两个参数,一个和是username,另一个就是刚才的encode_table,双击点进去看看whatwhatme是一个啥玩意!
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 public class whatwhatme { public static String encodee (String keyStr, int[] data ) { byte[] key = keyStr.getBytes (); int[] s = new int[256 ]; int[] k = new int[256 ]; int j = 0 ; for (int i = 0 ; i < 256 ; i++) { s[i] = i; k[i] = key[i % key.length ]; } for (int i2 = 0 ; i2 < 256 ; i2++) { j = (s[i2] + j + k[i2]) & 255 ; int temp = s[i2]; s[i2] = s[j]; s[j] = temp; } StringBuilder result = new StringBuilder (); int j2 = 0 ; int i3 = 0 ; for (int i4 : data) { i3 = (i3 + 1 ) & 255 ; j2 = (s[i3] + j2) & 255 ; int temp2 = s[i3]; s[i3] = s[j2]; s[j2] = temp2; int rnd = s[(s[i3] + s[j2]) & 255 ]; result.append ((char) (i4 ^ rnd)); } return result.toString (); } }
如果问gpt了的话或者做过类似的题话,可以看出来这里是一个rc4的加密,并且加密的秘钥是刚刚的用户名,然后加密的密文是刚刚的encode_yable
rc4加密虽然过程很复杂,就是什么什么盒子又是什么盒子,只要没有动算法,那就可以把他当成黑盒子,然后就可以当成异或就行了,他也是可逆的
网上随便搜个python的脚本就行然后加密得到了我们加密(解密)之后的数据:
BADCFEHGJILKNMPORQTSVUXWZYbadcfehgjilknmporqts.uxwzy1032547698/+
这玩意说实话一眼顶针,很明显了就是base64的码表了,盲猜后面的就是base换表加密了!
这里就贴上一个rc4的解密脚本:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 def decode (key_str, data): key = key_str.encode () s = list (range (256 )) k = [key[i % len (key)] for i in range (256 )] j = 0 for i in range (256 ): j = (s[i] + j + k[i]) & 255 s[i], s[j] = s[j], s[i] result = bytearray () j2 = 0 i3 = 0 for i in range (len (data)): i3 = (i3 + 1 ) & 255 j2 = (s[i3] + j2) & 255 s[i3], s[j2] = s[j2], s[i3] rnd = s[(s[i3] + s[j2]) & 255 ] result.append (data[i] ^ rnd) return result.decode () key = "genshinimpact" encoded_data = [125 , 239 , 101 , 151 , 77 , 163 , 163 , 110 , 58 , 230 , 186 , 206 , 84 , 84 , 189 , 193 , 30 , 63 , 104 , 178 , 130 , 211 , 164 , 94 , 75 , 16 , 32 , 33 , 193 , 160 , 120 , 47 , 30 , 127 , 157 , 66 , 163 , 181 , 177 , 47 , 0 , 236 , 106 , 107 , 144 , 231 , 162 , 16 , 36 , 34 , 91 , 9 , 188 , 81 , 5 , 241 , 235 , 3 , 54 , 150 , 40 , 119 , 202 , 150 ] decoded_data = decode (key, encoded_data) print ("re4解密之后的码表:" , decoded_data)
虽然能猜到是base64,但是继续往下看吧:
这里定义了一个result2,并且走的 是whatme.encode()的加密方式
并且也是调用了两个参数,一个是刚刚输入的密码也就是password,并且后面有getBytes()方法,就是把密码变成比特形的数据传进去
跟进一下whatme.encode
这是标准的base64算法,跟刚才猜的一样,然后数据应该就是下面的那个if的判断了,直接拿那个密文和刚刚rc4得到的码表去赛博厨子也能直接秒了!
这边也顺便给上全部的脚本:
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 import base64import stringdef decode (key_str, data): key = key_str.encode () s = list (range (256 )) k = [key[i % len (key)] for i in range (256 )] j = 0 for i in range (256 ): j = (s[i] + j + k[i]) & 255 s[i], s[j] = s[j], s[i] result = bytearray () j2 = 0 i3 = 0 for i in range (len (data)): i3 = (i3 + 1 ) & 255 j2 = (s[i3] + j2) & 255 s[i3], s[j2] = s[j2], s[i3] rnd = s[(s[i3] + s[j2]) & 255 ] result.append (data[i] ^ rnd) return result.decode () key = "genshinimpact" encoded_data = [125 , 239 , 101 , 151 , 77 , 163 , 163 , 110 , 58 , 230 , 186 , 206 , 84 , 84 , 189 , 193 , 30 , 63 , 104 , 178 , 130 , 211 , 164 , 94 , 75 , 16 , 32 , 33 , 193 , 160 , 120 , 47 , 30 , 127 , 157 , 66 , 163 , 181 , 177 , 47 , 0 , 236 , 106 , 107 , 144 , 231 , 162 , 16 , 36 , 34 , 91 , 9 , 188 , 81 , 5 , 241 , 235 , 3 , 54 , 150 , 40 , 119 , 202 , 150 ] decoded_data = decode (key, encoded_data) print ("re4解密之后的码表:" , decoded_data)string = "VVwPUWsYcXEPW0MpN35gW0FwW1RxandgJTE8" #base64密文 tableBase64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" #base64原来的码表 tableNew = decoded_data flag = base64.b64decode (string.translate (str.maketrans (tableNew, tableBase64))) print ("解密之后的flag:" ,end="" )print ( flag )'' ' 一些base64库的函数介绍: maketrans():用于创建字符映射的转换表,对于接受两个参数的最简单的调用方式,第一个参数是字符串,表示需要转换的字符,第二个参数也是字符串表示转换的目标; translate():法根据参数table给出的表(包含 256 个字符)转换字符串的字符, 要过滤掉的字符放到 del 参数中; decode():以encoding指定的编码格式解码字符串。' ''
flag:QLNU{YuaN_Sh3n!_Q1_D0ng!!!}
另外其实whatwhatme和whatme这俩函数上面也有提示是什么加密,细心的人捏应该已经看到了
彩蛋:拿到正确的flag输入为密码时,会真正的原神启动!!!!
澳门博彩模拟器 这个题可能是在你们的环境上有点问题,可能会报毒,而且好像部分python版本太高的电脑用uncompyle6反编译不了!然后pycdc可能搜到的东西也比较少,所以就爆0了 python打包的exe
查壳
pyinstaller,这个可不算是什么壳,这个是真的打包工具,是python写的py文件,然后使用pyinstaller打包出来的exe程序
具体的讲解可以学习一下雪月三十佬的博客:
exe文件转py文件 exe -> pyc -> py 详细步骤(例题)
他用的是uncompyle6,但是随着现在时代的进步,uncompyle6只能支持python 3.8.6之前的版本了,后面的版本就编译不了了(出的题时候用的3.10,编译了好久好久都寄)
现在推荐用pycdc,但是吧,pycdc有点难配置(指要用ide和cmake加载程序)大佬可以自行搜素配置
首先是exe -> py,这一步就有pyinstxtractor就行
python pyinstxtractor game.exe
然后就转到了pyc,之后可以用uncompyle6
pip install uncompyle6 配置环境
uncompyle6 game.pyc 得到源码,当然为了方便观看,就加上 ->来生成一个1.py
打开之后,发现汉字是乱码,并且用pycharm打开的话提示编码问题
那就将编码设置为GBK吧,然后就可以看到完整的源码,找到几个比较关键的地方
首先是一个enc的数值:
enc = ‘48514D5A4C5455364141416A466855544B67456D46523874487773644B5473505067347A436877304743674A4541494B6643556D4A7967704B6E6439’
然后往下看看哪里调用了这个enc的数据:
这里有一个购买密文的地方,调用了enc,然后传入了一个encodeeee.cccccccc()函数里面
但是在这个game里面并没有找到我们要的encodeeee.cccccccc()这个函数,说明是调用了外部的函数
再看一下文件头:
有一个import
Time 和 random是python自带的内置函数,但是那个encodeeee这个名字,一看就知道是我们自己定义的,所以可以找找有没有encodeeee.pyc这个文件,并且给他编译回py看代码
有的有的!编译一下
反编译后打开就看到了这个cccccccc函数,参数应该就是那个enc
这个函数是干啥的嘞,23级数电应该学到了BCD8421码吧,我就不多解释了,这里就是一个BCD码转化成字符串的代码,当然也可以拿赛博厨子嗦:
得到了被加密之后的密文,这里再给一个python的代码实现相应的功能 (不用会写,会用就行)
1 2 3 4 5 6 7 8 9 def bcd_to_string (bcd_string ): output_string = "" for i in range (0 , len (bcd_string), 2 ): bcd_code = int (bcd_string[i:i+2 ], 16 ) output_string += chr (bcd_code) return output_string enc = "48514D5A4C5455364141416A466855544B67456D46523874487773644B5473505067347A436877304743674A4541494B6643556D4A7967704B6E6439" secret = bcd_to_string(enc) print ("我们得到的密文是:" +secret)
然后回到game.py继续看
我记得是玩游戏的时候是可以选择验证flag还是玩游戏获得密文来着,到现在我们就完成了获得密文的工作
验证flag的话,看一下
还是调用了encodeeee里面的check_flag()的方法
浅看一下:
大体的流程就是,首先把enc经过bec转字符串函数,得到我们的密文,刚刚也得到了:HQMZLTU6AAAjFhUTKgEmFR8tHwsdKTsPPg4zChw0GCgJEAIKfCUmJygpKnd9
然后是一个异或:
1 2 for i in range (len (inputs) - 1 ): inputs[i] = inputs[i] ^ inputs[i + 1 ] ^ i
这个呢就是一个自身异或之后再和i异或,逆的话要从后往前进行,并且异或一下i就行
再然后就是一个base64了
逆向的过程就是先解base64–>然后异或–>拿到flag
脚本奉上:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 import base64def bcd_to_string (bcd_string ): output_string = "" for i in range (0 , len (bcd_string), 2 ): bcd_code = int (bcd_string[i:i+2 ], 16 ) output_string += chr (bcd_code) return output_string enc = "48514D5A4C5455364141416A466855544B67456D46523874487773644B5473505067347A436877304743674A4541494B6643556D4A7967704B6E6439" secret = bcd_to_string(enc) print ("我们得到的密文是:" +secret)secret = secret.encode('utf-8' ) secret = bytearray (base64.b64decode(secret)) secret = secret.decode('utf-8' ) for i in range (len (secret) - 2 , -1 , -1 ): secret = secret[:i] + chr (ord (secret[i]) ^ i ^ ord (secret[i + 1 ])) + secret[i + 1 :] print ("解密之后的flag:" +secret)
flag:QLNU{Just_@_GamE_PlaypLay_HappY_hApPy!!!!!!!}
base64??快秒!! 本来题更难,在原有的基础上,把逻辑弄得稍微复杂了一点,然后就改回了”简略版”
然后下面是校赛版本:
本次可以拿这个反编译的代码和正常的base64加密后的代码对比一下,其实仔细观察就发现是对于base64的加密源码进行了一些”稍微”的改动
这是常规的base64编码,在后面有前三个位移是,2,4,6并且没有异或符号,但是反观本题的base64,它不仅仅是0,6,4,2的位移,而且还在后面加了一个异或符号
虽然看上去是修改了base64的加密流程,其实base64还是base64,只是重新分配了顺序
所以逆向的大体思路可以是先四个为一组倒过来排列,然后再异或各自的数字就可以了
解密脚本如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 import base64 secret = "G~QW]r\TpmCQK?5WNH\[nTnLnHROqPif}?Rgn3CS~Phg`T7ZG?ROn3CS1PSO" enc = [] for i in range(0 , len(secret), 4 ): for j in range(3 , -1 , -1 ): enc.append(secret[i+j]) key = [2 , 4 , 6 , 8 ] data = [ord(char ) for char in enc] flag = [] for i in range(len(data)): data[i] = data[i] ^ key[i % 4 ] flag.append(chr(data[i])) decoded_flag = base64.b64decode("" .join(flag)).decode() print(decoded_flag)