Adding a new probe¶
Writing a Plugin for the probe¶
Note
To be a valid probe module, IRMA expects it to have a predefined structure. To save time, one can get a minimal working structure from the skeleton plugin. The new plugin is stored in the appropriate sub-directory of the directory probe/modules according to the type of the new probe (antivirus, metadata, external…).
For a probe that is not a antivirus¶
1. Copy the directory skeleton to the new module (appropriate localisation). Example with a module my_module with metadata type :
$ cp -r probe/modules/custom/skeleton/ probe/modules/metadata/my_module
- If there are packages to install, specify them in the file requirements.txt. Otherwise remove the file
- Adjust the file plugin.py according to the module :
- Adjust the class’s name with the name of your probe
- Fill in the fields of the class :- _plugin_name_ = [the plugin name]
- _plugin_display_name_ = [the field _name of the class of the probe]
- _plugin_version_ = [the version number]
- _plugin_category = [the type of the probe: IrmaProbeType.]
- _plugin_description = [quick description]
- _plugin_dependencies = [list of dependencies: platform, binary or/and file] => if used import from lib.plugins PlatformDependency, BinaryDependency or/and FileDependency
- _mimetype_regexp = [mimetype corresponding]
- Implement the functions corresponding to the type of the plugin
For an antivirus¶
In the case of an antivirus, it is a little different because an Antivirus class was created to avoid code’s duplication. You can use the skeleton below:
plugin.py:
#
# Copyright (c) 2013-2018 Quarkslab.
# This file is part of IRMA project.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License in the top-level directory
# of this distribution and at:
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# No part of the project, including this file, may be copied,
# modified, propagated, or distributed except according to the
# terms contained in the LICENSE file.
from .skeleton import Skeleton
from ..interface import AntivirusPluginInterface
from irma.common.plugins import PluginMetaClass
class SkeletonPlugin(AntivirusPluginInterface, metaclass=PluginMetaClass):
# =================
# plugin metadata
# =================
_plugin_name_ = "Skeleton"
_plugin_display_name_ = Skeleton._name
_plugin_author_ = "IRMA (c) Quarkslab"
_plugin_version_ = "1.0.0"
_plugin_category_ = "custom"
_plugin_description_ = "Plugin skeleton"
_plugin_dependencies_ = []
_mimetype_regexp = None
# ================
# interface data
# ================
module_cls = Skeleton
# If needed, overload the `verify` classmethod in order to check your class
# is instanciable. It should return if everything is alright, otherwise
# raise an exception. By default it checks that the module's attribute
# `self.scan_path` is an existing file (cf. `super()._chk_scanpath`)
#
# @classmethod
# def verify(cls):
# pass
The metaclass PluginMetaClass
handles the registering of the plugin to a plugin manager. It also checks that the class is instanciable thanks to the verify
method.
skeleton.py:
#
# Copyright (c) 2013-2018 Quarkslab.
# This file is part of IRMA project.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License in the top-level directory
# of this distribution and at:
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# No part of the project, including this file, may be copied,
# modified, propagated, or distributed except according to the
# terms contained in the LICENSE file.
import logging
# Choose the class you need to inherit from
from modules.antivirus.base import AntivirusUnix, AntivirusWindows
log = logging.getLogger(__name__)
# Inhererit from AntivirusUnix or AntivirusWindows according to your plateform
class Skeleton(Antivirus):
name = "Skeleton for Antivirus"
# ==================================
# Constructor and destructor stuff
# ==================================
def __init__(self, *args, **kwargs):
# class super class constructor
super().__init__(*args, **kwargs)
# do your initialization stuff
The recipe is the same, the files with the corresponding module name and differents fields need to be updated.
The attributes in Antivirus._attributes
are meant to be defined by the instanciation. One can either:
- leave it blank, in this case the super class will assign it a default value (eg.
"unavailable"
forself.version
);- define it directly (eg.
self.scan_path = Path("/opt/skeleton/skeleton")
);- define a function to be called to assign it (eg.
def get_scan_path(self): ...
), the super class will take care of calling it and handling exceptions.
Testing the new plugin¶
Before testing, module’s necessary stuff (binaries, files, etc) must be provisioned to the VM.
$ cd ansible
$ vagrant rsync
$ vagrant ssh
$ sudo su deploy
$ cd /opt/irma/irma-probe/current
$ venv/bin/python -m extras.tools.run_module
This last command lists available modules.
Now, if the new module is available, its launching can be done:
$ venv/bin/python -m extras.tools.run_module my_module file
Automatic provisioning¶
Creating a new role¶
Create a new directory with this structure:
cd ansible
tree roles/quarsklab.my_module
roles/quarkslab.my_module/
+-- defaults
| +-- main.yml
+-- tasks
+-- main.yml
tasks/main.yml is the default entry point for a role containing Ansible tasks. In this file, write the instruction to install the module. Add the file tasks/update.yml to write the informations for the update if necessary. In defaults/main.yml it is usual to store default variables for this role. If there are particular instructions, for example how to obtain a licence for a antivirus, add a README file.
Invoking the module role¶
Modify playbooks/provisioning.yml : add the module
-name : my_module
hosts: my_module
roles:
- { role: quarkslab.my_module, tags: 'my_module'}
If a task update was defined, add the module in playbooks/updating.yml :
-name : my_module
hosts: my_module
roles:
- { role: quarkslab.module, tags: 'my_module', task_from : update}
Defining hosts¶
Modify the environment to add the new probe.
For example for the allinone_dev :
$ cat environments/allinone_dev.yml
[ ... snip ... ]
virustotal:
- brain.irma
my_module:
- brain.irma
"probe:children":
- clamav
- comodo
- mcafee
- static-analyzer
- virustotal
- my_module