汇编指令移位有什么作用?

What Does Assembly Instruction Shift Do?

我遇到了一个很有趣的 article 演示了如何从 shellcode 中删除空字节字符。在使用的技术中,汇编指令 shlshr 似乎在代码中占据了相当重要的作用。

我意识到汇编指令 mov [=13=]x3b, %raxmov , %rax 实际上都生成了机器码指令 48 c7 c0 3b 00 00 00。因此,为了解决这个问题,作者改为使用 mov [=16=]x1111113b, %rax 用系统调用号填充寄存器,而不是生成机器代码 48 c7 c0 3b 11 11 11,从而成功删除空字节。

不幸的是,代码仍然没有执行,因为系统调用将 3b 11 11 11 视为非法指令,或者这会导致代码出现段错误。所以作者随后所做的就是使用命令

来回移动 %rax 56 个字节
shl [=10=]x38, %rax 
shr [=10=]x38, %rax

这次转变后,代码完美执行。我想知道的是移位指令如何解决 48 c7 c0 3b 11 11 11 问题,并以某种方式使 %rax 正确且可系统调用。我知道 shl/shr 向左和向右移动位,这意味着向左移动将位向上移动到更高的位,向右移动使它们再次降低,因为二进制是从右到左读取的。但是,这到底是如何改变代码并使其可执行的呢?来回移动本质上不会改变任何东西,将移位的位准确地放回它们开始时的位置吗?

我唯一的理论是移开位会留下零。但我仍然看不出如何将 %rax 向前移动然后向后移动来修复解决方案,因为它不会带回 11 11 11 部分吗?

无论如何,我认为这很有趣,因为我在今天之前从未见过移位操作数。提前致谢。

移位是一种有损操作 - 如果位被移出寄存器,它们就会消失。 (有时其中之一存储在进位标志中,但这在这里并不重要。)参见 http://en.wikibooks.org/wiki/X86_Assembly/Shift_and_Rotate#Logical_Shift_Instructions .

左移 (shl) 操作执行此操作:

0x000000001111113b << 0x38 = 0x3b00000000000000

0x111111 部分会占用位 64、65、66 等,但 %rax 是一个 64 位寄存器,所以这些位消失了。然后,逻辑右移 (shr) 操作执行此操作:

0x3b00000000000000 >> 0x38 = 0x000000000000003b

给你你想要的号码。仅此而已。