快速读出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’
使用效果如下:
在这里插入图片描述

  • 6
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Linux内核消息队列是一种特定的数据结构,由内核提供,并通过维护这个数据结构来实现消息的传递。消息队列具有以下特点:可以实现消息的随机查询,满足队列的特点但不一定要以先进先出的次序读取,可以按消息的类型读取;允许一个或多个进程向它写入或者读取消息;从消息队列读出消息后,消息队列的数据会被删除;消息队列是面向记录的,其的消息具有特定的格式以及特定的优先级;只有内核重启或人工删除时,该消息才会被删除,否则消息队列会一直存在于内存。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [Linux进程间通信——消息队列](https://blog.csdn.net/m0_53267045/article/details/127660444)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *2* *3* [Linux消息队列](https://blog.csdn.net/xiaozuo666/article/details/80546754)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值