Skip to content

Commit

Permalink
Improve parameter extraction
Browse files Browse the repository at this point in the history
  • Loading branch information
Manuel Bischof authored and cakeless committed Oct 11, 2023
1 parent 4597232 commit 1682b22
Show file tree
Hide file tree
Showing 5 changed files with 187 additions and 62 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3792,7 +3792,7 @@ Modules:
NtSetContextThread:
Parameters:
ThreadHandle: HANDLE
Context: CONTEXT
Context: LPCONTEXT
ReturnValue: NTSTATUS
NtSuspendThread:
Parameters:
Expand Down Expand Up @@ -4724,8 +4724,9 @@ Structures:
Type: PVOID # TODO Add real definition
Offset: 0
LPCONTEXT: # TODO Add definition https://learn.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-context
Type: PVOID # TODO Add real definition
Offset: 0
CONTEXT:
Type: PVOID # TODO Add real definition
Offset: 0
LPPROCESS_INFORMATION:
hProcess:
Type: HANDLE
Expand Down Expand Up @@ -4866,10 +4867,10 @@ Structures:
UniqueThread:
Type: HANDLE
Offset: 8
PCONTEXT: # TODO Add definition for CONTEXT https://learn.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-context
CONTEXT:
Type: PVOID
Offset: 0
PCONTEXT: # TODO Add definition for CONTEXT https://learn.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-context
CONTEXT:
Type: PVOID
Offset: 0
PFILE_BASIC_INFORMATION:
CreationTime:
Type: LARGE_INTEGER
Expand Down Expand Up @@ -5002,13 +5003,11 @@ HighLevelParameterTypes:
LPTHREAD_START_ROUTINE: PVOID
LPWSTR: LPWSTR_32
LPBYTE: unsigned int
LPCONTEXT: CONTEXT
LPCVOID: unsigned int
LPDWORD: unsigned int
LPVOID: unsigned int
NTSTATUS: unsigned __int32
PANSI_STRING: PVOID
PHANDLE: HANDLE
PIO_APC_ROUTINE: PVOID
PIO_STATUS_BLOCK: PVOID
PINITIAL_TEB: PVOID
Expand Down Expand Up @@ -5062,14 +5061,11 @@ HighLevelParameterTypes:
LPTHREAD_START_ROUTINE: PVOID # Pointer to the starting address of a thread. E.g. https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-createremotethreadex
LPWSTR: LPWSTR_64
LPBYTE: unsigned __int64
LPCONTEXT: CONTEXT
LPCVOID: unsigned __int64
LPDWORD: unsigned __int64
LPVOID: unsigned __int64
NTSTATUS: unsigned __int32
PANSI_STRING: PVOID # TODO find definition
PCONTEXT: PVOID # TODO Add Context struct definition https://learn.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-context
PHANDLE: HANDLE
PIO_APC_ROUTINE: PVOID # TODO find definition
PIO_STATUS_BLOCK: PVOID # TODO add struct https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/ns-wdm-_io_status_block
PINITIAL_TEB: PVOID # TODO add struct definition from http://undocumented.ntinternals.net/
Expand Down Expand Up @@ -5108,6 +5104,7 @@ BackingParameterTypes:
LPWSTR_64: 8
UNICODE_WSTR_32: 4
UNICODE_WSTR_64: 8
unsigned __int32: 4
unsigned __int64: 8
unsigned long: 4
unsigned int: 4
Expand Down
2 changes: 1 addition & 1 deletion plugins/apitracing/src/lib/TracedProcess.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ namespace ApiTracing
: ConstantDefinitions::x64AddressWidth;
auto definitions = functionDefinitions->getFunctionParameterDefinitions(
moduleHookTarget.name, functionName, addressWidth);
auto extractor = std::make_shared<Extractor>(introspectionAPI, addressWidth);
auto extractor = std::make_shared<Extractor>(introspectionAPI, pluginInterface, addressWidth);
auto functionHook = std::make_shared<FunctionHook>(
moduleHookTarget.name, functionName, extractor, introspectionAPI, definitions, pluginInterface);
functionHook->hookFunction(moduleBaseAddress, processInformation);
Expand Down
101 changes: 76 additions & 25 deletions plugins/apitracing/src/lib/os/Extractor.cpp
Original file line number Diff line number Diff line change
@@ -1,15 +1,22 @@
#include "Extractor.h"
#include "../ConstantDefinitions.h"
#include "../Filenames.h"
#include <fmt/core.h>
#include <stdexcept>

