كيفية استخدام ZwqueryInformationProcess للحصول على ProcessImageFilename في سائق kernel؟

StackOverflow https://stackoverflow.com/questions/3707133

  •  02-10-2019
  •  | 
  •  

سؤال

أنا أكتب برنامج تشغيل 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);

DbgView Output

كما ترى str.Buffer فارغ أو مليء بالقمامة. ربما فائض المخزن المؤقت أثناء ملء str عبر ZwQueryInformationProcess() يؤدي إلى BSOD.

alt text

سيكون موضع تقدير أي مساعدة.

هل كانت مفيدة؟

المحلول

تشير مستندات 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 للحصول على المقبض أولاً.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top