跳过正文
  1. Writeups/

DASCTF2024系列赛 Reverse

·1551 字·8 分钟·
CTF Reverse
目录

DASCTF 2024暑期挑战赛|为热爱,并肩作战
#

DosSnake
#

re签到,DOS程序只能反汇编,不能继续反编译成c伪代码。

汇编的代码量有点大,好在本题是游戏题,直接到最后面看flag的生成逻辑就行。简单的逐字节异或

DAS_snake

key = b"DASCTF"
data = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x09, 0x63, 0x34, 
  0x32, 0x13, 0x2A, 0x2F, 0x2A, 0x37, 0x3C, 0x23, 0x00, 0x2E, 
  0x20, 0x10, 0x3A, 0x27, 0x2F, 0x24, 0x3A, 0x30, 0x75, 0x67, 
  0x65, 0x3C]
for i in range(len(data)):
    data[i]^=key[i%6]
print(bytes(data))    
#b'DASCTF{H0wfUnnytheDosSnakeis!!!}'

BabyAndroid
#

说是baby,实际一点也不baby

题目情境比较新颖,给出了apk程序和一份截取的加密流量,需要逆向apk来找出加密算法

POST / HTTP/1.1

Content-Type: application/x-www-form-urlencoded

charset: utf-8

User-Agent: Dalvik/2.1.0 (Linux; U; Android 11; M2004J7AC Build/RP1A.200720.011)

Host: yuanshen.com

Connection: close

Accept-Encoding: gzip, deflate

Content-Length: 413

data=TwMkYUkg4bYsY0hL99ggYWnVjWyXQrWAdNmToB0eBXbS6wBzL6ktorjNWI9VOroTU4

HgIUYyzGLpcHzd1zNGT+bFZZI7IoxJwpcgXfdwW1LSmiNSP+PuSUsqAzNclF1nJ07b4tYyLWg0z

TypbzWsLhOIM+6uci3RFZLREUCALafi01M8mS+KMNxX1Pyn8mSP+KKKjQ5S5fasHRSn+L9qB

Fws0mWavpfI0QEiMgarxv0iGhYU8cfgonWyL70RvoXET5VUDP1vfYWIBLzzzaAqLC0OiMtUK3T

TATSU7yijdgXm18OKMcGIke/NZIM6Sr5fL3t6psDOOkw2C/5uYrJVPn+D6U9KTL64bgREppDq

MOvhvbhtuf/S3ASW/+rhtPMtoaD8FxDg0wWSLZA53fQfNA==

反编译之后,发现程序功能很多(代码很多)。先快速浏览了一下,在 model.sendRequest 找到了和流量POST请求相照应的函数 sendPost,内容也对应上一部分。说明程序最后调用这个函数发送流量。

交叉引用,定位到函数 doInBackground。基本上整个加密的流程都在这里了,其中还涉及到解密dex文件和导入外部函数。下图分别用红线和蓝线做了标注:

doInBackground

逐行分析。Sex.jpg 是一个被加密的文件,在 loadData 中进行RC4解密,恢复成dex文件。之后装载该dex文件中的类 site.qifen.note.ui.Encrypto,导入函数 encrypt。因为没配置动态调试的环境,所以在assert文件夹下手动提取出 Sex.jpg,进行解密。然后反编译该dex,找到 Encrypto 类。

在原来的 site.qifen.note.ui 下还有一个类 Encrypt0(专门来混淆的,差点踩坑),不用管它。

#include<stdio.h>
#include<string.h>
void RC4decrypt(unsigned char *data,int data_len,unsigned char *key,int key_len)
{
    unsigned char s_box[256],temp,t;
    int v0 = 0, v1 = 0, v2 = 0;
    for ( int i = 0; i < 256; ++i ) s_box[i] = i;
    for ( int k = 0; k < 256; ++k )
    {
        v0 = (key[k % key_len] + v0 + s_box[k]) % 256;
        temp = s_box[k];
        s_box[k] = s_box[v0];
        s_box[v0] = temp;
    }
    for ( int m = 0; m < data_len; ++m )
    {
        v1 = (v1 + 1) % 256;
        v2 = (v2 + s_box[v1]) % 256;
        t = s_box[v1];
        s_box[v1] = s_box[v2];
        s_box[v2] = t;
        data[m] ^= s_box[(s_box[v1] + s_box[v2]) % 256];
    }
}

