i'am trying to make a simple NASM program on Linux Manjaro 20.2, the code:
section .data
global _start
_start:
mov rax, 60
mov rdi, 0
syscall
and build it up with
nasm -f elf64 test.asm
ld -o test.out test.o
./test.out
but no matter what, it always outputs Segmentation fault.
On the other side, i tried it up on Linux Mint Ulyssa and the program exits perfectly.
Related
Using 7th gen i5 processor, nasm, ld.
Written using general purpose registers and system calls, the program runs on Ubuntu. An example is a simple hello world program.
global _start
section .text
_start:
mov eax, 0x4 ; write(int fd, char *buf, int len)
mov ebx, 0x1 ; fd
mov ecx, message ; *buf
mov edx, message_length ; len
int 0x80 ; syscall
mov eax, 0x1 ; exit(int status)
mov ebx, 0x0 ; status
int 0x80 ; syscall
section .data
message db "hello world", 0xA
message_length equ $-message
nasm -f elf64 -o hello_world.o hello_world.s
ld hello_world.o -o hello_world
./hello_world
output: hello_world
However, the program written using the intel system instructions does not work.
global _start
section .text
_start:
CLI
HLT
nasm -f elf64 halt.s -o halt.o
ld halt.o -o halt
./halt
output: Segmentation fault (core dumped)
What prevents this code from compiling this way and running?
How can this code be compiled and run?
You have two questions:
What prevents this code from compiling this way and running?
Nothing prevents it from assembling, because it is valid code.
The reason that it does not run/throws a segmentation fault is, that you are attempting to run instructions that require certain privileges in user mode.
Have a look at HLT which description states
The HLT instruction is a privileged instruction.
Also look at CLI/STI, whose situation is more complicated (which is explained in the below article and the comments below), but is also mostly useful for kernel mode code. Wikipedia says
In all three cases, only privileged applications (usually the OS kernel) may modify IF[Interrupt flag]. [...] CLI and STI are [also] privileged instructions, which trigger a general protection fault if an unprivileged application attempts to execute it, [...]
That should answer your question regarding the difference between these two instructions and why HLT surely generates a GPF (General Protection Fault) executed in User Mode.
How can this code be compiled and run?
The only way to run this code is in privileged mode. So on Windows or Linux you'd have to code a kernel driver or code your own OS to make sensible use of these instructions.
The above only applies to Protected Mode or Long Mode code.
(Real mode code may always modify IF, the Interrupt flag)
I want to get a machine code of the running proccess by his PID for analysing malicious instructions, by using heuristic methods of data analysing.
All I need to know is list of current machine instructions and values of registers (EIP, EAX, EBX...).
I can use gdb for reach this goal gdb output, but is take a several problems:
I don't know how interact with gdb from my application;
malicious code can use some technics of debugger detection like this: http://www.ouah.org/linux-anti-debugging.txt
https://www.youtube.com/watch?v=UTVp4jpJoyc&list=LLw7XNcx80oj63tRYAg7hrsA
for windows;
Getting info from console output makes work of my application slower.
Is are any way to get this information by PID in Linux? Or maybe Windows?
you may have a look to gcore:
$ gcore
usage: gcore [-o filename] pid
so you can dump process core using its pid:
$ gcore 792
warning: Could not load vsyscall page because no executable was specified
0x00007f5f73998410 in ?? ()
Saved corefile core.792
and then open it in gdb:
$ gdb -c core.792
GNU gdb (GDB) Fedora 8.0.1-30.fc26
Copyright (C) 2017 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
[...]
[New LWP 792]
Missing separate debuginfo for the main executable file
Try: dnf --enablerepo='*debug*' install /usr/lib/debug/.build-id/09/b9d38bb6291b6282de4a2692e45448828d50da
Core was generated by `./a.out'.
#0 0x00007f5f73998410 in ?? ()
(gdb) info registers
rax 0xfffffffffffffe00 -512
rbx 0x0 0
rcx 0x7f5f73998410 140047938061328
rdx 0x1 1
rsi 0x7ffd30683d73 140725415591283
rdi 0x3 3
rbp 0x7ffd30683d90 0x7ffd30683d90
rsp 0x7ffd30683d68 0x7ffd30683d68
r8 0x1d 29
r9 0x0 0
r10 0x3 3
r11 0x246 582
r12 0x4006d0 4196048
r13 0x7ffd30683e70 140725415591536
r14 0x0 0
r15 0x0 0
rip 0x7f5f73998410 0x7f5f73998410
eflags 0x246 [ PF ZF IF ]
cs 0x33 51
ss 0x2b 43
ds 0x0 0
es 0x0 0
fs 0x0 0
gs 0x0 0
or even using the binary image from /proc to get some symbols:
gdb -c core.792 /proc/792/exe
You may know that you can pass scripts to gdb, this can ease not having to interact with it from your binary (man gdb for more details).
if you don't want to use gdb directly you may try using ptrace() directly, but it is for sure more work.
For the anti debugging technics, well... they work and there is no easy way to handle them directly as far as I know, each one may be worked arounded manually, (patching binary, disassembling from unaligned addresses manually by setting then in objdump, etc...)
I'm not an expert of the domain, I hope this will help you a bit.
I have been teaching myself x86 assembly and have been looking at doing basic malloc() and free() calls. I have spent quite a bit of time searching but most examples are for 64-bit or only show the malloc call without the free, etc. I even wrote this in c, then compiled and disassembled it, which helped but gcc adds a lot of other instructions.
Here is a basic example I made of what I was able to figure out, please let me know if this is correct or if there is anything else I should be doing:
global _start
; glibc stuff
extern _malloc, _free
section .data
err: db "malloc failed!", 10, 0
.len: equ $ - err
section .bss
mptr resd 1 ;pointer to begining of malloc'd memory
section .text
_start:
push 20 ;allocate 20 bytes
call _malloc ;call malloc
add esp, 4 ;clean pushed imm
test eax, eax ;check for malloc error
jz merror
mov [mptr], eax ;store address
mov byte [eax], 0
mov byte [eax + 1], 1
push mptr ;push address
call _free ;call free
add esp, 4 ;clean push
exit:
mov eax, 0x1
int 80h
merror:
mov eax, 0x4
mov ebx, 0x1
mov ecx, err
mov edx, err.len
int 80h
jmp exit
The second part to my question is compiling it. From what I was able to find I need to link /lib/ld-linux.so.2. So in my makefile I have the following but it errors out:
mem: mem.asm
nasm -f elf mem.asm
ld -melf_i386 -lc -I /lib/ld-linux.so.2 mem.o -o mem
This is the error I get when trying to compile:
As I said I am a noob at x86 so if you also have any comments for better ways to do things I would appreciate those too! :)
UPDATE :
So I went ahead and used gcc and got that to work (without and errors at least):
mem: mem.asm
nasm -f elf mem.asm
gcc -m32 mem.o -o mem
However when I went to run it it crashed big time:
I am clearly doing something wrong with free but as I mentioned, I wasn't positive about my use of malloc and free since I couldn't find any solid examples. Any clues?
Thanks to everyone for the help! So first I was able to get the linking errors fixed by using gcc to link instead of ld:
mem: mem.asm
nasm -f elf mem.asm
gcc -m32 mem.o -o mem
In order to get that to work I needed to change the names of the functions from _malloc and _free to malloc and free. I also had to change the standard global _start to global main in order to get gcc happy. This let it compile and link without errors but as you saw in the update the program crashed horribly when it came time to free the memory.
This was because I was pushing the wrong address to the stack. I initially had the instruction push mptr but that was pushing the address of mptr to the stack rather than the address it was pointing to, hence the error. A simple update to the instruction in order to push the correct address to the stack allowed my simple program to run without errors:
push dword [mptr]
The final result:
global main
; glibc stuff
extern malloc, free
section .data
err: db "malloc failed!", 10, 0
.len: equ $ - err
section .bss
mptr resd 1 ;pointer to begining of malloc'd memory
section .text
main:
push 20 ;allocate 20 bytes
call malloc ;call malloc
add esp, 4 ;clean pushed imm
test eax, eax ;check for malloc error
jz merror
mov [mptr], eax ;store address
mov byte [eax], 0 ;store 0 at index 0
mov byte [eax + 1], 1 ;store 1 at index 1
push dword [mptr] ;push address
call free ;call free
add esp, 4 ;clean push
exit:
mov eax, 0x1
int 80h
merror:
mov eax, 0x4
mov ebx, 0x1
mov ecx, err
mov edx, err.len
int 80h
jmp exit
Thanks again to everyone for the help and thanks Peter Cordes for giving me a chance to provide a proper answer! :)
I'm sure i'll be back with more noob x86 questions as my journey continues!
I'm trying to learn about ARM assembler programming using the GNU assembler. I've setup my PC with QEmu and have a Debian ARM-HF chroot environment.
If I assemble and link my test program:
.text
.global _start
_start:
mov r0, #6
bx lr
with:
as test.s -o test.o
ld test.o -o test
Then load the file into gdb and set a breakpoint on _start:
root#Latitude-E6420:/root# gdb test
GNU gdb (GDB) 7.6.1 (Debian 7.6.1-1)
Copyright (C) 2013 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "arm-linux-gnueabihf".
For bug reporting instructions, please see:
...
Reading symbols from /root/test...(no debugging symbols found)...done.
(gdb) break _start
Breakpoint 1 at 0x8054
(gdb)
How do I single step the code, display the assembler source code and monitor the registers?
I tried some basic commands and they did not work:
(gdb) break _start
Breakpoint 1 at 0x8054
(gdb) info regi
The program has no registers now.
(gdb) stepi
The program is not being run.
(gdb) disas
No frame selected.
(gdb) r
Starting program: /root/test
qemu: Unsupported syscall: 26
qemu: uncaught target signal 11 (Segmentation fault) - core dumped
qemu: Unsupported syscall: 26
During startup program terminated with signal SIGSEGV, Segmentation fault.
(gdb)
Your problem here is that you're trying to run an ARM gdb under QEMU's user-mode emulation. QEMU doesn't support the ptrace syscall (that's what syscall number 26 is), so this is never going to work.
What you need to do is run your test binary under QEMU with the QEMU options to enable QEMU's own builtin gdb stub which will listen on a TCP port. Then you can run a gdb compiled to run on your host system but with support for ARM targets, and tell that to connect to the TCP port.
(Emulating ptrace within QEMU is technically very tricky, and it would not provide much extra functionality that you can't already achieve via the QEMU builtin gdbstub. It's very unlikely it'll ever be implemented.)
Minimal working QEMU user mode example
I was missing the -fno-pie -no-pie options:
sudo apt-get install gdb-multiarch gcc-arm-linux-gnueabihf qemu-user
printf '
#include <stdio.h>
#include <stdlib.h>
int main() {
puts("hello world");
return EXIT_SUCCESS;
}
' > hello_world.c
arm-linux-gnueabihf-gcc -fno-pie -ggdb3 -no-pie -o hello_world hello_world.c
qemu-arm -L /usr/arm-linux-gnueabihf -g 1234 ./hello_world
On another terminal:
gdb-multiarch -q --nh \
-ex 'set architecture arm' \
-ex 'set sysroot /usr/arm-linux-gnueabihf' \
-ex 'file hello_world' \
-ex 'target remote localhost:1234' \
-ex 'break main' \
-ex continue \
-ex 'layout split'
;
This leaves us at main, in a split code / disassembly view due to layout split. You will also interested in:
layout regs
which shows the registers.
At the end of the day however, GDB Dashboard is more flexible and reliable: gdb split view with code
-fno-pie -no-pie is required because the packaged Ubuntu GCC uses -fpie -pie by default, and those fail due to a QEMU bug: How to GDB step debug a dynamically linked executable in QEMU user mode?
There was no gdbserver --multi-like functionality for the QEMU GDB stub on QEMU 2.11: How to restart QEMU user mode programs from the GDB stub as in gdbserver --multi?
For those learning ARM assembly, I am starting some runnable examples with assertions and using the C standard library for IO at: https://github.com/cirosantilli/arm-assembly-cheat
Tested on Ubuntu 18.04, gdb-multiarch 8.1, gcc-arm-linux-gnueabihf 7.3.0, qemu-user 2.11.
Freestanding QEMU user mode example
This analogous procedure also works on an ARM freestanding (no standard library) example:
printf '
.data
msg:
.ascii "hello world\\n"
len = . - msg
.text
.global _start
_start:
/* write syscall */
mov r0, #1 /* stdout */
ldr r1, =msg /* buffer */
ldr r2, =len /* len */
mov r7, #4 /* Syscall ID. */
swi #0
/* exit syscall */
mov r0, #0 /* Status. */
mov r7, #1 /* Syscall ID. */
swi #0
' > hello_world.S
arm-linux-gnueabihf-gcc -ggdb3 -nostdlib -o hello_world -static hello_world.S
qemu-arm -g 1234 ./hello_world
On another terminal:
gdb-multiarch -q --nh \
-ex 'set architecture arm' \
-ex 'file hello_world' \
-ex 'target remote localhost:1234' \
-ex 'layout split' \
;
We are now left at the first instruction of the program.
QEMU full system examples
Linux kernel: How to debug the Linux kernel with GDB and QEMU?
Bare metal: https://github.com/cirosantilli/newlib-examples/tree/f70f8a33f8b727422bd6f0b2975c4455d0b33efa#gdb
Single step of an assembly instruction is done with stepi. disas will disassemble around the current PC. info regi will display the current register state. There are some examples for various processors on my blog for my ELLCC cross development tool chain project.
You should add the -g option too to the assembling. Otherwise the codeline info is not included.
That crash probably comes from running some garbage after the code lines.
Maybe you should add the exit system call:
mov eax, 1 ; exit
mov ebx, 0 ; returm value
int 0x80 ; system call
How to simply get a code of exactly one assembly instruction?
For example for "mov eax 0x14".
I want to get it in linux terminal preferably with gcc or gdm.
$ echo "mov eax, 0x14" | as -o /dev/null -al -msyntax=intel -mnaked-reg
GAS LISTING page 1
1 0000 B8140000 mov eax,0x14
1 00
rasm2 from the radare2 package fits this purpose nicely:
$ rasm2 'nop'
90
$ rasm2 -d '90'
nop
http://radare.org/y/?p=examples&f=rasm