Skip to content

Commit

Permalink
Use Bro-like hashing architecture.
Browse files Browse the repository at this point in the history
Bro's hashing architecture allows easy utilization and extensibility of
hashing by using opaque values.
  • Loading branch information
J-Gras committed Dec 4, 2017
1 parent 3bebbbc commit 9e29157
Show file tree
Hide file tree
Showing 15 changed files with 295 additions and 116 deletions.
11 changes: 6 additions & 5 deletions CMakeLists.txt
Expand Up @@ -8,21 +8,22 @@ include(BroPlugin)
find_package(LibFuzzy)

if ( SSDEEP_FOUND )
message(STATUS "Libfuzzy header prefix : ${SSDEEP_INCLUDE_DIR}")
message(STATUS "Libfuzzy library path : ${SSDEEP_LIBRARY}")
message(STATUS "Libfuzzy (ssdeep) header prefix : ${SSDEEP_INCLUDE_DIR}")
message(STATUS "Libfuzzy (ssdeep) library path : ${SSDEEP_LIBRARY}")

include_directories(${SSDEEP_INCLUDE_DIR})

bro_plugin_begin(JGras SSDeep)
bro_plugin_begin(JGras FuzzyHashing)
bro_plugin_cc(src/Plugin.cc)
bro_plugin_cc(src/SSDeep.cc)
bro_plugin_cc(src/FuzzyHash.cc)
bro_plugin_cc(src/FuzzyHashVal.cc)
bro_plugin_bif(src/events.bif)
bro_plugin_dist_files(README CHANGES COPYING VERSION)
bro_plugin_link_library(${SSDEEP_LIBRARY})
bro_plugin_end()
else ()
message(FATAL_ERROR "Build failed:")
if ( NOT SSDEEP_FOUND )
message(FATAL_ERROR "Libfuzzy not found.")
message(FATAL_ERROR "Libfuzzy (ssdeep) not found.")
endif ()
endif ()
2 changes: 1 addition & 1 deletion VERSION
@@ -1 +1 @@
0.1
0.2
4 changes: 2 additions & 2 deletions bro-pkg.meta
@@ -1,7 +1,7 @@
[package]
description = This plugin provides ssdeep fuzzy hashing for Bro.
description = This plugin provides fuzzy hashing for Bro.
tags = bro plugin
plugin_dir = build/JGras_SSDeep.tgz
plugin_dir = build/JGras_FuzzyHashing.tgz
build_command = ./configure --bro-dist=%(bro_dist)s && make
test_command = cd tests && btest -d
depends =
Expand Down
2 changes: 1 addition & 1 deletion configure
Expand Up @@ -53,7 +53,7 @@ append_cache_entry () {

# set defaults
builddir=build
brodist=`cd ../../.. && pwd`
brodist=`bro-config --bro_dist 2> /dev/null || (cd ../../.. && pwd)`
installroot="default"
CMakeCacheEntries=""

Expand Down
4 changes: 0 additions & 4 deletions scripts/Bro/SSDeep/__load__.bro

This file was deleted.

58 changes: 58 additions & 0 deletions src/FuzzyHash.cc
@@ -0,0 +1,58 @@
// See the file "COPYING" in the main distribution directory for copyright.

#include "FuzzyHash.h"

#include <file_analysis/Manager.h>

using namespace plugin::JGras_FuzzyHashing;

FuzzyHash::FuzzyHash(RecordVal* args, file_analysis::File* file, FuzzyHashVal* hv,
const char* arg_kind)
: file_analysis::Analyzer(file_mgr->GetComponentTag(to_upper(arg_kind).c_str()), args, file),
fuzzy_hash(hv),
fed(false),
kind(arg_kind)
{
fuzzy_hash->Init();
}

FuzzyHash::~FuzzyHash()
{
Unref(fuzzy_hash);
}

bool FuzzyHash::DeliverStream(const u_char* data, uint64 len)
{
if ( ! fuzzy_hash->IsValid() )
return false;

if ( ! fed )
fed = len > 0;

fuzzy_hash->Feed(data, len);
return true;
}

bool FuzzyHash::EndOfFile()
{
Finalize();
return false;
}

bool FuzzyHash::Undelivered(uint64 offset, uint64 len)
{
return false;
}

void FuzzyHash::Finalize()
{
if ( ! fuzzy_hash->IsValid() || ! fed )
return;

val_list* vl = new val_list();
vl->append(GetFile()->GetVal()->Ref());
vl->append(new StringVal(kind));
vl->append(fuzzy_hash->Get());

mgr.QueueEvent(file_fuzzy_hash, vl);
}
66 changes: 42 additions & 24 deletions src/SSDeep.h → src/FuzzyHash.h
@@ -1,38 +1,27 @@
// See the file "COPYING" in the main distribution directory for copyright.

#ifndef BRO_PLUGIN_JGRAS_SSDEEP_ANALYZER_H
#define BRO_PLUGIN_JGRAS_SSDEEP_ANALYZER_H
#ifndef BRO_PLUGIN_JGRAS_FUZZYHASHING_ANALYZER_H
#define BRO_PLUGIN_JGRAS_FUZZYHASHING_ANALYZER_H

#include <Val.h>
#include <file_analysis/Analyzer.h>

//extern "C" {
#include <fuzzy.h>
//}
#include "FuzzyHashVal.h"
#include "events.bif.h"

namespace plugin {
namespace JGras_SSDeep {

namespace JGras_FuzzyHashing {

/**
* An analyzer to produce context triggered piecewise hashes (CTPH) of file contents.
* An analyzer to produce a hash of file contents.
*/
class SSDeep : public file_analysis::Analyzer {
class FuzzyHash : public file_analysis::Analyzer {
public:

/**
* Destructor.
*/
virtual ~SSDeep();

/**
* Create a new instance of the ssdeep hashing file analyzer.
* @param args the \c AnalyzerArgs value which represents the analyzer.
* @param file the file to which the analyzer will be attached.
* @return the new ssdeep analyzer instance or a null pointer if there's no
* handler for the "file_hash_ssdeep" event.
*/
static file_analysis::Analyzer* Instantiate(RecordVal* args, file_analysis::File* file);
virtual ~FuzzyHash();

/**
* Incrementally hash next chunk of file contents.
Expand Down Expand Up @@ -67,21 +56,50 @@ class SSDeep : public file_analysis::Analyzer {
* @param hv specific hash calculator object.
* @param kind human readable name of the hash algorithm to use.
*/
SSDeep(RecordVal* args, file_analysis::File* file);
FuzzyHash(RecordVal* args, file_analysis::File* file, FuzzyHashVal* hv, const char* kind);

/**
* If some file contents have been seen, finalizes the hash of them and
* raises the "file_hash" event with the results.
* raises the "file_fuzzy_hash" event with the results.
*/
void Finalize();

private:
//HashVal* hash;
FuzzyHashVal* fuzzy_hash;
bool fed;
fuzzy_state* state;
const char* kind;
};

/**
* An analyzer to produce context triggered piecewise hashes (CTPH) of file contents
* using the ssdeep library.
*/
class SSDeep : public FuzzyHash {
public:

/**
* Create a new instance of the ssdeep hashing file analyzer.
* @param args the \c AnalyzerArgs value which represents the analyzer.
* @param file the file to which the analyzer will be attached.
* @return the new ssdeep analyzer instance or a null pointer if there's no
* handler for the "file_hash" event.
*/
static file_analysis::Analyzer* Instantiate(RecordVal* args, file_analysis::File* file)
{ return file_fuzzy_hash ? new SSDeep(args, file) : 0; }

protected:

/**
* Constructor.
* @param args the \c AnalyzerArgs value which represents the analyzer.
* @param file the file to which the analyzer will be attached.
*/
SSDeep(RecordVal* args, file_analysis::File* file)
: FuzzyHash(args, file, new SSDeepVal(), "ssdeep")
{}
};

}
}

#endif
#endif
120 changes: 120 additions & 0 deletions src/FuzzyHashVal.cc
@@ -0,0 +1,120 @@
// See the file "COPYING" in the main distribution directory for copyright.

// #include <Serializer.h>

#include "FuzzyHashVal.h"

using namespace plugin::JGras_FuzzyHashing;

FuzzyHashVal::FuzzyHashVal(OpaqueType* t) : HashVal(t)
{
}

/*
IMPLEMENT_SERIAL(FuzzyHashVal, SER_FUZZY_HASH_VAL);
bool FuzzyHashVal::DoSerialize(SerialInfo* info) const
{
DO_SERIALIZE(SER_FUZZY_HASH_VAL, OpaqueVal);
return SERIALIZE(valid);
}
bool FuzzyHashVal::DoUnserialize(UnserialInfo* info)
{
DO_UNSERIALIZE(OpaqueVal);
return UNSERIALIZE(&valid);
}
*/

static OpaqueType* ssdeep_type = new OpaqueType("ssdeep");

SSDeepVal::SSDeepVal() : FuzzyHashVal(ssdeep_type)
{
}

bool SSDeepVal::DoInit()
{
assert(! IsValid());
state = fuzzy_new();
return state != NULL;
}

bool SSDeepVal::DoFeed(const void* data, size_t size)
{
if ( ! IsValid() )
return false;

bool success = (fuzzy_update(state, static_cast<const u_char*>(data), size) == 0);
return success;
}

StringVal* SSDeepVal::DoGet()
{
if ( ! IsValid() )
return new StringVal("");

char hash[FUZZY_MAX_RESULT] = "";
if (fuzzy_digest(state, hash, 0) != 0 )
return new StringVal("");

fuzzy_free(state);
return new StringVal(hash);
}

/*
IMPLEMENT_SERIAL(SSDeepVal, SER_SSDEEP_VAL);
bool SSDeepVal::DoSerialize(SerialInfo* info) const
{
DO_SERIALIZE(SER_SSDEEP_VAL, HashVal);
if ( ! IsValid() )
return true;
if ( ! (SERIALIZE(ctx.A) &&
SERIALIZE(ctx.B) &&
SERIALIZE(ctx.C) &&
SERIALIZE(ctx.D) &&
SERIALIZE(ctx.Nl) &&
SERIALIZE(ctx.Nh)) )
return false;
for ( int i = 0; i < MD5_LBLOCK; ++i )
{
if ( ! SERIALIZE(ctx.data[i]) )
return false;
}
if ( ! SERIALIZE(ctx.num) )
return false;
return true;
}
bool SSDeepVal::DoUnserialize(UnserialInfo* info)
{
DO_UNSERIALIZE(FuzzyHashVal);
if ( ! IsValid() )
return true;
if ( ! (UNSERIALIZE(&ctx.A) &&
UNSERIALIZE(&ctx.B) &&
UNSERIALIZE(&ctx.C) &&
UNSERIALIZE(&ctx.D) &&
UNSERIALIZE(&ctx.Nl) &&
UNSERIALIZE(&ctx.Nh)) )
return false;
for ( int i = 0; i < MD5_LBLOCK; ++i )
{
if ( ! UNSERIALIZE(&ctx.data[i]) )
return false;
}
if ( ! UNSERIALIZE(&ctx.num) )
return false;
return true;
}
*/
44 changes: 44 additions & 0 deletions src/FuzzyHashVal.h
@@ -0,0 +1,44 @@
// See the file "COPYING" in the main distribution directory for copyright.

#ifndef BRO_PLUGIN_JGRAS_FUZZYHASHING_VAL_H
#define BRO_PLUGIN_JGRAS_FUZZYHASHING_VAL_H

#include <OpaqueVal.h>

#include "fuzzy.h"

namespace plugin {
namespace JGras_FuzzyHashing {

class FuzzyHashVal : public HashVal {
protected:
FuzzyHashVal() { };
FuzzyHashVal(OpaqueType* t);

//DECLARE_SERIAL(FuzzyHashVal);
};

class SSDeepVal : public FuzzyHashVal {
public:
// TODO: static functionality?
//static void digest(val_list& vlist, u_char result[MD5_DIGEST_LENGTH]);

SSDeepVal();

protected:
friend class Val;

virtual bool DoInit() override;
virtual bool DoFeed(const void* data, size_t size) override;
virtual StringVal* DoGet() override;

//DECLARE_SERIAL(SSDeepVal);

private:
fuzzy_state* state;
};

}
}

#endif

0 comments on commit 9e29157

Please sign in to comment.