一如既往的前言
DAS的比赛我只能说,力不从心了。令我惊讶的是一道定位为简单题的”喝茶“题我也没做出来,这就是所谓的”春回大地“难度…
显而易见,真正意义上我只做出了一题…本来不打算写这个博客的,因为C#的题直接粘贴运行就好了= =后来用Python尝试复现一下,写下来算是学习一下Python下的无符号参数的处理吧
Enjoyit-1
C#程序,直接放ILSpy就能出源码
敏感的发现那段Base64字符串,去看c方法,CTF经典的换码表
替换码表后解密就能得到text
方法一(最快)
从主处理逻辑里扣代码出来,运行完事
static void bbbb(ref uint[] A_0, byte[] A_1) { uint num = 2654435464u; uint num2 = A_0[0]; uint num3 = A_0[1]; uint num4 = 0u; for (int i = 0; i < 32; i++) { num2 += (((num3 << 4) ^ (num3 >> 5)) + num3) ^ (num4 + A_1[num4 & 3]); num4 += num; num3 += (((num2 << 4) ^ (num2 >> 5)) + num2) ^ (num4 + A_1[(num4 >> 11) & 3]); Console.Write(num2); Console.Write(" "); Console.Write(num4); Console.Write(" "); Console.WriteLine(num3); } A_0[0] = num2; A_0[1] = num3; } static void Main(string[] args) { string str = ""; string text = ""; byte[] array = new byte[26]; _ = new byte[26]; byte[] array2 = new byte[8]; byte[] array3 = new byte[32] {2, 5, 4, 13, 3, 84, 11, 4, 87, 3, 86, 3, 80, 7, 83, 3, 0, 4, 83, 94, 7, 84, 4, 0, 1, 83, 3, 84, 6, 83, 5, 80 }; uint[] A_ = new uint[2] { 288u, 369u }; text = "combustible_oolong_tea_plz"; array = Encoding.Default.GetBytes(text); bbbb(ref A_, array); Console.WriteLine("Here is your tea, and flag!"); str += A_[0].ToString("x2"); str += A_[1].ToString("x2"); array2 = Encoding.Default.GetBytes(str); Console.Write("flag{"); for (int j = 0; j < 32; j++){ array3[j] ^= array2[j % array2.Length]; } Console.Write(Encoding.Default.GetString(array3)); Console.Write("}"); Console.ReadKey(); }
方法二(Python)
个人认为打比赛的时候用Python去复现这种C#能直接跑出来的题,有点浪费时间
因为Python特性,无符号类型的参数在Python中无法通过定义的方式声明
但好在Python拥有ctypes
模块强制指定为无符号参数
import ctypes def b(A_0, A_1): num = ctypes.c_uint32(2654435464) num2 = A_0[0] num3 = A_0[1] num4 = ctypes.c_uint32(0) for i in range(32): num2.value += (((num3.value << 4) ^ (num3.value >> 5)) + num3.value) ^ (num4.value + A_1[num4.value & 3].value) num4.value += num.value num3.value += (((num2.value << 4) ^ (num2.value >> 5)) + num2.value) ^ ( num4.value + A_1[(num4.value >> 11) & 3].value) A_0[0] = num2 A_0[1] = num3 strs = "" array = [] for i in "combustible_oolong_tea_plz": array.append(ctypes.c_ubyte(ord(i))) A_ = [ctypes.c_uint32(288), ctypes.c_uint32(369)] b(A_, array) strs += hex(A_[0].value)[2:].zfill(2) strs += hex(A_[1].value)[2:].zfill(2) array2 = strs array3 = [2, 5, 4, 13, 3, 84, 11, 4, 87, 3, 86, 3, 80, 7, 83, 3, 0, 4, 83, 94, 7, 84, 4, 0, 1, 83, 3, 84, 6, 83, 5, 80] for j in range(32): array3[j] = chr(array3[j] ^ ord(array2[j % len(array2)])) print("".join(array3))
drinkSomeTea
喝茶吗?(苦涩)
昨天赛后,Buu群的一位师傅发了一份此题的WP,拜读了一下,师傅是直接汇编patch掉了,奈何我刚学的汇编没这么强的功底。周日正好有空,就打算用Python还原下这个特殊的TEA算法
然而想法是简单的,过程是曲折的,Python缺少了算术位移(也可能是我Python了解并不透彻),只好自己写了一个函数模拟算术移位
先上一下那位师傅的WP叭
Python的复现之路
正如师傅们所说的,对于此题,直接使用C去还原算法是较快的解决方法,但是,我还是选择使用Python复现一下这个算法,也算是我对于汇编知识以及Python特性的一个练习叭
如有不足之处,欢迎师傅们指正~
核心的处理过程当然是TEA算法,不过此题的TEA算法使用了算术移位,并且是带符号
这对于Python来说并不是一件顺其自然的事情……..不说了,上exp了(废话太多)
import struct def sar(DWORD=0, num=0): """ python没有算数右移,笨办法模拟了一下算数右移 :param DWORD: 四字节 整数 :param num:右移量 :return:移位后整数 """ binWORD = bin(DWORD) # 四字节转二进制 signbit = binWORD[2:3] # 取符号位 DWORD = DWORD >> num # 逻辑右移 if signbit == 0 or len(binWORD[2:]) != 32: # 高位为 0 或 不足32位 return DWORD # 直接返回右移结果 else: bit = ["1"] * num # 高位 补num位 1 DWORD = "0b" + "".join(bit) + bin(DWORD).replace('0b', '').zfill(8) # 组合成二进制形式 return int(DWORD, 2) # 转整数 def teaEnc(DwordArray, keys): delta = 0 v1 = DwordArray[1] v0 = DwordArray[0] for i in range(32): delta += 0x9E3779B9 v0 += (keys[1] + sar(v1, 5) & 0xffffffff) ^ ((delta + v1) & 0xffffffff) ^ (keys[0] + (16 * v1) & 0xffffffff) v0 = v0 & 0xffffffff v1 += (keys[3] + sar(v0, 5) & 0xffffffff) ^ ((delta + v0) & 0xffffffff) ^ (keys[2] + (16 * v0) & 0xffffffff) v1 = v1 & 0xffffffff DwordArray[1] = v1 DwordArray[0] = v0 result = DwordArray return result def teaDec(DwordArray, keys): delta = 0x9E3779B9 << 5 v1 = DwordArray[1] v0 = DwordArray[0] for i in range(32): v1 -= (keys[3] + sar(v0, 5) & 0xffffffff) ^ ((delta + v0) & 0xffffffff) ^ ( keys[2] + (16 * v0) & 0xffffffff) v1 = v1 & 0xffffffff v0 -= (keys[1] + sar(v1, 5) & 0xffffffff) ^ ((delta + v1) & 0xffffffff) ^ ( keys[0] + (16 * v1) & 0xffffffff) v0 = v0 & 0xffffffff delta -= 0x9E3779B9 DwordArray[1] = v1 DwordArray[0] = v0 result = DwordArray return result key = [0x67616C66, 0x6B61667B, 0x6C665F65, 0x7D216761] with open("tea.png.out", "rb") as f: file = f.read() png = b"" for i in range(len(file) // 8): arr = list(struct.unpack("<LL", file[i*8:i*8 + 8])) # 小端,转为 DWORD dec = teaDec(DwordArray=arr, keys=key) png += struct.pack("<LL", dec[0], dec[1]) # 小端,转为字节 with open("tea.png", "wb") as f: f.write(png)
拿到的是一张图片,真就爽歪歪
感想
我还是老老实实用C还原吧(逃)
发表回复