From 2f0973230a3396b7c246f2691ddb713305216fc0 Mon Sep 17 00:00:00 2001 From: Herz3h Date: Fri, 16 Jun 2017 02:22:50 +0200 Subject: [PATCH] Mov instruction manipulating esp and ebp added to plugin to detect more args (#22) * Arguments passed using mov instruction (mov* [ebp*], ... or mov* [esp*], ...) are recognized, Functions ending with Stub are also recognized, small bugfix with string concatenation * Ignoring instructions of prolog and epilog when trying to detect arguments of functions * Avoid putting same comments duplicated whenever analysis is done again * Reverted back to VS2013 since appveyor was failing the build (untested here, dont have VS2013) * Update xAnalyzer.vcxproj * Update xanalyzer.cpp --- xAnalyzer/plugin.cpp | 2 +- xAnalyzer/pluginmain.cpp | 2 +- xAnalyzer/xAnalyzer.vcxproj | 4 +-- xAnalyzer/xanalyzer.cpp | 52 +++++++++++++++++++++++++++++-------- xAnalyzer/xanalyzer.h | 5 ++-- 5 files changed, 48 insertions(+), 17 deletions(-) diff --git a/xAnalyzer/plugin.cpp b/xAnalyzer/plugin.cpp index b329f4e..c4eeabf 100644 --- a/xAnalyzer/plugin.cpp +++ b/xAnalyzer/plugin.cpp @@ -119,7 +119,7 @@ PLUG_EXPORT void CBMENUENTRY(CBTYPE cbType, PLUG_CB_MENUENTRY* info) mbp.cbSize = sizeof(MSGBOXPARAMS); mbp.hInstance = pluginHInstance; mbp.lpszCaption = "About..."; - mbp.lpszText = "["PLUGIN_NAME " " PLUGIN_VERSION_STR"]\n" + mbp.lpszText = "[" PLUGIN_NAME " " PLUGIN_VERSION_STR"]\n" "Extended analysis for static code \n\n" "http://github.com/ThunderCls/xAnalyzer\n" "Coded By : ThunderCls - 2016\n" diff --git a/xAnalyzer/pluginmain.cpp b/xAnalyzer/pluginmain.cpp index 283d99b..75769c9 100644 --- a/xAnalyzer/pluginmain.cpp +++ b/xAnalyzer/pluginmain.cpp @@ -2,7 +2,7 @@ #include "plugin.h" // Variables -const char *szprojectnameInfo = "\n"PLUGIN_NAME " " PLUGIN_VERSION_STR" Plugin by ThunderCls 2017\n" +const char *szprojectnameInfo = "\n" PLUGIN_NAME " " PLUGIN_VERSION_STR" Plugin by ThunderCls 2017\n" "Extended analysis for static code\n" "-> For latest release, issues, etc....\n" "-> For help type command \"xanal help\"\n" diff --git a/xAnalyzer/xAnalyzer.vcxproj b/xAnalyzer/xAnalyzer.vcxproj index 78f191d..af4a590 100644 --- a/xAnalyzer/xAnalyzer.vcxproj +++ b/xAnalyzer/xAnalyzer.vcxproj @@ -1,4 +1,4 @@ - + @@ -366,4 +366,4 @@ - \ No newline at end of file + diff --git a/xAnalyzer/xanalyzer.cpp b/xAnalyzer/xanalyzer.cpp index ef170b7..f087a6c 100644 --- a/xAnalyzer/xanalyzer.cpp +++ b/xAnalyzer/xanalyzer.cpp @@ -328,7 +328,7 @@ void AnalyzeBytesRange(duint dwEntry, duint dwExit) CallDestination = bii.addr; DbgDisasmFastAt(CallDestination, &cbii); GuiGetDisassembly(CurrentAddress, szDisasmText); - GuiGetDisassembly(bii.addr, szJmpDisasmText); // Detect function name on call scheme: CALL -> JMP -> JMP -> API + GuiGetDisassembly(CallDestination, szJmpDisasmText); // Detect function name on call scheme: CALL -> JMP -> JMP -> API // save data for the argument ai.manual = true; @@ -336,6 +336,12 @@ void AnalyzeBytesRange(duint dwEntry, duint dwExit) if (Strip_x64dbg_calls(szDisasmText) || (cbii.branch && Strip_x64dbg_calls(szJmpDisasmText))) { szOriginalCharsetAPIFunction = szAPIFunction; + + // Remove Stub suffix from function names if found + auto stub = szAPIFunction.find("Stub"); + if (stub != std::string::npos) + szAPIFunction = szAPIFunction.substr(0, stub); + // transform charsets search if (szAPIFunction.back() == 'A' || szAPIFunction.back() == 'W') szAPIFunction.pop_back(); @@ -445,7 +451,7 @@ void AnalyzeBytesRange(duint dwEntry, duint dwExit) // -------------------------------------------------------------------------------------- else if (!bii.branch) { - if (IsArgumentInstruction(&bii)) // only arguments instruction / excluding unusual instructions + if (IsArgumentInstruction(&bii, CurrentAddress)) // only arguments instruction / excluding unusual instructions { if (IS.size() < INSTRUCTIONSTACK_MAXSIZE) // save instruction into stack { @@ -899,7 +905,7 @@ bool Strip_x64dbg_calls(LPSTR lpszCallText) // in case of undefined: CALL [0x007FF154] strcpy_s(funct, MAX_COMMENT_SIZE, lpszAPIFunction); - if (ishex(funct) || HasRegister(funct)) + if (IsHex(funct) || HasRegister(funct)) sprintf_s(lpszAPIFunction, MAX_COMMENT_SIZE, "sub_[%s]", funct); szAPIFunction = lpszAPIFunction; @@ -1026,7 +1032,7 @@ void SetAutoCommentIfCommentIsEmpty(INSTRUCTIONSTACK *inst, char *CommentString, if (inst_source != NULL && ((strlen(inst_source) + 10) <= spaceleft - 1)) // avoid BoF for longer comments than MAX_COMMENT_SIZE (FIXED!) { - bool instHex = ishex(inst_source); + bool instHex = IsHex(inst_source); if (instHex) // get constants as value of argument / excluding push memory, registers, etc ToUpperHex(inst_source); @@ -1122,6 +1128,28 @@ bool IsNumericParam(string paramType) return false; } +// ------------------------------------------------------------------------------------ +// Returns true if instruction is a mov manipulating esp or ebp, excluding epilog, prolog +// otherwise returns false +// ------------------------------------------------------------------------------------ +bool IsMovStack(const BASIC_INSTRUCTION_INFO *bii, duint CurrentAddress) +{ + auto isMovInstruction = strstr(bii->instruction, "mov") != nullptr; + + if (isMovInstruction && !IsProlog(bii, CurrentAddress) && !IsEpilog(bii)) // Is a mov instruction excluding prolog and epilog + { + char *next_token = NULL; + auto movDestination = strtok_s((char*)bii->instruction, ",", &next_token); // Get the left part of , + auto isMovDestinationEsp = strstr(movDestination, "esp") != nullptr; + auto isMovDestinationEbp = strstr(movDestination, "ebp") != nullptr; + + if(movDestination != nullptr && (isMovDestinationEsp || isMovDestinationEbp)) // If instruction manipulate [esp*] or [ebp*], its valid + return true; + } + + return false; +} + // ------------------------------------------------------------------------------------ // Check if the current executable is a VB // ------------------------------------------------------------------------------------ @@ -1318,7 +1346,7 @@ bool IsHeaderConstant(const char *CommentString, char *szComment, char *inst_sou if (inst_source != NULL) { - if(instHex = ishex(inst_source)) + if(instHex = IsHex(inst_source)) instConst = hextoduint(inst_source); } @@ -1622,7 +1650,7 @@ int GetFunctionParamCount(LPSTR lpszApiModule, string lpszApiFunction) Utf8Ini *defApiFile = search->second; string params = defApiFile->GetValue(lpszApiFunction, "ParamCount"); // check if key is found - if (!params.empty() && ishex(params.c_str())) + if (!params.empty() && IsHex(params.c_str())) return atoi(params.c_str()); } @@ -1662,7 +1690,7 @@ bool GetFunctionParam(LPSTR lpszApiModule, string lpszApiFunction, duint dwParam // ------------------------------------------------------------------------------------ // Returns true if the specified string is a valid hex value // ------------------------------------------------------------------------------------ -bool ishex(const char *str) +bool IsHex(const char *str) { duint index = 0; @@ -1906,7 +1934,7 @@ bool IsArgumentRegister(const char *destination) // ------------------------------------------------------------------------------------ // True if instruction is a valid argument instruction // ------------------------------------------------------------------------------------ -bool IsArgumentInstruction(const BASIC_INSTRUCTION_INFO *bii) +bool IsArgumentInstruction(const BASIC_INSTRUCTION_INFO *bii, duint CurrentAddress) { #ifdef _WIN64 bool IsArgument = false; @@ -1935,11 +1963,13 @@ bool IsArgumentInstruction(const BASIC_INSTRUCTION_INFO *bii) return IsArgument; #else - return (strncmp(bii->instruction, "push ", 5) == 0 && + auto validPushInstruction = strncmp(bii->instruction, "push ", 5) == 0 && strcmp((char*)(bii->instruction + 5), "ebp") != 0 && strcmp((char*)(bii->instruction + 5), "esp") != 0 && strcmp((char*)(bii->instruction + 5), "ds") != 0 && - strcmp((char*)(bii->instruction + 5), "es") != 0); + strcmp((char*)(bii->instruction + 5), "es") != 0; + + return (validPushInstruction || IsMovStack(bii, CurrentAddress)); #endif } @@ -2414,4 +2444,4 @@ void DisplayHelp() "xanal help : Brings up this help text\r\n\n"; GuiAddLogMessage(pluginHelp); -} \ No newline at end of file +} diff --git a/xAnalyzer/xanalyzer.h b/xAnalyzer/xanalyzer.h index 06aa460..5fdefbe 100644 --- a/xAnalyzer/xanalyzer.h +++ b/xAnalyzer/xanalyzer.h @@ -73,7 +73,7 @@ void SetAutoCommentIfCommentIsEmpty(INSTRUCTIONSTACK *inst, char *CommentString, bool SearchApiFileForDefinition(LPSTR lpszApiModule, LPSTR lpszApiDefinition, bool recursive); int GetFunctionParamCount(LPSTR lpszApiModule, string lpszApiFunction); bool GetFunctionParam(LPSTR lpszApiModule, string lpszApiFunction, duint dwParamNo, LPSTR lpszApiFunctionParameter); -bool ishex(const char *str); +bool IsHex(const char *str); duint hextoduint(LPCTSTR str); void DoInitialAnalysis(); void ProcessDllFunctionCalls(duint startAddr = -1, duint size = -1); @@ -95,10 +95,11 @@ string CallDirection(BASIC_INSTRUCTION_INFO *bii); bool SetFunctionParams(Script::Argument::ArgumentInfo *ai, char *szAPIModuleName); bool IsHeaderConstant(const char *CommentString, char *szComment, char *inst_source = NULL); bool IsNumericParam(string paramType); +bool IsMovStack(BASIC_INSTRUCTION_INFO *bii, duint CurrentAddress); void TraverseHFilesTree(string &base, string header, string &htype, char *lpszApiConstant, Utf8Ini *defApiHFile, bool getTypeDisplay = false); void GetConstantValue(char *lpszApiConstant, const char *CommentString); bool SetSubParams(Argument::ArgumentInfo *ai); -bool IsArgumentInstruction(const BASIC_INSTRUCTION_INFO *bii); +bool IsArgumentInstruction(const BASIC_INSTRUCTION_INFO *bii, duint CurrentAddress); bool IsProlog(const BASIC_INSTRUCTION_INFO *bii, duint CurrentAddress); bool IsEpilog(const BASIC_INSTRUCTION_INFO *bii); char *GetInstructionSource(char *instruction);