Added support for uncompressed kallsyms to klookup (#2479)

* Added support for uncompressed kallsyms to klookup

Signed-off-by: Chirag Aggarwal <thechiragaggarwal@gmail.com>

* Added info message instead of error for kallsyms type

Signed-off-by: Chirag Aggarwal <thechiragaggarwal@gmail.com>

* Linting fix

Signed-off-by: Chirag Aggarwal <thechiragaggarwal@gmail.com>

---------

Signed-off-by: Chirag Aggarwal <thechiragaggarwal@gmail.com>
pull/2504/head
jetchirag 1 year ago committed by GitHub
parent 4ca87e39c1
commit 72a51147ce
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -1,5 +1,7 @@
from __future__ import annotations
from re import match
from re import search
from struct import unpack_from
from pwnlib.util.packing import p16
@ -48,11 +50,20 @@ class Kallsyms:
self.rbase_offset = 0
self.is_big_endian = None
self.token_table = self.find_token_table()
# TODO: if self.token_table is None its maybe an uncompressed kallsyms
self.is_uncompressed = self.token_table is None
if self.is_uncompressed:
print(M.info("Detected Uncompressed Kallsyms"))
self.find_names_uncompressed()
self.markers = self.find_markers_uncompressed()
else:
print(M.info("Detected Compressed Kallsyms"))
self.token_index = self.find_token_index()
self.markers = self.find_markers()
self.token_index = self.find_token_index()
self.markers = self.find_markers()
self.num_syms = self.find_num_syms()
self.offsets = self.find_offsets()
@ -112,7 +123,7 @@ class Kallsyms:
if len(ascii_candidates) == 1:
candidates = ascii_candidates
elif len(candidates) == 0:
print(M.error("No candidates for token_table"))
# print(M.error("No candidates for token_table, maybe uncompressed kallsyms"))
return None
position = candidates[0]
@ -283,7 +294,7 @@ class Kallsyms:
"""
forward_search = self.kernel_version >= (6, 4)
if forward_search:
if forward_search and not self.is_uncompressed:
position = self.token_index
self.is_offsets = True
else:
@ -387,15 +398,143 @@ class Kallsyms:
self.kallsyms[name[1:]] = (addr, name[0])
def get_token_table(self):
tokens = []
position = self.token_table
if not self.is_uncompressed:
tokens = []
position = self.token_table
for num_token in range(256):
token = ""
while self.kernel_ro_mem[position]:
token += chr(self.kernel_ro_mem[position])
position += 1
position += 1
tokens.append(token)
else:
tokens = [chr(i) for i in range(256)]
return tokens
def find_names_uncompressed(self):
# Find the length byte-separated symbol names
ksymtab_match = search(
rb"(?:[\x05-\x23][TWtbBrRAdD][a-z0-9_.]{4,34}){14}", self.kernel_ro_mem
)
if not ksymtab_match:
print(M.error("Failed to find kallsyms"))
return None
kallsyms_names__offset = ksymtab_match.start(0)
# Count the number of symbol names
position = kallsyms_names__offset
num_syms = 0
while position + 1 < len(self.kernel_ro_mem):
if (
self.kernel_ro_mem[position] < 2
or chr(self.kernel_ro_mem[position + 1]).lower() not in "abdrtvwginpcsu-?"
):
break
symbol_name_and_type = self.kernel_ro_mem[
position + 1 : position + 1 + self.kernel_ro_mem[position]
]
if not match(rb"^[\x21-\x7e]+$", symbol_name_and_type):
break
position += 1 + self.kernel_ro_mem[position]
num_syms += 1
if num_syms < 100:
print(M.error("Failed to find kallsyms"))
return None
self.end_of_kallsyms_names_uncompressed = position
def find_markers_uncompressed(self):
"""
This function searches for the kallsyms_markers structure in the kernel memory
Original Source: https://github.com/marin-m/vmlinux-to-elf/blob/master/vmlinux_to_elf/kallsyms_finder.py
"""
position = self.end_of_kallsyms_names_uncompressed
position += -position % 4
max_number_of_space_between_two_nulls = 0
# Go just after the first chunk of non-null bytes
for num_token in range(256):
token = ""
while self.kernel_ro_mem[position]:
token += chr(self.kernel_ro_mem[position])
# while position + 1 < len(self.kernel_img) and self.kernel_img[position + 1] == 0:
# position += 1
while position + 1 < len(self.kernel_ro_mem) and self.kernel_ro_mem[position + 1] == 0:
position += 1
for null_separated_bytes_chunks in range(20):
num_non_null_bytes = 1 # we always start at a non-null byte in this loop
num_null_bytes = (
1 # we will at least encounter one null byte before the end of this loop
)
while True:
position += 1
assert position >= 0
if self.kernel_ro_mem[position] == 0:
break
num_non_null_bytes += 1
while True:
position += 1
assert position >= 0
if self.kernel_ro_mem[position] != 0:
break
num_null_bytes += 1
max_number_of_space_between_two_nulls = max(
max_number_of_space_between_two_nulls, num_non_null_bytes + num_null_bytes
)
if (
max_number_of_space_between_two_nulls % 2 == 1
): # There may be a leap to a shorter offset in the latest processed entries
max_number_of_space_between_two_nulls -= 1
if max_number_of_space_between_two_nulls not in (2, 4, 8):
print(M.error("Could not guess the architecture register size for kernel"))
return None
self.offset_table_element_size = max_number_of_space_between_two_nulls
# Once the size of a long has been guessed, use it to find
# the first offset (0)
position = self.end_of_kallsyms_names_uncompressed
position += -position % 4
# Go just at the first non-null byte
while position < len(self.kernel_ro_mem) and self.kernel_ro_mem[position] == 0:
position += 1
tokens.append(token)
return tokens
likely_is_big_endian = position % self.offset_table_element_size > 1
if self.is_big_endian is None: # Manual architecture specification
self.is_big_endian = likely_is_big_endian
if position % self.offset_table_element_size == 0:
position += self.offset_table_element_size
else:
position += -position + self.offset_table_element_size
position -= self.offset_table_element_size
position -= self.offset_table_element_size
position -= position % self.offset_table_element_size
self.kallsyms_markers__offset = position
# print('Found kallsyms_markers at file offset 0x%08x' % position)
return position

Loading…
Cancel
Save