修改被調試程序的二進制文件

例子

#include <stdio.h>
#include <stdlib.h>

void drawing (int n)
{
  if (n != 0)
    puts ("Try again?\nAll you need is a dollar, and a dream.");
  else
    puts ("You win $3000!");
}

int main (void)
{
  int n;

  srand (time (0));
  n = rand () % 10;
  printf ("Your number is %d\n", n);
  drawing (n);

  return 0;
}

技巧

gdb不僅可以用來調試程序,還可以修改程序的二進制代碼。

缺省情況下,gdb是以只讀方式加載程序的。可以通過命令行選項指定為可寫:

$ gcc -write ./a.out
(gdb) show write
Writing into executable and core files is on.

也可以在gdb中,使用命令設置並重新加載程序:

(gdb) set write on
(gdb) file ./a.out

接下來,查看反彙編:

(gdb) disassemble /mr drawing 
Dump of assembler code for function drawing:
5	{
   0x0000000000400642 <+0>:	55	push   %rbp
   0x0000000000400643 <+1>:	48 89 e5	mov    %rsp,%rbp
   0x0000000000400646 <+4>:	48 83 ec 10	sub    $0x10,%rsp
   0x000000000040064a <+8>:	89 7d fc	mov    %edi,-0x4(%rbp)

6	  if (n != 0)
   0x000000000040064d <+11>:	83 7d fc 00	cmpl   $0x0,-0x4(%rbp)
   0x0000000000400651 <+15>:	74 0c	je     0x40065f <drawing+29>

7	    puts ("Try again?\nAll you need is a dollar, and a dream.");
   0x0000000000400653 <+17>:	bf e0 07 40 00	mov    $0x4007e0,%edi
   0x0000000000400658 <+22>:	e8 b3 fe ff ff	callq  0x400510 <puts@plt>
   0x000000000040065d <+27>:	eb 0a	jmp    0x400669 <drawing+39>

8	  else
9	    puts ("You win $3000!");
   0x000000000040065f <+29>:	bf 12 08 40 00	mov    $0x400812,%edi
   0x0000000000400664 <+34>:	e8 a7 fe ff ff	callq  0x400510 <puts@plt>

10	}
   0x0000000000400669 <+39>:	c9	leaveq 
   0x000000000040066a <+40>:	c3	retq   

End of assembler dump.

修改二進制代碼(注意大小端和指令長度):

(gdb) set variable *(short*)0x400651=0x0ceb
(gdb) disassemble /mr drawing 
Dump of assembler code for function drawing:
5	{
   0x0000000000400642 <+0>:	55	push   %rbp
   0x0000000000400643 <+1>:	48 89 e5	mov    %rsp,%rbp
   0x0000000000400646 <+4>:	48 83 ec 10	sub    $0x10,%rsp
   0x000000000040064a <+8>:	89 7d fc	mov    %edi,-0x4(%rbp)

6	  if (n != 0)
   0x000000000040064d <+11>:	83 7d fc 00	cmpl   $0x0,-0x4(%rbp)
   0x0000000000400651 <+15>:	eb 0c	jmp    0x40065f <drawing+29>

7	    puts ("Try again?\nAll you need is a dollar, and a dream.");
   0x0000000000400653 <+17>:	bf e0 07 40 00	mov    $0x4007e0,%edi
   0x0000000000400658 <+22>:	e8 b3 fe ff ff	callq  0x400510 <puts@plt>
   0x000000000040065d <+27>:	eb 0a	jmp    0x400669 <drawing+39>

8	  else
9	    puts ("You win $3000!");
   0x000000000040065f <+29>:	bf 12 08 40 00	mov    $0x400812,%edi
   0x0000000000400664 <+34>:	e8 a7 fe ff ff	callq  0x400510 <puts@plt>

10	}
   0x0000000000400669 <+39>:	c9	leaveq 
   0x000000000040066a <+40>:	c3	retq   

End of assembler dump.

可以看到,條件跳轉指令“je”已經被改為無條件跳轉“jmp”了。

退出,運行一下:

$ ./a.out 
Your number is 2
You win $3000!

詳情參見gdb手冊

貢獻者

xmj


书籍推荐