diff options
Diffstat (limited to 'client/src/util')
| -rw-r--r-- | client/src/util/native.h | 209 | ||||
| -rw-r--r-- | client/src/util/pe.h | 55 | ||||
| -rw-r--r-- | client/src/util/syscalls.cpp | 99 | ||||
| -rw-r--r-- | client/src/util/syscalls.h | 22 | ||||
| -rw-r--r-- | client/src/util/util.cpp | 52 | ||||
| -rw-r--r-- | client/src/util/util.h | 26 |
6 files changed, 463 insertions, 0 deletions
diff --git a/client/src/util/native.h b/client/src/util/native.h new file mode 100644 index 0000000..623e577 --- /dev/null +++ b/client/src/util/native.h @@ -0,0 +1,209 @@ +#pragma once + +namespace native { + struct PEB_LDR_DATA { + uint32_t Length; + uint8_t Initialized; + uintptr_t SsHandle; + LIST_ENTRY InLoadOrderModuleList; + LIST_ENTRY InMemoryOrderModuleList; + LIST_ENTRY InInitializationOrderModuleList; + uintptr_t EntryInProgress; + uint8_t ShutdownInProgress; + uintptr_t ShutdownThreadId; + }; + + struct UNICODE_STRING { + uint16_t Length; + uint16_t MaximumLength; + wchar_t *Buffer; + }; + + struct STRING { + uint16_t Length; + uint16_t MaximumLength; + char *Buffer; + }; + + struct CURDIR { + UNICODE_STRING DosPath; + uintptr_t Handle; + }; + + struct RTL_DRIVE_LETTER_CURDIR { + uint16_t Flags; + uint16_t Length; + uint32_t TimeStamp; + STRING DosPath; + }; + + struct RTL_USER_PROCESS_PARAMETERS { + uint32_t MaximumLength; + uint32_t Length; + uint32_t Flags; + uint32_t DebugFlags; + uintptr_t ConsoleHandle; + uint32_t ConsoleFlags; + uintptr_t StandardInput; + uintptr_t StandardOutput; + uintptr_t StandardError; + CURDIR CurrentDirectory; + UNICODE_STRING DllPath; + UNICODE_STRING ImagePathName; + UNICODE_STRING CommandLine; + uintptr_t Environment; + uint32_t StartingX; + uint32_t StartingY; + uint32_t CountX; + uint32_t CountY; + uint32_t CountCharsX; + uint32_t CountCharsY; + uint32_t FillAttribute; + uint32_t WindowFlags; + uint32_t ShowWindowFlags; + UNICODE_STRING WindowTitle; + UNICODE_STRING DesktopInfo; + UNICODE_STRING ShellInfo; + UNICODE_STRING RuntimeData; + RTL_DRIVE_LETTER_CURDIR CurrentDirectores[ 32 ]; + uintptr_t EnvironmentSize; + uintptr_t EnvironmentVersion; + uintptr_t PackageDependencyData; + uint32_t ProcessGroupId; + uint32_t LoaderThreads; + }; + + struct RTL_BALANCED_NODE { + RTL_BALANCED_NODE *Children[ 2 ]; + RTL_BALANCED_NODE *Left; + RTL_BALANCED_NODE *Right; + uintptr_t ParentValue; + }; + + struct _PEB { + uint8_t InheritedAddressSpace; + uint8_t ReadImageFileExecOptions; + uint8_t BeingDebugged; + uint8_t BitField; + //uchar Padding0[ 4 ]; + uintptr_t Mutant; + uintptr_t ImageBaseAddress; + PEB_LDR_DATA *Ldr; + RTL_USER_PROCESS_PARAMETERS *ProcessParameters; + uintptr_t SubSystemData; + uintptr_t ProcessHeap; + RTL_CRITICAL_SECTION *FastPebLock; + uintptr_t AtlThunkSListPtr; + uintptr_t IFEOKey; + uint32_t CrossProcessFlags; + uint8_t Padding1[ 4 ]; + uintptr_t KernelCallbackTable; + uintptr_t UserSharedInfoPtr; + uint32_t SystemReserved[ 1 ]; + uint32_t AtlThunkSListPtr32; + uintptr_t ApiSetMap; + uint32_t TlsExpansionCounter; + uint8_t Padding2[ 4 ]; + uintptr_t TlsBitmap; + uint32_t TlsBitmapBits[ 2 ]; + uintptr_t ReadOnlySharedMemoryBase; + uintptr_t SparePvoid0; + uintptr_t ReadOnlyStaticServerData; + uintptr_t AnsiCodePageData; + uintptr_t OemCodePageData; + uintptr_t UnicodeCaseTableData; + uint32_t NumberOfProcessors; + uint32_t NtGlobalFlag; + LARGE_INTEGER CriticalSectionTimeout; + uintptr_t HeapSegmentReserve; + uintptr_t HeapSegmentCommit; + uintptr_t HeapDeCommitTotalFreeThreshold; + uintptr_t HeapDeCommitFreeBlockThreshold; + uint32_t NumberOfHeaps; + uint32_t MaximumNumberOfHeaps; + uintptr_t ProcessHeaps; + uintptr_t GdiSharedHandleTable; + uintptr_t ProcessStarterHelper; + uint32_t GdiDCAttributeList; + uint8_t Padding3[ 4 ]; + RTL_CRITICAL_SECTION *LoaderLock; + uint32_t OSMajorVersion; + uint32_t OSMinorVersion; + uint16_t OSBuildNumber; + uint16_t OSCSDVersion; + uint32_t OSPlatformId; + uint32_t ImageSubsystem; + uint32_t ImageSubsystemMajorVersion; + uint32_t ImageSubsystemMinorVersion; + uint8_t Padding4[ 4 ]; + uintptr_t ActiveProcessAffinityMask; +#ifdef _WIN32 + uint32_t GdiHandleBuffer[ 34 ]; +#else + uint32_t GdiHandleBuffer[ 60 ]; +#endif + uintptr_t PostProcessInitRoutine; + uintptr_t TlsExpansionBitmap; + uint32_t TlsExpansionBitmapBits[ 32 ]; + uint32_t SessionId; + uint8_t Padding5[ 4 ]; + ULARGE_INTEGER AppCompatFlags; + ULARGE_INTEGER AppCompatFlagsUser; + uintptr_t pShimData; + uintptr_t AppCompatInfo; + UNICODE_STRING CSDVersion; + uintptr_t ActivationContextData; + uintptr_t ProcessAssemblyStorageMap; + uintptr_t SystemDefaultActivationContextData; + uintptr_t SystemAssemblyStorageMap; + uintptr_t MinimumStackCommit; + uintptr_t FlsCallback; + LIST_ENTRY FlsListHead; + uintptr_t FlsBitmap; + uint32_t FlsBitmapBits[ 4 ]; + uint32_t FlsHighIndex; + uintptr_t WerRegistrationData; + uintptr_t WerShipAssertPtr; + uintptr_t pUnused; + uintptr_t pImageHeaderHash; + uint32_t TracingFlags; + uint8_t Padding6[ 4 ]; + uint64_t CsrServerReadOnlySharedMemoryBase; + uintptr_t TppWorkerpListLock; + LIST_ENTRY TppWorkerpList; + uintptr_t WaitOnAddressHashTable[ 128 ]; + }; + + struct LDR_DATA_TABLE_ENTRY { + LIST_ENTRY InLoadOrderLinks; + LIST_ENTRY InMemoryOrderLinks; + LIST_ENTRY InInitializationOrderLinks; + uintptr_t DllBase; + uintptr_t EntryPoint; + uint32_t SizeOfImage; + UNICODE_STRING FullDllName; + UNICODE_STRING BaseDllName; + uint8_t FlagGroup[ 4 ]; + uint32_t Flags; + uint16_t ObsoleteLoadCount; + uint16_t TlsIndex; + LIST_ENTRY HashLinks; + uint32_t TimeDateStamp; + uintptr_t EntryPointActivationContext; + uintptr_t Lock; + uintptr_t DdagNode; + LIST_ENTRY NodeModuleLink; + uintptr_t LoadContext; + uintptr_t ParentDllBase; + uintptr_t SwitchBackContext; + RTL_BALANCED_NODE BaseAddressIndexNode; + RTL_BALANCED_NODE MappingInfoIndexNode; + uintptr_t OriginalBase; + LARGE_INTEGER LoadTime; + uint32_t BaseNameHashValue; + uint32_t LoadReason; + uint32_t ImplicitPathOptions; + uint32_t ReferenceCount; + }; + +}; // namespace native
\ No newline at end of file diff --git a/client/src/util/pe.h b/client/src/util/pe.h new file mode 100644 index 0000000..a4d835d --- /dev/null +++ b/client/src/util/pe.h @@ -0,0 +1,55 @@ +#pragma once + +namespace pe { + +class image { + std::unordered_map<std::string, uintptr_t> m_exports; + + IMAGE_NT_HEADERS64 *m_nt; + uintptr_t m_base; + bool m_valid; + + public: + image(){}; + image(const uintptr_t base) : m_valid{false}, m_base{base}, m_nt{nullptr} { + auto dos = reinterpret_cast<IMAGE_DOS_HEADER *>(base); + if (!dos || dos->e_magic != IMAGE_DOS_SIGNATURE) { + return; + } + + m_nt = reinterpret_cast<IMAGE_NT_HEADERS64 *>(base + dos->e_lfanew); + if (m_nt->Signature != IMAGE_NT_SIGNATURE) { + return; + } + + m_valid = true; + } + + void parse_exports() { + auto dir = m_nt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT]; + auto exp = + reinterpret_cast<IMAGE_EXPORT_DIRECTORY *>(m_base + dir.VirtualAddress); + + if (exp->NumberOfFunctions == 0) return; + + auto names = reinterpret_cast<uint32_t *>(m_base + exp->AddressOfNames); + auto funcs = reinterpret_cast<uint32_t *>(m_base + exp->AddressOfFunctions); + auto ords = + reinterpret_cast<uint16_t *>(m_base + exp->AddressOfNameOrdinals); + + if (!names || !funcs || !ords) return; + + for (size_t i{}; i < exp->NumberOfFunctions; i++) { + uintptr_t va = m_base + funcs[ords[i]]; + std::string name = reinterpret_cast<const char *>(m_base + names[i]); + + m_exports[name] = va; + } + } + + auto &exports() { return m_exports; } + + operator bool() { return m_valid; } +}; + +}; // namespace pe
\ No newline at end of file diff --git a/client/src/util/syscalls.cpp b/client/src/util/syscalls.cpp new file mode 100644 index 0000000..624ce5a --- /dev/null +++ b/client/src/util/syscalls.cpp @@ -0,0 +1,99 @@ +#include "../include.h" +#include "io.h" +#include "util.h" +#include "syscalls.h" + +syscalls g_syscalls; + +syscalls::syscalls() { + m_call_table = VirtualAlloc(0, 0x100000, MEM_COMMIT | MEM_RESERVE, + PAGE_EXECUTE_READWRITE); + std::memset(m_call_table, 0x90, 0x100000); +} + +syscalls::~syscalls() { + VirtualFree(m_call_table, 0, MEM_RELEASE); +} + +void syscalls::init() { + auto nt = util::ntdll(); + for (auto& exp : nt.exports()) { + auto addr = exp.second; + + uint16_t offset; + auto idx = get_index(addr, offset); + + if(!idx) continue; + + m_indexes[exp.first] = std::make_pair(idx, offset); + + if (m_stub.empty()) { + auto s = func_size(reinterpret_cast<uint8_t*>(addr)); + + m_stub.resize(s); + + std::memcpy(&m_stub[0], (void*)addr, s); + } + } + + io::logger->info("{:x}", uintptr_t(m_call_table)); + + for (auto& syscall : m_indexes) { + auto idx = syscall.second.first; + + auto addr = uintptr_t(m_call_table) + (idx * m_stub.size()); + std::memcpy(reinterpret_cast<void*>(addr), m_stub.data(), m_stub.size()); + + *reinterpret_cast<uint8_t*>(addr + m_stub.size() - 1) = 0xc3; + *reinterpret_cast<uint16_t*>(addr + syscall.second.second + 1) = idx; + } +} + +bool syscalls::valid(const uintptr_t addr, const size_t &size) { + auto func = reinterpret_cast<uint8_t*>(addr); + + // mov r10, rcx + uint32_t a = func[0] + func[1] + func[2]; + if (a != 0x1a8) { + return false; + } + + for (size_t i{}; i < size; i++) { + auto op = func[i]; + auto next = func[i + 1]; + + if (op == 0x0f && next == 0x05) { + return true; + } + } + + return false; +} + +uint16_t syscalls::get_index(const uintptr_t va, uint16_t &offset) { + auto func = reinterpret_cast<uint8_t*>(va); + auto size = func_size(reinterpret_cast<uint8_t*>(va)); + if (!valid(va, size)) { + return 0; + } + + for (size_t i{}; i < size; i++) { + auto op = func[i]; + if (op == 0xb8) { + offset = i; + + return *reinterpret_cast<uint16_t*>(va + i + 1); + } + } + return 0; +} + +size_t syscalls::func_size(const uint8_t* func) { + for (size_t i = 0; i < 64; i++) { + auto op = func[i]; + if (op == 0xc3 || op == 0xc2) { + return i + 1; + } + } + return 0; +} diff --git a/client/src/util/syscalls.h b/client/src/util/syscalls.h new file mode 100644 index 0000000..0d73e4e --- /dev/null +++ b/client/src/util/syscalls.h @@ -0,0 +1,22 @@ +#pragma once + +class syscalls { + std::unordered_map<std::string, std::pair<uint16_t, uint16_t>> m_indexes; + std::vector<char> m_stub; + + void *m_call_table; +public: + syscalls(); + ~syscalls(); + void init(); + bool valid(const uintptr_t func, const size_t &size); + uint16_t get_index(const uintptr_t va, uint16_t &offset); + size_t func_size(const uint8_t *func); + + template<class T> + T get(const std::string_view func) { + return reinterpret_cast<T>(uintptr_t(m_call_table) + (m_indexes[func.data()].first * m_stub.size())); + }; +}; + +extern syscalls g_syscalls;
\ No newline at end of file diff --git a/client/src/util/util.cpp b/client/src/util/util.cpp new file mode 100644 index 0000000..a23c03c --- /dev/null +++ b/client/src/util/util.cpp @@ -0,0 +1,52 @@ +#include "../include.h" +#include "io.h" +#include "util.h" + +std::unordered_map<std::string, pe::image> util::loaded_modules; + +std::string util::wide_to_multibyte(const std::wstring &str) { + std::string ret; + int32_t str_len; + + // check if not empty str + if (str.empty()) + return{}; + + // count size + str_len = WideCharToMultiByte(CP_UTF8, 0, &str[0], (int32_t) str.size(), 0, 0, 0, 0); + + // setup return value + ret = std::string(str_len, 0); + + // final conversion + WideCharToMultiByte(CP_UTF8, 0, &str[0], (int32_t) str.size(), &ret[0], str_len, 0, 0); + + return ret; +} + + +native::_PEB* util::get_peb() { + return reinterpret_cast<native::_PEB*>(__readgsqword(0x60)); +} + +bool util::init() { + auto peb = get_peb(); + if (!peb) return false; + + if (!peb->Ldr->InMemoryOrderModuleList.Flink) return false; + + auto* list = &peb->Ldr->InMemoryOrderModuleList; + + for (auto i = list->Flink; i != list; i = i->Flink) { + auto entry = CONTAINING_RECORD(i, native::LDR_DATA_TABLE_ENTRY, InMemoryOrderLinks); + if (!entry) + continue; + + auto name = wide_to_multibyte(entry->BaseDllName.Buffer); + std::transform(name.begin(), name.end(), name.begin(), ::tolower); + + loaded_modules[name] = pe::image(entry->DllBase); + } + + return true; +} diff --git a/client/src/util/util.h b/client/src/util/util.h new file mode 100644 index 0000000..b4bf699 --- /dev/null +++ b/client/src/util/util.h @@ -0,0 +1,26 @@ +#pragma once + +#include "native.h" +#include "pe.h" + +namespace util { + +extern std::unordered_map<std::string, pe::image> loaded_modules; + +std::string wide_to_multibyte(const std::wstring &str); + +native::_PEB *get_peb(); + +bool init(); + +static pe::image& ntdll() { + static pe::image nt{}; + if (!nt) { + nt = loaded_modules["ntdll.dll"]; + nt.parse_exports(); + } + return nt; +} + +}; // namespace util + |