16位简单ASM题的记录——[HGAME 2022 week1]easyasm

第一次遇见16位,和纯看汇编的题目,记录一下

DIE

16位,IDA用32位或者64位都可以打开

IDA

主要汇编部分

复制代码
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          ; 数据段寄存器ds。
seg003:0005                 assume ds:dseg
seg003:0005                 mov     ax, seg seg001  ; 告诉汇编器ds寄存器现在指向dseg段。
seg003:0008                 mov     es, ax          ; 额外段寄存器es。
seg003:000A                 assume es:seg001
seg003:000A                 mov     si, 0           ; 告诉汇编器es寄存器现在指向seg001段。
seg003:000A                                         ; 将寄存器si置零,用于遍历数组或字符串。
seg003:000D
seg003:000D loc_100DD:                              ; CODE XREF: start+38↓j
seg003:000D                 cmp     si, 28          ; 比较寄存器si的值与28(即检查是否已经处理了28个字节)。
seg003:0010                 jz      short loc_10135 ; 成功跳转
seg003:0010                                         ; 如果si等于28,跳转到标签loc_10135。
seg003:0012                 xor     ax, ax          ; 将寄存器ax清零。
seg003:0014                 mov     al, [si]        ; 将ds:[si]处的字节值加载到al(si是索引寄存器,指向当前要处理的数据字节)。
seg003:0016                 shl     al, 1
seg003:0018                 shl     al, 1
seg003:001A                 shl     al, 1
seg003:001C                 shl     al, 1           ; 将al中的值左移4次(每次左移一位,相当于乘以16)。
seg003:001E                 push    ax              ; 将ax的值压入堆栈。
seg003:001F                 xor     ax, ax          ; 将寄存器ax清零。
seg003:0021                 mov     al, [si]        ; 将ds:[si]处的字节值再次加载到al。
seg003:0023                 shr     al, 1
seg003:0025                 shr     al, 1
seg003:0027                 shr     al, 1
seg003:0029                 shr     al, 1           ; 将al中的值右移4次(每次右移一位,相当于除以16)。
seg003:002B                 pop     bx              ; 将堆栈中的值,即左移处理后的值,弹出到寄存器bx。
seg003:002C                 add     ax, bx          ; 将ax和bx的值相加,结果存入ax。
seg003:002E                 xor     ax, 17h         ; 将ax的值与17h(23十进制)异或。
seg003:0031                 add     si, 1           ; 将si加1,指向下一个字节。
seg003:0034                 cmp     al, es:[si-1]   ; 将al中的值与es:[si-1]处的值比较。
seg003:0038                 jz      short loc_100DD ; 如果相等,跳回到标签loc_100DD继续处理下一个字节。
seg003:003A                 mov     ax, 0B800h      ; 将视频内存段地址B800h加载到ax。
seg003:003D                 mov     es, ax          ; 将寄存器ax的值(即视频内存段地址B800h)加载到额外段寄存器es。
seg003:003F                 assume es:nothing
seg003:003F                 mov     byte ptr es:0, 77h ; 'w' ; 告诉汇编器es寄存器现在指向视频内存段。
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 ; '!' ; 将字符串"wrong!"依次写入视频内存,显示在屏幕上。
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 ; '!' ; 将字符串"right!"依次写入视频内存,显示在屏幕上。
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

dseg段

复制代码
dseg:0000 ; Segment type: Pure data
dseg:0000 dseg            segment para public 'DATA' use16
dseg:0000                 assume cs:dseg
dseg:0000 aHgameFillInYou db 'hgame{Fill_in_your_flag}',0
dseg:0019                 db    0
dseg:001A                 db    0
dseg:001B                 db    0
dseg:001C                 db    0
dseg:001D                 db    0
dseg:001E                 db    0
dseg:001F                 db    0
dseg:0020                 db    0
dseg:0021                 db    0
dseg:0022                 db    0
dseg:0023                 db    0
dseg:0024                 db    0
dseg:0025                 db    0
dseg:0026                 db    0
dseg:0027                 db    0
dseg:0028                 db    0
dseg:0029                 db    0
dseg:002A                 db    0
dseg:002B                 db    0
dseg:002C                 db    0
dseg:002D                 db    0
dseg:002E                 db    0
dseg:002F                 db    0
dseg:002F dseg            ends

seg001段

复制代码
seg001:0000 ; Segment type: Regular
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

shift+E提取出来

复制代码
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

疑问:0B800h为什么是视频内存?

x86汇编语言之显存操控屏幕输出

操控显存输出字符串

前面咱们介绍过使用中断的方式输出字符串, 今天我们学习一种不使用中断的方式实现字符串的打印

在8086的内存地址结构中,B8000H~BFFFFH这部分的内存区域为显存区域,一旦向这个地址空间写入数据,cpu会从0号偏移地址开始读取数据然后显示输出, (每写入一次数据就从0开始读取一次)

代码尝试:

复制代码
start:
       mov ax,0B800H
       mov ds,ax
  
     
       mov dl,'a'           
       mov ds:[0],dl
end start

在这块区域中,每个字符固定占用两个字节的空间,也就是ds:[0]ds:[1]存放一个字符的信息,前者存放字符具体的内容,后者存放字符对应的颜色

比如:

复制代码
start:
       mov ax,0B800H
       mov ds,ax
  
     
       mov dl,'a'           
       mov ds:[0],dl
       
       mov dl,00000100B ;让字符以红色显示          
       mov ds:[1],dl
end start

作者:乱码三千
链接:https://juejin.cn/post/7028744851805978638
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
汇编都标注好了注释,逻辑不难理解
将dseg的每个字节左移与右移的结果相加,再进行异或操作,最后与seg001比较

EXP

复制代码
 1 flag = ''
 2 
 3 seg001 = [
 4     0x91, 0x61, 0x01, 0xC1, 0x41, 0xA0, 0x60, 0x41, 0xD1, 0x21,
 5     0x14, 0xC1, 0x41, 0xE2, 0x50, 0xE1, 0xE2, 0x54, 0x20, 0xC1,
 6     0xE2, 0x60, 0x14, 0x30, 0xD1, 0x51, 0xC0, 0x17
 7 ]
 8 
 9 for i in seg001:
10     add = i ^ 23
11     temp1 = add >> 4  # 低位
12     temp2 = add << 4  # 高位
13     flag += chr((temp1 + temp2) & 0xFF)  ##第一次漏了,报错:TypeError: ord() expected string of length 1, but int found
14 
15 print(flag)

flag

复制代码
hgame{welc0me_to_4sm_w0rld}