linux elf文件 破解,Linux系统编程练习 ELF文件头读取和修改

ELF

文件有三种类型:可重定位文件:也就是通常称的目标文件,后缀为.o。共享文件:也就是通常称的库文件,后缀为.so。可执行文件:本文主要讨论的文件格

式,总的来说,可执行文件的格式与上述两种文件的格式之间的区别主要在于观察的角度不同:一种称为连接视图(Linking

View),一种称为执行视图(Execution View)。

一个典型的ELF文件有两种描述视图:program header和section header.

program header:是对程序运行时所使用的段的描述.

section header: 是对所有二进制段的描述.

每一个ELF文件是由一个ELF 文件头(ELF header)和其余的文件数据构成.这些文件数据包括一下一些内容:

·Program header table 描述0个或是多个段(segments)

·Section header table, 描述0个或是多个节(sections)

·要写到上面两个表中的数据.

段(segments)包含的是程序运行是必要的信息

节(sections)包含的是链接和重定向时所需要的重要数据

同一时间整个文件中的每个beyt不会属于一个以上的段,但是也可以存在不属于任何段的字节.

linux下ELF文件分析工具:

readelfis: 是一个unix下的二进制工具,用来显示一个或多个ELF文件的信息.

elfdump: 是一个Solaris命令,用来查看单个ELF文件的信息.

objdump:     可以查看ELF文件或是其它对象格式的更多信息.

这里自己写了个简单的分析ELF文件头和修改文件头的小程序

//elf_head.h

#ifndef ELF_HEAD_H

#define ELF_HEAD_H

#define MAGIC           "\177ELF"

#define INVAL           0

#define INFO_POS        40

#define FOPEN_FAILED    -1

#define FORMAT_ERROR    -2

#define SUCCESS         0

#define MODTIP() do{puts("\tEnter new value:");}while(0)

#define CUR_FTYPE_MAX   4

#define CUR_ARCH_MAX    40

typedef struct elf_head{

char magic[4]; //Magic Number

char addr_width; //Class 1 - 32bits(ELF32);2 - 64bits

char byteorder; //Byte order 1 - little-endian;2 - big-endian

char hversion; //Header version 1

char pad[9]; //Padding bytes

short filetype; //1 - relocatable;2 - executable;3 - shared object;4 - core-image

short archtype; //Architecture 2 - SPARC;3 - x86;4 - 68K

int fversion; //File version 1

int entry;//Entry point if executable

int phdrpos; //Program header position

int shdrpos; //Section header position

int flags; //Architecture relative

short hdrsize; //ELF header size

short phdrent;//Size of program headers

short phdrcnt;//Number of program headers

short shdrent;//Size of section headers

short shdrcnt;//Number of section headers

short strsec;//Section header string table index

}elf_header;

int read_elf_header(elf_header *ehdr,char *filename); //读取文件头信息

int print_elfhdr_info(elf_header *ehdr); //打印相关信息

int modify_elfhdr(elf_header *ehdr,char *filename); //修改文件头

#endif /*ELF_HEAD_H*/

#include

#include

#include

#include "elf_head.h"

static char *file_type[] = { //文件类型字段的描述字符串数组

"Unknown",

"Relocatable",

"Executable",

"Shared object",

"Core imgae"

};

static char *arch_type[] = { //硬件平台的描述字符串数组

"Unknown",

"Reserved",

"SPARC",

"x86",

"68K",

" ",               //5

" ",

" ",

" ",

" ",

" ",             //10

" ",

" ",

" ",

" ",

" ",            //15

" ",

" ",

" ",

" ",

" ",            //20

" ",

" ",

" ",

" ",

" ",            //25

" ",

" ",

" ",

" ",

" ",            //30

" ",

" ",

" ",

" ",

" ",            //35

" ",

" ",

" ",

" ",

"ARM",          //40

};

//Check if the file is an elf format file

static int is_elf(elf_header *ehdr)

{

if(strncmp(ehdr->magic,MAGIC,strlen(MAGIC)) == 0)

return 1;

else

return 0;

}

int read_elf_header(elf_header *ehdr,char *filename)

{

FILE *fp;

fp = fopen(filename,"r");

if(fp == NULL)

return FOPEN_FAILED;

bzero(ehdr,sizeof(elf_header));

fread(ehdr,sizeof(elf_header),1,fp);

if(strncmp(ehdr->magic,MAGIC,strlen(MAGIC)) != 0)

{

fclose(fp);

return FORMAT_ERROR;

}

fclose(fp);

return SUCCESS;

}

