一个程序明白elf格式组成



#include <stdio.h>  
#include <stdlib.h>  
#include <asm/user.h>  
#include <asm/ptrace.h>  
#include <sys/ptrace.h>  
#include <sys/wait.h>  
#include <sys/mman.h>  
#include <dlfcn.h>  
#include <dirent.h>  
#include <unistd.h>  
#include <string.h>  
#include <elf.h>  
#include <android/log.h>  




#include <malloc.h>
#include <string.h>
#include <stdlib.h>
#include <dlfcn.h>


#include <cutils/compiler.h>
#include <cutils/properties.h>


#include <utils/Log.h>












#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <android/log.h>
#include <EGL/egl.h>
#include <GLES/gl.h>
#include <elf.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <termios.h>


#define LOG_TAG "DEBUG"
#define LOGD(fmt, args...) printf(fmt, ##args)  










#define Ser_Printf   printf
#define macdbg_prser printf


#define my_printf printf


static int g_com_fd = -1;






int main(int argc, char** argv);
extern int my_tgkill(int);




/* p_type */
#define PT_NULL_STR "NULL"
/* Program header table entry unused */


#define PT_LOAD_STR "LOAD"
/* Loadable program segment */




#define PT_DYNAMIC_STR  "DYNAMIC"
/* Dynamic linking information */


#define PT_INTERP_STR       "INTERP"
/* Program interpreter */




#define PT_NOTE_STR "NOTE"
/* Auxiliary information */


#define PT_SHLIB_STR "SHLIB"
/* Reserved, unspecified semantics */


#define PT_PHDR_STR "PHDR"
/* Entry for header table itself */


#define PT_TLS_STR "TLS"
/* TLS initialisation image */




#define PT_NUM_STR "NUM"


#define PT_GNU_EH_FRAME_STR "GNU_EH_FRAME"
#define PT_GNU_STACK_STR "GNU_STACK"
#define PT_GNU_RELRO_STR "GNU_RELRO"


#define PT_ARM_EXIDX_STR "EXIDX"




#define HELLO_LIBSF_PATH    "/system/bin/asmhello"




#ifndef PT_ARM_EXIDX
#define PT_ARM_EXIDX 0x70000001
#endif




#define PT_NULL 0 /* Program header table entry unused */
#define PT_LOAD 1 /* Loadable program segment */
#define PT_DYNAMIC 2 /* Dynamic linking information */
#define PT_INTERP 3 /* Program interpreter */
#define PT_NOTE 4 /* Auxiliary information */
#define PT_SHLIB 5 /* Reserved, unspecified semantics */
#define PT_PHDR 6 /* Entry for header table itself */
#define PT_TLS 7 /* TLS initialisation image */
#define PT_NUM 8


#define PT_GNU_EH_FRAME 0x6474e550 /* EH frame segment */
#define PT_GNU_STACK 0x6474e551 /* Indicate executable stack */
#define PT_GNU_RELRO 0x6474e552 /* Make read-only after relocation */


char *get_p_type(int type)
{
    char *pp_type = NULL;
    switch (type)
    {  
      case  PT_NULL:
        pp_type = PT_NULL_STR;
      break;
      case  PT_LOAD:
        pp_type = PT_LOAD_STR;
      break;
      case  PT_DYNAMIC:
        pp_type = PT_DYNAMIC_STR;
      break;
      case  PT_INTERP:
        pp_type = PT_INTERP_STR;
      break;
      case  PT_NOTE:
        pp_type = PT_NOTE_STR;
      break;
      case  PT_SHLIB:
        pp_type = PT_SHLIB_STR;
      break;
      case  PT_PHDR:
        pp_type = PT_PHDR_STR;
      break;
      case  PT_TLS:
        pp_type = PT_TLS_STR;
      break;
      case  PT_NUM:
        pp_type = PT_NUM_STR;
      break;
      case  PT_GNU_EH_FRAME:
        pp_type = PT_GNU_EH_FRAME_STR;
      break;
      case  PT_GNU_STACK:
        pp_type = PT_GNU_STACK_STR;
      break;
      case  PT_GNU_RELRO:
        pp_type = PT_GNU_RELRO_STR;
      break;
      case  PT_ARM_EXIDX:
        pp_type = PT_ARM_EXIDX_STR;
      break;
                
      default:
        pp_type = NULL;
      break;
    }
    return pp_type;
}






