├── gif.gif
├── README.md
├── install.py
└── pystat_core.py
/gif.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/roothaxor/PyStat/HEAD/gif.gif
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # PyStat - Advanced Netstat For Windows
2 | #### Compatible with Python Version 2.7
3 | [](https://www.roothaxor.in)
4 | [](https://github.com/roothaxor/The-Password-Manager)
5 |
6 | #### Features
7 | * Know remote address of process
8 | * Know remote ports of process
9 | * Know which user using process along with title & PID
10 |
11 | #### Changelogs:
12 | * Auto Install python modules support added in install.py
13 |
14 | ### Installation Guide:
15 | > Download the [.zip file](https://github.com/roothaxor/PyStat/archive/master.zip)
16 |
17 | > Extract the pystat folder from .zip file to some drive i.e `C:\tools\pystat`
18 |
19 | > Goto `C:\tools\pystat` Press SHIFT KEY + RIGHT CLICK and select open Command Window here
20 |
21 | > Enter this command `python install.py`, Enjoy
22 |
23 | * Warning! Dont move pystat folder after installation, will stop working
24 |
25 | #### In Work!
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/install.py:
--------------------------------------------------------------------------------
1 | import os, sys
2 | from sys import platform as _platform
3 | import shutil
4 | try:
5 | from termcolor import colored
6 | except ImportError:
7 | print '[!] Failed to Import termcolor'
8 | try:
9 | choice = raw_input('[*] Wana install termcolor? [y/n] ')
10 | except KeyboardInterrupt:
11 | print '\n[!] User Interrupted Choice'
12 | sys.exit(1)
13 | if choice.strip().lower()[0] == 'y':
14 | print '[*] Attempting to Install termcolor... ',
15 | sys.stdout.flush()
16 | try:
17 | import pip
18 | pip.main(['install', '-q', 'termcolor==1.1.0'])
19 | from termcolor import colored
20 | print '[DONE]'
21 | except Exception:
22 | print '[FAIL]'
23 | sys.exit(1)
24 | elif choice.strip().lower()[0] == 'n':
25 | print '[*] User Denied Auto-install'
26 | sys.exit(1)
27 | else:
28 | print '[!] Invalid Decision'
29 | sys.exit(1)
30 | try:
31 | import colorama
32 | except ImportError:
33 | print '[!] Failed to Import colorama'
34 | try:
35 | choice = raw_input('[*] Wana install colorama? [y/n] ')
36 | except KeyboardInterrupt:
37 | print '\n[!] User Interrupted Choice'
38 | sys.exit(1)
39 | if choice.strip().lower()[0] == 'y':
40 | print '[*] Attempting to Install colorama... ',
41 | sys.stdout.flush()
42 | try:
43 | import pip
44 | pip.main(['install', '-q', 'colorama==0.3.9'])
45 | import colorama
46 | print '[DONE]'
47 | except Exception:
48 | print '[FAIL]'
49 | sys.exit(1)
50 | elif choice.strip().lower()[0] == 'n':
51 | print '[*] User Denied Auto-install'
52 | sys.exit(1)
53 | else:
54 | print '[!] Invalid Decision'
55 | sys.exit(1)
56 |
57 |
58 | if _platform == 'win32':
59 | import colorama
60 | colorama.init()
61 |
62 | def yellow(text):
63 | return colored(text, 'yellow', attrs=['bold'])
64 |
65 | def green(text):
66 | return colored(text, 'green', attrs=['bold'])
67 |
68 | def red(text):
69 | return colored(text, 'red', attrs=['bold'])
70 |
71 | def cyan(text):
72 | return colored(text, 'cyan', attrs=['bold'])
73 |
74 | loc = os.getcwd()
75 | file = loc+'\pystat.bat'
76 | contfile = loc+'\pystat_core.py'
77 | cont = '''@echo off
78 | python %s
79 | pause'''%(contfile)
80 | out = open(file, 'w')
81 | out.write(cont)
82 | out.close()
83 | os.system('cls')
84 | print green("\n\n\n[!] Script Generated pystat.bat file")
85 | dest = os.environ['WINDIR']
86 | full_file_name = file
87 | try:
88 | shutil.copy(full_file_name, dest)
89 | except IOError:
90 | print red("\nError:")+cyan(" Permission denied While moving pystat.bat to C:\Windows")
91 | print green("\n[!] Please copy pystat.bat file to C:\Windows")
92 | print green("\n[+] For test open CMD and enter pystat\n\n\n")
--------------------------------------------------------------------------------
/pystat_core.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python2
2 | # -*- coding: utf-8 -*-
3 | import os, re, time, sys
4 | from subprocess import check_output
5 | from sys import platform as _platform
6 | from termcolor import colored
7 | if _platform == 'win32':
8 | import colorama
9 | colorama.init()
10 |
11 | def yellow(text):
12 | return colored(text, 'yellow', attrs=['bold'])
13 |
14 | def green(text):
15 | return colored(text, 'green', attrs=['bold'])
16 |
17 | def red(text):
18 | return colored(text, 'red', attrs=['bold'])
19 |
20 | def cyan(text):
21 | return colored(text, 'cyan', attrs=['bold'])
22 |
23 |
24 | infrm = '''
25 | ===============================================================================================================================================================
26 | Port RemoteIP PID Executable Name User Title
27 | ==============================================================================================================================================================='''
28 |
29 |
30 | def id_netstat_processes():
31 |
32 | # First Run netstat to get network connections
33 | # Options
34 | # a Displays all active TCP connections and the TCP and UDP ports on which the computer is listening.
35 | # o Displays active TCP connections and includes the process ID (PID) for each
36 | # connection. You can find the application based on the PID on the Processes
37 | # tab inWindows Task Manager. This parameter can be combined with -a, -n, and -p.
38 | # n Displays active TCP connections, however, addresses and port numbers are
39 | # expressed numerically and no attempt is made to determine names.
40 | result = check_output("netstat -aon", shell=True)
41 |
42 | # Now make an array of terms to remove from the data obtained from netstat
43 | clean_up_array = [
44 | ("Active Connections", ""),
45 | ("Proto", ""),
46 | ("Local Address", ""),
47 | ("Foreign Address", ""),
48 | ("State", ""),
49 | ("PID", ""),
50 | ("\r", ""),
51 | ("\t", " ")
52 | ]
53 |
54 | # Remove terms from the netstat data
55 | for find, replace in clean_up_array:
56 | result = result.replace(find, replace)
57 |
58 | # * Because I am feeling feisty, I will utilize an evil regular expression to extract the
59 | # netstat information via regex groups via the () command
60 | #
61 | # * Likewise Because terminal output is space padded rather than tabbed we need to account
62 | # for variable spacing via the regex (space)* or ' *' expression
63 | #
64 | # * Becuase the 1st group is either UDP or TCP use (UDP|TCP) to find either or
65 | #
66 | # * Because the 2ed group is either a IPV4 xxx.xxx.xxx.xxx or IPV6 XXXX::XXXX::XXXX::XXXX::XXXX%xx address or [::]
67 | # Use [0-9]*\\.[0-9]*\\.[0-9]*\\.[0-9]* for any or none number length with dots or
68 | # [ *[a-z0-9]*:* *[a-z0-9]*:* *[a-z0-9]*:* *[a-z0-9]*:* *[a-z0-9%]*\\] for any or none letters or numbers of : until the port :
69 | #
70 | # * Because the 3ed group is the port use any number [0-9]*
71 | #
72 | # * Because the 4th group is remote ip (i only had ipv4) or *:* use [0-9]*\\.[0-9]*\\.[0-9]*\\.[0-9]*|\\[:*\\] or \\*
73 | #
74 | # * Because the 5th group is the remote ip use any number [0-9]*
75 | #
76 | # * Because the 6th group is the status use LISTENING|ESTABLISHED|TIME_WAIT|CLOSE_WAIT with any or none group find
77 | #
78 | # * Becuase the 7th group is pid use any number [0-9]*
79 | # a ugly regex string that extracts the required information into groups... does not support IPV6 remote address atm but supports local IPV6
80 | reexstring = " *(UDP|TCP) *([0-9]*\\.[0-9]*\\.[0-9]*\\.[0-9]*|\\[ *[a-z0-9]*:* *[a-z0-9]*:* *[a-z0-9]*:* *[a-z0-9]*:* *[a-z0-9%]*\\]):([0-9]*) *([0-9]*\\.[0-9]*\\.[0-9]*\\.[0-9]*|\\[:*\\]|\\*):(\\*|[0-9]*) *(LISTENING|ESTABLISHED|TIME_WAIT|CLOSE_WAIT)* *([0-9]*)"
81 |
82 | # Build the regex string
83 | regexcompiled = re.compile(reexstring)
84 |
85 | # Process the input
86 | items = regexcompiled.finditer(result)
87 |
88 | networkitems = []
89 |
90 | # Loop thru the results
91 | for match in items:
92 | # we could just do data.append((match.groups())) but do this for user Configurability
93 | # Extract and trim the data obtained
94 | networktype = match.group(1).strip()
95 | localip = match.group(2).strip()
96 | localport = match.group(3).strip()
97 | remoteip = match.group(4).strip()
98 | remoteport = match.group(5).strip()
99 |
100 | # Because status can be None we need to check for None
101 | if not match.group(6) is None:
102 | status = match.group(6).strip()
103 | else:
104 | status = ""
105 | pid = match.group(7).strip()
106 |
107 | # Append items to an array for future processing
108 | networkitems.append(( localip, localport, remoteip, remoteport, status, pid))
109 |
110 | # At this point we are ready to get a list of all PID running
111 | tasklist = check_output("tasklist /v", shell=True)
112 |
113 | # Again our console result needs to be cleaned up prior to processing
114 | clean_up_array = [
115 | ("Image Name", "" ),
116 | ("PID", "" ),
117 | ("Session Name", "" ),
118 | ("Session#", "" ),
119 | ("Mem Usage", "" ),
120 | ("Status", "" ),
121 | ("User Name", "" ),
122 | ("CPU Time", "" ),
123 | ("Window Title", "" ),
124 | ("=",""),
125 | ("\r", ""),
126 | ("\t", " ")
127 | ]
128 |
129 | # Remove terms from the tasklist data
130 | for find, replace in clean_up_array:
131 | tasklist = tasklist.replace(find, replace)
132 |
133 |
134 | # Because application names can have spaces in them , our regex becomes a touch more complex and requires look aheads via ?
135 | # Likewise, because the terminal is heavily space padded we can safely assuming two spaces will end each segment
136 | # thus, ' *' (or space space *) and ' *' (space space space *) are used in the look ahead as group stoppers
137 | # Beyond this, wildcard (.*) for any characters are used for group extraction
138 | regexstring2 = "^(.*?) *([0-9]*) *(.*?) *([0-9]*) *([0-9,]* .) *(.*?) *(.*?) *([0-9:]*) *(.*?) "
139 |
140 | # To make life easier, a dictionary will be utilized to lookup the pid
141 | tasks = {}
142 |
143 | # Build the regex string And allow for multiline processing
144 | regexcompiled2 = re.compile(regexstring2, re.MULTILINE)
145 |
146 | # Process the input
147 | items = regexcompiled2.finditer(tasklist)
148 |
149 | # Loop thru the results
150 | for match in items:
151 | # Extract and trim the data obtained
152 | imagename = match.group(1).strip()
153 | pid = match.group(2).strip()
154 |
155 | # Sometimes this approach yields an empty string at the start check for this and continue if found
156 | if pid == '':
157 | continue
158 |
159 | sessionname = match.group(3).strip()
160 | sessionnumber = match.group(4).strip()
161 | memory = match.group(5).strip()
162 | status = match.group(6).strip()
163 | user = match.group(7).strip()
164 | cputime = match.group(8).strip()
165 | title = match.group(9).strip()
166 |
167 | # Populate our dictionary with information
168 | tasks[pid] = (imagename,sessionname,sessionnumber,memory,status,user,cputime,title)
169 |
170 | # Create a variable to hold our output
171 | output = ""
172 | # Loop thru all netstat items
173 | for item in networkitems:
174 | # Extract our array object
175 | localip, localport, remoteip, remoteport, status, pid = item
176 |
177 | # See if the PID exists within our PID array
178 | if pid in tasks.keys():
179 | # If so extract the PID information and add it to the output
180 | imagename,sessionname,sessionnumber,memory,status,user,cputime,title = tasks[pid]
181 | output += localport.ljust(10) + remoteip.ljust(20) + pid.ljust(10) + imagename.ljust(35) + user.ljust(35) + title + "\n"
182 | else:
183 | # If not report the error in the output, if this happens then the application is likely something hidden deep in
184 | # administrative privileges and googling will be required to attempt to access it. This is the domain of viruses!
185 | output += localport.ljust(10) + remoteip.ljust(20) + "PID "+ pid +" Missing" + "\n"
186 |
187 | # Print output, resize Dos screen size
188 | os.system('mode 160')
189 | os.system('title Python netstat v.0.0.7')
190 | print green(infrm)
191 | print cyan(output)
192 | # This is our application entry point
193 | if __name__ == "__main__":
194 | # Run our extraction function
195 | id_netstat_processes()
--------------------------------------------------------------------------------