A Kestrel-based server providing just-in-time (JIT) hash generation for memory integrity checking without database maintenance overhead.
Features β’ Quick Start β’ How It Works β’ Configuration β’ Usage β’ Contributing
- Overview
- Features
- Architecture
- Quick Start
- How It Works
- Configuration
- Usage Examples
- API Reference
- Troubleshooting
- Contributing
- License
π‘ Quick Reference: See Quick Reference Guide for commands and common tasks
HashServer eliminates the traditional burden of maintaining cryptographic hash databases for memory integrity checking. Instead of managing hash databases that require constant updates with every patch or binary change, HashServer dynamically generates expected hash values on-demand based on how binaries are loaded into memory.
Traditional memory integrity checking solutions require:
- β Maintaining massive hash databases
- β Updating hashes with every patch/update
- β Managing false positives from out-of-sync databases
- β High administrative overhead
HashServer provides:
- β Infinite hash database - JIT generated on-demand
- β Zero database maintenance - no manual updates needed
- β 100% verification rates - when properly configured
- β Cross-platform support - Windows and Linux tested
- β Free public API - pre-loaded with Microsoft OS files, Chrome, and Mozilla
Results are based on cryptographic hashes, not heuristics or signatures that can be fooled.
- Scan only working set of live systems
- Parallel server requests (faster with more usage)
- Client and server-side caching
- Optimized for real-time analysis
- β Windows (fully tested)
- β Linux (fully tested)
β οΈ macOS (should work, limited testing)
- Server: .NET Core 2.0
- Clients: PowerShell, Python, Bash
- Integrations: Volatility plugin, inVtero.core
- GUI tools (TreeMap, Hex Diff viewer)
- Scripting support
- RESTful API
- PowerShell client in K2/Scripting
Access to Internet HashServer pre-loaded with:
- Microsoft OS files
- Chrome datasets
- Mozilla datasets
- Selected GitHub projects (coming soon)
Public API: https://pdb2json.azurewebsites.net/
HashServer works by understanding how binaries are relocated when loaded into memory. When a client queries a hash:
βββββββββββββββ ββββββββββββββββ βββββββββββββββ
β Client βββββββββΆβ HashServer βββββββββΆβ Golden β
β (Scanner) ββββββββββ (JIT Gen) β β Files β
βββββββββββββββ ββββββββββββββββ βββββββββββββββ
β
β Fallback
βΌ
ββββββββββββββββ
β Internet β
β JITHash β
ββββββββββββββββ
Key Concepts:
- JIT Hash Generation: Hashes are computed on-demand based on binary metadata
- No Database: Uses filesystem of known-good binaries instead of hash DB
- Memory Relocation: Accounts for how binaries change when loaded into memory
- Cascading Fallback: Local β Local HashServer β Internet JITHash
- .NET Core 2.0 or higher
- Known-good filesystem images of your deployed software
# Clone the repository
git clone https://github.com/K2/HashServer.git
cd HashServer
# Restore dependencies
dotnet restore
# Build the project
dotnet build
# Run the server
dotnet runEdit appsettings.json:
{
"App": {
"Host": {
"BasePort": 3342,
"ProxyToExternalgRoot": true
},
"GoldSourceFiles": {
"Images": [
{
"OS": "Win10",
"ROOT": "C:\\GoldenImages\\Win10"
}
]
}
}
}Use the PowerShell client from K2/Scripting:
# Download the client
Invoke-WebRequest -Uri "https://raw.githubusercontent.com/K2/Scripting/master/Test-AllVirtualMemory.ps1" -OutFile "Test-AllVirtualMemory.ps1"
# Configure to use your local HashServer
$HashServerUri = "http://localhost:3342/api/PageHash/x"
# Run memory integrity check
.\Test-AllVirtualMemory.ps1Traditional approach:
Binary β Hash β Store in DB β Compare on scan
β
Manual maintenance
HashServer approach:
Binary + Metadata β JIT Hash Calculation β Compare
β
No maintenance!
When a binary is loaded into memory:
- Base addresses may change
- Relocation tables are applied
- Import Address Table (IAT) is populated
- Code sections are modified
HashServer understands these transformations and generates the expected hash for the relocated binary.
sequenceDiagram
Scanner->>Target: Deploy memory manager
Target->>Scanner: Ready
loop Scan all executable pages
Scanner->>Target: Request memory hashes
Target->>Scanner: SHA256 + Metadata
Scanner->>HashServer: Verify hash
HashServer->>HashServer: JIT calculation
alt Locally serviced
HashServer->>Scanner: Known β
else Check Internet
HashServer->>JITHash: Forward request
JITHash->>Scanner: Known β/β
end
end
You do NOT need to maintain a hash database. Instead:
- Mount/copy known-good filesystem images
- Point HashServer to these locations
- Update images when you deploy new versions
- Restart HashServer (it will re-index)
That's it! No hash recalculation, no database updates.
{
"App": {
"Host": {
"Machine": "gRootServer",
"FileLocateNfo": "GoldState.buf",
"LogLevel": "Warning",
"CertificateFile": "testCert.pfx",
"CertificatePassword": "testPassword",
"ThreadCount": 128,
"MaxConcurrentConnections": 4096,
"ProxyToExternalgRoot": true,
"BasePort": 3342
},
"External": {
"gRoot": "https://pdb2json.azurewebsites.net/"
},
"Internal": {
"gRoot": "http://*:3342/"
},
"InternalSSL": {
"gRoot": "https://*:3343/"
},
"GoldSourceFiles": {
"Images": [
{
"OS": "Win10",
"ROOT": "T:\\"
},
{
"OS": "Win2016",
"ROOT": "K:\\"
},
{
"OS": "MinRequirements",
"ROOT": "C:\\Windows\\system32\\Drivers"
}
]
}
}
}| Setting | Description |
|---|---|
FileLocateNfo |
πΎ Cache file for indexed files (speeds up startup) |
GoldSourceFiles.Images |
π Array of known-good filesystem locations |
Images[].OS |
π·οΈ Metadata tag for the file set |
Images[].ROOT |
π Root path to recursively scan for binaries |
ProxyToExternalgRoot |
π Enable fallback to Internet JITHash service |
BasePort |
π HTTP port for the service (default: 3342) |
ThreadCount |
π§΅ Worker thread pool size |
LogLevel |
π Logging verbosity (Warning, Info, Debug) |
When you update your golden images:
- Overwrite the files in the
ROOTlocations - Delete the
FileLocateNfocache file (e.g.,GoldState.buf) - Restart the HashServer
The server will re-index on startup. This may take a few minutes for large file sets.
The primary client is in the K2/Scripting repository.
# Configure endpoints
$gRoot = "https://pdb2json.azurewebsites.net/api/PageHash/x" # Public fallback
$HashServerUri = "http://10.0.0.118:3342/api/PageHash/x" # Your local server
# Run the memory integrity check
.\Test-AllVirtualMemory.ps1
# Results include:
# - TreeMap GUI for visual analysis
# - Hex diff view for modified memory regions
# - PowerShell objects for custom analyticsFeatures:
- π― Scans working set (active memory) by default
- β‘ Parallel processing with Invoke-Parallel
- π¨ TreeMap visualization (Process β Modules β Blocks)
- π Hex diff viewer for memory modifications
- π Detailed verification reports
The Volatility plugin works with memory dumps:
# inVteroJitHash.py plugin
# https://github.com/K2/Scripting/blob/master/inVteroJitHash.py
vol.py -f memory.dmp --profile=Win10x64 invterojithashFor more aggressive scanning of memory dumps:
# Using inVtero.core CLI
inVtero -f memory.dmp --hash-server http://localhost:3342Method: POST
Request Body:
{
"Hash": "sha256_hash_of_memory_block",
"Size": 4096,
"TimeStamp": 1234567890,
"VirtualSize": 4096,
"FileName": "kernel32.dll",
"PDB": "kernel32.pdb",
"Characteristics": 0x20000020
}Response:
{
"IsKnown": true,
"Source": "Local",
"MatchedFile": "C:\\Windows\\System32\\kernel32.dll",
"Confidence": 100
}| Field | Type | Description |
|---|---|---|
IsKnown |
boolean | Whether the hash matches a known-good binary |
Source |
string | "Local" or "Internet" |
MatchedFile |
string | Path to the matched golden image file |
Confidence |
integer | Match confidence (0-100) |
Problem: Server takes minutes to start
Solution:
- First startup indexes all files (cached to
FileLocateNfo) - Subsequent startups use cache and are much faster
- Reduce number of files in golden images if indexing is too slow
Problem: Many unknown hashes reported
Solutions:
- Ensure golden images contain all deployed software
- Check that
ProxyToExternalgRootis enabled for Internet fallback - Verify golden images match deployed versions exactly
Problem: Server not detecting updated files
Solution:
# Delete cache file
rm GoldState.buf
# Restart server
dotnet runProblem: Can't connect to HashServer
Check:
- Server is running:
netstat -an | grep 3342 - Firewall allows port 3342
- Correct IP/hostname in client configuration
Contributions are welcome! Here's how you can help:
- Use GitHub Issues
- Include error messages and logs
- Describe expected vs actual behavior
- Provide configuration (sanitized)
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
Help improve these docs:
- Fix typos or unclear sections
- Add examples
- Translate to other languages
- JavaScript/JIT Code Validation - Next major feature
- Dynamic code integrity checking
- Enhanced caching mechanisms
- Performance optimizations
- macOS testing and full support
- Additional language clients (Go, Rust)
- Web-based management UI
- Kubernetes/container deployment guides
- Integration with SIEM systems
Have a feature request? Open an issue with the enhancement label!
This project is licensed under the GNU Affero General Public License v3.0 (AGPL-3.0).
See LICENSE or agpl-3.0.txt for details.
- PowerShell Client: Uses native PowerShell sessions, threading with Invoke-Parallel
- Code Contributions: @mattifestation (token handling), JayKul (ShowUI), Proxb (TreeMap control)
- Related Projects: inVtero.net, K2/Scripting
- Issues: GitHub Issues
- Discussions: GitHub Discussions
- Scripting Client: K2/Scripting Repository
- Security: See SECURITY.md for security policy
- Contributing: See CONTRIBUTING.md for contribution guidelines
β Star this repo if you find it useful! β
Made with β€οΈ for the security and forensics community