HyperDbg/hyperdbg/libhyperdbg/code/debugger/commands/debugging-commands/eval.cpp

264 lines
6.9 KiB
C++

/**
* @file eval.cpp
* @author Sina Karvandi (sina@hyperdbg.org)
* @brief eval (?) command
* @details
* @version 0.1
* @date 2021-02-05
*
* @copyright This project is released under the GNU Public License v3.
*
*/
#include "pch.h"
//
// Global Variables
//
extern BOOLEAN g_IsSerialConnectedToRemoteDebuggee;
extern ACTIVE_DEBUGGING_PROCESS g_ActiveProcessDebuggingState;
/**
* @brief help of the ? command
*
* @return VOID
*/
VOID
CommandEvalHelp()
{
ShowMessages("? : evaluates and execute expressions in debuggee.\n\n");
ShowMessages("syntax : \t? [Expression (string)]\n");
ShowMessages("\n");
ShowMessages("\t\te.g : ? print(dq(poi(@rcx)));\n");
ShowMessages("\t\te.g : ? json(dq(poi(@rcx)));\n");
}
/**
* @brief Check test-cases for script-engine
*
* @return BOOLEAN
*/
BOOLEAN
CommandEvalCheckTestcase()
{
string Line;
BOOLEAN IsOpened = FALSE;
UINT64 ExpectedValue = 0;
BOOLEAN ExpectError = FALSE;
string Expr = "";
std::vector<std::string> TestFiles;
try
{
TestFiles = ListDirectory(SCRIPT_ENGINE_TEST_CASES_DIRECTORY, "*.txt");
}
catch (const std::exception &)
{
ShowMessages("err, test-cases not found, make sure to run test-environment.py "
"before running test cases\n");
return FALSE;
}
for (auto item : TestFiles)
{
//
// Read the test-case file for script-engine
//
ifstream File(item.c_str());
if (File.is_open())
{
IsOpened = TRUE;
//
// File name
//
ShowMessages("Running from : %s\n\n", item.c_str());
while (std::getline(File, Line))
{
//
// Test case number
//
ShowMessages("Test-case number : %s\n", Line.c_str());
//
// Test-case statement
//
if (!std::getline(File, Line))
{
goto ErrorMessage;
}
Expr = Line;
ShowMessages("Statement : %s\n", Line.c_str());
//
// Test-case result
//
if (!std::getline(File, Line))
{
goto ErrorMessage;
}
if (!Line.compare("$error$"))
{
//
// It's an $error$ statement
//
ShowMessages("Expected result : %s\n", Line.c_str());
ExpectError = TRUE;
ExpectedValue = NULL;
}
else if (!ConvertStringToUInt64(Line, &ExpectedValue))
{
ShowMessages("err, the expected results are in incorrect format\n");
goto ErrorMessage;
}
else
{
//
// It's a value expected statement
//
ExpectError = FALSE;
ShowMessages("Expected result : %llx\n", ExpectedValue);
}
//
// Call wrapper for testing statements
//
Expr.append(" ");
//
// Test results
//
if (ScriptAutomaticStatementsTestWrapper(Expr, ExpectedValue, ExpectError))
{
ShowMessages("Test result : Passed\n");
}
else
{
ShowMessages("Test result : Failed\n");
}
//
// Test-case end
//
if (!std::getline(File, Line))
{
goto ErrorMessage;
}
//
// Check end case
//
if (Line.compare("$end$"))
{
//
// err, we'd expect a $end$ at this situation
//
goto ErrorMessage;
}
ShowMessages("\n------------------------------------------------------------\n\n");
}
File.close();
}
}
if (!IsOpened)
{
ShowMessages("err, could not find files for script engine test-cases\n");
return FALSE;
}
return TRUE;
ErrorMessage:
ShowMessages("\nerr, testing failed! incorrect file format for the testing "
"script engine\nmake sure files have a correct ending format\n");
return FALSE;
}
/**
* @brief handler of ? command
*
* @param CommandTokens
* @param Command
*
* @return VOID
*/
VOID
CommandEval(vector<CommandToken> CommandTokens, string Command)
{
if (CommandTokens.size() == 1)
{
ShowMessages("incorrect use of the '%s'\n\n",
GetCaseSensitiveStringFromCommandToken(CommandTokens.at(0)).c_str());
CommandEvalHelp();
return;
}
//
// Trim the command
//
Trim(Command);
//
// Remove the first command from it
//
Command.erase(0, GetCaseSensitiveStringFromCommandToken(CommandTokens.at(0)).size());
//
// Trim it again
//
Trim(Command);
//
// Check if it's a test-case check or not
//
if (!Command.compare("test"))
{
//
// It's a test-case checker
//
if (!CommandEvalCheckTestcase())
{
ShowMessages("err, testing script engine test-cases was not successful\n");
}
else
{
ShowMessages("testing script engine test-cases was successful\n");
}
return;
}
//
// Check if we're connected to a remote debuggee (kernel debugger) or the user debugger
//
if (g_IsSerialConnectedToRemoteDebuggee || g_ActiveProcessDebuggingState.IsActive)
{
//
// Send data to the target user debugger or kernel debugger
//
ScriptEngineExecuteSingleExpression((CHAR *)Command.c_str(), TRUE, FALSE);
}
else
{
//
// It's a test (simulated) run of the script-engine
//
ShowMessages("this command should not be used while you're in VMI-Mode (not attached to the user debugger) "
"or not in the debugger mode, the results that you see is a simulated result for TESTING the script engine "
"and is not based on the status of your system. You can use this command, either in the debugger mode "
"(kernel debugger), or when you attached to a user debugger\n\n");
ShowMessages("test expression : %s \n", Command.c_str());
ScriptEngineWrapperTestParser(Command);
}
}