int main()
{
    unsigned char buffer[0x800],key[]="DASCTF";
    FILE *srcfile = fopen("C:\\Users\\LENOVO\\Desktop\\Sex.jpg","rb+");
    FILE *dstfile = fopen("C:\\Users\\LENOVO\\Desktop\\desex.dex","wb+");
    memset(buffer,0,0x800); 
    fread(buffer,sizeof(char),0x7AB,srcfile);
    RC4decrypt(buffer,0x7AB,key,6);
    fwrite(buffer,sizeof(char),0x7AB,dstfile);
    return 0;
}

encrypt调用了一个魔改的Hash算法,把 "DSACTF" 的16位Hash值作为key,进行ECB加密。最后转成Base64,就得到了流量中的加密部分。写脚本反过来解密即可。

das_newdex

from Crypto.Cipher import AES
import base64

def customhash(input_byte):
    temp = [0 for i in range(16)]
    for byte in input_byte:
        for j in range(16):
            ix = temp[j]*31
            ix = (ix + byte) % 251
            temp[j] = ix
    key = [t % 256 for t in temp]
    return bytes(key)
unpad = lambda s: s[0:-ord(s[-1:])]

key = customhash(b"DSACTF")
b64data = "TwMkYUkg4bYsY0hL99ggYWnVjWyXQrWAdNmToB0eBXbS6wBzL6ktorjNWI9VOroTU4HgIUYyzGLpcHzd1zNGT+bFZZI7IoxJwpcgXfdwW1LSmiNSP+PuSUsqAzNclF1nJ07b4tYyLWg0zTypbzWsLhOIM+6uci3RFZLREUCALafi01M8mS+KMNxX1Pyn8mSP+KKKjQ5S5fasHRSn+L9qBFws0mWavpfI0QEiMgarxv0iGhYU8cfgonWyL70RvoXET5VUDP1vfYWIBLzzzaAqLC0OiMtUK3TTATSU7yijdgXm18OKMcGIke/NZIM6Sr5fL3t6psDOOkw2C/5uYrJVPn+D6U9KTL64bgREppDqMOvhvbhtuf/S3ASW/+rhtPMtoaD8FxDg0wWSLZA53fQfNA=="
data = base64.b64decode(b64data)

cryptor = AES.new(key,AES.MODE_ECB)
text=cryptor.decrypt(data)
print(unpad(text))
#b'458.853181,-18.325492,-18.251911,-2.097520,-21.198660,-22.304648,21.103162,-5.786284,-15.248906,15.329286,16.919499,-19.669045,30.928253,-37.588034,-16.593954,-5.505211,3.014744,6.553616,31.131491,16.472500,6.802400,-78.278577,15.280099,3.893073,56.493581,-34.576344,30.146729,4.445671,6.732204'

解密的结果是一系列浮点数,还不是flag。重新回到关键函数 doInBackground,发现剩了一个 sendInit,这个函数在程序中只有声明没有定义。那么它应该是从外部的so文件导入的。找到 libnote.so 进行反编译。

so文件中这个函数是 Java_site_qifen_note_ui_NoteActivity_sendInit

在函数中看到了 cos((j+0.5)*(i*3.14159265)/v10)*v7 这样一个数学公式,当时在这里卡住了。赛后看其他选手的wp了解到是离散余弦变换。贴上师傅的脚本:

