JonathanSalwan / Triton

Triton is a dynamic binary analysis library. Build your own program analysis tools, automate your reverse engineering, perform software verification or just emulate code.
https://triton-library.github.io
Apache License 2.0
3.53k stars 539 forks source link

[question] Removing Capstone need to use Triton once built #1102

Closed illera88 closed 2 years ago

illera88 commented 2 years ago

Hey there again!

I'm not sure if we talked about this a few years ago and the answer was that it couldn't be done but here it is:

Right now if I build triton and use it from my application I still require to have capstone headers to build my project. And that happens because of: https://github.com/JonathanSalwan/Triton/blob/master/src/libtriton/includes/triton/externalLibs.hpp

As a Triton user I don't need to have access to the capstone API since triton should be abstracting capstone through the Triton API. As a triton user (not to build triton) I should just have the triton library and the libraries that triton uses as binaries, but not the headers. Basically the same that happens with z3. I think externalLibs.hpp shouldn't be part of the triton includes but internal to triton since apps using triton do not need capstone to compile the app.

Am I missing something?

Cheers

illera88 commented 2 years ago

Same thing applies to tritonTypes.hpp and boost (unless you really want the Triton types to be accessible to the Triton users which in that case I would strongly recommend looking into https://github.com/JonathanSalwan/Triton/issues/1073)

mrexodia commented 2 years ago

Doesn't Triton still use the capstone instruction and register ids in the API? Same with boost, there are functions to get the value exposed to the user (and the value is a uint512_t). In general this problem is solved by using find_package, but currently capstone is blocking this. I created an issue https://github.com/capstone-engine/capstone/issues/1826 with a draft and the capstone authors agreed with the idea.

Triton's FindTriton.cmake can then do something like:

find_dependency(Boost REQUIRED)
find_dependency(Z3 REQUIRED)
find_dependency(capstone REQUIRED)

Which will find those packages whenever you call find_package(Triton) from your project. You could use vcpkg or a precompiled dependencies folder with -DCMAKE_PREFIX_PATH=/path/to/precompiled to make it easy for your users to obtain the dependencies.

mrexodia commented 2 years ago

Quick update, I opened a PR to unify packaging on capstone's side: https://github.com/capstone-engine/capstone/pull/1841

illera88 commented 2 years ago

It seems that it was already merged into capstone. Can you do a PR to do what you said so capstone headers are not needed when using Triton?

Thanks

mrexodia commented 2 years ago

You will still need the capstone headers with this method, it just becomes easier to manage capstone as a dependency.

JonathanSalwan commented 2 years ago

@illera88

As a Triton user I don't need to have access to the capstone API since triton should be abstracting capstone through the Triton API. As a triton user (not to build triton) I should just have the triton library and the libraries that triton uses as binaries, but not the headers. Basically the same that happens with z3. I think externalLibs.hpp shouldn't be part of the triton includes but internal to triton since apps using triton do not need capstone to compile the app.

Am I missing something?

In order to apply what you said, all external dep headers (ex. capstone) must be used in our cpp and not hpp files. For capstone we can do this but the Triton's performance will be impacted. Let me explain. First take a look at where externalLibs.hpp is used:

$ grep -r externalLibs.hpp src/libtriton
src/libtriton/includes/triton/arm32Cpu.hpp:#include <triton/externalLibs.hpp>
src/libtriton/includes/triton/x86Cpu.hpp:#include <triton/externalLibs.hpp>
src/libtriton/includes/triton/x8664Cpu.hpp:#include <triton/externalLibs.hpp>
src/libtriton/includes/triton/aarch64Cpu.hpp:#include <triton/externalLibs.hpp>

src/libtriton/arch/arm/aarch64/aarch64Specifications.cpp:#include <triton/externalLibs.hpp>
src/libtriton/arch/arm/arm32/arm32Specifications.cpp:#include <triton/externalLibs.hpp>
src/libtriton/arch/x86/x86Specifications.cpp:#include <triton/externalLibs.hpp>

The header is in all our <arch>Specifications.cpp which is used for enums translation and like you said, it's only needed by the core of Triton. Once the libtriton is compiled the user should not need to access to capstone enums.

The problem is that it's needed by <arch>Cpu.hpp. We keep a reference to the capstone handle in order to initialize it only once and thus avoid multiple cs_open when calling <Arch>Cpu::disassembly(). If we want to remove externalLibs.hpp from <arch>Cpu.hpp, we have to remove the handle attribute from our class and thus call cs_open each time we want to disassemble an instruction, which will decrease a bit Triton's performance. (See #868 - basically you just have to revert what I did if you do not want capstone headers in your Triton tools)

Same thing applies to tritonTypes.hpp and boost (unless you really want the Triton types to be accessible to the Triton users which in that case I would strongly recommend looking into https://github.com/JonathanSalwan/Triton/issues/1073)

For boost it's not possible as a triton::uint is just a typedef on the boost type. So, when you use a triton type you actually use a boost type.

To resume, it could be possible to remove capstone headers (externalLibs.hpp) from our .hpp files but Triton's perf will be impacted and i'm not sure it worth it. For boost headers it's not possible.

mrexodia commented 2 years ago

Not sure how often the Cpu instance is allocated, but you can forward declare a struct CsHandleWrapper and store it in a unique_ptr to hide the implementation details. Of course this is a double indirection, but 🤷‍♂️.

JonathanSalwan commented 2 years ago

Yeah, we can do a lot of hack, like what you said or storing void* + casting, wrappers, etc. but i'm not comfortable with the idea to add ugly hack ^^

JonathanSalwan commented 2 years ago

Mmmmh, in fact i've just took a look at the type of the Capstone's handle and it's just a size_t (see below). So it could be easy to avoid capstone headers on our own headers.

 70 // Handle using with all API                                                    
 71 typedef size_t csh;