Reputation: 285
How can I create my own virus signature of a .exe or .lib file? I started my reading certain bytes to the file and then just storing them in another file and manually adding this to a virus scanner. Will this work? thanks
Upvotes: 1
Views: 4683
Reputation: 89
First must understand differences of hash-based (versus signature based analysis,) plus the static analyses (which executables should pass.) produceAbortListSignatures
produces signatures for antivirus.
Disclaimer: am author of this FLOSS code. Dual licenses: choose Creative Commons or Apache 2 (allows all uses).
[ Version of post is ?cxx/ClassSys.*xx %s/vector<const /vector<
SwuduSusuwu/SubStack@ee7c23a ] For the most new sources (+ static libs), use apps such as iSH (for iOS) or Termux (for Android OS) to run this:
git clone https://github.com/SwuduSusuwu/SubStack.git && cd ./Substack/ && ./build.sh
less
cxx/ClassPortableExecutable.hxx
typedef std::string FilePath;
typedef FilePath FileBytecode;
typedef FilePath FileHash;
typedef class PortableExecutable : Object {
public:
PortableExecutable(FilePath path_ = "") : path(path_) {}
PortableExecutable(FilePath path_, FileBytecode bytecode_) : path(path_), bytecode(bytecode_) {}
const std::string getName() const {return "Susuwu::class PortableExecutable";}
FilePath path; /* Suchas "C:\Program.exe" or "/usr/bin/library.so" */
FileBytecode bytecode; /* compiled programs; bytecode */
std::string hex; /* `hexdump(path)`, hexadecimal, for C string functions */
} PortableExecutable;
typedef class PortableExecutableBytecode : public PortableExecutable {
public:
PortableExecutableBytecode(FilePath path_) : input(path_) {path = path_; if(input.good()) {bytecode = std::string(std::istreambuf_iterator<char>(input), std::istreambuf_iterator<char>());}}
std::ifstream input;
} PortableExecutableBytecode;
less
cxx/ClassSha2.cxx
/* Uses https://www.rfc-editor.org/rfc/rfc6234#section-8.2.2 */
FileHash sha2(const FileBytecode &bytecode) {
FileHash result;
SHA256Context context;
result.resize(SHA256HashSize);
SHA256Reset(&context);
SHA256Input(&context, reinterpret_cast<const unsigned char *>(bytecode.c_str()), bytecode.size());
SHA256Result(&context, const_cast<unsigned char *>(reinterpret_cast<const unsigned char *>(result.c_str())));
return result;
}
typedef FileHash ResultListHash;
typedef FileBytecode ResultListBytecode;
typedef FilePath ResultListSignature;
typedef ptrdiff_t BytecodeOffset;
typedef struct ResultList /* : Object */ {
const std::string getName() const {return "Susuwu::struct ResultList";}
std::unordered_set<ResultListHash> hashes; /* Checksums of executables (or pages); to avoid duplicates, plus to do constant ("O(1)") test for which executables (or pages) exists */
std::vector<ResultListSignature> signatures; /* Smallest substrings (or regexes, or Universal Resource Locators) which can identify `bytecodes`; has uses close to `hashes`, but can match if executables (or pages) have small differences */
std::vector<ResultListBytecode> bytecodes;
} ResultList;
template<class List>
const size_t listMaxSize(const List &list) {
auto it = std::max_element(list.cbegin(), list.cend(), [](const auto &s, const auto &x) { return s.size() < x.size(); });
return it->size();
}
template<class List>
void listDumpTo(const List &list, std::ostream &os, const bool index, const bool whitespace, const bool pascalValues) {
size_t index_ = 0;
os << '{';
for(const auto &value : list) {
if(0 != index_) {
os << ',';
}
if(whitespace) {
os << std::endl << '\t';
}
if(index) {
os << index_;
}
if(pascalValues) {
os << value.size() << value;
} else {
os << (index ? "=>0x" : "0x");
for(char ch : value) {
os << std::hex << static_cast<int>(ch);
}
os << std::dec;
}
++index_;
}
if(whitespace) {
os << "\n};" << std::endl;
} else {
os << "};";
}
}
template<class List>
void resultListDumpTo(const List &list, std::ostream &os, const bool index, const bool whitespace, const bool pascalValues) {
os << "list.hashes" << (whitespace ? " = " : "=");
listDumpTo(list.hashes, os, index, whitespace, pascalValues);
os << "list.signatures" << (whitespace ? " = " : "=");
listDumpTo(list.signatures, os, index, whitespace, pascalValues);
os << "list.bytecodes" << (whitespace ? " = " : "=");
listDumpTo(list.bytecodes, os, index, whitespace, pascalValues);
}
template<class List, class List2>
void listToHashes(const List &list /* ResultList::bytecodes or ResultList::hex*/, List2 &hashes /* ResultList::hashess */) {
for(const auto &value : list) {
hashes.insert(sha2(value));
}
}
static void resultListProduceHashes(ResultList &resultList) {
listToHashes(resultList.bytecodes, resultList.hashes);
}
/* @pre @code std::is_sorted(list.cbegin(), list.cend()) && std::is_sorted(list2.cbegin(), list2.cend()) @endcode */
template<class List>
const List listIntersections(const List &list, const List &list2) {
List intersections;
std::set_intersection(list.cbegin(), list.cend(), list2.cbegin(), list2.cend(), std::back_inserter(intersections));
return intersections;
}
template<class List>
const bool listsIntersect(const List &list, const List &list2) {
return listIntersections(list, list2).size();
}
template<class List>
auto listFindValue(const List &list, const typename List::value_type &value) {
return std::find(list.cbegin(), list.cend(), value);
}
template<class List>
const bool listHasValue(const List &list, const typename List::value_type &value) {
return list.cend() != listFindValue(list, value);
}
template<class List>
const typename List::value_type::const_iterator listDefaultIterator = typename List::value_type::const_iterator(); /* Equates to "Not found" */
template<class List>
/* @pre @code itBegin < itEnd @endcode */
typeof listDefaultIterator<List> listFindSubstr(const List &list, typename List::value_type::const_iterator itBegin, typename List::value_type::const_iterator itEnd) {
#pragma unroll
for(const auto &value : list) {
auto result = std::search(value.cbegin(), value.cend(), itBegin, itEnd, [](char chValue, char chIt) { return chValue == chIt; });
if(value.cend() != result) {
return result;
}
}
return listDefaultIterator<List>;
}
template<class List>
/* @pre @code itBegin < itEnd @endcode */
const bool listHasSubstr(const List &list, typename List::value_type::const_iterator itBegin, typename List::value_type::const_iterator itEnd) {
return listDefaultIterator<List> != listFindSubstr(list, itBegin, itEnd);
}
template<class List>
const std::tuple<typename List::value_type::const_iterator, typename List::value_type::const_iterator> listProduceSignature(const List &list, const typename List::value_type &value) {
size_t smallest = value.size();
auto itBegin = value.cbegin(), itEnd = value.cend();
for(auto first = itBegin; value.cend() != first; ++first) {
for(auto last = value.cend(); first != last; --last) {
if((last - first) < smallest) {
if(listHasSubstr(list, first, last)) {
break;
}
smallest = last - first;
itBegin = first, itEnd = last;
}
}
}
return {itBegin, itEnd};
}
typedef struct ResultListSignatureMatch {
BytecodeOffset fileOffset;
ResultListSignature signature;
} ResultListSignatureMatch;
#include "Macros.hxx" /* SUSUWU_DEBUG */
template<class List>
ResultListSignatureMatch listFindSignatureOfValue(const List &list, const typename List::value_type &value) {
for(const auto &signature : list) {
auto it = std::search(value.cbegin(), value.cend(), signature.cbegin(), signature.cend(), [](char ch1, char ch2) { return ch1 == ch2; });
if(signature.cend() != it) {
return {it - value.cbegin(), signature};
}
}
return {-1, ""};
}
template<class List>
const bool listHasSignatureOfValue(const List &list, const typename List::value_type &value) {
return -1 != listFindSignatureOfValue(list, value).fileOffset;
}
template<class S>
const std::vector<S> explodeToList(const S &s, const S &token) {
std::vector<S> list;
for(auto x = s.cbegin(); s.cend() != x; ) {
auto it = std::search(x, s.cend(), token.cbegin(), token.cend(), [](char ch1, char ch2) { return ch1 == ch2; });
list.push_back(S(x, it));
if(s.cend() == x) {
return list;
}
x = it;
}
return list;
}
less
cxx/ClassSys.hxx
extern int classSysArgc;
extern const char **classSysArgs;
bool classSysInit(int argc, const char *args[]);
/* @pre @code (-1 != access(argv[0], X_OK) @endcode */
const pid_t execvesFork(const std::vector<std::string> &argvS = {}, const std::vector<std::string> &envpS = {});
static const pid_t execvexFork(const std::string &toSh) {return execvesFork({"/bin/sh", "-c", toSh});}
const int execves(const std::vector<std::string> &argvS = {}, const std::vector<std::string> &envpS = {});
static const int execvex(const std::string &toSh) {return execves({"/bin/sh", "-c", toSh});}
const bool hasRoot();
const bool setRoot(bool root);
template<typename Func, typename... Args>
auto templateCatchAll(Func func, const std::string &funcName, Args... args) {
try {
return func(args...);
} catch (const std::exception &ex) {
SUSUWU_CERR(ERROR, funcName + " {throw std::exception(\"" + ex.what() + "\");}");
return decltype(func(args...))();
}
}
typedef enum VirusAnalysisHook : char {
virusAnalysisHookDefault = 0, /* "real-time" virus scans not initialized */
virusAnalysisHookQuery = 0, /* return present hooks (as enum) */
virusAnalysisHookClear = 1 << 0, /* unhook (remove present hooks), then parse rest of bits */
virusAnalysisHookExec = 1 << 1, /* hook {execl(), execlp(), execle(), execv(), execvp(), execvpe()} */
virusAnalysisHookNewFile = 1 << 2, /* hook (for modeNew in {"w+", "a", "a+"}) fwrite((void *)ptr, (size_t)size, (size_t)nmemb, {fopen((const char *)pathname, modeNew), fdopen((int)fd, modeNew), freopen((const char *)pathname, modeNew, (FILE *)stream)}) */
}
} VirusAnalysisHook;
static const VirusAnalysisHook operator|(VirusAnalysisHook x, VirusAnalysisHook s) {return static_cast<VirusAnalysisHook>(static_cast<unsigned>(x) | static_cast<unsigned>(s));}
static const VirusAnalysisHook operator&(VirusAnalysisHook x, VirusAnalysisHook s) {return static_cast<VirusAnalysisHook>(static_cast<unsigned>(x) & static_cast<unsigned>(s));}
static VirusAnalysisHook globalVirusAnalysisHook = virusAnalysisHookDefault;
typedef enum VirusAnalysisResult : char {
virusAnalysisAbort = static_cast<char>(false), /* do not launch */
virusAnalysisPass = static_cast<char>(true), /* launch this (file passes) */
virusAnalysisRequiresReview, /* submit to hosts to do analysis */
virusAnalysisContinue /* continue to next tests */
} VirusAnalysisResult;
extern ResultList passList, abortList;
extern Cns analysisCns, virusFixCns;
/* @pre @code analysisCns.hasImplementation() && virusFixCns.hasImplementation() @endcode */
const bool virusAnalysisTests();
static const bool virusAnalysisTestsNoexcept() NOEXCEPT {return templateCatchAll(virusAnalysisTests, "virusAnalysisTests()");}
const bool virusAnalysisHookTests;
static const bool virusAnalysisHookTestsNoexcept() NOEXCEPT {return templateCatchAll(virusAnalysisHookTests, "virusAnalysisHookTests()");}
const VirusAnalysisHook virusAnalysisHook(VirusAnalysisHook);
static const VirusAnalysisHook virusAnalysisGetHook() {return virusAnalysisHook(virusAnalysisHookQuery);}
const VirusAnalysisResult hashAnalysis(const PortableExecutable &file, const ResultListHash &fileHash);
/* To produce virus signatures:
* use passlists (of files reviewed which pass),
* plus abortlists (of files which failed), such lists as Virustotal has.
* `produceAbortListSignatures()` is to produce the `abortList.signatures` list, with the smallest substrings unique to infected files; is slow, requires huge database of executables; just hosts should produce this.
* For clients: Comodo has lists of virus signatures to check against at https://www.comodo.com/home/internet-security/updates/vdp/database.php
* @pre @code passList.bytecodes.size() && abortList.bytecodes.size() && !listsIntersect(passList.bytecodes, abortList.bytecodes) @endcode
* @post @code abortList.signatures.size() @endcode */
void produceAbortListSignatures(const ResultList &passList, ResultList &abortList);
/* @pre @code abortList.signatures.size() @endcode */
const VirusAnalysisResult signatureAnalysis(const PortableExecutable &file, const ResultListHash &fileHash);
/* @throw bad_alloc */
const std::vector<std::string> importedFunctionsList(const PortableExecutable &file);
extern std::vector<std::string> syscallPotentialDangers;
const VirusAnalysisResult staticAnalysis(const PortableExecutable &file, const ResultListHash &fileHash);
const VirusAnalysisResult sandboxAnalysis(const PortableExecutable &file, const ResultListHash &fileHash);
extern std::vector<std::string> stracePotentialDangers;
const VirusAnalysisResult straceOutputsAnalysis(const FilePath &straceOutput); /* TODO: regex */
/* @pre @code cns.hasImplementation() && pass.bytecodes.size() && abort.bytecodes.size() @endcode
* @post @code cns.isInitialized() @endcode */
void produceAnalysisCns(const ResultList &pass, const ResultList &abort,
const ResultList &unreviewed = ResultList(),
Cns &cns = analysisCns
);
/* @pre @code cns.isInitialized() @endcode */
const float cnsAnalysisScore(const PortableExecutable &file, const ResultListHash &fileHash, const Cns &cns = analysisCns);
/* @pre @code cns.isInitialized() @endcode */
const VirusAnalysisResult cnsAnalysis_(const PortableExecutable &file, const ResultListHash &fileHash, const Cns &cns = analysisCns);
const VirusAnalysisResult cnsAnalysis(const PortableExecutable &file, const ResultListHash &fileHash);
extern std::map<ResultListHash, VirusAnalysisResult> hashAnalysisCaches, signatureAnalysisCaches, staticAnalysisCaches, cnsAnalysisCaches, sandboxAnalysisCaches;
typedef const VirusAnalysisResult (*VirusAnalysisFun)(const PortableExecutable &file, const ResultListHash &fileHash);
extern std::vector<typeof(VirusAnalysisFun)> virusAnalyses;
const VirusAnalysisResult virusAnalysis(const PortableExecutable &file);
static const VirusAnalysisResult submitSampleToHosts(const PortableExecutable &file) {return virusAnalysisRequiresReview;} /* TODO */
/* @pre @code cns.hasImplementation() @endcode
* @post @code cns.isInitialized() @encode */
void produceVirusFixCns(
const ResultList &passOrNull, /* Expects `resultList->bytecodes[x] = NULL` if does not pass */
const ResultList &abortOrNull, /* Expects `resultList->bytecodes[x] = NULL` if does pass */
Cns &cns = virusFixCns
);
/* @pre @code cns.isInitialized() @endcode */
const std::string cnsVirusFix(const PortableExecutable &file, const Cns &cns = virusFixCns);
VirusAnalysisHook globalVirusAnalysisHook = virusAnalysisHookDefault;
ResultList passList, abortList;
Cns analysisCns, virusFixCns;
std::vector<std::string> syscallPotentialDangers = {
"memopen", "fwrite", "socket", "GetProcAddress", "IsVmPresent"
};
std::vector<std::string> stracePotentialDangers = {"write(*)"};
std::map<ResultListHash, VirusAnalysisResult> hashAnalysisCaches, signatureAnalysisCaches, staticAnalysisCaches, cnsAnalysisCaches, sandboxAnalysisCaches;
std::vector<typeof(VirusAnalysisFun)> virusAnalyses = {hashAnalysis, signatureAnalysis, staticAnalysis, cnsAnalysis, sandboxAnalysis};
const bool virusAnalysisTests() {
ResultList abortOrNull {
.bytecodes {
"infection",
"infectedSW",
"corruptedSW",
""
}
};
ResultList passOrNull {
.bytecodes {
"",
"SW",
"SW",
"newSW"
}
};
resultListProduceHashes(passOrNull);
resultListProduceHashes(abortOrNull);
produceAbortListSignatures(passOrNull, abortOrNull);
SUSUWU_NOTICE_DEBUGEXECUTE(resultListDumpTo(passOrNull, std::cout, true, true, false));
SUSUWU_NOTICE_DEBUGEXECUTE((resultListDumpTo(/*.list = */abortOrNull, std::cout, false, false, false), std::cout << std::endl));
assert(4 == passOrNull.bytecodes.size());
assert(passOrNull.bytecodes.size() - 1 /* 2 instances of "SW", discount dup */ == passOrNull.hashes.size());
assert(0 == passOrNull.signatures.size());
assert(4 == abortOrNull.bytecodes.size());
assert(abortOrNull.bytecodes.size() == abortOrNull.hashes.size());
assert(abortOrNull.bytecodes.size() - 1 /* discount empty substr */ == abortOrNull.signatures.size());
produceAnalysisCns(passOrNull, abortOrNull, ResultList(), analysisCns);
produceVirusFixCns(passOrNull, abortOrNull, virusFixCns);
if(0 < classSysArgc) {
PortableExecutableBytecode executable(classSysArgs[0]);
if(virusAnalysisAbort == virusAnalysis(executable)) {
throw std::runtime_error(SUSUWU_ERRSTR(ERROR, "{virusAnalysisAbort == virusAnalysis(args[0]);} /* With such false positives, shouldn't hook kernel modules */"));
}
}
const bool originalRootStatus = hasRoot();
setRoot(true);
virusAnalysisHookTests();
setRoot(originalRootStatus);
return true;
}
const bool virusAnalysisHookTests() {
const VirusAnalysisHook originalHookStatus = virusAnalysisGetHook();
VirusAnalysisHook hookStatus = virusAnalysisHook(virusAnalysisHookClear | virusAnalysisHookExec);
if(virusAnalysisHookExec != hookStatus) {
throw std::runtime_error("`virusAnalysisHook(virusAnalysisHookClear | virusAnalysisHookExec)` == " + std::to_string(hookStatus));
return false;
}
hookStatus = virusAnalysisHook(virusAnalysisHookClear | virusAnalysisHookNewFile);
if(virusAnalysisHookNewFile != hookStatus) {
throw std::runtime_error("`virusAnalysisHook(virusAnalysisHookClear | virusAnalysisHookNewFile)` == " + std::to_string(hookStatus));
return false;
}
hookStatus = virusAnalysisHook(virusAnalysisHookClear);
if(virusAnalysisHookDefault != hookStatus) {
throw std::runtime_error("`virusAnalysisHook(virusAnalysisHookClear)` == " + std::to_string(hookStatus));
return false;
}
hookStatus = virusAnalysisHook(virusAnalysisHookExec | virusAnalysisHookNewFile);
if((virusAnalysisHookExec | virusAnalysisHookNewFile) != hookStatus) {
throw std::runtime_error("`virusAnalysisHook(virusAnalysisExec | virusAnalysisHookNewFile)` == " + std::to_string(hookStatus));
return false;
}
hookStatus = virusAnalysisHook(virusAnalysisHookClear | originalHookStatus);
if(originalHookStatus != hookStatus) {
throw std::runtime_error("`virusAnalysisHook(virusAnalysisHookClear | originalHookStatus)` == " + std::to_string(hookStatus));
return false;
}
return true;
}
const VirusAnalysisHook virusAnalysisHook(VirusAnalysisHook virusAnalysisHookStatus) {
const VirusAnalysisHook originalHookStatus = globalVirusAnalysisHook;
if(virusAnalysisHookQuery == virusAnalysisHookStatus || originalHookStatus == virusAnalysisHookStatus) {
return originalHookStatus;
}
if(virusAnalysisHookClear & virusAnalysisHookStatus) {
/* TODO: undo OS-specific "hook"s/"callback"s */
globalVirusAnalysisHook = virusAnalysisHookDefault;
}
if(virusAnalysisHookExec & virusAnalysisHookStatus) {
/* callbackHook("exec*", */ [](const PortableExecutable &file) { /* TODO: OS-specific "hook"/"callback" for `exec()`/app-launches */
switch(virusAnalysis(file)) {
case virusAnalysisPass:
return true; /* launch this */
case virusAnalysisRequiresReview:
submitSampleToHosts(file); /* manual review */
return false;
default:
return false; /* abort */
}
} /* ) */ ;
globalVirusAnalysisHook = (globalVirusAnalysisHook | virusAnalysisHookExec);
}
if(virusAnalysisHookNewFile & virusAnalysisHookStatus) {
/* callbackHook("fwrite", */ /* TODO: OS-specific "hook"/"callback" for new files/downloads */
globalVirusAnalysisHook = (globalVirusAnalysisHook | virusAnalysisHookNewFile);
}
return virusAnalysisGetHook();
}
const VirusAnalysisResult virusAnalysis(const PortableExecutable &file) {
const auto fileHash = sha2(file.bytecode);
for(const auto &analysis : virusAnalyses) {
switch(analysis(file, fileHash)) {
case virusAnalysisPass:
return virusAnalysisPass;
case virusAnalysisRequiresReview:
/*submitSampleToHosts(file);*/ /* TODO:? */
return virusAnalysisRequiresReview;
case virusAnalysisAbort:
return virusAnalysisAbort;
virusAnalysisContinue:
continue;
}
}
return virusAnalysisPass;
}
const VirusAnalysisResult hashAnalysis(const PortableExecutable &file, const ResultListHash &fileHash) {
try {
const auto result = hashAnalysisCaches.at(fileHash);
return result;
} catch (...) {
if(listHasValue(passList.hashes, fileHash)) {
return hashAnalysisCaches[fileHash] = virusAnalysisPass;
} else if(listHasValue(abortList.hashes, fileHash)) {
return hashAnalysisCaches[fileHash] = virusAnalysisAbort;
} else {
return hashAnalysisCaches[fileHash] = virusAnalysisContinue; /* continue to next tests */
}
}
}
const VirusAnalysisResult signatureAnalysis(const PortableExecutable &file, const ResultListHash &fileHash) {
try {
const auto result = signatureAnalysisCaches.at(fileHash);
return result;
} catch (...) {
if(listHasSignatureOfValue(abortList.signatures, file.bytecode)) {
return signatureAnalysisCaches[fileHash] = virusAnalysisAbort;
}
return signatureAnalysisCaches[fileHash] = virusAnalysisContinue;
}
}
void produceAbortListSignatures(const ResultList &passList, ResultList &abortList) {
abortList.signatures.reserve(abortList.bytecodes.size());
for(const auto &file : abortList.bytecodes) {
auto tuple = listProduceSignature(passList.bytecodes, file);
if(std::get<0>(tuple) < std::get<1>(tuple)) {
abortList.signatures.push_back(ResultListSignature(std::get<0>(tuple), std::get<1>(tuple)));
}
} /* The most simple signature is a substring, but some analyses use regexes. */
}
const std::vector<std::string> importedFunctionsList(const PortableExecutable &file) {
return {}; /* fixes crash, until importedFunctionsList is implemented/finished */
/* TODO: https://www.codeproject.com/Questions/338807/How-to-get-list-of-all-imported-functions-invoked shows how to analyse dynamic loads of functions (if do this, `syscallPotentialDangers[]` does not include `GetProcAddress()`.)
*/
}
const VirusAnalysisResult staticAnalysis(const PortableExecutable &file, const ResultListHash &fileHash) {
try {
const auto result = staticAnalysisCaches.at(fileHash);
return result;
} catch (...) {
auto syscallsUsed = importedFunctionsList(file);
std::sort(syscallPotentialDangers.begin(), syscallPotentialDangers.end());
std::sort(syscallsUsed.begin(), syscallsUsed.end());
if(listsIntersect(syscallPotentialDangers, syscallsUsed)) {
return staticAnalysisCaches[fileHash] = virusAnalysisRequiresReview;
}
return staticAnalysisCaches[fileHash] = virusAnalysisContinue;
}
}
const VirusAnalysisResult sandboxAnalysis(const PortableExecutable &file, const ResultListHash &fileHash) {
try {
const auto result = sandboxAnalysisCaches.at(fileHash);
return result;
} catch (...) {
execvex("cp -r '/usr/home/sandbox/' '/usr/home/sandbox.bak'"); /* or produce FS snapshot */
execvex("cp '" + file.path + "' '/usr/home/sandbox/'");
execvex("chroot '/usr/home/sandbox/' \"strace basename '" + file.path + "'\" >> strace.outputs");
execvex("mv/ '/usr/home/sandbox/strace.outputs' '/tmp/strace.outputs'");
execvex("rm -r '/usr/home/sandbox/' && mv '/usr/home/sandbox.bak' '/usr/home/sandbox/'"); /* or restore FS snapshot */
return sandboxAnalysisCaches[fileHash] = straceOutputsAnalysis("/tmp/strace.outputs");
}
}
const VirusAnalysisResult straceOutputsAnalysis(const FilePath &straceOutput) {
auto straceDump = std::ifstream(straceOutput);
std::vector<std::string> straceOutputs /*= explodeToList(straceDump, "\n")*/;
for(std::string straceOutput; std::getline(straceDump, straceOutput); ) {
straceOutputs.push_back(straceOutput);
}
std::sort(stracePotentialDangers.begin(), stracePotentialDangers.end());
std::sort(straceOutputs.begin(), straceOutputs.end());
if(listsIntersect(stracePotentialDangers, straceOutputs)) { /* Todo: regex */
return virusAnalysisRequiresReview;
}
return virusAnalysisContinue;
}
void produceAnalysisCns(const ResultList &pass, const ResultList &abort,const ResultList &unreviewed,Cns &cns) {
std::vector<std::tuple<FileBytecode, float>> inputsToOutputs;
const size_t maxPassSize = listMaxSize(pass.bytecodes);
const size_t maxAbortSize = listMaxSize(abort.bytecodes);
cns.setInputMode(cnsModeString);
cns.setOutputMode(cnsModeFloat);
cns.setInputNeurons(maxPassSize > maxAbortSize ? maxPassSize : maxAbortSize);
cns.setOutputNeurons(1);
cns.setLayersOfNeurons(6666);
cns.setNeuronsPerLayer(26666);
inputsToOutputs.reserve(pass.bytecodes.size());
for(const auto &bytecodes : pass.bytecodes) {
inputsToOutputs.push_back({bytecodes, 1.0});
}
cns.setupSynapses(inputsToOutputs);
inputsToOutputs.clear();
if(!unreviewed.bytecodes.empty()) {
inputsToOutputs.reserve(unreviewed.bytecodes.size());
for(const auto &bytecodes : unreviewed.bytecodes) {
inputsToOutputs.push_back({bytecodes, 1 / 2});
}
cns.setupSynapses(inputsToOutputs);
inputsToOutputs.clear();
}
inputsToOutputs.reserve(abort.bytecodes.size());
for(const auto &bytecodes : abort.bytecodes) {
inputsToOutputs.push_back({bytecodes, 0.0});
}
cns.setupSynapses(inputsToOutputs);
inputsToOutputs.clear();
}
const float cnsAnalysisScore(const PortableExecutable &file, const Cns &cns) {
return cns.processToFloat(file.bytecode);
}
const VirusAnalysisResult cnsAnalysis_(const PortableExecutable &file, const ResultListHash &fileHash, const Cns &cns) {
try {
const auto result = cnsAnalysisCaches.at(fileHash);
return result;
} catch (...) {
return cnsAnalysisCaches[fileHash] = static_cast<bool>(round(cnsAnalysisScore(file, cns))) ? virusAnalysisContinue : virusAnalysisRequiresReview;
}
}
const VirusAnalysisResult cnsAnalysis(const PortableExecutable &file, const ResultListHash &fileHash) {
return cnsAnalysis_(file, fileHash);
}
void produceVirusFixCns(const ResultList &passOrNull, const ResultList &abortOrNull, Cns &cns) {
std::vector<std::tuple<FileBytecode, FileBytecode>> inputsToOutputs;
cns.setInputMode(cnsModeString);
cns.setOutputMode(cnsModeString);
cns.setInputNeurons(listMaxSize(passOrNull.bytecodes));
cns.setOutputNeurons(listMaxSize(abortOrNull.bytecodes));
cns.setLayersOfNeurons(6666);
cns.setNeuronsPerLayer(26666);
assert(passOrNull.bytecodes.size() == abortOrNull.bytecodes.size());
inputsToOutputs.reserve(passOrNull.bytecodes.size());
for(int x = 0; passOrNull.bytecodes.size() > x; ++x) {
inputsToOutputs.push_back({abortOrNull.bytecodes[x], passOrNull.bytecodes[x]});
}
cns.setupSynapses(inputsToOutputs);
}
const FileBytecode cnsVirusFix(const PortableExecutable &file, const Cns &cns /* = virusFixCns */) {
return cns.processToString(file.bytecode);
}
less
cxx/main.cxx
namespace Susuwu {
void noExcept() NOEXCEPT;
NORETURN void noReturn();
void noExcept() NOEXCEPT {std::cout << std::flush;}
void noReturn() {exit(0);}
int testHarnesses() EXPECTS(true) ENSURES(true) {
std::cout << "cxx/Macros.hxx: " << std::flush;
ASSUME(true);
noExcept();
std::cout << "pass" << std::endl;
std::cout << "execves(): " << std::flush;
(EXIT_SUCCESS == execves({"/bin/echo", "pass"})) || std::cout << "error" << std::endl;
std::cout << "execvex(): " << std::flush;
(EXIT_SUCCESS == execvex("/bin/echo pass")) || std::cout << "error" << std::endl;
std::cout << "virusAnalysisTestsNoexcept(): " << std::flush;
if(virusAnalysisTestsNoexcept()) {
std::cout << "pass" << std::endl;
} else {
std::cout << "error" << std::endl;
}
std::cout << "assistantCnsTestsNoexcept(): " << std::flush;
if(assistantCnsTestsNoexcept()) {
std::cout << "pass" << std::endl;
} else {
std::cout << "error" << std::endl;
}
noReturn();
}
}; /* namespace Susuwu */
int main(int argc, const char **args) {
const bool classSysInitSuccess = Susuwu::classSysInit(argc, args);
assert(classSysInitSuccess);
return Susuwu::testHarnesses();
}
For comparison; produceVirusFixCns
is close to assistants
cxx/AssistantCns.hxx
cxx/AssistantCns.cxx
/* snipped due to 30000 character limit */
Upvotes: 0
Reputation: 4253
Basically you need to find a sequence of bytes that's makes it unique, the AV companies spend a lot of time to analyse the behaviour, traints and find something unique. And the Antivirus application reads the binary file to look for the byte pattern
Kindly read the Antivirus fundamentals: Viruses, signatures, disinfection from Kasperskey
To start with basic you need to create/maintain a hex table where signature is unique column followed by the Name, Type. And read files in your computer and try to get a match with the Hex database table.
Now how to keep it unique, as it's hard to analyse each .exe
on your own to get the signature. As stated here, kindly read the intro-to-creating-anti-virus-signatures
Look for what is yara
Engine & Rules here virustotal.github.io/yara/ and how VirusTotal uses it to create AV signatures then on to rules yararules.com .There are few tools like yaraeditor to help you out but with google you can find more.
Then you can put your hands on OpenSource Antivirus like ClamAV github.com/Cisco-Talos/clamav-devel and use it for purpose.
Upvotes: 3
Reputation: 3190
There are many different ways to create a signature of a file, one of the simplest, and easiest, is to take a hashing function, like SHA1, and run it against the whole file.
Upvotes: 1