5
5
# Public researches: https://i.blackhat.com/USA21/Wednesday-Handouts/us-21-Fixing-A-Memory-Forensics-Blind-Spot-Linux-Kernel-Tracing-wp.pdf
6
6
7
7
import logging
8
- from typing import Dict , List , Iterable , Optional
8
+ from typing import Dict , List , Generator
9
9
from enum import Enum
10
10
from dataclasses import dataclass
11
11
@@ -67,7 +67,7 @@ class CheckFtrace(interfaces.plugins.PluginInterface):
67
67
Investigate the ftrace infrastructure to uncover kernel attached callbacks, which can be leveraged
68
68
to hook kernel functions and modify their behaviour."""
69
69
70
- _version = (1 , 0 , 0 )
70
+ _version = (2 , 0 , 0 )
71
71
_required_framework_version = (2 , 19 , 0 )
72
72
73
73
@classmethod
@@ -103,32 +103,35 @@ def get_requirements(cls) -> List[interfaces.configuration.RequirementInterface]
103
103
def extract_hash_table_filters (
104
104
cls ,
105
105
ftrace_ops : interfaces .objects .ObjectInterface ,
106
- ) -> Optional [ Iterable [ interfaces .objects .ObjectInterface ] ]:
106
+ ) -> Generator [ interfaces .objects .ObjectInterface , None , None ]:
107
107
"""Wrap the process of walking to every ftrace_func_entry of an ftrace_ops.
108
108
Those are stored in a hash table of filters that indicates the addresses hooked.
109
109
110
110
Args:
111
111
ftrace_ops: The ftrace_ops struct to walk through
112
112
113
- Returns :
113
+ Return, None, None :
114
114
An iterable of ftrace_func_entry structs
115
115
"""
116
116
117
+ if hasattr (ftrace_ops , "func_hash" ):
118
+ ftrace_hash = ftrace_ops .func_hash .filter_hash
119
+ else :
120
+ ftrace_hash = ftrace_ops .filter_hash
121
+
117
122
try :
118
- current_bucket_ptr = ftrace_ops . func_hash . filter_hash .buckets .first
123
+ current_bucket_ptr = ftrace_hash .buckets .first
119
124
except exceptions .InvalidAddressException :
120
125
vollog .log (
121
126
constants .LOGLEVEL_VV ,
122
127
f"ftrace_func_entry list of ftrace_ops@{ ftrace_ops .vol .offset :#x} is empty/invalid. Skipping it..." ,
123
128
)
124
- return []
129
+ return
125
130
126
131
while current_bucket_ptr .is_readable ():
127
132
yield current_bucket_ptr .dereference ().cast ("ftrace_func_entry" )
128
133
current_bucket_ptr = current_bucket_ptr .next
129
134
130
- return None
131
-
132
135
@classmethod
133
136
def parse_ftrace_ops (
134
137
cls ,
@@ -137,7 +140,7 @@ def parse_ftrace_ops(
137
140
known_modules : Dict [str , List [extensions .module ]],
138
141
ftrace_ops : interfaces .objects .ObjectInterface ,
139
142
run_hidden_modules : bool = True ,
140
- ) -> Optional [ Iterable [ ParsedFtraceOps ] ]:
143
+ ) -> Generator [ ParsedFtraceOps , None , None ]:
141
144
"""Parse an ftrace_ops struct to highlight ftrace kernel hooking.
142
145
Iterates over embedded ftrace_func_entry entries, which point to hooked memory areas.
143
146
@@ -234,12 +237,10 @@ def parse_ftrace_ops(
234
237
formatted_ftrace_flags ,
235
238
)
236
239
237
- return None
238
-
239
240
@classmethod
240
241
def iterate_ftrace_ops_list (
241
242
cls , context : interfaces .context .ContextInterface , kernel_name : str
242
- ) -> Optional [ Iterable [ interfaces .objects .ObjectInterface ] ]:
243
+ ) -> Generator [ interfaces .objects .ObjectInterface , None , None ]:
243
244
"""Iterate over (ftrace_ops *)ftrace_ops_list.
244
245
245
246
Returns:
0 commit comments