-
-
Notifications
You must be signed in to change notification settings - Fork 314
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
frida_libafl
links multiple versions of capstone
#1018
Comments
If capstone-rust/capstone-rs#140 gets merged we should have a fix |
I have raised this ticket against |
Did we get a new frida release yet? cc @s1341 |
I think this got resolved in the meantime? |
Summary
When updating the version of the
frida-rust
dependency, it was observed that moving fromfrida-gum-sys
0.5
to0.6
things stopped working on ARM64 MacOS. This issue serves to both explain the defect but also document the means to analyse the defect such that future problems can be more easily diagnosed.Modifying frida-rust
To use a local copy of
frida-rust
rather than one from crates.io, you can apply the following patch and use the following commands:Modifying FRIDA Gum
FRIDA rust unsurprisingly depends on FRIDA itself, more specifically the
frida-gum-devkit
. In bumping the version offrida-gum-sys
from0.5
to0.6
, we end up in turn moving from FRIDA16.0.2
to16.0.7
. More careful analysis showed that usingfrida-gum-sys
0.5
but manually bumping the version of FRIDA it depended on from16.0.2
to16.0.3
again introduced the regression.Now in order to investigate further we need to be able to use a custom version of FRIDA. We can do this by removing the "auto-download" feature and instead copying the built
frida-gum-devkit
into thefrida-gum-sys
folder offrida-rust
. But to do that we first need to build the devkit.Building the
frida-gum-devkit
We can build the devkit using the following commands...
The just copy the library and header from the
./dk
directory into thefrida-gum-sys
folder offrida-rust
.The step to build the SDK is optional (since it will download a pre-built binary one if omitted, but as we'll see later, we want to rule out issues with that). We disable the V8 javascript engine because we don't need it (it's part of the
frida-gumjs-devkit
instead) and it takes ages to build.To the printf mobile
We know the issue is with the stalker engine, by adding some
println!
to LibAFL (and running withLIBAFL_DEBUG_OUTPUT=1
), we can see out call to stalker'sfollow_me
function never returns. Now, code generated on the fly by dynamic binary instrumentation engines and debuggers are not a recipe for success when used together. So we need some good old fashionedprintfs
.Now the other issue is that the instrumentation engine from which we want to print our debug information runs in the same thread as the one executing the code. If that thread was running
printf
and we are duly instrumenting and executing it, and we callprintf
ourselves in the middle of all this, we end up re-entering the function in libc on the same thread. Whilstprintf
is designed to work when called by multiple threads concurrently, it isn't intended to be called by the same thread, half way through executing itself. This is a very painful lesson which you only need to learn once. We therefore use the following snippet of code to handle ourprintfs
which we add to the FRIDA engine.We also need a little helper routine to let us disassemble the code being instrumented and the code which is generated...
We can now add the following few lines to the bottom of function which commits new blocks within the Stalker engine to peek at whats going on. We first print the code of the basic block which was about to be executed, and then print the code which stalker generated to be used in its place.
Contrasting the logs...
We can see with FRIDA
16.0.2
we get this output (cleaned up for simplicity)...But with FRIDA
16.0.3
we get the following...We can see with
16.0.2
, FRIDA generates a new version of the original code, up until the end of the basic block (instructions which are RIP relative are replaced with equivalents whilst the others can simply be copied verbatim). Note that at the end of the block, we don't jump to the original location, but instead back into the Stalker engine to have it instrument the next block and start executing the instrumented copy.However, with
16.0.3
, FRIDA is instead just copying the branch verbatim and continuing on past the end of the basic block!?!Some more printfs
To work out why we need some more details, so we add some more
printfs
this time to where the basic block is processed and this time include the bytes of the original code and the instruction ID used by capstone to represent it...We also add the following...
And see
We can see that capstone has generated the instruction ID 0x2E whereas GUM thinks the ID using the capstone headers should be 0x44. Looking at Capstone in GitHub, it hasn't changed in years, it doesn't make any sense!
Capstone Versioning
After lots of tedious git bisection, and some other revelations, we can see that rather than using the original capstone project from GitHub, it uses its own fork at
https://github.com/frida/capstone
, and although themaster
branch of capstone shows that the enumeration of ARM64 instruction IDs hasn't changed in forever, it is actually thenext
branch which is under active development and the one which is tracker by FRIDA's fork.Back to our bisection and we can see that it is this commit which is causing us problems...
frida/frida@bb8c82d
We have taken a long and tedious path to discovering where
frida-gum-devkit
gets its capstone from. And we can now compare these two versions of capstone. We see in thisnext
branch that capstone is introducing support for ARM v9.2-A and adding new instructions into the enumeration. The enum lists them in alphabetical order and the values are not defined so they are just sequential too. This means that between versions, the values of the enum values will change.After much playing around with
frida-gum-devkit
to determine whether it is using different versions of capstone when building its SDK to when it is building FRIDA gum itself, we determine that it is correctly using just one version, the later one. We add a unit test (infrida-gum/tests/core/arch-arm64/arm64relocator.c
) and sure enough capstone is correctly disassembling ourBL
instruction and assigning it the ID0x44
as we expect, it does.So why when we run in the fuzzer does capstone give us an ID of
0x2E
(the value which was used in the old version of capstone)?Crushing Realisation
So if capstone is giving us the old value for the instruction ID, then we must be using an old version of capstone, not the one which is incorporated in the
frida-gum-devkit
. So we check outLibAFL
and sure enough...Capstone Capstone Everywhere
But it's not that simple, using
cargo tree
, we can see capstone is a dependency of:frida_libpng
(the fuzzer itself)frida-gum
(one of the components offrida-rust
)libafl_frida
Conclusions
Now we have worked out the root cause of our issues, we have the following unanswered questions:
glibc
on Linux?The text was updated successfully, but these errors were encountered: