Skip to content

Commit ce1087a

Browse files
pe: better detection of thunks
1 parent 250ecf1 commit ce1087a

File tree

3 files changed

+33
-10
lines changed

3 files changed

+33
-10
lines changed

core/src/analysis/pe/mod.rs

Lines changed: 31 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -224,18 +224,40 @@ pub fn find_functions(pe: &PE) -> Result<Vec<Function>> {
224224
.filter(|&va| heuristics::is_probably_code(&pe.module, &decoder, va)),
225225
);
226226

227-
let thunks = find_thunks(pe, &imports, &function_starts)?;
228-
229227
// ensure that all functions pointed to by a thunk are a function.
230228
// some of these target functions may not be recongized by other passes.
231-
for thunk in thunks.values() {
232-
if let ThunkTarget::Function(target) = thunk.target {
233-
debug!("found new function candidate from thunk target: 0x{target:x}");
234-
function_starts.insert(target);
229+
//
230+
// we keep searching until we reach a fixed point,
231+
// to ensure we account for thunks to thunks to functions.
232+
let mut thunk_candidates = function_starts.clone();
233+
let mut thunks: BTreeMap<VA, Thunk> = Default::default();
234+
while thunk_candidates.is_empty().not() {
235+
let confirmed_thunks = find_thunks(pe, &imports, &thunk_candidates)?;
236+
237+
// these are all the addresses pointed to by thunks,
238+
// which we need to ensure are functions.
239+
let function_thunk_targets = confirmed_thunks
240+
.values()
241+
.filter_map(|thunk| match thunk.target {
242+
ThunkTarget::Function(target) => Some(target),
243+
ThunkTarget::Import(_) => None,
244+
})
245+
.collect::<Vec<VA>>();
246+
247+
thunks.extend(confirmed_thunks.into_iter());
248+
249+
let mut next_candidates: BTreeSet<VA> = Default::default();
250+
for &target in function_thunk_targets.iter() {
251+
if function_starts.insert(target) {
252+
debug!("found new function candidate from thunk target: 0x{target:x}");
253+
next_candidates.insert(target);
254+
// next loop we'll check if this target is a thunk, too.
255+
}
235256
}
257+
258+
debug!("found {} thunk candidates this round", next_candidates.len());
259+
thunk_candidates = next_candidates;
236260
}
237-
// TODO: in theory, we want to do this iteratively, until we reach a fixed
238-
// point, to account for thunks to thunks to functions.
239261

240262
debug!("functions: found {} function candidates", function_starts.len());
241263
debug!("functions: found {} thunks", thunks.len());
@@ -265,6 +287,7 @@ pub fn find_function_starts(pe: &PE) -> Result<Vec<VA>> {
265287
.into_iter()
266288
.filter_map(|f| match f {
267289
Function::Local(va) => Some(va),
290+
Function::Thunk(Thunk { address: va, .. }) => Some(va),
268291
_ => None,
269292
})
270293
.collect())

pyflirt/pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[project]
22
name = "python-flirt"
3-
version = "0.9.4"
3+
version = "0.9.6"
44
description = "A Python library for parsing, compiling, and matching Fast Library Identification and Recognition Technology (FLIRT) signatures."
55
readme = "README.md"
66
requires-python = ">=3.9"

pylancelot/pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[project]
22
name = "python-lancelot"
3-
version = "0.9.4"
3+
version = "0.9.6"
44
description = "Intel x86(-64) code analysis library that reconstructs control flow"
55
readme = "README.md"
66
requires-python = ">=3.9"

0 commit comments

Comments
 (0)