📄 rndwin32.c
字号:
checkPollExit();
initRandomData( randomState, buffer, BIG_RANDOM_BUFSIZE );
/* Take a snapshot of everything we can get to that's currently in the
system */
hSnapshot = pCreateToolhelp32Snapshot( TH32CS_SNAPALL, 0 );
if( !hSnapshot )
return;
/* Walk through the local heap. We have to be careful to not spend
excessive amounts of time on this if we're linked into a large
application with a great many heaps and/or heap blocks, since the
heap-traversal functions are rather slow. Fortunately this is
quite rare under Win95/98, since it implies a large/long-running
server app that would be run under NT/Win2K/XP rather than Win95
(the performance of the mapped ToolHelp32 helper functions under
these OSes is even worse than under Win95, fortunately we don't
have to use them there).
Ideally in order to prevent excessive delays we'd count the number
of heaps and ensure that no_heaps * no_heap_blocks doesn't exceed
some maximum value, however this requires two passes of (slow) heap
traversal rather than one, which doesn't help the situation much.
To provide at least some protection, we limit the total number of
heaps and heap entries traversed, although this leads to slightly
suboptimal performance if we have a small number of deep heaps
rather than the current large number of shallow heaps.
There is however a second consideration that needs to be taken into
account when doing this, which is that the heap-management functions
aren't completely thread-safe, so that under (very rare) conditions
of heavy allocation/deallocation this can cause problems when calling
HeapNext(). By limiting the amount of time that we spend in each
heap, we can reduce our exposure somewhat */
hl32.dwSize = sizeof( HEAPLIST32 );
if( pHeap32ListFirst( hSnapshot, &hl32 ) )
do
{
HEAPENTRY32 he32;
int entryCount = 0;
/* First add the information from the basic Heaplist32
structure */
checkPollExit();
addRandomData( randomState, &hl32, sizeof( HEAPLIST32 ) );
/* Now walk through the heap blocks getting information
on each of them */
he32.dwSize = sizeof( HEAPENTRY32 );
if( pHeap32First( &he32, hl32.th32ProcessID, hl32.th32HeapID ) )
do
{
checkPollExit();
addRandomData( randomState, &he32,
sizeof( HEAPENTRY32 ) );
}
while( entryCount++ < 20 && pHeap32Next( &he32 ) );
}
while( listCount++ < 20 && pHeap32ListNext( hSnapshot, &hl32 ) );
/* Walk through all processes */
pe32.dwSize = sizeof( PROCESSENTRY32 );
if( pProcess32First( hSnapshot, &pe32 ) )
do
{
checkPollExit();
addRandomData( randomState, &pe32, sizeof( PROCESSENTRY32 ) );
}
while( pProcess32Next( hSnapshot, &pe32 ) );
/* Walk through all threads */
te32.dwSize = sizeof( THREADENTRY32 );
if( pThread32First( hSnapshot, &te32 ) )
do
{
checkPollExit();
addRandomData( randomState, &te32, sizeof( THREADENTRY32 ) );
}
while( pThread32Next( hSnapshot, &te32 ) );
/* Walk through all modules associated with the process */
me32.dwSize = sizeof( MODULEENTRY32 );
if( pModule32First( hSnapshot, &me32 ) )
do
{
checkPollExit();
addRandomData( randomState, &me32, sizeof( MODULEENTRY32 ) );
}
while( pModule32Next( hSnapshot, &me32 ) );
/* Clean up the snapshot */
CloseHandle( hSnapshot );
checkPollExit();
/* Flush any remaining data through */
endRandomData( randomState, 100 );
}
/* Perform a thread-safe slow poll for Windows 95 */
unsigned __stdcall threadSafeSlowPollWin95( void *dummy )
{
UNUSED( dummy );
slowPollWin95();
_endthreadex( 0 );
return( 0 );
}
/* Type definitions for function pointers to call NetAPI32 functions */
typedef DWORD ( WINAPI *NETSTATISTICSGET )( LPWSTR szServer, LPWSTR szService,
DWORD dwLevel, DWORD dwOptions,
LPBYTE *lpBuffer );
typedef DWORD ( WINAPI *NETAPIBUFFERSIZE )( LPVOID lpBuffer, LPDWORD cbBuffer );
typedef DWORD ( WINAPI *NETAPIBUFFERFREE )( LPVOID lpBuffer );
/* Type definitions for functions to call native NT functions */
typedef DWORD ( WINAPI *NTQUERYSYSTEMINFO )( DWORD dwType, DWORD dwData,
DWORD dwMaxSize, DWORD dwDataSize );
/* Global function pointers. These are necessary because the functions need to
be dynamically linked since only the WinNT kernel currently contains them.
Explicitly linking to them will make the program unloadable under Win95 */
static NETSTATISTICSGET pNetStatisticsGet = NULL;
static NETAPIBUFFERSIZE pNetApiBufferSize = NULL;
static NETAPIBUFFERFREE pNetApiBufferFree = NULL;
static NTQUERYSYSTEMINFO pNtQuerySystemInfo = NULL;
/* When we query the performance counters, we allocate an initial buffer and
then reallocate it as required until RegQueryValueEx() stops returning
ERROR_MORE_DATA. The following values define the initial buffer size and
step size by which the buffer is increased */
#define PERFORMANCE_BUFFER_SIZE 65536 /* Start at 64K */
#define PERFORMANCE_BUFFER_STEP 16384 /* Step by 16K */
static void slowPollWinNT( void )
{
static int isWorkstation = CRYPT_ERROR;
static int cbPerfData = PERFORMANCE_BUFFER_SIZE;
RESOURCE_DATA msgData;
PPERF_DATA_BLOCK pPerfData;
HANDLE hDevice;
LPBYTE lpBuffer;
DWORD dwSize, status;
int nDrive, iterations = 0;
/* Find out whether this is an NT server or workstation if necessary */
if( isWorkstation == CRYPT_ERROR )
{
HKEY hKey;
if( RegOpenKeyEx( HKEY_LOCAL_MACHINE,
"SYSTEM\\CurrentControlSet\\Control\\ProductOptions",
0, KEY_READ, &hKey ) == ERROR_SUCCESS )
{
BYTE szValue[ 32 ];
dwSize = sizeof( szValue );
isWorkstation = TRUE;
status = RegQueryValueEx( hKey, "ProductType", 0, NULL,
szValue, &dwSize );
if( status == ERROR_SUCCESS && stricmp( szValue, "WinNT" ) )
/* Note: There are (at least) three cases for ProductType:
WinNT = NT Workstation, ServerNT = NT Server, LanmanNT =
NT Server acting as a Domain Controller */
isWorkstation = FALSE;
RegCloseKey( hKey );
}
}
/* Initialize the NetAPI32 function pointers if necessary */
if( hNetAPI32 == NULL )
{
/* Obtain a handle to the module containing the Lan Manager functions */
if( ( hNetAPI32 = LoadLibrary( "NETAPI32.DLL" ) ) != NULL )
{
/* Now get pointers to the functions */
pNetStatisticsGet = ( NETSTATISTICSGET ) GetProcAddress( hNetAPI32,
"NetStatisticsGet" );
pNetApiBufferSize = ( NETAPIBUFFERSIZE ) GetProcAddress( hNetAPI32,
"NetApiBufferSize" );
pNetApiBufferFree = ( NETAPIBUFFERFREE ) GetProcAddress( hNetAPI32,
"NetApiBufferFree" );
/* Make sure we got valid pointers for every NetAPI32 function */
if( pNetStatisticsGet == NULL ||
pNetApiBufferSize == NULL ||
pNetApiBufferFree == NULL )
{
/* Free the library reference and reset the static handle */
FreeLibrary( hNetAPI32 );
hNetAPI32 = NULL;
}
}
}
/* Initialize the NT kernel native API function pointers if necessary */
if( hNTAPI == NULL && \
( hNTAPI = GetModuleHandle( "NTDll.dll" ) ) != NULL )
{
/* Get a pointer to the NT native information query function */
pNtQuerySystemInfo = ( NTQUERYSYSTEMINFO ) GetProcAddress( hNTAPI,
"NtQuerySystemInformation" );
if( pNtQuerySystemInfo == NULL )
hNTAPI = NULL;
}
checkPollExit();
/* Get network statistics. Note: Both NT Workstation and NT Server by
default will be running both the workstation and server services. The
heuristic below is probably useful though on the assumption that the
majority of the network traffic will be via the appropriate service. In
any case the network statistics return almost no randomness */
if( hNetAPI32 != NULL &&
pNetStatisticsGet( NULL,
isWorkstation ? L"LanmanWorkstation" : L"LanmanServer",
0, 0, &lpBuffer ) == 0 )
{
pNetApiBufferSize( lpBuffer, &dwSize );
setMessageData( &msgData, lpBuffer, dwSize );
krnlSendMessage( SYSTEM_OBJECT_HANDLE, IMESSAGE_SETATTRIBUTE_S,
&msgData, CRYPT_IATTRIBUTE_ENTROPY );
pNetApiBufferFree( lpBuffer );
}
/* Get disk I/O statistics for all the hard drives */
for( nDrive = 0;; nDrive++ )
{
BYTE diskPerformance[ 256 ];
char szDevice[ 24 ];
/* Check whether we can access this device */
sprintf( szDevice, "\\\\.\\PhysicalDrive%d", nDrive );
hDevice = CreateFile( szDevice, 0, FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL, OPEN_EXISTING, 0, NULL );
if( hDevice == INVALID_HANDLE_VALUE )
break;
/* Note: This only works if the user has turned on the disk
performance counters with 'diskperf -y'. These counters are
usually disabled, although they appear to be enabled in newer
installs of Win2K and XP. In addition using the documented
DISK_PERFORMANCE data structure to contain the returned data
returns ERROR_INSUFFICIENT_BUFFER (which is wrong) and doesn't
change dwSize (which is also wrong), so we pass in a larger
buffer and pre-set dwSize to a safe value. Finally, there is a
bug in pre-SP4 Win2K in which enabling diskperf, installing a
file system filter driver, and then disabling diskperf, causes
diskperf to corrupt the registry key HKEY_LOCAL_MACHINE\SYSTEM\
CurrentControlSet\Control\Class\{71A27CDD-812A-11D0-BEC7-
08002BE2092F}\Upper Filters, resulting in a Stop 0x7B bugcheck */
dwSize = sizeof( diskPerformance );
if( DeviceIoControl( hDevice, IOCTL_DISK_PERFORMANCE, NULL, 0,
&diskPerformance, sizeof( diskPerformance ),
&dwSize, NULL ) )
{
checkPollExit();
setMessageData( &msgData, &diskPerformance, dwSize );
krnlSendMessage( SYSTEM_OBJECT_HANDLE, IMESSAGE_SETATTRIBUTE_S,
&msgData, CRYPT_IATTRIBUTE_ENTROPY );
}
CloseHandle( hDevice );
}
checkPollExit();
/* In theory we should be using the Win32 performance query API to obtain
unpredictable data from the system, however this is so unreliable (see
the multiple sets of comments further down) that it's too risky to
rely on it except as a fallback in emergencies. Instead, we rely
mostly on an NT native API function that has the dual advantages that
it doesn't have as many (known) problems as the Win32 equivalent, and
that it doesn't access the data indirectly via pseudo-registry keys,
which means that it's much faster. Note that the Win32 equivalent
actually works almost all of the time, the problem is that on one or
two systems it can fail in strange ways that are never the same and
can't be reproduced on any other system, which is why we use the
native API here. Microsoft officially documented this function in
early 2003, so it'll be fairly safe to use */
if( hNTAPI != NULL )
{
void *buffer = clAlloc( "slowPollNT", PERFORMANCE_BUFFER_SIZE );
if( buffer != NULL )
{
DWORD dwSize = PERFORMANCE_BUFFER_SIZE, dwType;
int noResults = 0;
/* Scan the first 64 possible information types (we don't bother
with increasing the buffer size as we do with the Win32 version
of the performance data read, we may miss a few classes but
it's no big deal). In addition the returned size value for
some classes is wrong (e.g. 23 and 24 return a size of 0) so we
miss a few more things, but again it's no big deal. This scan
typically yields around 20 pieces of data, there's nothing in
the range 65...128 so chances are there won't be anything above
there either */
for( dwType = 0; dwType < 64; dwType++ )
{
status = pNtQuerySystemInfo( dwType, ( DWORD ) buffer,
32768, ( DWORD ) &dwSize );
if( status == ERROR_SUCCESS && dwSize > 0 )
{
checkPollExit();
setMessageData( &msgData, buffer, dwSize );
status = krnlSendMessage( SYSTEM_OBJECT_HANDLE,
IMESSAGE_SETATTRIBUTE_S, &msgData,
CRYPT_IATTRIBUTE_ENTROPY );
if( cryptStatusOK( status ) )
noResults++;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -