Skip to content

Commit

Permalink
Attempt to guess if strings are ANSI or Unicode.
Browse files Browse the repository at this point in the history
plowsec committed Jul 10, 2020
1 parent b2f53ac commit 76d440d
Showing 11 changed files with 249,378 additions and 636 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -4,3 +4,4 @@ cmake-build-debug/*

.idea
CMakeBuild/*
misc/*
98 changes: 61 additions & 37 deletions MatchHandler.cpp
Original file line number Diff line number Diff line change
@@ -5,6 +5,7 @@
#include "MatchHandler.h"
#include <random>
#include <regex>
#include <utility>
#include <vector>
#include <string>
#include <sstream>
@@ -51,9 +52,30 @@ MatchHandler::getNodeParents(const StringLiteral &NodeString, clang::ast_type_tr
return CurrentParents;
}

std::string
MatchHandler::findStringType(const StringLiteral &NodeString, clang::ASTContext *const pContext) {

ASTContext::DynTypedNodeList parents = pContext->getParents(NodeString);;
std::string StringType;
for (const auto &parent : parents) {

StringRef ParentNodeKind = parent.getNodeKind().asStringRef();

if (ParentNodeKind.find("Cast") != std::string::npos) {

StringType = parent.get<clang::ImplicitCastExpr>()->getType().getAsString();
llvm::outs() << "StringType is " << StringType << "\n";
}

llvm::outs() << "getParent, Node kind ot^^o: " << parent.getNodeKind().asStringRef() << "\n";
}

return StringType;
}

bool
MatchHandler::climbParentsIgnoreCast(const StringLiteral &NodeString, clang::ast_type_traits::DynTypedNode node,
clang::ASTContext *const pContext, uint64_t iterations) {
clang::ASTContext *const pContext, uint64_t iterations, std::string StringType) {

ASTContext::DynTypedNodeList parents = pContext->getParents(NodeString);;

@@ -67,10 +89,10 @@ MatchHandler::climbParentsIgnoreCast(const StringLiteral &NodeString, clang::ast

if (ParentNodeKind.find("Cast") != std::string::npos) {

return climbParentsIgnoreCast(NodeString, parent, pContext, ++iterations);
return climbParentsIgnoreCast(NodeString, parent, pContext, ++iterations, StringType);
}

handleStringInContext(&NodeString, pContext, parent);
handleStringInContext(&NodeString, pContext, parent, StringType);
}

return false;
@@ -88,68 +110,54 @@ void MatchHandler::run(const MatchResult &Result) {
return;
}

climbParentsIgnoreCast(*Decl, clang::ast_type_traits::DynTypedNode(), Result.Context, 0);
auto StringType = findStringType(*Decl, Result.Context);

/*
std::vector<std::string> Parents;
getNodeParents(*Decl, clang::ast_type_traits::DynTypedNode(), Result.Context, Parents, 0);
std::stringstream ListOfParents;
bool IsFirst = true; // used as a sentinel to avoid printing a "comma" for the first element.
for (auto &CurrentParent : Parents) {
climbParentsIgnoreCast(*Decl, clang::ast_type_traits::DynTypedNode(), Result.Context, 0, StringType);

if (IsFirst) {
IsFirst = false;
} else {
ListOfParents << ", ";
}
ListOfParents << CurrentParent;
}
llvm::outs() << ListOfParents.str() << "\n";
*/
}

