Skip to content

Commit 40eabe2

Browse files
author
Thomas Dangl
committed
Initial implementation of ARMv8 support
1 parent ea232b1 commit 40eabe2

13 files changed

Lines changed: 160 additions & 40 deletions

vmicore/.clang-format

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,4 +18,5 @@ AllowShortEnumsOnASingleLine: false
1818
AllowShortFunctionsOnASingleLine: Empty
1919
AllowShortIfStatementsOnASingleLine: Never
2020
AllowShortLoopsOnASingleLine: false
21-
IndentCaseLabels: true
21+
IndentCaseLabels: true
22+
SortIncludes: false

vmicore/CMakeLists.txt

Lines changed: 41 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,16 @@
11
cmake_minimum_required(VERSION 3.16)
22
project(vmicore)
33

4+
set(X86_64 OFF)
5+
set(ARM64 OFF)
6+
7+
if (${CMAKE_SYSTEM_PROCESSOR} STREQUAL "x86_64")
8+
set(X86_64 ON)
9+
elseif (${CMAKE_SYSTEM_PROCESSOR} STREQUAL "aarch64")
10+
set(ARM64 ON)
11+
else ()
12+
message(FATAL_ERROR "Unknown architecture ${CMAKE_SYSTEM_PROCESSOR}")
13+
endif ()
414

515
# Options
616

@@ -15,7 +25,11 @@ set(CMAKE_CXX_STANDARD 20)
1525
set(CMAKE_CXX_STANDARD_REQUIRED ON)
1626
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
1727

18-
set(core_compile_flags -m64 -Wall)
28+
if (${X86_64})
29+
set(core_compile_flags -m64 -Wall)
30+
elseif (${ARM64})
31+
set(core_compile_flags -march=armv8-a -Wall)
32+
endif ()
1933
set(extra_compile_flags -Wunused -Wunreachable-code -Wextra -Wpedantic -Wno-dollar-in-identifier-extension)
2034

2135
# Toolchain checks
@@ -64,26 +78,40 @@ FetchContent_MakeAvailable(googletest)
6478

6579
# Setup libvmi
6680

67-
FetchContent_Declare(
68-
libvmi
69-
GIT_REPOSITORY https://github.com/GDATASoftwareAG/libvmi
70-
GIT_TAG test
71-
)
72-
set(libvmi_ENABLE_STATIC OFF)
73-
set(libvmi_BUILD_EXAMPLES OFF)
81+
set(ENABLE_STATIC OFF CACHE INTERNAL "")
82+
set(BUILD_EXAMPLES OFF CACHE INTERNAL "")
83+
set(ENABLE_VMIFS OFF CACHE INTERNAL "")
84+
set(ENABLE_FILE OFF CACHE INTERNAL "")
85+
set(ENABLE_BAREFLANK OFF CACHE INTERNAL "")
86+
set(ENABLE_PROFILES OFF CACHE INTERNAL "")
87+
set(ENABLE_TESTING OFF CACHE INTERNAL "")
88+
89+
if (${X86_64})
90+
FetchContent_Declare(
91+
libvmi
92+
GIT_REPOSITORY https://github.com/GDATASoftwareAG/libvmi
93+
GIT_TAG test
94+
)
95+
elseif (${ARM64})
96+
FetchContent_Declare(
97+
libvmi
98+
GIT_REPOSITORY https://gitlab.sec.uni-passau.de/sis/vmi-on-arm/libvmi.git
99+
GIT_TAG master
100+
)
101+
endif ()
74102
FetchContent_MakeAvailable(libvmi)
75103

76104
include_directories(BEFORE SYSTEM ${libvmi_SOURCE_DIR})
77105

78106
# Setup yaml-cpp
79107

108+
set(YAML_BUILD_SHARED_LIBS OFF CACHE INTERNAL "")
109+
set(YAML_CPP_BUILD_TOOLS OFF CACHE INTERNAL "")
80110
FetchContent_Declare(
81111
yaml-cpp
82112
GIT_REPOSITORY https://github.com/jbeder/yaml-cpp.git
83113
GIT_TAG yaml-cpp-0.7.0
84114
)
85-
set(yaml-cpp_YAML_BUILD_SHARED_LIBS OFF)
86-
set(yaml-cpp_YAML_CPP_BUILD_TOOLS OFF)
87115
FetchContent_MakeAvailable(yaml-cpp)
88116
set_property(TARGET yaml-cpp PROPERTY POSITION_INDEPENDENT_CODE TRUE)
89117

@@ -164,6 +192,9 @@ set(test_files
164192
test/vmi/LibvmiInterface_UnitTest.cpp
165193
test/vmi/SingleStepSupervisor_UnitTest.cpp)
166194

