从C ++中的二进制路径(命令行语句)中获取ProcessID

时间:2017-08-26 01:05:11

标签: c++ windows process

我需要找到一个特定的svchost进程。我唯一拥有的是命令行语句(二进制路径):c:\windows\system32\svchost.exe -k netsvcs -s Themes。 如何从中获取processID?

1 个答案:

答案 0 :(得分:0)

当然不可能从命令行直接获取进程ID。反之亦然 - 从进程ID获取进程命令行。所以可以枚举所有进程并查询它的命令行。并将它与你的字符串进行比较(和你所拥有的有趣的是命令行语句“?它是硬编码的?

WINBLUE开始(win 8.1)存在特殊PROCESSINFOCLASS - ProcessCommandLineInformation(从8.1或10 wdk查看<ntddk.h>)。有了这个,我们可以将进程命令行作为unicode字符串。这将适用于本机和wow64进程。另外,进程句柄只有PROCESS_QUERY_LIMITED_INFORMATION访问权限。如果我们有SE_DEBUG_PRIVILEGE,我们可以用这个打开所有进程。如果我们没有 - 所有,除了受保护的进程。所以 WINBLUE +的代码将是:

volatile UCHAR guz;
OBJECT_ATTRIBUTES zoa = { sizeof(zoa) };

// since WINBLUE (8.1)
NTSTATUS GetProcessCommandLine8(HANDLE UniqueProcess, PUNICODE_STRING CommandLine)
{
    HANDLE hProcess;
    CLIENT_ID cid = { UniqueProcess };

    NTSTATUS status = NtOpenProcess(&hProcess, PROCESS_QUERY_LIMITED_INFORMATION, &zoa, &cid);

    if (0 <= status)
    {
        PVOID stack = alloca(guz);

        union {
            PVOID buf;
            PUNICODE_STRING CmdLine;
        };

        ULONG cb = 0, rcb = 512;

        do 
        {
            if (cb < rcb) cb = RtlPointerToOffset(buf = alloca(rcb - cb), stack);

            if (0 <= (status = NtQueryInformationProcess(hProcess, ProcessCommandLineInformation, buf, cb, &rcb)))
            {
                status = RtlDuplicateUnicodeString(RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE, CmdLine, CommandLine);
                break;
            }

        } while (status == STATUS_INFO_LENGTH_MISMATCH);

        NtClose(hProcess);
    }

    return status;
}

但旧系统变得更加复杂。需要首先查询ProcessBasicInformation以获取进程 PEB 地址,而不是从 PEB 获取ProcessParametersRTL_USER_PROCESS_PARAMETERS)的地址。最后从中读取CommandLineUNICODE_STRING)。但是对于这种需要,首先是PROCESS_QUERY_INFORMATION|PROCESS_VM_READ访问权限的开放流程。因此,即使我们有SE_DEBUG_PRIVILEGE,我们也无法打开受保护的进程,如果我们没有它 - 我们通常可以从自己的登录会话中打开进程(因此对于所有提升的进程,所有系统进程都会失败)。在第二个需要为native和wow64编写不同的代码:如果我们的代码是32位 - 需要检查我们是否wow64进程,如果是 - 首先查询NtWow64QueryInformationProcess64NtWow64ReadVirtualMemory64,然后才能开始查询过程cmd line。

本机进程的代码:

NTSTATUS GetProcessCommandLineOldNative(HANDLE UniqueProcess, PUNICODE_STRING CommandLine)
{
    HANDLE hProcess;
    CLIENT_ID cid = { UniqueProcess };

    NTSTATUS status = NtOpenProcess(&hProcess, PROCESS_QUERY_INFORMATION|PROCESS_VM_READ, &zoa, &cid);

    if (0 <= status)
    {
        PROCESS_BASIC_INFORMATION pbi;
        UNICODE_STRING CmdLine;
        union {
            _RTL_USER_PROCESS_PARAMETERS * ProcessParameters;
            PVOID buf;
            PWSTR psz;
        };
        if (
            0 <= (status = NtQueryInformationProcess(hProcess, ProcessBasicInformation, &pbi, sizeof(pbi), 0)) &&
            0 <= (status = ZwReadVirtualMemory(hProcess, &((_PEB*)pbi.PebBaseAddress)->ProcessParameters, &ProcessParameters, sizeof(ProcessParameters), 0)) &&
            0 <= (status = ZwReadVirtualMemory(hProcess, &ProcessParameters->CommandLine, &CmdLine, sizeof(CmdLine), 0)) &&
            0 <= (status = ZwReadVirtualMemory(hProcess, CmdLine.Buffer, buf = alloca(CmdLine.Length), CmdLine.Length, 0))
            )
        {
            CmdLine.Buffer = psz;
            status = RtlDuplicateUnicodeString(RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE, &CmdLine, CommandLine);
        }

        NtClose(hProcess);
    }

    return status;
}

