интересно, что в win2000 эта функция почему-то не считает необходимый размер буфера... этот код в ХР возвращает в переменную ul_procinfo_buff_len размер данных, а в Win2000 возвращает 0. Код (Text): ul_status = ZwQuerySystemInformation(SystemProcesses, 0, 0, &ul_procinfo_buff_len); как получить размер буфера? а вообще-то вот что написано в SDK XP: [NtQuerySystemInformation is available for use in Windows 2000 and Windows XP. It may be altered or unavailable in subsequent versions. Applications should use the alternate functions listed in this topic.] ReturnLength [out, optional] Optional pointer to a location where the function writes the actual size of the information requested. If that size is less than or equal to the SystemInformationLength parameter, the function copies the information into the SystemInformation buffer; otherwise, it returns an NTSTATUS error code and returns in ReturnLength the size of buffer required to receive the requested information.
Смотрите сами. Это часть кода NtQuerySystemInformation, обратите внимание на проверку размера буфера: Код (Text): case SystemProcessInformation: if (SystemInformationLength < sizeof( SYSTEM_PROCESS_INFORMATION)) { return STATUS_INFO_LENGTH_MISMATCH; } Status = ExpGetProcessInformation (SystemInformation, SystemInformationLength, &Length, NULL); if (NT_SUCCESS(Status) && ARGUMENT_PRESENT( ReturnLength )) { *ReturnLength = Length; } break; Таким же образом проверяются параметры и в некоторых других функциях, в т.ч. и в системах Windows XP и Windows Server 2003. Решение простое - передать для начала минимально возможный размер буфера, а не 0. В данном случае это будет sizeof (SYSTEM_PROCESS_INFORMATION).
SYSTEM_PROCESSES buff; ul_status = ZwQuerySystemInformation(SystemProcesses, &buff, sizeof(buff), &ul_procinfo_buff_len); ничего не изменилось. по прежднему в ul_procinfo_buff_len 0.
Вот вам код из Windows 2000, разбирайтесь: Код (Text): NTSTATUS ExpGetProcessInformation ( OUT PVOID SystemInformation, IN ULONG SystemInformationLength, OUT PULONG Length, IN PULONG SessionId OPTIONAL ) /*++ Routine Description: This function returns information about all the processes and threads in the system. Arguments: SystemInformation - A pointer to a buffer which receives the specified information. SystemInformationLength - Specifies the length in bytes of the system information buffer. Length - An optional pointer which, if specified, receives the number of bytes placed in the system information buffer. Return Value: Returns one of the following status codes: STATUS_SUCCESS - normal, successful completion. STATUS_INVALID_INFO_CLASS - The SystemInformationClass parameter did not specify a valid value. STATUS_INFO_LENGTH_MISMATCH - The value of the SystemInformationLength parameter did not match the length required for the information class requested by the SystemInformationClass parameter. STATUS_ACCESS_VIOLATION - Either the SystemInformation buffer pointer or the Length pointer value specified an invalid address. STATUS_WORKING_SET_QUOTA - The process does not have sufficient working set to lock the specified output structure in memory. STATUS_INSUFFICIENT_RESOURCES - Insufficient system resources exist for this request to complete. --*/ { KEVENT Event; PEPROCESS Process; PETHREAD Thread; PSYSTEM_PROCESS_INFORMATION ProcessInfo; PSYSTEM_THREAD_INFORMATION ThreadInfo; PLIST_ENTRY NextProcess; PLIST_ENTRY NextThread; PVOID MappedAddress; PVOID LockVariable; ULONG TotalSize = 0; ULONG NextEntryOffset = 0; PUCHAR Src; PWSTR Dst; ULONG n; NTSTATUS status = STATUS_SUCCESS; *Length = 0; MappedAddress = ExLockUserBuffer( SystemInformation, SystemInformationLength, &LockVariable ); if (MappedAddress == NULL) { return( STATUS_ACCESS_VIOLATION ); } MmLockPagableSectionByHandle (ExPageLockHandle); ExAcquireFastMutex(&PspActiveProcessMutex); // // Initialize an event object and then set the event with the wait // parameter TRUE. This causes the event to be set and control is // returned with the dispatcher database locked at dispatch IRQL. // KeInitializeEvent (&Event, NotificationEvent, FALSE); try { ProcessInfo = (PSYSTEM_PROCESS_INFORMATION)MappedAddress; if (!ARGUMENT_PRESENT(SessionId)) { NextEntryOffset = sizeof(SYSTEM_PROCESS_INFORMATION); TotalSize = sizeof(SYSTEM_PROCESS_INFORMATION); ExpCopyProcessInfo (ProcessInfo, PsIdleProcess); // // Since Idle process and system process share the same // object table, zero out idle processes handle count to // reduce confusion // ProcessInfo->HandleCount = 0; // Idle Process always has SessionId 0 ProcessInfo->SessionId = 0; // // Set the event with the wait // parameter TRUE. This causes the event to be set and control is // returned with the dispatcher database locked at dispatch IRQL. // // WARNING - The following code assumes that the process structure // uses kernel objects to synchronize access to the thread and // process lists. // KeSetEvent (&Event, 0, TRUE); // // WARNING - The following code runs with the kernel dispatch database // locked. EXTREME caution should be taken when modifying this // code. Extended execution will ADVERSELY affect system operation // and integrity. // // Get info for idle process's threads // // // Get information for each thread. // ThreadInfo = (PSYSTEM_THREAD_INFORMATION)(ProcessInfo + 1); ProcessInfo->NumberOfThreads = 0; NextThread = PsIdleProcess->Pcb.ThreadListHead.Flink; while (NextThread != &PsIdleProcess->Pcb.ThreadListHead) { NextEntryOffset += sizeof(SYSTEM_THREAD_INFORMATION); TotalSize += sizeof(SYSTEM_THREAD_INFORMATION); if (TotalSize > SystemInformationLength) { status = STATUS_INFO_LENGTH_MISMATCH; KeWaitForSingleObject (&Event, Executive, KernelMode, FALSE, NULL); goto Failed; } Thread = (PETHREAD)(CONTAINING_RECORD(NextThread, KTHREAD, ThreadListEntry)); ExpCopyThreadInfo (ThreadInfo,Thread); ProcessInfo->NumberOfThreads += 1; NextThread = NextThread->Flink; ThreadInfo += 1; } // // Unlock the dispatch database by waiting on the event that was // previously set with the wait parameter TRUE. // KeWaitForSingleObject (&Event, Executive, KernelMode, FALSE, NULL); ProcessInfo->ImageName.Buffer = NULL; ProcessInfo->ImageName.Length = 0; ProcessInfo->NextEntryOffset = NextEntryOffset; } NextProcess = PsActiveProcessHead.Flink; while (NextProcess != &PsActiveProcessHead) { Process = CONTAINING_RECORD(NextProcess, EPROCESS, ActiveProcessLinks); if (ARGUMENT_PRESENT(SessionId) && (Process->SessionId != *SessionId)) { NextProcess = NextProcess->Flink; continue; } ProcessInfo = (PSYSTEM_PROCESS_INFORMATION) ((PUCHAR)MappedAddress + TotalSize); NextEntryOffset = sizeof(SYSTEM_PROCESS_INFORMATION); TotalSize += sizeof(SYSTEM_PROCESS_INFORMATION); if (TotalSize > SystemInformationLength) { status = STATUS_INFO_LENGTH_MISMATCH; goto Failed; } // // Get information for each process. // ExpCopyProcessInfo (ProcessInfo, Process); // // Set the event with the wait // parameter TRUE. This causes the event to be set and control is // returned with the dispatcher database locked at dispatch IRQL. // // WARNING - The following code assumes that the process structure // uses kernel objects to synchronize access to the thread and // process lists. // KeSetEvent (&Event, 0, TRUE); // // WARNING - The following code runs with the kernel dispatch database // locked. EXTREME caution should be taken when modifying this // code. Extended execution will ADVERSELY affect system operation // and integrity. // // // Get information for each thread. // ThreadInfo = (PSYSTEM_THREAD_INFORMATION)(ProcessInfo + 1); ProcessInfo->NumberOfThreads = 0; NextThread = Process->Pcb.ThreadListHead.Flink; while (NextThread != &Process->Pcb.ThreadListHead) { NextEntryOffset += sizeof(SYSTEM_THREAD_INFORMATION); TotalSize += sizeof(SYSTEM_THREAD_INFORMATION); if (TotalSize > SystemInformationLength) { status = STATUS_INFO_LENGTH_MISMATCH; KeWaitForSingleObject (&Event, Executive, KernelMode, FALSE, NULL); goto Failed; } Thread = (PETHREAD)(CONTAINING_RECORD(NextThread, KTHREAD, ThreadListEntry)); ExpCopyThreadInfo (ThreadInfo,Thread); ProcessInfo->NumberOfThreads += 1; NextThread = NextThread->Flink; ThreadInfo += 1; } // // Store the Remote Terminal SessionId // ProcessInfo->SessionId = Process->SessionId; // // Unlock the dispatch database by waiting on the event that was // previously set with the wait parameter TRUE. // KeWaitForSingleObject (&Event, Executive, KernelMode, FALSE, NULL); // // Get the image name. // ProcessInfo->ImageName.Buffer = NULL; ProcessInfo->ImageName.Length = 0; ProcessInfo->ImageName.MaximumLength = 0; if ((n = strlen( Src = Process->ImageFileName ))) { n = ROUND_UP( ((n + 1) * sizeof( WCHAR )), sizeof(LARGE_INTEGER) ); TotalSize += n; NextEntryOffset += n; if (TotalSize > SystemInformationLength) { status = STATUS_INFO_LENGTH_MISMATCH; } else { Dst = (PWSTR)(ThreadInfo); while (*Dst++ = (WCHAR)*Src++) { ; } ProcessInfo->ImageName.Length = (USHORT)((PCHAR)Dst - (PCHAR)ThreadInfo - sizeof( UNICODE_NULL )); ProcessInfo->ImageName.MaximumLength = (USHORT)n; // // Set the image name to point into the user's memory. // ProcessInfo->ImageName.Buffer = (PWSTR) ((PCHAR)SystemInformation + ((PCHAR)(ThreadInfo) - (PCHAR)MappedAddress)); } if (!NT_SUCCESS( status )) { goto Failed; } } // // Point to next process. // ProcessInfo->NextEntryOffset = NextEntryOffset; NextProcess = NextProcess->Flink; } ProcessInfo->NextEntryOffset = 0; status = STATUS_SUCCESS; *Length = TotalSize; Failed: ; } finally { ExReleaseFastMutex(&PspActiveProcessMutex); MmUnlockPagableImageSection(ExPageLockHandle); ExUnlockUserBuffer( LockVariable ); } return(status); } В Windows XP всё работает как надо, и SystemProcessInformation и SystemModuleInformation, и другие.
Интересно, програмисты Microsoft сами читают MSDN? нахрена писать вот это: ... returns in ReturnLength the size of buffer required to receive the requested information и мало того, функция CreateToolhelp32Snapshot выглядит вот так что в XP, что в NT: Код (Text): int __userpurge sub_7C864138<eax>(int a1<ebp>, int a2, int a3, int a4, int a5, int a6) { signed int v6; // ecx@1 int v7; // edi@1 int v8; // esi@1 int v10; // eax@2 int v11; // eax@3 int v12; // eax@3 int v13; // eax@7 int v14; // eax@13 sub_7C8024CB(&dword_7C8642D8, 28); v8 = 0; v6 = 65536; *(_DWORD *)(a1 - 28) = 65536; v7 = *(_DWORD *)(a1 + 16); *(_DWORD *)v7 = 0; **(_DWORD **)(a1 + 20) = 0; **(_DWORD **)(a1 + 24) = 0; if ( *(_BYTE *)(a1 + 8) & 6 ) { while ( 1 ) { *(_DWORD *)(a1 - 4) = 0; *(_DWORD *)(a1 - 28) = v6; v10 = NtAllocateVirtualMemory(-1, v7, 0, a1 - 28, 0x1000u, 4); v8 = v10; *(_DWORD *)(a1 - 44) = v10; *(_DWORD *)(a1 - 4) = -1; if ( v10 < 0 ) break; v11 = *(_DWORD *)(a1 - 28); *(_DWORD *)(a1 - 32) = *(_DWORD *)(a1 - 28); v12 = NtQuerySystemInformation(5, *(_DWORD *)v7, v11, 0); v8 = v12; if ( v12 != 0xC0000004 ) break; NtFreeVirtualMemory(-1, v7, a1 - 28, 0x8000u); *(_DWORD *)v7 = 0; *(_DWORD *)(a1 - 32) += 8192; v6 = *(_DWORD *)(a1 - 32); } } if ( *(_BYTE *)(a1 + 8) & 0x18 ) { if ( v8 >= 0 ) { v13 = RtlCreateQueryDebugBuffer(0, 0); **(_DWORD **)(a1 + 20) = v13; if ( !v13 ) v8 = -1073741823; if ( v8 >= 0 ) v8 = RtlQueryProcessDebugInformation( *(_DWORD *)(a1 + 12), (*(_DWORD *)(a1 + 8) >> 3) & 1 | 4 * (*(_DWORD *)(a1 + 8) & 0x10 | 0xE0000000), **(_DWORD **)(a1 + 20)); } } if ( !(*(_BYTE *)(a1 + 8) & 1) ) { LABEL_17: if ( v8 >= 0 ) return sub_7C80250B(); goto LABEL_18; } if ( v8 >= 0 ) { v14 = RtlCreateQueryDebugBuffer(0, 0); **(_DWORD **)(a1 + 24) = v14; if ( !v14 ) v8 = -1073741823; if ( v8 >= 0 ) { v8 = RtlQueryProcessDebugInformation(*(_DWORD *)(a1 + 12), 4, **(_DWORD **)(a1 + 24)); goto LABEL_17; } } LABEL_18: if ( *(_DWORD *)v7 ) { *(_DWORD *)(a1 - 40) = 0; NtFreeVirtualMemory(-1, v7, a1 - 40, 32768); *(_DWORD *)v7 = 0; } if ( **(_DWORD **)(a1 + 20) ) { RtlDestroyQueryDebugBuffer(**(_DWORD **)(a1 + 20)); **(_DWORD **)(a1 + 20) = 0; } if ( **(_DWORD **)(a1 + 24) ) { RtlDestroyQueryDebugBuffer(**(_DWORD **)(a1 + 24)); **(_DWORD **)(a1 + 24) = 0; } return sub_7C80250B(); } нафига делать цикл и крутить его, вычисляя размер, если в MSDN написано, что функция NtQuerySystemInformation должна возвратить необходимый размер???
Quark Сказал же, НЕ ВСЕ ИНФОКЛАССЫ, зачем возвращать размер буфера для SystemProcessesInformation, если состояние этой инфы а значит и размер буфера меняется часто, поэтому вызывающий код должен сам указать размер. Ужос, код это ида ? Код (Text): NTSTATUS ThpCreateRawSnap( IN DWORD dwFlags, IN DWORD th32ProcessID, PUCHAR *RawProcess, PRTL_DEBUG_INFORMATION *RawModule, PRTL_DEBUG_INFORMATION *RawDebugInfo) /*++ Routine Description: This function gets raw snapshots for the data types specified by dwFlags. Arguments: th32ProcessID - Supplies a WIN32 process ID. See CreateToolhelp32Snapshot for full description. dwFlags - Supplies switches requesting various data. See CreateToolhelp32Snapshot for full description Return Value: NTSTATUS as appropriate --*/ { NTSTATUS Status = 0; ULONG BufferSize = BUFFER_SIZE; SIZE_T stBufferSize = BUFFER_SIZE; // // get process/thread/module/heap info // *RawProcess = NULL; *RawModule = NULL; *RawDebugInfo = NULL; if((dwFlags & TH32CS_SNAPPROCESS) || (dwFlags & TH32CS_SNAPTHREAD)){ do { try { stBufferSize = BufferSize; Status = NtAllocateVirtualMemory(NtCurrentProcess(), RawProcess, 0, &stBufferSize, MEM_COMMIT, PAGE_READWRITE); } except( EXCEPTION_EXECUTE_HANDLER ) { Status = GetExceptionCode(); } if (!NT_SUCCESS(Status)) { break; } BufferSize = (ULONG)stBufferSize; // // get all of the status information */ // Status = NtQuerySystemInformation(SystemProcessInformation, *RawProcess, BufferSize, NULL); if (Status == STATUS_INFO_LENGTH_MISMATCH) { NtFreeVirtualMemory(NtCurrentProcess(), RawProcess, &stBufferSize, MEM_RELEASE); *RawProcess = NULL; BufferSize += 8192; } } while(Status == STATUS_INFO_LENGTH_MISMATCH); } // // get module information // if(dwFlags & TH32CS_SNAPMODULE) { if (NT_SUCCESS(Status)) { *RawModule = RtlCreateQueryDebugBuffer(0, FALSE); if (!*RawModule) { Status = STATUS_UNSUCCESSFUL; } } if (NT_SUCCESS(Status)) { Status = RtlQueryProcessDebugInformation((HANDLE)LongToHandle(th32ProcessID), RTL_QUERY_PROCESS_MODULES, *RawModule); } } // // get the heap summary information for the specified process */ // if (dwFlags & TH32CS_SNAPHEAPLIST) { if (NT_SUCCESS(Status)) { *RawDebugInfo = RtlCreateQueryDebugBuffer(0, FALSE); if (!*RawDebugInfo) { Status = STATUS_UNSUCCESSFUL; } } if (NT_SUCCESS(Status)) { Status = RtlQueryProcessDebugInformation((HANDLE)LongToHandle(th32ProcessID), RTL_QUERY_PROCESS_HEAP_SUMMARY, *RawDebugInfo); } } if (!NT_SUCCESS(Status)) { if (*RawProcess) { SIZE_T Size = 0; NtFreeVirtualMemory(NtCurrentProcess(), RawProcess, &Size, MEM_RELEASE); *RawProcess = NULL; } if (*RawModule) { RtlDestroyQueryDebugBuffer(*RawModule); *RawModule = NULL; } if (*RawDebugInfo) { RtlDestroyQueryDebugBuffer(*RawDebugInfo); *RawDebugInfo = NULL; } } return Status; }
1. за тем, что в MSDN написано. 2. зачем вводить в заблуждение и в разных осях делать по разномку. 3. конечно, есть вероятность того, что в промежутке между вызовами ZwQuerySystemInformation произойдёт создание ещё одного процесса, но не думаю что большая. 4. хотя бы приблизительный размер буфера можно узнать одним вызовом ZwQuerySystemInformation. и не выделять сразу 64кб памяти (зачастую 30 из которых лишние). кто запрещает - узнай приблизительный размер и запускай цикл, увеличивая размер буфера в случае неудачи на размер одной-двух структур. а тут получается пальцем в небо.
Раз читал МСДН, то надо было ещё и шапку перевести. Вообще что за бред ты тут развел? Если ты умнее M$ - напиши свой аналог. Потому что во 1x: во времена Win2k это в MSDN не было вообще, во 2x: никто никого не вводил в заблуждение. Это внутреннее апи и как хотят так его и декларируют. x64 Интересная позиция. Что бы вы все делали без скомунизденных исходников?
интересный подход... то есть функции документированы, а использовать их нельзя. зачем же их документировать? что я и пытаюсь сделать, заюзав вместо Process32First, Process32Next натив апи ZwQuerySystemInformation. получается что вы свой совет называете бредом? пусть дулают. видимо вы совершенно не понимаете к чему я привёл пример реализации CreateToolhelp32Snapshot. Я привёл это за тем, чтобы показать что описание MSDN не соответствует реализации функций. если следовать MSDN, то оптимальнее было бы реализовать иначе.
Quark Винапи гуан полный, я не пойму что ты хочешь сделать. Ыы песикиато, пример это листинг иды В сорсах более конкретно. ;-------------------------------------------------------------------- Это ты бредишь, если решил юзать натив(как и я ), то и не думай о винапи. Выбор мелкомягких ведь не идеален, винапи вообще кривые. Чего тока стоит баг слепков с перечислением куч, это точно студенты писали, как ктото сказал. Если хрю не нравится напиши свою ось DD
Quark, подумайте логически.. Если вы припомощи етой функции хотите узнать список процессов, то как она может вернуть размер буфера, а вдруг в ето же время будет запущен еще один процесс (ЧИСТО ЛОГИЧЕСКИ)? Юзайте ступенчатое увеличение буфера (в разумных пределах). п.с. и смотрите в отладчике SYSTEM_PROCESS_INFORMATION (все пи*дят).
Тем не менее размер буфера она таки возвращает. Система возвращает размер буфера, необходимый на момент вызова, а не "вообще". На время вычисления размера какие-либо изменения в списках процессов/потоков не блокируются, т.к. это операции атомарные, нет нужды.
А кто-нибудь пробывал ZwQueryVirtualMemory с классом 2 (или GetMappedImageFileName) ? У меня на 2к сп2 всегда возвращаеться c0000141, хотя судя по сорцам и ошибке этот класс поддерживаеться.
tylerdurden Какое отношение к поддержке имеет c0000141? GetMappedImageFileName - это psapi.GetMappedFileName?