aboutsummaryrefslogtreecommitdiff
path: root/CRT
diff options
context:
space:
mode:
Diffstat (limited to 'CRT')
-rw-r--r--CRT/DriverThread.cpp297
-rw-r--r--CRT/DriverThread.hpp167
-rw-r--r--CRT/eastl_compat.cpp189
-rw-r--r--CRT/eastl_compat.hpp26
-rw-r--r--CRT/eastl_user_config.hpp37
-rw-r--r--CRT/except.h35
-rwxr-xr-xCRT/gen_wrapper.sh174
-rw-r--r--CRT/kcrt.c313
-rw-r--r--CRT/kcrt.cpp51
-rw-r--r--CRT/nanoprintf.h1104
-rw-r--r--CRT/ntdll_zw_functions.c409
-rw-r--r--CRT/ntdll_zw_functions.txt19
-rw-r--r--CRT/obfuscate.hpp163
-rw-r--r--CRT/ucrt.cpp10
14 files changed, 2994 insertions, 0 deletions
diff --git a/CRT/DriverThread.cpp b/CRT/DriverThread.cpp
new file mode 100644
index 0000000..3a77dc8
--- /dev/null
+++ b/CRT/DriverThread.cpp
@@ -0,0 +1,297 @@
+#include <DriverThread.hpp>
+
+class WorkQueueArgs : public DriverThread::ThreadArgs
+{
+ friend class WorkQueue;
+
+public:
+ WorkQueueArgs(DriverThread::WorkQueue * wq) : m_wq(wq){};
+ WorkQueueArgs(const WorkQueueArgs &) = delete;
+ DriverThread::WorkQueue * getWorkQueue()
+ {
+ return m_wq;
+ }
+
+private:
+ DriverThread::WorkQueue * m_wq;
+};
+
+// Thread
+
+DriverThread::Thread::Thread(void)
+{
+}
+
+DriverThread::Thread::~Thread(void)
+{
+ WaitForTermination();
+}
+
+extern "C" void InterceptorThreadRoutine(PVOID threadContext)
+{
+ NTSTATUS threadReturn;
+ DriverThread::Thread * self = (DriverThread::Thread *)threadContext;
+
+ self->m_threadId = PsGetCurrentThreadId();
+ threadReturn = self->m_routine(self->m_threadContext);
+ self->m_threadId = nullptr;
+ self->m_threadContext = nullptr;
+ PsTerminateSystemThread(threadReturn);
+}
+
+NTSTATUS DriverThread::Thread::Start(ThreadRoutine routine, eastl::shared_ptr<ThreadArgs> args)
+{
+ HANDLE threadHandle;
+ NTSTATUS status;
+
+ LockGuard lock(m_mutex);
+ if (m_threadObject != nullptr)
+ {
+ return STATUS_UNSUCCESSFUL;
+ }
+
+ m_routine = routine;
+ m_threadContext = args;
+ status = PsCreateSystemThread(&threadHandle, (ACCESS_MASK)0, NULL, (HANDLE)0, NULL, InterceptorThreadRoutine, this);
+
+ if (!NT_SUCCESS(status))
+ {
+ return status;
+ }
+
+ status =
+ ObReferenceObjectByHandle(threadHandle, THREAD_ALL_ACCESS, NULL, KernelMode, (PVOID *)&m_threadObject, NULL);
+
+ if (!NT_SUCCESS(status))
+ {
+ return status;
+ }
+
+ return ZwClose(threadHandle);
+}
+
+NTSTATUS DriverThread::Thread::WaitForTermination(LONGLONG timeout)
+{
+ if (PsGetCurrentThreadId() == m_threadId)
+ {
+ return STATUS_UNSUCCESSFUL;
+ }
+
+ LockGuard lock(m_mutex);
+ if (m_threadObject == nullptr)
+ {
+ return STATUS_UNSUCCESSFUL;
+ }
+
+ LARGE_INTEGER li_timeout = {.QuadPart = timeout};
+ NTSTATUS status =
+ KeWaitForSingleObject(m_threadObject, Executive, KernelMode, FALSE, (timeout == 0 ? NULL : &li_timeout));
+
+ ObDereferenceObject(m_threadObject);
+ m_threadObject = nullptr;
+ return status;
+}
+
+// Spinlock
+
+DriverThread::Spinlock::Spinlock(void)
+{
+ KeInitializeSpinLock(&m_spinLock);
+}
+
+NTSTATUS DriverThread::Spinlock::Acquire(void)
+{
+ return KeAcquireSpinLock(&m_spinLock, &m_oldIrql);
+}
+
+void DriverThread::Spinlock::Release(void)
+{
+ KeReleaseSpinLock(&m_spinLock, m_oldIrql);
+}
+
+KIRQL DriverThread::Spinlock::GetOldIrql(void)
+{
+ return m_oldIrql;
+}
+
+// Semaphore
+
+DriverThread::Semaphore::Semaphore(LONG initialValue, LONG maxValue)
+{
+ KeInitializeSemaphore(&m_semaphore, initialValue, maxValue);
+}
+
+NTSTATUS DriverThread::Semaphore::Wait(LONGLONG timeout)
+{
+ LARGE_INTEGER li_timeout = {.QuadPart = timeout};
+ return KeWaitForSingleObject(&m_semaphore, Executive, KernelMode, FALSE, (timeout == 0 ? NULL : &li_timeout));
+}
+
+LONG DriverThread::Semaphore::Release(LONG adjustment)
+{
+ return KeReleaseSemaphore(&m_semaphore, 0, adjustment, FALSE);
+}
+
+// Event
+
+DriverThread::Event::Event()
+{
+ KeInitializeEvent(&m_event, NotificationEvent, FALSE);
+}
+
+NTSTATUS DriverThread::Event::Wait(LONGLONG timeout)
+{
+ LARGE_INTEGER li_timeout = {.QuadPart = timeout};
+ return KeWaitForSingleObject(&m_event, Executive, KernelMode, FALSE, (timeout == 0 ? NULL : &li_timeout));
+}
+
+NTSTATUS DriverThread::Event::Notify()
+{
+ return KeSetEvent(&m_event, 0, FALSE);
+}
+
+// Mutex
+
+DriverThread::Mutex::Mutex(void)
+{
+}
+
+DriverThread::Mutex::~Mutex(void)
+{
+}
+
+void DriverThread::Mutex::Lock(void)
+{
+ while (m_interlock == 1 || InterlockedCompareExchange(&m_interlock, 1, 0) == 1) {}
+}
+
+void DriverThread::Mutex::Unlock(void)
+{
+ m_interlock = 0;
+}
+
+// LockGuard
+
+DriverThread::LockGuard::LockGuard(Mutex & m) : m_Lock(m)
+{
+ m_Lock.Lock();
+}
+
+DriverThread::LockGuard::~LockGuard(void)
+{
+ m_Lock.Unlock();
+}
+
+// WorkQueue
+
+DriverThread::WorkQueue::WorkQueue(void)
+ : m_mutex(), m_queue(), m_wakeEvent(), m_stopWorker(false), m_worker(), m_workerRoutine(nullptr)
+{
+}
+
+DriverThread::WorkQueue::~WorkQueue(void)
+{
+ Stop();
+}
+
+NTSTATUS DriverThread::WorkQueue::Start(WorkerRoutine routine)
+{
+ NTSTATUS status;
+
+ {
+ LockGuard lock(m_mutex);
+ m_workerRoutine = routine;
+ auto wqa = eastl::make_shared<WorkQueueArgs>(this);
+ status = m_worker.Start(WorkerInterceptorRoutine, wqa);
+ }
+
+ if (!NT_SUCCESS(status) && status != STATUS_UNSUCCESSFUL)
+ {
+ Stop();
+ }
+
+ return status;
+}
+
+void DriverThread::WorkQueue::Stop(bool wait)
+{
+ LockGuard lock(m_mutex);
+ if (m_stopWorker == true)
+ {
+ return;
+ }
+ m_stopWorker = true;
+ m_wakeEvent.Notify();
+ if (wait)
+ {
+ m_worker.WaitForTermination();
+ }
+}
+
+void DriverThread::WorkQueue::Enqueue(WorkItem & item)
+{
+ {
+ LockGuard lock(m_mutex);
+ m_queue.emplace_back(item);
+ }
+ m_wakeEvent.Notify();
+}
+
+void DriverThread::WorkQueue::Enqueue(eastl::deque<WorkItem> & items)
+{
+ {
+ LockGuard lock(m_mutex);
+ m_queue.insert(m_queue.end(), items.begin(), items.end());
+ }
+ m_wakeEvent.Notify();
+}
+
+NTSTATUS DriverThread::WorkQueue::WorkerInterceptorRoutine(eastl::shared_ptr<ThreadArgs> args)
+{
+ auto wqa = eastl::static_pointer_cast<WorkQueueArgs>(args);
+ WorkQueue * wq = wqa->getWorkQueue();
+
+ PAGED_CODE();
+
+ for (;;)
+ {
+ eastl::deque<WorkItem> doQueue;
+ std::size_t nItems;
+
+ {
+ LockGuard lock(wq->m_mutex);
+ nItems = wq->m_queue.size();
+ }
+
+ if (nItems == 0)
+ {
+ if (wq->m_stopWorker == true)
+ {
+ break;
+ }
+
+ wq->m_wakeEvent.Wait();
+ continue;
+ }
+
+ {
+ LockGuard lock(wq->m_mutex);
+ doQueue = wq->m_queue;
+ wq->m_queue.clear();
+ }
+
+ while (doQueue.size() > 0)
+ {
+ WorkItem & item = doQueue.front();
+
+ if (wq->m_workerRoutine(item) != STATUS_SUCCESS)
+ {
+ wq->m_stopWorker = true;
+ }
+
+ doQueue.pop_front();
+ }
+ }
+
+ return STATUS_SUCCESS;
+}
diff --git a/CRT/DriverThread.hpp b/CRT/DriverThread.hpp
new file mode 100644
index 0000000..ac2eddd
--- /dev/null
+++ b/CRT/DriverThread.hpp
@@ -0,0 +1,167 @@
+#ifndef DDK_THREAD
+#define DDK_THREAD 1
+
+#include <ntddk.h>
+
+#include <EASTL/deque.h>
+#include <EASTL/functional.h>
+#include <EASTL/shared_ptr.h>
+
+extern "C" void InterceptorThreadRoutine(PVOID threadContext);
+
+namespace DriverThread
+{
+class Mutex
+{
+public:
+ Mutex(void);
+ ~Mutex(void);
+
+private:
+ void Lock();
+ void Unlock();
+
+ volatile long int m_interlock;
+
+ friend class LockGuard;
+};
+
+class LockGuard
+{
+public:
+ LockGuard(Mutex & m);
+ ~LockGuard(void);
+
+private:
+ Mutex m_Lock;
+};
+
+class ThreadArgs : public virtual eastl::enable_shared_from_this<ThreadArgs>
+{
+public:
+ ThreadArgs(void)
+ {
+ }
+ ThreadArgs(const ThreadArgs &) = delete;
+ virtual ~ThreadArgs(void)
+ {
+ }
+};
+
+using ThreadRoutine = eastl::function<NTSTATUS(eastl::shared_ptr<ThreadArgs> args)>;
+
+class Thread
+{
+public:
+ Thread(void);
+ Thread(const Thread &) = delete;
+ ~Thread(void);
+ NTSTATUS Start(ThreadRoutine routine, eastl::shared_ptr<ThreadArgs> args);
+ NTSTATUS WaitForTermination(LONGLONG timeout = 0);
+ HANDLE GetThreadId(void)
+ {
+ return m_threadId;
+ }
+ bool isRunning(void)
+ {
+ return GetThreadId() != nullptr;
+ }
+
+private:
+ friend void ::InterceptorThreadRoutine(PVOID threadContext);
+
+ HANDLE m_threadId = nullptr;
+ PETHREAD m_threadObject = nullptr;
+ Mutex m_mutex;
+ ThreadRoutine m_routine;
+ eastl::shared_ptr<ThreadArgs> m_threadContext;
+};
+
+class Spinlock
+{
+public:
+ Spinlock(void);
+ NTSTATUS Acquire(void);
+ void Release(void);
+ KIRQL GetOldIrql(void);
+
+private:
+ KIRQL m_oldIrql;
+ KSPIN_LOCK m_spinLock;
+};
+
+class Semaphore
+{
+public:
+ Semaphore(LONG initialValue = 0, LONG maxValue = MAXLONG);
+ NTSTATUS Wait(LONGLONG timeout = 0);
+ LONG Release(LONG adjustment = 1);
+
+private:
+ KSEMAPHORE m_semaphore;
+};
+
+class Event
+{
+public:
+ Event();
+ NTSTATUS Wait(LONGLONG timeout = 0);
+ NTSTATUS Notify();
+
+private:
+ KEVENT m_event;
+};
+
+class WorkItem final
+{
+ friend class WorkQueue;
+
+public:
+ WorkItem(const eastl::shared_ptr<void> & user) : m_user(std::move(user))
+ {
+ }
+ virtual ~WorkItem(void)
+ {
+ }
+ template <class T>
+ eastl::shared_ptr<T> Get(void)
+ {
+ return eastl::static_pointer_cast<T>(m_user);
+ }
+ template <class T>
+ void Get(eastl::shared_ptr<T> & dest)
+ {
+ dest = eastl::static_pointer_cast<T>(m_user);
+ }
+
+private:
+ eastl::shared_ptr<void> m_user;
+};
+
+using WorkerRoutine = eastl::function<NTSTATUS(WorkItem & item)>;
+
+class WorkQueue final
+{
+public:
+ WorkQueue(void);
+ WorkQueue(const WorkQueue &) = delete;
+ ~WorkQueue(void);
+ NTSTATUS Start(WorkerRoutine routine);
+ void Stop(bool wait = true);
+ void Enqueue(WorkItem & item);
+ void Enqueue(eastl::deque<WorkItem> & items);
+
+private:
+ Mutex m_mutex;
+ eastl::deque<WorkItem> m_queue;
+ Event m_wakeEvent;
+ bool m_stopWorker; // Work LIST must be empty and StopWorker TRUE to be able to stop!
+ Thread m_worker;
+ WorkerRoutine m_workerRoutine;
+
+ static NTSTATUS WorkerInterceptorRoutine(eastl::shared_ptr<ThreadArgs> args);
+};
+
+}; // namespace DriverThread
+
+#endif
diff --git a/CRT/eastl_compat.cpp b/CRT/eastl_compat.cpp
new file mode 100644
index 0000000..e252f5f
--- /dev/null
+++ b/CRT/eastl_compat.cpp
@@ -0,0 +1,189 @@
+#include "eastl_compat.hpp"
+
+#define NANOPRINTF_VISIBILITY_STATIC 1
+#define NANOPRINTF_USE_FLOAT_FORMAT_SPECIFIERS 1
+#define NANOPRINTF_USE_PRECISION_FORMAT_SPECIFIERS 1
+#define NANOPRINTF_USE_FIELD_WIDTH_FORMAT_SPECIFIERS 1
+#define NANOPRINTF_USE_LARGE_FORMAT_SPECIFIERS 1
+#define NANOPRINTF_USE_BINARY_FORMAT_SPECIFIERS 0
+#define NANOPRINTF_USE_WRITEBACK_FORMAT_SPECIFIERS 0
+#define NANOPRINTF_IMPLEMENTATION 1
+#include "nanoprintf.h"
+
+#ifndef NATIVE
+#include <wdm.h>
+#endif
+
+/*
+ * eastl::to_string(...) does not work yet event if with a provided Vsnprintf/Vsnprintf8
+ * The issue seems to be caused by a broken va_list/va_copy.
+ */
+
+eastl::string to_string(int value)
+{
+ int nbytes = npf_snprintf(nullptr, 0, "%d", value);
+ if (nbytes > 0)
+ {
+ char result[nbytes + 1] = {};
+ npf_snprintf(result, nbytes, "%d", value);
+ return result;
+ }
+ else
+ return "";
+}
+
+eastl::string to_string(long value)
+{
+ int nbytes = npf_snprintf(nullptr, 0, "%ld", value);
+ if (nbytes > 0)
+ {
+ char result[nbytes + 1] = {};
+ npf_snprintf(result, nbytes, "%ld", value);
+ return result;
+ }
+ else
+ return "";
+}
+
+eastl::string to_string(long long value)
+{
+ int nbytes = npf_snprintf(nullptr, 0, "%lld", value);
+ if (nbytes > 0)
+ {
+ char result[nbytes + 1] = {};
+ npf_snprintf(result, nbytes, "%lld", value);
+ return result;
+ }
+ else
+ return "";
+}
+
+eastl::string to_string(unsigned int value)
+{
+ int nbytes = npf_snprintf(nullptr, 0, "%u", value);
+ if (nbytes > 0)
+ {
+ char result[nbytes + 1] = {};
+ npf_snprintf(result, nbytes, "%u", value);
+ return result;
+ }
+ else
+ return "";
+}
+
+eastl::string to_string(unsigned long int value)
+{
+ int nbytes = npf_snprintf(nullptr, 0, "%lu", value);
+ if (nbytes > 0)
+ {
+ char result[nbytes + 1] = {};
+ npf_snprintf(result, nbytes, "%lu", value);
+ return result;
+ }
+ else
+ return "";
+}
+
+eastl::string to_string(unsigned long long int value)
+{
+ int nbytes = npf_snprintf(nullptr, 0, "%llu", value);
+ if (nbytes > 0)
+ {
+ char result[nbytes + 1] = {};
+ npf_snprintf(result, nbytes, "%llu", value);
+ return result;
+ }
+ else
+ return "";
+}
+
+eastl::string to_string(float value)
+{
+ int nbytes = npf_snprintf(nullptr, 0, "%f", value);
+ if (nbytes > 0)
+ {
+ char result[nbytes + 1] = {};
+ npf_snprintf(result, nbytes, "%f", value);
+ return result;
+ }
+ else
+ return "";
+}
+
+eastl::string to_string(double value)
+{
+ int nbytes = npf_snprintf(nullptr, 0, "%lf", value);
+ if (nbytes > 0)
+ {
+ char result[nbytes + 1] = {};
+ npf_snprintf(result, nbytes, "%lf", value);
+ return result;
+ }
+ else
+ return "";
+}
+
+template <typename T>
+static eastl::string to_string_hex(T w, size_t hex_len = sizeof(T) << 1)
+{
+ static const char * const digits = "0123456789ABCDEF";
+ const size_t len = sizeof(T) << 1;
+
+ if (hex_len < len)
+ hex_len = len;
+ eastl::string rc(hex_len, '0');
+ for (size_t i = hex_len - len, j = (hex_len - 1) * 4; i < hex_len; ++i, j -= 4)
+ rc[i] = digits[(w >> j) & 0x0f];
+ return rc;
+}
+
+eastl::string to_string_hex(int value, size_t fill_width)
+{
+ return to_string_hex<int>(value, fill_width);
+}
+
+eastl::string to_string_hex(long value, size_t fill_width)
+{
+ return to_string_hex<long>(value, fill_width);
+}
+
+eastl::string to_string_hex(long long value, size_t fill_width)
+{
+ return to_string_hex<long long>(value, fill_width);
+}
+
+eastl::string to_string_hex(unsigned int value, size_t fill_width)
+{
+ return to_string_hex<unsigned int>(value, fill_width);
+}
+
+eastl::string to_string_hex(unsigned long int value, size_t fill_width)
+{
+ return to_string_hex<unsigned long int>(value, fill_width);
+}
+
+eastl::string to_string_hex(unsigned long long int value, size_t fill_width)
+{
+ return to_string_hex<unsigned long long int>(value, fill_width);
+}
+
+#ifndef NATIVE
+eastl::string from_unicode(wchar_t * wstr, unsigned short wlen, unsigned short wmax)
+{
+ ANSI_STRING ansi;
+ UNICODE_STRING unicode;
+
+ unicode.Buffer = wstr;
+ unicode.Length = wlen;
+ unicode.MaximumLength = (wmax > 0 ? wmax : wlen);
+
+ if (NT_SUCCESS(RtlUnicodeStringToAnsiString(&ansi, &unicode, TRUE)))
+ {
+ eastl::string result(ansi.Buffer, ansi.Length);
+ RtlFreeAnsiString(&ansi);
+ return result;
+ }
+
+ return "";
+}
+#endif
diff --git a/CRT/eastl_compat.hpp b/CRT/eastl_compat.hpp
new file mode 100644
index 0000000..2459e75
--- /dev/null
+++ b/CRT/eastl_compat.hpp
@@ -0,0 +1,26 @@
+#ifndef EASTL_COMPAT
+#define EASTL_COMPAT 1
+
+#include <EASTL/string.h>
+
+eastl::string to_string(int value);
+eastl::string to_string(long value);
+eastl::string to_string(long long value);
+eastl::string to_string(unsigned int value);
+eastl::string to_string(unsigned long int value);
+eastl::string to_string(unsigned long long int value);
+eastl::string to_string(float value);
+eastl::string to_string(double value);
+
+eastl::string to_string_hex(int value, size_t fill_width = 0);
+eastl::string to_string_hex(long value, size_t fill_width = 0);
+eastl::string to_string_hex(long long value, size_t fill_width = 0);
+eastl::string to_string_hex(unsigned int value, size_t fill_width = 0);
+eastl::string to_string_hex(unsigned long int value, size_t fill_width = 0);
+eastl::string to_string_hex(unsigned long long int value, size_t fill_width = 0);
+
+#ifndef NATIVE
+eastl::string from_unicode(wchar_t * wstr, unsigned short wlen, unsigned short wmax = 0);
+#endif
+
+#endif
diff --git a/CRT/eastl_user_config.hpp b/CRT/eastl_user_config.hpp
new file mode 100644
index 0000000..5a2f733
--- /dev/null
+++ b/CRT/eastl_user_config.hpp
@@ -0,0 +1,37 @@
+#ifndef EASTL_USER_CONFIG_HPP
+#define EASTL_USER_CONFIG_HPP 1
+
+#include <string.h>
+
+extern "C" {
+static inline int snprintf_eastl_to_string_warning(char * out, unsigned long long int size)
+{
+ const char msg[] = "!!! DO NOT USE eastl::to_string !!!";
+ const unsigned long long int msg_size = sizeof(msg);
+
+ if (out == NULL || size < msg_size)
+ {
+ return sizeof(msg);
+ }
+
+ memcpy(out, msg, msg_size);
+ return msg_size;
+}
+
+static inline int Vsnprintf8(char * out, unsigned long long int size, const char *, char *)
+{
+ return snprintf_eastl_to_string_warning(out, size);
+}
+
+static inline int Vsnprintf16(char * out, unsigned long long int size, const char *, char *)
+{
+ return snprintf_eastl_to_string_warning(out, size);;
+}
+
+static inline int Vsnprintf32(char * out, unsigned long long int size, const char *, char *)
+{
+ return snprintf_eastl_to_string_warning(out, size);
+}
+};
+
+#endif
diff --git a/CRT/except.h b/CRT/except.h
new file mode 100644
index 0000000..7f39eac
--- /dev/null
+++ b/CRT/except.h
@@ -0,0 +1,35 @@
+#ifndef EXCEPT_H
+#define EXCEPT_H 1
+
+#ifndef __SEH__
+#error "SEH not supported by your toolchain!"
+#endif
+
+#ifdef __try1
+#undef __try1
+#endif
+
+#ifdef __except1
+#undef __except1
+#endif
+
+#define __dpptry(handler, counter) \
+ __asm__ goto( \
+ ".seh_handler __C_specific_handler, @except\n\t" \
+ ".seh_handlerdata\n\t" \
+ ".long 1\n\t" \
+ ".rva .l_startw" #counter ", .l_endw" #counter ", " #handler ", .l_exceptw" #counter \
+ "\n\t" \
+ ".section .text\n" \
+ ".l_startw" #counter ":" :: ::except);
+
+#define __dppexcept(counter) \
+ goto end; \
+ except: \
+ __asm__(".l_exceptw" #counter ":");
+
+#define __dpptryend(counter) \
+ end: \
+ __asm__(".l_endw" #counter ":");
+
+#endif
diff --git a/CRT/gen_wrapper.sh b/CRT/gen_wrapper.sh
new file mode 100755
index 0000000..35e0d43
--- /dev/null
+++ b/CRT/gen_wrapper.sh
@@ -0,0 +1,174 @@
+#!/usr/bin/env sh
+
+MYDIR="$(dirname ${0})"
+FN_FILE="${1:-${MYDIR}/ntdll_zw_functions.txt}"
+
+TYPEDEFS=""
+STATICS=""
+CURLINE=0
+while read -r line; do
+ CURLINE=$(expr ${CURLINE} + 1)
+ VALID=1
+ SYMBOL_EXISTS=0
+
+ if [ -z "${line}" ]; then
+ continue
+ fi
+ if [ $(printf '%s\n' "${line}" | grep -oE '^#*') ]; then
+ continue
+ fi
+
+ rtype=$(printf '%s\n' "${line}" | grep -oE '(NTSTATUS NTAPI|VOID NTAPI|PVOID NTAPI)')
+ if [ -z "${rtype}" ]; then
+ printf '%s\n' "Line ${CURLINE}: Missing return value of either type 'NTSTATUS NTAPI' or 'VOID NTAPI'." >&2
+ VALID=0
+ fi
+
+ fnname=$(printf '%s\n' "${line}" | grep -oE '(_|)(Zw|Rtl|Ob[^j]|Mm|Io)[^ (]*')
+ if [ -z "${fnname}" ]; then
+ printf '%s\n' "Line ${CURLINE}: Missing function name." >&2
+ VALID=0
+ fi
+ if [ $(printf '%s\n' "${fnname}" | wc -l) -ne 1 ]; then
+ printf '%s\n' "Invalid function name '${fnname}'." >&2
+ VALID=0
+ fi
+ if [ $(printf '%s\n' "${fnname}" | grep -oE '^_*') ]; then
+ SYMBOL_EXISTS=1
+ fi
+
+ fnsig=$(printf '%s\n' "${line}" | grep -oE '\([^;]*')
+ if [ -z "${fnsig}" ]; then
+ printf '%s\n' "Line ${CURLINE}: Missing function signature." >&2
+ VALID=0
+ fi
+
+ params_without_braces=$(printf '%s\n' "${fnsig}" | tr -d '()')
+ if [ ! -z "${params_without_braces}" ]; then
+ param_names=$(printf '%s\n' "${params_without_braces}" | sed 's/\([^,]*\)/\1\n/g' | grep -oE '[^ ]*$')
+ if [ -z "${param_names}" ]; then
+ printf '%s\n' "Line ${CURLINE}: Could not parse function parameters." >&2
+ VALID=0
+ fi
+ else
+ param_names=""
+ fi
+ params=""
+ for param in ${param_names}; do
+ if [ -z "${param}" ]; then
+ printf '%s\n' "Line ${CURLINE}: Invalid parameter found. Please re-check regex'es used." >&2
+ VALID=0
+ fi
+ params="${params}${param}, "
+ done
+ params=$(printf '%s\n' "${params}" | sed 's/^\(.*\), $/\1/g')
+ if [ -z "${params}" -a ! -z "${params_without_braces}" ]; then
+ printf '%s\n' "Line ${CURLINE}: Parameters empty. Please re-check regex'es used." >&2
+ VALID=0
+ fi
+
+ if [ ${VALID} -eq 1 ]; then
+ TYPE="${fnname}_t"
+ VAR="_${fnname}"
+ TYPEDEFS="${TYPEDEFS}\ntypedef ${rtype} (*${TYPE}) ${fnsig};"
+ STATICS="${STATICS}\nstatic ${TYPE} ${VAR} = NULL;"
+ if [ ${SYMBOL_EXISTS} -eq 1 ]; then
+ fnname_str=$(printf '%s\n' "${fnname}" | sed 's/^\(.\)\{1\}//g')
+ else
+ fnname_str="${fnname}"
+ fi
+ INITS=$(cat <<EOF
+${INITS}
+#ifdef __cplusplus
+ RtlInitUnicodeString(&fnName, skCrypt(L"${fnname_str}"));
+#else
+ RtlInitUnicodeString(&fnName, L"${fnname_str}");
+#endif
+ ${VAR} = (${TYPE})MmGetSystemRoutineAddress(&fnName);
+ if (${VAR} == NULL)
+ {
+#ifdef __cplusplus
+ DbgPrint(skCrypt("%s\\\n"), skCrypt("System routine ${fnname_str} not found."));
+#else
+ DbgPrint("%s\\\n", "System routine ${fnname_str} not found.");
+#endif
+ retval++;
+ }
+EOF
+ )
+ WRAPPERS=$(cat <<EOF
+${WRAPPERS}
+
+${rtype} ${fnname} ${fnsig}
+{
+EOF
+ )
+ case $rtype in
+ NTSTATUS*)
+ WRAPPERS=$(cat <<EOF
+${WRAPPERS}
+ if (${VAR} == NULL)
+ return STATUS_PROCEDURE_NOT_FOUND;
+
+ return ${VAR} (${params});
+}
+
+${rtype} Wrapper${fnname_str} ${fnsig}
+{
+ return ${VAR} (${params});
+}
+EOF
+ )
+ ;;
+ PVOID*)
+ WRAPPERS=$(cat <<EOF
+${WRAPPERS}
+ return ${VAR} (${params});
+}
+
+${rtype} Wrapper${fnname} ${fnsig}
+{
+ return ${VAR} (${params});
+}
+EOF
+ )
+ esac
+ fi
+done < "${FN_FILE}"
+
+cat <<EOF
+/* This file was auto generated by $(basename ${0}) */
+#include <ntddk.h>
+
+#ifdef __cplusplus
+#define _KERNEL_MODE 1
+#include "obfuscate.hpp"
+
+extern "C" {
+#endif
+EOF
+echo "${TYPEDEFS}"
+echo "${STATICS}"
+cat <<EOF
+
+int __cdecl $(basename -a -s '.txt' ${FN_FILE}) (void)
+{
+ int retval = 0;
+ UNICODE_STRING fnName;
+EOF
+echo "${INITS}"
+cat <<EOF
+
+ return retval;
+}
+EOF
+echo "${WRAPPERS}"
+
+cat <<EOF
+
+#ifdef __cplusplus
+};
+#endif
+EOF
+
+printf '%s lines parsed\n' "${CURLINE}" >&2
diff --git a/CRT/kcrt.c b/CRT/kcrt.c
new file mode 100644
index 0000000..11f20d3
--- /dev/null
+++ b/CRT/kcrt.c
@@ -0,0 +1,313 @@
+/*
+ * Shameless copy pasta from: https://github.com/sidyhe/dxx
+ * and: https://github.com/liupengs/Mini-CRT
+ * and some minor modifications.
+ */
+
+#include <ntddk.h>
+
+#include "except.h"
+
+#define KCRT_POOL_DEFAULT_TAG 0xDEADBEEF
+
+extern void (*__CTOR_LIST__)();
+extern void (*__DTOR_LIST__)();
+extern NTSTATUS __cdecl DriverEntry(struct _DRIVER_OBJECT * DriverObject, PUNICODE_STRING RegistryPath);
+extern void __cdecl DriverUnload(struct _DRIVER_OBJECT * DriverObject);
+extern int __cdecl ntdll_zw_functions(void);
+
+DRIVER_INITIALIZE __cdecl _CRT_DriverEntry;
+DRIVER_UNLOAD __cdecl _CRT_DriverUnload;
+
+typedef void (*__cdecl init_and_deinit_fn)(void);
+typedef void (*__cdecl atexit_func_t)(void);
+
+typedef struct _func_node
+{
+ atexit_func_t func;
+ struct _func_node * next;
+} func_node;
+
+typedef struct _MALLOC_HEADER
+{
+ ULONG32 Tags;
+ ULONG32 _Resv0;
+ ULONG_PTR Size;
+} MALLOC_HEADER, *PMALLOC_HEADER;
+C_ASSERT(sizeof(MALLOC_HEADER) % sizeof(void *) == 0);
+
+static func_node * atexit_list = NULL;
+
+// dynamic memory mgmt
+
+PMALLOC_HEADER GET_MALLOC_HEADER(PVOID ptr)
+{
+ return (MALLOC_HEADER *)((PUCHAR)ptr - sizeof(MALLOC_HEADER));
+}
+
+PVOID GET_MALLOC_ADDRESS(PMALLOC_HEADER header)
+{
+ return (PVOID)((PUCHAR)header + sizeof(MALLOC_HEADER));
+}
+
+ULONG_PTR GET_MALLOC_SIZE(PVOID ptr)
+{
+ PMALLOC_HEADER header = GET_MALLOC_HEADER(ptr);
+
+ if (header->Tags != KCRT_POOL_DEFAULT_TAG)
+ KeBugCheckEx(BAD_POOL_HEADER, 0, 0, 0, 0);
+
+ return header->Size;
+}
+
+// c runtime
+
+static int register_atexit(atexit_func_t func)
+{
+ func_node * node;
+ if (!func)
+ return -1;
+
+ node = (func_node *)malloc(sizeof(func_node));
+
+ if (node == 0)
+ return -1;
+
+ node->func = func;
+ node->next = atexit_list;
+ atexit_list = node;
+ return 0;
+}
+
+int __cdecl atexit(atexit_func_t func)
+{
+ return register_atexit(func);
+}
+
+void __cdecl free(void * ptr)
+{
+ if (ptr)
+ {
+ MALLOC_HEADER * mhdr = GET_MALLOC_HEADER(ptr);
+
+ if (mhdr->Tags != KCRT_POOL_DEFAULT_TAG)
+ KeBugCheckEx(BAD_POOL_HEADER, 0, 0, 0, 0);
+
+ ExFreePool(mhdr);
+ }
+}
+
+void * __cdecl malloc(size_t size)
+{
+ PMALLOC_HEADER mhdr = NULL;
+ const size_t new_size = size + sizeof(MALLOC_HEADER);
+
+ mhdr = (PMALLOC_HEADER)ExAllocatePoolWithTag(new_size > PAGE_SIZE ? PagedPool : NonPagedPool, new_size, KCRT_POOL_DEFAULT_TAG);
+ if (mhdr)
+ {
+ RtlZeroMemory(mhdr, new_size);
+
+ mhdr->Tags = KCRT_POOL_DEFAULT_TAG;
+ mhdr->Size = size;
+ return GET_MALLOC_ADDRESS(mhdr);
+ }
+
+ return NULL;
+}
+
+void * __cdecl calloc(size_t nmemb, size_t size)
+{
+ return malloc(nmemb * size);
+}
+
+void * __cdecl realloc(void * ptr, size_t new_size)
+{
+ if (!ptr)
+ {
+ return malloc(new_size);
+ }
+ else if (new_size == 0)
+ {
+ free(ptr);
+ return NULL;
+ }
+ else
+ {
+ size_t old_size = GET_MALLOC_SIZE(ptr);
+
+ if (new_size <= old_size)
+ {
+ return ptr;
+ }
+ else
+ {
+ void * new_ptr = malloc(new_size);
+
+ if (new_ptr)
+ {
+ memcpy(new_ptr, ptr, old_size);
+ free(ptr);
+ return new_ptr;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+void __cdecl __cxa_pure_virtual(void)
+{
+ // definitly not perfect, but we get at least a notification
+ while (1)
+ {
+ DbgPrint("Pure virtual function call..\n");
+ LARGE_INTEGER li = {.QuadPart = -10000000};
+ KeDelayExecutionThread(KernelMode, TRUE, &li);
+ }
+}
+
+// stolen from musl: https://elixir.bootlin.com/musl/v1.1.9/source/src/math/ceilf.c
+#define FORCE_EVAL(x) \
+ do \
+ { \
+ if (sizeof(x) == sizeof(float)) \
+ { \
+ volatile float __x __attribute__((unused)); \
+ __x = (x); \
+ } \
+ else if (sizeof(x) == sizeof(double)) \
+ { \
+ volatile double __x __attribute__((unused)); \
+ __x = (x); \
+ } \
+ else \
+ { \
+ volatile long double __x __attribute__((unused)); \
+ __x = (x); \
+ } \
+ } while (0)
+
+float __cdecl ceilf(float x)
+{
+ union
+ {
+ float f;
+ UINT32 i;
+ } u = {x};
+ int e = (int)(u.i >> 23 & 0xff) - 0x7f;
+ UINT32 m;
+
+ if (e >= 23)
+ return x;
+ if (e >= 0)
+ {
+ m = 0x007fffff >> e;
+ if ((u.i & m) == 0)
+ return x;
+ FORCE_EVAL(x + 0x1p120f);
+ if (u.i >> 31 == 0)
+ u.i += m;
+ u.i &= ~m;
+ }
+ else
+ {
+ FORCE_EVAL(x + 0x1p120f);
+ if (u.i >> 31)
+ u.f = -0.0;
+ else if (u.i << 1)
+ u.f = 1.0;
+ }
+ return u.f;
+}
+
+// functions called in DRIVER_INITIALIZE and DRIVER_UNLOAD
+
+static void __cdecl __ctors(void)
+{
+ unsigned long long int const * const * const l = (unsigned long long int const * const * const) & __CTOR_LIST__;
+ unsigned long long int i = (unsigned long long int)*l;
+ init_and_deinit_fn const * p;
+
+ if (i == (unsigned long long int)-1)
+ {
+ for (i = 1; l[i] != NULL; i++)
+ ;
+ i--;
+ }
+
+ p = (init_and_deinit_fn *)&l[i];
+
+ while (i--)
+ {
+ (**p--)();
+ }
+}
+
+static void __cdecl __dtors(void)
+{
+ func_node * p = atexit_list;
+ for (; p != NULL; p = p->next)
+ {
+ p->func();
+ free(p);
+ }
+ atexit_list = NULL;
+}
+
+void __cdecl KCRT_OnDriverEntry(void)
+{
+ __ctors();
+}
+
+void __cdecl KCRT_OnDriverUnload(void)
+{
+ __dtors();
+}
+
+void __cdecl _CRT_DriverUnload(struct _DRIVER_OBJECT * DriverObject)
+{
+ DriverUnload(DriverObject);
+
+ KCRT_OnDriverUnload();
+}
+
+NTSTATUS __cdecl _CRT_DriverEntry(struct _DRIVER_OBJECT * DriverObject, PUNICODE_STRING RegistryPath)
+{
+ NTSTATUS retval;
+
+ KCRT_OnDriverEntry();
+
+ int zw_retval = ntdll_zw_functions();
+ if (zw_retval != 0)
+ {
+ return STATUS_NOT_IMPLEMENTED;
+ }
+
+ retval = DriverEntry(DriverObject, RegistryPath);
+
+ /* support for service stopping and CRT de-init */
+ DriverObject->DriverUnload = _CRT_DriverUnload;
+
+ return retval;
+}
+
+void __cdecl _enable(void)
+{
+ __asm__ __volatile__("sti");
+}
+
+void __cdecl _disable(void)
+{
+ __asm__ __volatile__("cli");
+}
+
+void * __cdecl _AddressOfReturnAddress(void)
+{
+ return __builtin_extract_return_addr(__builtin_return_address(0));
+}
+
+char __cdecl _putchar(char c)
+{
+ DbgPrint("%c", c);
+ return c;
+}
diff --git a/CRT/kcrt.cpp b/CRT/kcrt.cpp
new file mode 100644
index 0000000..32681ab
--- /dev/null
+++ b/CRT/kcrt.cpp
@@ -0,0 +1,51 @@
+/*
+ * Shameless copy pasta from: https://github.com/sidyhe/dxx
+ * and: https://github.com/liupengs/Mini-CRT
+ * and some minor modifications.
+ */
+
+#include <cstdio>
+#include <cstdlib>
+
+// new & delete
+
+void * __cdecl operator new(std::size_t size)
+{
+ return malloc(size);
+}
+
+void * __cdecl operator new[](size_t size)
+{
+ return malloc(size);
+}
+
+void __cdecl operator delete(void * ptr)
+{
+ free(ptr);
+}
+
+void __cdecl operator delete(void * ptr, size_t)
+{
+ free(ptr);
+}
+
+void __cdecl operator delete[](void * ptr, long long unsigned int)
+{
+ free(ptr);
+}
+
+void __cdecl operator delete[](void * ptr)
+{
+ free(ptr);
+}
+
+// EASTL
+
+void * operator new[](size_t size, const char *, int, unsigned, const char *, int)
+{
+ return malloc(size);
+}
+void * operator new[](size_t size, size_t, size_t, const char *, int, unsigned, const char *, int)
+{
+ return malloc(size);
+}
diff --git a/CRT/nanoprintf.h b/CRT/nanoprintf.h
new file mode 100644
index 0000000..290ddfe
--- /dev/null
+++ b/CRT/nanoprintf.h
@@ -0,0 +1,1104 @@
+/* nanoprintf: a tiny embeddable printf replacement written in C.
+ https://github.com/charlesnicholson/nanoprintf
+ charles.nicholson+nanoprintf@gmail.com
+ dual-licensed under 0bsd and unlicense, take your pick. see eof for details. */
+
+#ifndef NANOPRINTF_H_INCLUDED
+#define NANOPRINTF_H_INCLUDED
+
+#include <stdarg.h>
+#include <stddef.h>
+
+// Define this to fully sandbox nanoprintf inside of a translation unit.
+#ifdef NANOPRINTF_VISIBILITY_STATIC
+ #define NPF_VISIBILITY static
+#else
+ #define NPF_VISIBILITY extern
+#endif
+
+#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__)
+ #define NPF_PRINTF_ATTR(FORMAT_INDEX, VARGS_INDEX) \
+ __attribute__((format(printf, FORMAT_INDEX, VARGS_INDEX)))
+#else
+ #define NPF_PRINTF_ATTR(FORMAT_INDEX, VARGS_INDEX)
+#endif
+
+// Public API
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// The npf_ functions all return the number of bytes required to express the
+// fully-formatted string, not including the null terminator character.
+// The npf_ functions do not return negative values, since the lack of 'l' length
+// modifier support makes encoding errors impossible.
+
+NPF_VISIBILITY int npf_snprintf(
+ char *buffer, size_t bufsz, const char *format, ...) NPF_PRINTF_ATTR(3, 4);
+
+NPF_VISIBILITY int npf_vsnprintf(
+ char *buffer, size_t bufsz, char const *format, va_list vlist) NPF_PRINTF_ATTR(3, 0);
+
+typedef void (*npf_putc)(int c, void *ctx);
+NPF_VISIBILITY int npf_pprintf(
+ npf_putc pc, void *pc_ctx, char const *format, ...) NPF_PRINTF_ATTR(3, 4);
+
+NPF_VISIBILITY int npf_vpprintf(
+ npf_putc pc, void *pc_ctx, char const *format, va_list vlist) NPF_PRINTF_ATTR(3, 0);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // NANOPRINTF_H_INCLUDED
+
+/* The implementation of nanoprintf begins here, to be compiled only if
+ NANOPRINTF_IMPLEMENTATION is defined. In a multi-file library what follows would
+ be nanoprintf.c. */
+
+#ifdef NANOPRINTF_IMPLEMENTATION
+
+#ifndef NANOPRINTF_IMPLEMENTATION_INCLUDED
+#define NANOPRINTF_IMPLEMENTATION_INCLUDED
+
+#include <inttypes.h>
+#include <stdint.h>
+
+// Pick reasonable defaults if nothing's been configured.
+#if !defined(NANOPRINTF_USE_FIELD_WIDTH_FORMAT_SPECIFIERS) && \
+ !defined(NANOPRINTF_USE_PRECISION_FORMAT_SPECIFIERS) && \
+ !defined(NANOPRINTF_USE_FLOAT_FORMAT_SPECIFIERS) && \
+ !defined(NANOPRINTF_USE_LARGE_FORMAT_SPECIFIERS) && \
+ !defined(NANOPRINTF_USE_BINARY_FORMAT_SPECIFIERS) && \
+ !defined(NANOPRINTF_USE_WRITEBACK_FORMAT_SPECIFIERS)
+ #define NANOPRINTF_USE_FIELD_WIDTH_FORMAT_SPECIFIERS 1
+ #define NANOPRINTF_USE_PRECISION_FORMAT_SPECIFIERS 1
+ #define NANOPRINTF_USE_FLOAT_FORMAT_SPECIFIERS 1
+ #define NANOPRINTF_USE_LARGE_FORMAT_SPECIFIERS 0
+ #define NANOPRINTF_USE_BINARY_FORMAT_SPECIFIERS 0
+ #define NANOPRINTF_USE_WRITEBACK_FORMAT_SPECIFIERS 0
+#endif
+
+// If anything's been configured, everything must be configured.
+#ifndef NANOPRINTF_USE_FIELD_WIDTH_FORMAT_SPECIFIERS
+ #error NANOPRINTF_USE_FIELD_WIDTH_FORMAT_SPECIFIERS must be #defined to 0 or 1
+#endif
+#ifndef NANOPRINTF_USE_PRECISION_FORMAT_SPECIFIERS
+ #error NANOPRINTF_USE_PRECISION_FORMAT_SPECIFIERS must be #defined to 0 or 1
+#endif
+#ifndef NANOPRINTF_USE_FLOAT_FORMAT_SPECIFIERS
+ #error NANOPRINTF_USE_FLOAT_FORMAT_SPECIFIERS must be #defined to 0 or 1
+#endif
+#ifndef NANOPRINTF_USE_LARGE_FORMAT_SPECIFIERS
+ #error NANOPRINTF_USE_LARGE_FORMAT_SPECIFIERS must be #defined to 0 or 1
+#endif
+#ifndef NANOPRINTF_USE_BINARY_FORMAT_SPECIFIERS
+ #error NANOPRINTF_USE_BINARY_FORMAT_SPECIFIERS must be #defined to 0 or 1
+#endif
+#ifndef NANOPRINTF_USE_WRITEBACK_FORMAT_SPECIFIERS
+ #error NANOPRINTF_USE_WRITEBACK_FORMAT_SPECIFIERS must be #defined to 0 or 1
+#endif
+
+// Ensure flags are compatible.
+#if (NANOPRINTF_USE_FLOAT_FORMAT_SPECIFIERS == 1) && \
+ (NANOPRINTF_USE_PRECISION_FORMAT_SPECIFIERS == 0)
+ #error Precision format specifiers must be enabled if float support is enabled.
+#endif
+
+#if defined(NANOPRINTF_SNPRINTF_SAFE_EMPTY_STRING_ON_OVERFLOW) && \
+ defined(NANOPRINTF_SNPRINTF_SAFE_TRIM_STRING_ON_OVERFLOW)
+ #error snprintf safety flags are mutually exclusive.
+#endif
+
+// intmax_t / uintmax_t require stdint from c99 / c++11
+#if NANOPRINTF_USE_LARGE_FORMAT_SPECIFIERS == 1
+ #ifndef _MSC_VER
+ #ifdef __cplusplus
+ #if __cplusplus < 201103L
+ #error large format specifier support requires C++11 or later.
+ #endif
+ #else
+ #if __STDC_VERSION__ < 199409L
+ #error nanoprintf requires C99 or later.
+ #endif
+ #endif
+ #endif
+#endif
+
+// Figure out if we can disable warnings with pragmas.
+#ifdef __clang__
+ #define NANOPRINTF_CLANG 1
+ #define NANOPRINTF_GCC_PAST_4_6 0
+#else
+ #define NANOPRINTF_CLANG 0
+ #if defined(__GNUC__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 6)))
+ #define NANOPRINTF_GCC_PAST_4_6 1
+ #else
+ #define NANOPRINTF_GCC_PAST_4_6 0
+ #endif
+#endif
+
+#if NANOPRINTF_CLANG || NANOPRINTF_GCC_PAST_4_6
+ #define NANOPRINTF_HAVE_GCC_WARNING_PRAGMAS 1
+#else
+ #define NANOPRINTF_HAVE_GCC_WARNING_PRAGMAS 0
+#endif
+
+#if NANOPRINTF_HAVE_GCC_WARNING_PRAGMAS
+ #pragma GCC diagnostic push
+ #pragma GCC diagnostic ignored "-Wunused-function"
+ #pragma GCC diagnostic ignored "-Wimplicit-fallthrough"
+ #ifdef __cplusplus
+ #pragma GCC diagnostic ignored "-Wold-style-cast"
+ #endif
+ #pragma GCC diagnostic ignored "-Wpadded"
+ #pragma GCC diagnostic ignored "-Wfloat-equal"
+ #if NANOPRINTF_CLANG
+ #pragma GCC diagnostic ignored "-Wc++98-compat-pedantic"
+ #pragma GCC diagnostic ignored "-Wcovered-switch-default"
+ #pragma GCC diagnostic ignored "-Wdeclaration-after-statement"
+ #elif NANOPRINTF_GCC_PAST_4_6
+ #pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
+ #endif
+#endif
+
+#ifdef _MSC_VER
+ #pragma warning(push)
+ #pragma warning(disable:4514) // unreferenced inline function removed
+ #pragma warning(disable:4505) // unreferenced function removed
+ #pragma warning(disable:4701) // possibly uninitialized
+ #pragma warning(disable:4706) // assignment in conditional
+ #pragma warning(disable:4710) // not inlined
+ #pragma warning(disable:4711) // selected for inline
+ #pragma warning(disable:4820) // padding after data member
+ #pragma warning(disable:5039) // extern "C" throw
+ #pragma warning(disable:5045) // spectre mitigation
+ #pragma warning(disable:5262) // implicit switch fall-through
+#endif
+
+#if (NANOPRINTF_USE_FIELD_WIDTH_FORMAT_SPECIFIERS == 1) || \
+ (NANOPRINTF_USE_PRECISION_FORMAT_SPECIFIERS == 1)
+typedef enum {
+ NPF_FMT_SPEC_OPT_NONE,
+ NPF_FMT_SPEC_OPT_LITERAL,
+ NPF_FMT_SPEC_OPT_STAR,
+} npf_fmt_spec_opt_t;
+#endif
+
+typedef enum {
+ NPF_FMT_SPEC_LEN_MOD_NONE,
+ NPF_FMT_SPEC_LEN_MOD_SHORT, // 'h'
+ NPF_FMT_SPEC_LEN_MOD_LONG_DOUBLE, // 'L'
+ NPF_FMT_SPEC_LEN_MOD_CHAR, // 'hh'
+ NPF_FMT_SPEC_LEN_MOD_LONG, // 'l'
+#if NANOPRINTF_USE_LARGE_FORMAT_SPECIFIERS == 1
+ NPF_FMT_SPEC_LEN_MOD_LARGE_LONG_LONG, // 'll'
+ NPF_FMT_SPEC_LEN_MOD_LARGE_INTMAX, // 'j'
+ NPF_FMT_SPEC_LEN_MOD_LARGE_SIZET, // 'z'
+ NPF_FMT_SPEC_LEN_MOD_LARGE_PTRDIFFT, // 't'
+#endif
+} npf_format_spec_length_modifier_t;
+
+typedef enum {
+ NPF_FMT_SPEC_CONV_PERCENT, // '%'
+ NPF_FMT_SPEC_CONV_CHAR, // 'c'
+ NPF_FMT_SPEC_CONV_STRING, // 's'
+ NPF_FMT_SPEC_CONV_SIGNED_INT, // 'i', 'd'
+#if NANOPRINTF_USE_BINARY_FORMAT_SPECIFIERS == 1
+ NPF_FMT_SPEC_CONV_BINARY, // 'b'
+#endif
+ NPF_FMT_SPEC_CONV_OCTAL, // 'o'
+ NPF_FMT_SPEC_CONV_HEX_INT, // 'x', 'X'
+ NPF_FMT_SPEC_CONV_UNSIGNED_INT, // 'u'
+ NPF_FMT_SPEC_CONV_POINTER, // 'p'
+#if NANOPRINTF_USE_WRITEBACK_FORMAT_SPECIFIERS == 1
+ NPF_FMT_SPEC_CONV_WRITEBACK, // 'n'
+#endif
+#if NANOPRINTF_USE_FLOAT_FORMAT_SPECIFIERS == 1
+ NPF_FMT_SPEC_CONV_FLOAT_DEC, // 'f', 'F'
+ NPF_FMT_SPEC_CONV_FLOAT_SCI, // 'e', 'E'
+ NPF_FMT_SPEC_CONV_FLOAT_SHORTEST, // 'g', 'G'
+ NPF_FMT_SPEC_CONV_FLOAT_HEX, // 'a', 'A'
+#endif
+} npf_format_spec_conversion_t;
+
+typedef struct npf_format_spec {
+ char prepend; // ' ' or '+'
+ char alt_form; // '#'
+
+#if NANOPRINTF_USE_FIELD_WIDTH_FORMAT_SPECIFIERS == 1
+ npf_fmt_spec_opt_t field_width_opt;
+ int field_width;
+ char left_justified; // '-'
+ char leading_zero_pad; // '0'
+#endif
+
+#if NANOPRINTF_USE_PRECISION_FORMAT_SPECIFIERS == 1
+ npf_fmt_spec_opt_t prec_opt;
+ int prec;
+#endif
+
+ npf_format_spec_length_modifier_t length_modifier;
+ npf_format_spec_conversion_t conv_spec;
+ char case_adjust;
+} npf_format_spec_t;
+
+#if NANOPRINTF_USE_LARGE_FORMAT_SPECIFIERS == 0
+ typedef long npf_int_t;
+ typedef unsigned long npf_uint_t;
+#else
+ typedef intmax_t npf_int_t;
+ typedef uintmax_t npf_uint_t;
+#endif
+
+typedef struct npf_bufputc_ctx {
+ char *dst;
+ size_t len;
+ size_t cur;
+} npf_bufputc_ctx_t;
+
+static int npf_parse_format_spec(char const *format, npf_format_spec_t *out_spec);
+static void npf_bufputc(int c, void *ctx);
+static void npf_bufputc_nop(int c, void *ctx);
+static int npf_itoa_rev(char *buf, npf_int_t i);
+static int npf_utoa_rev(char *buf, npf_uint_t i, unsigned base, unsigned case_adjust);
+
+#if NANOPRINTF_USE_FLOAT_FORMAT_SPECIFIERS == 1
+static int npf_fsplit_abs(float f,
+ uint64_t *out_int_part,
+ uint64_t *out_frac_part,
+ int *out_frac_base10_neg_e);
+static int npf_ftoa_rev(char *buf, float f, char case_adj, int *out_frac_chars);
+#endif
+
+#if NANOPRINTF_USE_BINARY_FORMAT_SPECIFIERS == 1
+static int npf_bin_len(npf_uint_t i);
+#endif
+
+#if NANOPRINTF_USE_LARGE_FORMAT_SPECIFIERS == 1
+ #ifdef _MSC_VER
+ #include <BaseTsd.h>
+ typedef SSIZE_T ssize_t;
+ #else
+ #include <sys/types.h>
+ #endif
+#endif
+
+#ifdef _MSC_VER
+ #include <intrin.h>
+#endif
+
+static int npf_max(int x, int y) { return (x > y) ? x : y; }
+
+int npf_parse_format_spec(char const *format, npf_format_spec_t *out_spec) {
+ char const *cur = format;
+
+#if NANOPRINTF_USE_FIELD_WIDTH_FORMAT_SPECIFIERS == 1
+ out_spec->left_justified = 0;
+ out_spec->leading_zero_pad = 0;
+#endif
+ out_spec->case_adjust = 'a'-'A'; // lowercase
+ out_spec->prepend = 0;
+ out_spec->alt_form = 0;
+
+ while (*++cur) { // cur points at the leading '%' character
+ switch (*cur) { // Optional flags
+#if NANOPRINTF_USE_FIELD_WIDTH_FORMAT_SPECIFIERS == 1
+ case '-': out_spec->left_justified = '-'; out_spec->leading_zero_pad = 0; continue;
+ case '0': out_spec->leading_zero_pad = !out_spec->left_justified; continue;
+#endif
+ case '+': out_spec->prepend = '+'; continue;
+ case ' ': if (out_spec->prepend == 0) { out_spec->prepend = ' '; } continue;
+ case '#': out_spec->alt_form = '#'; continue;
+ default: break;
+ }
+ break;
+ }
+
+#if NANOPRINTF_USE_FIELD_WIDTH_FORMAT_SPECIFIERS == 1
+ out_spec->field_width_opt = NPF_FMT_SPEC_OPT_NONE;
+ if (*cur == '*') {
+ out_spec->field_width_opt = NPF_FMT_SPEC_OPT_STAR;
+ ++cur;
+ } else {
+ out_spec->field_width = 0;
+ while ((*cur >= '0') && (*cur <= '9')) {
+ out_spec->field_width_opt = NPF_FMT_SPEC_OPT_LITERAL;
+ out_spec->field_width = (out_spec->field_width * 10) + (*cur++ - '0');
+ }
+ }
+#endif
+
+#if NANOPRINTF_USE_PRECISION_FORMAT_SPECIFIERS == 1
+ out_spec->prec = 0;
+ out_spec->prec_opt = NPF_FMT_SPEC_OPT_NONE;
+ if (*cur == '.') {
+ ++cur;
+ if (*cur == '*') {
+ out_spec->prec_opt = NPF_FMT_SPEC_OPT_STAR;
+ ++cur;
+ } else {
+ if (*cur == '-') {
+ ++cur;
+ out_spec->prec_opt = NPF_FMT_SPEC_OPT_NONE;
+ } else {
+ out_spec->prec_opt = NPF_FMT_SPEC_OPT_LITERAL;
+ }
+ while ((*cur >= '0') && (*cur <= '9')) {
+ out_spec->prec = (out_spec->prec * 10) + (*cur++ - '0');
+ }
+ }
+ }
+#endif
+
+ int tmp_conv = -1;
+ out_spec->length_modifier = NPF_FMT_SPEC_LEN_MOD_NONE;
+ switch (*cur++) { // Length modifier
+ case 'h':
+ out_spec->length_modifier = NPF_FMT_SPEC_LEN_MOD_SHORT;
+ if (*cur == 'h') {
+ out_spec->length_modifier = NPF_FMT_SPEC_LEN_MOD_CHAR;
+ ++cur;
+ }
+ break;
+ case 'l':
+ out_spec->length_modifier = NPF_FMT_SPEC_LEN_MOD_LONG;
+#if NANOPRINTF_USE_LARGE_FORMAT_SPECIFIERS == 1
+ if (*cur == 'l') {
+ out_spec->length_modifier = NPF_FMT_SPEC_LEN_MOD_LARGE_LONG_LONG;
+ ++cur;
+ }
+#endif
+ break;
+#if NANOPRINTF_USE_FLOAT_FORMAT_SPECIFIERS == 1
+ case 'L': out_spec->length_modifier = NPF_FMT_SPEC_LEN_MOD_LONG_DOUBLE; break;
+#endif
+#if NANOPRINTF_USE_LARGE_FORMAT_SPECIFIERS == 1
+ case 'j': out_spec->length_modifier = NPF_FMT_SPEC_LEN_MOD_LARGE_INTMAX; break;
+ case 'z': out_spec->length_modifier = NPF_FMT_SPEC_LEN_MOD_LARGE_SIZET; break;
+ case 't': out_spec->length_modifier = NPF_FMT_SPEC_LEN_MOD_LARGE_PTRDIFFT; break;
+#endif
+ default: --cur; break;
+ }
+
+ switch (*cur++) { // Conversion specifier
+ case '%': out_spec->conv_spec = NPF_FMT_SPEC_CONV_PERCENT;
+#if NANOPRINTF_USE_PRECISION_FORMAT_SPECIFIERS == 1
+ out_spec->prec_opt = NPF_FMT_SPEC_OPT_NONE;
+#endif
+ break;
+
+ case 'c': out_spec->conv_spec = NPF_FMT_SPEC_CONV_CHAR;
+#if NANOPRINTF_USE_PRECISION_FORMAT_SPECIFIERS == 1
+ out_spec->prec_opt = NPF_FMT_SPEC_OPT_NONE;
+#endif
+ break;
+
+ case 's': out_spec->conv_spec = NPF_FMT_SPEC_CONV_STRING;
+#if NANOPRINTF_USE_FIELD_WIDTH_FORMAT_SPECIFIERS == 1
+ out_spec->leading_zero_pad = 0;
+#endif
+ break;
+
+ case 'i':
+ case 'd': tmp_conv = NPF_FMT_SPEC_CONV_SIGNED_INT;
+ case 'o': if (tmp_conv == -1) { tmp_conv = NPF_FMT_SPEC_CONV_OCTAL; }
+ case 'u': if (tmp_conv == -1) { tmp_conv = NPF_FMT_SPEC_CONV_UNSIGNED_INT; }
+ case 'X': if (tmp_conv == -1) { out_spec->case_adjust = 0; }
+ case 'x': if (tmp_conv == -1) { tmp_conv = NPF_FMT_SPEC_CONV_HEX_INT; }
+ out_spec->conv_spec = (npf_format_spec_conversion_t)tmp_conv;
+#if (NANOPRINTF_USE_FIELD_WIDTH_FORMAT_SPECIFIERS == 1) && \
+ (NANOPRINTF_USE_PRECISION_FORMAT_SPECIFIERS == 1)
+ if (out_spec->prec_opt != NPF_FMT_SPEC_OPT_NONE) { out_spec->leading_zero_pad = 0; }
+#endif
+ break;
+
+#if NANOPRINTF_USE_FLOAT_FORMAT_SPECIFIERS == 1
+ case 'F': out_spec->case_adjust = 0;
+ case 'f':
+ out_spec->conv_spec = NPF_FMT_SPEC_CONV_FLOAT_DEC;
+ if (out_spec->prec_opt == NPF_FMT_SPEC_OPT_NONE) { out_spec->prec = 6; }
+ break;
+
+ case 'E': out_spec->case_adjust = 0;
+ case 'e':
+ out_spec->conv_spec = NPF_FMT_SPEC_CONV_FLOAT_SCI;
+ if (out_spec->prec_opt == NPF_FMT_SPEC_OPT_NONE) { out_spec->prec = 6; }
+ break;
+
+ case 'G': out_spec->case_adjust = 0;
+ case 'g':
+ out_spec->conv_spec = NPF_FMT_SPEC_CONV_FLOAT_SHORTEST;
+ if (out_spec->prec_opt == NPF_FMT_SPEC_OPT_NONE) { out_spec->prec = 6; }
+ break;
+
+ case 'A': out_spec->case_adjust = 0;
+ case 'a':
+ out_spec->conv_spec = NPF_FMT_SPEC_CONV_FLOAT_HEX;
+ if (out_spec->prec_opt == NPF_FMT_SPEC_OPT_NONE) { out_spec->prec = 6; }
+ break;
+#endif
+
+#if NANOPRINTF_USE_WRITEBACK_FORMAT_SPECIFIERS == 1
+ case 'n':
+ // todo: reject string if flags or width or precision exist
+ out_spec->conv_spec = NPF_FMT_SPEC_CONV_WRITEBACK;
+#if NANOPRINTF_USE_PRECISION_FORMAT_SPECIFIERS == 1
+ out_spec->prec_opt = NPF_FMT_SPEC_OPT_NONE;
+#endif
+ break;
+#endif
+
+ case 'p':
+ out_spec->conv_spec = NPF_FMT_SPEC_CONV_POINTER;
+#if NANOPRINTF_USE_PRECISION_FORMAT_SPECIFIERS == 1
+ out_spec->prec_opt = NPF_FMT_SPEC_OPT_NONE;
+#endif
+ break;
+
+#if NANOPRINTF_USE_BINARY_FORMAT_SPECIFIERS == 1
+ case 'B':
+ out_spec->case_adjust = 0;
+ case 'b':
+ out_spec->conv_spec = NPF_FMT_SPEC_CONV_BINARY;
+ break;
+#endif
+
+ default: return 0;
+ }
+
+ return (int)(cur - format);
+}
+
+int npf_itoa_rev(char *buf, npf_int_t i) {
+ int n = 0;
+ int const sign = (i >= 0) ? 1 : -1;
+ do { *buf++ = (char)('0' + (sign * (i % 10))); i /= 10; ++n; } while (i);
+ return n;
+}
+
+int npf_utoa_rev(char *buf, npf_uint_t i, unsigned base, unsigned case_adj) {
+ int n = 0;
+ do {
+ unsigned const d = (unsigned)(i % base);
+ *buf++ = (char)((d < 10) ? ('0' + d) : ('A' + case_adj + (d - 10)));
+ i /= base;
+ ++n;
+ } while (i);
+ return n;
+}
+
+#if NANOPRINTF_USE_FLOAT_FORMAT_SPECIFIERS == 1
+enum {
+ NPF_MANTISSA_BITS = 23,
+ NPF_EXPONENT_BITS = 8,
+ NPF_EXPONENT_BIAS = 127,
+ NPF_FRACTION_BIN_DIGITS = 64,
+ NPF_MAX_FRACTION_DEC_DIGITS = 8
+};
+
+int npf_fsplit_abs(float f, uint64_t *out_int_part, uint64_t *out_frac_part,
+ int *out_frac_base10_neg_exp) {
+ /* conversion algorithm by Wojciech Muła (zdjęcia@garnek.pl)
+ http://0x80.pl/notesen/2015-12-29-float-to-string.html
+ grisu2 (https://bit.ly/2JgMggX) and ryu (https://bit.ly/2RLXSg0)
+ are fast + precise + round, but require large lookup tables. */
+
+ uint32_t f_bits; { // union-cast is UB, let compiler optimize byte-copy loop.
+ char const *src = (char const *)&f;
+ char *dst = (char *)&f_bits;
+ for (unsigned i = 0; i < sizeof(f_bits); ++i) { dst[i] = src[i]; }
+ }
+
+ int const exponent =
+ ((int)((f_bits >> NPF_MANTISSA_BITS) & ((1u << NPF_EXPONENT_BITS) - 1u)) -
+ NPF_EXPONENT_BIAS) - NPF_MANTISSA_BITS;
+
+ if (exponent >= (64 - NPF_MANTISSA_BITS)) { return 0; } // value is out of range
+
+ uint32_t const implicit_one = ((uint32_t)1) << NPF_MANTISSA_BITS;
+ uint32_t const mantissa = f_bits & (implicit_one - 1);
+ uint32_t const mantissa_norm = mantissa | implicit_one;
+
+ if (exponent > 0) {
+ *out_int_part = (uint64_t)mantissa_norm << exponent;
+ } else if (exponent < 0) {
+ if (-exponent > NPF_MANTISSA_BITS) {
+ *out_int_part = 0;
+ } else {
+ *out_int_part = mantissa_norm >> -exponent;
+ }
+ } else {
+ *out_int_part = mantissa_norm;
+ }
+
+ uint64_t frac; {
+ int const shift = NPF_FRACTION_BIN_DIGITS + exponent - 4;
+ if ((shift >= (NPF_FRACTION_BIN_DIGITS - 4)) || (shift < 0)) {
+ frac = 0;
+ } else {
+ frac = ((uint64_t)mantissa_norm) << shift;
+ }
+ // multiply off the leading one's digit
+ frac &= 0x0fffffffffffffffllu;
+ frac *= 10;
+ }
+
+ { // Count the number of 0s at the beginning of the fractional part.
+ int frac_base10_neg_exp = 0;
+ while (frac && ((frac >> (NPF_FRACTION_BIN_DIGITS - 4))) == 0) {
+ ++frac_base10_neg_exp;
+ frac &= 0x0fffffffffffffffllu;
+ frac *= 10;
+ }
+ *out_frac_base10_neg_exp = frac_base10_neg_exp;
+ }
+
+ { // Convert the fractional part to base 10.
+ uint64_t frac_part = 0;
+ for (int i = 0; frac && (i < NPF_MAX_FRACTION_DEC_DIGITS); ++i) {
+ frac_part *= 10;
+ frac_part += (uint64_t)(frac >> (NPF_FRACTION_BIN_DIGITS - 4));
+ frac &= 0x0fffffffffffffffllu;
+ frac *= 10;
+ }
+ *out_frac_part = frac_part;
+ }
+ return 1;
+}
+
+int npf_ftoa_rev(char *buf, float f, char case_adj, int *out_frac_chars) {
+ uint32_t f_bits; { // union-cast is UB, let compiler optimize byte-copy loop.
+ char const *src = (char const *)&f;
+ char *dst = (char *)&f_bits;
+ for (unsigned i = 0; i < sizeof(f_bits); ++i) { dst[i] = src[i]; }
+ }
+
+ if ((uint8_t)(f_bits >> 23) == 0xFF) {
+ if (f_bits & 0x7fffff) {
+ for (int i = 0; i < 3; ++i) { *buf++ = (char)("NAN"[i] + case_adj); }
+ } else {
+ for (int i = 0; i < 3; ++i) { *buf++ = (char)("FNI"[i] + case_adj); }
+ }
+ return -3;
+ }
+
+ uint64_t int_part, frac_part;
+ int frac_base10_neg_exp;
+ if (npf_fsplit_abs(f, &int_part, &frac_part, &frac_base10_neg_exp) == 0) {
+ for (int i = 0; i < 3; ++i) { *buf++ = (char)("ROO"[i] + case_adj); }
+ return -3;
+ }
+
+ char *dst = buf;
+
+ while (frac_part) { // write the fractional digits
+ *dst++ = (char)('0' + (frac_part % 10));
+ frac_part /= 10;
+ }
+
+ // write the 0 digits between the . and the first fractional digit
+ while (frac_base10_neg_exp-- > 0) { *dst++ = '0'; }
+ *out_frac_chars = (int)(dst - buf);
+ *dst++ = '.';
+
+ // write the integer digits
+ do { *dst++ = (char)('0' + (int_part % 10)); int_part /= 10; } while (int_part);
+ return (int)(dst - buf);
+}
+
+#endif // NANOPRINTF_USE_FLOAT_FORMAT_SPECIFIERS
+
+#if NANOPRINTF_USE_BINARY_FORMAT_SPECIFIERS == 1
+int npf_bin_len(npf_uint_t u) {
+ // Return the length of the binary string format of 'u', preferring intrinsics.
+ if (!u) { return 1; }
+
+#ifdef _MSC_VER // Win64, use _BSR64 for everything. If x86, use _BSR when non-large.
+ #ifdef _M_X64
+ #define NPF_HAVE_BUILTIN_CLZ
+ #define NPF_CLZ _BitScanReverse64
+ #elif NANOPRINTF_USE_LARGE_FORMAT_SPECIFIERS == 0
+ #define NPF_HAVE_BUILTIN_CLZ
+ #define NPF_CLZ _BitScanReverse
+ #endif
+ #ifdef NPF_HAVE_BUILTIN_CLZ
+ unsigned long idx;
+ NPF_CLZ(&idx, u);
+ return (int)(idx + 1);
+ #endif
+#elif defined(NANOPRINTF_CLANG) || defined(NANOPRINTF_GCC_PAST_4_6)
+ #define NPF_HAVE_BUILTIN_CLZ
+ #if NANOPRINTF_USE_LARGE_FORMAT_SPECIFIERS == 1
+ #define NPF_CLZ(X) ((sizeof(long long) * 8) - (size_t)__builtin_clzll(X))
+ #else
+ #define NPF_CLZ(X) ((sizeof(long) * 8) - (size_t)__builtin_clzl(X))
+ #endif
+ return (int)NPF_CLZ(u);
+#endif
+
+#ifndef NPF_HAVE_BUILTIN_CLZ
+ int n;
+ for (n = 0; u; ++n, u >>= 1); // slow but small software fallback
+ return n;
+#else
+ #undef NPF_HAVE_BUILTIN_CLZ
+ #undef NPF_CLZ
+#endif
+}
+#endif
+
+void npf_bufputc(int c, void *ctx) {
+ npf_bufputc_ctx_t *bpc = (npf_bufputc_ctx_t *)ctx;
+ if (bpc->cur < bpc->len) { bpc->dst[bpc->cur++] = (char)c; }
+}
+
+void npf_bufputc_nop(int c, void *ctx) { (void)c; (void)ctx; }
+
+typedef struct npf_cnt_putc_ctx {
+ npf_putc pc;
+ void *ctx;
+ int n;
+} npf_cnt_putc_ctx_t;
+
+static void npf_putc_cnt(int c, void *ctx) {
+ npf_cnt_putc_ctx_t *pc_cnt = (npf_cnt_putc_ctx_t *)ctx;
+ ++pc_cnt->n;
+ pc_cnt->pc(c, pc_cnt->ctx); // sibling-call optimization
+}
+
+#define NPF_PUTC(VAL) do { npf_putc_cnt((int)(VAL), &pc_cnt); } while (0)
+
+#define NPF_EXTRACT(MOD, CAST_TO, EXTRACT_AS) \
+ case NPF_FMT_SPEC_LEN_MOD_##MOD: val = (CAST_TO)va_arg(args, EXTRACT_AS); break
+
+#define NPF_WRITEBACK(MOD, TYPE) \
+ case NPF_FMT_SPEC_LEN_MOD_##MOD: *(va_arg(args, TYPE *)) = (TYPE)pc_cnt.n; break
+
+int npf_vpprintf(npf_putc pc, void *pc_ctx, char const *format, va_list args) {
+ npf_format_spec_t fs;
+ char const *cur = format;
+ npf_cnt_putc_ctx_t pc_cnt;
+ pc_cnt.pc = pc;
+ pc_cnt.ctx = pc_ctx;
+ pc_cnt.n = 0;
+
+ while (*cur) {
+ int const fs_len = (*cur != '%') ? 0 : npf_parse_format_spec(cur, &fs);
+ if (!fs_len) { NPF_PUTC(*cur++); continue; }
+ cur += fs_len;
+
+ // Extract star-args immediately
+#if NANOPRINTF_USE_FIELD_WIDTH_FORMAT_SPECIFIERS == 1
+ if (fs.field_width_opt == NPF_FMT_SPEC_OPT_STAR) {
+ fs.field_width_opt = NPF_FMT_SPEC_OPT_LITERAL;
+ fs.field_width = va_arg(args, int);
+ if (fs.field_width < 0) {
+ fs.field_width = -fs.field_width;
+ fs.left_justified = 1;
+ }
+ }
+#endif
+#if NANOPRINTF_USE_PRECISION_FORMAT_SPECIFIERS == 1
+ if (fs.prec_opt == NPF_FMT_SPEC_OPT_STAR) {
+ fs.prec_opt = NPF_FMT_SPEC_OPT_NONE;
+ fs.prec = va_arg(args, int);
+ if (fs.prec >= 0) { fs.prec_opt = NPF_FMT_SPEC_OPT_LITERAL; }
+ }
+#endif
+
+ union { char cbuf_mem[32]; npf_uint_t binval; } u;
+ char *cbuf = u.cbuf_mem, sign_c = 0;
+ int cbuf_len = 0, need_0x = 0;
+#if NANOPRINTF_USE_FIELD_WIDTH_FORMAT_SPECIFIERS == 1
+ int field_pad = 0;
+ char pad_c = 0;
+#endif
+#if NANOPRINTF_USE_PRECISION_FORMAT_SPECIFIERS == 1
+ int prec_pad = 0;
+#if NANOPRINTF_USE_FIELD_WIDTH_FORMAT_SPECIFIERS == 1
+ int zero = 0;
+#endif
+#endif
+#if NANOPRINTF_USE_FLOAT_FORMAT_SPECIFIERS == 1
+ int frac_chars = 0, inf_or_nan = 0;
+#endif
+
+ // Extract and convert the argument to string, point cbuf at the text.
+ switch (fs.conv_spec) {
+ case NPF_FMT_SPEC_CONV_PERCENT:
+ *cbuf = '%';
+ cbuf_len = 1;
+ break;
+
+ case NPF_FMT_SPEC_CONV_CHAR:
+ *cbuf = (char)va_arg(args, int);
+ cbuf_len = 1;
+ break;
+
+ case NPF_FMT_SPEC_CONV_STRING: {
+ cbuf = va_arg(args, char *);
+#if NANOPRINTF_USE_PRECISION_FORMAT_SPECIFIERS == 1
+ for (char const *s = cbuf;
+ *s && ((fs.prec_opt == NPF_FMT_SPEC_OPT_NONE) || (cbuf_len < fs.prec));
+ ++s, ++cbuf_len);
+#else
+ for (char const *s = cbuf; *s; ++s, ++cbuf_len); // strlen
+#endif
+ } break;
+
+ case NPF_FMT_SPEC_CONV_SIGNED_INT: {
+ npf_int_t val = 0;
+ switch (fs.length_modifier) {
+ NPF_EXTRACT(NONE, int, int);
+ NPF_EXTRACT(SHORT, short, int);
+ NPF_EXTRACT(LONG_DOUBLE, int, int);
+ NPF_EXTRACT(CHAR, char, int);
+ NPF_EXTRACT(LONG, long, long);
+#if NANOPRINTF_USE_LARGE_FORMAT_SPECIFIERS == 1
+ NPF_EXTRACT(LARGE_LONG_LONG, long long, long long);
+ NPF_EXTRACT(LARGE_INTMAX, intmax_t, intmax_t);
+ NPF_EXTRACT(LARGE_SIZET, ssize_t, ssize_t);
+ NPF_EXTRACT(LARGE_PTRDIFFT, ptrdiff_t, ptrdiff_t);
+#endif
+ default: break;
+ }
+
+ sign_c = (val < 0) ? '-' : fs.prepend;
+
+#if NANOPRINTF_USE_PRECISION_FORMAT_SPECIFIERS == 1
+#if NANOPRINTF_USE_FIELD_WIDTH_FORMAT_SPECIFIERS == 1
+ zero = !val;
+#endif
+ // special case, if prec and value are 0, skip
+ if (!val && (fs.prec_opt == NPF_FMT_SPEC_OPT_LITERAL) && !fs.prec) {
+ cbuf_len = 0;
+ } else
+#endif
+ { cbuf_len = npf_itoa_rev(cbuf, val); }
+ } break;
+
+#if NANOPRINTF_USE_BINARY_FORMAT_SPECIFIERS == 1
+ case NPF_FMT_SPEC_CONV_BINARY:
+#endif
+ case NPF_FMT_SPEC_CONV_OCTAL:
+ case NPF_FMT_SPEC_CONV_HEX_INT:
+ case NPF_FMT_SPEC_CONV_UNSIGNED_INT: {
+ npf_uint_t val = 0;
+
+ switch (fs.length_modifier) {
+ NPF_EXTRACT(NONE, unsigned, unsigned);
+ NPF_EXTRACT(SHORT, unsigned short, unsigned);
+ NPF_EXTRACT(LONG_DOUBLE, unsigned, unsigned);
+ NPF_EXTRACT(CHAR, unsigned char, unsigned);
+ NPF_EXTRACT(LONG, unsigned long, unsigned long);
+#if NANOPRINTF_USE_LARGE_FORMAT_SPECIFIERS == 1
+ NPF_EXTRACT(LARGE_LONG_LONG, unsigned long long, unsigned long long);
+ NPF_EXTRACT(LARGE_INTMAX, uintmax_t, uintmax_t);
+ NPF_EXTRACT(LARGE_SIZET, size_t, size_t);
+ NPF_EXTRACT(LARGE_PTRDIFFT, size_t, size_t);
+#endif
+ default: break;
+ }
+
+#if NANOPRINTF_USE_PRECISION_FORMAT_SPECIFIERS == 1
+#if NANOPRINTF_USE_FIELD_WIDTH_FORMAT_SPECIFIERS == 1
+ zero = !val;
+#endif
+ if (!val && (fs.prec_opt == NPF_FMT_SPEC_OPT_LITERAL) && !fs.prec) {
+ // Zero value and explicitly-requested zero precision means "print nothing".
+ if ((fs.conv_spec == NPF_FMT_SPEC_CONV_OCTAL) && fs.alt_form) {
+ fs.prec = 1; // octal special case, print a single '0'
+ }
+ } else
+#endif
+#if NANOPRINTF_USE_BINARY_FORMAT_SPECIFIERS == 1
+ if (fs.conv_spec == NPF_FMT_SPEC_CONV_BINARY) {
+ cbuf_len = npf_bin_len(val); u.binval = val;
+ } else
+#endif
+ {
+ unsigned const base = (fs.conv_spec == NPF_FMT_SPEC_CONV_OCTAL) ?
+ 8u : ((fs.conv_spec == NPF_FMT_SPEC_CONV_HEX_INT) ? 16u : 10u);
+ cbuf_len = npf_utoa_rev(cbuf, val, base, (unsigned)fs.case_adjust);
+ }
+
+ if (val && fs.alt_form && (fs.conv_spec == NPF_FMT_SPEC_CONV_OCTAL)) {
+ cbuf[cbuf_len++] = '0'; // OK to add leading octal '0' immediately.
+ }
+
+ if (val && fs.alt_form) { // 0x or 0b but can't write it yet.
+ if (fs.conv_spec == NPF_FMT_SPEC_CONV_HEX_INT) { need_0x = 'X'; }
+#if NANOPRINTF_USE_BINARY_FORMAT_SPECIFIERS == 1
+ else if (fs.conv_spec == NPF_FMT_SPEC_CONV_BINARY) { need_0x = 'B'; }
+#endif
+ if (need_0x) { need_0x += fs.case_adjust; }
+ }
+ } break;
+
+ case NPF_FMT_SPEC_CONV_POINTER: {
+ cbuf_len =
+ npf_utoa_rev(cbuf, (npf_uint_t)(uintptr_t)va_arg(args, void *), 16, 'a'-'A');
+ need_0x = 'x';
+ } break;
+
+#if NANOPRINTF_USE_WRITEBACK_FORMAT_SPECIFIERS == 1
+ case NPF_FMT_SPEC_CONV_WRITEBACK:
+ switch (fs.length_modifier) {
+ NPF_WRITEBACK(NONE, int);
+ NPF_WRITEBACK(SHORT, short);
+ NPF_WRITEBACK(LONG, long);
+ NPF_WRITEBACK(LONG_DOUBLE, double);
+ NPF_WRITEBACK(CHAR, signed char);
+#if NANOPRINTF_USE_LARGE_FORMAT_SPECIFIERS == 1
+ NPF_WRITEBACK(LARGE_LONG_LONG, long long);
+ NPF_WRITEBACK(LARGE_INTMAX, intmax_t);
+ NPF_WRITEBACK(LARGE_SIZET, size_t);
+ NPF_WRITEBACK(LARGE_PTRDIFFT, ptrdiff_t);
+#endif
+ default: break;
+ } break;
+#endif
+
+#if NANOPRINTF_USE_FLOAT_FORMAT_SPECIFIERS == 1
+ case NPF_FMT_SPEC_CONV_FLOAT_DEC:
+ case NPF_FMT_SPEC_CONV_FLOAT_SCI:
+ case NPF_FMT_SPEC_CONV_FLOAT_SHORTEST:
+ case NPF_FMT_SPEC_CONV_FLOAT_HEX: {
+ float val;
+ if (fs.length_modifier == NPF_FMT_SPEC_LEN_MOD_LONG_DOUBLE) {
+ val = (float)va_arg(args, long double);
+ } else {
+ val = (float)va_arg(args, double);
+ }
+
+ sign_c = (val < 0.f) ? '-' : fs.prepend;
+#if NANOPRINTF_USE_FIELD_WIDTH_FORMAT_SPECIFIERS == 1
+ zero = (val == 0.f);
+#endif
+ cbuf_len = npf_ftoa_rev(cbuf, val, fs.case_adjust, &frac_chars);
+
+ if (cbuf_len < 0) {
+ cbuf_len = -cbuf_len;
+ inf_or_nan = 1;
+ } else {
+ int const prec_adj = npf_max(0, frac_chars - fs.prec);
+ cbuf += prec_adj;
+ cbuf_len -= prec_adj;
+ }
+ } break;
+#endif
+ default: break;
+ }
+
+#if NANOPRINTF_USE_FIELD_WIDTH_FORMAT_SPECIFIERS == 1
+ // Compute the field width pad character
+ if (fs.field_width_opt == NPF_FMT_SPEC_OPT_LITERAL) {
+ if (fs.leading_zero_pad) { // '0' flag is only legal with numeric types
+ if ((fs.conv_spec != NPF_FMT_SPEC_CONV_STRING) &&
+ (fs.conv_spec != NPF_FMT_SPEC_CONV_CHAR) &&
+ (fs.conv_spec != NPF_FMT_SPEC_CONV_PERCENT)) {
+#if NANOPRINTF_USE_PRECISION_FORMAT_SPECIFIERS == 1
+ if ((fs.prec_opt == NPF_FMT_SPEC_OPT_LITERAL) && !fs.prec && zero) {
+ pad_c = ' ';
+ } else
+#endif
+ { pad_c = '0'; }
+ }
+ } else { pad_c = ' '; }
+ }
+#endif
+
+ // Compute the number of bytes to truncate or '0'-pad.
+ if (fs.conv_spec != NPF_FMT_SPEC_CONV_STRING) {
+#if NANOPRINTF_USE_FLOAT_FORMAT_SPECIFIERS == 1
+ if (!inf_or_nan) { // float precision is after the decimal point
+ int const prec_start =
+ (fs.conv_spec == NPF_FMT_SPEC_CONV_FLOAT_DEC) ? frac_chars : cbuf_len;
+ prec_pad = npf_max(0, fs.prec - prec_start);
+ }
+#elif NANOPRINTF_USE_PRECISION_FORMAT_SPECIFIERS == 1
+ prec_pad = npf_max(0, fs.prec - cbuf_len);
+#endif
+ }
+
+#if NANOPRINTF_USE_FIELD_WIDTH_FORMAT_SPECIFIERS == 1
+ // Given the full converted length, how many pad bytes?
+ field_pad = fs.field_width - cbuf_len - !!sign_c;
+ if (need_0x) { field_pad -= 2; }
+
+#if NANOPRINTF_USE_FLOAT_FORMAT_SPECIFIERS == 1
+ if ((fs.conv_spec == NPF_FMT_SPEC_CONV_FLOAT_DEC) && !fs.prec && !fs.alt_form) {
+ ++field_pad; // 0-pad, no decimal point.
+ }
+#endif
+#if NANOPRINTF_USE_PRECISION_FORMAT_SPECIFIERS == 1
+ field_pad -= prec_pad;
+#endif
+ field_pad = npf_max(0, field_pad);
+#endif // NANOPRINTF_USE_FIELD_WIDTH_FORMAT_SPECIFIERS
+
+#if NANOPRINTF_USE_FIELD_WIDTH_FORMAT_SPECIFIERS == 1
+ // Apply right-justified field width if requested
+ if (!fs.left_justified && pad_c) { // If leading zeros pad, sign goes first.
+ if (pad_c == '0') {
+ if (sign_c) { NPF_PUTC(sign_c); sign_c = 0; }
+ // Pad byte is '0', write '0x' before '0' pad chars.
+ if (need_0x) { NPF_PUTC('0'); NPF_PUTC(need_0x); }
+ }
+ while (field_pad-- > 0) { NPF_PUTC(pad_c); }
+ // Pad byte is ' ', write '0x' after ' ' pad chars but before number.
+ if ((pad_c != '0') && need_0x) { NPF_PUTC('0'); NPF_PUTC(need_0x); }
+ } else
+#endif
+ { if (need_0x) { NPF_PUTC('0'); NPF_PUTC(need_0x); } } // no pad, '0x' requested.
+
+ // Write the converted payload
+ if (fs.conv_spec == NPF_FMT_SPEC_CONV_STRING) {
+ for (int i = 0; i < cbuf_len; ++i) { NPF_PUTC(cbuf[i]); }
+ } else {
+ if (sign_c) { NPF_PUTC(sign_c); }
+#if NANOPRINTF_USE_FLOAT_FORMAT_SPECIFIERS == 1
+ if (fs.conv_spec != NPF_FMT_SPEC_CONV_FLOAT_DEC) {
+#endif
+
+#if NANOPRINTF_USE_PRECISION_FORMAT_SPECIFIERS == 1
+ while (prec_pad-- > 0) { NPF_PUTC('0'); } // int precision leads.
+#endif
+
+#if NANOPRINTF_USE_FLOAT_FORMAT_SPECIFIERS == 1
+ } else {
+ // if 0 precision, skip the fractional part and '.'
+ // if 0 prec + alternative form, keep the '.'
+ if (!fs.prec && !fs.alt_form) { ++cbuf; --cbuf_len; }
+ }
+#endif
+
+#if NANOPRINTF_USE_BINARY_FORMAT_SPECIFIERS == 1
+ if (fs.conv_spec == NPF_FMT_SPEC_CONV_BINARY) {
+ while (cbuf_len) { NPF_PUTC('0' + ((u.binval >> --cbuf_len) & 1)); }
+ } else
+#endif
+ { while (cbuf_len-- > 0) { NPF_PUTC(cbuf[cbuf_len]); } } // payload is reversed
+
+#if NANOPRINTF_USE_FLOAT_FORMAT_SPECIFIERS == 1
+ // real precision comes after the number.
+ if ((fs.conv_spec == NPF_FMT_SPEC_CONV_FLOAT_DEC) && !inf_or_nan) {
+ while (prec_pad-- > 0) { NPF_PUTC('0'); }
+ }
+#endif
+ }
+
+#if NANOPRINTF_USE_FIELD_WIDTH_FORMAT_SPECIFIERS == 1
+ if (fs.left_justified && pad_c) { // Apply left-justified field width
+ while (field_pad-- > 0) { NPF_PUTC(pad_c); }
+ }
+#endif
+ }
+
+ return pc_cnt.n;
+}
+
+#undef NPF_PUTC
+#undef NPF_EXTRACT
+#undef NPF_WRITEBACK
+
+int npf_pprintf(npf_putc pc, void *pc_ctx, char const *format, ...) {
+ va_list val;
+ va_start(val, format);
+ int const rv = npf_vpprintf(pc, pc_ctx, format, val);
+ va_end(val);
+ return rv;
+}
+
+int npf_snprintf(char *buffer, size_t bufsz, const char *format, ...) {
+ va_list val;
+ va_start(val, format);
+ int const rv = npf_vsnprintf(buffer, bufsz, format, val);
+ va_end(val);
+ return rv;
+}
+
+int npf_vsnprintf(char *buffer, size_t bufsz, char const *format, va_list vlist) {
+ npf_bufputc_ctx_t bufputc_ctx;
+ bufputc_ctx.dst = buffer;
+ bufputc_ctx.len = bufsz;
+ bufputc_ctx.cur = 0;
+
+ npf_putc const pc = buffer ? npf_bufputc : npf_bufputc_nop;
+ int const n = npf_vpprintf(pc, &bufputc_ctx, format, vlist);
+ pc('\0', &bufputc_ctx);
+
+#ifdef NANOPRINTF_SNPRINTF_SAFE_EMPTY_STRING_ON_OVERFLOW
+ if (bufsz && (n >= (int)bufsz)) { buffer[0] = '\0'; }
+#elif defined(NANOPRINTF_SNPRINTF_SAFE_TRIM_STRING_ON_OVERFLOW)
+ if (bufsz && (n >= (int)bufsz)) { buffer[bufsz - 1] = '\0'; }
+#endif
+
+ return n;
+}
+
+#if NANOPRINTF_HAVE_GCC_WARNING_PRAGMAS
+ #pragma GCC diagnostic pop
+#endif
+
+#ifdef _MSC_VER
+ #pragma warning(pop)
+#endif
+
+#endif // NANOPRINTF_IMPLEMENTATION_INCLUDED
+#endif // NANOPRINTF_IMPLEMENTATION
+
+/*
+ nanoprintf is dual-licensed under both the "Unlicense" and the
+ "Zero-Clause BSD" (0BSD) licenses. The intent of this dual-licensing
+ structure is to make nanoprintf as consumable as possible in as many
+ environments / countries / companies as possible without any
+ encumberances.
+
+ The text of the two licenses follows below:
+
+ ============================== UNLICENSE ==============================
+
+ This is free and unencumbered software released into the public domain.
+
+ Anyone is free to copy, modify, publish, use, compile, sell, or
+ distribute this software, either in source code form or as a compiled
+ binary, for any purpose, commercial or non-commercial, and by any
+ means.
+
+ In jurisdictions that recognize copyright laws, the author or authors
+ of this software dedicate any and all copyright interest in the
+ software to the public domain. We make this dedication for the benefit
+ of the public at large and to the detriment of our heirs and
+ successors. We intend this dedication to be an overt act of
+ relinquishment in perpetuity of all present and future rights to this
+ software under copyright law.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ OTHER DEALINGS IN THE SOFTWARE.
+
+ For more information, please refer to <http://unlicense.org>
+
+ ================================ 0BSD =================================
+
+ Copyright (C) 2019- by Charles Nicholson <charles.nicholson+nanoprintf@gmail.com>
+
+ Permission to use, copy, modify, and/or distribute this software for
+ any purpose with or without fee is hereby granted.
+
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+*/
+
diff --git a/CRT/ntdll_zw_functions.c b/CRT/ntdll_zw_functions.c
new file mode 100644
index 0000000..312440c
--- /dev/null
+++ b/CRT/ntdll_zw_functions.c
@@ -0,0 +1,409 @@
+/* This file was auto generated by gen_wrapper.sh */
+#include <ntddk.h>
+
+#ifdef __cplusplus
+#define _KERNEL_MODE 1
+#include "obfuscate.hpp"
+
+extern "C" {
+#endif
+
+typedef PVOID NTAPI (*MmMapIoSpaceEx_t) (_In_ PHYSICAL_ADDRESS PhysicalAddress, _In_ SIZE_T NumberOfBytes, _In_ ULONG Protect);
+typedef NTSTATUS NTAPI (*ObOpenObjectByPointer_t) (_In_ PVOID obj, _In_ ULONG HandleAttributes, _In_ PACCESS_STATE PassedAccessState, _In_ ACCESS_MASK DesiredAccess, _In_ POBJECT_TYPE objType, _In_ KPROCESSOR_MODE AccessMode, _Out_ PHANDLE Handle);
+typedef NTSTATUS NTAPI (*MmCopyMemory_t) (_In_ PVOID TargetAddress, _In_ PVOID SourceAddress, _In_ SIZE_T NumberOfBytes, _In_ ULONG Flags, _Out_ PSIZE_T NumberOfBytesTransferred);
+typedef NTSTATUS NTAPI (*MmCopyVirtualMemory_t) (_In_ PEPROCESS SourceProcess, _In_ PVOID SourceAddress, _In_ PEPROCESS TargetProcess, _In_ PVOID TargetAddress, _In_ SIZE_T BufferSize, _In_ KPROCESSOR_MODE PreviousMode, _Out_ PSIZE_T ReturnSize);
+typedef PVOID NTAPI (*RtlLookupFunctionEntry_t) (_In_ DWORD64 ControlPc, _Out_ PDWORD64 ImageBase, _Out_ PVOID HistoryTable);
+typedef NTSTATUS NTAPI (*ZwTraceControl_t) (_In_ ULONG FunctionCode, PVOID InBuffer, _In_ ULONG InBufferLen, PVOID OutBuffer, _In_ ULONG OutBufferLen, _Out_ PULONG ReturnLength);
+typedef NTSTATUS NTAPI (*ZwTraceEvent_t) (_In_ HANDLE TraceHandle, _In_ ULONG Flags, _In_ ULONG FieldSize, _In_ PVOID Fields);
+typedef NTSTATUS NTAPI (*ZwQueryVirtualMemory_t) (_In_ HANDLE ProcessHandle, _In_ PVOID BaseAddress, _In_ int MemoryInformationClass, _Out_ PVOID MemoryInformation, _In_ SIZE_T MemoryInformationLength, _Out_ PSIZE_T ReturnLength);
+typedef NTSTATUS NTAPI (*ZwProtectVirtualMemory_t) (_In_ HANDLE ProcessHandle, _In_ _Out_ PVOID* BaseAddress, _In_ _Out_ PSIZE_T NumberOfBytesToProtect, _In_ ULONG NewAccessProtection, _Out_ PULONG OldAccessProtection);
+typedef NTSTATUS NTAPI (*ZwQuerySystemInformation_t) (_In_ int SystemInformationClass, _Inout_ PVOID SystemInformation, _In_ ULONG SystemInformationLength, _Out_opt_ PULONG ReturnLength);
+typedef NTSTATUS NTAPI (*_ZwCreateFile_t) (_Out_ PHANDLE FileHandle, _In_ ACCESS_MASK DesiredAccess, _In_ POBJECT_ATTRIBUTES ObjectAttributes, _Out_ PIO_STATUS_BLOCK StatusBlock, _In_ PLARGE_INTEGER AllocationSize, _In_ ULONG FileAttributes, _In_ ULONG ShareAccess, _In_ ULONG CreateDisposition, _In_ ULONG CreateOptions, _In_ PVOID EaBuffer, _In_ ULONG EaLength);
+typedef NTSTATUS NTAPI (*_ZwClose_t) (_In_ HANDLE Handle);
+typedef NTSTATUS NTAPI (*_ZwWriteFile_t) (_In_ HANDLE FileHandle, _In_ HANDLE Event, _In_ PIO_APC_ROUTINE ApcRoutine, _In_ PVOID ApcContext, _Out_ PIO_STATUS_BLOCK StatusBlock, _In_ PVOID Buffer, _In_ ULONG Length, _In_ PLARGE_INTEGER ByteOffset, _In_ PULONG Key);
+
+static MmMapIoSpaceEx_t _MmMapIoSpaceEx = NULL;
+static ObOpenObjectByPointer_t _ObOpenObjectByPointer = NULL;
+static MmCopyMemory_t _MmCopyMemory = NULL;
+static MmCopyVirtualMemory_t _MmCopyVirtualMemory = NULL;
+static RtlLookupFunctionEntry_t _RtlLookupFunctionEntry = NULL;
+static ZwTraceControl_t _ZwTraceControl = NULL;
+static ZwTraceEvent_t _ZwTraceEvent = NULL;
+static ZwQueryVirtualMemory_t _ZwQueryVirtualMemory = NULL;
+static ZwProtectVirtualMemory_t _ZwProtectVirtualMemory = NULL;
+static ZwQuerySystemInformation_t _ZwQuerySystemInformation = NULL;
+static _ZwCreateFile_t __ZwCreateFile = NULL;
+static _ZwClose_t __ZwClose = NULL;
+static _ZwWriteFile_t __ZwWriteFile = NULL;
+
+int __cdecl ntdll_zw_functions (void)
+{
+ int retval = 0;
+ UNICODE_STRING fnName;
+
+#ifdef __cplusplus
+ RtlInitUnicodeString(&fnName, skCrypt(L"MmMapIoSpaceEx"));
+#else
+ RtlInitUnicodeString(&fnName, L"MmMapIoSpaceEx");
+#endif
+ _MmMapIoSpaceEx = (MmMapIoSpaceEx_t)MmGetSystemRoutineAddress(&fnName);
+ if (_MmMapIoSpaceEx == NULL)
+ {
+#ifdef __cplusplus
+ DbgPrint(skCrypt("%s\n"), skCrypt("System routine MmMapIoSpaceEx not found."));
+#else
+ DbgPrint("%s\n", "System routine MmMapIoSpaceEx not found.");
+#endif
+ retval++;
+ }
+#ifdef __cplusplus
+ RtlInitUnicodeString(&fnName, skCrypt(L"ObOpenObjectByPointer"));
+#else
+ RtlInitUnicodeString(&fnName, L"ObOpenObjectByPointer");
+#endif
+ _ObOpenObjectByPointer = (ObOpenObjectByPointer_t)MmGetSystemRoutineAddress(&fnName);
+ if (_ObOpenObjectByPointer == NULL)
+ {
+#ifdef __cplusplus
+ DbgPrint(skCrypt("%s\n"), skCrypt("System routine ObOpenObjectByPointer not found."));
+#else
+ DbgPrint("%s\n", "System routine ObOpenObjectByPointer not found.");
+#endif
+ retval++;
+ }
+#ifdef __cplusplus
+ RtlInitUnicodeString(&fnName, skCrypt(L"MmCopyMemory"));
+#else
+ RtlInitUnicodeString(&fnName, L"MmCopyMemory");
+#endif
+ _MmCopyMemory = (MmCopyMemory_t)MmGetSystemRoutineAddress(&fnName);
+ if (_MmCopyMemory == NULL)
+ {
+#ifdef __cplusplus
+ DbgPrint(skCrypt("%s\n"), skCrypt("System routine MmCopyMemory not found."));
+#else
+ DbgPrint("%s\n", "System routine MmCopyMemory not found.");
+#endif
+ retval++;
+ }
+#ifdef __cplusplus
+ RtlInitUnicodeString(&fnName, skCrypt(L"MmCopyVirtualMemory"));
+#else
+ RtlInitUnicodeString(&fnName, L"MmCopyVirtualMemory");
+#endif
+ _MmCopyVirtualMemory = (MmCopyVirtualMemory_t)MmGetSystemRoutineAddress(&fnName);
+ if (_MmCopyVirtualMemory == NULL)
+ {
+#ifdef __cplusplus
+ DbgPrint(skCrypt("%s\n"), skCrypt("System routine MmCopyVirtualMemory not found."));
+#else
+ DbgPrint("%s\n", "System routine MmCopyVirtualMemory not found.");
+#endif
+ retval++;
+ }
+#ifdef __cplusplus
+ RtlInitUnicodeString(&fnName, skCrypt(L"RtlLookupFunctionEntry"));
+#else
+ RtlInitUnicodeString(&fnName, L"RtlLookupFunctionEntry");
+#endif
+ _RtlLookupFunctionEntry = (RtlLookupFunctionEntry_t)MmGetSystemRoutineAddress(&fnName);
+ if (_RtlLookupFunctionEntry == NULL)
+ {
+#ifdef __cplusplus
+ DbgPrint(skCrypt("%s\n"), skCrypt("System routine RtlLookupFunctionEntry not found."));
+#else
+ DbgPrint("%s\n", "System routine RtlLookupFunctionEntry not found.");
+#endif
+ retval++;
+ }
+#ifdef __cplusplus
+ RtlInitUnicodeString(&fnName, skCrypt(L"ZwTraceControl"));
+#else
+ RtlInitUnicodeString(&fnName, L"ZwTraceControl");
+#endif
+ _ZwTraceControl = (ZwTraceControl_t)MmGetSystemRoutineAddress(&fnName);
+ if (_ZwTraceControl == NULL)
+ {
+#ifdef __cplusplus
+ DbgPrint(skCrypt("%s\n"), skCrypt("System routine ZwTraceControl not found."));
+#else
+ DbgPrint("%s\n", "System routine ZwTraceControl not found.");
+#endif
+ retval++;
+ }
+#ifdef __cplusplus
+ RtlInitUnicodeString(&fnName, skCrypt(L"ZwTraceEvent"));
+#else
+ RtlInitUnicodeString(&fnName, L"ZwTraceEvent");
+#endif
+ _ZwTraceEvent = (ZwTraceEvent_t)MmGetSystemRoutineAddress(&fnName);
+ if (_ZwTraceEvent == NULL)
+ {
+#ifdef __cplusplus
+ DbgPrint(skCrypt("%s\n"), skCrypt("System routine ZwTraceEvent not found."));
+#else
+ DbgPrint("%s\n", "System routine ZwTraceEvent not found.");
+#endif
+ retval++;
+ }
+#ifdef __cplusplus
+ RtlInitUnicodeString(&fnName, skCrypt(L"ZwQueryVirtualMemory"));
+#else
+ RtlInitUnicodeString(&fnName, L"ZwQueryVirtualMemory");
+#endif
+ _ZwQueryVirtualMemory = (ZwQueryVirtualMemory_t)MmGetSystemRoutineAddress(&fnName);
+ if (_ZwQueryVirtualMemory == NULL)
+ {
+#ifdef __cplusplus
+ DbgPrint(skCrypt("%s\n"), skCrypt("System routine ZwQueryVirtualMemory not found."));
+#else
+ DbgPrint("%s\n", "System routine ZwQueryVirtualMemory not found.");
+#endif
+ retval++;
+ }
+#ifdef __cplusplus
+ RtlInitUnicodeString(&fnName, skCrypt(L"ZwProtectVirtualMemory"));
+#else
+ RtlInitUnicodeString(&fnName, L"ZwProtectVirtualMemory");
+#endif
+ _ZwProtectVirtualMemory = (ZwProtectVirtualMemory_t)MmGetSystemRoutineAddress(&fnName);
+ if (_ZwProtectVirtualMemory == NULL)
+ {
+#ifdef __cplusplus
+ DbgPrint(skCrypt("%s\n"), skCrypt("System routine ZwProtectVirtualMemory not found."));
+#else
+ DbgPrint("%s\n", "System routine ZwProtectVirtualMemory not found.");
+#endif
+ retval++;
+ }
+#ifdef __cplusplus
+ RtlInitUnicodeString(&fnName, skCrypt(L"ZwQuerySystemInformation"));
+#else
+ RtlInitUnicodeString(&fnName, L"ZwQuerySystemInformation");
+#endif
+ _ZwQuerySystemInformation = (ZwQuerySystemInformation_t)MmGetSystemRoutineAddress(&fnName);
+ if (_ZwQuerySystemInformation == NULL)
+ {
+#ifdef __cplusplus
+ DbgPrint(skCrypt("%s\n"), skCrypt("System routine ZwQuerySystemInformation not found."));
+#else
+ DbgPrint("%s\n", "System routine ZwQuerySystemInformation not found.");
+#endif
+ retval++;
+ }
+#ifdef __cplusplus
+ RtlInitUnicodeString(&fnName, skCrypt(L"ZwCreateFile"));
+#else
+ RtlInitUnicodeString(&fnName, L"ZwCreateFile");
+#endif
+ __ZwCreateFile = (_ZwCreateFile_t)MmGetSystemRoutineAddress(&fnName);
+ if (__ZwCreateFile == NULL)
+ {
+#ifdef __cplusplus
+ DbgPrint(skCrypt("%s\n"), skCrypt("System routine ZwCreateFile not found."));
+#else
+ DbgPrint("%s\n", "System routine ZwCreateFile not found.");
+#endif
+ retval++;
+ }
+#ifdef __cplusplus
+ RtlInitUnicodeString(&fnName, skCrypt(L"ZwClose"));
+#else
+ RtlInitUnicodeString(&fnName, L"ZwClose");
+#endif
+ __ZwClose = (_ZwClose_t)MmGetSystemRoutineAddress(&fnName);
+ if (__ZwClose == NULL)
+ {
+#ifdef __cplusplus
+ DbgPrint(skCrypt("%s\n"), skCrypt("System routine ZwClose not found."));
+#else
+ DbgPrint("%s\n", "System routine ZwClose not found.");
+#endif
+ retval++;
+ }
+#ifdef __cplusplus
+ RtlInitUnicodeString(&fnName, skCrypt(L"ZwWriteFile"));
+#else
+ RtlInitUnicodeString(&fnName, L"ZwWriteFile");
+#endif
+ __ZwWriteFile = (_ZwWriteFile_t)MmGetSystemRoutineAddress(&fnName);
+ if (__ZwWriteFile == NULL)
+ {
+#ifdef __cplusplus
+ DbgPrint(skCrypt("%s\n"), skCrypt("System routine ZwWriteFile not found."));
+#else
+ DbgPrint("%s\n", "System routine ZwWriteFile not found.");
+#endif
+ retval++;
+ }
+
+ return retval;
+}
+
+
+PVOID NTAPI MmMapIoSpaceEx (_In_ PHYSICAL_ADDRESS PhysicalAddress, _In_ SIZE_T NumberOfBytes, _In_ ULONG Protect)
+{
+ return _MmMapIoSpaceEx (PhysicalAddress, NumberOfBytes, Protect);
+}
+
+PVOID NTAPI WrapperMmMapIoSpaceEx (_In_ PHYSICAL_ADDRESS PhysicalAddress, _In_ SIZE_T NumberOfBytes, _In_ ULONG Protect)
+{
+ return _MmMapIoSpaceEx (PhysicalAddress, NumberOfBytes, Protect);
+}
+
+NTSTATUS NTAPI ObOpenObjectByPointer (_In_ PVOID obj, _In_ ULONG HandleAttributes, _In_ PACCESS_STATE PassedAccessState, _In_ ACCESS_MASK DesiredAccess, _In_ POBJECT_TYPE objType, _In_ KPROCESSOR_MODE AccessMode, _Out_ PHANDLE Handle)
+{
+ if (_ObOpenObjectByPointer == NULL)
+ return STATUS_PROCEDURE_NOT_FOUND;
+
+ return _ObOpenObjectByPointer (obj, HandleAttributes, PassedAccessState, DesiredAccess, objType, AccessMode, Handle);
+}
+
+NTSTATUS NTAPI WrapperObOpenObjectByPointer (_In_ PVOID obj, _In_ ULONG HandleAttributes, _In_ PACCESS_STATE PassedAccessState, _In_ ACCESS_MASK DesiredAccess, _In_ POBJECT_TYPE objType, _In_ KPROCESSOR_MODE AccessMode, _Out_ PHANDLE Handle)
+{
+ return _ObOpenObjectByPointer (obj, HandleAttributes, PassedAccessState, DesiredAccess, objType, AccessMode, Handle);
+}
+
+NTSTATUS NTAPI MmCopyMemory (_In_ PVOID TargetAddress, _In_ PVOID SourceAddress, _In_ SIZE_T NumberOfBytes, _In_ ULONG Flags, _Out_ PSIZE_T NumberOfBytesTransferred)
+{
+ if (_MmCopyMemory == NULL)
+ return STATUS_PROCEDURE_NOT_FOUND;
+
+ return _MmCopyMemory (TargetAddress, SourceAddress, NumberOfBytes, Flags, NumberOfBytesTransferred);
+}
+
+NTSTATUS NTAPI WrapperMmCopyMemory (_In_ PVOID TargetAddress, _In_ PVOID SourceAddress, _In_ SIZE_T NumberOfBytes, _In_ ULONG Flags, _Out_ PSIZE_T NumberOfBytesTransferred)
+{
+ return _MmCopyMemory (TargetAddress, SourceAddress, NumberOfBytes, Flags, NumberOfBytesTransferred);
+}
+
+NTSTATUS NTAPI MmCopyVirtualMemory (_In_ PEPROCESS SourceProcess, _In_ PVOID SourceAddress, _In_ PEPROCESS TargetProcess, _In_ PVOID TargetAddress, _In_ SIZE_T BufferSize, _In_ KPROCESSOR_MODE PreviousMode, _Out_ PSIZE_T ReturnSize)
+{
+ if (_MmCopyVirtualMemory == NULL)
+ return STATUS_PROCEDURE_NOT_FOUND;
+
+ return _MmCopyVirtualMemory (SourceProcess, SourceAddress, TargetProcess, TargetAddress, BufferSize, PreviousMode, ReturnSize);
+}
+
+NTSTATUS NTAPI WrapperMmCopyVirtualMemory (_In_ PEPROCESS SourceProcess, _In_ PVOID SourceAddress, _In_ PEPROCESS TargetProcess, _In_ PVOID TargetAddress, _In_ SIZE_T BufferSize, _In_ KPROCESSOR_MODE PreviousMode, _Out_ PSIZE_T ReturnSize)
+{
+ return _MmCopyVirtualMemory (SourceProcess, SourceAddress, TargetProcess, TargetAddress, BufferSize, PreviousMode, ReturnSize);
+}
+
+PVOID NTAPI RtlLookupFunctionEntry (_In_ DWORD64 ControlPc, _Out_ PDWORD64 ImageBase, _Out_ PVOID HistoryTable)
+{
+ return _RtlLookupFunctionEntry (ControlPc, ImageBase, HistoryTable);
+}
+
+PVOID NTAPI WrapperRtlLookupFunctionEntry (_In_ DWORD64 ControlPc, _Out_ PDWORD64 ImageBase, _Out_ PVOID HistoryTable)
+{
+ return _RtlLookupFunctionEntry (ControlPc, ImageBase, HistoryTable);
+}
+
+NTSTATUS NTAPI ZwTraceControl (_In_ ULONG FunctionCode, PVOID InBuffer, _In_ ULONG InBufferLen, PVOID OutBuffer, _In_ ULONG OutBufferLen, _Out_ PULONG ReturnLength)
+{
+ if (_ZwTraceControl == NULL)
+ return STATUS_PROCEDURE_NOT_FOUND;
+
+ return _ZwTraceControl (FunctionCode, InBuffer, InBufferLen, OutBuffer, OutBufferLen, ReturnLength);
+}
+
+NTSTATUS NTAPI WrapperZwTraceControl (_In_ ULONG FunctionCode, PVOID InBuffer, _In_ ULONG InBufferLen, PVOID OutBuffer, _In_ ULONG OutBufferLen, _Out_ PULONG ReturnLength)
+{
+ return _ZwTraceControl (FunctionCode, InBuffer, InBufferLen, OutBuffer, OutBufferLen, ReturnLength);
+}
+
+NTSTATUS NTAPI ZwTraceEvent (_In_ HANDLE TraceHandle, _In_ ULONG Flags, _In_ ULONG FieldSize, _In_ PVOID Fields)
+{
+ if (_ZwTraceEvent == NULL)
+ return STATUS_PROCEDURE_NOT_FOUND;
+
+ return _ZwTraceEvent (TraceHandle, Flags, FieldSize, Fields);
+}
+
+NTSTATUS NTAPI WrapperZwTraceEvent (_In_ HANDLE TraceHandle, _In_ ULONG Flags, _In_ ULONG FieldSize, _In_ PVOID Fields)
+{
+ return _ZwTraceEvent (TraceHandle, Flags, FieldSize, Fields);
+}
+
+NTSTATUS NTAPI ZwQueryVirtualMemory (_In_ HANDLE ProcessHandle, _In_ PVOID BaseAddress, _In_ int MemoryInformationClass, _Out_ PVOID MemoryInformation, _In_ SIZE_T MemoryInformationLength, _Out_ PSIZE_T ReturnLength)
+{
+ if (_ZwQueryVirtualMemory == NULL)
+ return STATUS_PROCEDURE_NOT_FOUND;
+
+ return _ZwQueryVirtualMemory (ProcessHandle, BaseAddress, MemoryInformationClass, MemoryInformation, MemoryInformationLength, ReturnLength);
+}
+
+NTSTATUS NTAPI WrapperZwQueryVirtualMemory (_In_ HANDLE ProcessHandle, _In_ PVOID BaseAddress, _In_ int MemoryInformationClass, _Out_ PVOID MemoryInformation, _In_ SIZE_T MemoryInformationLength, _Out_ PSIZE_T ReturnLength)
+{
+ return _ZwQueryVirtualMemory (ProcessHandle, BaseAddress, MemoryInformationClass, MemoryInformation, MemoryInformationLength, ReturnLength);
+}
+
+NTSTATUS NTAPI ZwProtectVirtualMemory (_In_ HANDLE ProcessHandle, _In_ _Out_ PVOID* BaseAddress, _In_ _Out_ PSIZE_T NumberOfBytesToProtect, _In_ ULONG NewAccessProtection, _Out_ PULONG OldAccessProtection)
+{
+ if (_ZwProtectVirtualMemory == NULL)
+ return STATUS_PROCEDURE_NOT_FOUND;
+
+ return _ZwProtectVirtualMemory (ProcessHandle, BaseAddress, NumberOfBytesToProtect, NewAccessProtection, OldAccessProtection);
+}
+
+NTSTATUS NTAPI WrapperZwProtectVirtualMemory (_In_ HANDLE ProcessHandle, _In_ _Out_ PVOID* BaseAddress, _In_ _Out_ PSIZE_T NumberOfBytesToProtect, _In_ ULONG NewAccessProtection, _Out_ PULONG OldAccessProtection)
+{
+ return _ZwProtectVirtualMemory (ProcessHandle, BaseAddress, NumberOfBytesToProtect, NewAccessProtection, OldAccessProtection);
+}
+
+NTSTATUS NTAPI ZwQuerySystemInformation (_In_ int SystemInformationClass, _Inout_ PVOID SystemInformation, _In_ ULONG SystemInformationLength, _Out_opt_ PULONG ReturnLength)
+{
+ if (_ZwQuerySystemInformation == NULL)
+ return STATUS_PROCEDURE_NOT_FOUND;
+
+ return _ZwQuerySystemInformation (SystemInformationClass, SystemInformation, SystemInformationLength, ReturnLength);
+}
+
+NTSTATUS NTAPI WrapperZwQuerySystemInformation (_In_ int SystemInformationClass, _Inout_ PVOID SystemInformation, _In_ ULONG SystemInformationLength, _Out_opt_ PULONG ReturnLength)
+{
+ return _ZwQuerySystemInformation (SystemInformationClass, SystemInformation, SystemInformationLength, ReturnLength);
+}
+
+NTSTATUS NTAPI _ZwCreateFile (_Out_ PHANDLE FileHandle, _In_ ACCESS_MASK DesiredAccess, _In_ POBJECT_ATTRIBUTES ObjectAttributes, _Out_ PIO_STATUS_BLOCK StatusBlock, _In_ PLARGE_INTEGER AllocationSize, _In_ ULONG FileAttributes, _In_ ULONG ShareAccess, _In_ ULONG CreateDisposition, _In_ ULONG CreateOptions, _In_ PVOID EaBuffer, _In_ ULONG EaLength)
+{
+ if (__ZwCreateFile == NULL)
+ return STATUS_PROCEDURE_NOT_FOUND;
+
+ return __ZwCreateFile (FileHandle, DesiredAccess, ObjectAttributes, StatusBlock, AllocationSize, FileAttributes, ShareAccess, CreateDisposition, CreateOptions, EaBuffer, EaLength);
+}
+
+NTSTATUS NTAPI WrapperZwCreateFile (_Out_ PHANDLE FileHandle, _In_ ACCESS_MASK DesiredAccess, _In_ POBJECT_ATTRIBUTES ObjectAttributes, _Out_ PIO_STATUS_BLOCK StatusBlock, _In_ PLARGE_INTEGER AllocationSize, _In_ ULONG FileAttributes, _In_ ULONG ShareAccess, _In_ ULONG CreateDisposition, _In_ ULONG CreateOptions, _In_ PVOID EaBuffer, _In_ ULONG EaLength)
+{
+ return __ZwCreateFile (FileHandle, DesiredAccess, ObjectAttributes, StatusBlock, AllocationSize, FileAttributes, ShareAccess, CreateDisposition, CreateOptions, EaBuffer, EaLength);
+}
+
+NTSTATUS NTAPI _ZwClose (_In_ HANDLE Handle)
+{
+ if (__ZwClose == NULL)
+ return STATUS_PROCEDURE_NOT_FOUND;
+
+ return __ZwClose (Handle);
+}
+
+NTSTATUS NTAPI WrapperZwClose (_In_ HANDLE Handle)
+{
+ return __ZwClose (Handle);
+}
+
+NTSTATUS NTAPI _ZwWriteFile (_In_ HANDLE FileHandle, _In_ HANDLE Event, _In_ PIO_APC_ROUTINE ApcRoutine, _In_ PVOID ApcContext, _Out_ PIO_STATUS_BLOCK StatusBlock, _In_ PVOID Buffer, _In_ ULONG Length, _In_ PLARGE_INTEGER ByteOffset, _In_ PULONG Key)
+{
+ if (__ZwWriteFile == NULL)
+ return STATUS_PROCEDURE_NOT_FOUND;
+
+ return __ZwWriteFile (FileHandle, Event, ApcRoutine, ApcContext, StatusBlock, Buffer, Length, ByteOffset, Key);
+}
+
+NTSTATUS NTAPI WrapperZwWriteFile (_In_ HANDLE FileHandle, _In_ HANDLE Event, _In_ PIO_APC_ROUTINE ApcRoutine, _In_ PVOID ApcContext, _Out_ PIO_STATUS_BLOCK StatusBlock, _In_ PVOID Buffer, _In_ ULONG Length, _In_ PLARGE_INTEGER ByteOffset, _In_ PULONG Key)
+{
+ return __ZwWriteFile (FileHandle, Event, ApcRoutine, ApcContext, StatusBlock, Buffer, Length, ByteOffset, Key);
+}
+
+#ifdef __cplusplus
+};
+#endif
diff --git a/CRT/ntdll_zw_functions.txt b/CRT/ntdll_zw_functions.txt
new file mode 100644
index 0000000..2cb1964
--- /dev/null
+++ b/CRT/ntdll_zw_functions.txt
@@ -0,0 +1,19 @@
+# Some functions that get resolved at runtime
+# They can always be called prefixed with "Wrapper" i.e. MmCopyMemory(...) becomes WrapperMmCopyMemory(...)
+# If not prefixed with '_', MmCopyMemory(...) should also work
+
+PVOID NTAPI MmMapIoSpaceEx(_In_ PHYSICAL_ADDRESS PhysicalAddress, _In_ SIZE_T NumberOfBytes, _In_ ULONG Protect);
+NTSTATUS NTAPI ObOpenObjectByPointer (_In_ PVOID obj, _In_ ULONG HandleAttributes, _In_ PACCESS_STATE PassedAccessState, _In_ ACCESS_MASK DesiredAccess, _In_ POBJECT_TYPE objType, _In_ KPROCESSOR_MODE AccessMode, _Out_ PHANDLE Handle);
+NTSTATUS NTAPI MmCopyMemory (_In_ PVOID TargetAddress, _In_ PVOID SourceAddress, _In_ SIZE_T NumberOfBytes, _In_ ULONG Flags, _Out_ PSIZE_T NumberOfBytesTransferred);
+NTSTATUS NTAPI MmCopyVirtualMemory (_In_ PEPROCESS SourceProcess, _In_ PVOID SourceAddress, _In_ PEPROCESS TargetProcess, _In_ PVOID TargetAddress, _In_ SIZE_T BufferSize, _In_ KPROCESSOR_MODE PreviousMode, _Out_ PSIZE_T ReturnSize);
+NTSYSAPI PVOID NTAPI RtlLookupFunctionEntry (_In_ DWORD64 ControlPc, _Out_ PDWORD64 ImageBase, _Out_ PVOID HistoryTable);
+NTSYSCALLAPI NTSTATUS NTAPI ZwTraceControl (_In_ ULONG FunctionCode, PVOID InBuffer, _In_ ULONG InBufferLen, PVOID OutBuffer, _In_ ULONG OutBufferLen, _Out_ PULONG ReturnLength)
+NTSYSCALLAPI NTSTATUS NTAPI ZwTraceEvent (_In_ HANDLE TraceHandle, _In_ ULONG Flags, _In_ ULONG FieldSize, _In_ PVOID Fields)
+NTSYSCALLAPI NTSTATUS NTAPI ZwQueryVirtualMemory(_In_ HANDLE ProcessHandle, _In_ PVOID BaseAddress, _In_ int MemoryInformationClass, _Out_ PVOID MemoryInformation, _In_ SIZE_T MemoryInformationLength, _Out_ PSIZE_T ReturnLength);
+NTSYSAPI NTSTATUS NTAPI ZwProtectVirtualMemory(_In_ HANDLE ProcessHandle, _In_ _Out_ PVOID* BaseAddress, _In_ _Out_ PSIZE_T NumberOfBytesToProtect, _In_ ULONG NewAccessProtection, _Out_ PULONG OldAccessProtection);
+NTSYSCALLAPI NTSTATUS NTAPI ZwQuerySystemInformation(_In_ int SystemInformationClass, _Inout_ PVOID SystemInformation, _In_ ULONG SystemInformationLength, _Out_opt_ PULONG ReturnLength);
+
+# Prefixed with a '_', the resulting function should only get called as "Wrapper" i.e. _ZwClose(...) will become WrapperZwClose(...)
+NTSYSAPI NTSTATUS NTAPI _ZwCreateFile(_Out_ PHANDLE FileHandle, _In_ ACCESS_MASK DesiredAccess, _In_ POBJECT_ATTRIBUTES ObjectAttributes, _Out_ PIO_STATUS_BLOCK StatusBlock, _In_ PLARGE_INTEGER AllocationSize, _In_ ULONG FileAttributes, _In_ ULONG ShareAccess, _In_ ULONG CreateDisposition, _In_ ULONG CreateOptions, _In_ PVOID EaBuffer, _In_ ULONG EaLength);
+NTSYSAPI NTSTATUS NTAPI _ZwClose(_In_ HANDLE Handle);
+NTSYSAPI NTSTATUS NTAPI _ZwWriteFile(_In_ HANDLE FileHandle, _In_ HANDLE Event, _In_ PIO_APC_ROUTINE ApcRoutine, _In_ PVOID ApcContext, _Out_ PIO_STATUS_BLOCK StatusBlock, _In_ PVOID Buffer, _In_ ULONG Length, _In_ PLARGE_INTEGER ByteOffset, _In_ PULONG Key);
diff --git a/CRT/obfuscate.hpp b/CRT/obfuscate.hpp
new file mode 100644
index 0000000..5522aad
--- /dev/null
+++ b/CRT/obfuscate.hpp
@@ -0,0 +1,163 @@
+#pragma once
+
+/*____________________________________________________________________________________________________________
+
+Original Author: skadro
+Github: https://github.com/skadro-official
+License: See end of file
+
+skCrypter
+ Compile-time, Usermode + Kernelmode, safe and lightweight string crypter library for C++11+
+
+ *Not removing this part is appreciated*
+____________________________________________________________________________________________________________*/
+
+#ifdef _KERNEL_MODE
+ namespace std
+ {
+ // STRUCT TEMPLATE remove_reference
+ template <class _Ty>
+ struct remove_reference {
+ using type = _Ty;
+ };
+
+ template <class _Ty>
+ struct remove_reference<_Ty&> {
+ using type = _Ty;
+ };
+
+ template <class _Ty>
+ struct remove_reference<_Ty&&> {
+ using type = _Ty;
+ };
+
+ template <class _Ty>
+ using remove_reference_t = typename remove_reference<_Ty>::type;
+
+ // STRUCT TEMPLATE remove_const
+ template <class _Ty>
+ struct remove_const { // remove top-level const qualifier
+ using type = _Ty;
+ };
+
+ template <class _Ty>
+ struct remove_const<const _Ty> {
+ using type = _Ty;
+ };
+
+ template <class _Ty>
+ using remove_const_t = typename remove_const<_Ty>::type;
+ }
+#else
+ #include <type_traits>
+#endif
+
+namespace skc
+{
+ template<class _Ty>
+ using clean_type = typename std::remove_const_t<std::remove_reference_t<_Ty>>;
+
+ template <int _size, char _key1, char _key2, typename T>
+ class skCrypter
+ {
+ public:
+ __forceinline constexpr skCrypter(T* data)
+ {
+ crypt(data);
+ }
+
+ __forceinline T* get()
+ {
+ return _storage;
+ }
+
+ __forceinline int size() // (w)char count
+ {
+ return _size;
+ }
+
+ __forceinline char key()
+ {
+ return _key1;
+ }
+
+ __forceinline T* encrypt()
+ {
+ if (!isEncrypted())
+ crypt(_storage);
+
+ return _storage;
+ }
+
+ __forceinline T* decrypt()
+ {
+ if (isEncrypted())
+ crypt(_storage);
+
+ return _storage;
+ }
+
+ __forceinline bool isEncrypted()
+ {
+ return _storage[_size - 1] != 0;
+ }
+
+ __forceinline void clear() // set full storage to 0
+ {
+ for (int i = 0; i < _size; i++)
+ {
+ _storage[i] = 0;
+ }
+ }
+
+ __forceinline operator T* ()
+ {
+ decrypt();
+
+ return _storage;
+ }
+
+ private:
+ __forceinline constexpr void crypt(T* data)
+ {
+ for (int i = 0; i < _size; i++)
+ {
+ _storage[i] = data[i] ^ (_key1 + i % (1 + _key2));
+ }
+ }
+
+ T _storage[_size]{};
+ };
+}
+
+#define skCrypt(str) skCrypt_key(str, __TIME__[4], __TIME__[7])
+#define skCrypt_key(str, key1, key2) []() { \
+ constexpr static auto crypted = skc::skCrypter \
+ <sizeof(str) / sizeof(str[0]), key1, key2, skc::clean_type<decltype(str[0])>>((skc::clean_type<decltype(str[0])>*)str); \
+ return crypted; }()
+
+/*________________________________________________________________________________
+
+MIT License
+
+Copyright (c) 2020 skadro
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+________________________________________________________________________________*/
diff --git a/CRT/ucrt.cpp b/CRT/ucrt.cpp
new file mode 100644
index 0000000..19ea583
--- /dev/null
+++ b/CRT/ucrt.cpp
@@ -0,0 +1,10 @@
+#include <cstdlib>
+
+void * operator new[](size_t size, const char *, int, unsigned, const char *, int)
+{
+ return malloc(size);
+}
+void * operator new[](size_t size, size_t, size_t, const char *, int, unsigned, const char *, int)
+{
+ return malloc(size);
+}