Beefy Boxes and Bandwidth Generously Provided by pair Networks
Think about Loose Coupling

NtQuerySystemInformation/Task Manger processes tab with Win32::API

by bulk88 (Priest)
on Dec 15, 2012 at 06:04 UTC ( #1008938=CUFP: print w/replies, xml ) Need Help??

Someone asked for Task Manager style information, without parsing pslist (a MS command line tool similar to Task Manager and Process Explorer), or using WMI (the "official way" according to Win32::Process::Info). So here is the answer in Perl. The author of Win32::Process::Info decided to not use Native API Win32::Process::Info::NT leaving only WMI as the alternative according to what I've been told. Anyway, here is calling NtQuerySystemInformation for Task Manager like info using Win32::API. Tested on Windows XP 64 bit and 32 bit corresponding bit Perls on each OS. It is rough (uninformative errors, assumptions about buffer sizes, etc), and the last 1/3rd of the struct is never processed. I dont plan to finish it, but more than half the work was done. Comparing the Dumper outputs with Task Manager processes tab shows this is the same info.
#!/usr/bin/perl -w use Win32::API; use Math::Int64 qw ( native_to_int64 int64_to_string); use Data::Dumper; use warnings; use strict; BEGIN { use Config; eval ' sub PTR_LET () { "' .($Config{ptrsize} == 8 ? 'Q' : 'L'). '" }'; } #Win32::API doesnt do enums Win32::API::Type->typedef( 'SYSTEM_INFORMATION_CLASS', 'ULONG' ); my $api = Win32::API::More->new('ntdll.dll', ' NTSTATUS WINAPI NtQuerySystemInformation( SYSTEM_INFORMATION_CLASS SystemInformationClass, PVOID SystemInformation, ULONG SystemInformationLength, PULONG ReturnLength );'); #uninfomative error, GetLastError should be fetched die "Win32::API failure" if !$api; #this should really be a loop, a fixed 65KB is wrong, #NtQuerySystemInformation will fail with STATUS_INFO_LENGTH_MISMATCH i +f the buffer #is not long enough #changing \x00 to \xff and comparing the before and after will show wh +at #reserved fields are never filled and truly have no meaning my $buf = "\x00" x 65000; my $retlen = 0; # 5 == SystemProcessInformation my $ret = $api->Call(5, $buf, length($buf), $retlen ); #todo print NTSTATUS code die "failed " if $ret; #ImageName.Buffer is a pointer to inside $buf, if $buf is realloced #there is a problem, so save the PV, then use that to convert Buffer t +o #offset not a ptr later my $bufptr = unpack(PTR_LET, pack('p', $buf)); #how far are we into the buffer, part of extracting ImageName.Buffer my $bufoffset = 0; print "retlen $retlen ret $ret\n"; #cut off uninit data at the end $buf = substr($buf, 0, $retlen); my %h; do { ($h{NextEntryOffset}, $h{NumberOfThreads}, $h{Reserved1}, $h{Reserved2}, $h{Reserved3}, $h{CreateTime}, $h{UserTime}, $h{KernelTime}, $h{ImageName}, $h{BasePriority}, $h{ProcessId}, $h{InheritedFromProcessId}, $h{HandleCount}, $h{Reserved4}, $h{Reserved5}, $h{PrivatePageCount} ) = unpack('LL(a[8])[6]a[SS'.(PTR_LET eq 'Q' ? 'x!['.PTR_LET.']' : + '').PTR_LET.']lx!['.PTR_LET.']' #pid .PTR_LET.'' #parent pid .PTR_LET. #handle count, 2 reserveds, private page count 'LLLL' #VM_COUNTERS VirtualMemoryCounters; #IO_COUNTERS IoCounters; #SYSTEM_THREAD Threads[0]; #not done/todo , $buf); #portable 64 bit int conversion, these are strings now $h{Reserved1} = int64_to_string(native_to_int64($h{Reserved1})); $h{Reserved2} = int64_to_string(native_to_int64($h{Reserved2})); $h{Reserved3} = int64_to_string(native_to_int64($h{Reserved3})); $h{CreateTime} = int64_to_string(native_to_int64($h{CreateTime})); $h{UserTime} = int64_to_string(native_to_int64($h{UserTime})); $h{KernelTime} = int64_to_string(native_to_int64($h{KernelTime})); { #this is still packed, make a copy my $in = $h{ImageName}; $h{ImageName} = {}; ($h{ImageName}->{Length}, $h{ImageName}->{MaximumLength}, $h{ImageName}->{Buffer} ) = unpack('SS'.(PTR_LET eq 'Q' ? 'x!['.PTR_LET.']' : '').PTR_ +LET, $in); #Buffer is still packed, but convert the pointer to the offset + into the #$buf $h{ImageName}->{Buffer} = substr($buf, $h{ImageName}->{Buffer} +-$bufptr-$bufoffset, $h{ImageName}->{Length}); #$h{ImageName}->{Buffer} is in UTF16 wont print nicely to cons +ole } #slice off the processed SYSTEM_PROCESS_INFORMATION struct and tra +iling #VLA/unprocesed data $buf = substr($buf, $h{NextEntryOffset}); $bufoffset += $h{NextEntryOffset}; print Dumper(\%h); } while ($h{NextEntryOffset});
This is the struct that the above script decodes. Debate exists about what is the correct struct for SystemProcessInformation . This is correct for Windows XP I guess. Vista/7 IDK.
typedef struct _SYSTEM_PROCESS_INFORMATION { ULONG NextEntryOffset; ULONG NumberOfThreads; LARGE_INTEGER Reserved[3]; LARGE_INTEGER CreateTime; LARGE_INTEGER UserTime; LARGE_INTEGER KernelTime; UNICODE_STRING ImageName; KPRIORITY BasePriority; HANDLE ProcessId; HANDLE InheritedFromProcessId; ULONG HandleCount; ULONG Reserved2[2]; ULONG PrivatePageCount; VM_COUNTERS VirtualMemoryCounters; IO_COUNTERS IoCounters; SYSTEM_THREAD Threads[0]; } SYSTEM_PROCESS_INFORMATION, *PSYSTEM_PROCESS_INFORMATION;
The h in %h means hash.

Replies are listed 'Best First'.
Re: NtQuerySystemInformation/Task Manger processes tab with Win32::API (win32 cwd/pwd from pid)
by Anonymous Monk on Dec 15, 2012 at 07:25 UTC

    Can you retrieve cwd/pwd from pid?

    Maybe using GetCurrentDirectoryFromPid?

    There is Win32::EnvProcess but it doesn't quite work for me, and I'm only interested in read only access

    volatility looks interesting, but i'd consider GUITest-ing procexp before resorting to python :)

    The author of Win32::Process::Info decided to not use Native API Win32::Process::Info::NT leaving only WMI as the alternative according to what I've been told.

    Well, Win32::Process::Info::NT "works" but the amount of info is less

      tlist tool will list the starting command line and cwd for a process, or use ReadProcessMemory and PEB traversal, tlist and process explorer both do ReadProcessMemory and PEB traversal. I suggest writing some XS code, since doing ReadProcessMemory and PEB stuff with Win32::API is possible, but painful to parse all the structs, and remain 32 and 64 bit compliant.

      edit: google says there is Win32::Process::Memory, dont know if it works, parsing the structs is the hardest job, not looking in another processes memory, also there is Win32::Process::CommandLine.

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: CUFP [id://1008938]
Approved by Athanasius
and the questions are moot...

How do I use this? | Other CB clients
Other Users?
Others avoiding work at the Monastery: (5)
As of 2018-03-19 01:59 GMT
Find Nodes?
    Voting Booth?
    When I think of a mole I think of:

    Results (231 votes). Check out past polls.