shellcode原理
(相关资料图)
系统调用execve("/bin/sh", 0, 0)
具体可以参考系统调用表、64位linux中断向量表
64位
寄存器:
rax = 0x3brdi = "/bin/sh"rsi = 0rdx = 0
一段简单的 shellcode:
mov rax, 0x68732f6e69622fpush raxmov rdi, rspxor rsi, rsixor rdx, rdxpush 0x3bpop raxsyscall
32位
寄存器:
eax = 0xbebx = "/bin/sh"ecx = 0edx = 0
一段简单的 shellcode:
push 0x68732fpush 0x6e69622fmov ebx, espxor edx, edxxor eax, eaxint 0x80
shellcode编码技术
限制字符集的shellcode:
一般的可以直接用工具生成。
限制严格的需要进行手写
手写shellcode
思路一:
根据限制的字符集列出对应的可以使用的指令
对上面的 shellcode 进行修改
再转为对应的机器码
思路二(ALPHA3就是这么实现的):
创建一个能够满足字符集的解码器
根据解码器将shellcode编码成能够满足字符集
这里参考Writing IA32 Restricted Instruction Set Shellcode Decoder Loops讲讲思路二。
首先,考虑为什么要解码:过滤输入的一个普遍问题是编码数据中每个字节可以具有的可能值少于 256 个。但是必须假设原始数据可以包含所有 256 个可能的字节。 这意味着必须使用两个或更多字节来编码一个字节。
编码后的 shellcode 要在程序中运行需要附带解码器先进行解码,大概是下面的结构:
[decoder][encoded shellcodes]
接下来是解码器实现的一些细节问题。
解码器
解码器循环:
.-> | 1. 读取编码数据 (input)| L | 2. 解码| O | 3. 保存结果 (output)| O | 4. 移动到下一段数据| P | 5. 检查是否到达数据`--'| 6. 如果没到跳转至第1步V (decoding finished)
重定位
解码器需要知道编码过的shellcode在内存中的位置才能进行解码。由于 shellcode 是被插入到程序中的,而且一些程序还开启了随机化保护,并不确定 shellcode 的实际位置,因此解码器中 shellcode 的位置操作数不能写死,而需要动态计算。这可以利用重定位技术实现。
其中一种重定位技术实现方法是:
利用特殊指令call、fnstenv等动态获取当前指令的运行时地址
计算该地址与当前指令相对shellcode的偏移的差值(被称为delta offset)
将该差值加到对应数据与该指令相对偏移上,得到的就是运行时数据的正确地址
Patch
对编码器种和补丁中不符合要求的指令可以再编码以使其符合要求。
syscall绕过
不允许出现syscall 字符时(\x0f\x05)
一般会利用一个0x9090 ^ 0x959f=0x0f05, 如下:
xor word ptr[rip], 0x959fnopnop ;0x909
使用0偏移
使用偏移为0的操作数,表示的意义相同,但生成的机器码不同:
00 00 add %al, (%eax)00 40 00 add %al, 0(%eax)
FNSTENV XOR decoder
fnstenv指令将最后执行的一条FPU指令相关的协处理器的信息保存在指定的内存中,保存的信息偏移12字节处就是最后执行的浮点指令的运行时地址。
Copyright 2015-2022 财务报告网版权所有 备案号: 京ICP备12018864号-19 联系邮箱:29 13 23 6 @qq.com