📄 rndwin32.c
字号:
addRandomValue( randomState, GetInputState() );
addRandomValue( randomState, GetMessagePos() );
addRandomValue( randomState, GetMessageTime() );
addRandomValue( randomState, GetOpenClipboardWindow() );
addRandomValue( randomState, GetProcessHeap() );
addRandomValue( randomState, GetProcessWindowStation() );
addRandomValue( randomState, GetTickCount() );
checkPollExit();
/* Calling the following function can cause problems in some cases in
that a calling application eventually stops getting events from its
event loop, so we can't (safely) use it as an entropy source */
/* addRandomValue( randomState, GetQueueStatus( QS_ALLEVENTS ) ); */
/* Get multiword system information: Current caret position, current
mouse cursor position */
GetCaretPos( &point );
addRandomData( randomState, &point, sizeof( POINT ) );
GetCursorPos( &point );
addRandomData( randomState, &point, sizeof( POINT ) );
/* Get percent of memory in use, bytes of physical memory, bytes of free
physical memory, bytes in paging file, free bytes in paging file, user
bytes of address space, and free user bytes */
memoryStatus.dwLength = sizeof( MEMORYSTATUS );
GlobalMemoryStatus( &memoryStatus );
addRandomData( randomState, &memoryStatus, sizeof( MEMORYSTATUS ) );
/* Get thread and process creation time, exit time, time in kernel mode,
and time in user mode in 100ns intervals */
handle = GetCurrentThread();
GetThreadTimes( handle, &creationTime, &exitTime, &kernelTime, &userTime );
addRandomData( randomState, &creationTime, sizeof( FILETIME ) );
addRandomData( randomState, &exitTime, sizeof( FILETIME ) );
addRandomData( randomState, &kernelTime, sizeof( FILETIME ) );
addRandomData( randomState, &userTime, sizeof( FILETIME ) );
handle = GetCurrentProcess();
GetProcessTimes( handle, &creationTime, &exitTime, &kernelTime, &userTime );
addRandomData( randomState, &creationTime, sizeof( FILETIME ) );
addRandomData( randomState, &exitTime, sizeof( FILETIME ) );
addRandomData( randomState, &kernelTime, sizeof( FILETIME ) );
addRandomData( randomState, &userTime, sizeof( FILETIME ) );
/* Get the minimum and maximum working set size for the current process */
GetProcessWorkingSetSize( handle, &minimumWorkingSetSize,
&maximumWorkingSetSize );
addRandomValue( randomState, minimumWorkingSetSize );
addRandomValue( randomState, maximumWorkingSetSize );
/* The following are fixed for the lifetime of the process so we only
add them once */
if( !addedFixedItems )
{
STARTUPINFO startupInfo;
char vendorID[ 12 ];
unsigned long processorID, featureFlags;
/* Get name of desktop, console window title, new window position and
size, window flags, and handles for stdin, stdout, and stderr */
startupInfo.cb = sizeof( STARTUPINFO );
GetStartupInfo( &startupInfo );
addRandomData( randomState, &startupInfo, sizeof( STARTUPINFO ) );
addedFixedItems = TRUE;
/* Check whether the CPU supports extended features like CPUID and
RDTSC, and get any info we need related to this. There is an
IsProcessorFeaturePresent() function, but all that this provides
is an indication of the availability of rdtsc (alongside some
stuff we don't care about, like MMX and 3DNow). Since we still
need to check for the presence of other features, we do the whole
thing ourselves */
_asm {
/* Detect the CPU type */
pushfd
pop eax /* Get EFLAGS in eax */
mov ebx, eax /* Save a copy for later */
xor eax, 0x200000 /* Toggle the CPUID bit */
push eax
popfd /* Update EFLAGS */
pushfd
pop eax /* Get updated EFLAGS back in eax */
push ebx
popfd /* Restore original EFLAGS */
xor eax, ebx /* Check if we could toggle CPUID bit */
jz noCPUID /* Nope, we can't do anything further */
mov [hasAdvFeatures], 1 /* Remember that we have CPUID, RDTSC */
/* We have CPUID, see what we've got */
xor ecx, ecx
xor edx, edx /* Tell VC++ that ECX, EDX will be trashed */
xor eax, eax /* CPUID function 0: */
cpuid
mov dword ptr [vendorID], ebx
mov dword ptr [vendorID+4], edx
mov dword ptr [vendorID+8], ecx /* Save vendor ID string */
mov eax, 1 /* CPUID function 1: */
cpuid
mov [processorID], eax /* Save processor ID */
mov [featureFlags], edx /* Save processor feature info */
noCPUID:
}
/* If there's a vendor ID present, check for vendor-specific
special features */
if( hasAdvFeatures && !memcmp( vendorID, "CentaurHauls", 12 ) )
{
_asm {
xor ebx, ebx
xor ecx, ecx /* Tell VC++ that EBX, ECX will be trashed */
mov eax, 0xC0000000 /* Centaur extended CPUID info */
cpuid
cmp eax, 0xC0000001 /* Need at least release 2 ext.feature set */
jb noRNG /* No extended info available */
mov eax, 0xC0000001 /* Centaur extended feature flags */
cpuid
and edx, 01100b
cmp edx, 01100b /* Check for RNG present + enabled flags */
jne noRNG /* No, RNG not present or enabled */
mov [hasHardwareRNG], 1 /* Remember that we have a hardware RNG */
noRNG:
}
}
}
/* The performance of QPC varies depending on the architecture it's
running on and on the OS, the MS documentation is vague about the
details because it varies so much. Under Win9x/ME it reads the
1.193180 MHz PIC timer. Under NT/Win2K/XP it may or may not read the
64-bit TSC depending on the HAL and assorted other circumstances,
generally on machines with a uniprocessor HAL
KeQueryPerformanceCounter() uses a 3.579545MHz timer and on machines
with a multiprocessor or APIC HAL it uses the TSC (the exact time
source is controlled by the HalpUse8254 flag in the kernel). That
choice of time sources is somewhat peculiar because on a
multiprocessor machine it's theoretically possible to get completely
different TSC readings depending on which CPU you're currently
running on, while for uniprocessor machines it's not a problem.
However, the kernel appears to synchronise the TSCs across CPUs at
boot time (it resets the TSC as part of its system init), so this
shouldn't really be a problem. Under WinCE it's completely platform-
dependant, if there's no hardware performance counter available, it
uses the 1ms system timer.
Another feature of the TSC (although it doesn't really affect us here)
is that mobile CPUs will turn off the TSC when they idle, Pentiums
will change the rate of the counter when they clock-throttle (to
match the current CPU speed), and hyperthreading Pentiums will turn
it off when both threads are idle (this more or less makes sense,
since the CPU will be in the halted state and not executing any
instructions to count).
To make things unambiguous, we detect a CPU new enough to call RDTSC
directly by checking for CPUID capabilities, and fall back to QPC if
this isn't present */
if( hasAdvFeatures )
{
unsigned long value;
__asm {
xor eax, eax
xor edx, edx /* Tell VC++ that EDX:EAX will be trashed */
rdtsc
mov [value], eax /* Ignore high 32 bits, which are > 1s res */
}
addRandomValue( randomState, &value );
}
else
if( QueryPerformanceCounter( &performanceCount ) )
addRandomData( randomState, &performanceCount,
sizeof( LARGE_INTEGER ) );
else
/* Millisecond accuracy at best... */
addRandomValue( randomState, GetTickCount() );
/* If there's a hardware RNG present, read data from it. We check that
the RNG is still present on each fetch since it could (at least in
theory) be disabled by the OS between fetches. We also read the data
into an explicitly dword-aligned buffer (which the standard buffer
should be anyway, but we make it explicit here just to be safe). Note
that we have to force alignment using a LONGLONG rather than a #pragma
pack, since chars don't need alignment it would have no effect on the
BYTE [] member */
if( hasHardwareRNG )
{
struct alignStruct {
LONGLONG dummy1; /* Force alignment of following member */
BYTE buffer[ 64 ];
};
struct alignStruct *rngBuffer = ( struct alignStruct * ) buffer;
void *bufPtr = rngBuffer->buffer; /* Get it into a form asm can handle */
int byteCount = 0;
_asm {
push es
xor ecx, ecx /* Tell VC++ that ECX will be trashed */
mov eax, 0xC0000001 /* Centaur extended feature flags */
cpuid
and edx, 01100b
cmp edx, 01100b /* Check for RNG present + enabled flags */
jne rngDisabled /* RNG was disabled after our initial check */
push ds
pop es
mov edi, bufPtr /* ES:EDI = buffer */
xor edx, edx /* Fetch 8 bytes */
xstore_rng
and eax, 011111b /* Get count of bytes returned */
jz rngDisabled /* Nothing read, exit */
mov [byteCount], eax
rngDisabled:
pop es
}
if( byteCount > 0 )
addRandomData( randomState, bufPtr, byteCount );
}
/* Flush any remaining data through. Quality = int( 33 1/3 % ) */
endRandomData( randomState, 34 );
}
/****************************************************************************
* *
* Slow Poll *
* *
****************************************************************************/
/* Type definitions for function pointers to call Toolhelp32 functions */
typedef BOOL ( WINAPI *MODULEWALK )( HANDLE hSnapshot, LPMODULEENTRY32 lpme );
typedef BOOL ( WINAPI *THREADWALK )( HANDLE hSnapshot, LPTHREADENTRY32 lpte );
typedef BOOL ( WINAPI *PROCESSWALK )( HANDLE hSnapshot, LPPROCESSENTRY32 lppe );
typedef BOOL ( WINAPI *HEAPLISTWALK )( HANDLE hSnapshot, LPHEAPLIST32 lphl );
typedef BOOL ( WINAPI *HEAPFIRST )( LPHEAPENTRY32 lphe, DWORD th32ProcessID, DWORD th32HeapID );
typedef BOOL ( WINAPI *HEAPNEXT )( LPHEAPENTRY32 lphe );
typedef HANDLE ( WINAPI *CREATESNAPSHOT )( DWORD dwFlags, DWORD th32ProcessID );
/* Global function pointers. These are necessary because the functions need to
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 )
{
PROCESSENTRY32 pe32;
THREADENTRY32 te32;
MODULEENTRY32 me32;
HEAPLIST32 hl32;
HANDLE hSnapshot;
RANDOM_STATE randomState;
BYTE buffer[ BIG_RANDOM_BUFSIZE ];
int bufIndex = 0, listCount = 0;
/* Initialize the Toolhelp32 function pointers if necessary */
if( pCreateToolhelp32Snapshot == NULL )
{
HANDLE hKernel;
/* 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;
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -