天天看點

X64-R3層通過PEB擷取程序指令行參數

關于指令行參數

程序建立程序時,會傳一個指令行給它,一般其第一個内容是其可執行檔案的名稱,因為在調用

CreateProcess

時,若 applicationname參數為空(大多數情況都為空),則

CreateProcess

将會去解析指令行參數以此獲得程序映像檔案的完整路徑.一般應用雙引号

"PathName"

将完整路徑包括起來,否則應用空格與其餘指令行參數隔開,具體解析方式這裡不詳述

擷取指令行參數by PEB

其實64位與32位通過PEB擷取程序資訊并無太大差別,這裡就當練練手,其餘如加載子產品,環境變量等值都可以通過這種方法獲得,下面上代碼:

首先是頭檔案,一些結構體的定義:(适用于64位)

#pragma once
#include <Windows.h>
#include<ntstatus.h>
#include<iostream>
using namespace std;



#ifdef _WIN64
typedef unsigned long __w64 duint;
typedef signed long __w64   dsint;
#endif // _WIN64

#define RTL_MAX_DRIVE_LETTERS 32

BOOL EnableSeDebugPrivilege(IN const CHAR*  PriviledgeName, BOOL IsEnable);

typedef struct _PROCESS_BASIC_INFORMATION
{
    PVOID Reserved1;
    PVOID PebBaseAddress;
    PVOID Reserved2[2];
    ULONG_PTR UniqueProcessId;
    PVOID Reserved3;
} PROCESS_BASIC_INFORMATION;
typedef PROCESS_BASIC_INFORMATION* PPROCESS_BASIC_INFORMATION;

typedef struct _UNICODE_STRING
{
    USHORT Length;
    USHORT MaximumLength;
    PWSTR Buffer;
} UNICODE_STRING, *PUNICODE_STRING;

typedef struct _CURDIR
{
    UNICODE_STRING DosPath;
    HANDLE Handle;
} CURDIR, *PCURDIR;

typedef struct _RTL_DRIVE_LETTER_CURDIR
{
    USHORT Flags;
    USHORT Length;
    ULONG TimeStamp;
    UNICODE_STRING DosPath;
} RTL_DRIVE_LETTER_CURDIR, *PRTL_DRIVE_LETTER_CURDIR;
typedef enum _PROCESSINFOCLASS
{
    ProcessBasicInformation,
    ProcessQuotaLimits,
    ProcessIoCounters,
    ProcessVmCounters,
    ProcessTimes,
    ProcessBasePriority,
    ProcessRaisePriority,
    ProcessDebugPort,
    ProcessExceptionPort,
    ProcessAccessToken,
    ProcessLdtInformation,
    ProcessLdtSize,
    ProcessDefaultHardErrorMode,
    ProcessIoPortHandlers,          // Note: this is kernel mode only
    ProcessPooledUsageAndLimits,
    ProcessWorkingSetWatch,
    ProcessUserModeIOPL,
    ProcessEnableAlignmentFaultFixup,
    ProcessPriorityClass,
    ProcessWx86Information,
    ProcessHandleCount,
    ProcessAffinityMask,
    ProcessPriorityBoost,
    ProcessDeviceMap,
    ProcessSessionInformation,
    ProcessForegroundInformation,
    ProcessWow64Information,
    ProcessImageFileName,
    ProcessLUIDDeviceMapsEnabled,
    ProcessBreakOnTermination,
    ProcessDebugObjectHandle,
    ProcessDebugFlags,
    ProcessHandleTracing,
    ProcessIoPriority,
    ProcessExecuteFlags,
    ProcessResourceManagement,
    ProcessCookie,
    ProcessImageInformation,
    MaxProcessInfoClass             // MaxProcessInfoClass should always be the last enum
} PROCESSINFOCLASS;

typedef struct _RTL_USER_PROCESS_PARAMETERS
{
    ULONG MaximumLength;
    ULONG Length;

    ULONG Flags;
    ULONG DebugFlags;

    HANDLE ConsoleHandle;
    ULONG ConsoleFlags;
    HANDLE StandardInput;
    HANDLE StandardOutput;
    HANDLE StandardError;

    CURDIR CurrentDirectory;
    UNICODE_STRING DllPath;
    UNICODE_STRING ImagePathName;
    UNICODE_STRING CommandLine;
    PWCHAR Environment;

    ULONG StartingX;
    ULONG StartingY;
    ULONG CountX;
    ULONG CountY;
    ULONG CountCharsX;
    ULONG CountCharsY;
    ULONG FillAttribute;

    ULONG WindowFlags;
    ULONG ShowWindowFlags;
    UNICODE_STRING WindowTitle;
    UNICODE_STRING DesktopInfo;
    UNICODE_STRING ShellInfo;
    UNICODE_STRING RuntimeData;
    RTL_DRIVE_LETTER_CURDIR CurrentDirectories[RTL_MAX_DRIVE_LETTERS];

    ULONG_PTR EnvironmentSize;
    ULONG_PTR EnvironmentVersion;
    PVOID PackageDependencyData;
    ULONG ProcessGroupId;
    ULONG LoaderThreads;
} RTL_USER_PROCESS_PARAMETERS, *PRTL_USER_PROCESS_PARAMETERS;