int macdbg_dmphex(const char* buff, int len)
{
    int retval = 0; 
    int x, y, tot, lineoff;
    const char* curr;
    
    //Ser_Printf("buff %x.\r\n", buff );


Ser_Printf("\r\n" );
    lineoff = 0;
    curr = buff;
    tot = 0;
    for( x = 0; x+16 < len; ){   
         Ser_Printf("%x\t", lineoff);
         for( y = 0; y < 16; y++ ){
              macdbg_prser("%02x ", (unsigned char)*(curr + y));
         }
         macdbg_prser("  ");
         for( y = 0; y < 16; y++ ){
              char c;
              c = *(curr + y);
              if( c > 31 && c < 127 ){
                  macdbg_prser("%c", c);
              }else{
                  macdbg_prser("%c", '.');
              }
              tot++;
         }
         curr += 16;
         x += 16;
         lineoff+=16;
         macdbg_prser("\r\n");
    }
    
    //do last line


//Ser_Printf("tot %d.\r\n", tot );
//Ser_Printf("len %d.\r\n", len );
    if( tot < len ){
        curr = (buff + tot);
        macdbg_prser("%x\t", lineoff);
        for( y = 0; y < (len - tot); y++ ){
             macdbg_prser("%02x ", (unsigned char)*(curr + y));
        }
        //padding with spaces
        //Ser_Printf("(len - tot) %d.\r\n", (len - tot) );
        if( (len - tot) < 16 ){
            for( y = 0; y < (32 - ((len - tot)*2)); y++ ){
                 macdbg_prser(" ");
            }
        }
        for( y = 0; y < 16-(len - tot); y++ ){
             macdbg_prser(" ");
        }


  
        macdbg_prser("  "); 
  //Ser_Printf("(len - tot) %d.\r\n", (len - tot) );
        for( y = 0; y < (len - tot); y++ ){
            char c;
            c = *(curr + y);
            if( c >31 && c < 127 ){
                macdbg_prser("%c", c);
            }else{
                macdbg_prser("%c", '.');
 //macdbg_prser("%c", c);
            }
        }
    }
    macdbg_prser("\r\n");
    return retval;
}














void old_funpoint(void)
{
    printf( "in old_funpoint.\n" );
}




void new_funpoint(void)
{
    printf( "in new_funpoint.\n" );
}


void* hello_get_module_base(pid_t pid, const char* module_name)
{
    FILE *fp;
    long addr = 0;
    char *pch;
    char filename[32];
    char line[1024];


    if (pid < 0) {
        /* self process */
        snprintf(filename, sizeof(filename), "/proc/self/maps", pid);
    } else {
        snprintf(filename, sizeof(filename), "/proc/%d/maps", pid);
    }


    fp = fopen(filename, "r");


    if (fp != NULL) {
        while (fgets(line, sizeof(line), fp)) {
            if (strstr(line, module_name)) {
                pch = strtok( line, "-" );
                addr = strtoul( pch, NULL, 16 );


                if (addr == 0x8000)
                    addr = 0;


                break;
            }
        }


        fclose(fp) ;
    }


    return (void *)addr;
}






//#define LIBSF_PATH    "/system/lib/libsurfaceflinger.so"










