介绍一种ELF文件函数粒度的加固方法,可以有效防止对程序的静态分析。这是一种有源码加固方式,需要被加固程序中代码配合。加固流程如下:
1)读取ELF文件头,获取e_phoff和e_phnum
2)通过Elf64_Phdr中的p_type字段,找到DYNAMIC
3)遍历.dynamic,找到.dynsym、.dynstr 节区偏移,和.dynstr节区的大小
4)遍历.dynsym,找到函数对应的Elf64_Sym符号后,根据st_value和st_size字段找到函数在ELF的偏移和函数大小
5)根据函数偏移和大小,加密之
加固程序代码如下,在x86_64平台测试通过:
#include
#include
#include
#include
#include
typedef struct {
Elf64_Addr st_value;
Elf64_Word st_size;
}func_info;
Elf64_Ehdr ehdr;
int
find_target_section_addr(const int fd, const char *sec_name){
lseek(fd, 0, SEEK_SET);
if(read(fd, &ehdr, sizeof(Elf64_Ehdr)) != sizeof(Elf64_Ehdr)){
puts("Read ELF header error");
return (-1);
}
return (0);
}
static char get_target_func_info(int fd, const char *func_name, func_info *info){
char flag = -1, *dynstr;
int i;
Elf64_Sym func_sym;
Elf64_Phdr phdr;
Elf64_Off dyn_off;
Elf64_Word dyn_size, dyn_strsz;
Elf64_Dyn dyn;
Elf64_Addr dyn_symtab, dyn_strtab;
lseek(fd, ehdr.e_phoff, SEEK_SET);
for(i = 0; i < ehdr.e_phnum; i++){
if(read(fd, &phdr, sizeof(Elf64_Phdr)) != sizeof(Elf64_Phdr)){
puts("Read segment failed");
return (-1);
}
if(phdr.p_type == PT_DYNAMIC){
dyn_size = phdr.p_filesz;
dyn_off = phdr.p_offset;
flag = 0;
printf("Find section %s, size = 0x%x, addr = 0x%lx\n", ".dynamic", dyn_size, dyn_off);
break;
}
}
if(flag) {
puts("Find .dynamic failed");
return (-1);
}
flag = 0;
lseek(fd, dyn_off, SEEK_SET);
for(i=0;i < dyn_size / sizeof(Elf64_Dyn); i++){
if(read(fd, &dyn, sizeof(Elf64_Dyn)) != sizeof(Elf64_Dyn)){
puts("Read .dynamic information failed");
return (-1);
}
if(dyn.d_tag == DT_SYMTAB){