美文网首页
动态链接后ELF中的Section Name

动态链接后ELF中的Section Name

作者: None_Ling | 来源:发表于2019-04-29 17:58 被阅读0次

    背景

    在So动态链接后,读取ELF文件,发现无法读取Section Header中的名称列表。即,无法在EShdr中根据e_shstrndx找到Section对应的名字。

    可是在readelf -a lib.so中,可以根据Section Header读取到Section对应的名称。

    Section Header String Table Index

    而读取出来的结果如下:


    Section Header

    其中,shstrtabstrtab的类型都是STRTAB,但是shstrtab仅仅只保存Section Name的字符串表,而strtab则包括其他的变量名、符号名等的字符串表。

    问题

    • 为什么在运行时无法通过Section Header中的sh_name来找到对应的名称?

      Section Header的
    • 为什么要分为strtabshstrtab两个字符串表?

    原因

    从运行时的日志来看

    • 根据ELF头中的e_shoff找到ELF_SHDR
      • libart.so加载后的位置在753042b000-7530a14000
      • 加载后的基址为:753042b000PHDR的地址为:753042b040
      • 计算得到的SHDR的地址为7530b55520

    运行日志:

    libs line :753042b000-7530a14000 r-xp 00000000 fd:00 3439 /system/lib64/libart.so
    base_addr:753042b000   PHDR :753042b040   shdr_offset:72a520
    SHDR :7530b55520  shstr:7530b55ba0
    

    运行时日志是通过/proc/self/maps中获取libart.so得到的基址,与上面通过readelf读取的ELF文件并不是同一个!该日志的基址和偏移量与上面的图无关。

    运行后的结果可知:
    通过e_shoff所计算的出来的SHDR的地址已经超出So加载的地址了。

    SHDR- libart.so的页结束地址 = 7530b55520 - 7530a14000 = 141520

    而在运行时候的动态链接是根据Segment来加载So中的文件,原因是希望尽可能小的使用内存页面,并且提升加载速度。

    ELF链接与执行时视图

    于是查看程序头部分,发现LOAD类型的段中,仅仅只有.dynstr这个字符串表会被加载到内存中。

    程序头

    也就是说:

    在So动态链接到内存中时,.shstrtab.strtab这两个Table是并没有加载到内存中的。ld仅仅只会加载.dynstr这个Table就够用了。

    并且从执行视图来看,ELF也不一定会有Section Header Table。

    而且单个Section可能属于多个Segment

    • 例如got这个Section就属于LOAD以及GNU_RELRO这两个Segment

    从IDA Pro打开的角度来看

    从Section Headers中可以看到:

    • strtaboffset395ac,大小为170c
    • shstrtaboffset3acb8,并且大小为194

    可以看到strtab之后紧接着就是shstrtab
    395ac+170c = 3acb8

    打开IDA Pro可以看到在文件的395ac处就是strtab的字符串表:

    strtab

    而在文件的3acb8处,可以看到是Section Header Name的字符串:

    shstrtab

    结论

    shstrtabstrtab这两个表仅仅只是链接后保存在So文件中的,而在链接之后的执行视图层面,这两个字符串表不会被加载到内存中。

    readelf这个程序中,会在文件中根据shstrtab表的偏移量来查找Section对应的名称,然后输出文案。

    并且,在执行视图中,可能没有SHDR,所以在链接完的文件中可以根据SHDR中的偏移量来找到对应的名字,而在加载到内存之后的执行视图中,不能按照SHDR来查找Section的名字了。

    后记

    Android GOT Hook该文中,则是通过对GOT表进行Hook,而查找GOT表的方式则是通过Section Header以及shstr来找到对应的Got表的偏移地址。

    而在本人测试的过程中发现这方案在Runtime时并不可行,在动态链接后,Section Header有可能不会加载,因为Section Header的加载可有可无,可能有些ROM会加载,有些ROM不会加载。

    ELF中可以被修改又不影响执行的区域该文中,本人比较认同。因为Program Header已经将需要加载的Section都决定了,Section Header只是为了readelf这种方便读取ELF文件而存在。减少加载也可以减少内存以及文件映射所带来的损耗。

    所以对于Got表的偏移量可以在静态的时候,通过readelf来读取Got表的偏移量,在Runtime的时候,通过基址加偏移量来获取Got表的地址。Android下的GOT表Hook实现这篇文章描述了3中Got表Hook的方式。

    相关文章

      网友评论

          本文标题:动态链接后ELF中的Section Name

          本文链接:https://www.haomeiwen.com/subject/suaynqtx.html