文章目录
  1. 1. 用C语言写一个execve调用的demo
  2. 2. execve的汇编代码
  3. 3. 经过以上分析,可以得到如下的精简指令算法

用C语言写一个execve调用的demo

1
2
3
4
5
6
7
#include
void main(){
char *name[2];
name[0]="bin/sh"
name[1]=NULL;
execve(name[0],name,NULL);
}

execve函数将执行一个程序。他需要程序的名字地址作为第一个参数。一个内容为该程序的argvi的指针数组作为第二个参数,以及(char*) 0作为第三个参数.

execve的汇编代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
(gdb) disassemble __execve
  Dump of assembler code for function __execve:
  0x80002bc <__execve>: pushl %ebp ;
  0x80002bd <__execve+1>: movl %esp,%ebp
  ;上面是函数头。
  0x80002bf <__execve+3>: pushl %ebx
  ;保存ebx
  0x80002c0 <__execve+4>: movl $0xb,%eax
  ;eax=0xb,eax指明第几号系统调用。
  0x80002c5 <__execve+9>: movl 0x8(%ebp),%ebx
  ;ebp+8是第一个参数"/bin/sh\0"
  0x80002c8 <__execve+12>: movl 0xc(%ebp),%ecx
  ;ebp+12是第二个参数name数组的地址
  0x80002cb <__execve+15>: movl 0x10(%ebp),%edx
  ;ebp+16是第三个参数空指针的地址。
  ;name[2-1]内容为NULL,用来存放返回值。
  0x80002ce <__execve+18>: int $0x80
  ;执行0xb号系统调用(execve)
  0x80002d0 <__execve+20>: movl %eax,%edx
  ;下面是返回值的处理就没有用了。
  0x80002d2 <__execve+22>: testl %edx,%edx
  0x80002d4 <__execve+24>: jnl 0x80002e6 <__execve+42>
  0x80002d6 <__execve+26>: negl %edx
  0x80002d8 <__execve+28>: pushl %edx
  0x80002d9 <__execve+29>: call 0x8001a34
  <__normal_errno_location>
  0x80002de <__execve+34>: popl %edx
  0x80002df <__execve+35>: movl %edx,(%eax)
  0x80002e1 <__execve+37>: movl $0xffffffff,%eax
  0x80002e6 <__execve+42>: popl %ebx
  0x80002e7 <__execve+43>: movl %ebp,%esp
  0x80002e9 <__execve+45>: popl %ebp
  0x80002ea <__execve+46>: ret
  0x80002eb <__execve+47>: nop
  End of assembler dump.

经过以上分析,可以得到如下的精简指令算法

1
2
3
4
5
movl $execve的系统调用号,%eax
  movl "bin/sh\0"的地址,%ebx
  movl name数组的地址,%ecx
  movl name[n-1]的地址,%edx
  int $0x80 ;执行系统调用(execve)
文章目录
  1. 1. 用C语言写一个execve调用的demo
  2. 2. execve的汇编代码
  3. 3. 经过以上分析,可以得到如下的精简指令算法