抽空就写了一题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中
然后用我的瓜子卡鼠标宏,一秒三发,洗个澡就出了
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 等