mirror of
https://github.com/BeneficialCode/WinArk.git
synced 2026-10-17 04:40:35 +08:00
Add the Hash Table.
This commit is contained in:
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
@@ -252,6 +252,7 @@
|
||||
<ClInclude Include="DevMonManager.h" />
|
||||
<ClInclude Include="disasm.h" />
|
||||
<ClInclude Include="FilterFileNameInformation.h" />
|
||||
<ClInclude Include="HashTable.h" />
|
||||
<ClInclude Include="IoTimer.h" />
|
||||
<ClInclude Include="KernelTimer.h" />
|
||||
<ClInclude Include="ExecutiveResource.h" />
|
||||
@@ -305,6 +306,7 @@
|
||||
<ClCompile Include="DevMonManager.cpp" />
|
||||
<ClCompile Include="disasm.cpp" />
|
||||
<ClCompile Include="FilterFileNameInformation.cpp" />
|
||||
<ClCompile Include="HashTable.cpp" />
|
||||
<ClCompile Include="IoTimer.cpp" />
|
||||
<ClCompile Include="KernelTimer.cpp" />
|
||||
<ClCompile Include="ExecutiveResource.cpp" />
|
||||
|
||||
@@ -195,6 +195,9 @@
|
||||
<ClInclude Include="ProcessNetFilter.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="HashTable.h">
|
||||
<Filter>ktl</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="pch.cpp">
|
||||
@@ -332,6 +335,9 @@
|
||||
<ClCompile Include="ProcessNetFilter.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="HashTable.cpp">
|
||||
<Filter>ktl</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<MASM Include="code64.asm">
|
||||
|
||||
@@ -1089,6 +1089,6 @@ bool StopLogDriverHash() {
|
||||
status = DetourTransactionCommit();
|
||||
if (!NT_SUCCESS(status))
|
||||
return false;
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
Reference in New Issue
Block a user