WindowsXP下获取命令行参数

本文探讨了在WindowsXP环境下,通过PsSetCreateProcessNotifyRoutine注册进程创建回调,并尝试从PEB结构中获取新创建进程的命令行参数的方法。详细介绍了如何在进程创建回调中正确读取命令行参数,包括使用windbg进行调试的过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1)背景

最近有个需求在WindowsXP下通过PsSetCreateProcessNotifyRoutine注册了一个进程创建回调,然后尝试通过PEB来获取被创建进程的命令行参数,发现PEB结构中的命令行等相关数据还没有被填充进去。

通过查看GetCommandLineA函数的反汇编,得知进程的命令行保存在一个固定的地址0x7C8855F4

MOVE EAX, DWORD PTR [0x7C8855F4]
RETN

在进程创建回调中,附加到目标进程,再查看这个地址的数据,如下所示。 因为时机还不对,这个地址还没被申请呢!!

kd> db 0x7C8855F4
7c8855f4  ?? ?? ?? ?? ?? ?? ?? ??-?? ?? ?? ?? ?? ?? ?? ??  ????????????????
7c885604  ?? ?? ?? ?? ?? ?? ?? ??-?? ?? ?? ?? ?? ?? ?? ??  ????????????????
7c885614  ?? ?? ?? ?? ?? ?? ?? ??-?? ?? ?? ?? ?? ?? ?? ??  ????????????????
7c885624  ?? ?? ?? ?? ?? ?? ?? ??-?? ?? ?? ?? ?? ?? ?? ??  ????????????????
7c885634  ?? ?? ?? ?? ?? ?? ?? ??-?? ?? ?? ?? ?? ?? ?? ??  ????????????????
7c885644  ?? ?? ?? ?? ?? ?? ?? ??-?? ?? ?? ?? ?? ?? ?? ??  ????????????????
7c885654  ?? ?? ?? ?? ?? ?? ?? ??-?? ?? ?? ?? ?? ?? ?? ??  ????????????????
7c885664  ?? ?? ?? ?? ?? ?? ?? ??-?? ?? ?? ?? ?? ?? ?? ??  ????????????????

通过windbg,检查PEB结构中的ProcessParameters字段,该字段指向一个_RTL_USER_PROCESS_PARAMETERS结构

kd> dt _PEB 7ffd5000
ntdll!_PEB
   +0x000 InheritedAddressSpace : 0 ''
   +0x001 ReadImageFileExecOptions : 0 ''
   +0x002 BeingDebugged    : 0 ''
   +0x003 SpareBool        : 0 ''
   +0x004 Mutant           : 0xffffffff Void
   +0x008 ImageBaseAddress : 0x01000000 Void
   +0x00c Ldr              : (null)
   +0x010 ProcessParameters : 0x00020000 _RTL_USER_PROCESS_PARAMETERS
   +0x014 SubSystemData    : (null)
   +0x018 ProcessHeap      : (null)

查看ProcessParameters中的数据,发现Commdline字段中保存的是一个无效地址0x000008ec

kd> dt _RTL_USER_PROCESS_PARAMETERS 0x00020000
ntdll!_RTL_USER_PROCESS_PARAMETERS
   +0x000 MaximumLength    : 0x1000
   +0x004 Length           : 0x970
   +0x008 Flags            : 0x2000
   +0x00c DebugFlags       : 0
   +0x010 ConsoleHandle    : 0x00310002 Void
   +0x014 ConsoleFlags     : 0
   +0x018 StandardInput    : 0x00000003 Void
   +0x01c StandardOutput   : 0x00000007 Void
   +0x020 StandardError    : 0x0000000b Void
   +0x024 CurrentDirectory : _CURDIR
   +0x030 DllPath          : _UNICODE_STRING "--- memory read error at address 0x00000498 ---"
   +0x038 ImagePathName    : _UNICODE_STRING "--- memory read error at address 0x000008ac ---"
   +0x040 CommandLine      : _UNICODE_STRING "--- memory read error at address 0x000008ec ---"
   +0x048 Environment      : 0x00010000 Void
   +0x04c StartingX        : 0
   +0x050 StartingY        : 1
   +0x054 CountX           : 0x64
   +0x058 CountY           : 0x64
   +0x05c CountCharsX      : 0
   +0x060 CountCharsY      : 0
   +0x064 FillAttribute    : 0
   +0x068 WindowFlags      : 0
   +0x06c ShowWindowFlags  : 1
   +0x070 WindowTitle      : _UNICODE_STRING "--- memory read error at address 0x0000091c ---"
   +0x078 DesktopInfo      : _UNICODE_STRING "--- memory read error at address 0x0000094c ---"
   +0x080 ShellInfo        : _UNICODE_STRING "--- memory read error at address 0x0000096c ---"
   +0x088 RuntimeData      : _UNICODE_STRING ""
   +0x090 CurrentDirectores : [32] _RTL_DRIVE_LETTER_CURDIR

