linux 下字符混淆器
阿新 • • 發佈:2018-07-04
exe break main uint8_t instr 文件內容 dup 副本 fine
//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 下字符混淆器