恢复文件管理器中鼠标双击运行ELF可执行文件的功能

新手涉及到的教学或入门贴,推荐新手必看,版主维护
回复
头像
astolia
论坛版主
帖子: 5256
注册时间: 2008-09-18 13:11
送出感谢: 1 次
接收感谢: 888 次

恢复文件管理器中鼠标双击运行ELF可执行文件的功能

#1

帖子 astolia » 2021-09-02 14:08

自从ubuntu 16.10开始,gcc包在编译时开启了--enable-default-pie配置项,导致用gcc在编译时是默认开启-fPIE和-pie的。这样一来,用gcc编译出来的可执行文件在ELF文件头中的类型设置成了shared,对应的mime类型成了和各种.so库一样的application/x-sharedlib而非以前的application/x-executable。

这种类型的可执行文件,在大多情况下也不会对用户造成影响。因为在图形环境下,一般是通过启动器(.desktop文件)来启动程序的,并不会有什么变化,而命令行下面以文件路径执行也不存在问题。但如果想要在图形环境下的文件管理器中以鼠标双击的方式运行,就不太行了,因为很多文件管理器(尤其是基于GTK的)只认application/x-executable类型。

如果有程序的源代码,倒是可以自己给gcc加上-fno-pie和-no-pie参数重新编译,这样编译出来的可执行文件的mime类型仍然是application/x-executable。不过重新编译毕竟是个麻烦事儿,不用pie也引入了一些安全隐患,更别说需要双击执行的程序不见得能找到源代码。

所以最好的方法,就是让linux能将编译时开启了pie编译选项的可执行文件仍然认成application/x-executable

具体方法如下:
用文本编辑器以root权限打开 /usr/share/mime/packages/freedesktop.org.xml,找到其中如下一段

代码: 全选

  <mime-type type="application/x-executable">
    <comment>executable</comment>
    <comment xml:lang="af">uitvoerbaar</comment>
   ... 很多的comment ....
    <comment xml:lang="zh-TW">可執行檔</comment>
    <generic-icon name="application-x-executable"/>
    <magic priority="40">
      <match type="string" value="\177ELF" offset="0">
        <match type="byte" value="1" offset="5">
          <match type="little16" value="2" offset="16"/>
        </match>
      </match>
      <match type="string" value="\177ELF" offset="0">
        <match type="byte" value="2" offset="5">
          <match type="big16" value="2" offset="16"/>
        </match>
      </match>
      <match type="string" value="MZ" offset="0"/>
      <match type="little16" value="0x521c" offset="0"/>
      <match type="host16" value="0420" offset="0"/>
      <match type="host16" value="0421" offset="0"/>
      <match type="little16" value="0603" offset="0"/>
    </magic>
  </mime-type>
然后在其中<generic-icon name="application-x-executable"/>和<magic priority="40">两行之间,加上下面一段

代码: 全选

    <magic priority="60">
      <match type="string" value="\177ELF" offset="0"><match type="byte" value="1" offset="4"><match type="byte" value="1" offset="5"><match type="little16" value="3" offset="16"><match type="little32" value="52" offset="28"><match type="little32" value="3" offset="84"/></match></match></match></match></match>
      <match type="string" value="\177ELF" offset="0"><match type="byte" value="2" offset="4"><match type="byte" value="1" offset="5"><match type="little16" value="3" offset="16"><match type="little32" value="64" offset="32"><match type="little32" value="0" offset="36"><match type="little32" value="3" offset="120"/></match></match></match></match></match></match>
    </magic>
保存文件, 再运行以下命令更新mime数据库

代码: 全选

sudo update-mime-database /usr/share/mime

==========================================================

稍微解释一下上面添加的内容。基本的xml文件格式就不说了。

依据mime类型文件格式规范 https://specifications.freedesktop.org/ ... -0.21.html ,用<magic>元素来匹配文件中特定位置的字节,如果能匹配上,就将对应的mime类型加入备选列表,此类型的优先级为priority属性指定的数值。以备选列表中优先级最大的类型作为最终的mime类型。由于同文件中application/x-sharedlib类型的优先级被设置为50,所以需要选一个更大一点的值,我设置成了60。

后面的两行<match>元素,参考ELF文件头格式( https://wiki.osdev.org/ELF#Header ),将其中的一行展开进行详细解说。

代码: 全选

      <match type="string" value="\177ELF" offset="0">          <!-- ELF文件格式的Magic number -->
        <match type="byte" value="1" offset="4">                <!--  1 = 32位, 2 = 64位  -->
          <match type="byte" value="1" offset="5">              <!-- 大小端:1 = little endian, 2 = big endian   -->
            <match type="little16" value="3" offset="16">       <!-- 类型:shared  -->
              <match type="little32" value="52" offset="28">    <!-- Program header表的起始位置,52 =  紧接在ELF文件头之后  -->
                <match type="little32" value="3" offset="84"/>  <!-- Program header表中第二段的段类型,3 = interp ,位置84 = 起始位置52+第一段长度32-->
              </match>
            </match>
          </match>
        </match>
      </match>
可执行文件,和一般的动态链接库.so,虽然都是shared类型,但可执行文件中的program header表中会包含interp段。我们就靠这一点来区分的。

当然,上面的两行匹配规则并不完美,只能匹配到一般情况下用gcc编译出来的可执行文件。这一般情况是指
1、Program header紧接ELF header
2、interp段位于Program header表中第二项
如果不符合这两点,就匹配不上,需要根据具体文件添加新的匹配规则。可以使用readelf -h xxx和readelf -l xxx来查看具体的变化

另外这两行是针对x86平台这种采用小端模式的,如果是在大端模式的平台上,还需要将little16/32改成big16/32,针对64位规则的offset="32"和offset="36"的值对调一下

最后再补充一点,linux上的程序判断mime类型,并不一定会用上面提到的freedesktop.org提供的mime数据库。像是file命令,就用的是libmagic库,它的数据库又是另外的文件。所以经过上面的修改后,用mimetype xxx会列出application/x-executable,而用20.04中的file -i xxx仍然显示application/x-sharedlib。不过这和本文主旨无关了
回复

回到 “教学和常见问答”