-
Notifications
You must be signed in to change notification settings - Fork 7
/
AutomaticSecurityTracker.py
224 lines (183 loc) · 7.78 KB
/
AutomaticSecurityTracker.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
import time
import subprocess, platform
import ctypes
# Command line arguments.
import sys
import argparse
# Windows log event.
import win32api
import win32con
import win32evtlog
import win32security
import win32evtlogutil
# Parse cmd line args.
parser = argparse.ArgumentParser(description="Track if station is locked, or instead if phone is connected to WiFi, \
and if iSpy isn't running, then run iSpy! \
Otherwise, exit iSpy.")
parser.add_argument('--debug',
default = False,
choices = ['true', 'false'],
metavar = 'false',
help = 'Print debug messages.')
parser.add_argument('--ping',
default = '',
metavar = '192.168.1.2',
help = 'IP of the phone to be reachable. \
Find yours in your router settings page. Disabled by default.')
parser.add_argument('--away',
default = False,
choices = ['true', 'false'],
metavar = 'false',
help = 'Only uses the phone to exit iSpy when returning home, \
otherwise uses station lock.')
parser.add_argument('--program',
default = 'iSpy.exe',
metavar = 'iSpy.exe',
help = 'Checks if this program is running or not.')
args = parser.parse_args()
### For the booleans, any arg value will be considered True, such as --debug 3ggww5. ###
# Print more information. Defaults to False.
DEBUG = args.debug and True
# IP / hostname of phone to reach on the network.
IP = args.ping
# Program to find if running. Defaults to iSpy.exe.
PROGRAM = args.program
# Only use phone when returning to exit iSpy.
AWAY = args.away and True
# Settings and data for ping testing.
class Tester:
waitTry = 5 # Time in seconds to wait before next check.
state = False # Station is locked, or device is unreachable. (Must lock/leave first to activate.)
program = PROGRAM # The process filename+extension that's searched for.
awayMode = AWAY # True will not start iSpy when phone is unreachable, only.
returned = False # Avoid starting iSpy when station locked but awayMode phone has returned, until next lock.
host = IP # The hostname or IP to ping.
maxFailures = 2 # How many ping failures before considered unreachable.
maxSuccess = 1 # How many ping successes before considered reachable.
pingResult = '' # Last returned value from ping.
failed = 0 # How many times ping has failed.
successes = 0 # How many times ping has succeded.
# Make an instance.
tester = Tester()
# Returns ping verbosity.
def ping(host):
# res = subprocess.check_output(['ping', '-n', '1', host])
process = subprocess.Popen(['ping', '-n', '1', host],
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT)
process.wait() # Returns event code.
res = process.stdout.read()
# DEBUG and print('ping result:', res)
return str(res)
# Creates a log event in Windows.
def logEvent(e, desc=''):
ph = win32api.GetCurrentProcess()
th = win32security.OpenProcessToken(ph, win32con.TOKEN_READ)
my_sid = win32security.GetTokenInformation(th, win32security.TokenUser)[0]
win32api.CloseHandle(th)
applicationName = 'Automatic Security Tracker'
eventID = e # 0 - Stop. 1 - Start.
category = 7 # Network
myType = win32evtlog.EVENTLOG_INFORMATION_TYPE
descr = [desc] # ['A warning', 'An even more dire warning']
data = None # 'Application\0Data'.encode('ascii')
win32evtlogutil.ReportEvent(
applicationName,
eventID,
eventCategory=category,
eventType=myType,
strings=descr,
data=data,
sid=my_sid
)
v = 'START' if e else 'STOP'
print('Logged event', v, e)
# Check if the Windows station is locked.
def isLocked():
hand = win32evtlog.OpenEventLog(None, "Security")
flags = win32evtlog.EVENTLOG_BACKWARDS_READ | win32evtlog.EVENTLOG_SEQUENTIAL_READ
records = win32evtlog.ReadEventLog(hand, flags, 0)
win32evtlog.CloseEventLog(hand)
# Find latest lock or unlock event.
for record in records:
eid = record.EventID
# Unlocked.
if (eid == 4801):
return False
# Locked.
elif (eid == 4800):
return True
# Assume state hasn't changed.
return tester.state
# Check if process is running.
def isRunning(name):
s = subprocess.check_output('tasklist', shell=True)
return name in str(s)
### Main loop. ###
print('Running Automatic Security Tracker...')
if tester.host:
if tester.awayMode:
mode_msg = 'Station Lock & Phone returning only.'
else:
mode_msg = 'Phone Reachability.'
else:
mode_msg = 'Station Lock.'
print('Tracking for', mode_msg)
# Let task load properly.
while True:
running = isRunning(tester.program)
# Remember the previous state.
# Avoid closing iSpy just because station is unlocked / phone is reachable
# during normal computer use.
oldState = tester.state
# Find phone on network.
if tester.host:
result = ping(tester.host) # Device IP or hostname.
# DEBUG and print('oldState:', oldState, 'isRunning:', running)
# Router can't see the device.
if 'Destination host unreachable.' in result:
tester.failed += 1
tester.successes = 0
# DEBUG and tester.failed <= 5 and print('Unreachable:', tester.failed)
# Reachable.
else:
tester.failed = 0
tester.successes += 1
# DEBUG and tester.successes <= 5 and print('Reachable:', tester.successes)
# Device considered unreachable.
if tester.failed == tester.maxFailures:
tester.state = True
# Log START to windows, if iSpy is not running.
if not running:
# Except in away mode.
if not tester.awayMode:
logEvent(1)
# Device considered reachable.
elif tester.successes == tester.maxSuccess:
tester.state = False
# Log STOP to windows, only if it was previously away,
# and if iSpy is running.
if oldState is not tester.state and running:
logEvent(0)
# Avoid restarting iSpy on station lock checks, until locked again.
tester.returned = True
if not tester.host or tester.awayMode:
# Or only check for station locked.
locked = isLocked()
DEBUG and print('oldState:', oldState, 'isRunning:', running, 'isLocked:', locked)
# Log START to windows, if station is locked, and iSpy is not running.
if locked and not running:
# Unless returned on awayMode.
if not tester.returned:
tester.state = True
logEvent(1)
# Log STOP to windows, only if it was previously locked,
# if station is unlocked, and iSpy is running.
elif not locked:
tester.state = False
# Reset returning for next lock in awayMode.
tester.returned = False
if oldState is not tester.state:
logEvent(0)
# Wait until next check.
time.sleep(tester.waitTry)