抽空就写了一题QAQ

re

Excel CPU

你们喜闻乐见的 Excel CPU 逆向(简单版)来啦😼

这是一个 flag 解密机,你只需要昼夜不停地按 F9 键,本周结束前 flag 就会自动出现在第 142 行了!

……或者,你也可以用 LilRan 写的反汇编器,获得解密机的汇编程序。

很有意思的一题

非预期:

用LilRan师傅的项目反汇编后,删除自循环(F9主要在该处耗时)

	INC	R14			; at 0062
					; XREF(X): [0064]
	CMP	R15	R14		; at 0063
	JLT	loc_0062		; at 0064

用项目载入xlsx中

然后用我的瓜子卡鼠标宏,一秒三发,洗个澡就出了

img

image-20241030032014927

flag=[83,72,67,84,70,123,85,95,97,114,69,95,97,110,95,51,88,67,51,76,108,69,78,116,95,97,53,53,69,77,54,73,89,95,80,82,79,57,82,65,77,109,69,114,125]
for i in flag:
    print(chr(i),end="")

预期

根据汇编语法写出对应脚本

; Source Generated with Excel-CPU-Disassembler.py
; https://github.com/Lil-Ran/Excel-CPU-Disassembler

; No guarantee of accuracy or functionality is provided.
; It is recommended to set tab width to 8 spaces.

; File: ROM.xlsx
; Time: 2024-10-29 21:54:05


.DATA
	var_0002 = $BA5E
	var_0003 = $C0DE
	var_0004 = $FACE
	var_0005 = $F00D
	var_0006 = $CAFE
	var_0007 = $BABE
	var_0008 = $BEEF
	var_0009 = $DEAD
	var_000A = $8529
	var_000B = $35F7
	var_000C = $B527
	var_000D = $5556
	var_000E = $9A9A
	var_000F = $2D56
	var_0010 = $A3B8
	var_0011 = $0FE9
	var_0012 = $CFF6
	var_0013 = $8905
	var_0014 = $B898
	var_0015 = $08C9
	var_0016 = $9417
	var_0017 = $1768
	var_0018 = $0719
	var_0019 = $B60B
	var_001A = $6E06
	var_001B = $7B78
	var_001C = $596B
	var_001D = $EDF7
	var_001E = $D95A
	var_001F = $8AB7
	var_0020 = $F557
	var_0021 = $5B28
	var_0022 = $47E9
	var_0023 = $C535
	var_0024 = $B7AB
	var_0025 = $5E1C
	var_0026 = $5899
	var_0027 = $F337
	var_0028 = $74DC
	var_0029 = $1A78
	var_002A = $2999
	var_002B = $2558
	var_002C = $8AA9
	var_002D = $A099
	var_002E = $F4E9
	var_002F = $32DA
	var_0030 = $93B9
	var_0031 = $96D8
	var_0032 = $6918
	var_0033 = $5E95
	var_0034 = $B768
	var_0035 = $58C7
	var_0036 = $C879

.CODE

Entrypoint_0037:
	LOAD	R1	$000A		; at 0037
					; XREF(X): [0000]
	LOAD	R2	$0000		; at 0039
	LOAD	R3	$0000		; at 003B
	LOAD	R15	$0001		; at 003D

loc_003F:
	LOAD	R3	R1		; at 003F
					; XREF(X): [0069]
	TRAN	R1	R8		; at 0040
	LOAD	R9	$0008		; at 0041
	DIV	R8	R9		; at 0043
	LOAD	R8	$0002		; at 0044
	CLC				; at 0046
	ADD	R8	R9		; at 0047
	LOAD	R10	R8		; at 0048
	CLC				; at 0049
	SUB	R3	R10		; at 004A
	LOAD	R9	$0008		; at 004B
	DIV	R2	R9		; at 004D
	LOAD	R8	$0002		; at 004E
	CLC				; at 0050
	ADD	R8	R9		; at 0051
	LOAD	R10	R8		; at 0052
	XOR	R3	R10		; at 0053
	ROL	R3	#4		; at 0054
	LOAD	R8	$00FF		; at 0055
	AND	R3	R8		; at 0057
	LOAD	R8	$01F6		; at 0058
	CLC				; at 005A
	ADD	R8	R1		; at 005B
	STORE	R3	R8		; at 005C
	LOAD	R2	R1		; at 005D
	INC	R1			; at 005E
	ROL	R15	#1		; at 005F
	LOAD	R14	$0000		; at 0060

loc_0062:
	INC	R14			; at 0062
					; XREF(X): [0064]
	CMP	R15	R14		; at 0063
	JLT	loc_0062		; at 0064
	LOAD	R4	$003F		; at 0066
	CMP	R4	R1		; at 0068
	JLT	loc_003F		; at 0069

loc_006B:
	JMP	loc_006B		; at 006B
					; XREF(X): [006B]

exp

# 初始化 .DATA 段的变量
data = [
    0,0,0xBA5E, 0xC0DE, 0xFACE, 0xF00D, 0xCAFE, 0xBABE, 0xBEEF, 0xDEAD,
    0x8529, 0x35F7, 0xB527, 0x5556, 0x9A9A, 0x2D56, 0xA3B8, 0x0FE9,
    0xCFF6, 0x8905, 0xB898, 0x08C9, 0x9417, 0x1768, 0x0719, 0xB60B,
    0x6E06, 0x7B78, 0x596B, 0xEDF7, 0xD95A, 0x8AB7, 0xF557, 0x5B28,
    0x47E9, 0xC535, 0xB7AB, 0x5E1C, 0x5899, 0xF337, 0x74DC, 0x1A78,
    0x2999, 0x2558, 0x8AA9, 0xA099, 0xF4E9, 0x32DA, 0x93B9, 0x96D8,
    0x6918, 0x5E95, 0xB768, 0x58C7, 0xC879
]
R1 = 0x000A
R2 = 0x0000
R3 = 0x0000
R15 = 0x0001

while R1 < len(data):
    R3 = data[R1]
    R8 = R1
    R9 = 0x0008
    R9 = R8 % R9
    R8=2
    R8 += R9
    R10=data[R8]
    R3 -= R10
    R3&=0xffff
    R9=8
    R9= R2 % R9
    R8 = 2
    R8 += R9
    R10=data[R8]

    R3 ^= R10
    R3 = ((R3 << 4) & 0xFFFF) +(R3>>12) 
    R3 &= 0x00FF 
    print(chr(R3),end="")
    R2 = data[R1]
    R1 += 1 

指令表

操作码 8b 4b 4b 16b 32b/16b 操作 ALU OP MUX SEL REG1W REG2W PC 设置 IMD L/H 16b 技术说明
00 0 JMP IMD 32b IMD -> PC 15 4 0 0 1 0 通过 MUX 选择的操作数 2 输出将 PC 设置为立即数
01 1 JEQ IMD 如果 Z = 1, IMD -> PC 15 4 0 0 1 0 如果零标志为真,则跳转
02 2 JLT IMD 如果 C = 0, IMD -> PC 15 4 0 0 1 0 如果进位标志为假,则跳转
03 3 JGE IMD 如果 C = 1 或 Z = 1, IMD -> PC 15 4 0 0 1 0 如果进位标志或零标志为真,则跳转
04 4 LOAD REG MEM [MEM] -> REGA 15 5 1 0 0 1 将寄存器设置为立即地址的内存值
05 5 LOAD REG IMD IMD -> REGA 15 4 1 0 0 1 将寄存器设置为立即值
06 6 STORE REG MEM REGA -> [MEM] 12 4 0 0 0 0 将寄存器值设置为立即地址的内存值
07 7 STORE REG REG 16b REGA -> [REGB] 12 1 0 0 0 0 将 REGA 的值存储在 REGB 地址的内存中
08 8 TRAN REG REG REGA -> REGB 12 1 0 1 0 0 将 REGA 值传输到 REGB
09 9 ADD REG REG REGA + REGB + C -> REGA 0 1 1 0 0 0 加 REGA、REGB 和进位标志,结果存储在 REGA 中
0A 10 SUB REG REG REGA - REGB - C -> REGA 1 1 1 0 0 0 减去 REGA、REGB 和进位标志,结果存储在 REGA 中
0B 11 MULT REG REG REGA * REGB -> 低 16 在 REGA,高 16 在 REGB 2 1 1 1 0 0 将 REGA 和 REGB 相乘,低 16 位结果存储在 REGA,高 16 位结果存储在 REGB
0C 12 DIV REG REG REGA / REGB -> 结果在 REGA,余数在 16 位的 REGB 3 1 1 1 0 0 将 REGA 除以 REGB,结果存储在 REGA,余数存储在 REGB
0D 13 INC REG REGA + 1 -> REGA(标志不受影响) 4 0 1 0 0 0 增加 REGA 值,进位标志不受影响
0E 14 DEC REG REGA - 1 -> REGA(标志不受影响) 5 0 1 0 0 0 减少 REGA 值,进位标志不受影响
0F 15 AND REG REG REGA 和 REGB -> REGA 6 1 1 0 0 0 REGA 和 REGB 的按位与,结果存储在 REGA
10 16 OR REG REG REGA 或 REGB -> REGA 7 1 1 0 0 0 REGA 和 REGB 的按位或,结果存储在 REGA
11 17 XOR REG REG REGA 异或 REGB -> REGA 8 1 1 0 0 0 REGA 和 REGB 的按位异或,结果存储在 REGA
12 18 NOT REG 非 REGA -> REGA 9 0 1 0 0 0 REGA 的按位非,结果存储在 REGA
13 19 ROL REG IMD REGA << IMD -> REGA 10 3 1 0 0 0 REGA 位左移 IMD 位
14 20 ROR REG IMD REGA >> IMD -> REGA 11 3 1 0 0 0 REGA 位右移 IMD 位
15 21 CMP REG REG REGA - REGB -> 仅标志更改 1 1 0 0 0 0 减去 REGA 和 REGB,结果不存储,仅标志受影响
16 22 CLC 0 -> C 13 0 0 0 0 0 进位标志设置为 0
17 23 STC 1 -> C 14 0 0 0 0 0 进位标志设置为 1
18 24 NOP 无操作 15 0 0 0 0 0 无操作执行
19 25 LOAD REG REG [REGB] -> REGA 15 2 1 0 0 1 将 REGB 地址的内存值加载到 REGA 中

类型

REG	; 指代任一16个通用寄存器
例如:R0, R1, R15 等

MEM	; 指代任一16位可寻址的内存单元(十六进制格式)
例如:@0000, @F000, @FFFF 等

IMD	; 指代一个通常为16位的立即数,ROL和ROR指令除外
	; 可以用十进制或十六进制表示
例如:#0000, $0CCC, #60340, $FF10 等