typedef struct _PEB_LDR_DATA
{
    ULONG Length;
    BOOLEAN Initialized;
    HANDLE SsHandle;
    LIST_ENTRY InLoadOrderModuleList;
    LIST_ENTRY InMemoryOrderModuleList;
    LIST_ENTRY InInitializationOrderModuleList;
    PVOID EntryInProgress;
    BOOLEAN ShutdownInProgress;
    HANDLE ShutdownThreadId;
} PEB_LDR_DATA, *PPEB_LDR_DATA;
typedef ULONG GDI_HANDLE_BUFFER[60];
typedef struct _PEB
{
    BOOLEAN InheritedAddressSpace;
    BOOLEAN ReadImageFileExecOptions;
    BOOLEAN BeingDebugged;
    union
    {
        BOOLEAN BitField;
        struct
        {
            BOOLEAN ImageUsesLargePages : 1;
            BOOLEAN IsProtectedProcess : 1;
            BOOLEAN IsImageDynamicallyRelocated : 1;
            BOOLEAN SkipPatchingUser32Forwarders : 1;
            BOOLEAN IsPackagedProcess : 1;
            BOOLEAN IsAppContainer : 1;
            BOOLEAN IsProtectedProcessLight : 1;
            BOOLEAN IsLongPathAwareProcess : 1;
        } s1;
    } u1;

    HANDLE Mutant;

    PVOID ImageBaseAddress;
    PPEB_LDR_DATA Ldr;
    PRTL_USER_PROCESS_PARAMETERS ProcessParameters;
    PVOID SubSystemData;
    PVOID ProcessHeap;
    PRTL_CRITICAL_SECTION FastPebLock;
    PVOID AtlThunkSListPtr;
    PVOID IFEOKey;
    union
    {
        ULONG CrossProcessFlags;
        struct
        {
            ULONG ProcessInJob : 1;
            ULONG ProcessInitializing : 1;
            ULONG ProcessUsingVEH : 1;
            ULONG ProcessUsingVCH : 1;
            ULONG ProcessUsingFTH : 1;
            ULONG ProcessPreviouslyThrottled : 1;
            ULONG ProcessCurrentlyThrottled : 1;
            ULONG ReservedBits0 : 25;
        } s2;
    } u2;
    union
    {
        PVOID KernelCallbackTable;
        PVOID UserSharedInfoPtr;
    } u3;
    ULONG SystemReserved[1];
    ULONG AtlThunkSListPtr32;
    PVOID ApiSetMap;
    ULONG TlsExpansionCounter;
    PVOID TlsBitmap;
    ULONG TlsBitmapBits[2];

    PVOID ReadOnlySharedMemoryBase;
    PVOID SharedData; // HotpatchInformation
    PVOID* ReadOnlyStaticServerData;

    PVOID AnsiCodePageData; // PCPTABLEINFO
    PVOID OemCodePageData; // PCPTABLEINFO
    PVOID UnicodeCaseTableData; // PNLSTABLEINFO

    ULONG NumberOfProcessors;
    ULONG NtGlobalFlag;

    LARGE_INTEGER CriticalSectionTimeout;
    SIZE_T HeapSegmentReserve;
    SIZE_T HeapSegmentCommit;
    SIZE_T HeapDeCommitTotalFreeThreshold;
    SIZE_T HeapDeCommitFreeBlockThreshold;

    ULONG NumberOfHeaps;
    ULONG MaximumNumberOfHeaps;
    PVOID* ProcessHeaps; // PHEAP

    PVOID GdiSharedHandleTable;
    PVOID ProcessStarterHelper;
    ULONG GdiDCAttributeList;

    PRTL_CRITICAL_SECTION LoaderLock;

    ULONG OSMajorVersion;
    ULONG OSMinorVersion;
    USHORT OSBuildNumber;
    USHORT OSCSDVersion;
    ULONG OSPlatformId;
    ULONG ImageSubsystem;
    ULONG ImageSubsystemMajorVersion;
    ULONG ImageSubsystemMinorVersion;
    ULONG_PTR ActiveProcessAffinityMask;
    GDI_HANDLE_BUFFER GdiHandleBuffer;
    PVOID PostProcessInitRoutine;

    PVOID TlsExpansionBitmap;
    ULONG TlsExpansionBitmapBits[32];

    ULONG SessionId;

    ULARGE_INTEGER AppCompatFlags;
    ULARGE_INTEGER AppCompatFlagsUser;
    PVOID pShimData;
    PVOID AppCompatInfo; // APPCOMPAT_EXE_DATA

    UNICODE_STRING CSDVersion;

    PVOID ActivationContextData; // ACTIVATION_CONTEXT_DATA
    PVOID ProcessAssemblyStorageMap; // ASSEMBLY_STORAGE_MAP
    PVOID SystemDefaultActivationContextData; // ACTIVATION_CONTEXT_DATA
    PVOID SystemAssemblyStorageMap; // ASSEMBLY_STORAGE_MAP

    SIZE_T MinimumStackCommit;

    PVOID* FlsCallback;
    LIST_ENTRY FlsListHead;
    PVOID FlsBitmap;
    ULONG FlsBitmapBits[FLS_MAXIMUM_AVAILABLE / (sizeof(ULONG) * 8)];
    ULONG FlsHighIndex;

    PVOID WerRegistrationData;
    PVOID WerShipAssertPtr;
    PVOID pUnused; // pContextData
    PVOID pImageHeaderHash;
    union
    {
        ULONG TracingFlags;
        struct
        {
            ULONG HeapTracingEnabled : 1;
            ULONG CritSecTracingEnabled : 1;
            ULONG LibLoaderTracingEnabled : 1;
            ULONG SpareTracingBits : 29;
        } s3;
    } u4;
    ULONGLONG CsrServerReadOnlySharedMemoryBase;
    PVOID TppWorkerpListLock;
    LIST_ENTRY TppWorkerpList;
    PVOID WaitOnAddressHashTable[128];
    PVOID TelemetryCoverageHeader; // REDSTONE3
    ULONG CloudFileFlags;
} PEB, *PPEB;
//以上為64位下的結構體,摘自開源調試器x64dbg的代碼