using VmiCore::addr_t;
using VmiCore::IInterruptEvent;
using VmiCore::IIntrospectionAPI;

namespace ApiTracing
{
Extractor::Extractor(std::shared_ptr<IIntrospectionAPI> introspectionApi, uint8_t addressWidth)
: addressWidth(addressWidth), introspectionAPI(std::move(introspectionApi))
Extractor::Extractor(std::shared_ptr<VmiCore::IIntrospectionAPI> introspectionApi,
VmiCore::Plugin::PluginInterface* pluginInterface,
uint8_t addressWidth)
: addressWidth(addressWidth),
introspectionAPI(std::move(introspectionApi)),
pluginInterface(pluginInterface),
logger(this->pluginInterface->newNamedLogger(APITRACING_LOGGER_NAME))
{
}

Expand Down Expand Up @@ -74,23 +81,40 @@ namespace ApiTracing

for (const auto& parameterInfo : *parameterInformation)
{
if (!parameterInfo.basicType.empty())
if (parameterInfo.basicType.empty())
{
extractedParameterInformation.emplace_back(
extractSingleParameter(shallowParameters.at(parameterIndex), cr3, parameterInfo));
throw std::runtime_error("Malformed parameter information ! Aborting");
}
else if (!parameterInfo.backingParameters.empty())

if (!parameterInfo.backingParameters.empty())
{
addr_t structVA = dereferencePointer(shallowParameters.at(parameterIndex), cr3);
// skip optional parameters (e.g. AllocationSize in NtCreateFile)
if (auto pointerAddress = shallowParameters.at(parameterIndex); pointerAddress == 0)
{
extractedParameterInformation.emplace_back(
extractSingleParameter(pointerAddress, cr3, parameterInfo));
parameterIndex++;
continue;
}

ExtractedParameterInformation paramStruct{
.name = parameterInfo.name, .data = {}, .backingParameters = {}};
paramStruct.backingParameters =
extractBackingParameters({parameterInfo.backingParameters}, structVA, cr3);
try
{
paramStruct.backingParameters = extractBackingParameters(
{parameterInfo.backingParameters}, shallowParameters.at(parameterIndex), cr3);
}
catch (const std::exception& e)
{
logger->debug("Could not deep extract parameter",
{{"name", parameterInfo.name}, {"exception", e.what()}});
}
extractedParameterInformation.emplace_back(paramStruct);
}
else
{
throw std::runtime_error("Malformed parameter information ! Aborting");
extractedParameterInformation.emplace_back(
extractSingleParameter(shallowParameters.at(parameterIndex), cr3, parameterInfo));
}
parameterIndex++;
}
Expand All @@ -103,8 +127,17 @@ namespace ApiTracing
{
ExtractedParameterInformation result{};
result.name = parameterInfo.name;

switch (basicTypeStringToEnum.at(parameterInfo.basicType))
BasicTypes parameterType;
try
{
parameterType = basicTypeStringToEnum.at(parameterInfo.basicType);
}
catch (...)
{
std::throw_with_nested(
std::invalid_argument(fmt::format("Parameter not defined: {}", parameterInfo.basicType)));
}
switch (parameterType)
{
using enum BasicTypes;

Expand All @@ -123,11 +156,19 @@ namespace ApiTracing
case UNICODE_WSTR_32:
case UNICODE_WSTR_64:
{
result.data = extractUnicodeString(shallowParameter, cr3);
try
{
result.data = extractUnicodeString(shallowParameter, cr3);
}
catch (std::exception&)
{
result.data = "";
}
break;
}
case __PTR32:
case __PTR64:
case UNSIGNED___INT32:
case UNSIGNED___INT64:
case UNSIGNED_LONG:
case UNSIGNED_INT:
Expand All @@ -145,7 +186,7 @@ namespace ApiTracing
}
default:
{
break;
throw std::invalid_argument(fmt::format("Parameter not defined: {}", parameterInfo.basicType));
}
}
return result;
Expand Down Expand Up @@ -202,21 +243,31 @@ namespace ApiTracing
std::vector<ExtractedParameterInformation> extractedBackingParameters;
for (const auto& parameter : backingParameters)
{
if (parameter.backingParameters.empty())
ExtractedParameterInformation extraction{.name = parameter.name, .data = {}, .backingParameters = {}};
try
{
auto parameterValue = introspectionAPI->readVA(address + parameter.offset, cr3, parameter.size);
extractedBackingParameters.emplace_back(extractSingleParameter(parameterValue, cr3, parameter));
if (parameter.backingParameters.empty())
{
auto parameterValue = introspectionAPI->readVA(address + parameter.offset, cr3, parameter.size);
extraction = extractSingleParameter(parameterValue, cr3, parameter);
}
else
{
// Extract shallow parameters (based on size) from shallowParameters.at(parameterIndex). Then pass
// those to the nexţ iteration
addr_t structPointer = dereferencePointer(address + parameter.offset, cr3);

extraction.backingParameters =
extractBackingParameters(parameter.backingParameters, structPointer, cr3);
}
}
else
// Don't stop extraction on first failed parameter. Instead, insert default element try to extract the rest.
catch (const std::exception& e)
{
// Extract shallow parameters (based on size) from shallowParameters.at(parameterIndex). Then pass those
// to the nexţ iteration
addr_t structPointer = dereferencePointer(address + parameter.offset, cr3);
ExtractedParameterInformation extraction{.name = parameter.name, .data = {}, .backingParameters = {}};
extraction.backingParameters =
extractBackingParameters(parameter.backingParameters, structPointer, cr3);
extractedBackingParameters.emplace_back(extraction);
logger->debug("Could not extract backing parameter",
{{"name", parameter.name}, {"exception", e.what()}});
}
extractedBackingParameters.emplace_back(extraction);
}
return extractedBackingParameters;
}
Expand Down
9 changes: 8 additions & 1 deletion plugins/apitracing/src/lib/os/Extractor.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include <ostream>
#include <variant>
#include <vector>
#include <vmicore/plugins/PluginInterface.h>
#include <vmicore/vmi/IIntrospectionAPI.h>
#include <vmicore/vmi/events/IInterruptEvent.h>

