aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--README.md14
-rw-r--r--bruiser/README.md21
-rwxr-xr-xmutator.py144
-rw-r--r--obfuscator/README.md18
-rw-r--r--obfuscator/obfuscator.cpp117
-rw-r--r--test/bruisertest/test.cpp10
6 files changed, 301 insertions, 23 deletions
diff --git a/README.md b/README.md
index 7a568ee..4a4fa5e 100644
--- a/README.md
+++ b/README.md
@@ -127,16 +127,13 @@ All the as-of-yet implemented features of the project are very much buildable an
## Announcements
+* announcing `obfuscator`, the newest mutator family member. it's a C/C++ source obfuscation tool.<br/>
* mutator has a new experimental member, bruiser. The idea is that we are already inside the code, so why not break it?<br/>
* mutator now has a daemon,a server and a client. It works, but we all know how much weight we can put on "it just works", don't we? I'll be polishing it over the coming days. For more info and detail see `README.md` under `daemon` in project root. Also, please do note that you don't have to use the server feature. You can just run mutator like before. It's an added functionality. It does not modify previous functionality.<br/>
* mutator will be implementing [SaferCPlusPlus](https://github.com/duneroadrunner/SaferCPlusPlus) rule checks and automatic refactoring of code bases to use SaferCPlusPlus libraries. The first phase will begin with implementing the compliancy checks. You can read more about SaferCPlusPlus [here](http://duneroadrunner.github.io/SaferCPlusPlus/).<br/>
* mutator's first website is up: [project mutator](https://bloodstalker.github.io/mutator/).<br/>
* project mutator has changed licenses from LGPLv3 to GPLv2.<br/>
-* `mutator-lvl0` has reached a release candidate. I will branch a release candidate for it and then we can start the unit tests.<br/>
-* The Implementation of the automatic refactoring facilities of `mutator` has begun. The UI is not yet capable of accomodating the current features so I'll try to add them as soon as possible.<br/>
-* The Travis build is now using 4.0 for build checks. LLVM 3.9 is still supported minus rule check 8.8 which uses a non-existant matcher in 3.9.<br/>
* There are no plans in regards to keeping or dropping LLVM 3.9 support but do keep in mind the libraries mutator uses are not guaranteed to keep backwards-compatibility by their developers as they are still under development.<br/>
-* There are only 4 actual defects on mutator's Coverity scan that belong to mutator's source code and not the library. 4 are potential defects which are not really defects.<br/>
## Building and Running
@@ -363,6 +360,10 @@ Project mutator uses the following cool libraries:
* [Linenoise](https://github.com/antirez/linenoise)
* [Lua](https://github.com/lua/lua)
* [LuaJIT](https://github.com/LuaJIT/LuaJIT)
+* Thanks to [Jonathan Brossard](https://github.com/endrazine) for [WCC](https://github.com/endrazine/wcc), specifically `wsh` which is the inspiration for `bruiser`.<br/>
+
+All mutator source code is provided under GPL-2.0.<br/>
+All libraries have their respective licences. for more info you can just visit their respective links.<br/>
### Feedback
If you run into an issue please raise one here or just contact me with proper information(including source code that causes the issue if there is any).<br/>
@@ -372,10 +373,7 @@ You can make a new issue for requests and suggestion. label them with "Feauture
Besides that, If you have any suggestions or have any feature requests for project mutator, you can send them to `thabogre@gmail.com`. I'll try to keep an open mind, so even if you feel like it might not be right up mutator's alley, do send them. Worst case, I'll just say no.<br/>
### TODO List
-* Misra-c:2012 and 98 check support<br/>
-* Ability to turn off some rule checks<br/>
-* Using Appveyor to test windows builds<br/>
-* Have the server capture stderr<br/>
+For a list of things that need to be done, take a look at the list of issues.<br/>
### Contributions
For a full description please read `Contributions.md` in the repo root.<br/>
diff --git a/bruiser/README.md b/bruiser/README.md
index cd4e341..97c0f67 100644
--- a/bruiser/README.md
+++ b/bruiser/README.md
@@ -6,30 +6,33 @@ Regarding the actual functionality, it will feature non-blind selective mutation
### How does it work?
To put it simply, bruiser is an interactive lua interpreter that uses linenoise for shell-like features(history, tab-completion, auto-suggestion). You get the full power of lua plus the bruiser functions whcih are implemented as lua scripts that call back to the cpp code to get things done.<br/>
-To put this into perspecttive, think you run `list vars` in bruiser. It gets you the list of vars but that's it. You can't save them to a file or do anything else with them. With the old way of doing things I had to add a command that did that and then you could do it but what if you wanted to do something else? what then? well you get the idea. That would also mean that bruiser's language would be made up gradually which would result in something ugly and warrant a lot of rewrites.<br/>
+To put this into perspective, think you run `list vars` in bruiser. It gets you the list of vars but that's it. You can't save them to a file or do anything else with them. With the old way of doing things I had to add a command that did that and then you could do it but what if you wanted to do something else? What then? Well you get the idea. That would also mean that bruiser's language would be made up gradually which would result in something ugly and warrant a lot of rewrites.<br/>
With the new way of doing things, the user is only limited by their imagination and lua, not me, and there is no learning curve for learning a garbage language that I would have to come up with.<br/>
-Also, there is no reason to implement any extra features to be able to automate your use of bruiser. just run a lua script and tell bruiser to run that.<br/>
+Also, there is no reason to implement any extra features to be able to automate your use of bruiser. Just run a lua script and tell bruiser to run that.<br/>
### DSL?
-bruiser has an embedded lua interpreter so nobody would have to deal with a new DSL. It's good old lua.<br/>
+Bruiser has an embedded lua interpreter so nobody would have to deal with a new DSL. It's good old lua.<br/>
### Lua vs Luajit
In the current implementation, bruiser will only support lua and not luajit. luajit is way faster than lua which will play an important role in bruiser's overall performance but luajit is generally less stable than lua and usually behind in terms of what new features of lua the language it supports.<br/>
The plan is to add both and for the user to be able to pick which one to use when running bruiser.<br/>
+### Prototyping
+I embedded the ability to run python scripts from C++ in bruiser. The feature was added to facilitate fast prototyping since I'd rather first do the experimental features in python and run them through bruiser and then re-implement them in C++ if speed is an actual concern.<br/>
+
### Warning
The current implementation loads all lua libraries which also includes it's `os` library. To give you an idea, `os.execute()` is very similar to `system()` in C. This decision has been made to speed up testing and the dev process.<br/>
Also like `mutatord` and `mutatorclient`, bruiser does not need any sudo access.<br/>
### Non-blind Selective mutation?
-bruiser looks at your code, learns your code and then decides how to mutate your code. That's non-blind selective mutation. now onto a real explanation:<br/>
-`m0` generates two sets of reports. one is the rules it checks on code which is for the better part, at the time of writing this very similar to Misra-c. The second report is the ancestry of the node that caused `m0` to tag a node in the first report. the second report is an experimental first attempt at narrowing down the parts of the code that would be better targets for mutation.<br/>
-The second point concerns the mutation opertors. The classical mutation operators are blind. Let me demonstrate with an example:<br/>
+Bruiser looks at your code, learns your code and then decides how to mutate your code. That's non-blind selective mutation. Now onto a real explanation:<br/>
+`m0` generates two sets of reports. One is the rules it checks on code which is for the better part, at the time of writing this very similar to Misra-c. The second report is the ancestry of the node that caused `m0` to tag a node in the first report. The second report is an experimental first attempt at narrowing down the parts of the code that would be better targets for mutation.<br/>
+The second point concerns the mutation operators. The classical mutation operators are blind. Let me demonstrate with an example:<br/>
Imagine we have a classical mutation operator that mutates all `+` operators to `-`. This mutation operator is blind. To put it in simple terms, it takes in text and spits out text with no regards to syntax or semantics.<br/>
`bruiser` will not be using classical blind mutation operators.<br/>
### How?
-I'm going to wrire about it as soon as I get my thoughts organized. In the meantime you can look at the source code for some hints.<br/>
+I'm going to write about it as soon as I get my thoughts organized. In the meantime you can look at the source code for some hints.<br/>
### Example
First you should clone the mutator repo and run `git submodule init` and `git submodule update` to get the cool third-party repos that enable mutator to run.<br/>
@@ -43,7 +46,7 @@ After building bruiser, you can run it like any other mutator tool. So for examp
```
After that you can just run your commands.<br/>
-To run you commands from a lua file, you can just use `dofile()` to call your script. bruiser has an embedded lua interpreter with the bruiser functions registered in it, so you do have full access to all lua libraries and functionalities plus the added bruiser functionality.<br/>
+To run you commands from a lua file, you can just use `dofile()` to call your script. Bruiser has an embedded lua interpreter with the bruiser functions registered in it, so you do have full access to all lua libraries and functionalities plus the added bruiser functionality.<br/>
For example you can run one of the example scripts that come with bruiser like this:<br/>
```lua
@@ -59,4 +62,4 @@ You can also run bruiser in non-cli mode:<br/>
```
-bruiser requires a compilation database to run. If you don't have a compilation database, take a look at [Bear](https://github.com/rizsotto/Bear). If you're using `cmake`, just tell it to generate a compilation database.<br/>
+Bruiser requires a compilation database to run. If you don't have a compilation database, take a look at [Bear](https://github.com/rizsotto/Bear). If you're using `cmake`, just tell it to generate a compilation database.<br/>
diff --git a/mutator.py b/mutator.py
new file mode 100755
index 0000000..376140c
--- /dev/null
+++ b/mutator.py
@@ -0,0 +1,144 @@
+#!/bin/python3
+
+import argparse
+import sys
+from subprocess import call
+
+class Colors:
+ purple = '\033[95m'
+ blue = '\033[94m'
+ green = '\033[92m'
+ yellow = '\033[93m'
+ red = '\033[91m'
+ grey = '\033[1;37m'
+ darkgrey = '\033[1;30m'
+ cyan = '\033[1;36m'
+ ENDC = '\033[0m'
+ BOLD = '\033[1m'
+ UNDERLINE = '\033[4m'
+
+class ArgParser(object):
+ def __init__(self):
+ self.inputs = []
+ self.outputs = []
+ self.opts = []
+ self.copts = []
+ self.command = []
+ self.pretty = bool
+ parser = argparse.ArgumentParser()
+ parser.add_argument("-help", action='store_true', help="display the driver's help", default=False)
+ parser.add_argument("-f", "--file", type=str, help="run an action file")
+ parser.add_argument("-c", "--command", type=str, help="run a command")
+ parser.add_argument("-v", "--version", action='store_true', help="display version info", default=False)
+ parser.add_argument("-i", "--input", type=str, help="the input file(s)")
+ parser.add_argument("-o", "--output", type=str, help="the output file(s)")
+ parser.add_argument("-pp", "--print-pretty", action='store_true', help="print pretty simple text reports", default=False)
+ parser.add_argument("-t", "--test", type=str, help="runs the tests on the built executables")
+ parser.add_argument("-opts", "--options", type=str, help="pass clang options to the executables")
+ parser.add_argument("-copts", "--custom-options", type=str, help="runs the tests on the built executables")
+ self.args = parser.parse_args()
+
+ def run(self):
+ if self.args.file is not None:
+ self.parseActionFile(self.args.file)
+ if self.args.command is not None:
+ self.runCommand(self.args.command)
+
+ def runTest(self):
+ pass
+
+ def parseActionFile(self, action_file_path):
+ line_number = int()
+ action_file = open(action_file_path)
+ self.inputs = str
+ self.outputs = str
+ self.opts = str
+ self.copts = str
+ self.command = str
+ self.logfile = str
+ self.pretty = bool
+ self.exename = str
+ self.endaction = str
+ self.action_name = str
+ for line in action_file:
+ line_number += 1
+ pos = line.find("action_name:", 0, len(line))
+ if pos == 0:
+ self.action_name = line[pos+len("action_name:"):-1]
+ print(Colors.green + "action name: " + Colors.cyan + self.action_name + Colors.ENDC)
+ pos = line.find("executable_name:", 0, len(line))
+ if pos == 0:
+ self.exename = line[pos+len("executable_name:"):-1]
+ print(Colors.green + "executable_name: " + Colors.cyan + self.exename + Colors.ENDC)
+ pos = line.find("exec_opts:", 0, len(line))
+ if pos == 0:
+ self.copts = line[pos+len("exec_opts:"):-1]
+ print(Colors.green + "exec options: " + Colors.cyan + self.copts + Colors.ENDC)
+ pos = line.find("in_files:", 0, len(line))
+ if pos == 0:
+ self.inputs = line[pos+len("in_files:"):-1]
+ print(Colors.green + "input files: " + Colors.cyan + self.inputs + Colors.ENDC)
+ pos = line.find("libtooling_options:", 0, len(line))
+ if pos == 0:
+ self.opts = line[pos+len("libtooling_options:"):-1]
+ print(Colors.green + "libtooling options: " + Colors.cyan + self.opts + Colors.ENDC)
+ pos = line.find("out_files:", 0, len(line))
+ if pos == 0:
+ self.outputs = line[pos+len("out_files:"):-1]
+ print(Colors.green + "output files: " + Colors.cyan + self.outputs + Colors.ENDC)
+ pos = line.find("log_files:", 0, len(line))
+ if pos == 0:
+ self.logfile = line[pos+len("log_files:"):-1]
+ print(Colors.green + "log files: " + Colors.cyan + self.logfile + Colors.ENDC)
+ pos = line.find("print_pretty:", 0, len(line))
+ if pos == 0:
+ if line[pos+len("print_pretty:"):-1] == "true": self.pretty = True
+ elif line[pos+len("print_pretty:"):-1] == "false": self.pretty = False
+ else: raise Exception(Colors.red + repr(line_number) + " : " + "invalid value for a boolean switch. should be true or false." + Colors.ENDC)
+ print(Colors.green + "pretty print: " + Colors.cyan + repr(self.pretty) + Colors.ENDC)
+ pos = line.find("end_action:", 0, len(line))
+ if pos == 0:
+ self.endaction = line[pos+len("end_action:"):-1]
+ print(Colors.green + "end action: " + Colors.cyan + self.endaction + Colors.ENDC)
+
+ def runActionFile(self):
+ pass
+
+ def printVersionInfo(self):
+ pass
+
+ def runCommand(self, command):
+ if command == "clean":
+ call(["make", "clean"])
+ elif command == "build":
+ call(["make", "all"])
+ elif command == "install":
+ call(["make", "install"])
+ elif command == "format":
+ pass
+ elif command == "test":
+ pass
+ elif command == "build-all":
+ call(["make", "build-all"])
+ elif command == "m0":
+ pass
+ elif command == "m1":
+ pass
+ elif command == "m2":
+ pass
+ elif command == "bruiser":
+ pass
+ elif command == "obfuscator":
+ pass
+ elif command == "safercpp":
+ pass
+ else:
+ raise Exception(Colors.red + "unknown command. for a list of valid commands run with -h." + Colors.ENDC);
+
+
+def main():
+ argparser = ArgParser()
+ argparser.run()
+
+if __name__ == "__main__":
+ main()
diff --git a/obfuscator/README.md b/obfuscator/README.md
new file mode 100644
index 0000000..585c054
--- /dev/null
+++ b/obfuscator/README.md
@@ -0,0 +1,18 @@
+# obfuscator
+
+obfuscator is a C/C++ source-code obfuscation tool.<br/>
+
+## Status
+obfuscator is not feature-complete yet. Below you can find a list of the implemented features and the ones that will be implemented.<br/>
+If you have suggestions or recommendations for features to add please make an issue with the `obfuscator` label.<br/>
+
+### Implemented Features
+* Identifier Obfuscation: Swaps the name of all identifiers with their hash. <br/>
+
+### Future Features
+* Obfuscation Exclusion List: obfuscator will accept a list of idenftifiers and their namespace and will not obfuscate those. This feature is added so the user can refrain from obfuscating the standard library.<br/>
+* Whitespace Deletion: Pretty much kills all whitespace where it doesn't change the syntax.<br/>
+* Comment Deletion: Deletes all comments.<br/>
+
+## Notes
+* Currently the hash function that is being used is `std::hash<>`. The GCC implementation will be probably the default option since the digest is shorter than 32 characters long. The decision was made since quite a few embedded C/C++ compilers can't correctly handle identifiers longer than 32 characters(implementation limitations).<br/>
diff --git a/obfuscator/obfuscator.cpp b/obfuscator/obfuscator.cpp
index 5d1171b..f987fc8 100644
--- a/obfuscator/obfuscator.cpp
+++ b/obfuscator/obfuscator.cpp
@@ -29,6 +29,8 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.*
#include <iostream>
#include <cassert>
#include <vector>
+#include <fstream>
+#include <regex>
/*LLVM headers*/
#include "clang/AST/AST.h"
#include "clang/AST/ASTConsumer.h"
@@ -162,11 +164,19 @@ public:
#ifdef DBG
std::cout << "Var name: " << varname << " Hash: " << hash << " New ID: " << newname << "\n";
#endif
-
SourceLocation SL = VD->getLocation();
- SourceLocation SLE = VD->getLocEnd();
+ SourceLocation SLE;
+ const clang::Expr* EXP = nullptr;
+
+ if (MR.Nodes.getNodeAs<clang::Expr>("expr") !=nullptr) {
+ EXP = MR.Nodes.getNodeAs<clang::Expr>("expr");
+ SLE = EXP->getExprLoc();
+ } else {
+ SLE = VD->getLocEnd();
+ }
- Rewrite.ReplaceText(SourceRange(SL, SLE), StringRef(newname));
+ //@devi-FIXME-cluncky
+ Rewrite.ReplaceText(SourceRange(SL, SL.getLocWithOffset(VD->getIdentifier()->getLength() - 1)), StringRef(newname));
}
}
@@ -245,7 +255,7 @@ class MyASTConsumer : public ASTConsumer {
public:
MyASTConsumer(Rewriter &R) : funcDeclHandler(R), HandlerForVar(R), HandlerForClass(R), HandlerForCalledFunc(R), HandlerForCalledVar(R) {
Matcher.addMatcher(functionDecl().bind("funcdecl"), &funcDeclHandler);
- Matcher.addMatcher(varDecl().bind("vardecl"), &HandlerForVar);
+ Matcher.addMatcher(varDecl(anyOf(unless(hasDescendant(expr(anything()))), hasDescendant(expr(anything()).bind("expr")))).bind("vardecl"), &HandlerForVar);
Matcher.addMatcher(recordDecl(isClass()).bind("classdecl"), &HandlerForClass);
//Matcher.addMatcher(callExpr().bind("calledfunc"), &HandlerForCalledFunc);
Matcher.addMatcher(declRefExpr().bind("calledvar"), &HandlerForCalledVar);
@@ -267,9 +277,16 @@ private:
class ObfFrontendAction : public ASTFrontendAction {
public:
ObfFrontendAction() {}
- ~ObfFrontendAction() {delete BDCProto;}
+ ~ObfFrontendAction() {
+ delete BDCProto;
+ delete tee;
+ }
void EndSourceFileAction() override {
+ std::error_code EC;
+ std::string OutputFilename = "./obfuscator-tee";
TheRewriter.getEditBuffer(TheRewriter.getSourceMgr().getMainFileID()).write(llvm::outs());
+ tee = new raw_fd_ostream(StringRef(OutputFilename), EC, sys::fs::F_None);
+ TheRewriter.getEditBuffer(TheRewriter.getSourceMgr().getMainFileID()).write(*tee);
}
std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI, StringRef file) override {
@@ -283,13 +300,101 @@ public:
private:
BlankDiagConsumer* BDCProto = new BlankDiagConsumer;
Rewriter TheRewriter;
+ raw_ostream *tee = &llvm::outs();
+};
+/**********************************************************************************************************************/
+class CommentWiper {
+ public:
+ CommentWiper(std::vector<std::string> SourceList) : sourcelist(SourceList) {}
+
+ int run(void) {
+ for (auto &filepath : sourcelist) {
+ //std::regex comment1("//.+");
+ //std::regex comment2("/\\*.+\\*/");
+ //std::regex comment2("/\\*[^]+\\*/");
+ //std::regex multibegin("/\\*.+(?!\\*/)");
+ //std::regex multiend("(?<!/\\*).+\\*/");
+ //std::smatch result;
+ //bool multiline;
+ bool slash, backslash, quote, star, multiline;
+ unsigned int ch_prv;
+
+ std::ifstream sourcefile;
+ sourcefile.open("../test/bruisertest/obfuscator-tee");
+ std::ofstream dupe;
+ dupe.open("./dupe.cpp");
+ std::string line;
+ while (std::getline(sourcefile, line)) {
+ line += "\n";
+ for (unsigned int ch = 0; ch < line.length(); ++ch) {
+ if (line[ch] == atoi("/")) slash = true;
+ if (line[ch] == atoi("\\")) backslash = true;
+ if (line[ch] == atoi("\"")) quote = true;
+ if (line[ch] == atoi("*")) star = true;
+ ch_prv = ch;
+ }
+ //if (std::regex_search(line, result, comment1)) {std::cout << "11111" << result.str() << "\n";}
+ //if (std::regex_search(line, result, comment2)) {std::cout << "22222" << result.str() << "\n";}
+ //if (std::regex_search(line, result, multibegin)) {std::cout << "33333" << result.str() << "\n";}
+ //if (std::regex_search(line, result, multiend)) {std::cout << "44444" << result.str() << "\n";}
+ dupe << line << "\n";
+ }
+ sourcefile.close();
+ dupe.close();
+ }
+ return 0;
+ }
+
+ private:
+ std::vector<std::string> sourcelist;
+};
+/**********************************************************************************************************************/
+class WhitespaceWarper {
+ public:
+ WhitespaceWarper(std::vector<std::string> SourceList) : sourcelist(SourceList) {}
+
+ int run(void) {
+ for (auto &filepath : sourcelist) {
+ std::ifstream sourcefile;
+ sourcefile.open("../test/bruisertest/obfuscator-tee");
+ std::ofstream dupe;
+ dupe.open("./dupe.cpp");
+ std::string line;
+ while (std::getline(sourcefile, line)) {
+ for (auto &character : line) {
+ if (std::to_string(character) == "\t") {
+ dupe << "\t";
+ }
+ else if (std::to_string(character) == "\n") {
+ }
+ else if (std::to_string(character) == " ") {
+ dupe << " ";
+ }
+ else {
+ dupe << character;
+ }
+ }
+ }
+ dupe.close();
+ }
+ return 0;
+ }
+
+ private:
+ std::vector<std::string> sourcelist;
};
/**********************************************************************************************************************/
/*Main*/
int main(int argc, const char **argv) {
CommonOptionsParser op(argc, argv, MatcherSampleCategory);
+ const std::vector<std::string> &SourcePathList = op.getSourcePathList();
ClangTool Tool(op.getCompilations(), op.getSourcePathList());
- return Tool.run(newFrontendActionFactory<ObfFrontendAction>().get());
+ int ret = Tool.run(newFrontendActionFactory<ObfFrontendAction>().get());
+ WhitespaceWarper WW(SourcePathList);
+ //WW.run();
+ CommentWiper CW(SourcePathList);
+ CW.run();
+ return ret;
}
/**********************************************************************************************************************/
/*last line intentionally left blank.*/
diff --git a/test/bruisertest/test.cpp b/test/bruisertest/test.cpp
index 78630e8..9b0ce2f 100644
--- a/test/bruisertest/test.cpp
+++ b/test/bruisertest/test.cpp
@@ -33,6 +33,16 @@ namespace devi
int main(int argc, const char **argv)
{
+ /***hya**/
+ /*
+ *
+ * */
+ // /**/
+ int bubba; // this one
+ int hubba; /*
+ *
+ */
+ //std::cout << "//" << "/**/" << "\n";
#if 0
std::ofstream myfile;
myfile.open("./touch");