You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
285 lines
7.6 KiB
285 lines
7.6 KiB
/*++
|
|
|
|
Copyright (c) 2001 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
webblade.c
|
|
|
|
Abstract:
|
|
|
|
This module contains the main routine and
|
|
helper routines to enforce software restrictions
|
|
for the Web Blade SKU.
|
|
|
|
exe's whose hash values test positive w.r.t
|
|
the hardcoded hash array in webblade.h will
|
|
be disallowed from executing.
|
|
|
|
Author:
|
|
|
|
Vishnu Patankar (VishnuP) 01-May-2001
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "basedll.h"
|
|
#pragma hdrstop
|
|
|
|
#include "webbladep.h"
|
|
#include "webbladehashesp.h"
|
|
|
|
#define WEB_BLADEP_EXTRACT_NIBBLE(bLeastSignificantNibble, HexNibbleMask) ((bLeastSignificantNibble) ? (HexNibbleMask) : ((HexNibbleMask) << 4))
|
|
|
|
BYTE WebBladeDisallowedHashes[][WEB_BLADE_MAX_HASH_SIZE*2+1] = {
|
|
WEBBLADE_SORTED_ASCENDING_HASHES
|
|
};
|
|
|
|
#define WEB_BLADE_NUM_HASHES sizeof(WebBladeDisallowedHashes)/(WEB_BLADE_MAX_HASH_SIZE * 2 + 1)
|
|
|
|
NTSTATUS
|
|
BasepCheckWebBladeHashes(
|
|
IN HANDLE hFile
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine computes the web blade hash for the candidate file
|
|
and checks for membership in the hardcoded WebBladeDisallowedHashes[].
|
|
|
|
If the hash is present, the code should not be allowed to execute.
|
|
|
|
Arguments:
|
|
|
|
hFile - the file handle of the exe file to check for allow/disallow.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - if disallowed, this is STATUS_ACCESS_DENIED else
|
|
it is the internal status of other APIs
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
BYTE FileHashValue[WEB_BLADE_MAX_HASH_SIZE];
|
|
DWORD dwIndex;
|
|
|
|
static BOOL bConvertReadableHashToByteHash = TRUE;
|
|
|
|
//
|
|
// Optimization: Half of the same array is used since the CHARs can
|
|
// be compressed 2:1 into actual hash'ish BYTES (e.g. two readable
|
|
// CHARS "0E" is actually one BYTE 00001110) i.e. each 32 CHAR hash
|
|
// becomes a 16 BYTE hash
|
|
//
|
|
|
|
if (bConvertReadableHashToByteHash) {
|
|
|
|
for (dwIndex = 0;
|
|
dwIndex < WEB_BLADE_NUM_HASHES;
|
|
dwIndex++) {
|
|
|
|
Status = WebBladepConvertStringizedHashToHash( WebBladeDisallowedHashes[dwIndex] );
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
goto ExitHandler;
|
|
}
|
|
}
|
|
|
|
//
|
|
// This conversion should be done only once per process (otherwise we
|
|
// would be doing a fixed point computation)
|
|
//
|
|
|
|
|
|
bConvertReadableHashToByteHash = FALSE;
|
|
}
|
|
|
|
//
|
|
// Compute the limited hash
|
|
//
|
|
|
|
#define ITH_REVISION_1 1
|
|
|
|
Status = RtlComputeImportTableHash( hFile, FileHashValue, ITH_REVISION_1 );
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
goto ExitHandler;
|
|
}
|
|
|
|
//
|
|
// Check for membership of the computed hash in the sorted disallowed hash array
|
|
// Use binary search for O (log n) complexity
|
|
//
|
|
|
|
if ( bsearch (FileHashValue,
|
|
WebBladeDisallowedHashes,
|
|
WEB_BLADE_NUM_HASHES,
|
|
WEB_BLADE_MAX_HASH_SIZE * 2 + 1,
|
|
pfnWebBladeHashCompare
|
|
)) {
|
|
|
|
//
|
|
// FileHashValue tested positive for membership in WebBladeDisallowedHashes[][]
|
|
//
|
|
|
|
Status = STATUS_ACCESS_DENIED;
|
|
|
|
}
|
|
|
|
ExitHandler:
|
|
|
|
return Status;
|
|
}
|
|
|
|
int
|
|
__cdecl pfnWebBladeHashCompare(
|
|
const BYTE *WebBladeFirstHash,
|
|
const BYTE *WebBladeSecondHash
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine byte-lexically compares two WebBladeHashes.
|
|
Essentially, it wraps memcmp.
|
|
|
|
Arguments:
|
|
|
|
WebBladeHashFirst - the first web blade hash
|
|
|
|
WebBladeHashSecond - the second web blade hash
|
|
|
|
Return Value:
|
|
|
|
0 if equal,
|
|
-ve if WebBladeHashFirst < WebBladeHashSecond
|
|
+ve if WebBladeHashFirst > WebBladeHashSecond
|
|
|
|
--*/
|
|
{
|
|
|
|
return memcmp(WebBladeFirstHash, WebBladeSecondHash, WEB_BLADE_MAX_HASH_SIZE);
|
|
|
|
}
|
|
|
|
NTSTATUS WebBladepConvertStringizedHashToHash(
|
|
IN OUT PCHAR pStringizedHash
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine converts a readable 32 CHAR hash into a 16 BYTE hash.
|
|
As an optimization, the conversion is done in-place.
|
|
|
|
Optimization: Half of the same array is used since the CHARs can
|
|
be compressed 2:1 into actual hash'ish BYTES (e.g. two readable
|
|
CHARS "0E" is actually one BYTE 00001110) i.e. each 32 CHAR hash
|
|
becomes a 16 BYTE hash
|
|
|
|
One byte is assembled by looking at two characters.
|
|
|
|
Arguments:
|
|
|
|
pStringizedHash - Pointer to the beginning of a 32 CHAR (in) 16 BYTE (out) hash.
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS if the hash value was computed, else the error in
|
|
hash computation (if any)
|
|
|
|
--*/
|
|
{
|
|
|
|
DWORD dwHashIndex = 0;
|
|
DWORD dwStringIndex = 0;
|
|
BYTE OneByte = 0;
|
|
BOOL bLeastSignificantNibble = FALSE;
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
|
|
if (pStringizedHash == NULL) {
|
|
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
goto ExitHandler;
|
|
|
|
}
|
|
|
|
for (dwStringIndex=0; dwStringIndex < WEB_BLADE_MAX_HASH_SIZE * 2; dwStringIndex++ ) {
|
|
|
|
switch (pStringizedHash[dwStringIndex]) {
|
|
case '0':
|
|
OneByte |= WEB_BLADEP_EXTRACT_NIBBLE(bLeastSignificantNibble, 0x0);
|
|
break;
|
|
case '1':
|
|
OneByte |= WEB_BLADEP_EXTRACT_NIBBLE(bLeastSignificantNibble, 0x1);
|
|
break;
|
|
case '2':
|
|
OneByte |= WEB_BLADEP_EXTRACT_NIBBLE(bLeastSignificantNibble, 0x2);
|
|
break;
|
|
case '3':
|
|
OneByte |= WEB_BLADEP_EXTRACT_NIBBLE(bLeastSignificantNibble, 0x3);
|
|
break;
|
|
case '4':
|
|
OneByte |= WEB_BLADEP_EXTRACT_NIBBLE(bLeastSignificantNibble, 0x4);
|
|
break;
|
|
case '5':
|
|
OneByte |= WEB_BLADEP_EXTRACT_NIBBLE(bLeastSignificantNibble, 0x5);
|
|
break;
|
|
case '6':
|
|
OneByte |= WEB_BLADEP_EXTRACT_NIBBLE(bLeastSignificantNibble, 0x6);
|
|
break;
|
|
case '7':
|
|
OneByte |= WEB_BLADEP_EXTRACT_NIBBLE(bLeastSignificantNibble, 0x7);
|
|
break;
|
|
case '8':
|
|
OneByte |= WEB_BLADEP_EXTRACT_NIBBLE(bLeastSignificantNibble, 0x8);
|
|
break;
|
|
case '9':
|
|
OneByte |= WEB_BLADEP_EXTRACT_NIBBLE(bLeastSignificantNibble, 0x9);
|
|
break;
|
|
case 'a':
|
|
case 'A':
|
|
OneByte |= WEB_BLADEP_EXTRACT_NIBBLE(bLeastSignificantNibble, 0xa);
|
|
break;
|
|
case 'b':
|
|
case 'B':
|
|
OneByte |= WEB_BLADEP_EXTRACT_NIBBLE(bLeastSignificantNibble, 0xb);
|
|
break;
|
|
case 'c':
|
|
case 'C':
|
|
OneByte |= WEB_BLADEP_EXTRACT_NIBBLE(bLeastSignificantNibble, 0xc);
|
|
break;
|
|
case 'd':
|
|
case 'D':
|
|
OneByte |= WEB_BLADEP_EXTRACT_NIBBLE(bLeastSignificantNibble, 0xd);
|
|
break;
|
|
case 'e':
|
|
case 'E':
|
|
OneByte |= WEB_BLADEP_EXTRACT_NIBBLE(bLeastSignificantNibble, 0xe);
|
|
break;
|
|
case 'f':
|
|
case 'F':
|
|
OneByte |= WEB_BLADEP_EXTRACT_NIBBLE(bLeastSignificantNibble, 0xf);
|
|
break;
|
|
default:
|
|
ASSERT(FALSE);
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
goto ExitHandler;
|
|
}
|
|
|
|
if (bLeastSignificantNibble) {
|
|
pStringizedHash[dwHashIndex++] = OneByte;
|
|
OneByte = 0;
|
|
}
|
|
|
|
bLeastSignificantNibble = !bLeastSignificantNibble;
|
|
}
|
|
|
|
|
|
ExitHandler:
|
|
|
|
return Status;
|
|
}
|