int hook_hello()
{
    //old_funpoint = NULL;
    //LOGD("Orig eglSwapBuffers = %p\n", old_funpoint);            
    void * base_addr = hello_get_module_base(getpid(), HELLO_LIBSF_PATH);
    LOGD("asmhello address = %p\n", base_addr);
    //macdbg_dmphex(base_addr, 0x1000);                                                      
    int fd;
    fd = open(HELLO_LIBSF_PATH, O_RDONLY);
    if( -1 == fd ){
        LOGD("error\n");
        return -1;   
    }

    Elf32_Ehdr ehdr;
    read(fd, &ehdr, sizeof(Elf32_Ehdr));


    //macdbg_dmphex(&ehdr, sizeof(Elf32_Ehdr));




    //以下代码主要分析段头数据结构
    unsigned long shdr_addr = ehdr.e_shoff;
    int shnum = ehdr.e_shnum;
    //Number of section headers
    //段头项目的个数
    int shent_size = ehdr.e_shentsize;
    //Section header entry size
    //每一个段头项目的大小      
     
    unsigned long stridx = ehdr.e_shstrndx;


    Elf32_Shdr shdr;
    //my_printf( "ehdr.e_phoff = %x\n", ehdr.e_phoff );
    //程序头偏移地址,直接跟随ELF Header 0x34
    //ELF Header占用52字节,描述程序头,段头,体系结构等信息
    //my_printf( "ehdr.e_phnum = %x\n", ehdr.e_phnum );
    //程序头结构体的个数
    //my_printf( "ehdr.e_phentsize = %x\n", ehdr.e_phentsize );
    //程序头结构体每一个的大小

    //my_printf( "shdr_addr = %x\n", shdr_addr );
    //段头的偏移地址
    //my_printf( "shnum = %x\n", shnum );
    //段头结构体的个数
    //my_printf( "shent_size = %x\n", shent_size );
    //每一个段头结构体的大小
    //my_printf( "stridx = %x\n", stridx );
    //Section header string table index: 23
    //在所有段头结构体内,有一个叫"串表"的结构体
    //此结构体在所有段头结构体的个数中的索引值 指向最后一个段头结构体
    //此调试信息可以看出-->shnum = 18 shent_size = 28 stridx = 17


    //my_printf( "shdr_addr = %x\n", shdr_addr );
    //my_printf( "shdr_addr + stridx * shent_size = %x\n", shdr_addr + stridx * shent_size );
    lseek(fd, shdr_addr + stridx * shent_size, SEEK_SET);
    //文件指针定位到"串表"段头结构体
    read(fd, &shdr, shent_size);
    //读取"串表"段头结构体






  
    char *string_table = (char *)malloc(shdr.sh_size);
    //my_printf( "string_table = %x\n", string_table );
    //my_printf( "shdr.sh_size = %x\n", shdr.sh_size );
    //section size,串表的大小 描述了串表占用的存储空间的大小
    //my_printf( "shdr.sh_offset = %x\n", shdr.sh_offset );
    //file offset 串表在整个elf文件中的偏移位置
      
                 
    lseek(fd, shdr.sh_offset, SEEK_SET);           
    read(fd, string_table, shdr.sh_size);
    lseek(fd, shdr_addr, SEEK_SET);
    //指向段头结构体存储的首地址
    
     
    //elf内存结构描述如下:
    //-->开始
    //ELF Header 0x34
    //程序头结构体存储位置:
    //PHDR->第一个程序头结构体
    //描述了总共有多少个程序头结构体
    //INTERP->第二个程序头结构体
    //描述了linker在系统中的位置                      
                                                       
    //整个串表   
    //段头结构体存储位置:
    //第一个段头表入口为空
    //->Section header table entry unused
    
    //.interp   
    //.dynsym
    //.dynstr
    //.hash
    //.rel.dyn
    //.rel.plt
    //.plt
    
    //.text
    //->函数执行代码 
    
    //.note.android.ident
    //.ARM.exidx
    //->部分函数地址可以在此用公式获取



    //.ARM.extab
    
    //.rodata
    //->全局const变量 字符串等 printf("test string");
    //->程序本身的一些表 看情况
                 
    //.preinit_array
    //.init_array
    //.fini_array
    //.dynamic
    
    //.got
    //->动态库相关的函数地址
    
    //.bss
    //->未初始化的全局变量
    
    //.comment
    //.note.gnu.gold-version
    //.ARM.attributes
    //.gnu_debuglink
    
    //.shstrtab
    //->串表描述
    //-->结束    


    

    int i,j;                          
    uint32_t out_addr = 0;                    
    uint32_t out_size = 0;             
    uint32_t got_item = 0;                
    int32_t got_found = 0;     
    int32_t get_off = 0;   


    //my_printf( "shnum = %x\n", shnum );
    //段头结构体的个数 0x18
    //my_printf( "shent_size = %x\n", shent_size );
    //每一个段头结构体的大小 0x28
    for( j = 0; j < shnum; j++ ){
         read(fd, &shdr, shent_size);
         //macdbg_dmphex(&shdr, sizeof(Elf32_Shdr));  
         //my_printf( "shdr.sh_type = %x\n", shdr.sh_type );
         int name_idx = shdr.sh_name;  
         if( shdr.sh_type == SHT_PROGBITS ){
             //my_printf( "get Section header entry %s\n", &string_table[name_idx] );
             //my_printf( "shdr.sh_addr = %x\n", shdr.sh_addr );
             //my_printf( "shdr.sh_offset = %x\n", shdr.sh_offset );
             //my_printf( "shdr.sh_size = %x\n", shdr.sh_size );
             //my_printf( "shdr.sh_entsize = %x\n", shdr.sh_entsize );
             if( strcmp(&(string_table[name_idx]), ".got.plt") == 0 || 
                 strcmp(&(string_table[name_idx]), ".got") == 0 ){
                 out_addr = base_addr + shdr.sh_addr;
                 out_size = shdr.sh_size;
                //LOGD("out_addr = %lx, out_size = %lx\n", out_addr, out_size);
 //my_printf( "old_funpoint = %x\n", old_funpoint );
 //my_printf( "new_funpoint = %x\n", new_funpoint );
 //my_printf( "main = %x\n", main );
                for (i = 0; i < out_size; i += 4) {
                    got_item = *(uint32_t *)(out_addr + i);
//my_printf( "got_item = %x\n", got_item );
 
                    if (got_item == old_funpoint) {
                        LOGD("Found eglSwapBuffers in got\n");
                        got_found = 1;
                        uint32_t page_size = getpagesize();
                        uint32_t entry_page_start = (out_addr + i) & (~(page_size - 1));
                        mprotect((uint32_t *)entry_page_start, page_size, PROT_READ | PROT_WRITE);
                        *(uint32_t *)(out_addr + i) = new_funpoint;
my_printf( "shnum = %x\n", shnum );
                        break;
                    } else if (got_item == new_funpoint) {
                        LOGD("Already hooked\n");
                        break;
                    }
                }
                if (got_found) { 
                    //break;
                }
            }else if( strcmp(&(string_table[name_idx]), ".rodata") == 0 ) {
                //const,固定字符串等在此段找
                my_printf("get .rodata\n");
            }

        }else if (shdr.sh_type == SHT_NULL) {
            //Section header table entry unused
            //第一个段头表入口为空
            my_printf("get null\n");
        }else if (shdr.sh_type == PT_ARM_EXIDX) {
            //Section header table entry unused
            //第一个段头表入口为空
            
            my_printf( "macdbg_dmphex = %x\n", macdbg_dmphex );
            my_printf( "old_funpoint = %x\n", old_funpoint );
            my_printf( "new_funpoint = %x\n", new_funpoint );
            my_printf( "hello_get_module_base = %x\n", hello_get_module_base );
            my_printf( "hook_hello = %x\n", hook_hello );
            my_printf( "main = %x\n", main );
            my_printf( "my_tgkill = %x\n", my_tgkill );
 
            //my_printf( "get .ARM.exidx\n" );  
            //my_printf( "string_table[name_idx] = %s\n", &string_table[name_idx] );
            //my_printf( "shdr.sh_addr = %x\n", shdr.sh_addr );
            //my_printf( "shdr.sh_offset = %x\n", shdr.sh_offset );
            //my_printf( "shdr.sh_size = %x\n", shdr.sh_size );
            //my_printf( "shdr.sh_entsize = %x\n", shdr.sh_entsize );
            out_addr = base_addr + shdr.sh_addr;
            out_size = shdr.sh_size;
            my_printf("out_addr = %lx, out_size = %lx\n", out_addr, out_size); 
            
            for( i = 0; i < out_size; i += 8 ){
                 get_off = *(int32_t *)(out_addr+i);  
                 got_item = *(uint32_t *)(out_addr + i + 4);
                 //my_printf( "get_off = %x\n", get_off );
  //my_printf( "get_off1 = %x\n", shdr.sh_addr - (~get_off +1)&0xffff )+i;
  my_printf( "func point = %x\n", shdr.sh_addr + i - ((~get_off +1)&0xffff) + base_addr );
  //shdr.sh_addr + i 描述函数指针的虚拟地址的偏移位置的虚拟地址
  //*(shdr.sh_addr + i)描述函数指针的虚拟地址的偏移位置
  //(相对于描述函数指针的虚拟地址的虚拟地址) 为负数
  //base_addr 该进程内核内存映射的基地址
                 //my_printf( "got_item = %x\n\n", got_item );
  //my_printf( "got_item = %d\n", got_item );
            }
        }else{                                           
            //int name_idx = shdr.sh_name;                      
//section name (.shstrtab index)                 
  //my_printf( "name_idx = %x\n", name_idx );
  //my_printf( "Section header entry %s\n", &string_table[name_idx] );


  //my_printf( "shdr.sh_addr = %x\n", shdr.sh_addr );
  //my_printf( "shdr.sh_offset = %x\n", shdr.sh_offset );
  //my_printf( "shdr.sh_size = %x\n", shdr.sh_size );
  //my_printf( "shdr.sh_entsize = %x\n", shdr.sh_entsize );
                
        }
    }


    free(string_table);


    //以下代码主要分析程序头数据结构
    shdr_addr = ehdr.e_phoff;
    //首个程序头项目的偏移
    shnum = ehdr.e_phnum;
    //程序头项目的个数
    shent_size = ehdr.e_phentsize;
    //每一个程序头项目的大小      
     
    //stridx = ehdr.e_shstrndx;


Elf32_Phdr program_shdr;
    my_printf( "ehdr.e_phoff = %x\n", ehdr.e_phoff );
    //程序头偏移地址,直接跟随ELF Header 0x34
    //ELF Header占用52字节,描述程序头,段头,体系结构等信息
    my_printf( "ehdr.e_phnum = %x\n", ehdr.e_phnum );
    //程序头结构体的个数
    my_printf( "ehdr.e_phentsize = %x\n", ehdr.e_phentsize );
    shnum = ehdr.e_phnum;

    lseek(fd, ehdr.e_phoff, SEEK_SET);       
    char *p_type_tmp;
    for( j = 0; j < shnum; j++ ){
         read(fd, &program_shdr, sizeof(Elf32_Phdr));
         macdbg_dmphex(&program_shdr, sizeof(Elf32_Phdr));
         p_type_tmp = get_p_type(program_shdr.p_type);
         my_printf( "program_shdr.p_type = %s\n", p_type_tmp );
         
         my_printf( "program_shdr.p_offset = %x\n", program_shdr.p_offset );
         my_printf( "program_shdr.p_vaddr = %x\n", program_shdr.p_vaddr );
         my_printf( "program_shdr.p_paddr = %x\n", program_shdr.p_paddr );
         my_printf( "program_shdr.p_filesz = %x\n", program_shdr.p_filesz );
         my_printf( "program_shdr.p_memsz = %x\n", program_shdr.p_memsz );
         my_printf( "program_shdr.p_flags = %x\n", program_shdr.p_flags );
         my_printf( "program_shdr.p_align = %x\n", program_shdr.p_align );
         if( strcmp(p_type_tmp, PT_INTERP_STR) == 0 ){
             //程序解释器 加载器
             //描述了此程序的加载器在系统中的位置
             long temp_file_position;
             temp_file_position = lseek(fd, 0, SEEK_CUR);
             char *linker = (char *)malloc(program_shdr.p_memsz);              
             lseek(fd, program_shdr.p_offset, SEEK_SET);           
             read(fd, linker, program_shdr.p_memsz);
             my_printf( "program loader = %s\n", linker );
             free(linker);
             lseek(fd, temp_file_position, SEEK_SET);
         }else if( strcmp(p_type_tmp, PT_PHDR_STR) == 0 ){
             //描述了此程序的程序头的整体大小
             my_printf( "get program head = %x\n", program_shdr.p_memsz );
         }


 
    }




    //lseek(fd, shdr_addr, SEEK_SET);
    //指向段头结构体存储的首地址



    close(fd);
    return 0;
}










