//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);
}
linux 下字符混淆器
猜你喜欢
转载自blog.51cto.com/haidragon/2136241
今日推荐
周排行