自动重构Meterpreter绕过杀软( 四 )

请注意,WIN_INCLUDE指向一个文件夹,其中包含与Win32 API进行交互的所有必需的标头 。这些是从标准Windows 10安装中直接获取的,为了避免让你头疼,我们建议你执行相同操作,千万不要选择MinGW 。然后,以需要测试的C文件作为参数来调用脚本 。虽然这会产生一个18MB的文件,但通过搜索我们定义的字符串之一(例如“ NtMapViewOfSection”),可以轻松导航到AST的有趣部分:

自动重构Meterpreter绕过杀软

文章插图
 
现在,我们有了一种可视化AST的方法,可以更轻易地了解如何更新节点才能获得结果,同时不在结果源代码中引入任何语法错误 。以下各节包含与使用libTooling进行AST操作有关实现的详细信息 。
ClangTool样板在进入有趣的内容之前,需要一些样板代码,因此需要将以下代码插入main.cpp中:
#include "clang/AST/ASTConsumer.h"#include "clang/AST/ASTContext.h"#include "clang/AST/Decl.h"#include "clang/AST/Type.h"#include "clang/ASTMatchers/ASTMatchFinder.h"#include "clang/ASTMatchers/ASTMatchers.h"#include "clang/Basic/SourceManager.h"#include "clang/Frontend/CompilerInstance.h"#include "clang/Frontend/FrontendAction.h"#include "clang/Tooling/CommonOptionsParser.h"#include "clang/Tooling/Tooling.h"#include "clang/Rewrite/Core/Rewriter.h"// LLVM includes#include "llvm/ADT/ArrayRef.h"#include "llvm/ADT/StringRef.h"#include "llvm/Support/CommandLine.h"#include "llvm/Support/raw_ostream.h"#include "Consumer.h"#include "MatchHandler.h"#include <IOStream>#include <memory>#include <string>#include <vector>#include <fstream>#include <clang/Tooling/Inclusions/IncludeStyle.h>#include <clang/Tooling/Inclusions/HeaderIncludes.h>#include <sstream>namespace ClSetup {llvm::cl::OptionCategory ToolCategory("StringEncryptor");}namespace StringEncryptor {clang::Rewriter ASTRewriter;class Action : public clang::ASTFrontendAction {public:using ASTConsumerPointer = std::unique_ptr<clang::ASTConsumer>;ASTConsumerPointer CreateASTConsumer(clang::CompilerInstance &Compiler,llvm::StringRef Filename) override {ASTRewriter.setSourceMgr(Compiler.getSourceManager(), Compiler.getLangOpts());std::vector<ASTConsumer*> consumers;consumers.push_back(&StringConsumer);// several passes can be combined together by adding them to `consumers`auto TheConsumer = llvm::make_unique<Consumer>();TheConsumer->consumers = consumers;return TheConsumer;}bool BeginSourceFileAction(clang::CompilerInstance &Compiler) override {llvm::outs() << "Processing file " << 'n';return true;}void EndSourceFileAction() override {clang::SourceManager &SM = ASTRewriter.getSourceMgr();std::string FileName = SM.getFileEntryForID(SM.getMainFileID())->getName();llvm::errs() << "** EndSourceFileAction for: " << FileName << "n";// Now emit the rewritten buffer.llvm::errs() << "Here is the edited source file :nn";std::string TypeS;llvm::raw_string_ostream s(TypeS);auto FileID = SM.getMainFileID();auto ReWriteBuffer = ASTRewriter.getRewriteBufferFor(FileID);if(ReWriteBuffer != nullptr)ReWriteBuffer->write((s));else{llvm::errs() << "File was not modifiedn";return;}std::string result = s.str();std::ofstream fo(FileName);if(fo.is_open())fo << result;elsellvm::errs() << "[!] Error saving result to " << FileName << "n";}};}auto main(int argc, const char *argv[]) -> int {using namespace clang::tooling;using namespace ClSetup;CommonOptionsParser OptionsParser(argc, argv, ToolCategory);ClangTool Tool(OptionsParser.getCompilations(),OptionsParser.getSourcePathList());auto Action = newFrontendActionFactory<StringEncryptor::Action>();return Tool.run(Action.get());}由于该样板代码取自官方文档中的示例,因此不需要再进一步的描述 。唯一值得一提的修改是在CreateASTConsumer的内部 。我们的最终目标是在同一个翻译单元上进行多次转换 。可以通过将项目添加到集合中来完成(基本行是consumers.push_back(&...);) 。
字符串混淆本节描述有关字符串混淆过程的最重要的实现细节,包括三个步骤:
在源代码中找到字符串 。用变量替换它们在适当的位置(包含函数或全局上下文中)插入变量定义/赋值 。
在源代码中查找字符串文字可以如下定义StringConsumer(在StringEncryptor命名空间的开头):
class StringEncryptionConsumer : public clang::ASTConsumer {public:void HandleTranslationUnit(clang::ASTContext &Context) override {using namespace clang::ast_matchers;using namespace StringEncryptor;llvm::outs() << "[StringEncryption] Registering ASTMatcher...n";MatchFinder Finder;MatchHandler Handler(&ASTRewriter);const auto Matcher = stringLiteral().bind("decl");Finder.addMatcher(Matcher, &Handler);Finder.matchAST(Context);}};StringEncryptionConsumer StringConsumer = StringEncryptionConsumer();


推荐阅读