📄 rndwin32.c
字号:
be dynamically linked since only the Win95 kernel currently contains them.
Explicitly linking to them will make the program unloadable under NT */
static CREATESNAPSHOT pCreateToolhelp32Snapshot = NULL;
static MODULEWALK pModule32First = NULL;
static MODULEWALK pModule32Next = NULL;
static PROCESSWALK pProcess32First = NULL;
static PROCESSWALK pProcess32Next = NULL;
static THREADWALK pThread32First = NULL;
static THREADWALK pThread32Next = NULL;
static HEAPLISTWALK pHeap32ListFirst = NULL;
static HEAPLISTWALK pHeap32ListNext = NULL;
static HEAPFIRST pHeap32First = NULL;
static HEAPNEXT pHeap32Next = NULL;
/* Since there are a significant number of ToolHelp data blocks, we use a
larger-than-usual intermediate buffer to cut down on kernel traffic */
#define BIG_RANDOM_BUFSIZE ( RANDOM_BUFSIZE * 4 )
static void slowPollWin95( void )
{
BYTE buffer[ BIG_RANDOM_BUFSIZE ];
PROCESSENTRY32 pe32;
THREADENTRY32 te32;
MODULEENTRY32 me32;
HEAPLIST32 hl32;
HANDLE hSnapshot;
int quality = 100, bufIndex = 0;
/* Initialize the Toolhelp32 function pointers if necessary */
if( pCreateToolhelp32Snapshot == NULL )
{
HANDLE hKernel = NULL;
/* Obtain the module handle of the kernel to retrieve the addresses
of the Toolhelp32 functions */
if( ( hKernel = GetModuleHandle( "KERNEL32.DLL" ) ) == NULL )
return;
/* Now get pointers to the functions */
pCreateToolhelp32Snapshot = ( CREATESNAPSHOT ) GetProcAddress( hKernel,
"CreateToolhelp32Snapshot" );
pModule32First = ( MODULEWALK ) GetProcAddress( hKernel,
"Module32First" );
pModule32Next = ( MODULEWALK ) GetProcAddress( hKernel,
"Module32Next" );
pProcess32First = ( PROCESSWALK ) GetProcAddress( hKernel,
"Process32First" );
pProcess32Next = ( PROCESSWALK ) GetProcAddress( hKernel,
"Process32Next" );
pThread32First = ( THREADWALK ) GetProcAddress( hKernel,
"Thread32First" );
pThread32Next = ( THREADWALK ) GetProcAddress( hKernel,
"Thread32Next" );
pHeap32ListFirst = ( HEAPLISTWALK ) GetProcAddress( hKernel,
"Heap32ListFirst" );
pHeap32ListNext = ( HEAPLISTWALK ) GetProcAddress( hKernel,
"Heap32ListNext" );
pHeap32First = ( HEAPFIRST ) GetProcAddress( hKernel,
"Heap32First" );
pHeap32Next = ( HEAPNEXT ) GetProcAddress( hKernel,
"Heap32Next" );
/* Make sure we got valid pointers for every Toolhelp32 function */
if( pModule32First == NULL || pModule32Next == NULL || \
pProcess32First == NULL || pProcess32Next == NULL || \
pThread32First == NULL || pThread32Next == NULL || \
pHeap32ListFirst == NULL || pHeap32ListNext == NULL || \
pHeap32First == NULL || pHeap32Next == NULL || \
pCreateToolhelp32Snapshot == NULL )
{
/* Mark the main function as unavailable in case for future
reference */
pCreateToolhelp32Snapshot = NULL;
return;
}
}
/* Take a snapshot of everything we can get to which is currently
in the system */
hSnapshot = pCreateToolhelp32Snapshot( TH32CS_SNAPALL, 0 );
if( !hSnapshot )
return;
/* Walk through the local heap */
hl32.dwSize = sizeof( HEAPLIST32 );
if( pHeap32ListFirst( hSnapshot, &hl32 ) )
do
{
HEAPENTRY32 he32;
/* First add the information from the basic Heaplist32
structure */
addRandomString( buffer, &bufIndex, BIG_RANDOM_BUFSIZE,
&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
addRandomString( buffer, &bufIndex, BIG_RANDOM_BUFSIZE,
&he32, sizeof( HEAPENTRY32 ) );
while( pHeap32Next( &he32 ) );
}
while( pHeap32ListNext( hSnapshot, &hl32 ) );
/* Walk through all processes */
pe32.dwSize = sizeof( PROCESSENTRY32 );
if( pProcess32First( hSnapshot, &pe32 ) )
do
addRandomString( buffer, &bufIndex, BIG_RANDOM_BUFSIZE,
&pe32, sizeof( PROCESSENTRY32 ) );
while( pProcess32Next( hSnapshot, &pe32 ) );
/* Walk through all threads */
te32.dwSize = sizeof( THREADENTRY32 );
if( pThread32First( hSnapshot, &te32 ) )
do
addRandomString( buffer, &bufIndex, BIG_RANDOM_BUFSIZE,
&te32, sizeof( THREADENTRY32 ) );
while( pThread32Next( hSnapshot, &te32 ) );
/* Walk through all modules associated with the process */
me32.dwSize = sizeof( MODULEENTRY32 );
if( pModule32First( hSnapshot, &me32 ) )
do
addRandomString( buffer, &bufIndex, BIG_RANDOM_BUFSIZE,
&me32, sizeof( MODULEENTRY32 ) );
while( pModule32Next( hSnapshot, &me32 ) );
/* Clean up the snapshot */
CloseHandle( hSnapshot );
/* Flush any remaining data through */
addRandomString( buffer, &bufIndex, BIG_RANDOM_BUFSIZE, NULL, 0 );
krnlSendMessage( SYSTEM_OBJECT_HANDLE, RESOURCE_IMESSAGE_SETATTRIBUTE,
&quality, CRYPT_IATTRIBUTE_RANDOM_QUALITY );
}
/* Perform a thread-safe slow poll for Windows 95. The following function
*must* be started as a thread */
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;
}
/* 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 );
setResourceData( &msgData, lpBuffer, dwSize );
krnlSendMessage( SYSTEM_OBJECT_HANDLE, RESOURCE_IMESSAGE_SETATTRIBUTE_S,
&msgData, CRYPT_IATTRIBUTE_RANDOM );
pNetApiBufferFree( lpBuffer );
}
/* Get disk I/O statistics for all the hard drives */
for( nDrive = 0;; nDrive++ )
{
DISK_PERFORMANCE diskPerformance;
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 off
by default */
if( DeviceIoControl( hDevice, IOCTL_DISK_PERFORMANCE, NULL, 0,
&diskPerformance, sizeof( DISK_PERFORMANCE ),
&dwSize, NULL ) )
{
setResourceData( &msgData, &diskPerformance, dwSize );
krnlSendMessage( SYSTEM_OBJECT_HANDLE,
RESOURCE_IMESSAGE_SETATTRIBUTE_S, &msgData,
CRYPT_IATTRIBUTE_RANDOM );
}
CloseHandle( hDevice );
}
/* 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 which 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
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 which are never the same and can't be reproduced on any
other system, which is why we take the rather drastic step of using the
native API here */
if( hNTAPI != NULL )
{
void *buffer = malloc( PERFORMANCE_BUFFER_SIZE );
if( buffer != NULL )
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -