Linux獲取so/ko文件版本號教程


一、需要獲取版本號的原因

從使用角度而言,有時只有特定版本的庫才支持某些功能,所以我們需要確定庫文件版本號。

從安全加固角度而言,有些版本存在漏洞有些版本不存在漏洞,所以我們需要獲取版本號以確定當前使用版本是否需要處理。

不過就實際來看,針對庫文件(尤其是ko文件)來發布的漏洞是比較少的,另一方面so和ko文件並沒有強制要求實現版本號所以他們並不一定有版本號。

 

二、手動獲取版本號方法

2.1 so文件手動獲取版本號方法

2.1.1 從文件名獲取版本號

很多so文件都直接將so號寫到文件名中,".so"前面或后面的數字串即是其版本號,如下所示

 

2.1.2 使用readelf讀取SONAME獲取主版本號

如果文件名中沒有版本號,那么退而求其次,通過readelf讀取so的SONAME字段獲取其主版本號。

 

2.2 ko文件手動獲取版本號方法

2.2.1 使用modinfo獲取版本號

ko文件一般不會將版本號放在文件名中,也沒有類似SONAME的字段。在少數的ko文件中會設置version變量可用modinfo讀取,如果沒有那ko文件也就沒有版本號了。

modinfo后可直接接ko文件路徑,但也可以是加載到內核的模塊名,已加載到內核的模塊名可以用lsmod查看。

 

 三、自動化讀取so/ko文件版本python腳本

所謂自動化不過也就是將手動獲取版本號的方法代碼化。腳本使用python3編寫,設置好main中root_dir直接運行,結果會自動保存在so_version.txt和ko_version.txt中

import os
import re
import platform

class ReadLibVersion:
    def __init__(self):
        so_version_file = "so_version.txt"
        ko_version_file = "ko_version.txt"
        self.so_version_file_obj = open(so_version_file,"w+")
        self.ko_version_file_obj = open(ko_version_file,"w+")
        system = platform.system()
        if "Windows" in system:
            self.path_split = "\\"
        else:
            self.path_split = "/"
        self.so_file_pattern = "\.so$"
        self.ko_file_pattern = "\.ko$"

    # 遍歷要掃描的目錄,尋找出目錄下的所有so/ko文件
    def traversal_dir(self,dir):
        dir_contains = os.listdir(dir)
        for tmp in dir_contains:
            tmp_path = f"{dir}{self.path_split}{tmp}"
            if os.path.isfile(tmp_path):
                # 如果是so文件,則調用so版本號獲取函數獲取版本號
                if re.search(self.so_file_pattern,tmp_path) is not None:
                    # 首先從文件名獲取版本號
                    so_version = self.read_so_version_by_name(tmp_path)
                    if so_version != "-":
                        self.so_version_file_obj.writelines(f"{tmp_path}\t\t{so_version}\r\n")
                    else:
                        # 如果從文件名獲取不到版本號,那么就通過readelf讀SONAME獲取主版本號
                        so_version = self.read_so_version_by_readelf(tmp_path)
                        self.so_version_file_obj.writelines(f"{tmp_path}\t\t{so_version}\r\n")
                # 如果是ko文件,則通過modinfo讀取version變量獲取版本號
                elif re.search(self.ko_file_pattern,tmp_path) is not None:
                    ko_version = self.read_ko_version_by_modinfo(tmp_path)
                    self.ko_version_file_obj.writelines(f"{tmp_path}\t\t{ko_version}\r\n")
            elif os.path.isdir(tmp_path):
                sub_dir = tmp_path
                self.traversal_dir(sub_dir)

    # 從文件名獲取so文件版本號
    def read_so_version_by_name(self,file_path):
        file = file_path.split(f"{self.path_split}")[-1]
        ver_pattern = "[.|\d]+\d"
        so_versions = re.findall(ver_pattern,file)
        if len(so_versions) >0:
            so_version = so_versions[0]
        else:
            so_version = "-"
        return so_version
        pass

    # 使用readelf讀SONAME獲取so文件主版本號
    def read_so_version_by_readelf(self,file_path):
        so_version = "-"
        readelf_result = os.popen(f"readelf -d  {file_path} |grep SONAME").read().strip()
        if readelf_result != "":
            so_version = readelf_result.split()[-1]
        return so_version
        pass

    # 使用modinfo讀取version變量獲取ko文件版本號
    def read_ko_version_by_modinfo(self,file_path):
        ko_version = "-"
        modinfo_result = os.popen(f"modinfo {file_path}|grep ^version:").read().strip()
        if modinfo_result != "":
            ko_version = modinfo_result.split()[-1]
        return ko_version
        pass

    def __del__(self):
        self.so_version_file_obj.close()
        self.ko_version_file_obj.close()
        pass


if __name__ == "__main__":
    # 要掃描的目錄
    root_dir = "/usr/lib"
    read_lib_version_obj = ReadLibVersion()
    read_lib_version_obj.traversal_dir(root_dir)

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM