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

HappyEmoji

知识点省流

四进制 图像识别

WP

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

image-20260107165222588

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

 1from PIL import Image, ImageSequence
 2import math
 3
 4# ================= 配置区 =================
 5GIF_PATH = 'flag.gif'
 6FRAME_INDEXES = [3, 34, 65, 96]   # 从 1 开始计数
 7
 8BLOCK_H = 42
 9BLOCK_W = 61
10GAP_H = 10
11
12TARGET_Y = 15
13TARGET_X = 34
14
15SHIFT_X = 5   # 向右平移 5 像素
16# =========================================
17
18COLOR_MAP = {
19    (191, 175, 143): 0,
20    (255, 223, 127): 2,
21    (255, 239, 111): 1
22}
23
24STRIDE_H = BLOCK_H * 4 + GAP_H
25
26
27def shift_image_right(img, shift):
28    """整张图向右平移 shift 像素"""
29    w, h = img.size
30    new_img = Image.new('RGB', (w, h), (0, 0, 0))
31    new_img.paste(img, (shift, 0))
32    return new_img
33
34
35def decode_image(img):
36    width, height = img.size
37    pixels = img.load()
38
39    cols = math.ceil(width / BLOCK_W)
40    groups = math.ceil(height / STRIDE_H)
41
42    decoded_chars = []
43
44    for group in range(groups):          # 从上到下
45        for col in range(cols):          # 从左到右
46            digits = []
47
48            for i in range(4):
49                base_x = col * BLOCK_W
50                base_y = group * STRIDE_H + i * BLOCK_H
51
52                x = base_x + TARGET_X
53                y = base_y + TARGET_Y
54
55                if x >= width or y >= height:
56                    value = 3
57                else:
58                    pixel = pixels[x, y]
59                    value = COLOR_MAP.get(pixel, 3)
60
61                digits.append(str(value))
62
63            base4 = ''.join(digits)
64
65            if any(c not in '0123' for c in base4):
66                decoded_chars.append('?')
67            else:
68                decoded_chars.append(chr(int(base4, 4)))
69
70    return ''.join(decoded_chars)
71
72
73# ================= 主流程 =================
74gif = Image.open(GIF_PATH)
75
76final_result = []
77
78print('==== GIF 帧解码 ====')
79
80for idx in FRAME_INDEXES:
81    frame_no = idx - 1  # 转为 0-based
82
83    gif.seek(frame_no)
84    frame = gif.convert('RGB')
85
86    # 右移 5 像素
87    shifted = shift_image_right(frame, SHIFT_X)
88
89    decoded = decode_image(shifted)
90
91    print(f'\n{idx} 解码结果:')
92    print(decoded)
93
94    final_result.append(decoded)
95
96print('\n==== 最终拼接结果 ====')
97print(''.join(final_result))

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

image-20260107165726109

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

HappyEmoji

知识点省流

四进制 图像识别

WP

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

image-20260107165222588

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

 1from PIL import Image, ImageSequence
 2import math
 3
 4# ================= 配置区 =================
 5GIF_PATH = 'flag.gif'
 6FRAME_INDEXES = [3, 34, 65, 96]   # 从 1 开始计数
 7
 8BLOCK_H = 42
 9BLOCK_W = 61
10GAP_H = 10
11
12TARGET_Y = 15
13TARGET_X = 34
14
15SHIFT_X = 5   # 向右平移 5 像素
16# =========================================
17
18COLOR_MAP = {
19    (191, 175, 143): 0,
20    (255, 223, 127): 2,
21    (255, 239, 111): 1
22}
23
24STRIDE_H = BLOCK_H * 4 + GAP_H
25
26
27def shift_image_right(img, shift):
28    """整张图向右平移 shift 像素"""
29    w, h = img.size
30    new_img = Image.new('RGB', (w, h), (0, 0, 0))
31    new_img.paste(img, (shift, 0))
32    return new_img
33
34
35def decode_image(img):
36    width, height = img.size
37    pixels = img.load()
38
39    cols = math.ceil(width / BLOCK_W)
40    groups = math.ceil(height / STRIDE_H)
41
42    decoded_chars = []
43
44    for group in range(groups):          # 从上到下
45        for col in range(cols):          # 从左到右
46            digits = []
47
48            for i in range(4):
49                base_x = col * BLOCK_W
50                base_y = group * STRIDE_H + i * BLOCK_H
51
52                x = base_x + TARGET_X
53                y = base_y + TARGET_Y
54
55                if x >= width or y >= height:
56                    value = 3
57                else:
58                    pixel = pixels[x, y]
59                    value = COLOR_MAP.get(pixel, 3)
60
61                digits.append(str(value))
62
63            base4 = ''.join(digits)
64
65            if any(c not in '0123' for c in base4):
66                decoded_chars.append('?')
67            else:
68                decoded_chars.append(chr(int(base4, 4)))
69
70    return ''.join(decoded_chars)
71
72
73# ================= 主流程 =================
74gif = Image.open(GIF_PATH)
75
76final_result = []
77
78print('==== GIF 帧解码 ====')
79
80for idx in FRAME_INDEXES:
81    frame_no = idx - 1  # 转为 0-based
82
83    gif.seek(frame_no)
84    frame = gif.convert('RGB')
85
86    # 右移 5 像素
87    shifted = shift_image_right(frame, SHIFT_X)
88
89    decoded = decode_image(shifted)
90
91    print(f'\n{idx} 解码结果:')
92    print(decoded)
93
94    final_result.append(decoded)
95
96print('\n==== 最终拼接结果 ====')
97print(''.join(final_result))

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

image-20260107165726109

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

HappyEmoji

知识点省流

四进制 图像识别

WP

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

image-20260107165222588

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

 1from PIL import Image, ImageSequence
 2import math
 3
 4# ================= 配置区 =================
 5GIF_PATH = 'flag.gif'
 6FRAME_INDEXES = [3, 34, 65, 96]   # 从 1 开始计数
 7
 8BLOCK_H = 42
 9BLOCK_W = 61
10GAP_H = 10
11
12TARGET_Y = 15
13TARGET_X = 34
14
15SHIFT_X = 5   # 向右平移 5 像素
16# =========================================
17
18COLOR_MAP = {
19    (191, 175, 143): 0,
20    (255, 223, 127): 2,
21    (255, 239, 111): 1
22}
23
24STRIDE_H = BLOCK_H * 4 + GAP_H
25
26
27def shift_image_right(img, shift):
28    """整张图向右平移 shift 像素"""
29    w, h = img.size
30    new_img = Image.new('RGB', (w, h), (0, 0, 0))
31    new_img.paste(img, (shift, 0))
32    return new_img
33
34
35def decode_image(img):
36    width, height = img.size
37    pixels = img.load()
38
39    cols = math.ceil(width / BLOCK_W)
40    groups = math.ceil(height / STRIDE_H)
41
42    decoded_chars = []
43
44    for group in range(groups):          # 从上到下
45        for col in range(cols):          # 从左到右
46            digits = []
47
48            for i in range(4):
49                base_x = col * BLOCK_W
50                base_y = group * STRIDE_H + i * BLOCK_H
51
52                x = base_x + TARGET_X
53                y = base_y + TARGET_Y
54
55                if x >= width or y >= height:
56                    value = 3
57                else:
58                    pixel = pixels[x, y]
59                    value = COLOR_MAP.get(pixel, 3)
60
61                digits.append(str(value))
62
63            base4 = ''.join(digits)
64
65            if any(c not in '0123' for c in base4):
66                decoded_chars.append('?')
67            else:
68                decoded_chars.append(chr(int(base4, 4)))
69
70    return ''.join(decoded_chars)
71
72
73# ================= 主流程 =================
74gif = Image.open(GIF_PATH)
75
76final_result = []
77
78print('==== GIF 帧解码 ====')
79
80for idx in FRAME_INDEXES:
81    frame_no = idx - 1  # 转为 0-based
82
83    gif.seek(frame_no)
84    frame = gif.convert('RGB')
85
86    # 右移 5 像素
87    shifted = shift_image_right(frame, SHIFT_X)
88
89    decoded = decode_image(shifted)
90
91    print(f'\n{idx} 解码结果:')
92    print(decoded)
93
94    final_result.append(decoded)
95
96print('\n==== 最终拼接结果 ====')
97print(''.join(final_result))

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

image-20260107165726109