diff --git a/KernelLibrary/HashTable.cpp b/KernelLibrary/HashTable.cpp
new file mode 100644
index 0000000..a429d97
--- /dev/null
+++ b/KernelLibrary/HashTable.cpp
@@ -0,0 +1,236 @@
+#include "pch.h"
+#include "HashTable.h"
+
+UINT64 HashBytesGeneric(PUCHAR pBytes, size_t size,
+ UINT64 kMagicNum, UINT64 coefficient) {
+ UINT64 hashCode = kMagicNum;
+ for (int i = 0; i < size; i++) {
+ hashCode = pBytes[i] + coefficient * hashCode;
+ }
+ return hashCode;
+}
+
+UINT64 HashBytesEx(PUCHAR pBytes, size_t size, UINT64 kMagicNum) {
+ return HashBytesGeneric(pBytes, size, kMagicNum, 37);
+}
+
+UINT64 HashBytes(PUCHAR pBytes, size_t size) {
+ return HashBytesEx(pBytes, size, 314159);
+}
+
+UINT64 HashUlongPtr(UINT64 value) {
+ PUCHAR pBytes = (PUCHAR)&value;
+ return HashBytes(pBytes, sizeof(value));
+}
+
+UINT64 HashUStringUpcase(PWCH pBuffer, int len) {
+ PWCH pStart = pBuffer;
+ PWCH pEnd = &pBuffer[len];
+ UINT64 kMagicNumber = 314159;
+ while (pStart < pEnd) {
+ WCHAR upper = RtlUpcaseUnicodeChar(*pBuffer++);
+ kMagicNumber = HashBytesEx((PUCHAR)&upper, sizeof(upper), kMagicNumber);
+ }
+ return kMagicNumber;
+}
+
+UINT32 HashTableGetBucketIndex(UINT32 bucketCount, UINT64 key) {
+ return (bucketCount - 1) & HashUlongPtr(key);
+}
+
+UINT32 HashTableInsert(PHASH_TABLE Hash, PHASH_BUCKET HashEntry) {
+ UINT32 count = (Hash->BucketCount >> 5) & 0x7FFFFFF;
+ UINT64 key = (-1ull << (Hash->BucketCount & 0x1F)) & HashEntry->HashValue;
+ UINT32 idx = HashTableGetBucketIndex(count, key);
+ PushEntryList(&Hash->Buckets[idx].Entry, &HashEntry->Entry);
+ count = Hash->ItemCount + 1;
+ Hash->ItemCount = count;
+ return count;
+}
+
+BOOLEAN HashBucketLastLink(PHASH_BUCKET bucket) {
+ return (bucket->Hash & 1) != 0;
+}
+
+UINT32 GetHighestBitIndex(UINT32 value) {
+ UINT32 index = 0;
+ while (value > 0) {
+ index += 1;
+ value >>= 1;
+ }
+ return index;
+}
+
+void HashTableInitialize(PHASH_TABLE Hash, UINT32 Flags,
+ UINT32 BucketCount, PHASH_BUCKET Buckets) {
+ UINT32 count = RoundToPowerOfTwo(BucketCount, FALSE);
+ if (count > 0x4000000)
+ count = 0x4000000;
+ Hash->ItemCount = 0;
+ Hash->BucketCount = (count << 5) | Hash->BucketCount & 0x1F;
+ Hash->Buckets = Buckets;
+ Hash->BucketCount = Flags & 0x1F | Hash->BucketCount & 0xFFFFFFE0;
+ PHASH_BUCKET p = Buckets;
+ PHASH_BUCKET pEnd = &Buckets[count];
+ if (p) {
+ while (p < pEnd) {
+ p->Hash = ((ULONG_PTR)Hash | 1);
+ p++;
+ }
+ }
+}
+
+// Returns true if the given number is a power of 2.
+BOOLEAN IsPowerOfTwo(UINT32 x) {
+ return (x > 0) && ((x & (x - 1)) == 0);
+}
+
+UINT32 RoundToPowerOfTwo(UINT32 value, BOOLEAN roundUpToNext){
+ // if value is a power of 2, return it
+ if (IsPowerOfTwo(value)) {
+ return value;
+ }
+
+ UINT32 idx = GetHighestBitIndex(value);
+ if (roundUpToNext)
+ ++idx;
+ return (1ul << idx);
+}
+
+PHASH_BUCKET HashTableCleanup(PHASH_TABLE Hash) {
+ return Hash->Buckets;
+}
+
+PHASH_BUCKET HashTableFindNext(PHASH_TABLE Hash, UINT32 Key, PHASH_BUCKET Bucket) {
+ UINT64 value = -1ull << (Hash->BucketCount & 0x1F);
+ UINT32 k = value & Key;
+ PHASH_BUCKET pBucket = NULL;
+ BOOL bLastLink = FALSE;
+ if (Bucket) {
+ pBucket = Bucket;
+ bLastLink = HashBucketLastLink(pBucket);
+ }
+ else {
+ UINT32 count = (Hash->BucketCount >> 5) & 0x7FFFFFF;
+ if (count == 0)
+ return NULL;
+ UINT32 idx = HashTableGetBucketIndex(count, k);
+ pBucket = &Hash->Buckets[idx];
+ }
+ for (bLastLink = HashBucketLastLink(pBucket); !bLastLink;
+ bLastLink = HashBucketLastLink(pBucket)) {
+ if (k == (value & pBucket->HashValue)) {
+ return pBucket;
+ }
+ }
+ return NULL;
+}
+
+PHASH_TABLE HashTableGetTable(PHASH_BUCKET HashEntry) {
+ BOOL bLastLink = FALSE;
+ PHASH_TABLE pHash = NULL;
+ PHASH_BUCKET pBucket = (PHASH_BUCKET)HashEntry;
+ PHASH_BUCKET pEntry = NULL;
+
+ for (bLastLink = HashBucketLastLink(pBucket); !bLastLink;
+ bLastLink = HashBucketLastLink(pBucket)) {
+ pEntry = pBucket;
+ }
+
+ pHash = (PHASH_TABLE)(pBucket->Hash & ~1ull);
+ pEntry = NULL;
+ do
+ {
+ pEntry = HashTableFindNext(pHash, HashEntry->HashValue, pEntry);
+ } while (pEntry && pEntry != HashEntry);
+
+ return pHash;
+}
+
+PHASH_TABLE HashTableChangeTable(PHASH_TABLE Hash, ULONG size,
+ PHASH_BUCKET pBuckets) {
+ UINT32 count = RoundToPowerOfTwo(size, FALSE);
+ if (count > 0x4000000)
+ count = 0x4000000;
+ PHASH_BUCKET p = pBuckets;
+ PHASH_BUCKET pEnd = &pBuckets[count];
+ for (; p < pEnd; ++p) {
+ p->Hash = (ULONG_PTR)Hash | 1;
+ }
+
+ UINT64 value = -1ull << (Hash->BucketCount & 0x1F);
+ count = (Hash->BucketCount >> 5) & 0x7FFFFFF;
+ for (UINT32 j = 0; j < count; ++j) {
+ PHASH_BUCKET pBucket = &Hash->Buckets[j];
+ while (!HashBucketLastLink(pBucket)) {
+ p = pBucket;
+ pBucket = CONTAINING_RECORD(pBucket->Entry.Next, HASH_BUCKET, Entry);
+ UINT32 idx = HashTableGetBucketIndex(count, value & p->HashValue);
+ PushEntryList(&pBuckets[idx].Entry, &p->Entry);
+ }
+ }
+ pBuckets = Hash->Buckets;
+ Hash->Buckets = pBuckets;
+ Hash->BucketCount = (count >> 32) | Hash->BucketCount & 0x1F;
+
+ return Hash;
+}
+
+PHASH_TABLE_ITERATOR HashTableIterInit(PHASH_TABLE_ITERATOR Iterator,
+ PHASH_TABLE Hash) {
+ RtlZeroMemory(Iterator, sizeof(HASH_TABLE_ITERATOR));
+ Iterator->Hash = Hash;
+ Iterator->Bucket = Hash->Buckets;
+ Iterator->HashEntry = Iterator->Bucket;
+ return Iterator;
+}
+
+PHASH_BUCKET HashTableIterGetNext(PHASH_TABLE_ITERATOR Iterator) {
+ PHASH_BUCKET HashEntry = Iterator->HashEntry;
+ UINT32 count = 0;
+ if (!HashEntry || HashBucketLastLink(HashEntry)) {
+ PHASH_TABLE Hash = Iterator->Hash;
+
+ UINT32 count = (Hash->BucketCount >> 5) & 0x7FFFFFF;
+ PHASH_BUCKET pBucket = Iterator->Bucket;
+ PHASH_BUCKET pEnd = &Hash->Buckets[count];
+ while (TRUE)
+ {
+ if (pBucket >= pEnd)
+ return NULL;
+ if (!HashBucketLastLink(pBucket))
+ break;
+ pBucket = CONTAINING_RECORD(pBucket->Entry.Next, HASH_BUCKET, Entry);
+ }
+ PHASH_BUCKET pHashEntry = CONTAINING_RECORD(pBucket->Entry.Next, HASH_BUCKET, Entry);
+ count = (Iterator->Bucket - Iterator->Hash->Buckets) >> 3;
+ Iterator->Bucket = pBucket;
+ Iterator->HashEntry = pHashEntry;
+ return pHashEntry;
+ }
+ else {
+ count = (Iterator->Bucket - Iterator->Hash->Buckets) >> 3;
+ return Iterator->HashEntry;
+ }
+}
+
+PHASH_BUCKET MpHashTableIterRemove(PHASH_TABLE_ITERATOR Iterator) {
+ PHASH_BUCKET pHashEntry;
+ pHashEntry = Iterator->HashEntry;
+ PHASH_BUCKET pBucket = Iterator->Bucket;
+ BOOLEAN bLastLink = FALSE;
+
+ for (bLastLink = HashBucketLastLink(pBucket); !bLastLink;
+ bLastLink = HashBucketLastLink(pBucket)) {
+ PHASH_BUCKET p = CONTAINING_RECORD(pBucket->Entry.Next, HASH_BUCKET, Entry);
+ if (p == pHashEntry) {
+ --Iterator->Hash->ItemCount;
+ p->Entry.Next = pHashEntry->Entry.Next;
+ pHashEntry->Entry.Next = (PSINGLE_LIST_ENTRY)((ULONG_PTR)pHashEntry->Entry.Next | 0x8000000000000002);
+ Iterator->HashEntry = p;
+ return pHashEntry;
+ }
+ }
+
+ return NULL;
+}
\ No newline at end of file
diff --git a/KernelLibrary/HashTable.h b/KernelLibrary/HashTable.h
new file mode 100644
index 0000000..d0a70a2
--- /dev/null
+++ b/KernelLibrary/HashTable.h
@@ -0,0 +1,54 @@
+#pragma once
+typedef struct _HASH_BUCKET {
+ union {
+ ULONG_PTR Hash;
+ SINGLE_LIST_ENTRY Entry;
+ };
+ UINT64 HashValue;
+}HASH_BUCKET,*PHASH_BUCKET;
+
+typedef struct _HASH_TABLE {
+ UINT32 ItemCount;
+ UINT32 BucketCount;
+ PHASH_BUCKET Buckets;
+}HASH_TABLE,*PHASH_TABLE;
+
+typedef struct _HASH_TABLE_ITERATOR {
+ PHASH_TABLE Hash;
+ PHASH_BUCKET HashEntry;
+ PHASH_BUCKET Bucket;
+}HASH_TABLE_ITERATOR, * PHASH_TABLE_ITERATOR;
+
+UINT64 HashBytesGeneric(PUCHAR pBytes, size_t size,
+ UINT64 kMagicNum, UINT64 coefficient);
+
+UINT64 HashBytesEx(PUCHAR pBytes, size_t size, UINT64 kMagicNum);
+
+UINT64 HashBytes(PUCHAR pBytes, size_t size);
+
+UINT64 HashUlongPtr(UINT64 value);
+
+UINT64 HashUStringUpcase(PWCH pBuffer, int len);
+
+UINT32 HashTableGetBucketIndex(UINT32 bucketCount, UINT64 key);
+
+UINT32 HashTableInsert(PHASH_TABLE Hash, PHASH_BUCKET HashEntry);
+
+BOOLEAN HashBucketLastLink(PHASH_BUCKET bucket);
+
+void HashTableInitialize(PHASH_TABLE Hash, UINT32 Flags,
+ UINT32 BucketCount, PHASH_BUCKET Buckets);
+
+UINT32 GetHighestBitIndex(UINT32 value);
+
+UINT32 RoundToPowerOfTwo(UINT32 value, BOOLEAN roundUpToNext);
+
+BOOLEAN IsPowerOfTwo(UINT32 x);
+
+PHASH_BUCKET HashTableCleanup(PHASH_TABLE Hash);
+PHASH_BUCKET HashTableFindNext(PHASH_TABLE Hash, UINT32 Key, PHASH_BUCKET Bucket);
+PHASH_TABLE HashTableGetTable(PHASH_BUCKET HashEntry);
+PHASH_TABLE HashTableChangeTable(PHASH_TABLE Hash, ULONG size, PHASH_BUCKET pBucket);
+PHASH_TABLE_ITERATOR HashTableIterInit(PHASH_TABLE_ITERATOR Iterator, PHASH_TABLE Hash);
+PHASH_BUCKET HashTableIterGetNext(PHASH_TABLE_ITERATOR Iterator);
+PHASH_BUCKET MpHashTableIterRemove(PHASH_TABLE_ITERATOR Iterator);
\ No newline at end of file
diff --git a/KernelLibrary/KernelLibrary.vcxproj b/KernelLibrary/KernelLibrary.vcxproj
index 6029e25..d059dac 100644
--- a/KernelLibrary/KernelLibrary.vcxproj
+++ b/KernelLibrary/KernelLibrary.vcxproj
@@ -252,6 +252,7 @@
+
@@ -305,6 +306,7 @@
+
diff --git a/KernelLibrary/KernelLibrary.vcxproj.filters b/KernelLibrary/KernelLibrary.vcxproj.filters
index b00710c..e512dd2 100644
--- a/KernelLibrary/KernelLibrary.vcxproj.filters
+++ b/KernelLibrary/KernelLibrary.vcxproj.filters
@@ -195,6 +195,9 @@
Header Files
+
+ ktl
+
@@ -332,6 +335,9 @@
Source Files
+
+ ktl
+
diff --git a/KernelLibrary/SysMon.cpp b/KernelLibrary/SysMon.cpp
index 7af5b0b..5e2015a 100644
--- a/KernelLibrary/SysMon.cpp
+++ b/KernelLibrary/SysMon.cpp
@@ -1089,6 +1089,6 @@ bool StopLogDriverHash() {
status = DetourTransactionCommit();
if (!NT_SUCCESS(status))
return false;
-
+
return true;
}
\ No newline at end of file