# 汇编语言

这个题是寒假的时候一个叫 Hgame 的比赛的题,当时也做了一下没看懂,开学之后学了点汇编之后就勉强能看懂了,勉强弄懂了它的逻辑,先看看它的汇编语言吧:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
seg001:0000 seg001          segment byte public 'UNK' use16
seg001:0000 assume cs:seg001
seg001:0000 assume es:nothing, ss:nothing, ds:dseg, fs:nothing, gs:nothing
seg001:0000 db 91h
seg001:0001 db 61h ; a
seg001:0002 db 1
seg001:0003 db 0C1h
seg001:0004 db 41h ; A
seg001:0005 db 0A0h
seg001:0006 db 60h ; `
seg001:0007 db 41h ; A
seg001:0008 db 0D1h
seg001:0009 db 21h ; !
seg001:000A db 14h
seg001:000B db 0C1h
seg001:000C db 41h ; A
seg001:000D db 0E2h
seg001:000E db 50h ; P
seg001:000F db 0E1h
seg001:0010 db 0E2h
seg001:0011 db 54h ; T
seg001:0012 db 20h
seg001:0013 db 0C1h
seg001:0014 db 0E2h
seg001:0015 db 60h ; `
seg001:0016 db 14h
seg001:0017 db 30h ; 0
seg001:0018 db 0D1h
seg001:0019 db 51h ; Q
seg001:001A db 0C0h
seg001:001B db 17h
seg001:001C db 0
seg001:001D db 0
seg001:001E db 0
seg001:001F db 0
seg001:001F seg001 ends
seg001:001F
seg002:0000 ; ===========================================================================
seg002:0000
seg002:0000 ; Segment type: Uninitialized
seg002:0000 seg002 segment byte stack 'STACK' use16
seg002:0000 assume cs:seg002
seg002:0000 assume es:nothing, ss:nothing, ds:dseg, fs:nothing, gs:nothing
seg002:0000 db 80h dup(0)
seg002:0000 seg002 ends
seg002:0000
seg003:0000 ; ===========================================================================
seg003:0000
seg003:0000 ; Segment type: Pure code
seg003:0000 seg003 segment byte public 'CODE' use16
seg003:0000 assume cs:seg003
seg003:0000 assume es:nothing, ss:seg002, ds:nothing, fs:nothing, gs:nothing
seg003:0000
seg003:0000 ; =============== S U B R O U T I N E =======================================
seg003:0000
seg003:0000 ; Attributes: noreturn
seg003:0000
seg003:0000 public start
seg003:0000 start proc near
seg003:0000 mov ax, seg dseg
seg003:0003 mov ds, ax
seg003:0005 assume ds:dseg
seg003:0005 mov ax, seg seg001
seg003:0008 mov es, ax
seg003:000A assume es:seg001
seg003:000A mov si, 0
seg003:000D
seg003:000D loc_100DD: ; CODE XREF: start+38↓j
seg003:000D cmp si, 1Ch
seg003:0010 jz short loc_10135
seg003:0012 xor ax, ax
seg003:0014 mov al, [si]
seg003:0016 shl al, 1
seg003:0018 shl al, 1
seg003:001A shl al, 1
seg003:001C shl al, 1
seg003:001E push ax
seg003:001F xor ax, ax
seg003:0021 mov al, [si]
seg003:0023 shr al, 1
seg003:0025 shr al, 1
seg003:0027 shr al, 1
seg003:0029 shr al, 1
seg003:002B pop bx
seg003:002C add ax, bx
seg003:002E xor ax, 17h
seg003:0031 add si, 1
seg003:0034 cmp al, es:[si-1]
seg003:0038 jz short loc_100DD
seg003:003A mov ax, 0B800h
seg003:003D mov es, ax
seg003:003F assume es:nothing
seg003:003F mov byte ptr es:0, 77h ; 'w'
seg003:0045 mov byte ptr es:2, 72h ; 'r'
seg003:004B mov byte ptr es:4, 6Fh ; 'o'
seg003:0051 mov byte ptr es:6, 6Eh ; 'n'
seg003:0057 mov byte ptr es:8, 67h ; 'g'
seg003:005D mov byte ptr es:0Ah, 21h ; '!'
seg003:0063
seg003:0063 loc_10133: ; CODE XREF: start:loc_10133↓j
seg003:0063 jmp short loc_10133
seg003:0065 ; ---------------------------------------------------------------------------
seg003:0065
seg003:0065 loc_10135: ; CODE XREF: start+10↑j
seg003:0065 mov ax, 0B800h
seg003:0068 mov es, ax
seg003:006A mov byte ptr es:0, 72h ; 'r'
seg003:0070 mov byte ptr es:2, 69h ; 'i'
seg003:0076 mov byte ptr es:4, 67h ; 'g'
seg003:007C mov byte ptr es:6, 68h ; 'h'
seg003:0082 mov byte ptr es:8, 74h ; 't'
seg003:0088 mov byte ptr es:0Ah, 21h ; '!'
seg003:008E
seg003:008E loc_1015E: ; CODE XREF: start:loc_1015E↓j
seg003:008E jmp short loc_1015E
seg003:008E start endp
seg003:008E
seg003:008E seg003 ends
seg003:008E
seg003:008E
seg003:008E end start

# 思路

它的逻辑是将输入的字符左移四位再右移四位再相加,然后再将每一位与 0x17 异或运算,如果每一位结果都等于 seg001 中的值对应相等就输出 right,那么我们就逆着来写个脚本

# 脚本

# 问题

一开始我是用 python 写的,但是一直输出不了正确答案,我很疑惑,然后看了大佬写的脚本之后发现他们在第八行,在左移的时候给 xor 还与上了一个 0x0f(还有大佬与上的是 0xff),这样之后结果就是对的,这里我还是没搞懂

1
2
3
4
5
6
7
8
9
list = [0x91, 0x61, 0x1, 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]

flag = ''
for i in list:
xor = i ^ 0x17

flag += chr((xor >> 4) + ((xor & 0x0f) << 4))
print(flag)

然后我同学就告诉我用 c 语言来写脚本,发现 c 语言可以不用这样

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include<stdio.h>
int main()
{
int a[28] = {0x91,0x61,0x1,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};
for(int i=0;i<28;i++)
{
a[i] = a[i] ^ 23;
}
for(int i=0;i<28;i++)
{
a[i] = (a[i]>>4)+ (a[i]<<4);
printf("%c",a[i]);

}
return 0;
}

这里要注意一个细节,就是在程序中,我们的值是先进行左移再进行右移的,所以我们在写脚本的时候要注意,要先右移再左移,这样的结果才是对的,一开始我没注意,我同学告诉我之后我才知道这个细节,学到了

最后得到 flag:hgame{welc0me_to_4sm_w0rld}

题目来源:Hgame ctf 2022 – easyasm