from scipy.fftpack import dct, idct
A = [458.853181,-18.325492,-18.251911,-2.097520,-21.198660,-22.304648,
     21.103162,-5.786284,-15.248906,15.329286,16.919499,-19.669045,
     30.928253,-37.588034,-16.593954,-5.505211,3.014744,6.553616,
     31.131491,16.472500,6.802400,-78.278577,15.280099,3.893073,
     56.493581,-34.576344,30.146729,4.445671,6.732204]
#离散余弦变化逆变换 
C = idct(A, norm='ortho')
for i in range(len(C)):
    C[i] = round(C[i])
print(''.join([chr(int(i)) for i in C]))
#DASCTF{Y0u_Ar3Re4lly_H@ck3r!}

DASCTF 2024八月开学季|新生逐浪,热血向前
#

Maze
#

动调直接跑飞,应该有反调。用了ScyllaHide发现还是不行,先梳理一下流程

  1. 最先执行 TlsCallback,发现是一个SMC,修改了 sub_140001A60

  2. initterm 先于 main 进行初始化,依次调用 sub_140001000sub_140001020

    /*
    .rdata:0000000140004290 ; const _PVFV qword_140004290
    .rdata:0000000140004290 				dq 0                    
    .rdata:0000000140004298                 dq offset ?pre_cpp_initialization@@YAXXZ 
    .rdata:00000001400042A0                 dq offset sub_140001000
    .rdata:00000001400042A8                 dq offset sub_140001020
    .rdata:00000001400042B0 ; const _PVFV qword_1400042B0
    .rdata:00000001400042B0 				dq 0       
    */
    initterm((_PVFV *)&qword_140004290, (_PVFV *)&qword_1400042B0);
    
    • sub_140001000GetProcAddress(hModule, “ZwSetInformationThread”)

      动态调用 ZwSetInformationThread 反调试(如果程序正在被调试,则强制从调试器里分离出来)

    • sub_140001020:新开线程,新线程调用的函数正是前面经过SMC的 sub_140001A60

      检测 Dr0-Dr3 硬件断点,切换地图

      DAS48_smc_maze

  3. 最后来到主函数,读取字符,走迷宫

如果不打算用硬件断点调试的话,只绕过第一个反调即可。接下来就可以分析迷宫

全局变量dword_140006530在主线程和新线程中共享。主线程中其充当循环计数器,对应输入字符的索引。新线程中检测到其值改变,会根据奇偶在两个maze地图之间切换。另外发现,主线程中此循环变量自增后会Sleep挂起,为新线程切换地图留足时间,也就是说两个线程其实始终是同步运行的,这样一来就不用考虑竟态之类的问题。

迷宫部分也和传统的形式不同,switch-case 定义了六个方向,说明是三维迷宫,多出来的 "u","n" 分别代表上和下。按照字符对应的方向持续移动,直到遇到1停止。

地图是 8 x 8 x 8 的三维数组,起点索引是0(最底面的左上角),终点索引是436(6,6,4)

可以考虑手动求解,或者写一个bfs来跑

ezcpp
#

比较显眼的PEB反调,但并无影响,原因后面提到。

DAS48_cpp_debug

动调发现 v10 一开始是虚函数表 Derived::vftable 的指针,sub_7FF73FDD1B20 把其动态修改成第二个参数,实际上是VT hook。后面 (unsigned __int8 (__fastcall *)(_QWORD))**v7)() 调用的都是hook后的函数。

注意到hook了两次。第一次hook的函数显式抛出异常,跳过了try块后续的反调exit,只记录了调试情况。第二次则通过除零异常来到 except 块中的加密函数。

继续跟进,加密函数申请了一段内存并预先写入固定数据,又显式抛出异常。异常处理部分,异或解密上述内存数据实现SMC。接着调用新的函数,变种XTEA。

DAS48_smc_func

