Reputation: 533
I'm trying to write a 64-bit shellcode to read a file called '/proc/flag'. However, I'm getting some random errors when I'm compiling the assembly and don't know why its occuring.
This is my assembly file readflag.S
:
.intel_syntax noprefix
.global _start
.type _start, @function
_start:
mov dword [rsp], '/pro' /* build filename on stack */
mov dword [rsp+4], 'c/fl'
push 'ag'
pop rcx
mov [rsp+8], ecx
lea rdi, [rsp] /* rdi now points to filename '/proc/flag' */
xor rsi, rsi /* rsi contains O_RDONLY, the mode with which we'll open the file */
xor rax, rax
inc rax
inc rax /* syscall open = 2 */
syscall
mov rbx, rax /* filehandle of opened file */
lea rsi, [rsp] /* rsi is the buffer to which we'll read the file */
mov rdi, rbx /* rbx was the filehandle */
push byte 0x7f /* read 127 bytes. if we stay below this value, the generated opcode will not contain null bytes */
pop rdx
xor rax, rax /* syscall read = 0 */
syscall
lea rsi, [rsp] /* the contents of the file were on the stack */
xor rdi, rdi
inc rdi /* filehandle; stdout! */
mov rdx, rax /* sys_read() returns number of bytes read in rax, so we move it to rdx */
xor rax, rax
inc rax
syscall /* syscall write = 1 */
push byte 60 /* some bytes left... */
pop rax /* exit cleanly */
syscall
These are the errors I'm getting when I compile the assembly:
readflag.S: Assembler messages:
readflag.S:7: Error: junk `pro10mov dword [rsp+4]' after expression
readflag.S:21: Error: junk `0x7f' after expression
readflag.S:33: Error: junk `60' after expression
objcopy: 'readflag.o': No such file
I thought push byte 60
was considered a valid instruction in Intel syntax. I'm not sure where the errors are coming from. Would appreciate any help.
Upvotes: 2
Views: 2741
Reputation: 1
This is wrong syntax for GAS. You have to use movl '/pro', [rsp] ALso, use **$**xx for moving actual value xx into a location. Refer to the full syntax here.
https://en.wikibooks.org/wiki/X86_Assembly/GAS_Syntax
Upvotes: -1
Reputation: 244812
When you specify the .intel_syntax noprefix
option, you instruct the Gnu assembler that you will be using MASM syntax. What you've written is actually NASM syntax, which is similar to MASM syntax in many ways, but subtly different in others.
For a complete discussion of the differences, see this section of the NASM manual.
For a quick overview of NASM vs. MASM syntax, refer to this document.
(This second document used to be hosted online, in a more readable HTML format, here, but the link has gone down and I unfortunately can't find a copy in the Wayback Machine.)
The big thing that needs to change in your code is that you need to include the PTR
directive after each of the size specifiers. So, for example, instead of:
mov dword [rsp], '/pro'
mov dword [rsp+4], 'c/fl'
you need to write:
mov dword ptr [rsp], '/pro'
mov dword ptr [rsp+4], 'c/fl'
Also, while MASM syntax would normally write hexadecimal constants with a trailing h
, instead of the leading 0x
, Gas's "MASM" mode doesn't support this, and you need to use the C-style 0x
notation, even when using Intel syntax.
I thought
push byte 60
was considered a valid instruction in Intel syntax.
No, not really. The only size values you can PUSH
and POP
from the stack are the processor's native register width. So, in 32-bit binaries, you must push and pop 32-bit values, whereas in 64-bit binaries, you must push and pop 64-bit values.* That means these lines of code are technically wrong:
push 'ag'
push byte ptr 0x7f
push byte ptr 60
MASM will give you a warning about an invalid operand size for the latter two instructions that have a size explicitly specified, but it will implicitly extend these constants to be 64-bit values and still assemble successfully. I assume the Gnu assembler can do this automatic value-extension, too, so you should just drop the size directive:
push 'ag'
push 0x7f
push 60
__
* Technically, you can use an operand size override prefix to allow you to push a 16-bit immediate onto the stack, both in 32-bit and 64-bit mode. But you really shouldn't ever do that because it misaligns the stack, creating performance problems (and, if you're interoperating with code compiled in other languages, breaks the ABI). Only push 16-bit values onto the stack when writing 16-bit code. If you want to push a 16-bit value in 32-bit or 64-bit mode, just let the assembler extend it to 32-bit or 64-bit, accordingly.
Upvotes: 4