linux syscall uname for x86 - linux

I only study assembler (nasm) and have more question. For example i want make asm code that get info about operating system. I use linux 86 bit. In a code i use syscall uname. In a browser have more information about this syscall and code. I found this link:
https://github.com/hc0d3r/asm/blob/master/uname.asm
Uname syscall in buffer overflow
But i use 86 bit system. So, i tried rewrite code for my system. I understand, that in register eax i should move value of syscall (0x7a or 122) and in register ebx addres of array.
I used first link as example, but get error. So, can you help me decide this problem?
This is my main code:
extern printf
SYS_WRITE equ 4
SYS_UNAME equ 122
SYS_EXIT equ 60
STDOUT equ 1
section .data
str: db '%s',10,0
UTSNAME_SIZE equ 65
space db ' '
break_line db 0xa
section .bss
uname_res resb UTSNAME_SIZE*5
section .text
global main
main:
mov eax, 0x7A
mov ebx, uname_res
int 80h
push dword [uname_res]
push dword str
call printf
mov eax, 1
int 80h
and I got this error:
segmentation error (memory dump made)
This mistake on printf. Sorry for my crooked english

I wrote code for linux x86. Look it here (maybe will be useful)
https://github.com/OlegInfoSecurity/uname_x86
This error occurred when i output (print) info. I changed code for output info and program is work.

Related

Why is the RDI register missing in this "Hello world" assembly program?

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

assembly code unexpectedly printing .shstrtab.text.data

i am very new to assembly although i have lots of c and c++ experience.
my assembly code is supposed to print hello world like all first programs in a new language.
it prints out hello world but also prints out some extra text:
hello world!
.shstrtab.text.data
and here is my assembly program:
section .text
global _start ;for the linker
_start:
mov edx, length ; message length
mov ecx, message ; message to write
mov ebx, 1 ; file descriptor stdout
mov eax, 4 ; system call number
int 0x80 ; call kernel
mov eax, 1 ;system call number for sys_exit to exit program
int 0x80 ; call kernel
section .data
message db "hello world!"
length DD 10
if you know how to fix this also explain why is this happening.
thanks.
extra info: i am using nasm assembler with ld linker
so the problem is in adding length as it gives the address of length variable but not the value. the answer is to use move edx, [length]. thanks to Jester for pointing me that out
length equ $ - message | instead of length dd 10

Joining strings from registers and printing them (CPUID)

Starting to learn NASM assembly, I was looking at some assembly questions here in Stack Overflow and found this one here:
Concatenating strings from registers and printing them
I believe that this question is not duplicated because I am trying to
replicate the code in NASM and also things were not very clear in the
other question.
I decided to replicate this code in NASM, but I did not quite understand the MASM code in question.
I learned about CPUID and did some testing programs.
In order, I'd like to know how we can concatenate registers and then print them on the screen USING NASM.
I want to print 'ebx' + 'edx' + 'ecx' because this is how the CPUID output is organized by what I see in GDB.
I called CPUID with eax=1
"String" is not a very precise term. The Vendor Identification String of CPUID/EAX=0 contains only 12 ASCII characters, packed into 3 DWORD registers. There is no termination character like in C nor a length information like in PASCAL. But it's always the same registers and it's always 3*4=12 bytes. This is ideal for the write-syscall:
section .bss
buff resb 12
section .text
global _start
_start:
mov eax, 0
cpuid
mov dword [buff+0], ebx ; Fill the first four bytes
mov dword [buff+4], edx ; Fill the second four bytes
mov dword [buff+8], ecx ; Fill the third four bytes
mov eax, 4 ; SYSCALL write
mov ebx, 1 ; File descriptor = STDOUT
mov ecx, buff ; Pointer to ASCII string
mov edx, 12 ; Count of bytes to send
int 0x80 ; Call Linux kernel
mov eax, 1 ; SYSCALL exit
mov ebx, 0 ; Exit Code
int 80h ; Call Linux kernel

Segmentation Fault on simple ASM code

