快速读出linux 内核中全局变量

查问题时发现全局变量能读出来会提高效率,于是考虑从怎么读出内核态的全局变量,脚本如下

f = open("/proc/kcore", 'rb')
f.seek(4) # skip magic
assert f.read(1) == b'\x02' # 64 位

def read_number(bytes):
    return int.from_bytes(bytes, 'little', signed=False)

elf_header_len = 64
f.seek(elf_header_len - 10)
sec_header_size = read_number(f.read(2))
sec_header_num = read_number(f.read(2))

f.seek(elf_header_len + sec_header_size) # ignore note section
sections = []
for i in range(1, sec_header_num):
    sec_header = f.read(sec_header_size)
    sections.append({
        'offset': hex(read_number(sec_header[8:16])),
        'vaddr': hex(read_number(sec_header[16:24])),
        'size': hex(read_number(sec_header[32:40])),
    })
    print(f"section {i}: " + str(sections[-1]))

def addr_to_offset(addr):
    for sec in sections:
        vaddr = int(sec['vaddr'], 16)
        size = int(sec['size'], 16)
        if addr >= vaddr and addr < vaddr + size:
            return int(sec['offset'], 16) + (addr - vaddr)
    raise Exception("ilegel_addr: " + hex(addr))


def read_offset_value(offset, type):
    support_types = ['u8', 'u16', 'u32', 'u64', 's8', 's16', 's32', 's64', 'string','x8','x16','x32','x64']
    if type not in support_types:
        raise Exception("type should be in " + str())
    f.seek(offset)

    if type == 'string':
        ret = b''
        ch = f.read(1)
        while ch != b'\x00':
            ret += ch
            ch = f.read(1)
        return ret
    elif type.startswith('s'):
        return int.from_bytes(f.read(int(type[1:]) // 8), 'little', signed=True)
    elif type.startswith('u'):
        return int.from_bytes(f.read(int(type[1:]) // 8), 'little', signed=False)
    else: # 'x'
        return hex(int.from_bytes(f.read(int(type[1:]) // 8), 'little', signed=False))


def split_to_three_part(path):
    path = path.strip()
    prefixes = []
    suffixes = []
    prefix_bound = path.find('(')
    suffix_bound = path.rfind(')')
    while prefix_bound != -1:
        prefix = eval(path[:prefix_bound])
        prefixes.append(prefix)
        if suffix_bound == -1:
            raise Exception(f"unmatch backet for {path}")
        suffix = path[suffix_bound+1:]
        suffix = eval(suffix) if suffix else 0
        suffixes.append(suffix)
        path = path[prefix_bound+1:suffix_bound].strip()
        prefix_bound = path.find('(')
        suffix_bound = path.rfind(')')
    plus_start = path.find('+')
    if plus_start == -1:
        plus_start = len(path)
    minus_start = path.find('-')
    if minus_start == -1:
        minus_start = len(path)
    middle = path[:min(plus_start, minus_start)].strip()
    middle_part2 = path[len(middle):]
    middle_part2 = eval(middle_part2) if middle_part2 else 0
    prefixes.reverse()
    suffixes.reverse()
    return prefixes, middle, middle_part2, suffixes
        

while True:
    import sys
    import re
    import os
    sys.stdin.flush()
    msg = input("输入:").strip()
    try:
        path, type = msg.split(':')
        prefixes, middle, middle_part2, suffixes = split_to_three_part(path)

        if middle.startswith('0x') or re.search(r'[a-z,A-Z]+', middle) is None:
            start_addr = eval(middle)
        else: # is variable name
            ret = os.popen("cat /proc/kallsyms | grep \"" + middle + "\" | awk '{print $1,$3}'").read().strip()
            if ret == '':
                raise Exception("no symbol " + middle + " found, please load module first")
            ret = [i.split(' ') for i in ret.split('\n')]
            if len(ret) == 1:
                start_addr = int(ret[0][0], 16)
            else:
                find_exact = False
                for it in ret:
                    if it[1] == start_addr:
                        start_addr = int(it[0], 16)
                        find_exact = True
                        break
                if not find_exact:
                    print(f"maybe you means:")
                    for it in ret:
                        print(f"  {it[1]}")
                    print(f"find {len(ret)} candidates.")
                    continue

        start_offset = addr_to_offset(start_addr + middle_part2)
        for pre, suf in zip(prefixes, suffixes):
            start_addr = read_offset_value(start_offset, 'u64')
            start_offset = pre + addr_to_offset(start_addr) + suf
        print(read_offset_value(start_offset, type))
    except Exception as e:
        print(e)


输入的格式与 kprobe 的格式类似:+/-偏移(地址)+/-偏移:输出类型
输出类型有:‘u8’, ‘u16’, ‘u32’, ‘u64’, ‘s8’, ‘s16’, ‘s32’, ‘s64’, ‘string’,‘x8’,‘x16’,‘x32’,‘x64’
使用效果如下:
在这里插入图片描述

相关推荐

  1. 在 C++ 局部变量全局变量

    2024-07-14 00:22:03       60 阅读
  2. linux 创建全局快捷方式

    2024-07-14 00:22:03       51 阅读
  3. linux内核网络“每日读书

    2024-07-14 00:22:03       40 阅读
  4. Linux 系统启动时设置一个全局环境变量

    2024-07-14 00:22:03       28 阅读
  5. 微信小程序全局变量的应用

    2024-07-14 00:22:03       52 阅读
  6. vue3集成sass实现全局scss样式变量

    2024-07-14 00:22:03       49 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-07-14 00:22:03       67 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-07-14 00:22:03       72 阅读
  3. 在Django里面运行非项目文件

    2024-07-14 00:22:03       58 阅读
  4. Python语言-面向对象

    2024-07-14 00:22:03       69 阅读

热门阅读

  1. 使机器人在执行任务倒快递

    2024-07-14 00:22:03       18 阅读
  2. 基于FPGA设计基础知识

    2024-07-14 00:22:03       21 阅读
  3. hot100

    2024-07-14 00:22:03       17 阅读
  4. Zookeeper

    2024-07-14 00:22:03       15 阅读
  5. 用GPT 4o提高效率

    2024-07-14 00:22:03       16 阅读
  6. 商汤:带来实时的流式多模态AI交互体验

    2024-07-14 00:22:03       21 阅读
  7. hnust 1803: 二叉树遍历1

    2024-07-14 00:22:03       24 阅读