Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
18 changes: 18 additions & 0 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
name: Sandblaster tests
on:
workflow_dispatch: # Manual trigger

permissions:
contents: read

jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Python 3.10
uses: actions/setup-python@v3
with:
python-version: "3.10"
- name: Run test script
run: python3 tests/test.py
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -20,5 +20,6 @@ TAGS
*.pyc
*.log
*.bin
!tests/**/*.bin
core
.DS_STORE
16 changes: 16 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
FROM debian:bullseye

RUN set -xe; \
apt-get -yqq update; \
apt-get install -y libstdc++6 python2.7 python3 python3-pip; \
pip3 install lief;

COPY helpers /sandblaster/helpers/
COPY reverse-sandbox /sandblaster/reverse-sandbox
COPY sb_parser /sandblaster/sb_parser

WORKDIR /sandblaster/sb_parser

# apparently if you remove the 'make clean' line it goes bang :)
RUN make clean
RUN make
7 changes: 7 additions & 0 deletions sb_parser/.clang-format
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
BasedOnStyle: LLVM
IndentWidth: 4
TabWidth: 4
UseTab: Always
BreakBeforeBraces: Stroustrup
AllowShortIfStatementsOnASingleLine: false
IndentCaseLabels: false
16 changes: 16 additions & 0 deletions sb_parser/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
CXXFLAGS=-std=c++17

default: parser

block.o: block.hpp block.cpp

hasher.o: hasher.hpp hasher.cpp

string_utils.o: string_utils.hpp string_utils.cpp

parser: block.o hasher.o string_utils.o parser.cpp

.PHONY: clean

clean:
rm -rf parser *.o
147 changes: 147 additions & 0 deletions sb_parser/block.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
#include <algorithm>
#include <cstdio>

#include "block.hpp"
#include "hasher.hpp"
#include "string_utils.hpp"

Block::Block(StringHasher &hasher)
{
this->m_name = 0;

this->m_hasher = &hasher;
}

void Block::set_name(std::string str)
{
this->m_name = this->m_hasher->hash(str);
}

void Block::add_attr(std::string attr)
{
this->m_attributes.push_back(this->m_hasher->hash(attr));
}

void Block::add_child(Block *other) { this->m_children.push_back(other); }

std::string Block::to_string()
{
std::string name = this->m_hasher->reverse_hash(this->m_name);

std::string ans = "{\"name\": " + quote_string(name);

ans += ", \"attributes\": [";
if (!this->m_attributes.empty()) {
for (int attribute : this->m_attributes) {
ans += quote_string(this->m_hasher->reverse_hash(attribute)) + ",";
}

ans.pop_back();
}
ans += "], \"children\": [";
if (!this->m_children.empty()) {
for (Block *child_block_ptr : this->m_children) {
ans += child_block_ptr->to_string() + ",";
}
ans.pop_back();
}
ans += "]";

ans += "}";
return ans;
}

// todo maybe add comparator options here
int Block::compare_to(Block *other, bool skip_print)
{
//* check name first
if (this->m_name != other->m_name) {
if (!skip_print) {
std::fprintf(stderr, "Block names differ: '%s' vs '%s'\n",
this->m_hasher->reverse_hash(this->m_name).c_str(),
other->m_hasher->reverse_hash(other->m_name).c_str());
}

return this->m_name - other->m_name;
}

//* check attributes
//* check size first, if this fails, no need to sort
if (this->m_attributes.size() != other->m_attributes.size()) {
if (!skip_print) {
std::fprintf(stderr,
"Block attribute lengths differ: '%lu' vs '%lu'\n",
this->m_attributes.size(), other->m_attributes.size());
}

return ((int)(this->m_attributes.size())) -
((int)(other->m_attributes.size()));
}

//* check attribute values, sort first because order doesn't matter
std::sort(this->m_attributes.begin(), this->m_attributes.end());
std::sort(other->m_attributes.begin(), other->m_attributes.end());

for (int i = 0; i < (int)(this->m_attributes.size()); ++i) {
if (this->m_attributes[i] != other->m_attributes[i]) {
if (!skip_print) {
std::fprintf(
stderr, "Block attribute #%d differs: '%s' vs '%s'\n", i,
this->m_hasher->reverse_hash(this->m_attributes[i]).c_str(),
other->m_hasher->reverse_hash(other->m_attributes[i])
.c_str());
}
return this->m_attributes[i] - other->m_attributes[i];
}
}

//* check children
//* check size first, if this fails, no need to sort
if (this->m_children.size() != other->m_children.size()) {
if (!skip_print) {
std::fprintf(stderr,
"Block children lengths differ: '%lu' vs '%lu'\n",
this->m_children.size(), other->m_children.size());
}
return ((int)(this->m_children.size())) -
((int)(other->m_children.size()));
}

auto block_comparator = [](Block *i, Block *j) -> bool {
return i->compare_to(j, true) < 0;
};

std::sort(this->m_children.begin(), this->m_children.end(),
block_comparator);
std::sort(other->m_children.begin(), other->m_children.end(),
block_comparator);

for (int i = 0; i < (int)(this->m_children.size()); ++i) {
int result =
this->m_children[i]->compare_to(other->m_children[i], skip_print);

if (result != 0) {
if (!skip_print) {
std::fprintf(
stderr,
"Block child #%d differs: '%s' vs '%s' (see above error)\n",
i,
this->m_hasher->reverse_hash(this->m_children[i]->m_name)
.c_str(),
other->m_hasher->reverse_hash(other->m_children[i]->m_name)
.c_str());
}
return result;
}
}

//* if all checks pass, objects are equal
return 0;
}

Block::~Block()
{
for (Block *child_block_ptr : this->m_children) {
delete child_block_ptr;
}
}
30 changes: 30 additions & 0 deletions sb_parser/block.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#pragma once

#include <string>
#include <vector>

#include "hasher.hpp"

class Block {
public:
int m_name;
std::vector<int> m_attributes;
std::vector<Block *> m_children;

StringHasher *m_hasher;

public:
Block(StringHasher &hasher);

~Block();

void set_name(std::string str);

void add_attr(std::string str);

void add_child(Block *child);

std::string to_string();

int compare_to(Block *other, bool skip_print = false);
};
35 changes: 35 additions & 0 deletions sb_parser/hasher.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
#include "hasher.hpp"

#include <stdexcept>
#include <string>
#include <unordered_map>

StringHasher::StringHasher()
{
this->m_clean_id = 1;
this->m_hashmap = std::unordered_map<std::string, int>();
this->m_rev_hashmap = std::vector<std::string>();

this->m_rev_hashmap.push_back("default-name"); // reverse hash of 0
}

int StringHasher::hash(std::string str)
{
if (!this->m_hashmap.count(str)) {
this->m_hashmap[str] = this->m_clean_id;
this->m_rev_hashmap.push_back(str);
++(this->m_clean_id);
}

return this->m_hashmap[str];
}

std::string StringHasher::reverse_hash(int hash)
{
if (hash > this->m_rev_hashmap.size()) {
throw std::runtime_error("cannot reverse " + std::to_string(hash) +
" : invalid hash");
}

return this->m_rev_hashmap[hash];
}
19 changes: 19 additions & 0 deletions sb_parser/hasher.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#pragma once

#include <string>
#include <unordered_map>
#include <vector>

class StringHasher {
public:
int m_clean_id;
std::unordered_map<std::string, int> m_hashmap;
std::vector<std::string> m_rev_hashmap;

public:
StringHasher();

int hash(std::string str);

std::string reverse_hash(int hash);
};
Binary file added sb_parser/parser
Binary file not shown.
Loading