I would like to block all signals in a function using sigprocmask in assembly.
The following code works in C:
#include <stdio.h>
#include <signal.h>
int main() {
sigset_t n={(unsigned long int) 0xffffffff};
sigprocmask (SIG_BLOCK, &n, 0);
for (int i=0; i<0x8ffff; i++) printf(".");
}
When the code executes and starts printing dots on the terminal, I cannot interrupt it with Ctrl+C. So far so good.
The value of SIG_BLOCK is 0, apparently; and the syscall number for sys_rt_sigprocmask is 14:
http://blog.rchapman.org/post/36801038863/linux-system-call-table-for-x86-64
So I write:
[BITS 64]
[section .text align=1]
global main
main:
mov r10, 32
mov rdx, 0
mov rsi, newmask
mov rdi, 0
mov rax, 14
syscall
dotPrintLoop:
mov rdi, dotstring
mov rax, 0
syscall
jmp dotPrintLoop
[section .data align=1]
dotstring: db ".",0
newmask: dd 0xffffffff
dd 0xffffffff
dd 0xffffffff
...
And it does not work. gdb reveals that rax has the value -22 (EINVAL - "invalid parameter") after the first syscall; whereas the second syscall (of sys_write) works just fine.
What am I doing wrong?
Apparently r10 should hold the value 8 instead of 32.
I encountered 4 different definitions of sigset_t within the kernel code; and for each of them the sizeof() function returns a different result (32, 128, 4 and 8 as I recall). Only the final one is relevant to the syscall.
The kernel first checks that $r10 == sizeof(sigset_t); and returns EINVAL (-22) if that does not hold. The value of sizeof(sigset_t) is equal to 8 for both 32-bit and 64-bit versions.
Related
I found this "Hello" (shellcode) assembly program:
SECTION .data
SECTION .text
global main
main:
mov rax, 1
mov rsi, 0x6f6c6c6548 ; "Hello" is stored in reverse order "olleH"
push rsi
mov rsi, rsp
mov rdx, 5
syscall
mov rax, 60
syscall
And I found that mov rdi, 1 is missing. In other "hello world" programs that instruction appears so I would like to understand why this happens.
I was going to say it's an intentional trick or hack to save code bytes, using argc as the file descriptor. (1 if you run it from the shell without extra command line args). main(int argc, char**argv) gets its args in EDI and RSI respectively, in the x86-64 SysV calling convention used on Linux.
But given the other choices, like mov rax, 1 instead of mov eax, edi, it's probably just a bug that got overlooked because the code happened to work.
It would not work in real shellcode for a code-injection attack, where execution would probably reach this code with garbage other than 0, 1, or 2 in EDI. The shellcode test program on the tutorial you linked calls a const char[] of machine code as the only thing in main, which will normally compile to asm that doesn't touch RDI.
This code wouldn't work for code-injection attacks based on strcpy or other C-string overflows either, since the machine code contains 00 bytes as part of mov eax, 1, mov edx, 5, and the end of that character string.
Also, modern linkers don't link .rodata into an executable segment, and -zexecstack only affects the actual stack, not all readable memory. So that shellcode test won't work, although I expect it did when written. See How to get c code to execute hex machine code? for working ways, like using a local array and compiling with -zexecstack.
That tutorial is overall not great, probably something this guy wrote while learning. (But not as bad as I expected based on this bug and the use of Kali; it's at least decently written, just missing some tricks.)
Since you're using NASM, you don't need to manually waste time looking up ASCII codes and getting the byte order correct. Unlike some assemblers, mov rsi, "Hello" / push rsi results in those bytes being in memory in source order.
You also don't need an empty .data section, especially when making shellcode which is just a self-contained snippet of machine code which can't reference anything outside itself.
Writing a 32-bit register implicitly zero-extends to 64-bit. NASM optimizes mov rax,1 into mov eax,1 for you (as you can see in the objdump -d AT&D disassembly; objdump -drwC -Mintel to use Intel-syntax disassembly similar to NASM.)
The following should work:
global main
main:
mov rax, `Hello\n ` ; non-zero padding to fill 8 bytes
push rax
mov rsi, rsp
push 1 ; push imm8
pop rax ; __NR_write
mov edi, eax ; STDOUT_FD is also 1
lea edx, [rax-1 + 6] ; EDX = 6; using 3 bytes with no zeros
syscall
mov al, 60 ; assuming write success, RAX = 5, zero outside the low byte
;lea eax, [rdi-1 + 60] ; the safe way that works even with ./hello >&- to return -EBADF
syscall
This is fewer bytes of machine code than the original, and avoids \x00 bytes which strcpy would stop on. I changed the string to end with a newline, using NASM backticks to support C-style escape sequences like \n as 0x0a byte.
Running normally (I linked it into a static executable without CRT, despite it being called main instead of _start. ld foo.o -o foo):
$ strace ./foo > /dev/null
execve("./foo", ["./foo"], 0x7ffecdc70a20 /* 54 vars */) = 0
write(1, "Hello\n", 6) = 6
exit(1) = ?
Running with stdout closed to break the mov al, 60 __NR_exit hack:
$ strace ./foo >&-
execve("./foo", ["./foo"], 0x7ffe3d24a240 /* 54 vars */) = 0
write(1, "Hello\n", 6) = -1 EBADF (Bad file descriptor)
syscall_0xffffffffffffff3c(0x1, 0x7ffd0b37a988, 0x6, 0, 0, 0) = -1 ENOSYS (Function not implemented)
--- SIGSEGV {si_signo=SIGSEGV, si_code=SEGV_MAPERR, si_addr=0xffffffffffffffda} ---
+++ killed by SIGSEGV (core dumped) +++
Segmentation fault (core dumped)
To still exit cleanly, use lea eax, [rdi-1 + 60] (3 bytes) instead of mov al, 60 (2 bytes) to set RAX according to the unmodified EDI, instead of depending on the upper bytes of RAX being zero which they aren't after an error return.
See also https://codegolf.stackexchange.com/questions/132981/tips-for-golfing-in-x86-x64-machine-code
I am trying to use the write syscall in order to reproduce the putchar function behavior which prints a single character. My code is as follows,
asm_putchar:
push rbp
mov rbp, rsp
mov r8, rdi
call:
mov rax, 1
mov rdi, 1
mov rsi, r8
mov rdx, 1
syscall
return:
mov rsp, rbp
pop rbp
ret
From man 2 write, you can see the signature of write is,
ssize_t write(int fd, const void *buf, size_t count);
It takes a pointer (const void *buf) to a buffer in memory. You can't pass it a char by value, so you have to store it to memory and pass a pointer.
(Don't print one char at a time unless you only have one to print, that's really inefficient. Construct a buffer in memory and print that. e.g. this x86-64 Linux NASM function: How do I print an integer in Assembly Level Programming without printf from the c library?)
A NASM version of GCC: putchar(char) in inline assembly:
; x86-64 System V calling convention: input = byte in DIL
; clobbers: RDI, RSI, RDX, RCX, R11 (last 2 by syscall itself)
; returns: RAX = write return value: 1 for success, -1..-4095 for error
writechar:
mov byte [rsp-4], dil ; store the char from RDI
mov edi, 1 ; EDI = fd=1 = stdout
lea rsi, [rsp-4] ; RSI = buf
mov edx, edi ; RDX = len = 1
syscall ; rax = write(1, buf, 1)
ret
If you do pass an invalid pointer in RSI, such as '2' (integer 50), the system call will return -EFAULT (-14) in RAX. (The kernel returns error codes on bad pointers to system calls, instead of delivering a SIGSEGV like it would if you deref in user-space).
See also What are the return values of system calls in Assembly?
Instead of writing code to check return values, in toy programs / experiments you should just run them under strace ./a.out, especially if you're writing your own _start without libc there won't be any other system calls during startup that you don't make yourself, so it's very easy to read the output. How should strace be used?
I am trying to use the write syscall in order to reproduce the putchar function behavior which prints a single character. My code is as follows,
asm_putchar:
push rbp
mov rbp, rsp
mov r8, rdi
call:
mov rax, 1
mov rdi, 1
mov rsi, r8
mov rdx, 1
syscall
return:
mov rsp, rbp
pop rbp
ret
From man 2 write, you can see the signature of write is,
ssize_t write(int fd, const void *buf, size_t count);
It takes a pointer (const void *buf) to a buffer in memory. You can't pass it a char by value, so you have to store it to memory and pass a pointer.
(Don't print one char at a time unless you only have one to print, that's really inefficient. Construct a buffer in memory and print that. e.g. this x86-64 Linux NASM function: How do I print an integer in Assembly Level Programming without printf from the c library?)
A NASM version of GCC: putchar(char) in inline assembly:
; x86-64 System V calling convention: input = byte in DIL
; clobbers: RDI, RSI, RDX, RCX, R11 (last 2 by syscall itself)
; returns: RAX = write return value: 1 for success, -1..-4095 for error
writechar:
mov byte [rsp-4], dil ; store the char from RDI
mov edi, 1 ; EDI = fd=1 = stdout
lea rsi, [rsp-4] ; RSI = buf
mov edx, edi ; RDX = len = 1
syscall ; rax = write(1, buf, 1)
ret
If you do pass an invalid pointer in RSI, such as '2' (integer 50), the system call will return -EFAULT (-14) in RAX. (The kernel returns error codes on bad pointers to system calls, instead of delivering a SIGSEGV like it would if you deref in user-space).
See also What are the return values of system calls in Assembly?
Instead of writing code to check return values, in toy programs / experiments you should just run them under strace ./a.out, especially if you're writing your own _start without libc there won't be any other system calls during startup that you don't make yourself, so it's very easy to read the output. How should strace be used?
I'm trying to find a way to make my code wait for two seconds before proceeding. I'm using nasm for Linux in protected mode, so I can only use int 80h. I found a syscall called "alarm" (27) and another called "pause" (29). However, when I try to use those, the program waits and finishes instead of continuing execution. I've also found another syscall, sigaction, which changes the behavior of a signal (so I think it can be used to make the program ignore the signal generated by alarm instead of exiting) but I didn't quite understand how sigaction works. Thanks for any help.
Useful links:http://man7.org/linux/man-pages/man2/alarm.2.html
http://man7.org/linux/man-pages/man2/sigaction.2.html
There is a system call for sleeping the program, sys_nanosleep:
sys_nanosleep : eax = 162, ebx = struct timespec *, ecx = struct timespec *
this struct timespec structure has two members:
;; This is for 32-bit. Note that x86-64 uses 2x 64-bit members
tv_sec ; 32 bit seconds
tv_nsec ; 32 bit nanoseconds
this structure can be declared in nasm as:
section .data
timeval:
tv_sec dd 0
tv_usec dd 0
and then you sets the values and call it as:
mov dword [tv_sec], 5
mov dword [tv_usec], 0
mov eax, 162
mov ebx, timeval
mov ecx, 0
int 0x80
the program then will sleep for 5 seconds. A complete example:
global _start
section .text
_start:
; print "Sleep"
mov eax, 4
mov ebx, 1
mov ecx, bmessage
mov edx, bmessagel
int 0x80
; Sleep for 5 seconds and 0 nanoseconds
mov dword [tv_sec], 5
mov dword [tv_usec], 0
mov eax, 162
mov ebx, timeval
mov ecx, 0
int 0x80
; print "Continue"
mov eax, 4
mov ebx, 1
mov ecx, emessage
mov edx, emessagel
int 0x80
; exit
mov eax, 1
mov ebx, 0
int 0x80
section .data
timeval:
tv_sec dd 0
tv_usec dd 0
bmessage db "Sleep", 10, 0
bmessagel equ $ - bmessage
emessage db "Continue", 10, 0
emessagel equ $ - emessage
With NASM, if you are targeting Linux x86-64, you can simply do something similar to the following:
global _start
section .data
timespec:
tv_sec dq 1
tv_nsec dq 200000000
section .text
_start:
mov rax, 35
mov rdi, timespec
xor rsi, rsi
syscall
...
35 corresponds to the 64-bit system call number for sys_nanosleep (as listed here). If the call is interrupted, the remaining sleep time is written to the memory location pointed by register rsi; in this example rsi is set to 0 to ignore the value if it happens. This call will sleep for tv_sec seconds + tv_nsec nanoseconds, 1.2 seconds in the above code snippet.
More information about this system call can be found in the nanosleep man page.
I'm trying to write byte 0xff to the parallel port at 0x378. It compiles and links without issue, but segfaults at the OUTSB instruction.
section .text
global _start
_err_exit:
mov eax, 1
mov ebx, 1
int 80h
_start:
mov eax, 101 ; ioperm
mov ebx, 0x378 ; Parallel port addr
mov ecx, 2 ; number of bytes to 'unlock'
mov edx, 1 ; enable
int 80h
mov esi, 0xff
mov dx, 0x378
outsb
mov eax, 1 ; exit
mov ebx, 0
int 80h
If I step through it with GDB and check the registers just before the OUTSB instruction, it doesn't look like there is anything in the DX register? or dx == edx in 32bit?
(gdb) info registers
eax 0x0 0
ecx 0x2 2
edx 0x378 888
ebx 0x378 888
esp 0xffffd810 0xffffd810
ebp 0x0 0x0
esi 0xff 255
edi 0x0 0
eip 0x8048090 0x8048090 <_start+36>
eflags 0x246 [ PF ZF IF ]
cs 0x23 35
ss 0x2b 43
ds 0x2b 43
es 0x2b 43
fs 0x0 0
gs 0x0 0
What am I doing wrong here?
(info on the OUTS instructions: http://siyobik.info/main/reference/instruction/OUTS%2FOUTSB%2FOUTSW%2FOUTSD)
EDIT:
The C version of the program works:
int main(int argc, char *argv[])
{
int addr = 0x378;
int result = ioperm(addr,5,1);
outb(0xff, addr);
}
There is a number of issues with that code. Firstly, you seem to forget that OUTSB is a privileged instruction, i.e. it can be executed only if the calling process has ring 0 access, i.e. it's a part of the kernel code. As far as I'm aware, the only code in Linux that has access to privileged instructions is the kernel itself, and the modules that it loads. All the other processes will give you a Segmentation fault (which is actually a General Protection Fault signalled by the CPU) when you try to execute a privileged instruction from a nonprivileged segment of code. I don't know how calling the ioperm syscall influences that, though.
Secondly, OUTSB writes a byte from a memory location specified by ESI to the I/O port in DX. In this case, you're telling the processor to write data to the port from location 0xff, to which the process surely doesn't have access. You can simplify that by simply changing the code to use the OUT instruction, since OUTSB is rather meant to be used with the REP prefix. Try this :
mov al, 0xff
out 0x378, al
This outputs the byte in al to the I/O port specified by the immediate operand, in this case 0x378.
Let me know how that turned out.