ANSI转义序列
之前博主玩了玩wmctf2021的MISC题, 其中的logo题给人一个眼前一亮的感觉, 也是第一次接触ANSI转义序列, 这篇文章就来总结一下
定义
ANSI转义序列(ANSI escape sequences)是一种带内信号的转义序列标准,用于控制视频文本终端上的光标位置、颜色和其他选项。在文本中嵌入确定的字节序列,大部分以ESC
转义字符和""字符开始,终端会把这些字节序列解释为相应的指令,而不是普通的[字符编码。
ANSI序列是在二十世纪七十年代引入的标准,用以取代特定于终端供应商的序列,并在二十世纪八十年代早期开始在计算机设备市场上广泛使用。与早期缺少光标移动功能的系统相比,新生的电子公告板系统使用ANSI序列改进其显示。正是因为这个原因,ANSI序列变成了所有制造商共同采用的标准。
在21世纪,尽管硬件文本终端已经越来越少了,但ANSI标准依然存在,因为大多数终端模拟器会对部分ANSI转义序列进行解释。一个值得注意的例外是,在微软Windows 10更新TH2之前,Windows操作系统的Win32控制台是不支持ANSI转义序列的。( 引自wiki)
简而言之, ANSI转义是一种能把特定字符串转义成系统指令的转义序列, 它不像ASCII之类的只是转义不可见和可见字符, 他更多的是进行系统指令的转义,
案例
在bash中我们常常会遇到这么一种情况: 如果我们的bash界面因为打开了某些诸如socat之类的程序而被暂时"阻塞"的时候, 若这时我们按下了方向键, 如上下左右, 则会依次打印出
^[[A^[[B^[[D^[[C 就是使用ANSI转义的方向键, 其中^[是一个字符: 0x1b, 也就是[ESC]
, 所有序列都以ASCII字符[ESC]
(27 / 0x1B)开头,第二个字节则是0x40–0x5F(ASCII @A–Z[\]^_
)范围内的字符。
一些ANSI转义序列(不完整列表)
序列 | C1 | 名称 | 作用 |
---|---|---|---|
ESC N | 0x8e | SS2 – Single Shift Two | 从其中一个替代字符集中选择一个字符。在xterm中,SS2选择G2字符集,SS3选择G3字符集。 |
ESC O | 0x8f | SS3 – Single Shift Three | 从其中一个替代字符集中选择一个字符。在xterm中,SS2选择G2字符集,SS3选择G3字符集。 |
ESC P | 0x90 | DCS – 设备控制字符串(Device Control String) | 控制设备。在xterm中,这个序列的使用包括定义用户自定义的密钥,以及请求或设置Termcap/Terminfo数据。 |
ESC [ | 0x9b | CSI - 控制序列导入器(Control Sequence Introducer) | 大部分有用的序列。结束于ASCII 64到126 (@ 到~ /十六进制0x40到0x7E). |
ESC\ | 0x9c | ST – 字符串终止(String Terminator) | 终止其他控件(包括APC,DCS,OSC,PM和SOS)中的字符串。 |
ESC ] | 0x9d | OSC – 操作系统命令(Operating System Command) | 启动操作系统使用的控制字符串。OSC序列与CSI序列相似,但不限于整数参数。通常,这些控制序列由ST终止。在xterm中,它们也可能被BEL终止。例如,在xterm中,窗口标题可以这样设置:OSC 0;this is the window title BEL 。 |
ESC X | 0x98 | SOS – 字符串开始(Start of String) | 引用由ST终止的一串文本的参数。这些字符串控制序列的用途由应用程序或私有规则来定义。这些函数没有实现,参数被xterm忽略。 |
ESC ^ | 0x9e | PM – 私有消息(Privacy Message) | 将设备重置为原始状态。可能包括(如果适用的话):重置图形格式,清除制表符,重置为默认字体等等。 |
ESC _ | 0x9f | APC – 应用程序命令(Application Program Command) | 将设备重置为原始状态。可能包括(如果适用的话):重置图形格式,清除制表符,重置为默认字体等等。 |
ESC c | RIS – 重置为初始状态(Reset to Initial State) | 将设备重置为原始状态。可能包括(如果适用的话):重置图形格式,清除制表符,重置为默认字体等等。 |
由上表我们可以看到, 方向键是[ESC][
开头的, 也就是CSI序列, 这里描述方向键, 一方面是因为wmctf的pvz题目中, 为了完成自动化刷分脚本, 需要向服务器发送方向键, 所以当时就研究了一下, 当然, pvz的方向键并不是[ESC][
, 因为pvz程序是ncurses生成的界面, 不同于curses, 他的转义序列发生了改变. 另一方面, 主要还是引出颜色部分
24位颜色的ANSI
该题中, 多数wp均使用了nc xxxxxxxx > 1.txt重定向得到了类似[ESC][48;2;16;19;18m
(注意有空格)的字符串, 首先[ESC][
部分就是代表是CSI序列, 即 控制序列导入器(Control Sequence Introducer), 这里的48;2; 其实是固定格式:
ESC[ … 38;2;<r>;<g>;<b> … m
选择RGB前景色ESC[ … 48;2;<r>;<g>;<b> … m
选择RGB背景色
即这里是使用了RGB背景色, 又由于后面的[空格] 故导致了后面一位体现出了纯色像素块的特征, 而在题目中, 我们可以看到, 对于每行而言, 总会重复一次像素块, 这是因为在bash中, 空格的面积大概是 █ 这么大, 故重复后 ██ 更像方形( 虽然这里看起来不像), 看着好看(这句纯猜测
然后为了好玩, 写了一个从图片生成bash图片的python脚本
from PIL import Image
import sys
import subprocess
img = Image.open(sys.argv[1]).convert('RGB')
contents = '\x1b[48;2;{};{};{}m '
w, h = img.size
for y in range(h):
res = ''
for x in range(w):
r, g, b = img.getpixel((x, y))
res += contents.format(r, g, b)
subprocess.run(f'printf "{res}\n"', shell=True)
这里值得注意的是, linux中似乎只有printf才能进行ANSI转义, 而echo不行
效果图如下