最近我一直在搞乱 Windows,我在ntdll.dll
.
我尝试搜索,但似乎根本没有任何文档。
有人可以提示我它查询什么样的环境变量吗?
看到我很可能在这种奇怪的事情上得不到什么帮助(或者更确切地说,我很不耐烦),我决定自己做一些研究。
这是我为理解该功能而编写的一些伪代码:(向下滚动以获取 TL;DR)
// Credits to:
// -> http://filelog.net/func/RtlQueryEnvironmentVariable
// For helping with the arguments' names and types
// -> IDA Pro
// -> NirSoft for the RTL_CRITICAL_SECTION structure
// http://www.nirsoft.net/kernel_struct/vista/RTL_CRITICAL_SECTION.html
// https://msdn.microsoft.com/en-us/library/cc704588.aspx
#ifndef STATUS_VARIABLE_NOT_FOUND
#define STATUS_VARIABLE_NOT_FOUND 0xC0000100
#endif
NTSTATUS __stdcall RtlQueryEnvironmentVariable(PVOID Environment, PWSTR Name, size_t NameLength, PWSTR Value, size_t ValueLength, PSIZE_T ReturnLength){
// Here happens some exception stuff
// ...
// Return variable
NTSTATUS ret;
// PEB environment
PVOID pEnv = &teb->ProcessEnvironmentBlock->ProcessParameters->Environment;
// mov ebx, [ebp+ReturnLength]
// xor esi, esi
// mov [ebx], esi
*ReturnLength = 0;
// Sanity check
if ( !NameLength )
return STATUS_VARIABLE_NOT_FOUND;
// Here happens some exception stuff
// ...
// Check the variable
NTSTATUS envVar = RtlpCheckPseudoEnvironmentVariable(Name, NameLength, Value, ValueLength, ReturnLength);
// If the variable exists, fail.
if ( envVar >= 0 ) {
goto sehReturn;
}
/* Only process variables that haven't been set as pseudo.
I could've joined this with the previous if () with ||,
but I'd rather leave it as is for easier comprehension.
Do note that this is a signed comparison, and it's why
this doesn't always simply jump to 'sehReturn'.
P.S. typedef long NTSTATUS; 'long' is signed by default */
if ( envVar != (signed int) STATUS_VARIABLE_NOT_FOUND ) {
goto sehReturn;
}
// In case there's no environment supplied, just take it from TEB->PEB->ProcessParameters->Environment
if ( !Environment ) {
// Get a pointer to TEB
TEB* teb = __readfsdword(0x18);
// Wait till we get thread-safe access to PEB
RtlEnterCriticalSection(&FastPebLock);
// Exception handling stuff
// ...
// Try to load it from cache
NTSTATUS varFromCache = RtlpQueryEnvironmentCache(
pEnv,
Name, NameLength,
Value, ValueLength,
ReturnLength
);
// Get it from the actual environment if it isn't in the cache
if ( varFromCache == STATUS_VARIABLE_NOT_FOUND ) {
varFromCache = RtlpScanEnvironment(
pEnv,
Name, NameLength,
Value, ValueLength,
ReturnLength,
// I'm not really sure what this argument is for,
// but it's set to FALSE when the environment is not
// the same as the current process or the critical
// section is locked by a thread. mainly corner cases.
TRUE
);
}
// Save return value
ret = varFromCache;
// Exception handling stuff
// ...
RtlLeaveCriticalSection(&FastPebLock);
goto sehReturn;
}
// Try to determine if environment is valid
if ( !*PWORD(Environment) ) {
ret = STATUS_VARIABLE_NOT_FOUND;
goto sehReturn;
}
RTL_CRITICAL_SECTION* pCriticalSection = teb->ProcessEnvironmentBlock->FastPebLock;
BOOL cornerCase;
// Set 'cornerCase' to FALSE if the environment is not our process'
// environment or if it is locked by a thread.
if ( pEnv != Environment || (pCriticalSection != NULL && !RtlIsCriticalSectionLockedByThread(pCriticalSection)) ) {
cornerCase = FALSE;
} else {
// If the variable is in the current process, try to take it from the cache.
NTSTATUS varFromCache = RtlpQueryEnvironmentCache(
Environment,
Name, NameLength,
Value, ValueLength,
ReturnLength
);
if ( varFromCache != STATUS_VARIABLE_NOT_FOUND ) {
ret = varFromCache;
goto sehReturn;
}
cornerCase = TRUE;
}
// Take the variable from the environment
RtlpScanEnvironment(
Environment,
Name, NameLength,
Value, ValueLength,
ReturnLength,
cornerCase
);
// Structured Exception Handler return; does some SEH stuff and returns.
sehReturn:
ms_exc.registration.TryLevel = -2;
return ret;
}
TL;DR 这基本上检查 PEB->ProcessParameters->Reserved2 (Environment) 中的环境变量,并在传递的指针中返回它。
它检查缓存,并对案例进行规范化。