对于wow64进程:

#ifndef _WIN64

extern "C" 
{
    __declspec(dllimport) 
    NTSTATUS NTAPI NtWow64QueryInformationProcess64 (
        HANDLE ProcessHandle,
        PROCESSINFOCLASS ProcessInformationClass,
        PVOID ProcessInformation,
        ULONG ProcessInformationLength,
        PULONG ReturnLength
        );

    __declspec(dllimport) 
    NTSTATUS NTAPI NtWow64ReadVirtualMemory64(
        HANDLE ProcessHandle,
        UINT64 BaseAddress,
        PVOID Buffer,
        ULONG64 Size,
        PULONG64 NumberOfBytesRead
        );

    PVOID __imp_NtWow64ReadVirtualMemory64, __imp_NtWow64QueryInformationProcess64;
}

#ifdef _M_IX86
#pragma comment(linker, "/alternatename:__imp__NtWow64ReadVirtualMemory64@28=___imp_NtWow64ReadVirtualMemory64")
#pragma comment(linker, "/alternatename:__imp__NtWow64QueryInformationProcess64@20=___imp_NtWow64QueryInformationProcess64")
#endif

NTSTATUS GetProcessCommandLineOldWow(HANDLE UniqueProcess, PUNICODE_STRING CommandLine)
{
    struct PROCESS_BASIC_INFORMATION_64 {
        NTSTATUS ExitStatus;
        UINT64 PebBaseAddress;
        UINT64 AffinityMask;
        KPRIORITY BasePriority;
        UINT64 UniqueProcessId;
        UINT64 InheritedFromUniqueProcessId;
    };

    struct PEB_64
    {
        UCHAR InheritedAddressSpace;
        UCHAR ReadImageFileExecOptions;
        UCHAR BeingDebugged;
        UCHAR SpareBool;
        UINT64 Mutant;
        UINT64 ImageBaseAddress;
        UINT64 Ldr;
        UINT64 ProcessParameters;
    };

    struct UNICODE_STRING_64 {
        USHORT Length;
        USHORT MaximumLength;
        UINT64 Buffer;
    };

    struct CURDIR_64 {
        UNICODE_STRING_64 DosPath;
        UINT64 Handle;
    };

    struct RTL_USER_PROCESS_PARAMETERS_64 {
        ULONG MaximumLength;
        ULONG Length;
        ULONG Flags;
        ULONG DebugFlags;
        UINT64 ConsoleHandle;
        ULONG ConsoleFlags;
        UINT64 StandardInput;
        UINT64 StandardOutput;
        UINT64 StandardError;
        CURDIR_64 CurrentDirectory;
        UNICODE_STRING_64 DllPath;
        UNICODE_STRING_64 ImagePathName;
        UNICODE_STRING_64 CommandLine;
        /*...*/
    };

    HANDLE hProcess;
    CLIENT_ID cid = { UniqueProcess };

    NTSTATUS status = NtOpenProcess(&hProcess, PROCESS_QUERY_INFORMATION|PROCESS_VM_READ, &zoa, &cid);

    if (0 <= status)
    {
        PROCESS_BASIC_INFORMATION_64 pbi;
        UNICODE_STRING_64 CmdLine;
        UNICODE_STRING cl;
        UINT64 ProcessParameters;

        if (
            0 <= (status = NtWow64QueryInformationProcess64(hProcess, ProcessBasicInformation, &pbi, sizeof(pbi), 0)) &&
            0 <= (status = NtWow64ReadVirtualMemory64(hProcess, pbi.PebBaseAddress + FIELD_OFFSET(PEB_64, ProcessParameters), &ProcessParameters, sizeof(ProcessParameters), 0)) &&
            0 <= (status = NtWow64ReadVirtualMemory64(hProcess, ProcessParameters + FIELD_OFFSET(RTL_USER_PROCESS_PARAMETERS_64, CommandLine), &CmdLine, sizeof(CmdLine), 0)) &&
            0 <= (status = NtWow64ReadVirtualMemory64(hProcess, CmdLine.Buffer, cl.Buffer = (PWSTR)alloca(CmdLine.Length), CmdLine.Length, 0))
            )
        {
            cl.Length = CmdLine.Length, cl.MaximumLength = CmdLine.MaximumLength;
            status = RtlDuplicateUnicodeString(RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE, &cl, CommandLine);
        }

        NtClose(hProcess);
    }

    return status;
}

