2024BulidCTF-逆向部分题解
风瞬息 发表于 江西 CTF 333浏览 · 2024-10-26 02:44

Babyre

简单看main函数的话,我感觉像是一个要在一定时间内解答的程序,但在运行过程中发现没什么关系,去看一眼xor_string(Buffer)里面的东西

不得不说这个代码阅读起来还是有一些艰难的,有很多无意义的定义,尝试写脚本,看的出来是把输入的长度为46的flag分成两个部分,前部分是加密异或,后一部分是由前往后推异或,直接写的时候,从比较简单的第一段flag看出来和大小端序有问题,因为得到的flag是ftcdilub,这对后面做第二部分很有启示其实最主要的是这几段数据的前后关系

Buf2 = 0x6C7E696E66637F48i64;
qmemcpy(v8, "qo92i2??>'8=i;'", 15);
v5 = 0x5800144E51515719i64;
v6[0] = 0x56575257511D4905i64;
*(v6 + 7) = 0x1E52555200520156i64;

查看地址,和后面不断尝试每一段数据进行异或的解可以找出来相对的位置解出part2,分析最关键的部分是

LOBYTE(v5) = *v11 ^ a1[Count - 1];

就是第一段flag的最后一个要用于第二段开头得脚本

inputs = [0x48, 0x7F, 0x63, 0x66, 0x6E, 0x69, 0x7E, 0x6C, 0x71, 0x6f,
          0x39, 0x32, 0x69, 0x32, 0x3f, 0x3f, 0x3e, 0x27, 0x38, 0x3d,
          0x69, 0x3b, 0x27,
          0x19, 0x57, 0x51, 0x51, 0x4E, 0x14, 0x00, 0x58,
          0x05, 0x49, 0x1D, 0x51, 0x57, 0x52, 0x57, 0x56,
          0x01, 0x52, 0x00, 0x52, 0x55, 0x52, 0x1E]

part1 = [0] * 23
for i in range(23):
    part1[i] = inputs[i]
part2 = [0] * 23
for i in range(23):
    part2[i] = inputs[i + 23]

for i in range(23):
    part1[i] = part1[i] ^ 0xA

part2[0] ^= ord('-')
for i in range(0, 22):
    part2[i + 1] ^= part2[i]

for i in part1:
    print(chr(i), end="")
print("\n")

for i in part2:
    print(chr(i), end="")

Buildctf{e38c8554-27c1-4c2c-99ad-0a6d3ed66d1c}

pyc

网上随便找一个pyc反编译网站就可以了

import base64

def encode(message):
    s = bytearray()
    for i in message:
        x = ord(i) ^ 32
        x = x + 16
        if x > 255:
            x -= 256
        s.append(x)
    return base64.b64encode(bytes(s)).decode('utf-8')

correct = 'cmVZXFRzhHZrYFNpjyFjj1VRVWmPVl9ij4kgZW0='
flag = input('Input flag: ')
if encode(flag) == correct:
    print('正确的回答,awa!!!')
else:
    print('就差一点了,QWQ!!')

能看出来就是先把这段密文base64再hex 然后先-16再异或32,如果>255就-256

temp = [0x72,0x65,0x59,0x5c,0x54,0x73,0x84,0x76,0x6b,0x60,0x53,0x69,0x8f,0x21,0x63,0x8f,0x55,0x51,0x55,0x69,0x8f,0x56,0x5f,0x62,0x8f,0x89,0x20,0x65,0x6d]

for i in temp:
    i = i - 16
    i ^= 32
    if i > 255:
        i - 256

    print(chr(i),end="")

BuildCTF{pcy_1s_eaey_for_Y0u}

晴窗细乳戏分茶

一眼tea加密

密文,key都全给你了,很新手的一道题,然后第一步是标准tea加密,第二部分是xtea
参考网站:TEA、XTEA、XXTEA加密解密算法 - Kevin的编程之路 - SegmentFault 思否
xtea部分

void decipher(unsigned int num_rounds, uint32_t v[2], uint32_t const key[4]) {  
    unsigned int i;  
    uint32_t v0=v[0], v1=v[1], delta=0x9E3779B9, sum=delta*num_rounds;  
    for (i=0; i < num_rounds; i++) {  
        v1 -= (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + key[(sum>>11) & 3]);  
        sum -= delta;  
        v0 -= (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + key[sum & 3]);  
    }  
    v[0]=v0; v[1]=v1;  
}  

int main()  
{  
    uint32_t v1[2]={-2022820316,-1470027656}; 
    uint32_t v2[2]={1057529116,1243942236};  
    uint32_t const k[4]={358040470,1131796,85988116,120935944};  
    unsigned int r=32;//num_rounds建议取值为32  
    // v为要加密的数据是两个32位无符号整数  
    // k为加密解密密钥,为4个32位无符号整数,即密钥长度为128位  
    printf("解密前原始数据:%u %u\n",v1[0],v1[1]); 
    printf("解密前原始数据:%u %u\n",v2[0],v2[1]);
    decipher(r, v1, k);  
    decipher(r, v2, k);
    printf("解密后的数据:%u %u\n",v1[0],v1[1]);  
    printf("解密后的数据:%u %u\n",v2[0],v2[1]); 
    return 0;  
}

