linux 下字符混淆器


//gcc elfscure.c -o elfscure
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <elf.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <sys/time.h>
#include <time.h>

#define SHT_VERSYM  0x6fffffff
#define SHT_VERNEED 0x6ffffffe
//SHF_WRITE
#define W 1
//SHF_ALLOC
#define A 2
//SHF_EXECINSTR
#define X 4
//功能
struct options
{
    //字符串表随机化
    char smix;
    char verbose;
    //保持与字符串名称一致的区段类型
    char sh_type;
    //保持区段标志与字符串名称一致
    char sh_flags;

} opts;
struct stat st;
//节类型
struct section_type 
{
    char name[64];
    uint32_t type;
    int flags;
};

struct section_type section_type[] = {
{".interp",           SHT_PROGBITS,     A },
{".hash",         SHT_HASH,         A },
{".note.ABI-tag",  SHT_NOTE,        A },
{".gnu.hash",     SHT_GNU_HASH,     A },
{".dynsym",       SHT_DYNSYM,       A },
{".dynstr",       SHT_STRTAB,       A },
{".gnu.version",   SHT_VERSYM,      A },
{".gnu.version_r", SHT_VERNEED,     A },
{".rel.dyn",          SHT_REL,          A },
{".rel.plt",          SHT_REL,          A },
{".init",         SHT_PROGBITS,     A|X},
{".plt",              SHT_PROGBITS,     A|X},
{".text",         SHT_PROGBITS,     A|X},
{".fini",         SHT_PROGBITS,     A|X},
{".rodata",       SHT_PROGBITS,     A },
{".eh_frame_hdr",  SHT_PROGBITS,        A },
{".eh_frame",     SHT_PROGBITS,     A },
{".ctors",        SHT_PROGBITS,     W|A},
{".dtors",        SHT_PROGBITS,     W|A},
{".jcr",              SHT_PROGBITS,     W|A},
{".dynamic",          SHT_DYNAMIC,      W|A},
{".got",              SHT_PROGBITS,     W|A},
{".got.plt",          SHT_PROGBITS,     W|A},
{".data",         SHT_PROGBITS,     W|A},
{".bss",              SHT_NOBITS,       W|A},
{".shstrtab",      SHT_STRTAB,      0 },
{".symtab",       SHT_SYMTAB,       0 },
{".strtab",       SHT_STRTAB,       0 },
{"",              SHT_NULL            }
};

//用于获取节名的新偏移量
int STBL_OFFSET(char *p, char *string, int count)
{
    char *offset = p;
    while (count-- > 0)
    {
        while (*offset++ != '.')
            ;
        if (strcmp(string, offset-1) == 0)
            return ((offset - 1) - p);
        //有的节名有俩种
        if (!strncmp(offset-1, ".rel.", 5) || !strncmp(offset-1, ".gnu.", 5) 
        ||  !strncmp(offset-1, ".not.", 5) || !strncmp(offset-1, ".got.", 5))
            while (*offset++ != '.');

    }
    return 0;
}

int strused(char *s, char **used_strings, int count)
{
    int i;

    for (i = 0; i < count; i++)
        if (!strcmp(s, used_strings[i]))
            return 1;
    return 0;
}