For my Question when I tried to create a example of NASM under ubuntu 64-bit version and execute it after assembled and linked into ELF. It return error messages as below when I execute
NASM -f elf64 -o firstasm.o firstasm.asm
ld -o firstasm firstasm.o
firstasm
Segmentation fault (core dumped)
My NASM code would be below where I tried to perform simple write() and exit() function
section .data ;Data segment
msg db "This line is test", 0x0a
section .text ;text segment
global _start ;Default entry point for ELF linking
_start:
; SYSCALL : write (1,msg,14)
xor rax,rax
xor rbx,rbx
xor rcx,rcx
xor rdx,rdx
mov rax,64 ; make a syscall write 4
mov rbx,1 ; put 1 into rbx and also stdout is 1
mov rcx,msg ;put address of string in rcx
mov rdx,19 ; put length of string into rdx
int 0x80 ; call kernel to made syscall
; SYSCALL : exit(0)
xor rax,rax
xor rbx,rbx
mov rax,93 ; make a syscall exit 93
mov rbx, 0 ; store 0 argument into rbx, success to exit
int 0x80
Can someone pointed me what is problem to my NASM code and suggestions to fix the problem of "Segmentation fault (core dumped)". Appreciate thanks to anyone could help.
Uh, where are you getting the system call numbers? Are you pulling them out of the air?
64bit sys_exit = 60
32bit sys_exit = 1
64bit sys_write = 1
32bit sys_write = 4
Linux 64-bit System Call List
Linux 32-bit System Call List
Linux System Call Table for x86_64
The above link will show what registers are used for what.
the 32 bit system call - int 0x80 does not use the 64bit registers and the register parameters are different. The 64 bit system call is - syscall.
32 bit sys_exit:
mov ebx, ERR_CODE
mov eax, sys_exit ; 1
int 80h
64 bit sys_exit:
mov rdi, ERR_CODE
mov rax, sys_exit ; 60
syscall
see the difference?
if you want to create an inc file of the system call names and numbers for YOUR system (maybe they are different for some reason)
grep __NR /usr/include/asm/unistd_64.h | grep define | sed -e 's/\#/\%/' -e 's/__NR_/sys_/' > unistd_64.inc
of course, adjust the path to unistd_64.h for your system. It will be the same for 32 bit but the file is called unistd_32.h I believe.
Now that I showed you the difference between the exit sys call, and with the provided links, you can fix your write system call to be correct.

How to open a file in assembler and modify it?