typedef NTSTATUS(NTAPI *pfn)(__in HANDLE ProcessHandle,
    __in PROCESSINFOCLASS ProcessInformationClass,
    __out_bcount(ProcessInformationLength) PVOID ProcessInformation,
    __in ULONG ProcessInformationLength,
    __out_opt PULONG ReturnLength);

void*  GetPEBLocation(HANDLE hProcess);

BOOL getcommandlineaddr(duint* addr, HANDLE hProcess);
BOOL MemoryReadSafe(HANDLE hProcess, LPVOID lpBaseAddress, LPVOID lpBuffer, SIZE_T nSize, SIZE_T* lpNumberOfBytesRead);           

然後是cpp檔案c++

#include "CMD.h"

pfn NtQueryInformationProcess = NULL;
BOOL EnableSeDebugPrivilege(IN const CHAR*  PriviledgeName, BOOL IsEnable)
{
    // 打開權限令牌

    HANDLE  ProcessHandle = GetCurrentProcess();
    HANDLE  TokenHandle = NULL;
    TOKEN_PRIVILEGES TokenPrivileges = { 0 };
    if (!OpenProcessToken(ProcessHandle, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &TokenHandle))
    {
        return FALSE;
    }
    LUID             v1;
    if (!LookupPrivilegeValueA(NULL, PriviledgeName, &v1))      // 通過權限名稱查找uID
    {
        CloseHandle(TokenHandle);
        TokenHandle = NULL;
        return FALSE;
    }

    TokenPrivileges.PrivilegeCount = 1;     // 要提升的權限個數
    TokenPrivileges.Privileges[0].Attributes = IsEnable == TRUE ? SE_PRIVILEGE_ENABLED : 0;    // 動态數組,數組大小根據Count的數目
    TokenPrivileges.Privileges[0].Luid = v1;
    if (!AdjustTokenPrivileges(TokenHandle, FALSE, &TokenPrivileges,
        sizeof(TOKEN_PRIVILEGES), NULL, NULL))
    {
        CloseHandle(TokenHandle);
        TokenHandle = NULL;
        return FALSE;
    }
    CloseHandle(TokenHandle);
    TokenHandle = NULL;
    return TRUE;
}