int main(int argc, char **argv)
{   //文件头
    Elf32_Ehdr *ehdr;
    //节表
    Elf32_Shdr *shdr, *shp;
    //程序头
    Elf32_Phdr *phdr;
    //字符串表
    char *StringTable, *NewStringTable;
    char **STBL, **STBL_USED_STRINGS;
    char *p, exec[255];
    char tmp[64];
    //映射基址
    uint8_t *mem;

    int fd;
    int i, j, k, count;
    int strcnt, slen;
    char c, failed = 0;

    struct timeval tv;
    struct timezone tz;

    opts.smix = 0;
    opts.verbose = 0;
    opts.sh_type = 0;
    opts.sh_flags = 0;

    if (argc < 3)
    {
        printf("\n- Elf 二进制混淆器\n"
        "用法: %s <文件> [选项]\n"
        "[-s]    字符串表随机化 \n"
        "[-t]   保持与字符串名称一致的区段类型\n"
        "[-f]    保持区段标志与字符串名称一致\n"
        "如: \n"
        "%s evilprog -stf\n",
        argv[0], argv[0]);  
        exit(0);
    }

    strcpy(exec, argv[1]);
    //获取选项
    while ((c = getopt(argc, argv, "fstv")) != -1)
    {
        switch(c)
        {
            case 's':
                opts.smix++;
                break;
            case 't':
                opts.sh_type++;
                break;
            case 'f':
                opts.sh_flags++;
                break;
            case 'v':
                opts.verbose++;
                break;
        }
    }
    //打开文件
    if ((fd = open(exec, O_RDWR)) == -1)
    {
        perror("open");
        exit(-1);
    }
    //读文件描述符
    if (fstat(fd, &st) < 0)
    {
        perror("fstat");
        exit(-1);
    }
    //映射
    mem = mmap(0, st.st_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
    if (mem == MAP_FAILED)
    {
        perror("mmap");
        exit(-1);
    }
    //文件头
    ehdr = (Elf32_Ehdr *)mem;
    //程序头
    phdr = (Elf32_Phdr *)(mem + ehdr->e_phoff);
    //节表头
    shdr = (Elf32_Shdr *)(mem + ehdr->e_shoff);

    //设置字符串表指针
    StringTable = &mem[shdr[ehdr->e_shstrndx].sh_offset];

    printf("[+] ELF Section 混淆 ->\n");
    printf("[+] 开始字符串表随机化 \n");
    if (opts.sh_type)
        printf("[+] sh_type一致性启用\n");
    if (opts.sh_flags)
        printf("[+] sh_flag一致性启用\n");
    if (opts.sh_type || opts.sh_flags)
        ehdr->e_shnum = 0;
    //分配e_shnum个
    if ((STBL = calloc(ehdr->e_shnum, sizeof(char *))) == NULL)
    {
        perror("calloc");
        exit(-1);
    }
    //分配e_shnum个
    if ((STBL_USED_STRINGS = calloc(ehdr->e_shnum, sizeof(char *))) == NULL)
    {
        perror("calloc");
        exit(-1);
    }
    //遍历所有节
    for (i = 0, shp = shdr; i < ehdr->e_shnum; shp++, i++)
        //拷贝所有字符名称
        STBL[i] = strdup(&StringTable[shp->sh_name]); 
    strcnt = i - 1;
    //先计算出长度
    for (slen = 0, i = 0; i < strcnt; i++, slen += strlen(STBL[i]) + 1);
    //再申请空间
    if ((NewStringTable = (char *)malloc(slen)) == NULL)
    {
        perror("malloc");
        exit(-1);
    }
    //赋值
    for (p = NewStringTable, i = 0; i < strcnt; i++)
    {
        strcpy(p, STBL[i]); 
        p += strlen(p) + 1;
        *p = 0;
    }

    if (opts.verbose)
    {
        for (i = 0; i < slen; i++)
            printf("%c", NewStringTable[i]);
        printf("\n");
    }

    for (i = 0; i < strcnt; i++)
        STBL_USED_STRINGS[i] = malloc(64);
    j = 0;
    for (i = 0, shp = shdr; i < ehdr->e_shnum; i++, shp++)
    {

        memset(tmp, 0, sizeof(tmp));
        gettimeofday(&tv, NULL);
        srand(tv.tv_usec);
        //将随机段名称复制到TMP中
        strcpy(tmp, STBL[rand() % strcnt]); 

        //字符串是否被使用
        if (strused(tmp, STBL_USED_STRINGS, strcnt))
        {
            --i;
            --shp;
            continue;
        }
        //确认没有分配自己的副本
        //.symtab .symtab
        if (!strcmp(&StringTable[shp->sh_name], tmp))
        {
            --i; --shp;
            continue;
        } 
        if (shp->sh_type == SHT_NULL)
            continue;

        //动态节就保持在适当的位置
        if (!strcmp(&StringTable[shp->sh_name], ".dynamic") || !strcmp(tmp, ".dynamic"))
        {
            if ((shp->sh_name = STBL_OFFSET(NewStringTable, ".dynamic", strcnt)) == 0)
            {
                  printf("STBL_OFFSET failed, could not find section name: %s, moving on\n", tmp);
                              goto done;
            }
            continue;
        }
        //创建新的偏移量
        if ((shp->sh_name = STBL_OFFSET(NewStringTable, tmp, strcnt)) == 0)
            printf("STBL_OFFSET 失败, 找不到节名: %s\n", tmp);

        //代码段修改为0x8048000
        if (!strcmp(tmp, ".text"))
            shp->sh_addr = 0x8048000;

       //更改节类型以匹配其名称symtab、rel和dynsym类型需要特定的条目大小
        if (opts.sh_type)
            for (count = 0; count < strcnt; count++)
                if (!strcmp(tmp, section_type[count].name))
                {   
                    shp->sh_type = section_type[count].type;
                    if (shp->sh_type == SHT_SYMTAB)
                        shp->sh_entsize = 0x10;
                    else
                    if (shp->sh_type == SHT_DYNSYM)
                        shp->sh_entsize = 0x10;
                    else
                    if (shp->sh_type == SHT_REL)
                        shp->sh_entsize = 0x08;
                }

        if (opts.sh_flags)
            for (count = 0; count < strcnt; count++)
                if (!strcmp(tmp, section_type[count].name))
                    shp->sh_flags = section_type[count].flags;

        strcpy(STBL_USED_STRINGS[j++], tmp);
    }
    //拷贝字符串表
    memcpy(&mem[shdr[ehdr->e_shstrndx].sh_offset], NewStringTable, shdr[ehdr->e_shstrndx].sh_size);
    //实现磁盘文件内容与共享内存区中的内容一致
    if (msync(mem, st.st_size, MS_SYNC) == -1)
    {
        perror("msync");
        failed++;
    }

    done:
    //解除映射
    munmap(mem, st.st_size);
    for (i = 0; i < strcnt; i++)
    {   free(STBL[i]);
        free(STBL_USED_STRINGS[i]);
    } 
    if (!failed)
        printf("段混淆成功!!!\n");
    else
        printf("段没有完全混淆!!!\n");
    exit(0);
}

猜你喜欢

转载自blog.51cto.com/haidragon/2136241