NTSTATUS GetProcessCommandLineFail(HANDLE , PUNICODE_STRING )
{
    return STATUS_UNSUCCESSFUL;
}

#endif//_WIN64

最后在开始时我们需要确定的Windows版本和(如果版本&lt; 8.1)wow64和一旦选择get process cmdline的过程:

NTSTATUS (*GetProcessCommandLine)(HANDLE UniqueProcess, PUNICODE_STRING CommandLine);

WORD gosVersion;

void InitQueryCmdLine()
{
    BOOLEAN b;
    RtlAdjustPrivilege(SE_DEBUG_PRIVILEGE, TRUE, FALSE, &b);

    ULONG dwMajorVersion, dwMinorVersion;
    RtlGetNtVersionNumbers(&dwMajorVersion, &dwMinorVersion, 0);
    gosVersion = MAKEWORD(dwMinorVersion, dwMajorVersion);

    if (gosVersion < _WIN32_WINNT_WINBLUE)
    {
#ifdef _WIN64
        GetProcessCommandLine = GetProcessCommandLineOldNative;
#else
        GetProcessCommandLine = GetProcessCommandLineFail;

        PVOID wow64peb;
        if (0 <= NtQueryInformationProcess(NtCurrentProcess(), ProcessWow64Information, &wow64peb, sizeof(wow64peb), 0))
        {
            if (wow64peb)
            {
                if (HMODULE hmod = GetModuleHandle(L"ntdll"))
                {
                    if ((__imp_NtWow64ReadVirtualMemory64 = GetProcAddress(hmod, "NtWow64ReadVirtualMemory64")) &&
                        (__imp_NtWow64QueryInformationProcess64 = GetProcAddress(hmod, "NtWow64QueryInformationProcess64")))
                    {
                        GetProcessCommandLine = GetProcessCommandLineOldWow;
                    }
                }
            }
            else
            {
                GetProcessCommandLine = GetProcessCommandLineOldNative;
            }
        }
#endif
    }
    else
    {
        GetProcessCommandLine = GetProcessCommandLine8;
    }
}

之后,我们可以为每个进程枚举进程和查询命令行。

void DumpCmdLines()
{
    ULONG cb = 0, rcb = 0x10000;
    PVOID stack = alloca(guz);

    union {
        PVOID buf;
        PBYTE pb;
        PSYSTEM_PROCESS_INFORMATION pspi;
    };

    NTSTATUS status;
    do 
    {
        if (cb < rcb)
        {
            cb = RtlPointerToOffset(buf = alloca(0x1000 + rcb - cb), stack);
        }

        if (0 <= (status = ZwQuerySystemInformation(SystemProcessInformation, buf, cb, &rcb)))
        {
            ULONG NextEntryOffset = 0;
            do 
            {
                pb += NextEntryOffset;

                if (HANDLE UniqueProcessId = pspi->UniqueProcessId)
                {
                    UNICODE_STRING CommandLine;
                    status = GetProcessCommandLine(UniqueProcessId, &CommandLine);
                    if (0 > status)
                    {
                        DbgPrint("%p <%wZ> error=%x\n", UniqueProcessId, &pspi->ImageName, status);
                    }
                    else
                    {
                        DbgPrint("%p <%wZ> <%wZ>\n", UniqueProcessId, &pspi->ImageName, &CommandLine);
                        RtlFreeUnicodeString(&CommandLine);
                    }
                }

            } while (NextEntryOffset = pspi->NextEntryOffset);

            break;
        }

    } while (status == STATUS_INFO_LENGTH_MISMATCH);
}

和可能的结果(win10)

