C 堆栈,esp寄存器

C 堆栈,esp寄存器,c,assembly,C,Assembly,我从一本书上复制了这个代码。在每个注释中,我都会输入一个数字,然后向您询问与该数字注释的代码行相关的问题(1,2,3,4)。希望一切顺利 1) ESP指向这些缓冲区值。为什么我们不在这里看到“a”的0x41 2) ESP指向必须包含31337(十六进制为0x7a69)的标志变量内存。为什么它包含这个数字0xbffff89c 3) 指向上一个堆栈帧指针,在本例中,该指针包含正确的地址 4) 回信地址。也对 5) 争论。也可以修改值 那么在1)和2)中会发生什么?是填充物吗 非常感谢 void te

我从一本书上复制了这个代码。在每个注释中,我都会输入一个数字,然后向您询问与该数字注释的代码行相关的问题(1,2,3,4)。希望一切顺利

1) ESP指向这些缓冲区值。为什么我们不在这里看到“a”的0x41

2) ESP指向必须包含31337(十六进制为0x7a69)的标志变量内存。为什么它包含这个数字0xbffff89c

3) 指向上一个堆栈帧指针,在本例中,该指针包含正确的地址

4) 回信地址。也对

5) 争论。也可以修改值

那么在1)和2)中会发生什么?是填充物吗

非常感谢

void test_function(int a, int b, int c, int d) {
  int flag;
  char buffer[10];
  flag = 31337;
  buffer[0] = 'A';
}

int main() {
  test_function(1, 2, 3, 4);
}


GDB debug session
Breakpoint 2, test_function (a=1, b=2, c=3, d=4) at stack_example.c:5
5 flag = 31337;
(gdb) i r esp ebp eip
esp 0xbffff7c0 0xbffff7c0
ebp 0xbffff7e8 0xbffff7e8
eip 0x804834a 0x804834a <test_function+6>
(gdb) disass test_function
Dump of assembler code for function test_function:
0x08048344 <test_function+0>: push ebp
0x08048345 <test_function+1>: mov ebp,esp
0x08048347 <test_function+3>: sub esp,0x28
0x0804834a <test_function+6>: mov DWORD PTR [ebp-12],0x7a69
0x08048351 <test_function+13>: mov BYTE PTR [ebp-40],0x41
0x08048355 <test_function+17>: leave
0x08048356 <test_function+18>: ret
End of assembler dump.
(gdb) print $ebp-12
$1 = (void *) 0xbffff7dc
(gdb) print $ebp-40
$2 = (void *) 0xbffff7c0
  (gdb) x/16xw $esp  
    0xbffff7c0: 0x00000000 0x08049548 0xbffff7d8 0x08048249  // 1
    0xbffff7d0: 0xb7f9f729 0xb7fd6ff4 0xbffff808 0x080483b9  // 1 
    0xbffff7e0: 0xb7fd6ff4                                   // 1
    0xbffff89c                                               // 2
    0xbffff808                                               // 3
    0x0804838b                                               // 4
    0xbffff7f0:                                              // 4
    0x00000001 0x00000002 0x00000003 0x00000004              // 5




