2010-09-14 6 views
8

Estoy escribiendo un controlador de núcleo simple para mi aplicación (pensar en una manera muy sencilla aplicación anti-malware.)¿Cómo se usa ZwQueryInformationProcess para obtener ProcessImageFileName en un controlador de kernel?

he enganchado ZwOpenFile()PsGetCurrentProcess() y se utiliza para obtener un identificador para el proceso de la persona que llama.

Devuelve una estructura PEPROCESS:

PEPROCESS proc = PsGetCurrentProcess(); 

estoy usando ZwQueryInformationProcess() para obtener el PID y ImageFileName:

DbgPrint("ZwOpenFile Called...\n"); 
DbgPrint("PID: %d\n", PsGetProcessId(proc)); 
DbgPrint("ImageFileName: %.16s\n", PsGetProcessImageFileName(proc)); 

y tratando de conseguir el proceso FullPath esta manera (pero consigo 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

Como ve str.Buffer está vacío o lleno de basura. Quizás un desbordamiento del búfer mientras llena el str a través del ZwQueryInformationProcess() activa el BSOD.

alt text

Cualquier ayuda se agradece.

Respuesta

6

Los docs MSDN para esta API indican que

Cuando el parámetro ProcessInformationClass es ProcessImageFileName, el tampón apuntado por el parámetro ProcessInformation debe ser suficientemente grande para contener una estructura UNICODE_STRING así como la cadena sí mismo. La cadena almacenada en el miembro del búfer es el nombre de la imagen file.file.

Con esto en mente, le sugiero que trate de modificar su estructura de memoria intermedia como esto:

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); 

Además, el código necesita para comprobar y controlar el caso de error descrito en la documentación aquí. Esta puede ser la razón por la que te perdiste el caso del gatillo BSOD.

Si el búfer es demasiado pequeño, la función falla con el código de error STATUS_INFO_LENGTH_MISMATCH y el parámetro se establece ReturnLength al tamaño de búfer necesario.

0

ZwQueryInformationProcess necesita un HANDLE, no un PROCESS! Debe usar ObOpenObjectByPointer para obtener primero el identificador.

1

// Declare este fragmento de código en el archivo de encabezado si está disponible de otra manera antes de la definición de la Función.

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; 

// Definición de la función

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; 
} 

// Función de llamada .. Escribir este pedazo de código en el preoperatorio de llamada hacia atrás y IRQ debe ser PASSIVE_LEVEL

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); 

en la variable fullPath existe Ruta completa del proceso. Al igual que si el proceso es explorer.exe, la ruta se verá así: -

\Device\HarddiskVolume3\Windows\explorer.exe 

Nota: - \ Device \ HarddiskVolume3 La ruta se puede cambiar debido a la máquina y a un volumen diferente en el disco duro, este es un ejemplo en mi caso.

Cuestiones relacionadas