安界|自动重构Meterpreter绕过杀软·续( 三 )


然后运行:bashclang-astdump.shtest/messagebox_simple.c>test/messagebox_simple.c.ast
安界|自动重构Meterpreter绕过杀软·续
文章图片
在源代码中定位函数调用基本上等于查找CallExpr类型的AST节点 。 如上面的截图所示 , 实际调用的函数名是在其某个子节点中被指定的 , 因此后面应该可以访问它 。 找到给定API的函数调用
为了枚举给定函数的每个函数调用 , 根据需要我们选择了ASTMatcher 。 首先 , 正确使用这个匹配器的语法很重要 , 因为它比上一篇文章中使用的语法要复杂一些 。 为了得到正确的结果 , 我们选择依靠clang-query来完成 , 这是一个非常有价值的交互式工具 , 允许在源代码上运行自定义查询 。 有趣的是 , 它也基于libTooling , 并且其功能远比在本文章中展示的功能要强大得多(更多细节请参阅此处) 。 clang-query>matchcallExpr(callee(functionDecl(hasName("MessageBoxA"))))Match#1:/Users/vladimir/dev/scrt/avcleaner/test/messagebox_simple.c:6:5:note:"root"bindshereMessageBoxA(NULL,"Test","Something",MB_OK);^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~1match.clang-query>
反复试验可以迅速找到到有效的解决方案 。 现在通过验证我们发现匹配器工作良好 , 我们可以像前面的文章中提到的一样创建一个新的ASTConsumer 。 基本上 , 它是复制我们对clang-query所做的工作 , 只不过是在C++中:classApiCallConsumer:publicclang::ASTConsumer{public:ApiCallConsumer(std::stringApiName,std::stringTypeDef,std::stringLibrary):_ApiName(std::move(ApiName)),_TypeDef(std::move(TypeDef)),_Library(std::move(Library)){}voidHandleTranslationUnit(clang::ASTContext&Context)override{usingnamespaceclang::ast_matchers;usingnamespaceAVObfuscator;llvm::outs()<<"[ApiCallObfuscation]RegisteringASTMatcherfor"<<_ApiName<<"n";MatchFinderFinder;ApiMatchHandlerHandler(&ASTRewriter,_ApiName,_TypeDef,_Library);constautoMatcher=callExpr(callee(functionDecl(hasName(_ApiName)))).bind("callExpr");Finder.addMatcher(Matcher,&Handler);Finder.matchAST(Context);}private:std::string_ApiName;std::string_TypeDef;std::string_Library;};
我们发现此实现最重要的细节是能否提供匹配许多不同函数的能力 , 并且由于最终的目标是为每个替换的API函数前面插入LoadLibrary/GetProcAddress , 因此我们需要能够在函数原型中提供要加载的DLL名称 。
这样做可以优雅地注册与要替换的API一样多的ASTConsumers 。 此ASTConsumer的实例化必须在ASTFrontendAction中完成:
安界|自动重构Meterpreter绕过杀软·续
文章图片
这是我们在上一篇文章中对现有代码所做的唯一修改 。 从这里开始 , 其他东西都可以通过我们将要添加的一组代码来实现 , 首先创建ApiMatchHandler.cpp , 匹配器必须提供一个回调函数 , 所以让我们给它一个:voidApiMatchHandler::run(constMatchResult&Result){llvm::outs()<<"Found"<<_ApiName<<"n";constauto*CallExpression=Result.Nodes.getNodeAs
("callExpr");handleCallExpr(CallExpression,Result.Context);}
在本文开始的任务分解步骤的具体实现过程中 , 我们可以在代码层面给他做一些位置调换 , 例如使用以下方法:boolhandleCallExpr(constclang::CallExpr*CallExpression,clang::ASTContext*constpContext);boolreplaceIdentifier(constclang::CallExpr*CallExpression,conststd::string&ApiName,conststd::string&NewIdentifier);booladdGetProcAddress(constclang::CallExpr*pCallExpression,clang::ASTContext*constpContext,conststd::string&NewIdentifier,std::string&ApiName);clang::SourceRangefindInjectionSpot(clang::ASTContext*constContext,clang::ast_type_traits::DynTypedNodeParent,constclang::CallExpr&Literal,uint64_tIterations);替换函数调用