XTEA部分有一个不明来历的参数 a3 参与加密,动调发现是固定值1,不影响正常解密。看官方wp说代表是否被调试,应该是前面 _PEB->BeingDebugged 的返回值。调试状态和未调试状分别能解出两个8字节字符串,合并起来才是flag。(这里没有提示,感觉偏脑洞了

最后check,对硬编码的密文做了xor之后才和XTEA的结果比较。二者在内存中的形式是十进制字符串,类似 itoa,动调拿到数据即可解密。

#include<stdio.h>
#include<stdint.h>

void xtea_decry(uint64_t data, uint32_t a3, uint32_t *out)
{
    uint32_t key[4];
    key[0] = 0x42CA4455;
    key[1] = 0x8E0AE93B;
    key[2] = 0xA569C4D0;
    key[3] = 0x523A855B + a3;
    data = data ^ a3;

    uint32_t round = 32;
    uint32_t d1 = (data >> 32) & 0xFFFFFFFF;
    uint32_t d2 = data & 0xFFFFFFFF;
    uint32_t delta = 0xF3E56, number = delta * round;

    for (int i = 0; i < round; i++)
    {
        d2 -= ( ((d1<<4) ^ (d1>>5)) + d1) ^ (number + key[(number>>11) & 3]);
        number -= delta;
        d1 -= ( ((d2<<4) ^ (d2>>5)) + d2) ^ (number + key[number & 3]);
    }

    out[0] = ((d1 & 0xFF) << 24) | (((d1 >> 8) & 0xFF) << 16);
    out[0] |= (((d1 >> 16) & 0xFF) << 8) | ((d1 >> 24) & 0xFF);
    out[1] = ((d2 & 0xFF) << 24) | (((d2 >> 8) & 0xFF) << 16);
    out[1] |= (((d2 >> 16) & 0xFF) << 8) | ((d2 >> 24) & 0xFF);
}


int main()
{
    uint8_t flag[32] = {0};
    uint64_t data0 = 17529248803287439874ULL;
    uint64_t data1 = 12055721120662551337ULL;

    xtea_decry(data1, 1, (uint32_t *)flag);
    xtea_decry(data0, 0, (uint32_t *)flag + 2);

    printf("%s",flag);
}

DASCTF 2024最后一战|寒夜破晓,冬至终章
#

tryre
#

签到题,IDA静态看看就能分析得差不多

先换表Base64,之后逐字节异或 0x2。直接cyberchef梭

das12_tryre

黑客不许哭
#

程序无符号信息。但是经过分析,几个特殊函数以字符串常量保留了自身的函数名。由此推测功能

das12_cry_info1

das12_cry_info2

可以看出和cuda有关(英伟达的通用GPU库)

在文档中找到一些宏定义以及枚举变量,以方便分析。

//CUDA memory copy types
enum cudaMemcpyKind
{
	cudaMemcpyHostToHost = 0;		//Host -> Host
	cudaMemcpyHostToDevice = 1;		//Host -> Device
	cudaMemcpyDeviceToHost = 2;		//Device -> Host
	cudaMemcpyDeviceToDevice = 3;	//Device -> Device
	cudaMemcpyDefault = 4;			//inferred from the pointer values.
}

加密部分整个运算过程都在用double类型,因为浮点精度问题,通过逆运算解密的效果可能不好,这里考虑爆破。单字节爆破即可。

爆破过程中结合调试,发现每次得到结果都和check的密文刚好相差100。

#include<stdio.h>
#include<math.h>
int main()
{
    unsigned long long encdata[44] = {
    0x40B10696501E2585, 0x40B7EA4C5D638866, 0x40A0DD7DD1A21EA3, 0x40B755047D4E0978, 
    0x40C1EAEBA1FD156A, 0x40B814ADA31A4BDC, 0x40C802C39E8C47A1, 0x40AFF6A7A615A8DF, 
    0x40AA4164A3C64346, 0x40A2C755834091C1, 0x40A8FEE8FFDA4053, 0x40B3621E15011905, 
    0x40C025342C5E2CDC, 0x40A65E2036C9C0A9, 0x40905281565C2D28, 0x4090AE1F9D2BF552, 
    0x40A922F3E0157EED, 0x40B874F165C2D278, 0x40A99DE7B6FE2E6F, 0x4064172C9F2FDB90, 
    0x4082A661C68EC52A, 0x40A99BF2314013EC, 0x40B8E0C1F1F14984, 0x408A56DD68405B3A, 
    0x40B7252467CF1C32, 0x40A7CDDFD3B29A1C, 0x40C8E83135EB7458, 0x40A315184DFCE315, 
    0x409C8CA8B7E4DE3C, 0x40B327F640746456, 0x40B5F3DE9DF97AAB, 0x40AE167EEED8904F, 
    0x40B178FCD63CB817, 0x40C9A7D18476F2A6, 0x4099A285C5718EB9, 0x408E7B6FB86F47B6, 
    0x40A0FCC251E321A3, 0x40A1E3B0E1932D6F, 0x40A45B6A35B4EDB3, 0x40974258E8640208, 
    0x40C7DC0282E019B1, 0x40B1EC453A92A305, 0x40B2C35CF8B588E3, 0x40C975A6BC947065};

    unsigned long long newbuf4[44] = {
    0x404E425D046E0BBB, 0x40565E512BF5D8B8, 0x403807F2B4213872, 0x40552C14447517EC, 
    0x405A2AD9AF654289, 0x4054F066D7613C59, 0x40581A44A6E4B3A1, 0x4052D1537507F1FE, 
    0x404E2A6B8DC298FB, 0x40470D68C58C4673, 0x404C248F861F26DB, 0x4055AC1E8D98806B, 
    0x4054382EE9A71D0C, 0x404BA643C8564EC4, 0x40228603E483838D, 0x4034A091037CC6AF, 
    0x403F3092EE0B55F5, 0x405D0BF09991B04A, 0x403EDC239A70405A, 0x3FF10375A0B3084C, 
    0x40252ED23DE7CA70, 0x404BD327D12458CF, 0x405EBCD4229121F6, 0x401C90032C647FA6, 
    0x404BB99219281A65, 0x404F69DC68DC3E59, 0x405F53916405F1AA, 0x4046F8F189CB08B0, 
    0x404049328046AECF, 0x405717DDE2051F18, 0x405D6B8D70BC5387, 0x404FB611B00DAE6F, 
    0x4055057FF386071B, 0x405F536D3AFD1487, 0x403A812D835F129C, 0x402F378F374892AB, 
    0x4041D7F213D10431, 0x4042D635EB91F98C, 0x4038530805E42BBA, 0x4039B146B0E17FE6, 
    0x405D1DAF5CB6FEB2, 0x4055935E957A3B8B, 0x4053E1452099E93C, 0x005929B634E59ED1};
    
    unsigned long long num1 = 0x3FF0526CF94CA8DB;
    unsigned long long num2 = 0x3FF0000000000000;

    double key1 = *(double*) &num1;
    double key2 = *(double*) &num2;
    double *key = (double*) newbuf4;
    double *check_data = (double*) encdata;
    
    char flag[45] = {0};
    char table[] = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ{}-";
    for(int i = 0; i<45; i++)
    {
        double data = check_data[i] - 100;
        for(int j = 0; j<66; j++)
        {
            double chr = (double)table[j];
            double result = (chr * key1 + key2) * key[i];
            if(fabs(result - data) < 0.000001)
            {
                flag[i] = table[j];
                printf("%s\n",flag);
                break;
            }
        }
    }
    return 0;
}

das12_cry_res

刻板印象re
#

tlscallback 对加密函数 sub_40126C 进行inline hook,改成了 sub_41F000

hook的结果是在原加密完成后再调用一个新的函数来加密,新函数是在内存中动态写入的。

enchook

先来看原加密函数,有一段花指令干扰了反编译,nop掉之后分析。xor + XTEA + xor

接下来,对内存中的这段函数进行分析,可以尝试如下思路:

  • dump

动调时dump下来函数的机器码,重开一个IDA二次逆向

反汇编后能看出混淆非常严重,整个函数被拆成若干个基本块,通过 jmp ebx 实现间接跳转,静态分析不能确定控制流的走向(感觉类似FLA)。

在基本块内部也充斥着大量花指令,只有在 popapusha 之间的指令是有效的。

脚本去花,之后勉强可以看出XXTEA特征,但是依然不能确定执行顺序。还是动态分析效果好一些

  • IDA trace

先写脚本把内存中的机器码批量反汇编(非必须)

import idc
import idautils

start_ea = 0x63e4a1

current_ea = start_ea
end_ea = start_ea + 0x4359

spec_asm = 'jmp     ebx'
while current_ea <= end_ea: 
    length = idc.create_insn(current_ea)
    if idc.generate_disasm_line(current_ea,0) == spec_asm:
        current_ea += length + 1
    else:
        current_ea += length

关闭 “trace over debugger segments” 选项,之后F9运行自动trace。打开Tracing Window查看结果。我们关心的是debug段的指令顺序,所以对trace结果进行进一步处理。

enctraceIDA

trace_file = "trace.txt"
output_file = "output.txt"
trace = open(trace_file,"r+")
output = open(output_file,"w+")

def parse_line(line):
    if line:
        elements = line.split("\t")
        dis_asm = elements[2].strip()
        return dis_asm
    else:
        return line

skip = False

while True:
    dis = parse_line(trace.readline())
    if dis == "":
        trace.close()
        output.close()
        break
    elif dis == "pusha":
        skip = True
    elif dis == "popa":
        skip = False
    else:
        if not skip:
            output.write(dis + "\n")
  • x32dbg trace

思路差不多,参考官方wp,写表达式输出反汇编

之后看汇编指令分析加密,基本没什么难度了,可以借助deepseek分析:

encds

变种XXTEA,delta改成了 0x11451419,后面逐字节异或。从trace结果中分别提取一下这两个加密的key,脚本解密

mov     byte ptr [ebp-48h], 7Bh ; '{'
mov     byte ptr [ebp-47h], 57h ; 'W'
mov     byte ptr [ebp-46h], 68h ; 'h'
mov     byte ptr [ebp-45h], 61h ; 'a'
mov     byte ptr [ebp-44h], 74h ; 't'
mov     byte ptr [ebp-43h], 5Fh ; '_'
mov     byte ptr [ebp-42h], 69h ; 'i'
mov     byte ptr [ebp-41h], 73h ; 's'
mov     byte ptr [ebp-40h], 5Fh ; '_'
mov     byte ptr [ebp-3Fh], 74h ; 't'
mov     byte ptr [ebp-3Eh], 68h ; 'h'
mov     byte ptr [ebp-3Dh], 69h ; 'i'
mov     byte ptr [ebp-3Ch], 73h ; 's'
mov     byte ptr [ebp-3Bh], 5Fh ; '_'
mov     byte ptr [ebp-3Ah], 3Fh ; '?'
mov     byte ptr [ebp-39h], 7Dh ; '}'
#include<stdio.h>

void xtea_decry(unsigned int *data, unsigned int *key)
{
    unsigned int d1 = data[0], d2 = data[1];
    unsigned int delta = 0x9e3779b9, number = delta * 32;
    for (int i = 0; i < 32; i++)
    {
        d2 -= ( ((d1<<4) ^ (d1>>5)) + d1) ^ (number + key[(number>>11) & 3]);
        number -= delta;
        d1 -= ( ((d2<<4) ^ (d2>>5)) + d2) ^ (number + key[number & 3]);
    }
    data[0] = d1;
    data[1] = d2;
}

void xxtea_decry(unsigned int *data, unsigned int *key,unsigned int n)
{
    unsigned int rounds, e, y, z;
    unsigned int delta = 0x11451419, number;
    rounds = 6 + 52/n;
    number = delta * rounds;
    do
    {
        e = (number >> 2) & 3;
        for (int i = n-1; i>=0; i--)
        {
            y = data[(i+1)%n];
            z = data[(i+n-1)%n];
            
            data[i] -= ((y<<2 ^ z>>5) + (y>>3 ^ z<<4)) ^ ((number ^ y) + (z ^key[(e ^ i)&3]));
        }
        number -= delta;
    } while (--rounds);
}


int main()
{
    char xtea_key[] = "{you_find_it_!?}";
	char xxtea_key[] = "{What_is_this_?}";
    unsigned char xor_key[] = "Laughter_is_poison_to_fear";

	unsigned char xor_key1[] =
    {
		0xDA, 0x30, 0x23, 0xE3, 0xDC, 0x39, 0x82, 0x60, 
		0xA5, 0x44, 0x68, 0xC2, 0x43, 0x7A, 0xBB, 0xE4, 
		0x50, 0xE1, 0x02, 0xC2, 0x81, 0x59, 0xEA, 0x1E, 
		0xC6, 0x8B, 0x71, 0x38, 0x27, 0x83, 0x94, 0xD8, 
		0xF4, 0x8D, 0x1A, 0x2A, 0x56, 0x8A, 0x4A, 0xD4, 
		0x54, 0xDC, 0x24, 0x3F, 0xB9, 0xED, 0x7B, 0x9A
    };
	unsigned char xor_key2[] = 
	{
		0x8F, 0x6C, 0xA6, 0x3F, 0x94, 0x3D, 0xF5, 0xD9,
		0x36, 0x66, 0x51, 0xD7, 0x66, 0x2F, 0xB3, 0x8F,
		0xC0, 0x61, 0x9E, 0xCE, 0xE9, 0xD7, 0xE1, 0xBF,
		0x13, 0x14, 0x16, 0x14, 0xC2, 0xE7, 0xC3, 0x3A,
		0x7F, 0x94, 0xA1, 0xE7, 0x24, 0x0E, 0xA7, 0x5C,
		0xD3, 0x77, 0xFE, 0x4F, 0x11, 0xDC, 0x69, 0x23
	};
    unsigned char Bdata[] =
    {
		0x18, 0x09, 0x1C, 0x14, 0x37, 0x1D, 0x16, 0x2D, 0x3C, 0x05, 
		0x16, 0x3E, 0x02, 0x03, 0x10, 0x2C, 0x0E, 0x31, 0x39, 0x15, 
		0x04, 0x3A, 0x39, 0x03, 0x0D, 0x13, 0x2B, 0x3E, 0x06, 0x08, 
		0x37, 0x00, 0x17, 0x0B, 0x00, 0x1D, 0x1C, 0x00, 0x16, 0x06, 
		0x07, 0x17, 0x30, 0x03, 0x30, 0x06, 0x0A, 0x71, 0
    };

    unsigned int *Wdata = (unsigned int*)Bdata;
	unsigned int *Xkey = (unsigned int*)xtea_key;
    unsigned int *XXkey = (unsigned int*)xxtea_key;

    for(int i = 0; i < 48; i++)
        Bdata[i] ^= xor_key2[i];

    xxtea_decry(Wdata,XXkey,0xC);

    for(int i = 0; i < 48; i++)
        Bdata[i] ^= xor_key1[i];

    for(int j = 0; j < 12; j += 2)
        xtea_decry(Wdata+j, Xkey);

	for(int i = 0; i < 48; i++)
        Bdata[i] ^= xor_key[i%26];
    
    printf("%s",Bdata);
    return 0;
}

相关文章

HGAME2024 Revserse
·1327 字·7 分钟
CTF Reverse
reverse writeup of Hgame2024
第十七届CISCN初赛&华东北分区赛
·509 字·3 分钟
CTF AWDP Reverse Pwn
writeup and reproduction of 17th CISCN, reverse & pwn
LitCTF2024 Reverse
·163 字·1 分钟
CTF Reverse
reverse writeup of LitCTF(NSS) 2024