195+
configure_file(src/config.h.in ${PROJECT_BINARY_DIR}/config.h)
196+
include_directories(${PROJECT_BINARY_DIR})
197+
167198
# Link libraries
168199

169200
set(libraries rust_grpc_server vmicore_public_headers vmi_shared dl yaml-cpp GSL fmt-header-only)

vmicore/src/VmiHub.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,9 @@ uint VmiHub::run(const std::unordered_map<std::string, std::vector<std::string>>
151151
}
152152
case VMI_OS_WINDOWS:
153153
{
154+
#if defined(ARM64)
155+
throw new std::runtime_error("No support for Windows on ARM yet.");
156+
#endif
154157
auto kernelObjectExtractor = std::make_shared<Windows::KernelAccess>(vmiInterface);
155158
activeProcessesSupervisor = std::make_shared<Windows::ActiveProcessesSupervisor>(
156159
vmiInterface, kernelObjectExtractor, loggingLib, eventStream);

vmicore/src/config.h.in

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
2+
#cmakedefine ARM64
3+
#cmakedefine X86_64
4+

vmicore/src/os/linux/SystemEventSupervisor.cpp

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#include "SystemEventSupervisor.h"
22
#include "../../GlobalControl.h"
33
#include "Constants.h"
4+
#include <config.h>
45
#include <fmt/core.h>
56
#include <utility>
67

@@ -74,20 +75,33 @@ namespace Linux
7475

7576
InterruptEvent::InterruptResponse SystemEventSupervisor::procForkConnectorCallback(InterruptEvent& interruptEvent)
7677
{
77-
activeProcessesSupervisor->addNewProcess(interruptEvent.getRdi());
78+
#if defined(X86_64)
79+
uint64_t base = interruptEvent.getRegisters()->x86.rdi;
80+
#elif defined(ARM64)
81+
uint64_t base = interruptEvent.getRegisters()->arm.regs[0];
82+
#endif
83+
activeProcessesSupervisor->addNewProcess(base);
7884
return InterruptEvent::InterruptResponse::Continue;
7985
}
8086

8187
InterruptEvent::InterruptResponse SystemEventSupervisor::procExecConnectorCallback(InterruptEvent& interruptEvent)
8288
{
83-
activeProcessesSupervisor->removeActiveProcess(interruptEvent.getRdi());
84-
activeProcessesSupervisor->addNewProcess(interruptEvent.getRdi());
89+
#if defined(X86_64)
90+
uint64_t base = interruptEvent.getRegisters()->x86.rdi;
91+
#elif defined(ARM64)
92+
uint64_t base = interruptEvent.getRegisters()->arm.regs[0];
93+
#endif
94+
activeProcessesSupervisor->addNewProcess(base);
8595
return InterruptEvent::InterruptResponse::Continue;
8696
}
8797

8898
InterruptEvent::InterruptResponse SystemEventSupervisor::procExitConnectorCallback(InterruptEvent& interruptEvent)
8999
{
90-
auto taskStructBase = interruptEvent.getRdi();
100+
#if defined(X86_64)
101+
uint64_t taskStructBase = interruptEvent.getRegisters()->x86.rdi;
102+
#elif defined(ARM64)
103+
uint64_t taskStructBase = interruptEvent.getRegisters()->arm.regs[0];
104+
#endif
91105

92106
pluginSystem->passProcessTerminationEventToRegisteredPlugins(
93107
activeProcessesSupervisor->getProcessInformationByBase(taskStructBase));

vmicore/src/os/windows/SystemEventSupervisor.cpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -65,8 +65,9 @@ namespace Windows
6565
InterruptEvent::InterruptResponse
6666
SystemEventSupervisor::pspCallProcessNotifyRoutinesCallback(InterruptEvent& interruptEvent)
6767
{
68-
auto eprocessBase = interruptEvent.getRcx();
69-
bool isTerminationEvent = interruptEvent.getR8() == 0;
68+
auto& regs = interruptEvent.getRegisters()->x86;
69+
auto eprocessBase = regs.rcx;
70+
bool isTerminationEvent = regs.r8 == 0;
7071
logger->debug(fmt::format("{} called", __func__),
7172
{
7273
logfield::create("_EPROCESS_base ", fmt::format("{:#x}", eprocessBase)),
@@ -94,7 +95,7 @@ namespace Windows
9495

9596
InterruptEvent::InterruptResponse SystemEventSupervisor::keBugCheckExCallback(InterruptEvent& interruptEvent)
9697
{
97-
auto bugCheckCode = interruptEvent.getRcx();
98+
auto bugCheckCode = interruptEvent.getRegisters()->x86.rcx;
9899
eventStream->sendBSODEvent(static_cast<int64_t>(bugCheckCode));
99100
logger->warning("BSOD detected!", {logfield::create("BugCheckCode", fmt::format("{:#x}", bugCheckCode))});
100101
GlobalControl::endVmi = true;

vmicore/src/vmi/InterruptEvent.cpp

Lines changed: 34 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,9 @@ void InterruptEvent::initialize()
6969
void InterruptEvent::teardown()
7070
{
7171
disableEvent();
72-
interruptGuard->teardown();
72+
73+
if (interruptGuard)
74+
interruptGuard->teardown();
7375
}
7476

7577
InterruptEvent::~InterruptEvent()
@@ -89,33 +91,32 @@ void InterruptEvent::setupVmiInterruptEvent()
8991

9092
void InterruptEvent::enableEvent()
9193
{
94+
#if defined(X86_64)
9295
vmiInterface->write8PA(targetPA, INT3_BREAKPOINT);
96+
#elif defined(ARM64)
97+
vmiInterface->write32PA(targetPA, BRK64_BREAKPOINT);
98+
#endif
9399
logger->debug("Enabled interrupt event", {logfield::create("targetPA", targetPAString)});
94100
}
95101

96102
void InterruptEvent::disableEvent()
97103
{
104+
#if defined(X86_64)
98105
vmiInterface->write8PA(targetPA, originalValue);
106+
#elif defined(ARM64)
107+
vmiInterface->write32PA(targetPA, originalValue);
108+
#endif
99109
logger->debug("Disabled interrupt event", {logfield::create("targetPA", targetPAString)});
100110
}
101111

102-
uint64_t InterruptEvent::getRcx()
103-
{
104-
return event.x86_regs->rcx;
105-
}
106-
107-
uint64_t InterruptEvent::getRdi()
108-
{
109-
return event.x86_regs->rdi;
110-
}
111-
112-
uint64_t InterruptEvent::getR8()
112+
registers_t* InterruptEvent::getRegisters()
113113
{
114-
return event.x86_regs->r8;
114+
return (registers_t*)event.x86_regs;
115115
}
116116

117117
void InterruptEvent::storeOriginalValue()
118118
{
119+
#if defined(X86_64)
119120
originalValue = vmiInterface->read8PA(targetPA);
120121
logger->debug("Save original value",
121122
{logfield::create("targetPA", targetPAString),
@@ -125,16 +126,34 @@ void InterruptEvent::storeOriginalValue()
125126
throw VmiException(fmt::format(
126127
"{}: InterruptEvent originalValue @ {} is already an INT3 breakpoint.", __func__, targetPAString));
127128
}
129+
#elif defined(ARM64)
130+
originalValue = vmiInterface->read32PA(targetPA);
131+
logger->debug("Save original value",
132+
{logfield::create("targetPA", targetPAString),
133+
logfield::create("originalValue", fmt::format("{:#x}", originalValue))});
134+
if (originalValue == BRK64_BREAKPOINT)
135+
{
136+
throw VmiException(fmt::format(
137+
"{}: InterruptEvent originalValue @ {} is already an BRK64 breakpoint.", __func__, targetPAString));
138+
}
139+
#endif
128140
}
129141

130-
event_response_t InterruptEvent::_defaultInterruptCallback(__attribute__((unused)) vmi_instance_t vmi,
131-
vmi_event_t* event)
142+
event_response_t InterruptEvent::_defaultInterruptCallback(vmi_instance_t vmi, vmi_event_t* event)
132143
{
133144
auto eventResponse = VMI_EVENT_RESPONSE_NONE;
134145
try
135146
{
147+
#if defined(X86_64)
148+
(void)(vmi);
136149
auto eventPA =
137150
(event->interrupt_event.gfn << PagingDefinitions::numberOfPageIndexBits) + event->interrupt_event.offset;
151+
#elif defined(ARM64)
152+
addr_t eventPA;
153+
if (VMI_SUCCESS !=
154+
vmi_pagetable_lookup(vmi, event->arm_regs->ttbr1 & VMI_BIT_MASK(12, 47), event->arm_regs->pc, &eventPA))
155+
throw std::runtime_error("Failed address translation of breakpoint hit.");
156+
#endif
138157
auto interruptEventIterator = interruptsByPA.find(eventPA);
139158
if (interruptEventIterator != interruptsByPA.end())
140159
{

vmicore/src/vmi/InterruptEvent.h

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,13 @@
55
#include "Event.h"
66
#include "InterruptGuard.h"
77
#include "SingleStepSupervisor.h"
8+
#include <config.h>
89
#include <map>
910

1011
#define DONT_REINJECT_INTERRUPT 0
1112
#define REINJECT_INTERRUPT 1
1213
#define INT3_BREAKPOINT 0xCC
14+
#define BRK64_BREAKPOINT 0xD4200000
1315

1416
class InterruptEvent final : public Event, public std::enable_shared_from_this<InterruptEvent>
1517
{
@@ -33,11 +35,7 @@ class InterruptEvent final : public Event, public std::enable_shared_from_this<I
3335

3436
void teardown() override;
3537

36-
static uint64_t getRcx();
37-
38-
static uint64_t getRdi();
39-
40-
static uint64_t getR8();
38+
static registers_t* getRegisters();
4139

4240
static void initializeInterruptEventHandling(ILibvmiInterface& vmiInterface);
4341

@@ -68,9 +66,14 @@ class InterruptEvent final : public Event, public std::enable_shared_from_this<I
6866
std::unique_ptr<InterruptGuard> interruptGuard;
6967
std::function<InterruptResponse(InterruptEvent&)> callbackFunction;
7068
std::function<void(vmi_event_t*)> singleStepCallbackFunction;
71-
uint8_t originalValue = 0;
7269
std::string targetPAString;
7370

71+
#if defined(X86_64)
72+
uint8_t originalValue = 0;
73+
#elif defined(ARM64)
74+
uint32_t originalValue = 0;
75+
#endif
76+
7477
void enableEvent() override;
7578

7679
void disableEvent() override;

vmicore/src/vmi/InterruptFactory.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#include "InterruptFactory.h"
22
#include "../io/grpc/GRPCLogger.h"
33
#include "InterruptGuard.h"
4+
#include <config.h>
45
#include <memory>
56

67
InterruptFactory::InterruptFactory(std::shared_ptr<ILibvmiInterface> vmiInterface,
@@ -33,6 +34,7 @@ std::shared_ptr<InterruptEvent> InterruptFactory::createInterruptEvent(
3334

3435
auto targetPA = vmiInterface->convertVAToPA(targetVA, systemCr3);
3536

37+
#if defined(X86_64)
3638
auto interruptGuard = std::make_unique<InterruptGuard>(
3739
vmiInterface, loggingLib->newNamedLogger(interruptName), targetVA, targetPA, systemCr3);
3840

@@ -44,6 +46,14 @@ std::shared_ptr<InterruptEvent> InterruptFactory::createInterruptEvent(
4446
std::move(interruptGuard),
4547
callbackFunction,
4648
loggingLib->newNamedLogger(interruptName));
49+
#elif defined(ARM64)
50+
auto interruptEvent = std::make_shared<InterruptEvent>(vmiInterface,
51+
targetPA,
52+
singleStepSupervisor,
53+
nullptr,
54+
callbackFunction,
55+
loggingLib->newNamedLogger(interruptName));
56+
#endif
4757

4858
interruptEvent->initialize();
4959
return interruptEvent;

vmicore/src/vmi/LibvmiInterface.cpp

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,18 @@ uint8_t LibvmiInterface::read8PA(const uint64_t physicalAddress)
9090
return extractedValue;
9191
}
9292

93+
uint32_t LibvmiInterface::read32PA(const uint64_t physicalAddress)
94+
{
95+
uint32_t extractedValue = 0;
96+
auto accessContext = createPhysicalAddressAccessContext(physicalAddress);
97+
std::lock_guard<std::mutex> lock(libvmiLock);
98+
if (vmi_read_32(vmiInstance, &accessContext, &extractedValue) == VMI_FAILURE)
99+
{
100+
throw VmiException(fmt::format("{}: Unable to read four byte from PA: {:#x}", __func__, physicalAddress));
101+
}
102+
return extractedValue;
103+
}
104+
93105
uint8_t LibvmiInterface::read8VA(const uint64_t virtualAddress, const uint64_t cr3)
94106
{
95107
uint8_t extractedValue = 0;
@@ -147,6 +159,16 @@ void LibvmiInterface::write8PA(const uint64_t physicalAddress, uint8_t value)
147159
}
148160
}
149161

162+
void LibvmiInterface::write32PA(const uint64_t physicalAddress, uint32_t value)
163+
{
164+
auto accessContext = createPhysicalAddressAccessContext(physicalAddress);
165+
std::lock_guard<std::mutex> lock(libvmiLock);
166+
if (vmi_write_32(vmiInstance, &accessContext, &value) == VMI_FAILURE)
167+
{
168+
throw VmiException(fmt::format("{}: Unable to write {:#x} to PA {:#x}", __func__, value, physicalAddress));
169+
}
170+
}
171+
150172
access_context_t LibvmiInterface::createPhysicalAddressAccessContext(uint64_t physicalAddress)
151173
{
152174
access_context_t accessContext{};

0 commit comments

Comments
 (0)