When compiling C and nasm on Mac OS X, I found it is different to Linux when passing parameters and making system call. My code works but I'm really confused with it.
I write a function myprint in nasm to print string passed from C.
Here is the C code main.c
#include <stdio.h>
void myprint(char* msg, int len);
int main(void){
myprint("hello\n",6);
return 0;
}
Here is the nasm code myprint.asm
section .text
global _myprint
_syscall:
int 0x80
ret
_myprint:
push dword [esp+8] ;after push, esp-4
push dword [esp+8]
push dword 1
mov eax,4
call _syscall
add esp,12
ret
Compile and link them:
nasm -f macho -o myprint.o myprint.asm
gcc -m32 -o main main.c myprint.o
it prints "hello" correctly.
As you can see, OS X(FreeBSD) use push to pass parameters to sys call, but the parameters char* and int are already pushed into the stack and their addresses are esp+4 and esp+8. However, I have to read them from the stack and push them into stack again to make it work.
If I delete
push dword [esp+8] ;after push, esp-4
push dword [esp+8]
it will print lots of error codes and Bus error: 10, like this:
???]?̀?j????????
?hello
`44?4
__mh_execute_headerm"ain1yprint6???;??
<??
(
libSystem.B?
`%?. _syscall__mh_execute_header_main_myprintdyld_stub_binder ??z0&?z?&?z?&?z۽??۽????N?R?N?o?N???N??N?e?N?h?N?0?zR?N???N???t??N?N???N?????#?`#b?`?`?a#c aaU??]N?zBus error: 10
Why it needs to push the parameters into stack again? How can I pass these parameters already in stack to syscall without pushing again?
This is normal for even plain C function calls. The problem is that the return address is still on the stack before the arguments. If you don't push them again below the return address you will have 2 return addresses on the stack before the arguments (the first to main and the second to myprint) but the syscall only expects 1.
Related
I try to implement the C sqrt function in Nasm elf64, it works correctly without argument (with the value of "a" define in the function), but when I try to pass an argument to this function ,the code return an error "Stopped reason: SIGFPE".
Here's my code
The c function
int le_sqrt(int a) {
int n=1;
int number = a;
for (int i=0; i<10; i++) {
n=(n+number/n)/2;
}
return n;
}
The nasm program
bits 64
global _start
extern le_sqrt
_start:
mov rbp,9 ;argument
push rbp ;same argument push
call le_sqrt ; my c function
mov rax,60 ;exit program
mov rsi,0
syscall
If you want to call le_sqrt(9) with System V AMD64 ABI calling convention, do this:
_start:
mov rdi,9
call le_sqrt
SIGFPE usually happens when you divide a number by 0. In your assembly program, you are using mov rbp, 9 for passing an argument to c function, which might be wrong in your case. It becomes obvious since you're getting SIGFPE. See Microsoft calling conventions and System V ABI calling conventions (for 64-bit). For 32-bit, follow these calling conventions.
I'm trying to compile and run following program without main() function in C. I have compiled my program using the following command.
gcc -nostartfiles nomain.c
And compiler gives warning
/usr/bin/ld: warning: cannot find entry symbol _start; defaulting to 0000000000400340
Ok, No problem. then, I have run executable file(a.out), both printf statements print successfully, and then get segmentation fault.
So, my question is, Why segmentation fault after successfully execute print statements?
my code:
#include <stdio.h>
void nomain()
{
printf("Hello World...\n");
printf("Successfully run without main...\n");
}
output:
Hello World...
Successfully run without main...
Segmentation fault (core dumped)
Note:
Here, -nostartfiles gcc flag prevents the compiler from using standard startup files when linking
Let's have a look at the generated assembly of your program:
.LC0:
.string "Hello World..."
.LC1:
.string "Successfully run without main..."
nomain:
push rbp
mov rbp, rsp
mov edi, OFFSET FLAT:.LC0
call puts
mov edi, OFFSET FLAT:.LC1
call puts
nop
pop rbp
ret
Note the ret statement. Your program's entry point is determined to be nomain, all is fine with that. But once the function returns, it attempts to jump into an address on the call stack... that isn't populated. That's an illegal access and a segmentation fault follows.
A quick solution would be to call exit() at the end of your program (and assuming C11 we might as well mark the function as _Noreturn):
#include <stdio.h>
#include <stdlib.h>
_Noreturn void nomain(void)
{
printf("Hello World...\n");
printf("Successfully run without main...\n");
exit(0);
}
In fact, now your function behaves pretty much like a regular main function, since after returning from main, the exit function is called with main's return value.
In C, when functions/subroutines are called the stack is populated as (in the order):
The arguments,
Return address,
Local variables, --> top of the stack
main() being the start point, ELF structures the program in such a way that whatever instructions comes first would get pushed first, in this case printfs are.
Now, program is sort of truncated without return-address OR __end__ and infact it assumes that whatever is there on the stack at that(__end__) location is the return-address, but unfortunately its not and hence it crashes.
I am currently working on 'Pentester Academy's x86_64 Assembly Language and Shellcoding on Linux' course (www.pentesteracademy.com/course?id=7). I have one simple question that I can't quite figure out: what is the exact difference between running an assembly program that has been assembled and linked with NASM and ld vs. running the same disassembled program in the classic shellcode.c program (written below). Why use one method over the other?
As an example, when following the first method, I use the commands :
nasm -f elf64 -o execve_stack.o execve_stack.asm
ld -o execve_stack execve_stack.o
./execve_stack
When using the second method, I insert the disassembled shellcode in the shellcode.c program:
#include <stdio.h>
#include <string.h>
unsigned char code[] = \
"\x48\x31\xc0\x50\x48\x89\xe2\x48\xbb\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x53\x48\x89\xe7\x50\x57\x48\x89\xe6\xb0\x3b\x0f\x05";
int main(void) {
printf("Shellcode length: %d\n", (int)strlen(code));
int (*ret)() = (int(*)())code;
ret();
return 0;
}
... and use the commands:
gcc -fno-stack-protector -z execstack -o shellcode shellcode.c
./shellcode
I have analyzed both programs in GDB and found that addresses stored in certain registers differ. I have also read the answer to the following question (C code explanation), which helped me understand the way the shellcode.c program works. Having said that, I still don't fully understand the exact way in which these two methods differ.
There is no theoretical difference between the two methods. In both you end up executing a bunch of assembly instructions on the processor.
The shellcode.c program is there to just demonstrate what would happen if you run the assembly defined as an array of bytes in the unsigned char code[] variable.
Why use one method over the other?
I think you don't understand the purpose of shellcodes and the reasoning behind the shellcode.c program (why it shows what happens when an arbitrary sequence of bytes you have control on is executed on the processor).
A shellcode is a small piece of assembly code that is used to exploit a software vulnerability. An attacker usually injects a shellcode into software by taking advantage of common programming errors such as buffer overflows and then tries to make the software execute that injected shellcode.
A good article showing a step-by-step tutorial on how to generate a shell by performing shellcode injection using buffer overflows can be found here.
Here is how a classic shellcode \x83\xec\x48\x31\xc0\x31\xd2\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\xb0\x0b\xcd\x80 looks like in assembler:
sub esp, 72
xor eax, eax
xor edx, edx
push eax
push 0x68732f2f ; "hs//" (/ is doubled because you need to push 4 bytes on the stack)
push 0x6e69622f ; "nib/"
mov ebx, esp ; EBX = address of string "/bin//sh"
push eax
push ebx
mov ecx, esp
mov al, 0xb ; EAX = 11 (which is the ID of the sys_execve Linux system call)
int 0x80
In an x86 environment, this does an execve system call with the "/bin/sh" string as parameter.
I'm trying to do the following for the sake of practice in NASM:
1)Read a string from command-line in C
2)Pass that string to a NASM function which takes the string as its first parameter
3)Return that exact string from NASM function
prefix.asm:
;nasm -f elf32 prefix.asm -o prefix.o
segment .bss
pre resb 256
segment .text
global prefix
prefix:
push ebp ;save the old base pointer value
mov ebp,esp ;base pointer <- stack pointer
mov eax,[ebp+8] ;function argument
add esp, 4
pop ebp
ret
prefix c:
//nasm -f elf32 prefix.asm -o prefix.o
//gcc prefix.c prefix.o -o prefix -m32
#include <stdio.h>
#include <string.h>
char* prefix(char *str);
int main(void)
{
char str[256];
char* pre;
int a;
printf("Enter string: ");
scanf("%s" , str) ;
pre = prefix(str);
printf("Prefix array: %s\n", pre);
return 0;
}
After I run(it compiles w/o any problem) and supply my string to the program I get a Segmentation fault (core dumped) error.
First try to write a C program to implement char* prefix(char *str), disassemble it and understand it.
Problem 1: the add esp, 4 should be deleted. A function should preserve the stack pointer. I.e. the esp should be the same before the first instruction and before the return instruction. Your assembly code increases esp by 4.
Problem 2: Don't name your .asm and .c to be the same. Use different names.
I have the following code (two files):
main.c
#include <stdio.h>
void print();
void asm_print();
int main() {
asm_print();
printf("done\n");
return 0;
}
void print() {
printf("printing with number: %d\n", 1);
// printf("printing without number\n");
}
lib.s
.intel_syntax noprefix
.text
.globl asm_print
asm_print:
push rbp
mov rbp, rsp
call print
mov rsp, rbp
pop rbp
ret
expected output
printing with number: 1
done
If I compile on linux using gcc4.9.3 and the command line:
gcc -O2 -m64 -Wall -Wextra -Werror -std=gnu99 main.c lib.s
everything works fine. This also works if I use –O1 or –O3. If I compile on cygwin64 using gcc4.9.3 and the command line:
gcc –O1 -m64 -Wall -Wextra -Werror -std=gnu99 main.c lib.s
everything works fine.
If, however, I change the above to use –O2 or –O3, only the first line of output is produced. If in the function print() I comment out the first line and uncomment the second line, I get the expected output:
printing without number
done
regardless of the amount of optimization I use. Can anyone suggest what is wrong with the code such that I get the expected output regardless of the amount of optimization used on cygwin64?
The problem is that the windows 64 bit ABI is different than the 32-bit ABI, and requires the caller to allocate scratch parameter (home) space of 32 bytes on the stack for use by the callee.
http://eli.thegreenplace.net/2011/09/06/stack-frame-layout-on-x86-64/
https://msdn.microsoft.com/en-us/library/tawsa7cb.aspx
So what you need to do is to decrement the stack by at least 32 before the call. In addition, x64 requires maintaining the stack pointer on a multiple of 16 bytes. The 64 bit return address is 8 bytes, so you actually need to move rsp by 40, 56, etc.
asm_print:
push rbp
mov rbp, rsp
sub rsp, 40
call print
add rsp, 40
pop rbp
ret
Presumably, when you call print / printf with just a string constant, it doesn't actually use any of the scratch space, so nothing bad happens. On the other hand, when you use the %d format, it needs the parameter space, and clobbers your saved registers on the stack.
The reason it works with optimization disabled, is that the print function doesn't use the home space, and allocates parameter space when it calls printf. If you use -O2, the compiler does tail-call elimination and replaces the "call printf" instruction with a "jmp printf". This essentially results in re-using the parameter space that was supposed to be allocated by asm_print.