void MatchHandler::handleStringInContext(const clang::StringLiteral *pLiteral, clang::ASTContext *const pContext,
const clang::ast_type_traits::DynTypedNode node) {
const clang::ast_type_traits::DynTypedNode node, std::string StringType) {

StringRef ParentNodeKind = node.getNodeKind().asStringRef();

if (ParentNodeKind.compare("CallExpr") == 0) {
handleCallExpr(pLiteral, pContext, node);
handleCallExpr(pLiteral, pContext, node, StringType);
} else if (ParentNodeKind.compare("InitListExpr") == 0) {
handleInitListExpr(pLiteral, pContext, node);
handleInitListExpr(pLiteral, pContext, node, StringType);
}else if(ParentNodeKind.compare("VarDecl") == 0) {
handleVarDeclExpr(pLiteral, pContext, node);
handleVarDeclExpr(pLiteral, pContext, node, StringType);
} else {
llvm::outs() << "Unhandled context " << ParentNodeKind << " for string " << pLiteral->getBytes() << "\n";
}
}

bool MatchHandler::handleExpr(const clang::StringLiteral *pLiteral, clang::ASTContext *const pContext,
const clang::ast_type_traits::DynTypedNode node) {
const clang::ast_type_traits::DynTypedNode node, std::string StringType, std::string NewType) {

clang::SourceRange LiteralRange = clang::SourceRange(
ASTRewriter->getSourceMgr().getFileLoc(pLiteral->getBeginLoc()),
ASTRewriter->getSourceMgr().getFileLoc(pLiteral->getEndLoc())
);


if(shouldAbort(pLiteral, pContext, LiteralRange))
return false;

std::string Replacement = Utils::translateStringToIdentifier(pLiteral->getBytes().str());

if(!insertVariableDeclaration(pLiteral, pContext, LiteralRange, Replacement))
if(!insertVariableDeclaration(pLiteral, pContext, LiteralRange, Replacement, StringType))
return false ;

if(!StringType.empty() && !NewType.empty())
Replacement = "(" + NewType + ")" + Replacement;

Globs::PatchedSourceLocation.push_back(LiteralRange);

return replaceStringLiteral(pLiteral, pContext, LiteralRange, Replacement);
}

void MatchHandler::handleCallExpr(const clang::StringLiteral *pLiteral, clang::ASTContext *const pContext,
const clang::ast_type_traits::DynTypedNode node) {
const clang::ast_type_traits::DynTypedNode node, std::string StringType) {


const auto *FunctionCall = node.get<clang::CallExpr>();
@@ -158,32 +166,47 @@ void MatchHandler::handleCallExpr(const clang::StringLiteral *pLiteral, clang::A
return; // TODO: exclude printf-like functions when the replacement is not constant anymore.
}

handleExpr(pLiteral, pContext, node);
handleExpr(pLiteral, pContext, node, StringType);
}

// TODO : search includes for "common.h" or add it
void MatchHandler::handleInitListExpr(const clang::StringLiteral *pLiteral, clang::ASTContext *const pContext,
const clang::ast_type_traits::DynTypedNode node) {
const clang::ast_type_traits::DynTypedNode node, std::string StringType) {


handleExpr(pLiteral, pContext, node);
handleExpr(pLiteral, pContext, node, StringType);
}

void MatchHandler::handleVarDeclExpr(const clang::StringLiteral *pLiteral, clang::ASTContext *const pContext,
const clang::ast_type_traits::DynTypedNode node) {
const clang::ast_type_traits::DynTypedNode node, std::string StringType) {

auto Identifier = node.get<clang::VarDecl>()->getIdentifier()->getName();
auto TypeLoc = node.get<clang::VarDecl>()->getTypeSourceInfo()->getTypeLoc();
auto Type = TypeLoc.getType().getAsString();
auto Loc = TypeLoc.getSourceRange();
auto LHSReplacement = Type.replace(Type.find(" []"),3,"* ")+Identifier;
llvm::outs() << "Type of " << Identifier << " is " << Type << "\n";
std::string NewType = Type;
if (Type.find("BYTE*") != std::string::npos) {
NewType = "const char ";
} else if(Type.find("wchar") != std::string::npos){
NewType = "const wchar_t ";
} else if(Type.find("WCHAR") != std::string::npos){
NewType = "const wchar_t ";
} else if(Type.find("char*") != std::string::npos){
NewType = "const char ";
}

ASTRewriter->ReplaceText(Loc, LHSReplacement.str());
handleExpr(pLiteral, pContext, node);
llvm::outs() << "Type of " << Identifier << " is " << StringType << "\n";


handleExpr(pLiteral, pContext, node, NewType, Type);
}


