/*
ELF PolyCrypter
Copyright (c) 2016 picoFlamingo
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define SECTION ".txet"
#define CRYPT_ME __attribute__((section(SECTION)))
#define KEY_SIZE 8
#define KEY_MASK 0x7
/* All ceros gets optimised out, apparently */
static u_char key[KEY_SIZE + 1] ="\1\1\1\1\1\1\1\1";
#define DIE(s) {perror(s);exit(1);}
#define DIE1(s) {fprintf(stderr, s);exit(1);}
#define DEFAULT_EP ((unsigned char*)0x400000)
/* Data structure representing the crypter state */
typedef struct crypter_t
{
/* Secured section in memory */
int p; /* Segment Offset */
int len; /* Segment Lenght */
/* Binary file on disk */
char *fname;
void *code;
int code_len;
} CRYPTER;
/* Secured Code */
/* ----------------------------------------------------------- */
CRYPT_ME
int check (void)
{
char buffer[1024];
int i;
setvbuf(stdout, NULL, _IONBF, 0);
printf ("PolyCrypt password checker v 0.1\n");
printf ("$ ");
fgets (buffer, 1024, stdin);
printf ("Checking Password %s", buffer);
printf (" Please wait ");
for (i = 0; i < 20; i++)
{
putchar ('.');
sleep (1);
}
/* Actually we are no checking any thing. This is just a test
* so we return a typical error message :)*/
printf ("\nCommunications Error. Please try again later :P\n");
return 0;
}
/* ----------------------------------------------------------- */
/* Locates a Section in an ELF file and returns
* the section header
*/
Elf64_Shdr *
elfi_find_section (void *data, char *name)
{
char *sname;
int i;
Elf64_Ehdr* elf_hdr = (Elf64_Ehdr *) data;
Elf64_Shdr *shdr = (Elf64_Shdr *)(data + elf_hdr->e_shoff);
Elf64_Shdr *sh_strtab = &shdr[elf_hdr->e_shstrndx];
const char *const sh_strtab_p = data + sh_strtab->sh_offset;
for (i = 0; i < elf_hdr->e_shnum; i++)
{
sname = (char*) (sh_strtab_p + shdr[i].sh_name);
if (!strcmp (sname, name)) return &shdr[i];
}
return NULL;
}
/* Get the size of the file associated to the file descriptor fd */
static int
get_file_size (int fd)
{
struct stat _info;
fstat (fd, &_info);
return _info.st_size;
}
/* Basic hex dump function... for debugging */
#ifdef DEBUG
void
dump_mem (u_char *p, int size)
{
int i;
for (i = 0; i < size; i++)
printf ("%02x%c", p[i], ((i+1) % 16 == 0) ? '\n' : ' ');
printf ("\n");
}
#endif
/* This functions loads a binary file from disk and
* creates an associated CRYPTER structure
*/
CRYPTER*
load (char *f)
{
int fd;
CRYPTER *c;
if ((c = malloc (sizeof(CRYPTER))) == NULL) DIE1 ("malloc:");
c->fname = strdup (f);
/* Read the code in memory */
if ((fd = open (f, O_RDONLY, 0)) < 0) DIE ("open");
c->code_len = (get_file_size (fd));
c->code = malloc (c->code_len);
read (fd, c->code, c->code_len);
close (fd);
return c;
}
/* Dump the binary file associated to a crypter in disk */
void
save (CRYPTER *c)
{
int fd;
/* Delete the file so we can write a modified image */
if ((unlink (c->fname)) < 0) DIE ("unlink:");
if ((write ((fd = open (c->fname, O_CREAT | O_TRUNC | O_RDWR,S_IRWXU)),
c->code, c->code_len)) < 0) DIE ("write:");
close (fd);
return;
}
/* Function to xor encode a memory block
* The key is decreased in one unit so key \1\1\1\1\1\1\1\1 is the
* null key and it does not get removed from the data segment by the
* compiler... At least this is what it seesm to happen.
*/
void
xor_block (unsigned char *data, int len)
{
int i;
for (i = 0; i < len; data[i] ^= (key[i & KEY_MASK] - 1), i++);
}
/* Generates a random key */
void
gen_key (u_char *p, int size)
{
int i;
for (i = 0; i < size; i++) p[i] = key[i] = (rand() % 255);
}
/* This function decodes the secure part of the binary, in memory and
* reencodes the disk image stored by the CRYPTER struct in order to save
* a new re-encoded verson of the application.
*/
int
change (CRYPTER *c)
{
Elf64_Shdr *s;
int key_off;
/* Find data section to get the current key */
/* Actually we need this to modifiy the image file */
if ((s = elfi_find_section (c->code, ".data")) == NULL)
DIE1 (".data not found\n");
key_off = s->sh_offset + 0x10; /* XXX: Figure out where the 0x10 comes from */
/* Find the crypted code */
if ((s = elfi_find_section (c->code, SECTION)) == NULL)
DIE1 ("secured section not found");
c->p = s->sh_offset;
c->len = s->sh_size;
/* Change Permissions of section SECTION to decrypt code */
unsigned char *ptr = DEFAULT_EP + c->p;
unsigned char *ptr1 = DEFAULT_EP + c->p + c->len;
size_t pagesize = sysconf(_SC_PAGESIZE);
uintptr_t pagestart = (uintptr_t)ptr & -pagesize;
int psize = (ptr1 - (unsigned char*)pagestart);
/* Make the pages writable...*/
if (mprotect ((void*)pagestart, psize, PROT_READ | PROT_WRITE | PROT_EXEC) < 0)
perror ("mprotect:");
/* Decode memory and file */
xor_block (DEFAULT_EP + c->p, c->len);
xor_block (c->code + c->p, c->len);
/* Reset permissions */
if (mprotect ((void*)pagestart, psize, PROT_READ | PROT_EXEC) < 0)
perror ("mprotect:");
/* Update key and reencode file */
gen_key ((u_char*)c->code + key_off, KEY_SIZE + 1);
xor_block (c->code + c->p, c->len);
/* Dump the new file to disk. We are ready for next execution */
save (c);
return 0;
}
int
main (int argc, char *argv[])
{
CRYPTER *crypter;
srand (time(NULL));
crypter = load (argv[0]);
change (crypter);
check ();
return 0;
}