Doing an ASM call / ret in C - c

I try to do a simple call / ret sequence in assembly (from c code compiled with GCC), by manually writing the ret op code, and making a call to the ret address:
void *addr;
addr = mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANON, -1, 0);
// Writing the ret op code
((char*)addr)[0] = 0xC3;
// Going to addr with the ret
asm volatile("call *%0" : : "r" (addr));
But I get a segmentation fault. Anyone would know why, and how to correct ?

In order to be able to execute instructions on a memory page, read and write privileges are not enough; it also needs to be marked executable (PROT_EXEC).

Related

Remapping stack succeeds, but later SEGV is raised

I ran a simple program written in assembly that under strace that simply executes SYS_exit.
_start:
mov rax, 0x3C
mov rdi, 0x0
syscall
And noticed that there were nothing like mmap memory for the stack:
alrorp#dmspc:~$ strace ./bin
execve("./bin", ["./bin"], 0x7ffd591eda80 /* 65 vars */) = 0
exit(0) = ?
+++ exited with 0 +++
So I tried to do mmap with MAP_FIXED to the stack page-aligned address as follows:
int main(void){
int a = 1;
void *ptr = &a;
void *page_aligned_ptr = (void *)((intptr_t) ptr & -4096);
mmap(page_aligned_ptr, 4096, PROT_READ | PROT_WRITE, MAP_FIXED | MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
}
The thing is it segfaults after the call to mmap succeeds (i.e. it returns the requested address instead of MAP_FAILED).
mmap(0x7ffdf50db000, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7ffdf50db000
--- SIGSEGV {si_signo=SIGSEGV, si_code=SEGV_MAPERR, si_addr=NULL} ---
+++ killed by SIGSEGV (core dumped) +++
Segmentation fault
Can you give any hint about this behavior? Core dump seems to be (almost) useless in that case with stack corrupted.
Does something like create a custom mapping for stack even make sense?
Replacing the stack page containing your return address with a new anonymous page of zero bytes obvious leads to a segfault as soon as main returns, and pops 0 into RIP.
Note the si_addr=NULL, IIRC that's the code address where the fault happened. So RIP=0 after running a ret with RSP pointing at a 0. (The ret itself won't fault, but code-fetch from address 0 will.)
Or actually the segfault will be inside the libc wrapper for mmap, which itself has to ret.
Use a debugger to single-step the asm the C compiler created for you.

Mapped file doesn't take memory on read, but does on write

I've observed a weird behavior, where a large memory mapped file(2GB), doesn't take actual physical RAM when i read from it, but does when i start writing to it.
int err = 0;
int fd = open("large_file", O_RDWR);
if (fd == -1) {
return errno;
}
void *map = mmap(NULL, size, PROT_READ | PROT_WRITE,
MAP_PRIVATE, fd, 0);
if (map == MAP_FAILED) {
err = errno;
goto out;
}
for (unsigned int i = 0; i < 2 << 30; i += PAGE_SIZE) {
volatile uint8_t val = 0xff;
// val = ((volatile uint8_t *) map)[i]; /* Doesn't take actual memory */
// ((volatile uint8_t *) map[i]) = val; /* Takes actual memory */
}
while (1)
sleep(10);
out:
if (fd != -1)
close(fd);
if (map != MAP_FAILED)
munmap(map, size);
return err;
This is htop screenshot when i READ from the mapped file(look at "check")
This is htop screenshot when i WRITE to the mapped file(look at "check"
My laptop is pretty much IDLE, nothing else can take physical RAM other than my test process, so you can see when i write to the mapped file it actually takes 2GB(copy-on-write), and when reading, it doesn't. RES-SHR also fits in both of my cases.
I can't explain it.. the kernel maps a new page regardless if it's a read or a write to physical RAM. If it wasn't present, it should be mapped and take actual RAM after a page fault exception. The mapped file is not mapped to other processes, so it isn't shared. The test process is the only one and the first one that maps the file into memory.
EDIT:
I've added the (volatile) keyword to make sure the compiler doesn't optimize the critical code. This doesn't make any difference. This particular piece of assembly code is the output of reading from the memory mapped file:
mov BYTE PTR [rbp-0xbd],0xff /* volatile uint8_t val = 0xff; */
mov edx,DWORD PTR [rbp-0xbc]
mov rax,QWORD PTR [rbp-0xb0]
add rax,rdx
movzx eax,BYTE PTR [rax]
mov BYTE PTR [rbp-0xbd],al /* val = ((volatile uint8_t *)map)[i]; */
add DWORD PTR [rbp-0xbc],0x1000 /* i += PAGE_SIZE; */
Any thoughts?
Probably your compiler just optimizes the read accesses. It can do so, since you never do anything with it. Easiest would be to change the declaration of val:
uint8_t volatile val = ... ;
but you could also declare map accordingly:
uint8_t volatile*map = mmap(NULL, size, PROT_READ | PROT_WRITE,
MAP_PRIVATE, fd, 0);
(Declaring the sought type for map also avoids to have the nasty cast later on.)

KVM Userspace Port I/O

I'm currently experimenting with KVM, and trying to get US (userspace) I/O working. Currently, output (i.e. out dx, eax) works, and the US code can see the written value, but input (in eax, dx) does not seem to work - the VM doesn't receive the value written by the US code.
if (run->io.port == 0xface && run->io.direction == KVM_EXIT_IO_IN)
{
printf("Port 0xface read\n");
*(volatile uint32_t *)((uintptr_t)run + run->io.data_offset) = 0xdeadbeefu;
continue;
}
run is a pointer to a struct kvm_run that was mmaped earlier and has enough space (i.e. run->io.data_offset is a valid offset from the pointer). The continue statement eventually causes the VM to restart, and the code continues normally. However, when I try to get the VM's rax register (which should be 0xdeadbeef), I get zero. From what I read in the docs (kvm/Documentation/api.txt), this is how I should be doing it. Am I missing something?
On a semi-related note, if I precede the continue statement with run->io.count = run->io.count;, the I/O is triggered again (even though count isn't changed). Is this expected behavior? Or am I triggering undefined behavior?
The issue is with the actual mmap call:
run = mmap(NULL, mapSize, PROT_READ | PROT_WRITE, MAP_PRIVATE, vcpuID, 0);
The flags parameter should be MAP_SHARED instead of MAP_PRIVATE:
run = mmap(NULL, mapSize, PROT_READ | PROT_WRITE, MAP_SHARED, vcpuID, 0);
^^^^^^^^^^
The virtual machine will see the updated values when KVM_RUN is issued to restart it.

mmap substitute for malloc

I need to find a way to use mmap instead of malloc. How is this possible? (I am not using libc only syscalls) And yes brk() is possible. I used sbrk() but realized its not sys-call... (x86 inline assembly)
I've been looking around and saw this: How to use mmap to allocate a memory in heap? But it didn't help for me, because I had a segfault.
Basically, all I want to do a create 3 slabs of memory for storing characters.
Say,
char * x = malloc(1000);
char * y = malloc(2000);
char * z = malloc(3000);
How is this possible with mmap and how to free it later with munmap?
Did you carefully read the mmap(2) man page? I recommend reading it several times.
Notice that you can only ask the kernel [thru mmap etc...] to manage memory aligned to and multiple of the page size sysconf(_SC_PAGE_SIZE) which is often 4096 bytes (and I am supposing that in my answer).
Then you might do:
size_t page_size = sysconf(_SC_PAGE_SIZE);
assert (page_size == 4096); // otherwise this code is wrong
// 1000 bytes fit into 1*4096
char *x = mmap (NULL, page_size, PROT_READ|PROT_WRITE,
MAP_ANONYMOUS, -1, (off_t)0);
if (x == MMAP_FAILED) perror("mmap x"), exit (EXIT_FAILURE);
// 2000 bytes fit into 1*4096
char *y = mmap (NULL, page_size, PROT_READ|PROT_WRITE,
MAP_ANONYMOUS, -1, (off_t)0);
if (y == MMAP_FAILED) perror("mmap y"), exit (EXIT_FAILURE);
later to free the memory, use
if (munmap(x, page_size))
perror("munmap x"), exit(EXIT_FAILURE);
etc
If you want to allocate 5Kbytes, you'll need two pages (because 5Kbytes < 2*4096 and 5Kbytes > 1*4096) i.e. mmap(NULL, 2*page_size, ...
Actually, all of your x, y, z takes only 8000 bytes and could fit into two, not three, pages... But then you could only munmap that memory together.
Be aware that mmap is a system call which might be quite expensive. malloc implementations take care to avoid calling it too often, that is why they manage previously free-d zones to reuse them later (in further malloc-s) without any syscall. In practice, most malloc implementations manage differently big allocations (e.g. more than a megabyte), which are often mmap-ed at malloc and munmap-ed at free time.... You could study the source code of some malloc. The one from MUSL Libc might be easier to read than the Glibc malloc.
BTW, the file /proc/1234/maps is showing you the memory map of process of pid 1234. Try also cat /proc/self/maps in a terminal, it shows the memory map of that cat process.
You can call mmap to make an anonymous mapping in x86 asm with something like:
mov eax, 192 ; mmap
xor ebx, ebx ; addr = NULL
mov ecx, 4096 ; len = 4096
mov edx, $7 ; prot = PROT_READ|PROT_WRITE|PROT_EXEC
mov esi, $22 ; flags = MAP_PRIVATE|MAP_ANONYMOUS
mov edi, -1 ; fd = -1 (Ignored for MAP_ANONYMOUS)
xor ebp, ebp ; offset = 0 (4096*0) (Ignored for MAP_ANONYMOUS)
int $80 ; make call (There are other ways to do this too)

I need to recover my source code from the executable

It's the middle of the night, and I've accidently overwritten all my work by typing
gcc source.c -o source.c
I still have the original binary and my only hope is to dissemble it, but I don't know how or what the best tool to use to get the most readable result. I know this probably isn't the right place to post but I'm stressing out. Can someone help me out please?
Thanks for uploading the file. As I suspected, it was unstripped so the function names remained. Besides standard boilerplate code I could identify functions main, register_broker, connect_exchange (unused and empty) and handle_requests.
I spent a bit of time in IDA Pro and it wasn't too hard to recover the main() function. First, here's the original, unmodified listing of main() from IDA: http://pastebin.com/sBxhRJMM
To proceed, you need to familiarize yourself with AMD64 calling convention. To summarize, the first four arguments are passed in RDI(EDI), RSI(ESI), RDX(EDX) and RCX(ECX). The rest is passed on the stack, but all calls in main() use only up to four arguments so we don't need to worry about that.
IDA has helpfully labeled arguments of the standard C functions and even renamed some local variables. However, it can be improved and commented further. For example, since we're in main(), we know that argc (first argument) comes from EDI (since it's an int meaning 32-bit, it uses only the low half of RDI) and argv comes from RSI (it's a pointer so it uses the full 8 bytes of the register). So, we can rename the local variables into which EDI and RSI are copied:
mov [rbp+argc], edi
mov [rbp+argv], rsi
Next is a simple conditional block:
cmp [rbp+argc], 2
jz short loc_400EB3
mov rax, cs:stderr##GLIBC_2_2_5
mov rdx, rax
mov eax, offset aUsage ; "Usage"
mov rcx, rdx ; s
mov edx, 5 ; n
mov esi, 1 ; size
mov rdi, rax ; ptr
call _fwrite
mov edi, 1 ; status
call _exit
Here we compare argc with 2, and if it is equal, we jump further in the code. If it is not equal, we call fwrite(). The first argument to it is in rdi, and rdi is loaded from rax, which holds the address of a constant string "Usage". The second argument is in esi and is 1, the third in edx and is 5, the fourth in rcx, which is loaded from rdx which has the value of stderr##GLIBC_2_2_5, which is basically a fancy reference to the stderr variable from libc. Stringing it all up together, we get:
fwrite("Usage", 1, 5, stderr);
From my experience, I can say that most likely it is an inlined fprintf, since 5 is exactly the length of the string. I.e. the original code probably was:
fprintf(stderr, "Usage");
Next call is a simple exit(1);. Combining both with the comparison, we get:
if ( argc != 2 )
{
fprintf(stderr, "Usage");
exit(1);
}
Continuing in this vein, we can identify other calls and variables they use. It's somewhat tedious to describe it all, so I uploaded a commented version of the disassembly, where I tried to show the equivalent C code for each call. You can see it here: http://pastebin.com/p5sRSwgQ
From that commented version it's not very hard to imagine a possible version of main():
int main(int argc, char **argv)
{
if ( argc != 2 )
{
fprintf(stderr, "Usage");
exit(1);
}
char name[256];
gethostname(name, sizeof(name));
struct hostent* _hostent = gethostbyname(name);
struct in_addr *_addr0 = (struct in_addr *)(_hostent->h_addr_list[0]);
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(0);
addr.sin_addr.s_addr = _addr0->s_addr;
char *tmp = (char *)malloc(6);
sprintf(tmp, "%d", addr.sin_port);
char *ip_str = inet_ntoa(*_addr0);
char *newbuf = (char *)malloc(strlen(argv[1]) + strlen(ip_str) + strlen(tmp) + 5);
strcpy(newbuf, "r");
strcat(newbuf, " ");
strcat(newbuf, argv[1]);
strcat(newbuf, " ");
strcat(newbuf, ip_str);
strcat(newbuf, " ");
strcat(newbuf, tmp);
register_broker(newbuf);
int fd = socket(PF_INET, SOCK_STREAM, 0);
if ( fd < 0 )
{
perror("Error creating socket");
exit(1);
}
if ( bind(fd, (struct sockaddr*)&addr, sizeof(addr)) != 0 )
{
perror("Error binding socket");
exit(1);
}
if ( listen(fd, 0x80) != 0 )
{
perror("Error listening on socket");
exit(1);
}
handle_requests(fd);
}
Recovering the other two functions is left an exercise for the reader :)
There are several tools (you can search with Google) but I would suggest to re-code it. The time you will invest into refactoring what a disassebler will return is probably higher than re-coding.
I know it seems obvious but the correct answer would be: restore from a backup (that you should have)
There is unfortunately really no good way to go from the binary back to the source. You can try Boomerang, but I really don't expect good results.
Firstly, look for a backup source file. Most editors create files named .bak or filename.c~ with each file save. On a Windows machine, a forensic software tool might be able to retrieve the last source file(s). The tool I wrote, getfile used to be offered by NTI, but was acquired by Armor Holdings a few years ago—no idea if it is still available.
If the code is runnable, oftentimes running it under the strace() utility (a standard component of Linux distributions) can help with some aspects of decoding the program, especially if it is i/o oriented. Alas, if the program is mostly internal data manipulation, this is not of much use. Strace() creates a log of the system calls and parameters passed by the program; it is an invaluable tool at times for understanding how a program behaves. for example, strace date produces (in part—I've omitted the runtime library startup):
clock_gettime(CLOCK_REALTIME, {1315760058, 681379835}) = 0
open("/etc/localtime", O_RDONLY) = 3
fstat64(3, {st_mode=S_IFREG|0644, st_size=2819, ...}) = 0
fstat64(3, {st_mode=S_IFREG|0644, st_size=2819, ...}) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb78b5000
read(3, "TZif2\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\4\0\0\0\4\0\0\0\0"..., 4096) = 2819
_llseek(3, -24, [2795], SEEK_CUR) = 0
read(3, "\nPST8PDT,M3.2.0,M11.1.0\n", 4096) = 24
_llseek(3, 2818, [2818], SEEK_SET) = 0
close(3) = 0
munmap(0xb78b5000, 4096) = 0
fstat64(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 0), ...}) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb78b5000
write(1, "Sun Sep 11 09:54:18 PDT 2011\n", 29Sun Sep 11 09:54:18 PDT 2011) = 29
close(1) = 0
munmap(0xb78b5000, 4096) = 0
close(2) = 0
As soon as you have anything worth saving:
Add some sort of source control (git, svn, cvs, ...) maybe more than one
Use an automated build tool, like make to avoid silly mistakes
Make backups once in a while. Even when I am at a stone-knives-and-bear-skins client, I can still email myself source files for a last-ditch backup mechanism.
You can use dcc. But, next time, you should use Git ;)
You can try disassembling with objdump -d <filename>.
You can also look at the symbol names with the nm utility to jog your memory and help recode the source.
The commercial IDA Pro disassembler/debugger is popular in software reverse engineering. Unfortunately, reverse engineering a binary is slow and difficult work.

Resources