# 一种内核6.0之后快速定位kallsyms symbols的方法 Linux内核6.0后将kallsyms symbols引入了vmcoreinfo[1],具体函数为`crash_save_vmcoreinfo_init()` 主要功能是初始化vmcoreinfo。vmcoreinfo用于在系统发生crash时,保存关键的调试信息。在IDA加载无符号表的vmlinux时,搜索kallsyms symbols的字符串查找引用即可定位到`crash_save_vmcoreinfo_init()`函数中如下代码段: ```asm .init.text:FFFFFFFF83EAFC67 mov rdx, offset byte_FFFFFFFF8263C248 .init.text:FFFFFFFF83EAFC6E mov rsi, offset aKallsymsNames ; "kallsyms_names" .init.text:FFFFFFFF83EAFC75 mov rdi, offset aSymbolSLx ; "SYMBOL(%s)=%lx\n" .init.text:FFFFFFFF83EAFC7C call sub_FFFFFFFF811FDB20 .init.text:FFFFFFFF83EAFC81 mov rdx, offset dword_FFFFFFFF8263C240 .init.text:FFFFFFFF83EAFC88 mov rsi, offset aKallsymsNumSym ; "kallsyms_num_syms" .init.text:FFFFFFFF83EAFC8F mov rdi, offset aSymbolSLx ; "SYMBOL(%s)=%lx\n" .init.text:FFFFFFFF83EAFC96 call sub_FFFFFFFF811FDB20 .init.text:FFFFFFFF83EAFC9B mov rdx, offset byte_FFFFFFFF82938430 .init.text:FFFFFFFF83EAFCA2 mov rsi, offset aKallsymsTokenT ; "kallsyms_token_table" .init.text:FFFFFFFF83EAFCA9 mov rdi, offset aSymbolSLx ; "SYMBOL(%s)=%lx\n" .init.text:FFFFFFFF83EAFCB0 call sub_FFFFFFFF811FDB20 .init.text:FFFFFFFF83EAFCB5 mov rdx, offset word_FFFFFFFF829387B8 .init.text:FFFFFFFF83EAFCBC mov rsi, offset aKallsymsTokenI ; "kallsyms_token_index" .init.text:FFFFFFFF83EAFCC3 mov rdi, offset aSymbolSLx ; "SYMBOL(%s)=%lx\n" .init.text:FFFFFFFF83EAFCCA call sub_FFFFFFFF811FDB20 .init.text:FFFFFFFF83EAFCCF mov rdx, offset dword_FFFFFFFF825861C0 .init.text:FFFFFFFF83EAFCD6 mov rsi, offset aKallsymsOffset ; "kallsyms_offsets" .init.text:FFFFFFFF83EAFCDD mov rdi, offset aSymbolSLx ; "SYMBOL(%s)=%lx\n" .init.text:FFFFFFFF83EAFCE4 call sub_FFFFFFFF811FDB20 ``` 每个kallsyms symbols字符串对应的上一行汇编代码中的.rodata段的引用即为该kallsyms symbol的地址: ```asm .rodata:FFFFFFFF8263C240 dword_FFFFFFFF8263C240 dd 2D81Eh .rodata:FFFFFFFF8263C240 .rodata:FFFFFFFF8263C244 align 8 .rodata:FFFFFFFF8263C248 byte_FFFFFFFF8263C248 db 0Ah .rodata:FFFFFFFF8263C248 .rodata:FFFFFFFF8263C249 db 41h ; A .rodata:FFFFFFFF8263C24A db 0BFh .rodata:FFFFFFFF8263C24B db 78h ; x .rodata:FFFFFFFF8263C24C db 65h ; e .rodata:FFFFFFFF8263C24D db 0EDh ... ``` 这种方法的限制条件在于:1. 仅限于6.0版本之后的内核 2.内核编译选项需开启`CONFIG_KALLSYMS` 定位的ida脚本示例如下: ```python import ida_search import ida_xref import ida_segment kallsyms_list=["kallsyms_names","kallsyms_num_syms","kallsyms_token_table","kallsyms_token_index","kallsyms_offsets","kallsyms_relative_base"] def get_kallsyms_addr(startaddr,kallstr): str_addr = ida_search.find_text(startaddr,0,0,kallstr,ida_search.SEARCH_DOWN) if str_addr != idc.BADADDR: #print(hex(str_addr)) ref_code_addr = ida_xref.get_first_dref_to(str_addr) if ref_code_addr != idc.BADADDR: #print(hex(ref_code_addr)) prev_insn = idc.prev_head(ref_code_addr) target_addr = idc.get_operand_value(prev_insn,1) #print(hex(prev_insn),idc.generate_disasm_line(prev_insn,0),hex(idc.get_operand_value(prev_insn,1))) return target_addr if target_addr != idc.BADADDR else idc.BADADDR else: print("error:ref_code_addr") return idc.BADADDR else: print("error:str_addr") return idc.BADADDR def main(): start_ea=ida_segment.get_segm_by_name(".rodata") for i in kallsyms_list: kall_addr=get_kallsyms_addr(start_ea.start_ea,i) if kall_addr != idc.BADADDR: print(i+":"+hex(kall_addr)) else: print("error:kall_addr") main() ``` ## 参考链接 [1] https://github.com/torvalds/linux/commit/5fd8fea935a1091083506d0b982fcc5d35062f06 [2] http://scz.617.cn:8/unix/201903251646.txt