什么是RtlQueryEnvironmentVariable?

时间:2015-02-07 00:11:06

标签: windows ntdll

最近我一直在搞乱Windows,我在ntdll.dll中遇到了这个功能。

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

有人可以提示我查询了哪种环境变量吗?

1 个答案:

答案 0 :(得分:2)

看到我最有可能得到一些奇怪的东西(或者更确切地说,我不耐烦),我决定自己做一些研究。

这里有一些我用来理解功能的伪代码:(向下滚动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-&gt; ProcessParameters-&gt; Reserved2(Environment)中的环境变量,并在传递的指针中返回它。

检查缓存,并对案例进行规范化。