bool MatchHandler::insertVariableDeclaration(const clang::StringLiteral *pLiteral, clang::ASTContext *const pContext,
clang::SourceRange range, const std::string& Replacement) {
clang::SourceRange range, const std::string& Replacement, std::string StringType) {

std::string StringLiteralContent = pLiteral->getBytes().str();

@@ -192,7 +215,8 @@ bool MatchHandler::insertVariableDeclaration(const clang::StringLiteral *pLitera
// inject code to declare the string in an encrypted fashion
SourceRange FreeSpace = findInjectionSpot(pContext, clang::ast_type_traits::DynTypedNode(), *pLiteral,
IsInGlobalContext, 0);
std::string StringVariableDeclaration = Utils::generateVariableDeclaration(Replacement, StringLiteralContent);

std::string StringVariableDeclaration = Utils::generateVariableDeclaration(Replacement, StringLiteralContent, StringType);

if (!IsInGlobalContext) {
//StringVariableDeclaration += "\tdprintf(\"" + Replacement + "\");\n";
@@ -323,7 +347,7 @@ MatchHandler::shouldAbort(const clang::StringLiteral *pLiteral, clang::ASTContex
}

if(ShouldSkip) {
llvm::outs() << "Ignoring " << pLiteral->getBytes() << " because it was already patched";
llvm::outs() << "Ignoring " << pLiteral->getBytes() << " because it was already patched\n";
return true;
}
}
19 changes: 10 additions & 9 deletions MatchHandler.h
Original file line number Diff line number Diff line change
@@ -50,8 +50,7 @@ class MatchHandler : public clang::ast_matchers::MatchFinder::MatchCallback {

// climb the list of parents recursively until it finds a useful node (i.e. not Cast-like nodes).
bool climbParentsIgnoreCast(const clang::StringLiteral &NodeString, clang::ast_type_traits::DynTypedNode node,
clang::ASTContext *pContext, uint64_t iterations);

clang::ASTContext *const pContext, uint64_t iterations, std::string StringType);
/**
* gets a list of all the parent nodes of a given StringLiteral node, ignoring Cast-like nodes.
* @param NodeString a StringLiteral node
@@ -72,7 +71,7 @@ class MatchHandler : public clang::ast_matchers::MatchFinder::MatchCallback {
* @param node dummy node used to store the string literal successive parent.
*/
void handleStringInContext(const clang::StringLiteral *pLiteral, clang::ASTContext *pContext,
clang::ast_type_traits::DynTypedNode node);
clang::ast_type_traits::DynTypedNode node, std::string StringType);

/**
*
@@ -81,7 +80,7 @@ class MatchHandler : public clang::ast_matchers::MatchFinder::MatchCallback {
* @param node the AST node that makes use of the string pLiteral
*/
void handleCallExpr(const clang::StringLiteral *pLiteral, clang::ASTContext *pContext,
clang::ast_type_traits::DynTypedNode node);
clang::ast_type_traits::DynTypedNode node, std::string StringType);