void*  GetPEBLocation(HANDLE hProcess)//獲得PEB的VA
{
    ULONG RequiredLen = 0;
    void* PebAddress = 0;
    PROCESS_BASIC_INFORMATION myProcessBasicInformation[5] = { 0 };

    if (NtQueryInformationProcess(hProcess, ProcessBasicInformation, myProcessBasicInformation, sizeof(PROCESS_BASIC_INFORMATION), &RequiredLen) == STATUS_SUCCESS)
    {
        PebAddress = (void*)myProcessBasicInformation->PebBaseAddress;
    }
    else
    {
        if (NtQueryInformationProcess(hProcess, ProcessBasicInformation, myProcessBasicInformation, RequiredLen, &RequiredLen) == STATUS_SUCCESS)
        {
            PebAddress = (void*)myProcessBasicInformation->PebBaseAddress;
        }
    }

    return PebAddress;
}
BOOL  MemoryReadSafe(HANDLE hProcess, LPVOID lpBaseAddress, LPVOID lpBuffer, SIZE_T nSize, SIZE_T* lpNumberOfBytesRead)//非常便捷的函數,可以記下來
{
    SIZE_T ueNumberOfBytesRead = 0;
    SIZE_T* pNumBytes = 0;
    DWORD dwProtect = 0;
    BOOL retValue = false;

    //read memory
    if ((hProcess == 0) || (lpBaseAddress == 0) || (lpBuffer == 0) || (nSize == 0))
    {
        return false;
    }

    if (!lpNumberOfBytesRead)
    {
        pNumBytes = &ueNumberOfBytesRead;
    }
    else
    {
        pNumBytes = lpNumberOfBytesRead;
    }

    if (!ReadProcessMemory(hProcess, lpBaseAddress, lpBuffer, nSize, pNumBytes))
    {
        if (VirtualProtectEx(hProcess, lpBaseAddress, nSize, PAGE_EXECUTE_READWRITE, &dwProtect))//修改保護屬性
        {
            if (ReadProcessMemory(hProcess, lpBaseAddress, lpBuffer, nSize, pNumBytes))
            {
                retValue = TRUE;
            }
            VirtualProtectEx(hProcess, lpBaseAddress, nSize, dwProtect, &dwProtect);
        }
    }
    else
    {
        retValue = TRUE;
    }

    return retValue;
}


 BOOL getcommandlineaddr(duint* addr,HANDLE hProcess)
{
    duint pprocess_parameters;
    duint Addr = (duint)GetPEBLocation(hProcess);//獲得PEB位址

    if (Addr == 0)
    {
        return false;
    }
    if (!hProcess) { return FALSE; }
    SIZE_T NumberOfBytesRead;
    if (!MemoryReadSafe(hProcess, (LPVOID)((Addr) + offsetof(PEB, ProcessParameters)),
        &pprocess_parameters, sizeof(duint), &NumberOfBytesRead))//根據偏移獲得指令行位址
    {
        return false;
    }

    *addr = (pprocess_parameters)+offsetof(RTL_USER_PROCESS_PARAMETERS, CommandLine);

    return TRUE;
}


void main() {

    duint* CmdAddr = NULL;
    HANDLE hProcess = NULL;
    DWORD ProcessId = 0;
    HMODULE NtdllModuleBase = NULL;
    PUNICODE_STRING CmdLine;
    WCHAR* CmdLineBuffer = NULL;
    SIZE_T NumberOfBytesRead = 0;

    if (EnableSeDebugPrivilege("SeDebugPrivilege", TRUE) == FALSE)
    {
        goto EXIT;
    }
    NtdllModuleBase = GetModuleHandle(L"Ntdll.dll");
    if (NtdllModuleBase == NULL)
    {
        goto EXIT;
    }
    NtQueryInformationProcess = (pfn)GetProcAddress(NtdllModuleBase, "NtQueryInformationProcess");
    if (NtQueryInformationProcess == NULL)
    {
        int a = GetLastError();
        goto EXIT;
    }

    cout << "輸入程序id" << endl;
    cin >> ProcessId;

    hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, ProcessId);
    CmdAddr = (duint*)malloc(sizeof(duint*));
    CmdLine = (PUNICODE_STRING)malloc(sizeof(UNICODE_STRING));
    CmdLineBuffer = (WCHAR*)malloc(1024);
    getcommandlineaddr(CmdAddr,hProcess);

    if (!MemoryReadSafe(hProcess, (LPVOID)*CmdAddr, (LPVOID)CmdLine, sizeof(UNICODE_STRING), &NumberOfBytesRead))//獲得指令行位址
    {
        printf("ERROR\n");
        goto EXIT;
    }
    if (!MemoryReadSafe(hProcess, (LPVOID)CmdLine->Buffer, (LPVOID)CmdLineBuffer, 1024, &NumberOfBytesRead))//指令行是一個UNICODE_STRING結構,還要讀取一次讀取指令行的BUFEER
    {
        printf("ERROR\n");
        goto EXIT;
    }
    printf("%S", CmdLineBuffer);

EXIT:
    if (CmdAddr != NULL)
    {
        free(CmdAddr);
    }
    if (CmdLine!= NULL)
    {
        free(CmdLine);
    }
    if (CmdLineBuffer != NULL)
    {
        free(CmdLineBuffer);
    }
    EnableSeDebugPrivilege("SeDebugPrivilege", FALSE);
    getchar();
    return;
}           

下面是運作結果:

X64-R3層通過PEB擷取程式指令行參數
PEB g