reader@hacking:~/booksrc $ gcc -g stack_example.c
reader@hacking:~/booksrc $ gdb -q ./a.out
Using host libthread_db library "/lib/tls/i686/cmov/libthread_db.so.1".
(gdb) disass main
Dump of assembler code for function main():
0x08048357 <main+0>: push ebp
0x08048358 <main+1>: mov ebp,esp
0x0804835a <main+3>: sub esp,0x18
0x0804835d <main+6>: and esp,0xfffffff0
0x08048360 <main+9>: mov eax,0x0
0x08048365 <main+14>: sub esp,eax
0x08048367 <main+16>: mov DWORD PTR [esp+12],0x4
0x0804836f <main+24>: mov DWORD PTR [esp+8],0x3
0x08048377 <main+32>: mov DWORD PTR [esp+4],0x2
0x0804837f <main+40>: mov DWORD PTR [esp],0x1
0x08048386 <main+47>: call 0x8048344 <test_function>
0x0804838b <main+52>: leave
0x0804838c <main+53>: ret
End of assembler dump
(gdb) disass test_function()
Dump of assembler code for function test_function:
0x08048344 <test_function+0>: push ebp
0x08048345 <test_function+1>: mov ebp,esp
0x08048347 <test_function+3>: sub esp,0x28
0x0804834a <test_function+6>: mov DWORD PTR [ebp-12],0x7a69
0x08048351 <test_function+13>: mov BYTE PTR [ebp-40],0x41
0x08048355 <test_function+17>: leave
0x08048356 <test_function+18>: ret
End of assembler dump
(gdb)
void test_函数(int a、int b、int c、int d){
int标志;
字符缓冲区[10];
flag=31337;
缓冲区[0]=“A”;
}
int main(){
测试_功能(1,2,3,4);
}
GDB调试会话
断点2,堆栈处的test函数(a=1,b=2,c=3,d=4)示例。c:5
5旗=31337;
(gdb)i r esp ebp eip
esp 0xbffff7c0 0xbffff7c0
ebp 0xbffff7e8 0xbffff7e8
eip 0x804834a 0x804834a
(gdb)disass测试功能
函数测试\函数的汇编程序代码转储:
0x08048344:推动ebp
0x08048345:mov ebp,esp
0x08048347:子esp,0x28
0x0804834a:mov DWORD PTR[ebp-12],0x7a69
0x08048351:mov字节PTR[ebp-40],0x41
0x08048355:离开
0x08048356:ret
汇编程序转储结束。
(gdb)打印$ebp-12
$1=(无效*)0xbffff7dc
(gdb)打印$ebp-40
$2=(无效*)0xbffff7c0
(gdb)x/16xw$esp
0xbffff7c0:0x00000000 0x08049548 0xbffff7d8 0x08048249//1
0xbffff7d0:0xb7f9f729 0xb7fd6ff4 0xbffff808 0x080483b9//1
0xbffff7e0:0xb7fd6ff4//1
0xbffff89c//2
0xbffff808//3
0x0804838b//4
0xbffff7f0://4
0x00000001 0x00000002 0x00000003 0x00000004//5
reader@hacking:~/booksrc$gcc-gstack\u example.c
reader@hacking:~/booksrc$gdb-q./a.out
使用主机libthread_db library“/lib/tls/i686/cmov/libthread_db.so.1”。
(gdb)disass main
函数main()的汇编程序代码转储:
0x08048357:推动ebp
0x08048358:mov ebp,esp
0x0804835a:子esp,0x18
0x0804835d:和esp,0xFFFFF0
0x08048360:mov eax,0x0
0x08048365:子esp,eax
0x08048367:mov DWORD PTR[esp+12],0x4
0x0804836f:mov DWORD PTR[esp+8],0x3
0x08048377:mov DWORD PTR[esp+4],0x2
0x0804837f:mov DWORD PTR[esp],0x1
0x08048386:调用0x8048344
0x0804838b:离开
0x0804838c:ret
汇编程序转储结束
(gdb)disass测试_函数()
函数测试\函数的汇编程序代码转储:
0x08048344:推动ebp
0x08048345:mov ebp,esp
0x08048347:子esp,0x28
0x0804834a:mov DWORD PTR[ebp-12],0x7a69
0x08048351:mov字节PTR[ebp-40],0x41
0x08048355:离开
0x08048356:ret
汇编程序转储结束
(gdb)

'A'
31337
是文字。它们没有理由被放在堆栈上

如果您打印出该代码块的反汇编,以便准确地查看编译器发出的内容,那么您会更感兴趣。然后,您可以在运行时交叉检查堆栈包含的内容

考虑到你的功能没有副作用,它可以被优化为无操作

以下是我在更熟悉的环境中使用您的代码得到的信息:

Breakpoint 1, test_function (a=1, b=2, c=3, d=4) at t.c:4
4     flag = 31337;
(gdb) disass test_function
Dump of assembler code for function test_function:
   0x080483a4 <+0>: push   %ebp
   0x080483a5 <+1>: mov    %esp,%ebp
   0x080483a7 <+3>: sub    $0x10,%esp
=> 0x080483aa <+6>: movl   $0x7a69,-0x4(%ebp)
   0x080483b1 <+13>:    movb   $0x41,-0xe(%ebp)
   0x080483b5 <+17>:    leave  
   0x080483b6 <+18>:    ret    
End of assembler dump.
(gdb) display $ebp
2: $ebp = (void *) 0xffffcd70
(gdb) display $esp
3: $esp = (void *) 0xffffcd60
(gdb) x/16xw $esp
0xffffcd60: 0xf7e7dcdd  0xf7fa7324  0xf7fa6ff4  0x00000000
0xffffcd70: 0xffffcd88  0x080483e1  0x00000001  0x00000002
0xffffcd80: 0x00000003  0x00000004  0xffffcdf8  0xf7e66cc6
0xffffcd90: 0x00000001  0xffffce24  0xffffce2c  0x00000001
现在让我们分配给
标志

(gdb) n
5     buffer[0] = 'A';
(gdb) x/8xw $esp
0xffffcd60: 0xf7e7dcdd  0xf7fa7324  0xf7fa6ff4  0x00007a69
0xffffcd70: 0xffffcd88  0x080483e1  0x00000001  0x00000002
(gdb)  x/1xw $ebp-4
0xffffcd6c: 0x00007a69
(gdb)  x/1xw $ebp-0xe
0xffffcd62: 0x7324f7e7
一切正常,右侧堆栈插槽已更新(
$ebp-4
x/8KW第1行中的最后32位插槽)

让我们设置
缓冲区的第一项:

(gdb) n
6   }
(gdb)  x/4x $ebp-0xe
0xffffcd62: 0x41    0xf7    0x24    0x73
(gdb) x/8xw $esp
0xffffcd60: 0xf741dcdd  0xf7fa7324  0xf7fa6ff4  0x00007a69
0xffffcd70: 0xffffcd88  0x080483e1  0x00000001  0x00000002
(gdb)  x/1xw $ebp-4
0xffffcd6c: 0x00007a69
(gdb)  x/1xw $ebp-0xe
0xffffcd62: 0x7324f741

一切又好了。当以32位整数查看时,endianness使事情看起来有点奇怪,但如果逐字节查看,它看起来很好。

'a'
31337
都是文本。它们没有理由被放在堆栈上

如果您打印出该代码块的反汇编,以便准确地查看编译器发出的内容,那么您会更感兴趣。然后,您可以在运行时交叉检查堆栈包含的内容

考虑到你的功能没有副作用,它可以被优化为无操作

以下是我在更熟悉的环境中使用您的代码得到的信息:

Breakpoint 1, test_function (a=1, b=2, c=3, d=4) at t.c:4
4     flag = 31337;
(gdb) disass test_function
Dump of assembler code for function test_function:
   0x080483a4 <+0>: push   %ebp
   0x080483a5 <+1>: mov    %esp,%ebp
   0x080483a7 <+3>: sub    $0x10,%esp
=> 0x080483aa <+6>: movl   $0x7a69,-0x4(%ebp)
   0x080483b1 <+13>:    movb   $0x41,-0xe(%ebp)
   0x080483b5 <+17>:    leave  
   0x080483b6 <+18>:    ret    
End of assembler dump.
(gdb) display $ebp
2: $ebp = (void *) 0xffffcd70
(gdb) display $esp
3: $esp = (void *) 0xffffcd60
(gdb) x/16xw $esp
0xffffcd60: 0xf7e7dcdd  0xf7fa7324  0xf7fa6ff4  0x00000000
0xffffcd70: 0xffffcd88  0x080483e1  0x00000001  0x00000002
0xffffcd80: 0x00000003  0x00000004  0xffffcdf8  0xf7e66cc6
0xffffcd90: 0x00000001  0xffffce24  0xffffce2c  0x00000001
现在让我们分配给
标志

(gdb) n
5     buffer[0] = 'A';
(gdb) x/8xw $esp
0xffffcd60: 0xf7e7dcdd  0xf7fa7324  0xf7fa6ff4  0x00007a69
0xffffcd70: 0xffffcd88  0x080483e1  0x00000001  0x00000002
(gdb)  x/1xw $ebp-4
0xffffcd6c: 0x00007a69
(gdb)  x/1xw $ebp-0xe
0xffffcd62: 0x7324f7e7
一切正常,右侧堆栈插槽已更新(
$ebp-4
x/8KW第1行中的最后32位插槽)

让我们设置
缓冲区的第一项:

(gdb) n
6   }
(gdb)  x/4x $ebp-0xe
0xffffcd62: 0x41    0xf7    0x24    0x73
(gdb) x/8xw $esp
0xffffcd60: 0xf741dcdd  0xf7fa7324  0xf7fa6ff4  0x00007a69
0xffffcd70: 0xffffcd88  0x080483e1  0x00000001  0x00000002
(gdb)  x/1xw $ebp-4
0xffffcd6c: 0x00007a69
(gdb)  x/1xw $ebp-0xe
0xffffcd62: 0x7324f741

一切又好了。endianness在作为32位整数查看时会让事情看起来有点奇怪,但如果逐字节查看,它看起来很好。

您到底在哪里中断了代码执行?如果没有编译的代码,很难说什么。编译器可以决定不存储
标志
缓冲区
,因为它们从不被读取。请包含对
test\u函数
main
的反汇编。您在哪里中断了代码执行?没有编译的代码,很难说什么。编译器可以决定不存储
标志
缓冲区
,因为它们从不被读取。请包含
test\u函数
main
的反汇编。抱歉,这个答案没有意义。我认为它有意义。
标志=31337行被编译为带有31337的立即操作数的
mov
。绝对没有理由在堆栈上看到这些常量。如果它们是字符串文字(并且没有被优化掉),它们可能会作为指向只读常量区域的指针出现在反汇编中。也不需要将它们放在堆栈上(除非编译器开始在缺少寄存器的机器上玩有趣的把戏)。没有相应汇编代码的堆栈内容基本上是无用的。谢谢你聪明的回答。然后,当作者说指向2)的堆栈包含0xbffff89c是内存标志时,他指的是堆栈中内存的文本?和0xbffff89c