v是两次两次进去的,要不新增几个变量v1,v2然后进行解密函数,要不就一次一次重新填写数据

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]={1,2},k[4]={2,2,3,4};  
    // v为要加密的数据是两个32位无符号整数  
    // k为加密解密密钥,为4个32位无符号整数,即密钥长度为128位  
    printf("解密前原始数据:%u %u\n",v[0],v[1]);  
    encrypt(v, k);  
    printf("解密后的数据:%u %u\n",v[0],v[1]);  
    return 0;  
}

这个是tea(由于是回头来写的wp) 同上,记得把key换了,然后多定义几个v1,v2传进去.但是脚本跑出来的有点问题,我结合了一下我之前的一个脚本

#define _CRT_SECURE_NO_WARNINGS
#pragma warning(disable:4996)
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#define DELTA 0x9e3779b9

void coke(uint32_t* v, uint32_t* k) {
    uint32_t v0 = v[0], v1 = v[1], sum = 0;
    for (int i = 0; i < 32; i++) {
        v0 += ((v1 << 4) + k[0]) ^ (v1 + sum) ^ ((v1 >> 5) + k[1]);
        sum += DELTA;
        v1 += ((v0 << 4) + k[2]) ^ (v0 + sum) ^ ((v0 >> 5) + k[3]);
    }
    v[0] = v0; v[1] = v1;
    printf("v0: %u\n", v0);
    printf("v1: %u\n", v1);

}
void get_hp(uint32_t* v, uint32_t* k) {
    uint32_t v0 = v[0], v1 = v[1], sum = DELTA * 32;
    for (int i = 0; i < 32; i++) {
        v1 -= ((v0 << 4) + k[2]) ^ (v0 + sum) ^ ((v0 >> 5) + k[3]);
        v0 -= ((v1 << 4) + k[0]) ^ (v1 + sum) ^ ((v1 >> 5) + k[1]);
        sum -= DELTA;
    }
    v[0] = v0; v[1] = v1;
}

int main() {
    uint32_t key[4] = { 1646625, 164438, 164439, 2631985 };
    uint32_t v1[2] = { -1559465970, -158607645 };
    uint32_t v2[2] = { -1059812880, 314506021 };
    uint32_t v3[2] = { -2131835469, 731233488 };



    get_hp(v1, key);
    get_hp(v2, key);
    get_hp(v3, key);
    char kfc1[9] = { 0 };
    char kfc2[9] = { 0 };
    char kfc3[9] = { 0 };
    memcpy(kfc1, v1, 8);
    memcpy(kfc2, v2, 8);
    memcpy(kfc3, v3, 8);
    printf("这是flag:\n");
    printf("%s%s%s", kfc1, kfc2, kfc3);


    return 0;

}

