re出题人怎么这么喜欢矩阵,FPGA和deeptx都属于恢复出来逻辑不好逆的
ezFPGA:
查了查FPGA的相关知识,先用Digital-IDE查看vcd信号:
提取密文:AD00C09F1617EC25251F12E27F9F375312BA8D3860141B318E13E2560A1A25B980738A60
从encryptor恢复加密逻辑:
1 | module Encryptor#( |
python实现:
1 | m = bytearray(b"ACTF{?????????????????????????????????}") |
编写脚本解密:
RC4阶段:
1 | enc = bytearray.fromhex("AD00C09F1617EC25251F12E27F9F375312BA8D3860141B318E13E2560A1A25B980738A60") |
得到c2:6b01bf6dbc164991f3eb4c714ef0c0c546f87d51523d8b8e4ed8a2b233e3f4875287c322
矩阵阶段:
1 | from z3 import * |
得到c1:[79, 73, 151, 50, 184, 200, 100, 192, 131, 26, 249, 134, 159, 51, 3, 110, 114, 221, 227, 53, 217, 14, 87, 183, 172, 111, 194, 28, 122, 221, 22, 117, 218, 95, 0, 0]
加权求和阶段:
1 | from z3 import * |
得到flag:[65, 67, 84, 70, 123, 82, 67, 52, 95, 52, 110, 100, 95, 70, 80, 71, 65, 95, 119, 52, 108, 107, 95, 49, 110, 116, 48, 95, 52, 95, 98, 52, 114, 125, 0, 0, 0, 0, 0]
flag:ACTF{RC4_4nd_FPGA_w4lk_1nt0_4_b4r}.
deeptx:
cuda逆向,查看main:
1 | int __fastcall main(int argc, const char **argv, const char **envp) |
读取了一个flag.bmp,bmp是纯黑白的,没有rgb颜色,一个像素对应一个0~FF的值,被加密的是bmp中的256*256=65536个像素,用layer1、2、3加密了这65536个字节,cuobjdump得到ptx:
1 | Fatbin elf code: |
motion是一个浮点数组构成的模糊核:
1 | 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.01248378586024046, 0.04262230917811394, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.01248378586024046, 0.04262230917811394, 0.01248378586024046, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.01248378586024046, 0.04262230917811394, 0.01248378586024046, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.01248378586024046, 0.04262230917811394, 0.01248378586024046, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.01248378586024046, 0.04262230917811394, 0.01248378586024046, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.01248378586024046, 0.04262230917811394, 0.01248378586024046, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,0.0, 0.0, 0.0, 0.0, 0.01248378586024046, 0.04262230917811394, 0.01248378586024046, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.01248378586024046, 0.04262230917811394, 0.01248378586024046, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.01248378586024046, 0.04262230917811394, 0.01248378586024046, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.01248378586024046, 0.04262230917811394, 0.01248378586024046, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.01248378586024046, 0.04262230917811394, 0.01248378586024046, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.01248378586024046, 0.04262230917811394, 0.01248378586024046, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.01248378586024046, 0.04262230917811394, 0.01248378586024046, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.01248378586024046, 0.04262230917811394, 0.01248378586024046, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0055596730671823025, 0.04262230917811394, 0.01248378586024046, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0055596730671823025, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 |
sbox:
1 | D690E9FECCE13DB716B614C228FB2C052B679A762ABE04C3AA441326498606999C4250F491EF987A33540B43EDCFAC62E4B31CA9C908E89580DF94FA758F3FA64707A7FCF37317BA83593C19E6854FA8686B81B27164DA8BF8EB0F4B70569D351E240E5E6358D1A225227C3B01217887D40046579FD327524C3602E7A0C4C89EEABF8AD240C738B5A3F7F2CEF96115A1E0AE5DA49B341A55AD933230F58CB1E31DF6E22E8266CA60C02923AB0D534E6FD5DB3745DEFD8E2F03FF6A726D6C5B518D1BAF92BBDDBC7F11D95C411F105AD80AC13188A5CD7BBD2D74D012B8E5B4B08969974A0C96777E65B9F109C56EC68418F07DEC3ADC4D2079EE5F3ED7CB3948 |
tbox:
1 | 627C767AF26A6EC43000662AFED6AA76CA82C87CFA5846F0ACD4A2AE9CA472C0B6FC9226363EF6CC34A4E4F070D8301404C622C21896049A061280E2EA26B27408822C1A1A6E5AA0523AD6B228E22E8452D000EC20FCB05A6ACABE384A4C58CED0EEAAFA424C328444F8027E503C9EA850A2408E929C38F4BCB6DA2010FEF2D2CC0C12EC5E964416C4A67E3C645C187260804EDC222A908846EFB814DE5E0ADAE0323A0A4806245CC2D2AC629094E478E6C8366C8CD44EA86C56F4EA647AAE08BA78242E1CA6B4C6E8DC741E4ABC8A8A703EB4664802F60E603456B886C01C9EE0F8981068D88E949A1E86E8CE5428DE8CA0880CBEE6426840982C0EB054BA16 |
Layer1
逻辑恢复(by huanghunr):
1 | __global__ void Layer1(uint8_t* input, uint8_t* output) { |
Layer1中把输入的数据按照256*256的矩阵以motion为卷积核的卷积,但是motion的列要倒序一下,即input[0][0] … input[0][15] * motion[15][0]…motion[15][15].
Layer2
是一个简单的sbox置换:
1 | ld.param.u64 %rd1, [_Z6Layer2PhS__param_0]; |
python实现:
1 | for block in range(256): |
Layer3
起始部分有一个异或:
1 | cvt.u16.u32 %rs8, %r3; // 将线程索引转换为16位 |
其python实现:
1 | for block in range(256): |
中间按线程索引&7=0(为8的倍数)进行TEA加密的部分:
1 | bar.sync 0; |
其python模拟如下:
1 | delta = 0x6a82c908 |
之后在$L_BB2_4有一个异或:
1 | bar.sync 0; |
对应:
1 | for block in range(256): |
在$L_BB2_4的下半部分、$L_BB2_5和$L_BB2_7有Sbox、Tbox置换:
1 | bar.sync 0; |
对应:
1 | for block in range(256): |
Layer3总体逻辑:
1 | def bytes_to_dwords_little_endian(byte_array): |
Layer3求解:
经过测试发现ttl生成过程中的sbox修改对于thread0~255,在256轮后的结果都一样,并且等于原始sbox(SM4的sbox):
1 | sbox_ori = [0xD6, 0x90, 0xE9, 0xFE, 0xCC, 0xE1, 0x3D, 0xB7, 0x16, 0xB6, 0x14, 0xC2, 0x28, 0xFB, 0x2C, 0x05, |
cycle过程中的&224无效,因为取的是高3位,逆向最后的cycle循环得到解密函数:
1 | from numba import njit |
恢复出ttl,接下来的部分要解矩阵,注意到在一个block内,ttl是256字节的data和系数的乘积的加和,data可以看做一个256维向量,256线程的256轮的系数可以看做一个256阶的系数矩阵,矩阵乘以向量得到输出ttl,使用z3求解data:
1 | import numpy as np |
接下来对layer3剩余的两个异或和TEA加密进行逆向:
1 | from numba import njit |
得到layer2加密后的结果,还原layer2并验证:
1 | import numpy as np |
得到仅layer1加密的flag,查看图像:
发现只剩下因卷积产生的动态模糊效果了,说明layer2~3的逆向还原完全正确,layer1是一个动态模糊,由于模糊核大部分都是0,考虑用AI恢复字符,尝试多次得到一个比较清晰的图片:
编写脚本爆破flag:
1 | import hashlib |
爆破得到flag:ACTF{DeEptCUdAR1VQUZ}.
闲话
deeptx真难逆😭