static void put_tip(char *tip)

{

printf(" %s",tip);

printf("\033[%dC",INFO_POS - strlen(tip)); //每次输出第二列信息,即读出的数据的时候,先向右移动光固定个单位,保证对齐。详见ANSI控制码表

}

int print_elfhdr_info(elf_header *ehdr)

{

if(strncmp(ehdr->magic,MAGIC,strlen(MAGIC)) != 0)

{

puts("Not an elf format file.");

return FORMAT_ERROR;

}

puts("ELF header:");

put_tip("Magic:");

printf("%2x %2x %2x %2x (%c%c%c%c)\n"

,ehdr->magic[0],ehdr->magic[1],ehdr->magic[2],ehdr->magic[3]

,ehdr->magic[0],ehdr->magic[1],ehdr->magic[2],ehdr->magic[3]);

put_tip("Class:");

if(ehdr->addr_width == 1)

printf("ELF32\n");

if(ehdr->addr_width == 2)

printf("ELF64\n");

put_tip("Byte order:");

if(ehdr->byteorder == 1)

printf("Little-endian\n");

else

printf("Big-endian\n");

put_tip("Version:");

printf("0x%02x\n",ehdr->hversion);

put_tip("File type:");

if(ehdr->filetype > CUR_FTYPE_MAX)

ehdr->filetype = 0;

puts(file_type[ehdr->filetype]);

put_tip("Machine:");

if(ehdr->archtype > CUR_ARCH_MAX)

{

ehdr->archtype = 0;

}

puts(arch_type[ehdr->archtype]);

put_tip("File version");

printf("0x%x\n",ehdr->fversion);

put_tip("Entry point address:");

printf("0x%x\n%",ehdr->entry);

put_tip("Start of program headers:");

printf("%d (bytes into file)\n",ehdr->phdrpos);

put_tip("Start of section headers:");

printf("%d (bytes into file)\n",ehdr->shdrpos);

put_tip("flags:");

printf("%d(0x%x)\n",ehdr->flags,ehdr->flags);

put_tip("Size of this header:");

printf("%d bytes\n",ehdr->hdrsize);

put_tip("Size of program headers:");

printf("%d bytes\n",ehdr->phdrent);

put_tip("Number of program headers:");

printf("%d\n",ehdr->phdrcnt);

put_tip("Size of section headers:");

printf("%d bytes\n",ehdr->shdrent);

put_tip("Number of section headers:");

printf("%d\n",ehdr->shdrcnt);

put_tip("Section header string table index:");

printf("%d(0x%x)\n",ehdr->strsec,ehdr->strsec);

return SUCCESS;

}

static void mod_help()

{

puts("Select the part you want to modify:");

puts("1 -- Magic number.");

puts("2 -- Class(1:ELF32 2:ELF64).");

puts("3 -- Byteorder(1:Little-endian 2:Big-endian).");

puts("4 -- File type(1:relocatable 2:executable 3:shared object 4:core-image)");

puts("s -- save");

puts("q -- quit without saving");

puts("x -- save and quit");

}

static int atoh(char *buf)//将16进制形式的字符串转换成数值

{

int tmp = 0;

while(*buf != '\0')

{

if(*buf >= '0' && *buf <= '9')

tmp = tmp * 16 + *buf - '0';

else

{

if((*buf >= 'a' && *buf <= 'f'))

tmp = tmp * 16 + *buf - 'a' + 10;

else

{

if((*buf >= 'A' && *buf <= 'F'))

tmp = tmp * 16 + *buf - 'A' + 10;

else

return INVAL;

}

}

buf++;

}

return tmp;

}

//以下是修改ELF文件头的函数,只为了测试,如果随意修改会使文件无法使用

static void mod_magic(elf_header *ehdr)//修改MAGIC号

{

int i;

int magic;

int cur_val;

char buf[20];

char *tmp;

printf("\tOld magic number: %x %x %x %x\n",ehdr->magic[0],ehdr->magic[1],ehdr->magic[2],ehdr->magic[3]);

MODTIP();

puts("\te.g: 0a0b0c0d or 0A0B0C0D");

puts("\tEnter new value");

bzero(buf,20);

putchar('\t');

fgets(buf,19,stdin);

tmp = buf;

while(*tmp != '\0')

{

if((*tmp >= '0' && *tmp <= '9') || (*tmp >= 'a'

&& *tmp <= 'f') || (*tmp >= 'A' && *tmp <=

'Z'))

{

*(tmp + 8) = 0;

magic = atoh(tmp);

break;

}

tmp++;

}

//如果输入的是0x11223344,那么存在文件上就是0x44332211(小端模式),而访问magic字段的时候是以char型来访问,所以访问顺序正好相反,这里要交换字节序存入文件。

tmp = (char *)(&magic) + 3;

for(i = 0;i < 4;i++)

ehdr->magic[i] = *(tmp - i);

}