但是通过windbg的扩展命令!peb 却能正常查看PEB结构中的命令行数据,怎么直接通过dt _PEB address 就不行了?

kd> !peb
PEB at 7ffd5000
    InheritedAddressSpace:    No
    ReadImageFileExecOptions: No
    BeingDebugged:            No
    ImageBaseAddress:         01000000
    NtGlobalFlag:             0
    NtGlobalFlag2:            0
    Ldr                       00000000
    *** unable to read Ldr table at 00000000
    SubSystemData:     00000000
    ProcessHeap:       00000000
    ProcessParameters: 00020000
    CurrentDirectory:  '< Name not readable >'
    WindowTitle:  'notepad 11111111111.txt'
    ImageFile:    'C:\WINDOWS\system32\notepad.exe'
    CommandLine:  'notepad 11111111111.txt'

尝试在进程空间内暴力搜索命令行参数,得到以下两个结果:

kd> s -u 0x0 0x7ffffff "notepad 11111111111"
000208ec  006e 006f 0074 0065 0070 0061 0064 0020  n.o.t.e.p.a.d. .
0002091c  006e 006f 0074 0065 0070 0061 0064 0020  n.o.t.e.p.a.d. .

000208ec 这个地址看起来很眼熟,原来是(PEB.ProcessParameters + PEB.ProcessParameters.CommandLine),因为PEB结构中的_RTL_USER_PROCESS_PARAMETERS结构还没被完全填充好,在创建进程的通知回调被触发时,这个结构中的CommandLine只是一个相对偏移。

(000208ec = 0x00020000 + 0x000008ec )

2)代码

#include <ntifs.h>
void PcreateProcessNotifyRoutine(HANDLE ParentId,HANDLE ProcessId,BOOLEAN Create)
{
       PEPROCESS SubEProcess;
       if (Create)
       {
              DbgPrint("[Create Process]: ParentId:%d ProcessId:%d \n",  (ULONG)ParentId, (ULONG)ProcessId);
              SubEProcess = NULL;
              if (NT_SUCCESS(PsLookupProcessByProcessId(ProcessId, &SubEProcess)))
              {
            KAPC_STATE ks;
            KeStackAttachProcess(SubEProcess, &ks);
            PPEB pPeb = PsGetProcessPeb(SubEProcess);
            if (pPeb && pPeb->ProcessParameters)
            {
            PRTL_USER_PROCESS_PARAMETERS ProcessParameters = (PRTL_USER_PROCESS_PARAMETERS)pPeb->ProcessParameters;
            wchar_t* pRealComandLine = (wchar_t*)((ULONG_PTR)ProcessParameters->CommandLine.Buffer + (ULONG_PTR)ProcessParameters);
            DbgPrint("[KeStackAttachProcess]: commandline from 0x%08x: %S\n",  (ULONG_PTR)pRealComandLine, pRealComandLine);
            }
            KeUnstackDetachProcess(&ks);
                    ObDereferenceObject(SubEProcess);
              }
       }
}
VOID DriverUnload(PDRIVER_OBJECT  DriverObject)
{
       UNREFERENCED_PARAMETER(DriverObject);
       DbgPrint("DriverUnload Enter \n");
       PsSetCreateProcessNotifyRoutine(PcreateProcessNotifyRoutine, TRUE);
}
NTSTATUS DriverEntry(PDRIVER_OBJECT  DriverObject, PUNICODE_STRING RegistryPath)
{
       UNREFERENCED_PARAMETER(RegistryPath);
       DbgPrint("DriverEntry Enter \n");
       do
       {
              PsSetCreateProcessNotifyRoutine(PcreateProcessNotifyRoutine,FALSE);
              DriverObject->DriverUnload = DriverUnload;
       } while (0);
       return STATUS_SUCCESS;
}

4)效果

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值