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