int global_test = 123;


int main(int argc, char** argv) 
{
    int ret;
    //printf("asmhello.c main.\n");


    //printf( "&global_test = %x.\n", &global_test );


//printf( "global_test = %x.\n", global_test );


hook_hello();



#if 0
    int _src;
    _src =1;
    asm volatile(
            "nop\n"
            "mov r0, r0\n"
            "mov r0, %0\n"
         :: "r" (_src) : "r0", "r1", "r2", "r3");
         //:输出:输入:破坏的寄存器
         //"r" 告诉编译器使用寄存器处理输入变量
                    
    ret = -1;
    ret = my_tgkill(3);
    printf( "ret = %d\n", ret );


old_funpoint();
new_funpoint();
    hook_hello();


old_funpoint();
new_funpoint();
#endif
    return 3;

}






只能这样了,



Section Headers:
  [Nr] Name              Type            Addr     Off    Size   ES Flg Lk Inf Al
  [ 0]                   NULL            00000000 000000 000000 00      0   0  0
  [ 1] .interp           PROGBITS        00000134 000134 000013 00   A  0   0  1
  [ 2] .dynsym           DYNSYM          00000148 000148 0001e0 10   A  3   1  4
  [ 3] .dynstr           STRTAB          00000328 000328 000134 00   A  0   0  1
  [ 4] .hash             HASH            0000045c 00045c 0000c4 04   A  2   0  4
  [ 5] .rel.dyn          REL             00000520 000520 000038 08   A  2   0  4
  [ 6] .rel.plt          REL             00000558 000558 0000b0 08   A  2   7  4
  [ 7] .plt              PROGBITS        00000608 000608 00011c 00  AX  0   0  4
  [ 8] .text             PROGBITS        00000724 000724 000798 00  AX  0   0  4
  [ 9] .note.android.ide PROGBITS        00000ebc 000ebc 000018 00   A  0   0  4
  [10] .ARM.exidx        ARM_EXIDX       00000ed4 000ed4 000038 08  AL  8   0  4
  [11] .ARM.extab        PROGBITS        00000f0c 000f0c 000018 00   A  0   0  4
  [12] .rodata           PROGBITS        00000f24 000f24 000334 01 AMS  0   0  1
  [13] .preinit_array    PREINIT_ARRAY   00002e68 001e68 000008 00  WA  0   0  4
  [14] .init_array       INIT_ARRAY      00002e70 001e70 000008 00  WA  0   0  4
  [15] .fini_array       FINI_ARRAY      00002e78 001e78 000008 00  WA  0   0  4
  [16] .dynamic          DYNAMIC         00002e80 001e80 000100 08  WA  3   0  4
  [17] .got              PROGBITS        00002f80 001f80 000080 00  WA  0   0  4
  [18] .bss              NOBITS          00003000 002000 000004 00  WA  0   0  4
  [19] .comment          PROGBITS        00000000 002000 000010 01  MS  0   0  1
  [20] .note.gnu.gold-ve NOTE            00000000 002010 00001c 00      0   0  4
  [21] .ARM.attributes   ARM_ATTRIBUTES  00000000 00202c 00003c 00      0   0  1
  [22] .gnu_debuglink    PROGBITS        00000000 002068 000010 00      0   0  1
  [23] .shstrtab         STRTAB          00000000 002078 0000ec 00      0   0  1
Key to Flags:
  W (write), A (alloc), X (execute), M (merge), S (strings)
  I (info), L (link order), G (group), T (TLS), E (exclude), x (unknown)
  O (extra OS processing required) o (OS specific), p (processor specific)


There are no section groups in this file.


Program Headers:
  Type           Offset   VirtAddr   PhysAddr   FileSiz MemSiz  Flg Align
  PHDR           0x000034 0x00000034 0x00000034 0x00100 0x00100 R   0x4
  INTERP         0x000134 0x00000134 0x00000134 0x00013 0x00013 R   0x1
      [Requesting program interpreter: /system/bin/linker]
  LOAD           0x000000 0x00000000 0x00000000 0x01258 0x01258 R E 0x1000
  LOAD           0x001e68 0x00002e68 0x00002e68 0x00198 0x0019c RW  0x1000
  DYNAMIC        0x001e80 0x00002e80 0x00002e80 0x00100 0x00100 RW  0x4
  GNU_STACK      0x000000 0x00000000 0x00000000 0x00000 0x00000 RW  0
  EXIDX          0x000ed4 0x00000ed4 0x00000ed4 0x00038 0x00038 R   0x4
  GNU_RELRO      0x001e68 0x00002e68 0x00002e68 0x00198 0x00198 RW  0x4


 Section to Segment mapping:
  Segment Sections...
   00     
   01     .interp 
   02     .interp .dynsym .dynstr .hash .rel.dyn .rel.plt .plt .text .note.android.ident .ARM.exidx .ARM.extab .rodata 
   03     .preinit_array .init_array .fini_array .dynamic .got .bss 
   04     .dynamic 
   05     
   06     .ARM.exidx 
   07     .preinit_array .init_array .fini_array .dynamic .got 





具体这些程序头、段头的使用,估计得仔细研究linux的内核源代码了(loader,linker),这个是用户层的。

还有/system/bin/linker文件的源代码。









评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值