CTFSHOW - 2026元旦跨年欢乐赛 - Misc - WriteUp


碎碎念

本来是打算元旦不打ctf的,奈何小登找我帮忙做一下,遂出手了,结果越做越开心说是(),然后就干起来了
不得不说这次题目还挺好(指的是做起来很简单,基本都能梭),也就happyemoji难一点,其他的就有点懒得写了)

HappyEmoji

知识点省流

四进制 图像识别

WP

题目给了一个gif图,里面是超多微笑表情的旋转gif,我先将他们分帧切分后,发现里面一共存在四种转速,分别为不转,3帧一圈、7帧一圈、14帧一圈,根据描述一串为一个字符,并且我发现每四行为一组,第一行都是不转或者14帧一圈的组合,断定这是一个四进制数,然后开头为0或者1

image-20260107165222588

接下来就是如何去识别这些四进制数,我用的方法是像素识别,因为本质上每个emoji都是一样的,只是cp了而已,所以当转速不同时,不同帧的相同位置像素就可能出现不同,通过这个思想,我对图片进行切割,将每个emoji单独切出来,然后查找能够做区分的某一帧某个位置像素,借此去识别数值,最终的脚本如下:

from PIL import Image, ImageSequence
import math

# ================= 配置区 =================
GIF_PATH = 'flag.gif'
FRAME_INDEXES = [3, 34, 65, 96]   # 从 1 开始计数

BLOCK_H = 42
BLOCK_W = 61
GAP_H = 10

TARGET_Y = 15
TARGET_X = 34

SHIFT_X = 5   # 向右平移 5 像素
# =========================================

COLOR_MAP = {
    (191, 175, 143): 0,
    (255, 223, 127): 2,
    (255, 239, 111): 1
}

STRIDE_H = BLOCK_H * 4 + GAP_H


def shift_image_right(img, shift):
    """整张图向右平移 shift 像素"""
    w, h = img.size
    new_img = Image.new('RGB', (w, h), (0, 0, 0))
    new_img.paste(img, (shift, 0))
    return new_img


def decode_image(img):
    width, height = img.size
    pixels = img.load()

    cols = math.ceil(width / BLOCK_W)
    groups = math.ceil(height / STRIDE_H)

    decoded_chars = []

    for group in range(groups):          # 从上到下
        for col in range(cols):          # 从左到右
            digits = []

            for i in range(4):
                base_x = col * BLOCK_W
                base_y = group * STRIDE_H + i * BLOCK_H

                x = base_x + TARGET_X
                y = base_y + TARGET_Y

                if x >= width or y >= height:
                    value = 3
                else:
                    pixel = pixels[x, y]
                    value = COLOR_MAP.get(pixel, 3)

                digits.append(str(value))

            base4 = ''.join(digits)

            if any(c not in '0123' for c in base4):
                decoded_chars.append('?')
            else:
                decoded_chars.append(chr(int(base4, 4)))

    return ''.join(decoded_chars)


# ================= 主流程 =================
gif = Image.open(GIF_PATH)

final_result = []

print('==== GIF 帧解码 ====')

for idx in FRAME_INDEXES:
    frame_no = idx - 1  # 转为 0-based

    gif.seek(frame_no)
    frame = gif.convert('RGB')

    # 右移 5 像素
    shifted = shift_image_right(frame, SHIFT_X)

    decoded = decode_image(shifted)

    print(f'\n帧 {idx} 解码结果:')
    print(decoded)

    final_result.append(decoded)

print('\n==== 最终拼接结果 ====')
print(''.join(final_result))

最终能识别出一串base64字符串,解base得到flag

image-20260107165726109

qwq