`
Fangrn
  • 浏览: 818224 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/ioctl.h>

#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;
}

分享到:
评论
1 楼 Fangrn 2010-08-12  
从网上搜集来的这篇文章,中间提到的修改elf文件信息的这段比较的吸引我。
不知道有没有办法,修改elf文件,能够在相关的地方插入一段自己的代码放到程序中间去。

相关推荐

    Linux系统下的ELF文件分析.pdf

    ELF文件分析是一个非常重要的主题,在Linux系统下,ELF文件分析可以帮助开发者更好地理解Linux系统,提高开发效率和质量。同时,ELF文件分析也可以帮助开发者发现ELF文件中的错误和漏洞,优化ELF文件的执行效率和...

    Linux系统下的ELF文件分析

    ### Linux系统下的ELF文件分析 #### 1. 引言 随着Linux系统的不断发展与普及,**可执行和可链接格式(Executable and Linkable Format,简称ELF)**已成为Linux系统下极其重要的可执行文件格式之一。作为一种标准...

    Linux下的ELF文件格式简介.pdf

    "Linux下的ELF文件格式简介" ELF(Executable and Linkable Format,可执行与链接格式)文件格式是...了解ELF文件格式对于理解Linux操作系统的底层机制和开发高效的应用程序非常重要。 "Linux下的ELF文件格式简介

    读取elf文件代码

    在Linux系统中,ELF(Executable and Linkable Format)文件是一种标准的可执行文件和共享库格式。ELF文件包含了程序的机器代码、符号表、重定位信息等,是Linux和其他类UNIX系统中的核心组成部分。本篇文章将深入...

    Android/Linux 32位elf自动修复工具

    在IT行业中,尤其是在嵌入式系统和移动设备领域,Android/Linux平台上的32位ELF(Executable and Linkable Format)文件扮演着至关重要的角色。这些文件是可执行程序、库和共享对象,它们包含了计算机代码和数据,...

    Linux下的ELF文件格式简介.doc

    理解ELF文件格式对于深入学习Linux系统的底层运作、程序编译和链接过程、以及进行系统级编程和调试具有重要意义。通过解析ELF文件,我们可以获取程序的详细结构,甚至实现自定义的工具和调试方法。

    elf64_pack.zip_ELF64位格式PDF_elf_elf64位压缩源码_elf文件加密_linux elf加密

    在Linux系统中,ELF(Executable and Linkable Format)文件是一种标准的可执行文件和共享库格式。ELF64位格式是专为64位架构设计的,如x86_64或AMD64。它包含了程序的机器代码、符号表、重定位信息等,使得操作系统...

    ELF文件的加载和动态链接过程

    ELF文件格式是一种在Linux系统下广泛使用的对象文件格式,它是x86架构中用于可执行文件、目标代码和共享库文件的一种标准文件格式。ELF文件被分为几种主要类型,包括可重定位文件、可执行文件以及共享对象文件。可重...

    ELF文件系统格式

    总的来说,ELF文件系统格式是类UNIX系统中不可或缺的一部分,它为编译器、链接器、程序加载器和调试工具提供了统一的接口,确保了软件开发和运行的高效性和可靠性。理解ELF格式有助于深入理解操作系统是如何加载和...

    ELF 文件格式分析-北京大学信息科学技术学院操作系统实验室

    ELF(Executable and Linkable Format)是Linux和其他类UNIX系统中的可执行文件、共享库以及核心转储的标准格式。这个格式被广泛应用于多种处理器架构,包括x86、ARM、MIPS等。北京大学信息科学技术学院操作系统实验...

    《ELF文件格式分析.pdf》与elf解析代码

    ELF(Executable and Linkable Format)是Linux和其他类UNIX系统中广泛使用的可执行文件、共享库和对象文件的标准格式。这个格式提供了丰富的信息,包括程序的入口点、符号表、重定位信息等,使得编译器、链接器、...

    ELF解析工具 v1.7(elf格式解析工具)

    支持32位/64位elf文件自适应解析、可解析elf文件头、程序头、节头、字符表、符号表、hash表、版本定义表、版本依赖表、动态信息表等。 更多详细介绍请访问:...

    Linux下一种ELF文件的代码签名验证机制

    【Linux下ELF文件的代码签名验证机制】是针对Linux系统中可执行文件(ELF格式)的安全防护措施。ELF文件是Linux下主要的二进制格式,常常成为恶意代码的目标。传统的Linux系统并不检查代码完整性,这使得恶意修改变...

    Winux病毒感染Linux下ELF文件的分析

    Winux病毒是一种专门针对Linux系统的病毒,其主要特点是能够感染ELF文件,并通过修改这些文件实现自我复制和传播。下面详细介绍Winux病毒是如何感染ELF文件的: 1. **病毒代码注入** - Winux病毒会将自己的代码...

    ELF 文件格式分析-北京大学信息科学技术学院操作系统实验室.7z

    ELF(Executable and Linkable Format)是Linux和许多类UNIX系统中广泛使用的可执行文件、共享库和对象文件的标准格式。北京大学信息科学技术学院操作系统实验室的资料深入解析了这一重要概念,帮助我们理解ELF文件...

    linux下的elf 文件分析

    ELF (Executable and Linkable Format) 是一种被广泛应用于Linux和其他类Unix操作系统中的目标文件格式。它不仅用于存储可执行文件,还包括共享对象文件和目标代码文件。ELF格式的设计旨在支持多样的处理器架构,...

    第7题-ELF文件注入1

    1. **ELF文件格式理解**:ELF(Executable and Linkable Format)是Linux系统中常用的二进制文件格式,包含了程序的入口点(e_entry)、程序头表(program headers)、节区头表(section headers)等信息。了解这些结构...

    Winux病毒感染Linux下ELF文件的分析.pdf

    Winux病毒感染Linux下ELF文件的分析 ...本文对Winux病毒感染Linux下ELF文件的分析可以作为Linux操作系统安全和病毒研究的参考文献。同时,本文也可以作为Linux操作系统开发和安全相关的专业指导。

    ELF文件病毒的分析和编写

    ELF文件病毒是一种针对Linux系统的恶意软件,它利用了ELF(Executable and Linkable Format)文件格式的特性来嵌入自身的代码到合法的可执行文件中。本文将深入探讨ELF文件格式以及如何分析和编写ELF病毒。 首先,...

    ELF 文件格式分析(北京大学实验室出的标准版)

    ELF (Executable and Linkable Format) 是一种广泛用于类UNIX操作系统,如Linux、Solaris等的可执行文件、共享库和核心映像的文件格式。它由电气电子工程师协会(IEEE)和UNIX System Laboratories共同开发,并在1990...

Global site tag (gtag.js) - Google Analytics