My problem is related with Assembler and Shellcoding.
I started off by writing my first shellcode and it worked out pretty well so far. I then made an assembly script of the following C code:
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
int main()
{
int fd = open("test.txt", O_CREAT | O_WRONLY);
write(fd, "Hello World!", 6);
return 0;
}
The assembly code for that piece looks like this:
global _start
_start:
xor eax, eax ; null eax reg
push 0x7478742e ; push "test.txt" on stack
push 0x74736574
mov ebx, esp ; first Argument
mov cl, 0x41 ; Flags O_CREAT | O_WRONLY
mov al, 0x5 ; sys_open
int 0x80
push 0x736b6330 ; "shellcodingr0cks"
push 0x72676e69
push 0x646f636c
push 0x6c656853
mov ebx, eax ; file identifier
mov ecx, esp ; string on the stack
mov dl, 0x10 ; 0x10 is the size of the string
mov al, 0x4 ; sys_write
int 0x80
xor eax, eax ; exit proc
inc eax
int 0x80
The Program works pretty well and I've got the expected output but there is one problem and I don't know why this is occurring.
The filename of the file I'm writing to should be test.txt but it is writing to test.txt^A. I don't know where the ^A is coming from, nor do I know how to fix it.
Does anyone know what is wrong, and how I can fix it?
Related
Hello all.
So I'm learning assembly.And as per my usual learning steps with any new language I pick up I've arrived at networking with assembly.
Which, sadly isn't going that well as I've pretty much failed at step 0, which would be getting a socket through which communication can begin.
The assembly code should be roughly equal to the following C code:
#include <stdio.h>
#include <sys/socket.h>
int main(){
int sock;
sock = socket(AF_INET, SOCK_STREAM, 0);
}
(Let's ignore the fact that it's not closing the socket for now.)
So here's what I did thus far:
Checked the manual. Which would imply that I need to make a socketcall() this is all good and well. The problem starts with that it would need an int that describes what sort of socketcall it should make. The calls manpage isn't helping much with this either as it only describes that:
On a some architectures—for example, x86-64 and ARM—there is no
socketcall() system call; instead socket(2), accept(2), bind(2), and
so on really are implemented as separate system calls.
Yet there are no such calls in the original list of syscalls - and as far as I know the socket(), accept(), bind(), listen(), etc. are calls from libnet and not from the kernel. This got me utterly confused so I've decided to compile the above C code and check up on it with strace. This yielded the following:
socket(PF_INET, SOCK_STREAM, IPPROTO_IP) = 3
While that didn't got me any closer to knowing what socket() is it did explain it's arguments. For witch I don't seem to find the proper documentation (again). I thought that PF_INET, SOCK_STREAM, IPPROTO_IP would be defined in <sys/socket.h> but my grep-ing for them didn't seem to find anything of use. So I decided to just wing it by using gdb in tandem with disass main to find the values. This gave the following output:
Dump of assembler code for function main:
0x00000000004004fd <+0>: push rbp
0x00000000004004fe <+1>: mov rbp,rsp
0x0000000000400501 <+4>: sub rsp,0x10
0x0000000000400505 <+8>: mov edx,0x0
0x000000000040050a <+13>: mov esi,0x1
0x000000000040050f <+18>: mov edi,0x2
0x0000000000400514 <+23>: call 0x400400
0x0000000000400519 <+28>: mov DWORD PTR [rbp-0x4],eax
0x000000000040051c <+31>: leave
0x000000000040051d <+32>: ret
End of assembler dump.
In my experience this would imply that socket() gets it's parameters from EDX (PF_INET), ESI (SOCK_STREAM), and EDI (IPPROTO_IP). Which would be odd for a syscall (as the convention with linux syscalls would be to use EAX/RAX for the call number and other registers for the parameters in increasing order, eg. RBX, RCX, RDX ...). The fact that this is beaing CALL-ed and not INT 0x80'd would also imply that this is not in fact a system call but rather something thats being called from a shared object. Or something.
But then again. Passing arguments in registers is very odd for something that's CALL-ed. Normally as far as I know argument's for called things should be PUSH-ed onto the stack, as the compiler can't know what registers they would try to use.
This behavior becomes even more curious when checking the produced binary with ldd:
linux-vdso.so.1 (0x00007fff4a7fc000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f56b0c61000)
/lib64/ld-linux-x86-64.so.2 (0x00007f56b1037000)
There appears to be no networking library's linked.
And that's the point where I've ran out of ideas.
So I'm asking for the following:
A documentation that describes the x86-64 linux kernel's actual syscalls and their associated numbers. (Preferably as a header file for C.)
The header files that define PF_INET, SOCK_STREAM, IPPROTO_IP as it really bugs me that I wasn't able to find them on my own system.
Maybe a tutorial for networking in assembly on x86-64 linux. (For x86-32 it's easy to find material but for some reason I came up empty with the 64 bits stuff.)
Thanks!
The 64 bit calling convention does use registers to pass arguments, both in user space and to system calls. As you have seen, the user space convention is rdi,rsi, rdx, rcx, r8, r9. For system calls, r10 is used instead of rcx which is clobbered by the syscall instruction. See wikipedia or the ABI documentation for more details.
The definitions of the various constants are hidden in header files, which are nevertheless easily found via a file system search assuming you have the necessary development packages installed. You should look in /usr/include/x86_64-linux-gnu/bits/socket.h and /usr/include/linux/in.h.
As for a system call list, it's trivial to google one, such as this. You can also always look in the kernel source of course.
socket.asm
; Socket
; Compile with: nasm -f elf socket.asm
; Link with (64 bit systems require elf_i386 option): ld -m elf_i386 socket.o -o socket
; Run with: ./socket
%include 'functions.asm'
SECTION .text
global _start
_start:
xor eax, eax ; init eax 0
xor ebx, ebx ; init ebx 0
xor edi, edi ; init edi 0
xor esi, esi ; init esi 0
_socket:
push byte 6 ; push 6 onto the stack (IPPROTO_TCP)
push byte 1 ; push 1 onto the stack (SOCK_STREAM)
push byte 2 ; push 2 onto the stack (PF_INET)
mov ecx, esp ; move address of arguments into ecx
mov ebx, 1 ; invoke subroutine SOCKET (1)
mov eax, 102 ; invoke SYS_SOCKETCALL (kernel opcode 102)
int 80h ; call the kernel
call iprintLF ; call our integer printing function (print the file descriptor in EAX or -1 on error)
_exit:
call quit ; call our quit function
more docs...
this is for x86 system. if you want use for x86_64 system change x86 register to x86_64. for example change 'eax' to 'rax' or 'esp' to 'rsp'. and change syscall value in eax(rax), see https://chromium.googlesource.com/chromiumos/docs/+/master/constants/syscalls.md
[bits 32]
global _start
section .data
msg: db "Socket Failed To Create!",0xa,0
len: equ $-msg
msg1: db "Socket Created",0xa,0
len1: equ $-msg1
msg2: db "Recv Or Send Failed",0xa,0
len2: equ $-msg2
msg3: db "Shutdown Socket Failed",0xa,0
len3: equ $-msg3
DATASIZE: equ 5
SOCK_STREAM: equ 1
AF_INET: equ 2
AF_INET: equ 2
INADDR_ANY: equ 0
MSG_WAITALL: equ 0x100
MSG_DONTWAIT: equ 0x40
SHUT_RDWR: equ 2
SYS_SOCKET: equ 1 ; sys_socket(2)
SYS_BIND: equ 2 ; sys_bind(2)
SYS_CONNECT: equ 3 ; sys_connect(2)
SYS_LISTEN: equ 4 ; sys_listen(2)
SYS_ACCEPT: equ 5 ; sys_accept(2)
SYS_GETSOCKNAME:equ 6 ; sys_getsockname(2)
SYS_GETPEERNAME:equ 7 ; sys_getpeername(2)
SYS_SOCKETPAIR: equ 8 ; sys_socketpair(2)
SYS_SEND: equ 9 ; sys_send(2)
SYS_RECV: equ 10 ; sys_recv(2)
SYS_SENDTO: equ 11 ; sys_sendto(2)
SYS_RECVFROM: equ 12 ; sys_recvfrom(2)
SYS_SHUTDOWN: equ 13 ; sys_shutdown(2)
SYS_SETSOCKOPT: equ 14 ; sys_setsockopt(2)
SYS_GETSOCKOPT: equ 15 ; sys_getsockopt(2)
SYS_SENDMSG: equ 16 ; sys_sendmsg(2)
SYS_RECVMSG: equ 17 ; sys_recvmsg(2)
SYS_ACCEPT4: equ 18 ; sys_accept4(2)
SYS_RECVMMSG: equ 19 ; sys_recvmmsg(2)
SYS_SENDMMSG: equ 20 ; sys_sendmmsg(2)
struc sockaddr_in, -0x30
.sin_family: resb 2 ;2bytes
.sin_port: resb 2 ;2bytes
.sin_addr: resb 4 ;4bytes
.sin_zero: resb 8 ;8bytes
endstruc
struc socket, -0x40
.socketfd resb 4
.connectionfd resb 4
.count resb 4
.data resb DATASIZE
endstruc
section .text
_start:
push ebp
mov ebp, esp
sub esp, 0x400 ;1024byte
xor edx, edx ;or use cdq
;
; int socket(int domain, int type, int protocol);
; domain: The domain argument specifies a communication domain
;
push edx ; Push protocol
push dword SOCK_STREAM ; Push type
push dword AF_INET ; Push domain
mov ecx, esp ; ECX points to args
mov ebx, SYS_SOCKET ;
mov eax, 0x66 ; socketcall()
int 0x80
cmp eax, 0
jl .socket_failed
mov [ebp + socket.socketfd], eax
;
; fill struct sockaddr_in serv_addr;
;
mov word [ebp + sockaddr_in.sin_family], AF_INET
mov word [ebp + sockaddr_in.sin_port], 0x3905
mov dword [ebp + sockaddr_in.sin_addr], INADDR_ANY
push dword [ebp + sockaddr_in.sin_addr]
push word [ebp + sockaddr_in.sin_port]
push word [ebp + sockaddr_in.sin_family]
mov ecx, esp
;
; int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
;
push byte 0x10 ; sizeof(struct sockaddr)
push ecx ; pointer struct sockaddr
push dword [ebp + socket.socketfd]
mov ecx, esp ; ECX points to args
mov ebx, SYS_BIND ;
mov eax, 0x66
int 0x80
cmp eax, 0
jne .socket_failed
;
; int listen(int sockfd, int backlog);
;
push dword 0x10
push dword [ebp + socket.socketfd]
mov ecx, esp
mov ebx, SYS_LISTEN
mov eax, 0x66
int 0x80
cmp eax, 0
jne .socket_failed
;
; int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
;
xor ebx, ebx
push ebx
push ebx
push dword [ebp + socket.socketfd]
mov ecx, esp
mov ebx, SYS_ACCEPT
mov eax, 0x66
int 0x80
cmp eax, -1
je .socket_failed
mov [ebp + socket.connectionfd], eax
mov dword [ebp + socket.count], 0
.again:
lea edi, [ebp + socket.data]
mov ecx, DATASIZE
mov eax, 0
rep stosd
lea eax, [ebp + socket.data]
;
; ssize_t recv(int sockfd, const void *buf, size_t len, int flags);
;
push dword MSG_WAITALL
push dword DATASIZE
push eax
push dword [ebp + socket.connectionfd]
mov ecx, esp
mov ebx, SYS_RECV
mov eax, 0x66
int 0x80
cmp eax, 0
jle .recv_or_send_failed
mov edx, eax
lea ecx, [ebp + socket.data]
call printk
inc dword [ebp + socket.count]
cmp dword [ebp + socket.count], 5
jle .again
.break:
;
; int shutdown(int sockfd, int how);
;
push dword SHUT_RDWR
push dword [ebp + socket.socketfd]
mov ecx, esp
mov ebx, SYS_SHUTDOWN
mov eax, 0x66
int 0x80
cmp eax, 0
jne .shutdown_failed
;
; int close(int fd)
;
mov ebx, [ebp + socket.connectionfd]
mov eax, 0x06
int 0x80
cmp eax, 0
jne .shutdown_failed
jmp .success
.shutdown_failed:
mov edx, len3
mov ecx, msg3
call printk
jmp .end
.recv_or_send_failed:
mov edx, len2
mov ecx, msg2
call printk
jmp .end
.socket_failed:
mov edx, len
mov ecx, msg
call printk
jmp .end
.success:
mov edx, len1
mov ecx, msg1
call printk
jmp .end
.end:
leave
mov ebx,0 ;first syscall argument: exit code
mov eax,1 ;system call number (sys_exit)
int 0x80 ;call kernel
ret
; EDX: message length
; ECX: pointer to message to write
printk:
pusha
mov ebx,1 ;first argument: file handle (stdout)
mov eax,4 ;system call number (sys_write)
int 0x80 ;call kernel
popa
ret
I found the list of syscalls for x86-64 mode (with arguments):
http://filippo.io/linux-syscall-table/
but where can I get detailed description of this syscalls?
For example below, which flags can be used for 'open' syscall except 0102o (rw, create), in other cases:
read only, write only, etc.
SECTION .data
message: db 'Hello, world!',0x0a
length: equ $-message
fname db "result"
fd dq 0
SECTION .text
global _start
_start:
mov rax, 2 ; 'open' syscall
mov rdi, fname ; file name
mov rsi, 0102o ; read and write mode, create if not
mov rdx, 0666o ; permissions set
syscall
mov [fd], rax
mov rax, 1 ; 'write' syscall
mov rdi, [fd] ; file descriptor
mov rsi, message ; message address
mov rdx, length ; message string length
syscall
mov rax, 3 ; 'close' syscall
mov rdi, [fd] ; file descriptor
syscall
mov rax, 60
mov rdi, 0
syscall
Based on source (may be)
https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/fs/open.c
how to understand it, which (list of all for open) flags can be used?
The documentation for the syscalls is in section 2 of the man pages and/or in the comments in the source code.
The man page begins with:
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int open(const char *pathname, int flags);
int open(const char *pathname, int flags, mode_t mode);
The argument flags must include one of the following access modes: O_RDONLY, O_WRONLY, or O_RDWR. These request opening the file read-only, write-only, or read/write, respectively.
In addition, zero or more file creation flags and file status flags can be bitwise-or'd in flags. The file creation flags are O_CREAT, O_EXCL, O_NOCTTY, and O_TRUNC.
The values for these are trivially looked up in the system header files.
I found here some topics about converting value to ascii. But I am a bit stuck here.
Here's my code:
;GetPID
SECTION .data
msg: db "Your PID is:" ;pidmsg
msgl: equ $-msg ;pidlen
lookup: db "0123456789"
SECTION .bss
pid: resb 8 ;test is a variable im testing to
;receive the eax from sys_getpid
SECTION .text
global _start
_start:
call getpid ;get pid number into eax
mov ebx,0xa
lea ebp, [pid+6]
call ASCIIC
jmp exit ;exit
exit:
mov eax,1
mov ebx,0
int 0x80
getpid:
mov eax,20 ;getpid function (sys_getpid)
int 0x80
ret
;ASCIIC was taken from http://theropfather.github.io/asm/getpid_tutorial.html
ASCIIC:
div ebx ;Divide the PID
mov byte cl, [lookup+edx] ;Copy ASCII value to CL
mov [ebp], cl ;Copy ASCII value to buffer
dec ebp ;Next byte into buffer
xor edx, edx ;Clear the remainder
inc eax ;Dec eax tricking jnz
dec eax ;Push back to original value
jnz ASCIIC ;Keep looping until eax is zero
call .printPID ;Print out the buffer
ret
.printPID:
mov ecx, msg ;message
mov edx, msgl ;msg len
mov ebx,0x1 ;FD stdout
mov eax, 0x4 ;sys_write call
int 0x80 ;Call
mov [pid+7], byte 0xA ;Push a newline to PID string
mov edx,0x8 ;Max length of 8 bytes
mov ecx,pid ;Push PID value
mov ebx,0x1 ;FD stdout
mov eax, 0x4 ;sys_write call
ret
So the point here is get the pid number of the current program (this) and print it.
The program calls sys_getpid (eax=20) and the pidnumber is returned. But, sys_write parameters is: ssize_t sys_write(unsigned int fd, const char * buf, size_t count)
second argument is a char so I need to convert into char for each number.
output is only: "Your PID is:"
Anyone ? :)
You forgot to int 0x80 a second time to actually print the number.
When you div ebx, what is calculated is eax = edx:eax / ebx, so you have to make sure that edx is zero in your case. So xor edx,edx before you div ebx.
You should pad the front of your buffer with spaces, otherwise you might run into trouble depending on where stdout goes in the end.
I am very suspicious about your use of ebp to hold the pointer to the current buffer position. While it works here, the base pointer is a special purpose register and I see no reason to abuse it here.
I'm trying to learn the basics asm on linux and I can't find a very good reference. The NASM docs seem to assume you already know masm... I found no examples in the documentation of the cmp (outside the Intel instruction reference).
I'd written a program that reads a single byte from stdin and writes it to stdout. Below is my modification to try to detect EOF on stdin and exit when EOF is reached. The issue is it never exits. I just keeps printing the last char read from stdin. The issue is either in my EOF detection (cmp ecx, EOF) and/or my jump to the _exit label (je _exit) I think.
What am I doing wrong?
%define EOF -1
section .bss
char: resb 1
section .text
global _start
_exit:
mov eax, 1 ; exit
mov ebx, 0 ; exit status
int 80h
_start:
mov eax, 3 ; sys_read
mov ebx, 0 ; stdin
mov ecx, char ; buffer
cmp ecx, EOF ; EOF?
je _exit
mov edx, 1 ; read byte count
int 80h
mov eax, 4 ; sys_write
mov ebx, 1 ; stdout
mov ecx, char ; buffer
mov edx, 1 ; write byte count
int 80h
jmp _start
For the sake of sanity, I verified EOF is -1 with this C:
#include <stdio.h>
int main() { printf("%d\n", EOF); }
You are comparing the address of the buffer to EOF (-1) instead of the character stored in the buffer.
Having said that, the read system call does not return the value of EOF when end of file is reached, but it returns zero and doesn't stick anything in the buffer (see man 2 read). To identify end of file, just check the value of eax after the call to read:
section .bss
buf: resb 1
section .text
global _start
_exit:
mov eax, 1 ; exit
mov ebx, 0 ; exit status
int 80h
_start:
mov eax, 3 ; sys_read
mov ebx, 0 ; stdin
mov ecx, buf ; buffer
mov edx, 1 ; read byte count
int 80h
cmp eax, 0
je _exit
mov eax, 4 ; sys_write
mov ebx, 1 ; stdout
mov ecx, buf ; buffer
mov edx, 1 ; write byte count
int 80h
jmp _start
If you did want to properly compare the character to some value, use:
cmp byte [buf], VALUE
Also, I renamed char to buf. char is a basic C data type and a bad choice for a variable name.
I am trying to print a single digit integer in nasm assembly on linux. What I currently have compiles fine, but nothing is being written to the screen. Can anyone explain to me what I am doing wrong here?
section .text
global _start
_start:
mov ecx, 1 ; stores 1 in rcx
add edx, ecx ; stores ecx in edx
add edx, 30h ; gets the ascii value in edx
mov ecx, edx ; ascii value is now in ecx
jmp write ; jumps to write
write:
mov eax, ecx ; moves ecx to eax for writing
mov eax, 4 ; sys call for write
mov ebx, 1 ; stdout
int 80h ; call kernel
mov eax,1 ; system exit
mov ebx,0 ; exit 0
int 80h ; call the kernel again
This is adding, not storing:
add edx, ecx ; stores ecx in edx
This copies ecx to eax and then overwrites it with 4:
mov eax, ecx ; moves ecx to eax for writing
mov eax, 4 ; sys call for write
EDIT:
For a 'write' system call:
eax = 4
ebx = file descriptor (1 = screen)
ecx = address of string
edx = length of string
After reviewing the other two answers this is what I finally came up with.
sys_exit equ 1
sys_write equ 4
stdout equ 1
section .bss
outputBuffer resb 4
section .text
global _start
_start:
mov ecx, 1 ; Number 1
add ecx, 0x30 ; Add 30 hex for ascii
mov [outputBuffer], ecx ; Save number in buffer
mov ecx, outputBuffer ; Store address of outputBuffer in ecx
mov eax, sys_write ; sys_write
mov ebx, stdout ; to STDOUT
mov edx, 1 ; length = one byte
int 0x80 ; Call the kernel
mov eax, sys_exit ; system exit
mov ebx, 0 ; exit 0
int 0x80 ; call the kernel again
From man 2 write
ssize_t write(int fd, const void *buf, size_t count);
In addition to the other errors that have been pointed out, write() takes a pointer to the data and a length, not an actual byte itself in a register as you are trying to provide.
So you will have to store your data from a register to memory and use that address (or if it's constant as it currently is, don't load the data into a register but load its address instead).