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)效果