diff --git a/test.db b/DB/test.db similarity index 91% rename from test.db rename to DB/test.db index 693c4fc..72d8b3f 100644 Binary files a/test.db and b/DB/test.db differ diff --git a/LICENSE b/LICENSE deleted file mode 100644 index 261eeb9..0000000 --- a/LICENSE +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/conf/connect.conf b/conf/connect.conf new file mode 100644 index 0000000..e69de29 diff --git a/conf/test.db b/conf/test.db new file mode 100644 index 0000000..e69de29 diff --git a/requirements.txt b/requirements.txt index 779547f..fd3c9c7 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,4 +2,8 @@ docker tornado psutil supervisor -virtualenv \ No newline at end of file +virtualenv +websockets +ptyprocess +paramiko +pywinpty \ No newline at end of file diff --git a/run.py b/run.py index 7f02ec7..d14de1e 100644 --- a/run.py +++ b/run.py @@ -1,13 +1,4 @@ #! coding=utf-8 - - -''' - 常见漏洞的总结,可以在此项目里练习各种常见的web漏洞。 - 使用docker作为漏洞的容器,使用python调用容器,在web界面可以管理容器,开启,关闭。使用tornado框架开发web界面。 - -''' - - import os import sqlite3 import hashlib @@ -16,14 +7,16 @@ import re import random import asyncio +import time import tornado.httpserver import tornado.ioloop import tornado.web import tornado.websocket +import paramiko from docker_lib import Dockers_Start, Dockers_Stop, Dockers_Info -from system_info import Start_Get_Sysinfo +from utils import Start_Get_Sysinfo from log.logger import logger from tornado.options import define, options @@ -38,7 +31,7 @@ define("port", default = 8000, help = "run on the given port", type = int) define("host", default = '0.0.0.0',help = "run on the given host", type = str) -define("sqlite_path", default = "./test.db", help = "database path") +define("sqlite_path", default = "./DB/test.db", help = "database path") class Application(tornado.web.Application): @@ -73,6 +66,9 @@ def __init__(self): (r"/change_pass", Change_Pass_Handler), (r"/add_user", Add_User_Handler), + (r"/tool_manage", ToolManager), + (r"/ws", TreminalWebSocketHandler), + (r"/test", TestManager), (r".*", ErrorHandler), ] # 初始化tornado的设置 @@ -148,8 +144,27 @@ def db_update_insert(self, sql, variable = []): except Exception as e: logger.error('数据库插入更改数据出错!SQL语句为:%s,错误原因为:%s' % (sql, e)) return False - return True + + def check_and_create_table(self, table_name, create_sql): + ''' + 检查是否存在指定的数据表,如果不存在则创建 + :param table_name: 数据表名称 + :param create_sql: 创建数据表的SQL语句 + :return: 无返回值 + ''' + try: + cursors = self.application.db.cursor() + # 修改查询语句,正确检查表是否存在 + cursors.execute("SELECT count(*) FROM sqlite_master WHERE type='table' AND name=? ", (table_name,)) + if cursors.fetchone()['count(*)'] == 0: # 使用索引访问结果 + cursors.execute(create_sql) + self.application.db.commit() + logger.info(f"数据表 {table_name} 不存在,已创建。") + else: + logger.info(f"数据表 {table_name} 已存在。") + except Exception as e: + logger.error(f"检查或创建数据表 {table_name} 出错,错误原因为:{e}") def get_current_user(self): ''' @@ -330,7 +345,6 @@ class SettingHandler(BaseHandler): ''' 设置页面 ''' - @tornado.web.authenticated def get(self): self.render('change_pass.html', error='') @@ -785,7 +799,7 @@ def post(self): class Reset_System_Handler(BaseHandler): ''' - 系统重置页面 + 系统重置页面 重置系统 ''' @tornado.web.authenticated @@ -797,11 +811,11 @@ def post(self): password = self.get_argument('password', '') pass + class Add_User_Handler(BaseHandler): ''' - 系统重置页面 + 系统重置页面 新增用户 ''' - @tornado.web.authenticated def get(self): sys_pass = self.get_argument('sys_pass', '').strip() @@ -829,6 +843,139 @@ def get(self): self.render('setting.html', error = '加入用户成功!') +from utils.regProduct import generate_reg_file +class ToolManager(BaseHandler): + ''' + 工具管理界面 快捷使用攻击进行渗透测试 + ''' + @tornado.web.authenticated + def get(self): + local_tools = self.db_select('SELECT * FROM tb_local_tool;') + tool = dict() + tool.setdefault('local', {}) + tool.setdefault('remote', {}) + print(local_tools) + for local_tool in local_tools: + tool['local'][local_tool['tool_name']] = local_tool['tool_path'] + tool['remote'] = {"metasploit":"/", + "bee":"/", + "sqlmap":"/", + "nmap":"/" + } + self.render('tool_manage.html',tools=tool) + + @tornado.web.authenticated + def put(self): + # 检查是否存在本地工具表,如果不存在则创建 + self.check_and_create_table('tb_local_tool', 'CREATE TABLE tb_local_tool (id INTEGER PRIMARY KEY AUTOINCREMENT, tool_name VARCHAR(255), tool_path VARCHAR(255));') + # 检查是否存在远程工具表,如果不存在则创建 + self.check_and_create_table('tb_remote_tool', 'CREATE TABLE tb_remote_tool (id INTEGER PRIMARY KEY AUTOINCREMENT, tool_name VARCHAR(255), tool_path VARCHAR(255));') + data = self.request.body.decode('utf-8') + try: + data = json.loads(data) + except Exception as e: + logger.error('获取数据失败!') + self.write('error') + exeName = data.get('exeName', '') + exePath = data.get('exePath', '') + procotalName,file_path = generate_reg_file(exePath) + self.db_update_insert('INSERT INTO tb_local_tool (tool_name, tool_path) VALUES (?, ?);', [exeName, procotalName]) + # 文件传输 + file_name = os.path.basename(file_path) + # 设置HTTP头部,告诉浏览器这是一个文件下载响应 + self.set_header('Content-Type', 'application/json') + try: + with open(file_path, 'rb') as f: + data = f.read() # 读取文件块 + self.write(json.dumps({"status": "success","filename" : exeName +".reg","content": data.decode('utf-8')})) + except Exception as e: + self.write(json.dumps({"status": "error", "message": str(e)})) + self.finish() +''' +# class MyThread(threading.Thread): +# def __init__(self, id, chan): +# threading.Thread.__init__(self) +# self.chan = chan + +# def run(self): +# while not self.chan.chan.exit_status_ready(): +# time.sleep(0.1) +# try: +# data = self.chan.chan.recv(1024) +# self.chan.write_message(data) +# except Exception as ex: +# # 注释掉print,否则会报错,原因:库版本不对 +# # print(str(ex)) +# pass +# self.chan.sshclient.close() +# return False + +# SSH 远程连接版本 +# class SSHWebSocketHandler(tornado.websocket.WebSocketHandler): +# def open(self): +# self.sshclient = paramiko.SSHClient() +# self.sshclient.load_system_host_keys() +# self.sshclient.set_missing_host_key_policy(paramiko.AutoAddPolicy()) +# self.sshclient.connect("211.65.193.161", "22", "jhxu", "xujianhao.12345") +# self.chan = self.sshclient.invoke_shell(term='xterm') +# self.chan.settimeout(0) +# t1 = MyThread(999, self) +# t1.setDaemon(True) +# t1.start() + +# def on_message(self, message): +# try: +# print(message) +# self.chan.send(message) +# except Exception as ex: +# print(str(ex)) + +# def on_close(self): +# self.sshclient.close() + +# def check_origin(self, origin): +# # 允许跨域访问 +# return True +''' + +# pty Linux终端版本 +import pty +class TreminalWebSocketHandler(tornado.websocket.WebSocketHandler): + def open(self): + self.master_fd, slave_fd = pty.openpty() + self.pid = os.fork() + if self.pid == 0: # 子进程 + os.setsid() + os.dup2(slave_fd, 0) + os.dup2(slave_fd, 1) + os.dup2(slave_fd, 2) + os.close(slave_fd) + os.close(self.master_fd) + os.execv('/bin/bash', ['/bin/bash']) + else: # 父进程 + os.close(slave_fd) + self.ioloop = tornado.ioloop.IOLoop.current() + self.fd_handler = self.ioloop.add_handler(self.master_fd, self.handle_terminal_output, self.ioloop.READ) + + def on_message(self, message): + os.write(self.master_fd, message.encode()) + + def on_close(self): + self.ioloop.remove_handler(self.master_fd) + os.kill(self.pid, 9) + + def handle_terminal_output(self, fd, events): + if events & self.ioloop.READ: + output = os.read(self.master_fd, 1024).decode() + self.write_message(output) + +class TestManager(BaseHandler): + ''' + 工具管理界面 快捷使用攻击进行渗透测试 + ''' + @tornado.web.authenticated + def get(self): + self.render('test.html') def main(): tornado.options.parse_command_line() diff --git a/supervisor.conf b/supervisor.conf deleted file mode 100644 index 145b13e..0000000 --- a/supervisor.conf +++ /dev/null @@ -1,16 +0,0 @@ -[program:WebRange] -directory = /root/Webrange ; 程序的启动目录 -command = /usr/bin/python3 run.py ; 启动命令,可以看出与手动在命令行启动的命令是一样的 -autostart = true ; 在 supervisord 启动的时候也自动启动 -startsecs = 10 ; 启动 5 秒后没有异常退出,就当作已经正常启动了 -autorestart = true ; 程序异常退出后自动重启 -startretries = 3 ; 启动失败自动重试次数,默认是 3 -user = root ; 用哪个用户启动 -redirect_stderr = true ; 把 stderr 重定向到 stdout,默认 false -stdout_logfile_maxbytes = 20MB ; stdout 日志文件大小,默认 50MB -stdout_logfile_backups = 20 ; stdout 日志文件备份数 -; stdout 日志文件,需要注意当指定目录不存在时无法正常启动,所以需要手动创建目录(supervisord 会自动创建日志文件) -stdout_logfile = /var/log/supervisor/Webrange_log.logs - -; 可以通过 environment 来添加需要的环境变量,一种常见的用法是修改 PYTHONPATH -; environment=PYTHONPATH=$PYTHONPATH:/path/to/somewhere diff --git a/system_info/__init__.py b/system_info/__init__.py deleted file mode 100644 index 416971e..0000000 --- a/system_info/__init__.py +++ /dev/null @@ -1,6 +0,0 @@ -#! coding=utf-8 - - -from system_info.get_sysinfo import Start_Get_Sysinfo - - diff --git a/templates/layout.html b/templates/layout.html index b979241..95cf2bf 100755 --- a/templates/layout.html +++ b/templates/layout.html @@ -4,7 +4,7 @@ - Web Range + VULNMATRIX {% block css %} {% end %} @@ -27,12 +27,8 @@ - - - -
@@ -40,13 +36,12 @@
- - - - diff --git a/templates/test.html b/templates/test.html new file mode 100644 index 0000000..5fb02df --- /dev/null +++ b/templates/test.html @@ -0,0 +1,148 @@ + + + + + + + + + + + + 工具管理 + + + + + + +
+ +
+ +
+
+ + + + + + + + + + \ No newline at end of file diff --git a/templates/tool_manage.html b/templates/tool_manage.html new file mode 100644 index 0000000..bda1d62 --- /dev/null +++ b/templates/tool_manage.html @@ -0,0 +1,355 @@ +{% extends "layout.html" %} +{% block css %} + + + + + + + +{% end %} + +{% block webinfo %} +
+
+
+
+
+

Quick Start

+
+
+
+
本地工具
+ + +
+
+ + {% for index, (tool, path) in enumerate(tools['local'].items()) %} +
+ +
+ {% end %} +
+
+
+
远程工具
+
+ + {% for index, (tool, path) in enumerate(tools['remote'].items()) %} +
+ +
+ {% end %} +
+
+
+
+ +
+
    + +
+
+ +
+
+ + ] +
+
+ +{% end %} + +{% block js %} + + + + + + + + + + +{% end %} \ No newline at end of file diff --git a/test.json b/test.json deleted file mode 100644 index 9adf63d..0000000 --- a/test.json +++ /dev/null @@ -1,14 +0,0 @@ -[ - { - "name": "迅风扫描器", - "info": "巡风是一款适用于企业内网的漏洞快速应急,巡航扫描系统。", - "isupload": "true", - "types": "debug", - "tags": "扫描器", - "author": "同程", - "hub": "ysrc/xunfeng", - "flag": "", - "port": "80/tcp", - "risk": "simple" - } -] \ No newline at end of file diff --git a/tmp/CallBSEXE010.reg b/tmp/CallBSEXE010.reg new file mode 100644 index 0000000..e695e5f --- /dev/null +++ b/tmp/CallBSEXE010.reg @@ -0,0 +1,16 @@ +Windows Registry Editor Version 5.00 + +[HKEY_CLASSES_ROOT\CallBSEXE010] +@="URL: CallBSEXE010 Protocol Handler" +"URL Protocol"="" + +;E:\localExe\gy_print.exe 为本地EXE路径 +[HKEY_CLASSES_ROOT\CallBSEXE010\DefaultIcon] +@="C:\\tool\\010Editor\\010 Editor 12.0.1.exe" + +[HKEY_CLASSES_ROOT\CallBSEXE010\Shell] + +[HKEY_CLASSES_ROOT\CallBSEXE010\Shell\Open] + +[HKEY_CLASSES_ROOT\CallBSEXE010\Shell\Open\Command] +@="\"C:\\tool\\010Editor\\010 Editor 12.0.1.exe\" %1" diff --git a/tmp/CallBSEXEobsutil.reg b/tmp/CallBSEXEobsutil.reg new file mode 100644 index 0000000..787ce71 --- /dev/null +++ b/tmp/CallBSEXEobsutil.reg @@ -0,0 +1,16 @@ +Windows Registry Editor Version 5.00 + +[HKEY_CLASSES_ROOT\CallBSEXEobsutil] +@="URL: CallBSEXEobsutil Protocol Handler" +"URL Protocol"="" + +;E:\localExe\gy_print.exe 为本地EXE路径 +[HKEY_CLASSES_ROOT\CallBSEXEobsutil\DefaultIcon] +@="C:\\tool\\obsutil\\obsutil.exe" + +[HKEY_CLASSES_ROOT\CallBSEXEobsutil\Shell] + +[HKEY_CLASSES_ROOT\CallBSEXEobsutil\Shell\Open] + +[HKEY_CLASSES_ROOT\CallBSEXEobsutil\Shell\Open\Command] +@="\"C:\\tool\\obsutil\\obsutil.exe\" %1" diff --git a/system_info/.DS_Store b/utils/.DS_Store similarity index 100% rename from system_info/.DS_Store rename to utils/.DS_Store diff --git a/utils/__init__.py b/utils/__init__.py new file mode 100644 index 0000000..57d5859 --- /dev/null +++ b/utils/__init__.py @@ -0,0 +1,6 @@ +#! coding=utf-8 + + +from utils.get_sysinfo import Start_Get_Sysinfo + + diff --git a/system_info/get_sysinfo.py b/utils/get_sysinfo.py similarity index 100% rename from system_info/get_sysinfo.py rename to utils/get_sysinfo.py diff --git a/utils/index.html b/utils/index.html new file mode 100644 index 0000000..407ae7b --- /dev/null +++ b/utils/index.html @@ -0,0 +1,37 @@ + + + + + + + + + +
+ +
+
+ + +———————————————— + + 版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。 + +原文链接:https://blog.csdn.net/Naisu_kun/article/details/130774938 + diff --git a/utils/regProduct.py b/utils/regProduct.py new file mode 100644 index 0000000..e2f5a35 --- /dev/null +++ b/utils/regProduct.py @@ -0,0 +1,40 @@ +import os +import sys + +def generate_reg_file(path): + # 确保路径以 .exe 结尾 + if not path.lower().endswith('.exe'): + print("Provided path does not point to an .exe file.") + return + # 从完整路径中提取文件名 + filename = os.path.basename(path) + # 创建自定义协议名称 + protocol_name = f"CallBSEXE{filename}".split('.')[0] + protocol_name = protocol_name.split(" ")[0] + path = path.replace("\\", "\\\\") + + # 构建注册表文件内容 + reg_content = f"""Windows Registry Editor Version 5.00 + +[HKEY_CLASSES_ROOT\\{protocol_name}] +@="URL: {protocol_name} Protocol Handler" +"URL Protocol"="" + +;E:\\localExe\\gy_print.exe 为本地EXE路径 +[HKEY_CLASSES_ROOT\\{protocol_name}\\DefaultIcon] +@="{path}" + +[HKEY_CLASSES_ROOT\\{protocol_name}\\Shell] + +[HKEY_CLASSES_ROOT\\{protocol_name}\\Shell\\Open] + +[HKEY_CLASSES_ROOT\\{protocol_name}\\Shell\\Open\\Command] +@="\\"{path}\\" %1" +""" + # 写入到注册表文件 + with open(f"tmp/{protocol_name}.reg", "w",encoding="utf-8") as reg_file: + reg_file.write(reg_content) + return protocol_name,f"tmp/{protocol_name}.reg" + +# if __name__ == "__main__": +# generate_reg_file(r"C:\tool\010Editor\010 Editor 12.0.1.exe") \ No newline at end of file