110 lines
2.9 KiB
C++
110 lines
2.9 KiB
C++
#include "CExfil.h"
|
|
#include <cstdint>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
namespace
|
|
{
|
|
std::string ReadManagedName(uintptr_t stringObject)
|
|
{
|
|
if (!Memory::IsUserAddress(stringObject))
|
|
return {};
|
|
|
|
int32_t length = 0;
|
|
if (!m.TryRead(stringObject + offset::ManagedString::Length, length) ||
|
|
length <= 0 || length > 127)
|
|
{
|
|
return {};
|
|
}
|
|
|
|
std::vector<char16_t> chars;
|
|
if (!m.TryReadVector<char16_t>(stringObject + offset::ManagedString::Data,
|
|
static_cast<std::size_t>(length), chars, 127))
|
|
{
|
|
return {};
|
|
}
|
|
|
|
std::string name;
|
|
name.reserve(chars.size());
|
|
for (const char16_t ch : chars)
|
|
{
|
|
if (ch == 0)
|
|
break;
|
|
name.push_back(ch >= 0x20 && ch <= 0x7E ? static_cast<char>(ch) : '?');
|
|
}
|
|
return name;
|
|
}
|
|
}
|
|
|
|
ExfilDisplayCategory ClassifyExfilStatus(const uint8_t status) noexcept
|
|
{
|
|
switch (status)
|
|
{
|
|
case static_cast<uint8_t>(CLOSE):
|
|
return ExfilDisplayCategory::Closed;
|
|
case static_cast<uint8_t>(NOTREADY):
|
|
return ExfilDisplayCategory::Pending;
|
|
case static_cast<uint8_t>(OPEN):
|
|
case static_cast<uint8_t>(READY):
|
|
return ExfilDisplayCategory::Open;
|
|
default:
|
|
return ExfilDisplayCategory::Unknown;
|
|
}
|
|
}
|
|
|
|
const char* GetExfilStatusText(const uint8_t status) noexcept
|
|
{
|
|
switch (status)
|
|
{
|
|
case static_cast<uint8_t>(CLOSE): return "Closed";
|
|
case static_cast<uint8_t>(NOTREADY): return "Not ready";
|
|
case static_cast<uint8_t>(OPEN): return "Open";
|
|
case static_cast<uint8_t>(READY): return "Ready";
|
|
default: return "Unknown";
|
|
}
|
|
}
|
|
|
|
bool CExfil::GetAddress(uintptr_t& address)
|
|
{
|
|
ptr = address;
|
|
return Memory::IsUserAddress(ptr);
|
|
}
|
|
|
|
uint8_t CExfil::GetStatus()
|
|
{
|
|
uint8_t status = 0;
|
|
if (!Memory::IsUserAddress(ptr) || !m.TryRead(ptr + offset::Exfil::Status, status))
|
|
return 0;
|
|
return status;
|
|
}
|
|
|
|
std::string CExfil::GetName()
|
|
{
|
|
uintptr_t settings = 0;
|
|
uintptr_t namePtr = 0;
|
|
if (!Memory::IsUserAddress(ptr) ||
|
|
!m.TryRead(ptr + offset::Exfil::Settings, settings) || !Memory::IsUserAddress(settings) ||
|
|
!m.TryRead(settings + offset::Exfil::Name, namePtr) || !Memory::IsUserAddress(namePtr))
|
|
{
|
|
return {};
|
|
}
|
|
|
|
return ReadManagedName(namePtr);
|
|
}
|
|
|
|
bool CExfil::Update()
|
|
{
|
|
// Status is diagnostic data; a status read failure must not discard a valid position.
|
|
m_pExfilStatus = GetStatus();
|
|
m_pVecLocation = {};
|
|
|
|
if (!Memory::IsUserAddress(ptr))
|
|
return false;
|
|
|
|
const uintptr_t transform = m.ReadChain(ptr,
|
|
{ offset::UnityComponent::Step0, offset::UnityComponent::Step1, offset::UnityComponent::Step2,
|
|
offset::UnityComponent::Step3, offset::UnityComponent::Step4, offset::UnityComponent::Transform });
|
|
m_pVecLocation = GetTransformPosition(transform);
|
|
return !Vec3_Empty(m_pVecLocation);
|
|
}
|