acmfi / libradar

ACMFI version of libRadar
MIT License
0 stars 0 forks source link

Define actions and entry point of the program #4

Open 0xddom opened 4 years ago

0xddom commented 4 years ago

For a usable program we obviously need an entrypoint. The first and easiest is to create a cli program that does the training and the detection. The problem with this is, depending on how the cli is implemented we may have coupling issues. For example, if the whole detection algorithm is written in the detection cli entrypoint, do we need to reimplement it if we decide to have a HTTP entrypoint?

In order to future proof ourselves, the approach I believe is the fittest here is to apply the Command pattern. By implementing each action of the system in a separate command we can have more flexibility. The cli programs, HTTP clients or whatever will just be lightweight facades to the actual command.

Implementation-wise it could go as follows:

~An abstract interface that defines what the general behavior of the command is:~

trait Action {
  fn run(&mut self);
}

~Then, each action/command would be represented with a struct that hold all the parameters it needs.~

~Drawbacks: If the code of the action is to be entrypoint independent, we cant make assumptions like writing to stdout. This means that we need to have a common interface for the output of the actions, which potentially has many different formats or even no output at all.~

Something like this may be much more simple to do and can still fit into a Command in an upper layer of abstraction:

// A struct that holds the configuration for the application
// DB, libradar parameters, etc
struct Context {
  db: crate::db::DexDB,
  ...
}

impl Context {
  fn create_analysis() -> impl Analyzer {} // Returns some type of analysis (fuzzy or exact)
}

trait Analyzer {
  fn analyze_apk() -> AnalysisResult;
  fn analyze_dex() -> AnalysisResult;
}

struct ExampleAnalysis;

impl Analyzer for ExampleAnalysis {
  ...
}

With something like this the responsibilities are split into 3 components:

0xddom commented 4 years ago

One way to avoid the problem of the output interface is to use some kind of serialized output using Serde. Ideally, the output of the action would be a serializable entity that can be directly passed to any Serde serializer.

0xddom commented 4 years ago

One way to avoid the problem of the output interface is to use some kind of serialized output using Serde. Ideally, the output of the action would be a serializable entity that can be directly passed to any Serde serializer.

This does not work as the trait in Serde can't be converted into an object, making polymorphism impossible.