#pragma once #include "util.hpp" #include extern "C" { #include #include #include #include } namespace { static constexpr size_t UCRED_SIZE = 0x168; } template void kread(uintptr_t addr, T *dst) { kernel_copyout(addr, dst, sizeof(T)); } template T kread(uintptr_t addr) { T dst{}; kernel_copyout(addr, &dst, sizeof(T)); return dst; } template void kread(uintptr_t addr, uint8_t(&buf)[length]) { kernel_copyout(addr, buf, length); } template void kwrite(uintptr_t addr, const T& value) { kernel_copyin(const_cast(&value), addr, sizeof(T)); // NOLINT(cppcoreguidelines-pro-type-const-cast) } template void kwrite(uintptr_t addr, const uint8_t(&buf)[length]) { kernel_copyin(const_cast(buf), addr, length); // NOLINT(cppcoreguidelines-pro-type-const-cast) } inline void kwrite(uintptr_t addr, const void *src, size_t length) { kernel_copyin(const_cast(src), addr, length); // NOLINT(cppcoreguidelines-pro-type-const-cast) } template class KernelObject; template concept SizedKernelObject = requires { T::length; }; template concept DerivedKernelObject = requires (T t) { static_cast>(t); }; template concept KernelObjectBase = SizedKernelObject && DerivedKernelObject; template class KIterable; String getKernelString(uintptr_t addr); template class KernelObject { uintptr_t addr; protected: template friend class KIterable; uint8_t buf[__restrict size]; explicit KernelObject() = default; KernelObject(uintptr_t addr) : addr(addr) { // NOLINT(cppcoreguidelines-pro-type-member-init) #ifdef DEBUG if (addr == 0) [[unlikely]] { fatalf("kernel nullpointer dereference attempted\n"); volatile void **tmp = nullptr; *tmp = nullptr; // NOLINT(clang-analyzer-core.NullDereference) } #endif kernel_copyout(addr, buf, size); } void reload() { kernel_copyout(addr, buf, size); } template T get() const { static_assert(offset < size, "offset >= size"); return *(T *)(buf + offset); } template void set(T value) { static_assert(offset < size, "offset >= size"); *(T *)(buf + offset) = value; } template String getString() const { uintptr_t addr = get(); return getKernelString(addr); } public: static constexpr size_t length = size; KernelObject(KernelObject &&rhs) noexcept = default; KernelObject &operator=(KernelObject &&rhs) noexcept = default; KernelObject(const KernelObject &rhs) = default; KernelObject &operator=(const KernelObject &rhs) = default; ~KernelObject() noexcept = default; explicit operator bool() const { return addr; } const void *data() const { return buf; } uintptr_t address() const { return addr; } void flush() const { #ifdef DEBUG if (!addr) [[unlikely]] { fatalf("nullptr dereference\n"); } #endif kernel_copyin(const_cast(buf), addr, size); // NOLINT(cppcoreguidelines-pro-type-const-cast) } }; template class KPointer { protected: uintptr_t addr; public: KPointer(decltype(nullptr)) noexcept : addr(0) {} KPointer(uintptr_t addr) noexcept : addr(addr) {} T operator*() const { T t; kernel_copyout(addr, &t, sizeof(T)); return t; } explicit operator bool() const { return addr; } bool operator==(const KPointer &rhs) const { return addr == rhs.addr; } }; template struct KIterator; template class KIterable { friend struct KIterator; protected: uintptr_t addr; KIterable(decltype(nullptr)) : addr() {} public: KIterable(uintptr_t addr) : addr(addr) {} UniquePtr operator*() { return {new T{addr}}; } bool operator!=(const KIterable &rhs) const { return addr != rhs.addr; } KIterable &operator++() { #ifdef DEBUG if (addr == 0) [[unlikely]] { return *this; } #endif uintptr_t ptr = 0; kernel_copyout(addr, &ptr, sizeof(ptr)); addr = ptr; return *this; } explicit operator bool() const { return addr; } }; template struct KIterator { uintptr_t addr; KIterator(uintptr_t addr) : addr(addr) {} KIterable begin() const { return addr; } KIterable end() const { return nullptr; } }; class KUcred : public KernelObject { static constexpr size_t AUTHID_OFFSET = 0x58; public: KUcred(uintptr_t addr) : KernelObject(addr) {} uint64_t authid() const { return get(); } void authid(uint64_t value) { set(value); } };