查问题时发现全局变量能读出来会提高效率,于是考虑从怎么读出内核态的全局变量,脚本如下
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 = f.read(sec_header_size)
note_len = hex(read_number(sec_header[32:40]))
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(sections[-1])data_start = ((elf_header_len + sec_header_num * sec_header_size + int(note_len,16)) + 4095) // 4096base = int('0xfffffc0000000000', 16)
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)return addr - base + data_startraise 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 += chch = f.read(1)return retelif 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))while True:import sysimport reimport ossys.stdin.flush()msg = input("输入:").strip()try:path, type = msg.split(':')offsets = []bound = path.find('(')while bound != -1:offsets.append(int(path[:bound].strip()))path = path[bound+1: path.rfind(')')]bound = path.find('(')offsets.reverse()start_addr = path.strip()if start_addr.startswith('0x'):start_addr = int(start_addr, 16)elif re.search(r'[a-z,A-Z]+', start_addr) is None:start_addr = int(start_addr)else: # is varret = os.popen("cat /proc/kallsyms | grep \"" + start_addr + "\" | awk '{print $1,$3}'").read().strip()if ret == '':print("no symbol " + start_addr + " found, please load module first")continueret = [i.split(' ') for i in ret.split('\n')]if len(ret) == 1:start_addr = int(ret[0][0], 16)else:find_exact = Falsefor it in ret:if it[1] == start_addr:start_addr = int(it[0], 16)find_exact = Truebreakif not find_exact:print(f"find {len(ret)} candidates: ")for it in ret:print(f" {it[1]}")continuestart_offset = addr_to_offset(start_addr)for off in offsets:start_addr = read_offset_value(start_offset, 'u64')start_offset = addr_to_offset(start_addr) + offprint(read_offset_value(start_offset, type))except Exception as e:print(e)
使用效果如下: