Windows RtlQueryEnvironmentVariable用于什么?

Windows RtlQueryEnvironmentVariable用于什么?,windows,ntdll,Windows,Ntdll,最近我一直在搞乱Windows,我在ntdll.dll中遇到了这个函数 我尝试过搜索,但似乎根本没有相关文档 有人能告诉我它查询的是什么样的环境变量吗?看到我很可能在这种奇怪的事情上得不到什么帮助(或者更确切地说,我很不耐烦),我决定自己做一些研究 下面是我为理解函数而编写的一些伪代码:(向下滚动查找TL;DR) TL;DR 这基本上是在PEB->ProcessParameters->Reserved2(环境)中检查环境变量,并在传递的指针中返回它 它检查缓存,并使案例正常化。看到我很可能在类似

最近我一直在搞乱Windows,我在
ntdll.dll
中遇到了这个函数

我尝试过搜索,但似乎根本没有相关文档


有人能告诉我它查询的是什么样的环境变量吗?

看到我很可能在这种奇怪的事情上得不到什么帮助(或者更确切地说,我很不耐烦),我决定自己做一些研究

下面是我为理解函数而编写的一些伪代码:(向下滚动查找TL;DR)

TL;DR 这基本上是在PEB->ProcessParameters->Reserved2(环境)中检查环境变量,并在传递的指针中返回它


它检查缓存,并使案例正常化。

看到我很可能在类似这样奇怪的事情上得不到什么帮助(或者更确切地说,我不耐烦了),我决定自己做一些研究

下面是我为理解函数而编写的一些伪代码:(向下滚动查找TL;DR)

TL;DR 这基本上是在PEB->ProcessParameters->Reserved2(环境)中检查环境变量,并在传递的指针中返回它


它检查缓存,并使案例正常化。

看到我很可能在类似这样奇怪的事情上得不到什么帮助(或者更确切地说,我不耐烦了),我决定自己做一些研究

下面是我为理解函数而编写的一些伪代码:(向下滚动查找TL;DR)

TL;DR 这基本上是在PEB->ProcessParameters->Reserved2(环境)中检查环境变量,并在传递的指针中返回它


它检查缓存,并使案例正常化。

看到我很可能在类似这样奇怪的事情上得不到什么帮助(或者更确切地说,我不耐烦了),我决定自己做一些研究

下面是我为理解函数而编写的一些伪代码:(向下滚动查找TL;DR)

TL;DR 这基本上是在PEB->ProcessParameters->Reserved2(环境)中检查环境变量,并在传递的指针中返回它

它检查缓存,并规范化大小写

// 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;
}