LOADING

加载过慢请开启缓存 浏览器默认开启

单片机和偷摸零

好久没更博客了捏~

前段时间参与了ISCTF 2025的出题喵。

不过是闭着眼出的题,拿自己前段时间的一些作业改出来了三道题目出来。

看评价还可以,偷摸零算是0差评吧,两个单片机总共只有2个差评,感觉已经很不错了捏~

那末,本文就简单概述一下这三道题的Writeup以及出题想法吧。

冲刺!偷摸零!

Jar包,拿到题目直接解压。
看到解压出来一个ctf.db,用navicat看一眼。 这里设计这个ctf.db的原因其实是这个实训作业当时用了数据库,,,为了游戏不崩溃所以换成了sqlite3。于是就顺手把flag掰成两段塞里面了一份。
main-表-user,看到第一行有PART1。

9dbf6c57-c6c1-465b-aa1f-43964151d0d4

第一段flag就找到了。同时,看到这个形式,猜测第二段flag的开头也是PART,并且是PART2。
启动游戏,把凑企鹅玩死之后,弹窗提示内存多了什么东西。这里是:诶!☝️🤓

于是:

a2c5ff9d-3f43-4b6f-97b4-de01ec924a4b

两种方案:用CE查内存或者直接逆。
方案1:打开CE,然后打开GAME OVER!!!进程。

fc1e1514-06b6-49f1-bfaf-243e9241d8b9

用memory view查内存里PART2关键字。

34c2827e-b759-4ada-8cb8-24f97bd1bf77

53dfd173-3389-453c-9e65-ab8ab1e40f74

很快就找到了。

1763b5d8-0fc3-4473-ad1e-52bd0a64d63a

两段拼一起就是flag。

方案2:直接逆向法

加密算法并不难,所以逆着也简单。IDEA就能逆,逆向起来很方便。

先把Jar包解压掉,然后找到GameOverView类,点开即送。

这一坨就是密文,一眼异或,直接cyberchef一把梭。

这就出了捏~

ISCTF{Tom0R1_Dash_GuGu_GAGA!!}

单片机1

解题思路

其实是把flag的字模塞到了程序里。

用工具逆一下,可以发现最底部有大堆的数据。这些就是字模。

77b2a984-131c-4160-81a3-b6a5382ec54e

写个脚本,把字模渲染出来,就能看到flag了。

exp

def visualize_font(asm_data):
    # 1. 解析数据
    byte_list = []
    
    lines = asm_data.strip().split('\n')
    for line in lines:
        if "DB" not in line:
            continue
            
        # 提取 DB 后面的部分: "03CH, 018H..."
        content = line.split("DB")[1]
        
        # 按逗号分割并清理数据
        hex_values = content.split(',')
        for h in hex_values:
            # 去掉空格和结尾的 'H'
            clean_hex = h.strip().replace('H', '')
            if clean_hex:
                byte_list.append(int(clean_hex, 16))

    # 2. 显示字模 (假设是 8x8 点阵,每 8 个字节一个字符)
    bytes_per_char = 8
    total_chars = len(byte_list) // bytes_per_char

    print(f"解析到 {total_chars} 个字符:\n")

    for i in range(total_chars):
        # 获取当前字符的 8 个字节
        char_bytes = byte_list[i*bytes_per_char : (i+1)*bytes_per_char]
        
        print(f"--- 字符 {i+1} (Offset: {i*8}) ---")
        for b in char_bytes:
            # 转为二进制字符串,补足8位
            bits = format(b, '08b')
            # 替换 0 和 1 为更可视化的字符
            visual = bits.replace('0', '  ').replace('1', '██')
            print(f"{visual}  ({hex(b)})")
        print("")

# 你的原始数据
raw_data = """
0208:                DB      03CH, 018H, 018H, 018H, 018H, 018H, 03CH, 000H
0210:                DB      03CH, 042H, 040H, 03CH, 002H, 042H, 03CH, 000H
0218:                DB      03CH, 042H, 040H, 040H, 040H, 042H, 03CH, 000H
0220:                DB      07EH, 008H, 008H, 008H, 008H, 008H, 008H, 000H
0228:                DB      07EH, 040H, 040H, 07CH, 040H, 040H, 040H, 000H
0230:                DB      01EH, 010H, 010H, 020H, 010H, 010H, 01EH, 000H
0238:                DB      042H, 042H, 042H, 05AH, 07EH, 066H, 042H, 000H
0240:                DB      000H, 000H, 03CH, 042H, 042H, 042H, 03CH, 000H
0248:                DB      000H, 000H, 042H, 042H, 05AH, 07EH, 042H, 000H
0250:                DB      000H, 000H, 000H, 000H, 000H, 000H, 07EH, 000H
0258:                DB      042H, 042H, 042H, 03CH, 018H, 018H, 018H, 000H
0260:                DB      000H, 000H, 03CH, 042H, 042H, 042H, 03CH, 000H
0268:                DB      000H, 000H, 042H, 042H, 042H, 042H, 03EH, 000H
0270:                DB      000H, 000H, 000H, 000H, 000H, 000H, 07EH, 000H
0278:                DB      018H, 024H, 042H, 042H, 07EH, 042H, 042H, 000H
0280:                DB      000H, 000H, 05CH, 062H, 040H, 040H, 040H, 000H
0288:                DB      000H, 000H, 03CH, 042H, 07EH, 040H, 03CH, 000H
0290:                DB      000H, 000H, 000H, 000H, 000H, 000H, 07EH, 000H
0298:                DB      03CH, 042H, 040H, 04EH, 042H, 042H, 03EH, 000H
02A0:                DB      000H, 000H, 03CH, 042H, 042H, 042H, 03CH, 000H
02A8:                DB      000H, 000H, 03CH, 042H, 042H, 042H, 03CH, 000H
02B0:                DB      002H, 002H, 032H, 04AH, 04AH, 04AH, 03EH, 000H
02B8:                DB      000H, 000H, 000H, 000H, 000H, 000H, 07EH, 000H
02C0:                DB      018H, 024H, 042H, 042H, 07EH, 042H, 042H, 000H
02C8:                DB      010H, 010H, 07EH, 010H, 010H, 010H, 00EH, 000H
02D0:                DB      000H, 000H, 000H, 000H, 000H, 000H, 07EH, 000H
02D8:                DB      03EH, 020H, 020H, 03CH, 002H, 002H, 03CH, 000H
02E0:                DB      010H, 030H, 010H, 010H, 010H, 010H, 038H, 000H
02E8:                DB      078H, 008H, 008H, 00CH, 008H, 008H, 078H, 000H
"""

if __name__ == "__main__":
    visualize_font(raw_data)

单片机2

解题思路

1602A屏幕的显示程序,实际1602的DATA引脚要接收的是ASCII码。程序这里只是做了一个简单异或加密。

给的前面大堆反汇编出来的汇编源码和NOTE.txt其实都没什么用。真正有用的内容还是最后那一部分。

8e5203d8-defb-4c57-a5b6-ba06c35493eb

密文和解密逻辑都在这了,直接解。

091d6664-df65-46f5-9b46-a1006d56a2c4

其实这题是我1602的作业改的,,,专门加了一个解密逻辑进去喵~