كيفية استخدام ZwqueryInformationProcess للحصول على ProcessImageFilename في سائق kernel؟
سؤال
أنا أكتب برنامج تشغيل kernel بسيط لتطبيقي (فكر في تطبيق بسيط للغاية لمكافحة البرامج الضارة.)
لقد مدمن مخدرات ZwOpenFile()
ويستخدم PsGetCurrentProcess()
للحصول على مقبض لعملية المتصل.
يعيد بنية المعالجة:
PEPROCESS proc = PsGetCurrentProcess();
أنا استخدم ZwQueryInformationProcess()
للحصول على PID
و ImageFileName
:
DbgPrint("ZwOpenFile Called...\n");
DbgPrint("PID: %d\n", PsGetProcessId(proc));
DbgPrint("ImageFileName: %.16s\n", PsGetProcessImageFileName(proc));
ومحاولة الحصول على العملية FullPath
بهذه الطريقة (لكنني أحصل على BSOD):
WCHAR strBuffer[260];
UNICODE_STRING str;
//initialize
str.Buffer = strBuffer;
str.Length = 0x0;
str.MaximumLength = sizeof(strBuffer);
//note that the seconds arg (27) is ProcessImageFileName
ZwQueryInformationProcess(proc, 27, &str, sizeof(str), NULL);
DbgPrint("FullPath: %wZ\n", str.Buffer);
كما ترى str.Buffer
فارغ أو مليء بالقمامة. ربما فائض المخزن المؤقت أثناء ملء str
عبر ZwQueryInformationProcess()
يؤدي إلى BSOD.
سيكون موضع تقدير أي مساعدة.
المحلول
تشير مستندات MSDN لهذا API إلى ذلك
عندما تكون معلمة ProcessInformationClass هي ProcessImageFilename ، يجب أن يكون المخزن المؤقت الذي يشير إليه المعلمة المعالجة كبيرة بما يكفي لعقد بنية Unicode_String وكذلك السلسلة نفسها. السلسلة المخزنة في عضو المخزن المؤقت هي اسم ملف الصورة.
مع وضع هذا في الاعتبار ، أقترح عليك محاولة تعديل بنية العازلة مثل هذا:
WCHAR strBuffer[(sizeof(UNICODE_STRING) / sizeof(WCHAR)) + 260];
UNICODE_STRING str;
str = (UNICODE_STRING*)&strBuffer;
//initialize
str.Buffer = &strBuffer[sizeof(UNICODE_STRING) / sizeof(WCHAR)];
str.Length = 0x0;
str.MaximumLength = 260 * sizeof(WCHAR);
//note that the seconds arg (27) is ProcessImageFileName
ZwQueryInformationProcess(proc, 27, &strBuffer, sizeof(strBuffer), NULL);
بالإضافة إلى ذلك ، يحتاج الرمز الخاص بك إلى التحقق من حالة الخطأ والمعالجة الموضحة في المستندات هنا. قد يكون هذا هو السبب في أنك فاتتك قضية BSOD Trigger.
إذا كان المخزن المؤقت صغيرًا جدًا ، فإن الوظيفة تفشل مع رمز الخطأ status_info_length_mismatch ويتم ضبط معلمة طول الإرجاع على حجم المخزن المؤقت المطلوب.
نصائح أخرى
// أعلن هذا الجزء من الرمز في ملف الرأس إذا كان متاحًا خلاف ذلك قبل تعريف الوظيفة ..
typedef NTSTATUS (*QUERY_INFO_PROCESS) (
__in HANDLE ProcessHandle,
__in PROCESSINFOCLASS ProcessInformationClass,
__out_bcount(ProcessInformationLength) PVOID ProcessInformation,
__in ULONG ProcessInformationLength,
__out_opt PULONG ReturnLength
);
QUERY_INFO_PROCESS ZwQueryInformationProcess;
// تعريف الوظيفة
NTSTATUS GetProcessImageName(HANDLE processId, PUNICODE_STRING ProcessImageName)
{
NTSTATUS status;
ULONG returnedLength;
ULONG bufferLength;
HANDLE hProcess;
PVOID buffer;
PEPROCESS eProcess;
PUNICODE_STRING imageName;
PAGED_CODE(); // this eliminates the possibility of the IDLE Thread/Process
status = PsLookupProcessByProcessId(processId, &eProcess);
if(NT_SUCCESS(status))
{
status = ObOpenObjectByPointer(eProcess,0, NULL, 0,0,KernelMode,&hProcess);
if(NT_SUCCESS(status))
{
} else {
DbgPrint("ObOpenObjectByPointer Failed: %08x\n", status);
}
ObDereferenceObject(eProcess);
} else {
DbgPrint("PsLookupProcessByProcessId Failed: %08x\n", status);
}
if (NULL == ZwQueryInformationProcess) {
UNICODE_STRING routineName;
RtlInitUnicodeString(&routineName, L"ZwQueryInformationProcess");
ZwQueryInformationProcess =
(QUERY_INFO_PROCESS) MmGetSystemRoutineAddress(&routineName);
if (NULL == ZwQueryInformationProcess) {
DbgPrint("Cannot resolve ZwQueryInformationProcess\n");
}
}
/* Query the actual size of the process path */
status = ZwQueryInformationProcess( hProcess,
ProcessImageFileName,
NULL, // buffer
0, // buffer size
&returnedLength);
if (STATUS_INFO_LENGTH_MISMATCH != status) {
return status;
}
/* Check there is enough space to store the actual process
path when it is found. If not return an error with the
required size */
bufferLength = returnedLength - sizeof(UNICODE_STRING);
if (ProcessImageName->MaximumLength < bufferLength)
{
ProcessImageName->MaximumLength = (USHORT) bufferLength;
return STATUS_BUFFER_OVERFLOW;
}
/* Allocate a temporary buffer to store the path name */
buffer = ExAllocatePoolWithTag(NonPagedPool, returnedLength, 'uLT1');
if (NULL == buffer)
{
return STATUS_INSUFFICIENT_RESOURCES;
}
/* Retrieve the process path from the handle to the process */
status = ZwQueryInformationProcess( hProcess,
ProcessImageFileName,
buffer,
returnedLength,
&returnedLength);
if (NT_SUCCESS(status))
{
/* Copy the path name */
imageName = (PUNICODE_STRING) buffer;
RtlCopyUnicodeString(ProcessImageName, imageName);
}
/* Free the temp buffer which stored the path */
ExFreePoolWithTag(buffer, 'uLT1');
return status;
}
// استدعاء الوظيفة .. اكتب هذه القطعة من الكود في Preoperation Call مرة أخرى وينبغي أن يكون IRQ سلبيًا.
PEPROCESS objCurProcess=NULL;
HANDLE hProcess;
UNICODE_STRING fullPath;
objCurProcess=IoThreadToProcess(Data->Thread);//Note: Date is type of FLT_CALLBACK_DATA which is in PreOperation Callback as argument
hProcess=PsGetProcessID(objCurProcess);
fullPath.Length=0;
fullPath.MaximumLength=520;
fullPath.Buffer=(PWSTR)ExAllocatePoolWithTag(NonPagedPool,520,'uUT1');
GetProcessImageName(hProcess,&fullPath);
في متغير FullPath ، هناك مسار كامل للعملية .. مثل إذا كانت العملية هي Explorer.exe ، فسيبدو المسار على هذا النحو:--
\Device\HarddiskVolume3\Windows\explorer.exe
ملاحظة:- device harddiskvolume3 مسار قد يتم تغييره بسبب الجهاز وحجم مختلف في القرص الثابت ، وهذا مثال في حالتي.
ZwQueryInformationProcess
يحتاج HANDLE
, ، ليس أ PROCESS
! تحتاج إلى استخدام ObOpenObjectByPointer
للحصول على المقبض أولاً.