BuildCTF{D0_y0u_WanTT0 第二部分同上

自是花中第一流

一眼花指令

可以看到一大部分都没有被转成代码选中按c得到代码

把几个花指令的call和跳转nop,还有上面的一些数据
虽然会影响代码信息,但是都不太重要

能看出来
一个key函数,一个len获得长度,就要开始加密了

里面还有一个函数,可以搜一下,是RC4加密这里用到的有一个叫做key的关键变量,但是点击key进去却没有看到什么数据如果刚刚在main里面看了secret 能看到这上面有一个叫做is_key的

再去看一下init_key,修一下花指令,和上面的一样

这就很明了了,key就是^ 0x31之后的结果
写一个RC4脚本

from Crypto.Cipher import ARC4

# 已知的 Is_key 和 secret
Is_key = bytes([0x77, 0x00, 0x01, 0x5E, 0x46, 0x54, 0x43])
secret = bytes([
    0x7E, 0x58, 0x36, 0xF5, 0xC5, 0xF3, 0x39, 0xD4, 0x65, 0xCF,
    0x67, 0x85, 0x37, 0x8C, 0x0C, 0xD4, 0x46, 0x88, 0x95, 0x2F,
    0xDB, 0xB6, 0xA7, 0x56, 0xDC, 0xFE, 0xA9, 0x99, 0x92, 0x60,
    0xA6, 0xC9, 0xE7, 0xCF, 0xBD, 0xB5, 0x62
])

# 1. 通过 Is_key 和 0x31 进行异或操作,生成 key
key = bytes([b ^ 0x31 for b in Is_key])

# 2. 使用生成的 key 进行 RC4 解密
rc4 = ARC4.new(key)
flag = rc4.decrypt(secret)

# 输出解密后的 flag
try:
    print("Decrypted flag:", flag.decode('utf-8'))  # 假设 flag 是 UTF-8 编码的字符串
except UnicodeDecodeError:
    print("Decrypted flag (raw bytes):", flag)  # 如果解码失败,则输出原始字节

Decrypted flag: BuildCTF{What_A_Beautifu1_F10ower!!!}

ez_xor?

这道题确确实实学到知识了,
先IDA看代码,然后按照C语言风格的代码写了python的代码

v9 = [0] * 32
v9[0] = 25
v9[1] = 104
v9[2] = -94
v9[3] = -17
v9[4] = 123
v9[5] = -70
v9[6] = 14
v9[7] = -59
v9[8] = 93
v9[9] = 0x80
v9[10] = -17
v9[11] = 9
v9[12] = 11
v9[13] = -47
v9[14] = -127
v9[15] = -15
v9[16] = -16
v9[17] = 51
v9[18] = -90
v9[19] = 17
v9[20] = 35
v9[21] = 88
v9[22] = 92
v9[23] = 43
v9[24] = 56
v9[25] = -115
v9[26] = 0x80
v9[27] = 0x60
v9[28] = 0x61
v9[29] = 0x27
v9[30] = 0x48
v9[31] = 0x35

key = "BuildCTF2024!^_^"

for i in range(16):
    key += chr(ord(fakekey[i]) ^ tls[i])

temp = [0] * 256

for i in range(0, 256):
    temp[i] = i

result = 0
v6 = len(key)

v7 = [''] * 256
for j in range(256):
    v7[j] = key[j % v6]
    result = j + 1

v5 = 0
switch = 0

for k in range(256):
    v5 = (ord(v7[k]) + temp[k] % 63 + v5) % 256
    switch = temp[k]
    temp[k] = temp[v5]
    temp[v5] = switch
    result = k + 1

v3 = 0
v4 = 0
for i in range(32):
    v3 = (v3 + 7) % 256
    v4 = (v4 + temp[v3]) % 256
    switch = temp[v3]
    temp[v3] = temp[v4]
    temp[v4] = switch
    v9[i] += temp[(temp[v3] + temp[v4]) % 256]

flag = [''] * 32
for i in range(len(v9)):
    flag[i] = chr(v9[i] % 256)

for i in range(32):
    print(flag[i], end="")

结果发现怎么跑都跑不出来
这里学到几个知识点,主要就是对于int8变量的取模,在这个代码中溢出都成为一种正常现象了

for ( i = 0; ; ++i )
  {
    if ( i >= v6 )
      break;
    v3 += 7;
    v4 += byte_1400077B0[v3];
    sub_140001A50(&byte_1400077B0[v3], &byte_1400077B0[v4]);
    a1[i] -= byte_1400077B0[(byte_1400077B0[v4] + byte_1400077B0[v3])];
  }
  return result;

起初看这个代码,发现v6 = strlen(Str),那就是32。
这部分代码让v3,v4在循环中会变大很多,最终超出byte_1400077B0本来的范围256,后面经师傅指点得知
unsigned int8 v3;
unsigned
int8 v4;
int8即2进制8位,11111111 = 2^8 - 1 = 256 - 1 = 255
所以要取模256 后面就卡住了,主要是对tls太陌生
[原创]TLS回调函数(Note)-软件逆向-看雪-安全社区|安全招聘|kanxue.com

key被修改过,脚本改一下就好了

v9 = [0] * 32
v9[0] = 25
v9[1] = 104
v9[2] = -94
v9[3] = -17
v9[4] = 123
v9[5] = -70
v9[6] = 14
v9[7] = -59
v9[8] = 93
v9[9] = 0x80
v9[10] = -17
v9[11] = 9
v9[12] = 11
v9[13] = -47
v9[14] = -127
v9[15] = -15
v9[16] = -16
v9[17] = 51
v9[18] = -90
v9[19] = 17
v9[20] = 35
v9[21] = 88
v9[22] = 92
v9[23] = 43
v9[24] = 56
v9[25] = -115
v9[26] = 0x80
v9[27] = 0x60
v9[28] = 0x61
v9[29] = 0x27
v9[30] = 0x48
v9[31] = 0x35

fakekey = "BuildCTF2024!^_^"
key = ""
tls = [0x75, 0x1D, 0x58, 0x1F, 0x3B, 0x72, 0x61, 0x19, 0x72, 0x6F,
       0x59, 0x51, 0x58, 0x1E, 0x1E, 0x1E]
for i in range(16):
    key += chr(ord(fakekey[i]) ^ tls[i])

temp = [0] * 256

for i in range(0, 256):
    temp[i] = i

result = 0
v6 = len(key)

v7 = [''] * 256
for j in range(256):
    v7[j] = key[j % v6]
    result = j + 1

v5 = 0
switch = 0

for k in range(256):
    v5 = (ord(v7[k]) + temp[k] % 63 + v5) % 256
    switch = temp[k]
    temp[k] = temp[v5]
    temp[v5] = switch
    result = k + 1

v3 = 0
v4 = 0
for i in range(32):
    v3 = (v3 + 7) % 256
    v4 = (v4 + temp[v3]) % 256
    switch = temp[v3]
    temp[v3] = temp[v4]
    temp[v4] = switch
    v9[i] += temp[(temp[v3] + temp[v4]) % 256]

flag = [''] * 32
for i in range(len(v9)):
    flag[i] = chr(v9[i] % 256)

for i in range(32):
    print(flag[i], end="")

5trE4m_EncrYpt_15_eAsy_t0_cRaCk!

0 条评论
某人
表情
可输入 255