之前分析过的一些恶意软件中会使用这种方法来进行浏览器的主页劫持,其原理就是在进程创建回调函数中处理进程的创建消息。这个时候由于应用层的进程实体还没有开始初始化,所以通过命令行参数篡改来实现劫持;假如这个时候应用层的进程实体已经创建并完成初始化,修改命令行参数就达不到预期的作用(因为完成初始化后,peb中的命令行参数字段就不再需要了,不会重复初始化这个过程)。
下面示例展示了如何修改命令行参数:以abcdefg.exe进程为例,其完整文件路径为:"C:\Users\1909\Desktop\abcdefg.exe";进修改后变为:"C:\Users\1909\Desktop\abcdefg.exe" -124,当然也可以变为:"C:\Users\1909\Desktop\abcd.exe" -124。
/*
演示如何修改进程对象中的peb中命令行参数字段
这种方法常见的被用在浏览器主页篡改
也可以用来观察其他进程启动的命令行参数
之所以可以这要操作的原因时:当进程创建回调函数收到进程创建的通知时,内核中的进程对象已经创建,
但是用户层的进程还是一个空壳,还没有申请用户层的资源,连主线程的没有启动。从这里可以联想到,
如果在这个时候对应用层的某个api进行的话,可能时机太早了,模块可能都还有加载。
*/
typedef struct _RTL_USER_PROCESS_PARAMETERS {
BYTE Reserved1[16];
PVOID Reserved2[10];
UNICODE_STRING ImagePathName;
UNICODE_STRING CommandLine;
} RTL_USER_PROCESS_PARAMETERS, * PRTL_USER_PROCESS_PARAMETERS;
typedef struct _PEB {
BYTE Reserved1[2];
BYTE BeingDebugged;
BYTE Reserved2[1];
PVOID Reserved3[2];
PPEB_LDR_DATA Ldr;
PRTL_USER_PROCESS_PARAMETERS ProcessParameters;
BYTE Reserved4[104];
PVOID Reserved5[52];
PPS_POST_PROCESS_INIT_ROUTINE PostProcessInitRoutine;
BYTE Reserved6[128];
PVOID Reserved7[1];
ULONG SessionId;
} PEB, * PPEB;
NTSTATUS TamperProcessCommandLine(PEPROCESS process)
{
NTSTATUS status = STATUS_UNSUCCESSFUL;
LONG CompareResult=0;
UNICODE_STRING string1;
UNICODE_STRING append;
WCHAR* NewCommandLine=NULL;
if (process)
{
PPEB peb = PsGetProcessPeb(process);
if (peb)
{
KAPC_STATE ApcState;
//
//如果不附加目标进程,会导致后面的peb访问异常
//
KeStackAttachProcess(process, &ApcState);
DbgPrint("before CommandLine:%wZ\n", &(peb->ProcessParameters->CommandLine));
RtlInitUnicodeString(&string1, L"\"C:\\Users\\1909\\Desktop\\abcdefg.exe\"");
//DbgPrint("string1:%wZ\n", &string1);
CompareResult = RtlCompareUnicodeString(&string1, &(peb->ProcessParameters->CommandLine), FALSE);
if (wcsstr(peb->ProcessParameters->CommandLine.Buffer, L"abcdefg.exe"))
{
DbgPrint("CommandLine.Length:%d,CommandLine.MaxiumLength:%d\n", peb->ProcessParameters->CommandLine.Length, peb->ProcessParameters->CommandLine.MaximumLength);
RtlInitUnicodeString(&append, L" -124");
NewCommandLine = (WCHAR*)ExAllocatePool(NonPagedPool, 512);
if (NewCommandLine)
{
wcscpy(NewCommandLine, peb->ProcessParameters->CommandLine.Buffer);
wcscat(NewCommandLine, append.Buffer);
wcscpy(peb->ProcessParameters->CommandLine.Buffer, NewCommandLine);
peb->ProcessParameters->CommandLine.Length = (USHORT)wcslen(NewCommandLine) * 2;
peb->ProcessParameters->CommandLine.MaximumLength = (USHORT)wcslen(NewCommandLine) * 2 + 2;
DbgPrint("after CommandLine:%wZ\n", &(peb->ProcessParameters->CommandLine));
status = STATUS_SUCCESS;
}
}
KeUnstackDetachProcess(&ApcState);
}
}
if (NewCommandLine)
{
ExFreePool(NewCommandLine);
NewCommandLine = NULL;
}
return status;
}
效果截图: