收获

  • 汇编代码逻辑

【HGAME】easyasm


思路

将文件拖入 Exeinfo PE 查看文件类型:

HGAME-easyasm1.png

发现文件是一个 16位 的 MS-DOS 程序

拖入 IDA,对 start 函数 F5 反编译发现无法编译

HGAME-easyasm2.png

可能是 IDA 无法反编译 16位 程序

直接查看汇编代码:

HGAME-easyasm3.png

首先将 dseg 移入 ds 段,将 seg001 移入 es

dseg 的内容:hgame{Fill_in_your_flag}

HGAME-easyasm4.png

seg001 的内容:[0x91, 0x61, 0x01, 0xC1, 0x41, 0xA0, 0x60, 0x41, 0xD1, 0x21, 0x14, 0xC1, 0x41, 0xE2, 0x50, 0xE1, 0xE2, 0x54, 0x20, 0xC1, 0xE2, 0x60, 0x14, 0x30, 0xD1, 0x51, 0xC0, 0x17, 0x00, 0x00, 0x00, 0x00]

HGAME-easyasm5.png

初始时 si = 0,根据:

loc_100DD:                              ; CODE XREF: start+38↓j
cmp     si, 1Ch
jz      short loc_10135
---------------------------------------------------------------
add     si, 1
cmp     al, es:[si-1]
jz      short loc_100DD

mov     ax, 0B800h
mov     es, ax
assume es:nothing
mov     byte ptr es:0, 77h ; 'w'
mov     byte ptr es:2, 72h ; 'r'
mov     byte ptr es:4, 6Fh ; 'o'
mov     byte ptr es:6, 6Eh ; 'n'
mov     byte ptr es:8, 67h ; 'g'
mov     byte ptr es:0Ah, 21h ; '!'
---------------------------------------------------------------
loc_10135:                              ; CODE XREF: start+10↑j
mov     ax, 0B800h
mov     es, ax
mov     byte ptr es:0, 72h ; 'r'
mov     byte ptr es:2, 69h ; 'i'
mov     byte ptr es:4, 67h ; 'g'
mov     byte ptr es:6, 68h ; 'h'
mov     byte ptr es:8, 74h ; 't'
mov     byte ptr es:0Ah, 21h ; '!'

可知 loc_100DD 是一个循环,循环的次数由计数器 si 的值控制,每循环一次 si + 1
si = 1Ch 时,输出 “right!”
并且每一轮循环都必须满足 al = es:[si-1],否则就输出 “wrong!”

根据:

xor     ax, ax
mov     al, [si]
shl     al, 1
shl     al, 1
shl     al, 1
shl     al, 1
push    ax

首先通过异或 xor ax, axax 清零,然后将 si 中存放的值作为地址,取该地址上的值作为 [si] (间接寻址,si 中存放的是操作数的地址)
[si] 的值存入 ax,然后 4 个 shl al, 1al 逻辑左移(低位补 0) 4 位后,将 ax 送入堆栈段

同理,根据:

xor     ax, ax
mov     al, [si]
shr     al, 1
shr     al, 1
shr     al, 1
shr     al, 1

首先通过异或 xor ax, axax 清零,接着将 [si] 的值存入 ax
然后 4 个 shr al, 1al 逻辑右移(高位补 0) 4 位

注意这里:

pop     bx
add     ax, bx

这里将刚刚 push ax 时入栈的 ax 出栈作为 bx

假设 [si] = xxxx yyyy
此时的 bx 应该为 yyyy 0000,而此时 ax 的值为 0000 xxxx
因此 add ax, bx 后,ax = yyyy xxxx
即:此过程其实就是将 [si] 的高位和低位互换位置

根据:

xor     ax, 17h
add     si, 1
cmp     al, es:[si-1]
jz      short loc_100DD

这里将 ax(互换高位和低位后的 [si]) 与 0x17 异或,计数器 si 加一,然后将 al 与以 es 为段首址、以 si - 1 为偏移地址的地址处的值进行比较(ES 是附加数据段的段首址),如果相等就继续往下循环,否则就输出 “wrong!”

因此,程序逻辑就是将 flag 的每个字符的 前四位 和 后四位 进行置换,然后与 0x17 异或,再与 es 段的数据进行逐位比较


脚本

unk_10030 = [  
    0x91, 0x61, 0x01, 0xC1, 0x41, 0xA0, 0x60, 0x41, 0xD1, 0x21, 0x14, 0xC1, 0x41, 0xE2, 0x50, 0xE1,  
    0xE2, 0x54, 0x20, 0xC1, 0xE2, 0x60, 0x14, 0x30, 0xD1, 0x51, 0xC0, 0x17, 0x00, 0x00, 0x00, 0x00  
]  
  
for i in range(0x1c - 1):  
    key = unk_10030[i] ^ 0x17  
    key_h = int(key / 16)  
    key_l = key - key_h * 16  
    print(chr(key_l * 16 + key_h), end="")

结果

hgame{welc0me_to_4sm_w0rld}

HGAME-easyasm6.png