gpt4 book ai didi

linux - Intel Assembly 中的键盘缓冲区

转载 作者:塔克拉玛干 更新时间:2023-11-03 00:39:34 25 4
gpt4 key购买 nike

我在管理 Intel Assembly 上的“键盘溢出”时遇到问题。主要问题是在读取了 read 调用指定的最大大小之后,剩余的数据被扔进了终端。我在 x64 架构上使用 Linux。这其实就是功课。我的主要想法如下:

%define maxChars     10
%define maxChars_2 100

section .bss
strLida : resb maxChars
strLidaL : resd 1

read:
mov dword [strLidaL], maxChars

mov rax, 0
mov rdi, 1
mov rsi, strLida
mov rdx, [strLidaL]
syscall

mov [strLidaL], rax

size_compare:
cmp [strLidaL], maxChars
jge overflow

overflow:
mov dword [strLidaL_2], maxChars_2

mov rax, 0
mov rdi, 1
mov rsi, strLida_2
mov rdx, [strLidaL_2]
syscall

这远不是一个好的解决方案,它会在达到最大字符数时跳转到另一个读取函数,以便它可以吞下剩余的溢出字符。有一个系统调用吗?有更好的解决方案吗?感谢您的输入。

最佳答案

您的解决方案一旦得到推广,就非常完美。

首先,考虑这个C程序

cook.c

#include <stdio.h>

int main()
{
char buffer[200];
scanf("%s", buffer);

return 0;
}

它很脆弱,return 是多余的,但请耐心等待。
该程序只是从输入中读取一个字符串,与您的输入非常相似。

如果您键入一个短字符串,例如 hello world scanf 会将 hello 读入 buffer world 不会出现在终端中(与您的程序不同)。那么 scanf 是如何做到这一点的呢?

无需逆向工程(或获取源代码)即可分析程序的简便方法是 strace .
如果我在我的系统中运行 strace ./cook 我可以看到 cook 执行 sys_read 系统调用 as

read(0, "hello world\n", 1024)          = 12

因此,scanf 只是读取,在这种情况下,以 1024 字节的 block 为单位。
我不知道 libc 用来设置读取长度的逻辑,因为我认为它在这里不相关,所以我不会深入研究它。

如果我们输入超过 1024 个字符怎么办?
如果我输入 1 2 3 4 ... 1024(即所有 1024 以内的数字用空格分隔)并按下结果是

manager@debian64-jboss:~$ ./cook
1 2 3 4 5 [... omitted]
manager@debian64-jboss:~$ 284 285 286 287 288 289 290 [... omitted]

显示部分输入进入终端提示符。
如果我们进行数学计算,我们将得到预期的 9*2 + 90*3 + 184 * 4 = 1024。

长话短说:您并没有真正遇到问题 - 这是 Linux 下的预期行为。
在你的情况下,它更烦人,因为你读取的字节数很少。
长话短说the input processing mode: canonical or non-canonical .
默认的是 canonical,其中操作系统缓冲文本行以提供输入编辑功能。

如果您的程序要求 5 个字节并且用户键入 hello world 并按下回车键,操作系统将缓冲整个“hello world\n”字符串,但 sys_read 将读取只到空格,为下一个读者(shell)留下“world\n”。

您可以选择修复或缓解此问题。

读取更大的尺寸可以缓解这个问题——就像 C 的例子。由于您应该始终检查函数或系统调用的返回值,因此这不会对您的程序布局产生重大影响。

或者,您可以遵循 comp.lang.c 的建议并读取所有输入。
在汇编中,你可以用一般的方式做到这一点

 ;edi = file descriptor
emptyfd:
lea rsi, [rsp-80h] ;We use the redzone for the read buffer
mov edx, 80h ;Chunk length

.read_chunk:
xor eax, eax ;sys_read
syscall

;We read all the buffer? (Note: this also check for errors as long as rdx != -1)
cmp rdx, rax
je .read_chunk

ret

当心被破坏的寄存器。

我不知道有任何系统调用这样做,但我不希望有任何系统调用 - 标准输入对内核没有特殊意义。


作为旁注,将寄存器清零的一个好方法是 xoring it with itself .
此外,移动或对 64 位寄存器的低 32 位部分执行操作会将高 32 位归零 - 因此 mov rdi, 1 可以写为 mov edi, 1.
无论如何,NASM 都会将前者隐式转换为后者。

关于linux - Intel Assembly 中的键盘缓冲区,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44297833/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com