/**
@@ -104,7 +103,7 @@ class MatchHandler : public clang::ast_matchers::MatchFinder::MatchCallback {
static bool isBlacklistedFunction(const clang::CallExpr *FunctionName);

void handleInitListExpr(const clang::StringLiteral *pLiteral, clang::ASTContext *pContext,
clang::ast_type_traits::DynTypedNode node);
clang::ast_type_traits::DynTypedNode node, std::string StringType);

bool shouldAbort(const clang::StringLiteral *pLiteral, clang::ASTContext *pContext, clang::SourceRange string);

@@ -117,13 +116,15 @@ class MatchHandler : public clang::ast_matchers::MatchFinder::MatchCallback {
const std::string& string);

bool insertVariableDeclaration(const clang::StringLiteral *pLiteral, clang::ASTContext *pContext,
clang::SourceRange range, const std::string& string);
clang::SourceRange range, const std::string& string, std::string StringType="");

bool handleExpr(const clang::StringLiteral *pLiteral, clang::ASTContext *pContext,
clang::ast_type_traits::DynTypedNode node);
clang::ast_type_traits::DynTypedNode node, std::string StringType="", std::string NewType="");

void handleVarDeclExpr(const clang::StringLiteral *pLiteral, clang::ASTContext *pContext,
clang::ast_type_traits::DynTypedNode node, std::string StringType);

void handleVarDeclExpr(const clang::StringLiteral *pLiteral, clang::ASTContext *const pContext,
const clang::ast_type_traits::DynTypedNode node);
std::string findStringType(const clang::StringLiteral &NodeString, clang::ASTContext *const pContext);
};

#endif //AVCLEANER_MATCHHANDLER_H
26 changes: 21 additions & 5 deletions Utils.cpp
Original file line number Diff line number Diff line change
@@ -7,6 +7,7 @@
#include <regex>
#include <random>
#include <sstream>
#include <clang/AST/CommentLexer.h>

using namespace Utils;

@@ -49,17 +50,31 @@ void Utils::cleanParameter(std::string &Argument) {


std::string
Utils::generateVariableDeclaration(const std::string &StringIdentifier, const std::string &StringValue) {
Utils::generateVariableDeclaration(const std::string &StringIdentifier, const std::string &StringValue, std::string StringType) {

std::stringstream Result;

//Result << "\n#ifdef _UNICODE\n\twchar_t\n";
//Result << "#else\n\tchar\n#endif\n\t";
Result << "TCHAR " << StringIdentifier << "[] = {";
if(!StringType.empty()){
auto pos = StringType.find('*');
if (pos != std::string::npos)
StringType.erase(pos);

Result << StringType << StringIdentifier;
/*if (StringType.find("char") != std::string::npos && StringType.find("*") == std::string::npos) {
}*/
Result << "[]";

Result << " = {";
} else {
llvm::outs() << StringValue << " Oups\n";

Result << "TCHAR " << StringIdentifier << "[] = {";
}

auto CleanString = std::string(StringValue);
cleanParameter(CleanString);
bool ToggleZero = std::count(CleanString.begin(), CleanString.end(), 0) >= CleanString.size() / 2;
for (std::string::iterator it = CleanString.begin(); it != CleanString.end(); it++) {

if (*it == '\'') {
@@ -69,7 +84,8 @@ Utils::generateVariableDeclaration(const std::string &StringIdentifier, const st
} else if (*it == '\n') {
Result << "'\\n'";
} else if (*it != 0) {
Result << "'\\x" << std::hex << (int)*it << "'";
int nb = (int)*it & 0xff;
Result << "'\\x" << std::hex << nb << "'";
} else {
continue;
}
@@ -85,4 +101,4 @@ Utils::generateVariableDeclaration(const std::string &StringIdentifier, const st
else
Result << ",0};\n";
return std::regex_replace(Result.str(), std::regex(",,"), ",");
}
}
4 changes: 1 addition & 3 deletions Utils.h
Original file line number Diff line number Diff line change
@@ -42,9 +42,7 @@ namespace Utils {
* @param StringValue the actual value of the string literal.
* @return the generated code snippet.
*/
extern std::string
generateVariableDeclaration(const std::string &StringIdentifier, const std::string &StringValue);

extern std::string generateVariableDeclaration(const std::string &StringIdentifier, const std::string &StringValue, std::string StringType="");
};

#endif //AVCLEANER_UTILS_H
Loading
Oops, something went wrong.

0 comments on commit 76d440d

Please sign in to comment.