00000004 <System> error=c0000225
0000015C <smss.exe> <\SystemRoot\System32\smss.exe>
000001D4 <csrss.exe> <%SystemRoot%\system32\csrss.exe ObjectDirectory=\Windows SharedSection=1024,20480,768 Windows=On SubSystemType=Windows ServerDll=basesrv,1 ServerDll=winsrv:UserServerDllInitialization,3 ServerDll=sxssrv,4 ProfileControl=Off MaxRequestThreads=16>
00000234 <wininit.exe> <wininit.exe>
0000023C <csrss.exe> <%SystemRoot%\system32\csrss.exe ObjectDirectory=\Windows SharedSection=1024,20480,768 Windows=On SubSystemType=Windows ServerDll=basesrv,1 ServerDll=winsrv:UserServerDllInitialization,3 ServerDll=sxssrv,4 ProfileControl=Off MaxRequestThreads=16>
00000294 <winlogon.exe> <winlogon.exe>
000002C0 <services.exe> <C:\Windows\system32\services.exe>
000002C8 <lsass.exe> <C:\Windows\system32\lsass.exe>
0000032C <svchost.exe> <C:\Windows\system32\svchost.exe -k DcomLaunch>
0000036C <svchost.exe> <C:\Windows\system32\svchost.exe -k RPCSS>
000003D8 <dwm.exe> <"dwm.exe">
00000060 <svchost.exe> <C:\Windows\system32\svchost.exe -k netsvcs>
00000144 <svchost.exe> <C:\Windows\System32\svchost.exe -k LocalServiceNetworkRestricted>
00000300 <svchost.exe> <C:\Windows\system32\svchost.exe -k LocalSystemNetworkRestricted>
00000408 <svchost.exe> <C:\Windows\system32\svchost.exe -k LocalServiceNoNetwork>
0000044C <svchost.exe> <C:\Windows\system32\svchost.exe -k LocalService>
00000518 <svchost.exe> <C:\Windows\System32\svchost.exe -k LocalServiceNetworkRestricted>
00000550 <svchost.exe> <C:\Windows\system32\svchost.exe -k LocalServiceNetworkRestricted>
00000564 <svchost.exe> <C:\Windows\system32\svchost.exe -k NetworkService>
00000670 <svchost.exe> <C:\Windows\system32\svchost.exe -k imgsvc>
00000688 <svchost.exe> <C:\Windows\system32\svchost.exe -k appmodel>
00000698 <dasHost.exe> <dashost.exe {d48bf429-3cb0-4538-8bc9147caa7c9ef1}>
00000AE4 <sihost.exe> <sihost.exe>
00000B00 <taskhostw.exe> <taskhostw.exe {222A245B-E637-4AE9-A93F-A59CA119A75E}>
00000A2C <explorer.exe> <C:\Windows\Explorer.EXE>
00000A64 <RuntimeBroker.exe> <C:\Windows\System32\RuntimeBroker.exe -Embedding>
00000C2C <ShellExperienceHost.exe> <"C:\Windows\SystemApps\ShellExperienceHost_cw5n1h2txyewy\ShellExperienceHost.exe" -ServerName:App.AppXtk181tbxbce2qsex02s8tw7hfxa9xb3t.mca>
00000C84 <SearchUI.exe> <"C:\Windows\SystemApps\Microsoft.Windows.Cortana_cw5n1h2txyewy\SearchUI.exe" -ServerName:CortanaUI.AppXa50dqqa5gqv4a428c9y1jjw7m3btvepj.mca>
00000E38 <InstallAgent.exe> <C:\Windows\System32\InstallAgent.exe -Embedding>
00000E8C <InstallAgentUserBroker.exe> <C:\Windows\System32\InstallAgentUserBroker.exe -Embedding>
0000089C <WUDFHost.exe> <"C:\Windows\System32\WUDFHost.exe" -HostGUID:{193a1820-d9ac-4997-8c55-be817523f6aa} -IoEventPortName:HostProcess-cfc003bd-dfb8-4921-bf6c-d6392e543bad -SystemEventPortName:HostProcess-91a86d23-34aa-4a16-9d90-8417b8b3531f -IoCancelEventPortName:HostProcess-126930e6-a2d4-492d-87d4-837dcc9de0f1 -NonStateChangingEventPortName:HostProcess-13646e1e-5d48-479e-a391-22f24bfd3b7c -ServiceSID:S-1-5-80-2652678385-582572993-1835434367-1344795993-749280709 -LifetimeId:be105ab5-26a2-45ef-b565-1b2
0000052C <fontdrvhost.exe> <"fontdrvhost.exe">