I'm starting to learn Assembler and I'm working in Unix. I want to open a file and write 'Hello world' on it.
section .data
textoutput db 'Hello world!', 10
lentext equ $ - textoutput
filetoopen db 'hi.txt'
section .text
global _start
_start:
mov eax, 5 ;open
mov ebx, filetoopen
mov ecx, 2 ;read and write mode
int 80h
mov eax, 4
mov ebx, filetoopen ;I'm not sure what do i have to put here, what is the "file descriptor"?
mov ecx, textoutput
mov edx, lentext
mov eax, 1
mov ebx, 0
int 80h ; finish without errors
But when I compile it, it doesn't do anything. What am I doing wrong?
When I open a file where does the file descriptor value return to?
This is x86 Linux (x86 is not the only assembly language, and Linux is not the only Unix!)...
section .data
textoutput db 'Hello world!', 10
lentext equ $ - textoutput
filetoopen db 'hi.txt'
The filename string requires a 0-byte terminator: filetoopen db 'hi.txt', 0
section .text
global _start
_start:
mov eax, 5 ;open
mov ebx, filetoopen
mov ecx, 2 ;read and write mode
2 is the O_RDWR flag for the open syscall. If you want the file to be created if it doesn't already exist, you will need the O_CREAT flag as well; and if you specify O_CREAT, you need a third argument which is the permissions mode for the file. If you poke around in the C headers, you'll find that O_CREAT is defined as 0100 - beware of the leading zero: this is an octal constant! You can write octal constants in nasm using the o suffix.
So you need something like mov ecx, 0102o to get the right flags and mov edx, 0666o to set the permssions.
int 80h
The return code from a syscall is passed in eax. Here, this will be the file descriptor (if the open succeeded) or a small negative number, which is a negative errno code (e.g. -1 for EPERM). Note that the convention for returning error codes from a raw syscall is not quite the same as the C syscall wrappers (which generally return -1 and set errno in the case of an error)...
mov eax, 4
mov ebx, filetoopen ;I'm not sure what do i have to put here, what is the "file descriptor"?
...so here you need to mov ebx, eax first (to save the open result before eax is overwritten) then mov eax, 4. (You might want to think about checking that the result was positive first, and handling the failure to open in some way if it isn't.)
mov ecx, textoutput
mov edx, lentext
Missing int 80h here.
mov eax, 1
mov ebx, 0
int 80h ; finish without errors
Did you read the Linux Assembly HOWTO? It covers your question.
You can also compile some C code with gcc -S -fverbose-asm -O1 and look at the generated assembly. For example, with foo.c, run gcc -S -Wall -fverbose-asm -O1 foo.c (as a command in some terminal) then look (using some editor -perhaps GNU emacs) into the generated foo.s assembler file.
At last, I don't think it is worth bothering a lot about assembler. In 2020, a recent GCC compiler will surely generate better code than what you could write (if you invoke it with optimizations, at least -O2). See this draft report for more.
This is a x64 Linux sample
; Program to open and write to file
; Compile with:
; nasm -f elf64 -o writeToFile64.o writeToFile64.asm
; Link with:
; ld -m elf_x86_64 -o writeToFile64 writeToFile64.o
; Run with:
; ./writeToFile64
;==============================================================================
; Author : Rommel Samanez
;==============================================================================
global _start
%include 'basicFunctions.asm'
section .data
fileName: db "testFile.txt",0
fileFlags: dq 0102o ; create file + read and write mode
fileMode: dq 00600o ; user has read write permission
fileDescriptor: dq 0
section .rodata ; read only data section
msg1: db "Write this message to the test File.",0ah,0
msglen equ $ - msg1
msg2: db "File Descriptor=",0
section .text
_start:
mov rax,2 ; sys_open
mov rdi,fileName ; const char *filename
mov rsi,[fileFlags] ; int flags
mov rdx,[fileMode] ; int mode
syscall
mov [fileDescriptor],rax
mov rsi,msg2
call print
mov rax,[fileDescriptor]
call printnumber
call printnewline
; write a message to the created file
mov rax,1 ; sys_write
mov rdi,[fileDescriptor]
mov rsi,msg1
mov rdx,msglen
syscall
; close file Descriptor
mov rax,3 ; sys_close
mov rdi,[fileDescriptor]
syscall
call exit
It depends what assembler you are using and if you expect to be using the C runtime or not. In this case which appears to be the Hello World text example from rosettacode they are using nasm. Given you have a _start field you are not needing the C runtime so you assemble this to an elf object file and link it into a program:
nasm -felf hello.asm
ld hello.o -o hello
Now you can run the hello program.
A slightly more portable example that uses the C runtime to do the work rather than linux syscalls might look like the sample below. If you link this as described it can use printf to do the printing.
;;; helloworld.asm -
;;;
;;; NASM code for Windows using the C runtime library
;;;
;;; For windows - change printf to _printf and then:
;;; nasm -fwin32 helloworld.asm
;;; link -subsystem:console -out:helloworld.exe -nodefaultlib -entry:main
;;; helloworld.obj msvcrt.lib
;;; For gcc (linux, unix etc):
;;; nasm -felf helloworld.asm
;;; gcc -o helloworld helloworld.o
extern printf
section .data
message:
db 'Hello, World', 10, 0
section .text
global main
main:
push dword message ; push function parameters
call printf ; call C library function
add esp, 4 ; clean up the stack
mov eax, 0 ; exit code 0
ret
For information about file descriptors - read the open(2) manual page or look at wikipedia. It is how posix refers to an open i/o stream. In your case, stdout.

Resources