Expand All @@ -26,6 +27,7 @@ namespace ApiTracing
INT,
LONG,
__INT64,
UNSIGNED___INT32,
UNSIGNED___INT64,
UNSIGNED_LONG,
UNSIGNED_INT,
Expand Down Expand Up @@ -86,7 +88,9 @@ namespace ApiTracing
class Extractor : public IExtractor
{
public:
Extractor(std::shared_ptr<VmiCore::IIntrospectionAPI> introspectionApi, uint8_t addressWidth);
Extractor(std::shared_ptr<VmiCore::IIntrospectionAPI> introspectionApi,
VmiCore::Plugin::PluginInterface* pluginInterface,
uint8_t addressWidth);

[[nodiscard]] std::vector<ExtractedParameterInformation>
extractParameters(VmiCore::IInterruptEvent& event,
Expand All @@ -105,6 +109,8 @@ namespace ApiTracing
uint8_t addressWidth;
std::variant<std::string, uint64_t, int> extractedParameters;
std::shared_ptr<VmiCore::IIntrospectionAPI> introspectionAPI;
VmiCore::Plugin::PluginInterface* pluginInterface;
std::unique_ptr<VmiCore::ILogger> logger;
std::map<std::string, BasicTypes, std::less<>> basicTypeStringToEnum{
{"LPSTR_32", BasicTypes::LPSTR_32},
{"LPSTR_64", BasicTypes::LPSTR_64},
Expand All @@ -117,6 +123,7 @@ namespace ApiTracing
{"int", BasicTypes::INT},
{"long", BasicTypes::LONG},
{"__int64", BasicTypes::__INT64},
{"unsigned __int32", BasicTypes::UNSIGNED___INT32},
{"unsigned __int64", BasicTypes::UNSIGNED___INT64},
{"unsigned long", BasicTypes::UNSIGNED_LONG},
{"unsigned int", BasicTypes::UNSIGNED_INT},
Expand Down
Loading

0 comments on commit 1682b22

Please sign in to comment.