static void mod_class(elf_header *ehdr) //修改地址宽度,32位或是64位

{

char opt[2];

printf("\tOld class: %d \n\t1:ELF32 \n\t2:ELF64\n",ehdr->addr_width);

MODTIP();

while(1)

{

opt[0] = getchar();

opt[1] = getchar();

if(opt[0] > '2' || opt[0] < '1')

puts("\tWrong choice.Value should be 1 or 2");

else

break;

}

ehdr->addr_width = opt[0] - '0';

}

static void mod_byteorder(elf_header *ehdr) //修改字节序

{

char opt[2];

printf("\tOld byte order: %d \n\t1:Little-endian \n\t2:Big-endian\n",ehdr->byteorder);

MODTIP();

while(1)

{

opt[0] = getchar();

opt[1] = getchar();

if(opt[0] > '2' || opt[0] < '1')

puts("\tWrong choice.Value should be 1 or 2");

else

break;

}

ehdr->byteorder = opt[0] - '0';

}

static void mod_filetype(elf_header *ehdr)//修改文件类型

{

char opt[2];

printf("\tOld file type: %d \n\t1:Relocatable \n\t2:Executable

\n\t3:Shared object \n\t4:Core image\n)",ehdr->filetype);

MODTIP();

while(1)

{

opt[0] = getchar();

opt[1] = getchar();

if(opt[0] > '4' || opt[0] < '1')

puts("\tWrong choice.Value should be 1 or 2");

else

break;

}

ehdr->filetype = opt[0] - '0';

}

int modify_elfhdr(elf_header *ehdr,char *filename)

{

char opt[2];

FILE *fp;

//      elf_header ehdr_backup;

fp = fopen(filename,"r+");

if(fp == NULL)

return FOPEN_FAILED;

fread(ehdr,sizeof(elf_header),1,fp);

if(!is_elf(ehdr))

{

puts("Not an elf format file.");

return FORMAT_ERROR;

}

//      memcpy(&ehdr_backup,ehdr,sizeof(elf_header));

while(1)

{

mod_help();

opt[0] = getchar();

opt[1] = getchar();

switch(opt[0])

{

case '1':

mod_magic(ehdr);

break;

case '2':

mod_class(ehdr);

break;

case '3':

mod_byteorder(ehdr);

break;

case '4':

mod_filetype(ehdr);

break;

case 's':

fseek(fp,0,SEEK_SET);

fwrite(ehdr,sizeof(elf_header),1,fp);

break;

case 'q':

goto out;

break;

case 'x':

fseek(fp,0,SEEK_SET);

fwrite(ehdr,sizeof(elf_header),1,fp);

goto out;

break;

default:

puts("Wrong choice.");

}

}

out:

fclose(fp);

return SUCCESS;

}

//main.c

#include

#include

#include

#include

#include

#include

#include

#include "elf_head.h"

static void help()

{

puts("******************************************");

puts("*     ELF header reader and modifier     *");

puts("*     0 - exit                           *");

puts("*     1 - print header info              *");

puts("*     2 - modify elf header              *");

puts("******************************************");

}

int main(int argc,char **argv)

{

char cmd;

elf_header ehdr;

if(argc != 2)

{

printf("Usage: %s [filename]\n",strchr(argv[0],'/') + 1);

return 0;

}

switch(read_elf_header(&ehdr,argv[1]))

{

case FOPEN_FAILED:

printf("Can not open %s.\n",argv[1]);

goto out;

case FORMAT_ERROR:

printf("%s is not an elf format file.\n",argv[1]);

goto out;

}

while(cmd != '0')

{

help();

cmd = getchar();

switch(cmd)

{

case '1':

getchar();//由于终端不是非标准模式,所以输入字符后都要使用回车,回车符本身会当作输入的字符,这里使用getchar()目的就是使下次获得输入的字符时不为回车符

print_elfhdr_info(&ehdr);

break;

case '2':

getchar();

modify_elfhdr(&ehdr,argv[1]);

break;

default:

break;

}

}

out:

return 0;

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值