CTFSHOW - 2026元旦跨年欢乐赛 - Misc - WriteUp
碎碎念
本来是打算元旦不打ctf的,奈何小登找我帮忙做一下,遂出手了,结果越做越开心说是(),然后就干起来了
不得不说这次题目还挺好(指的是做起来很简单,基本都能梭),也就happyemoji难一点,其他的就有点懒得写了)
HappyEmoji
知识点省流
四进制 图像识别
WP
题目给了一个gif图,里面是超多微笑表情的旋转gif,我先将他们分帧切分后,发现里面一共存在四种转速,分别为不转,3帧一圈、7帧一圈、14帧一圈,根据描述一串为一个字符,并且我发现每四行为一组,第一行都是不转或者14帧一圈的组合,断定这是一个四进制数,然后开头为0或者1

接下来就是如何去识别这些四进制数,我用的方法是像素识别,因为本质上每个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
