为什么我无法在自修改代码中单步执行 aeskeygenassist 指令?

Why I cannot single stepping into aeskeygenassist instruction in self-modifying code?

我尝试用汇编语言实现aes128加密,我的最终目标是找出最终值。调试时(使用单步执行),调试器停在 0x8048074 地址。

这里是代码:

global _start
section .text

_start:

pxor    xmm2, xmm2
pxor    xmm3, xmm3
mov     bx, 0x36e5
mov     ah, 0x73

roundloop:
shr     ax, 7
div     bl
mov     byte [sdfsdf+5], ah

sdfsdf:
aeskeygenassist xmm1, xmm0, 0x45
pshufd  xmm1, xmm1, 0xff

shuffle:
shufps  xmm2, xmm0, 0x10
pxor    xmm0, xmm2
xor     byte [shuffle+3], 0x9c
js      short shuffle

pxor    xmm0, xmm1
cmp     ah, bh
jz      short lastround

aesenc  xmm3, xmm0
jmp     short roundloop

lastround:
aesenclast xmm3, xmm0
ret

调试器卡在这里,我无法single-stepping0x804807a

[-------------------------------------code-------------------------------------]
   0x804806c <_start+12>:       mov    ah,0x73
   0x804806e <roundloop>:       shr    ax,0x7
   0x8048072 <roundloop+4>:     div    bl
=> 0x8048074 <roundloop+6>:     mov    BYTE PTR ds:0x804807f,ah
   0x804807a <sdfsdf>:  aeskeygenassist xmm1,xmm0,0x45
   0x8048080 <sdfsdf+6>:        pshufd xmm1,xmm1,0xff
   0x8048085 <shuffle>: shufps xmm2,xmm0,0x10
   0x8048089 <shuffle+4>:       pxor   xmm0,xmm2

我正在为 GDB 使用 peda 插件。

编辑:

抱歉,我没有提到错误信息,错误信息是 Segmentation fault 在这个指令 mov BYTE PTR ds:0x804807f,ah

我假设您忘记了 link 和 --omagic 以使 .text 部分可写。


所以mov BYTE PTR ds:0x804807f,ah段错误,aeskeygenassist之前。你不能在你的程序崩溃后继续单步执行。 (您没有 SIGSEGV 的处理程序,默认操作是终止您的程序)。

当我出于好奇在我的桌面上尝试这个时,我可以想象将行为解释为单步执行 "stuck" 在 aeskeygenassist 之前,如果我忽略段错误消息!!!并且再次尝试说 "the program is no longer running".

来自 GDB 会话:

(gdb) layout reg
(gdb) starti          # like run with an implicit breakpoint on the first instruction
(gdb) si
0x0000000000401004 in _start ()
0x0000000000401008 in _start ()     ## I kept pressing return to repeat the command
0x000000000040100c in _start ()
0x000000000040100e in roundloop ()
0x0000000000401012 in roundloop ()
0x0000000000401014 in roundloop ()    # the MOV store

Program received signal SIGSEGV, Segmentation fault.
0x0000000000401014 in roundloop ()    # still pointing at the MOV store

注意 RIP 仍然指向 mov0x8048074 在你的 32 位版本中,0x401014 在我相同来源的 64 位版本中。


来自 ld 手册:

-N
--omagic
Set the text and data sections to be readable and writable. Also, do not page-align the data segment, and disable linking against shared libraries. If the output format supports Unix style magic numbers, mark the output as "OMAGIC". Note: Although a writable text section is allowed for PE-COFF targets, it does not conform to the format specification published by Microsoft.

如果我 link 使用:

,你的代码对我来说工作正常
  nasm -felf64 aes.asm &&
  ld --omagic aes.o -o aes

或者,您可以进行 mprotect 系统调用以提供包含此代码的页面 PROT_READ|PROT_WRITE|PROT_EXEC

GDB 的 layout reg 反汇编 window 甚至在 aeskeygenassist 的立即数被存储修改后更新反汇编。


另请注意,自修改代码 (SMC) 在现代 x86 上 极其 缓慢。完整 pipeline nuke after every store near instructions being executed。使用汇编宏展开会更好。

此外,您不能从 _start 到 Linux 下 ret;这不是一个功能。堆栈指针指向 argc,而不是 return 地址。 使用 int 0x80 对 32 位代码进行 _exit 系统调用。当我说 "works" 时,我的意思是它到达 ret 并且在将 argc 弹出到 RIP 后从地址 1 获取代码时出现段错误。

此外,使用 default rel 用于存储的 RIP 相对寻址;它更紧凑。或者我猜你出于某种原因正在根据你的代码地址构建一个 32 位可执行文件。起初我没有注意到,这就是我测试 64 位可执行文件的原因。幸运的是你正确地使用了标签,并且 aeskeygenassist 在两种模式下的长度相同,所以它仍然有效。