技术编程|自动重构Meterpreter绕过杀软·续( 三 )
然后运行:bash clang-astdump.sh test/messagebox_simple.c > test/messagebox_simple.c.ast
本文插图
在源代码中定位函数调用基本上等于查找CallExpr类型的AST节点 。如上面的截图所示 , 实际调用的函数名是在其某个子节点中被指定的 , 因此后面应该可以访问它 。 找到给定API的函数调用
为了枚举给定函数的每个函数调用 , 根据需要我们选择了ASTMatcher 。首先 , 正确使用这个匹配器的语法很重要 , 因为它比上一篇文章中使用的语法要复杂一些 。为了得到正确的结果 , 我们选择依靠clang-query来完成 , 这是一个非常有价值的交互式工具 , 允许在源代码上运行自定义查询 。有趣的是 , 它也基于libTooling , 并且其功能远比在本文章中展示的功能要强大得多(更多细节请参阅此处) 。 clang-query> match callExpr(callee(functionDecl(hasName("MessageBoxA"))))Match #1:/Users/vladimir/dev/scrt/avcleaner/test/messagebox_simple.c:6:5: note: "root" binds hereMessageBoxA(NULL, "Test", "Something", MB_OK);^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~1 match.clang-query>
反复试验可以迅速找到到有效的解决方案 。现在通过验证我们发现匹配器工作良好 , 我们可以像前面的文章中提到的一样创建一个新的ASTConsumer 。基本上 , 它是复制我们对clang-query所做的工作 , 只不过是在C++中:class ApiCallConsumer : public clang::ASTConsumer {public:ApiCallConsumer(std::string ApiName, std::string TypeDef, std::string Library): _ApiName(std::move(ApiName)), _TypeDef(std::move(TypeDef)), _Library(std::move(Library)) {}void HandleTranslationUnit(clang::ASTContext &Context) override {using namespace clang::ast_matchers;using namespace AVObfuscator;llvm::outs() << "[ApiCallObfuscation] Registering ASTMatcher for " << _ApiName << "\n";MatchFinder Finder;ApiMatchHandler Handler(&ASTRewriter, _ApiName, _TypeDef, _Library);const auto Matcher = 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中完成:
本文插图
这是我们在上一篇文章中对现有代码所做的唯一修改 。从这里开始 , 其他东西都可以通过我们将要添加的一组代码来实现 , 首先创建ApiMatchHandler.cpp , 匹配器必须提供一个回调函数 , 所以让我们给它一个:void ApiMatchHandler::run(const MatchResult &Result) {llvm::outs() << "Found " << _ApiName << "\n";const auto *CallExpression = Result.Nodes.getNodeAs
("callExpr");handleCallExpr(CallExpression, Result.Context);}
在本文开始的任务分解步骤的具体实现过程中 , 我们可以在代码层面给他做一些位置调换 , 例如使用以下方法:bool handleCallExpr(const clang::CallExpr *CallExpression, clang::ASTContext *const pContext);bool replaceIdentifier(const clang::CallExpr *CallExpression, const std::string &ApiName,const std::string &NewIdentifier);booladdGetProcAddress(const clang::CallExpr *pCallExpression, clang::ASTContext *const pContext,const std::string &NewIdentifier, std::string &ApiName);clang::SourceRange findInjectionSpot(clang::ASTContext *const Context, clang::ast_type_traits::DynTypedNode Parent,const clang::CallExpr &Literal, uint64_t Iterations);替换函数调用
推荐阅读
- 摄像头|小米截胡中兴屏下摄像头技术,小米研发还是供应链技术?
- AI人工智能|原创 智能门锁改造计划,德施曼小嘀全自动电子猫眼锁Q3M上线小米有品
- 马斯克|马斯克用活猪演示脑机接口技术:实时读取猪脑信息 心灵感应成真了
- 人工智能|济南将打造全球首个人工智能医药研发自动化实验室
- 三防|带你了解三防手持终端的秘密
- 第三|原创 小米发布第三代屏下相机技术,或将在Mix 4上首秀?
- 海信|首个新兴显示技术分标委成立 海信牵头制定国标
- 中年|Python编程语言有什么独特的优势呢?
- |马斯克用活猪演示脑机技术,他希望今年年底前能在人体内植入
- 智能家居|原创 智能门锁改造计划,德施曼小嘀全自动电子猫眼锁Q3M上线小米有品
