Error:.exe has triggered a breakpoint.

本文深入探讨了程序开发中常见的错误类型,包括数组越界和重复使用已释放内存的问题,并提供了有效的解决方法。从基础知识出发,帮助开发者避免常见陷阱,提升编程效率。

通常你的程序编译通过,但是在run或者debug时报错,常见原因有:
(1)在使用动态数组时,索引超出长度:

 double* a = new double[n]; //n = 3
 a[4] = 0.0; //索引只有0, 1, 2

(2)释放了分配的内存,但又使用了该变量

    char *a= (char *)malloc(10); 
    free(a); 
    strcpy(a, "hello"); 
import os import random import tkinter as tk from tkinter import filedialog, messagebox, ttk import shutil import hashlib import time import pefile import os import sys class ExeProtectorApp: def __init__(self, root): self.root = root self.root.title("EXE文件保护工具 v4.1") self.root.geometry("750x680") self.root.resizable(True, True) # 设置中文字体 self.style = ttk.Style() self.style.configure("TLabel", font=("SimHei", 10)) self.style.configure("TButton", font=("SimHei", 10)) self.style.configure("TProgressbar", thickness=20) # 创建主框架 self.main_frame = ttk.Frame(root, padding="20") self.main_frame.pack(fill=tk.BOTH, expand=True) # 文件选择部分 ttk.Label(self.main_frame, text="选择EXE文件:").grid(row=0, column=0, sticky=tk.W, pady=5) self.file_path_var = tk.StringVar() ttk.Entry(self.main_frame, textvariable=self.file_path_var, width=50).grid(row=0, column=1, padx=5, pady=5) ttk.Button(self.main_frame, text="浏览...", command=self.browse_file).grid(row=0, column=2, padx=5, pady=5) # 输出目录选择 ttk.Label(self.main_frame, text="输出目录:").grid(row=1, column=0, sticky=tk.W, pady=5) self.output_dir_var = tk.StringVar() ttk.Entry(self.main_frame, textvariable=self.output_dir_var, width=50).grid(row=1, column=1, padx=5, pady=5) ttk.Button(self.main_frame, text="浏览...", command=self.browse_output_dir).grid(row=1, column=2, padx=5, pady=5) # 选项设置 options_frame = ttk.LabelFrame(self.main_frame, text="选项", padding="10") options_frame.grid(row=2, column=0, columnspan=3, sticky=(tk.W, tk.E), pady=10) ttk.Label(options_frame, text="随机字节增加范围 (KB):").grid(row=0, column=0, sticky=tk.W, pady=5) self.min_size_var = tk.IntVar(value=100) ttk.Entry(options_frame, textvariable=self.min_size_var, width=10).grid(row=0, column=1, padx=5, pady=5) ttk.Label(options_frame, text="至").grid(row=0, column=2, padx=5, pady=5) self.max_size_var = tk.IntVar(value=500) ttk.Entry(options_frame, textvariable=self.max_size_var, width=10).grid(row=0, column=3, padx=5, pady=5) ttk.Label(options_frame, text="随机性强度:").grid(row=0, column=4, sticky=tk.W, pady=5) self.random_strength = tk.StringVar(value="中") strength_options = ttk.Combobox(options_frame, textvariable=self.random_strength, state="readonly", width=12) strength_options['values'] = ("低", "中", "高") strength_options.grid(row=0, column=5, padx=5, pady=5) ttk.Label(options_frame, text="模拟程序类型:").grid(row=1, column=0, sticky=tk.W, pady=5) self.app_type = tk.StringVar(value="通用程序") app_types = ttk.Combobox(options_frame, textvariable=self.app_type, state="readonly", width=15) app_types['values'] = ("通用程序", "游戏程序", "办公软件", "系统工具", "开发工具") app_types.grid(row=1, column=1, padx=5, pady=5) self.process_method = tk.StringVar(value="standard") ttk.Radiobutton(options_frame, text="标准保护", variable=self.process_method, value="standard").grid(row=1, column=2, sticky=tk.W, pady=5) ttk.Radiobutton(options_frame, text="高级保护", variable=self.process_method, value="advanced").grid(row=1, column=3, sticky=tk.W, pady=5) # 高级选项 advanced_frame = ttk.LabelFrame(self.main_frame, text="保护选项", padding="10") advanced_frame.grid(row=3, column=0, columnspan=3, sticky=(tk.W, tk.E), pady=10) self.obfuscate_resources = tk.BooleanVar(value=True) ttk.Checkbutton(advanced_frame, text="混淆资源文件", variable=self.obfuscate_resources).grid(row=0, column=0, sticky=tk.W, pady=5) self.encrypt_sections = tk.BooleanVar(value=True) ttk.Checkbutton(advanced_frame, text="轻度代码变换", variable=self.encrypt_sections).grid(row=0, column=1, sticky=tk.W, pady=5) self.add_dummy_sections = tk.BooleanVar(value=True) ttk.Checkbutton(advanced_frame, text="添加随机数据块", variable=self.add_dummy_sections).grid(row=1, column=0, sticky=tk.W, pady=5) self.randomize_imports = tk.BooleanVar(value=True) ttk.Checkbutton(advanced_frame, text="随机化导入表顺序", variable=self.randomize_imports).grid(row=1, column=1, sticky=tk.W, pady=5) # 处理按钮 ttk.Button(self.main_frame, text="保护文件", command=self.process_file).grid(row=4, column=0, columnspan=3, pady=20) # 状态和进度条 self.status_var = tk.StringVar(value="就绪") ttk.Label(self.main_frame, textvariable=self.status_var).grid(row=5, column=0, columnspan=2, sticky=tk.W, pady=5) self.progress_var = tk.DoubleVar(value=0) self.progress_bar = ttk.Progressbar(self.main_frame, variable=self.progress_var, length=100) self.progress_bar.grid(row=5, column=2, sticky=(tk.W, tk.E), pady=5) # 默认输出目录 self.output_dir_var.set(os.path.join(os.getcwd(), "protected_exes")) # 绑定窗口关闭事件 self.root.protocol("WM_DELETE_WINDOW", self.on_closing) # 初始化随机种子 self.initialize_random_seed() def initialize_random_seed(self): seed_material = ( time.time_ns().to_bytes(8, 'big') + os.getpid().to_bytes(4, 'big') + os.urandom(16) ) seed = int.from_bytes(hashlib.sha256(seed_material).digest(), 'big') random.seed(seed) def browse_file(self): file_path = filedialog.askopenfilename(filetypes=[("可执行文件", "*.exe"), ("所有文件", "*.*")]) if file_path: self.file_path_var.set(file_path) def browse_output_dir(self): dir_path = filedialog.askdirectory() if dir_path: self.output_dir_var.set(dir_path) def process_file(self): exe_path = self.file_path_var.get() output_dir = self.output_dir_var.get() if not exe_path: messagebox.showerror("错误", "请选择一个EXE文件") return if not os.path.exists(exe_path): messagebox.showerror("错误", "选择的文件不存在") return if not output_dir: messagebox.showerror("错误", "请选择输出目录") return if not os.path.exists(output_dir): try: os.makedirs(output_dir) except: messagebox.showerror("错误", "无法创建输出目录") return file_name, file_ext = os.path.splitext(os.path.basename(exe_path)) random_suffix = hashlib.md5(str(time.time_ns()).encode()).hexdigest()[:8] output_path = os.path.join(output_dir, f"{file_name}_protected_{random_suffix}{file_ext}") try: self.status_var.set("正在处理文件...") self.progress_var.set(0) self.root.update() min_size = self.min_size_var.get() max_size = self.max_size_var.get() if min_size < 0 or max_size < 0 or min_size > max_size: messagebox.showerror("错误", "请设置有效的字节增加范围") return strength_factor = 1.0 if self.random_strength.get() == "高": strength_factor = 1.5 elif self.random_strength.get() == "低": strength_factor = 0.5 adjusted_min = int(min_size * strength_factor) adjusted_max = int(max_size * strength_factor) random_size_kb = random.randint(adjusted_min, adjusted_max) random_size_bytes = random_size_kb * 1024 shutil.copy2(exe_path, output_path) original_hash = self.calculate_file_hash(exe_path) self.progress_var.set(5) self.root.update() if self.process_method.get() == "standard": self.standard_protection(output_path, random_size_bytes) else: self.advanced_protection(output_path, random_size_bytes) modified_hash = self.calculate_file_hash(output_path) self.progress_var.set(95) self.root.update() if self.verify_exe_file(output_path): self.status_var.set("文件处理完成") self.progress_var.set(100) messagebox.showinfo( "成功", f"文件保护成功!\n" f"原始文件大小: {os.path.getsize(exe_path) // 1024} KB\n" f"处理后文件大小: {os.path.getsize(output_path) // 1024} KB\n" f"增加了: {random_size_kb} KB\n\n" f"原始文件哈希 (MD5): {original_hash}\n" f"处理后文件哈希 (MD5): {modified_hash}\n\n" f"文件已保存至: {output_path}" ) else: self.status_var.set("文件验证失败") self.progress_var.set(100) messagebox.showwarning("警告", "处理后的文件可能需要在特定环境运行") except Exception as e: self.status_var.set("处理过程中出错") messagebox.showerror("错误", f"处理文件时出错: {str(e)}") finally: self.progress_var.set(0) self.initialize_random_seed() def calculate_file_hash(self, file_path): hash_md5 = hashlib.md5() with open(file_path, "rb") as f: for chunk in iter(lambda: f.read(4096), b""): hash_md5.update(chunk) return hash_md5.hexdigest() def standard_protection(self, file_path, additional_bytes): try: pe = pefile.PE(file_path) section_count = random.randint(1, 3) for _ in range(section_count): new_section = pefile.SectionStructure(pe.__IMAGE_SECTION_HEADER_format__) new_section.Name = self.generate_sane_section_name() section_size = random.randint(0x1000, 0x8000) new_section.Misc_VirtualSize = section_size base_virtual_address = (pe.sections[-1].VirtualAddress + pe.sections[-1].Misc_VirtualSize + 0x1000 - 1) & ~0xFFF new_section.VirtualAddress = base_virtual_address + random.randint(0, 0x1000) base_raw_data = (pe.sections[-1].PointerToRawData + pe.sections[-1].SizeOfRawData + 0x1000 - 1) & ~0xFFF new_section.PointerToRawData = base_raw_data + random.randint(0, 0x1000) new_section.SizeOfRawData = section_size section_flags = [0xC0000040, 0x40000040, 0x20000040, 0x80000040, 0x00000040, 0xE0000040] new_section.Characteristics = random.choice(section_flags) app_type = self.app_type.get() new_data = self.generate_application_specific_data(section_size, app_type) pe.set_bytes_at_offset(new_section.PointerToRawData, new_data) pe.sections.append(new_section) pe.FILE_HEADER.NumberOfSections += 1 pe.OPTIONAL_HEADER.SizeOfImage = (new_section.VirtualAddress + new_section.Misc_VirtualSize + 0x1000 - 1) & ~0xFFF if self.encrypt_sections.get(): self.apply_mild_code_transformations(pe) if self.randomize_imports.get() and hasattr(pe, 'DIRECTORY_ENTRY_IMPORT'): random.shuffle(pe.DIRECTORY_ENTRY_IMPORT) self.safe_modify_exe_file(file_path, additional_bytes) pe.FILE_HEADER.TimeDateStamp = int(time.time()) + random.randint(-3600, 3600) pe.write(file_path) pe.close() except Exception as e: print(f"标准保护执行: {e}") self.safe_modify_exe_file(file_path, additional_bytes) def advanced_protection(self, file_path, additional_bytes): try: pe = pefile.PE(file_path) section_count = random.randint(2, 4) for _ in range(section_count): new_section = pefile.SectionStructure(pe.__IMAGE_SECTION_HEADER_format__) new_section.Name = self.generate_sane_section_name() section_size = random.randint(0x1000, 0x10000) new_section.Misc_VirtualSize = section_size base_virtual_address = (pe.sections[-1].VirtualAddress + pe.sections[-1].Misc_VirtualSize + 0x1000 - 1) & ~0xFFF new_section.VirtualAddress = base_virtual_address + random.randint(0, 0x2000) base_raw_data = (pe.sections[-1].PointerToRawData + pe.sections[-1].SizeOfRawData + 0x1000 - 1) & ~0xFFF new_section.PointerToRawData = base_raw_data + random.randint(0, 0x2000) new_section.SizeOfRawData = section_size section_flags = [0xC0000040, 0x40000040, 0x20000040, 0x80000040, 0x00000040, 0xE0000040, 0x00000080, 0x40000080] new_section.Characteristics = random.choice(section_flags) app_type = self.app_type.get() new_data = self.generate_application_specific_data(section_size, app_type) pe.set_bytes_at_offset(new_section.PointerToRawData, new_data) pe.sections.append(new_section) pe.FILE_HEADER.NumberOfSections += 1 pe.OPTIONAL_HEADER.SizeOfImage = (new_section.VirtualAddress + new_section.Misc_VirtualSize + 0x1000 - 1) & ~0xFFF if self.encrypt_sections.get(): self.apply_mild_code_transformations(pe) if self.obfuscate_resources.get() and hasattr(pe, 'DIRECTORY_ENTRY_RESOURCE'): self.obfuscate_pe_resources(pe) if self.randomize_imports.get() and hasattr(pe, 'DIRECTORY_ENTRY_IMPORT'): for _ in range(random.randint(1, 3)): random.shuffle(pe.DIRECTORY_ENTRY_IMPORT) if self.add_dummy_sections.get(): dummy_size = random.randint(additional_bytes // 2, additional_bytes) self.safe_modify_exe_file(file_path, dummy_size) additional_bytes -= dummy_size self.safe_modify_exe_file(file_path, additional_bytes) pe.FILE_HEADER.TimeDateStamp = int(time.time()) + random.randint(-86400, 86400) pe.write(file_path) pe.close() except Exception as e: print(f"高级保护执行: {e}") self.standard_protection(file_path, additional_bytes) def safe_modify_exe_file(self, file_path, additional_bytes): with open(file_path, 'ab') as f: app_type = self.app_type.get() data = self.generate_application_specific_data(additional_bytes, app_type) f.write(data) def generate_application_specific_data(self, size, app_type): data = bytearray() type_templates = { "通用程序": [ b"C:\\Program Files\\Common Files\\\x00", b"HKLM\\Software\\Microsoft\\Windows\\\x00", b"ERROR_ACCESS_DENIED\x00", b"SUCCESS\x00", b"CONFIG_FILE\x00", b"LOG_FILE\x00", (0x00000001).to_bytes(4, 'little'), (0x00000100).to_bytes(4, 'little'), (0x00010000).to_bytes(4, 'little'), ], "游戏程序": [ b"C:\\Program Files\\Game\\Data\\\x00", b"C:\\Users\\Public\\Documents\\GameSaves\\\x00", b"TEXTURE_", b"MODEL_", b"SOUND_", b"LEVEL_", b"SCORE_", b"PLAYER_", b"ENEMY_", b"WEAPON_", (0x000F4240).to_bytes(4, 'little'), (0x000003E8).to_bytes(4, 'little'), ], "办公软件": [ b"C:\\Users\\%USERNAME%\\Documents\\\x00", b"File Format: DOCX\x00", b"File Format: XLSX\x00", b"Page ", b"Sheet ", b"Table ", b"Font ", b"Style ", b"Paragraph ", b"Header", b"Footer", (0x0000000A).to_bytes(4, 'little'), (0x00000014).to_bytes(4, 'little'), ], "系统工具": [ b"C:\\Windows\\System32\\\x00", b"C:\\Windows\\SysWOW64\\\x00", b"HKLM\\SYSTEM\\CurrentControlSet\\\x00", b"Driver ", b"Service ", b"Device ", b"Registry ", b"Process ", b"Thread ", (0x00000001).to_bytes(4, 'little'), (0x00000000).to_bytes(4, 'little'), (0xFFFFFFFF).to_bytes(4, 'little'), ], "开发工具": [ b"C:\\Program Files\\Developer\\SDK\\\x00", b"C:\\Users\\%USERNAME%\\Source\\\x00", b"Compiler ", b"Linker ", b"Debugger ", b"Library ", b"Include ", b"Namespace ", b"Class ", b"Function ", b"Variable ", (0x00000000).to_bytes(4, 'little'), (0x00000001).to_bytes(4, 'little'), (0x00000002).to_bytes(4, 'little'), ] } templates = type_templates.get(app_type, type_templates["通用程序"]) template_usage = 0.7 if self.random_strength.get() == "高": template_usage = 0.5 elif self.random_strength.get() == "低": template_usage = 0.9 while len(data) < size: if random.random() < template_usage: data.extend(random.choice(templates)) else: random_len = random.randint(1, 64) data.extend(os.urandom(random_len)) if random.random() < 0.3: data.extend(b'\x00' * random.randint(1, 8)) elif random.random() < 0.2: data.extend(b' ' * random.randint(1, 16)) return data[:size] def generate_sane_section_name(self): base_names = [ b'.data', b'.rdata', b'.text', b'.rsrc', b'.reloc', b'.bss', b'.edata', b'.idata', b'.pdata', b'.tls', b'.data1', b'.rdata2', b'.text1', b'.rsrc1', b'.data_', b'.rdata_', b'.text_', b'.rsrc_', b'.init', b'.fini', b'.ctors', b'.dtors', b'.gnu', b'.note', b'.eh_frame', b'.debug' ] name = random.choice(base_names) if random.random() < 0.7: if random.random() < 0.5: suffix = str(random.randint(10, 99)).encode() else: suffix = bytes(random.choice('abcdefghijklmnopqrstuvwxyz') for _ in range(2)) name = name[:8-len(suffix)] + suffix return name.ljust(8, b'\x00')[:8] def apply_mild_code_transformations(self, pe): text_section = None for section in pe.sections: if b'.text' in section.Name: text_section = section break if text_section: data = pe.get_data(text_section.VirtualAddress, text_section.SizeOfRawData) if not isinstance(data, bytes): data = bytes(data) data_list = list(data) transform_count = len(data_list) // 200 if self.random_strength.get() == "高": transform_count = len(data_list) // 100 elif self.random_strength.get() == "低": transform_count = len(data_list) // 400 transform_count = min(100, transform_count) for _ in range(transform_count): i = random.randint(0, len(data_list) - 1) transform_type = random.choice([0, 1, 2, 3, 4]) if transform_type == 0: data_list[i] = (data_list[i] + 1) % 256 elif transform_type == 1: data_list[i] = (data_list[i] - 1) % 256 elif transform_type == 2: data_list[i] ^= 0xFF elif transform_type == 3: data_list[i] = (data_list[i] << 1) % 256 else: data_list[i] = (data_list[i] >> 1) % 256 pe.set_bytes_at_offset(text_section.PointerToRawData, bytes(data_list)) def obfuscate_pe_resources(self, pe): try: for resource_type in pe.DIRECTORY_ENTRY_RESOURCE.entries: if hasattr(resource_type, 'directory'): for resource_id in resource_type.directory.entries: if hasattr(resource_id, 'directory'): for resource_lang in resource_id.directory.entries: data_rva = resource_lang.data.struct.OffsetToData size = resource_lang.data.struct.Size resource_data = list(pe.get_data(data_rva, size)) step_size = 200 if self.random_strength.get() == "高": step_size = 100 elif self.random_strength.get() == "低": step_size = 400 for i in range(0, len(resource_data), random.randint(step_size-50, step_size+50)): if i < len(resource_data): if random.random() < 0.3: resource_data[i] = (resource_data[i] + random.randint(1, 5)) % 256 elif random.random() < 0.6: resource_data[i] = (resource_data[i] - random.randint(1, 5)) % 256 else: resource_data[i] ^= random.randint(1, 255) pe.set_bytes_at_offset(data_rva, bytes(resource_data)) except Exception as e: print(f"资源混淆错误: {e}") def verify_exe_file(self, file_path): try: pe = pefile.PE(file_path) pe.close() return True except: return False def on_closing(self): if messagebox.askokcancel("退出", "确定要退出程序吗?"): self.root.destroy() if __name__ == "__main__": root = tk.Tk() app = ExeProtectorApp(root) root.mainloop() 用户希望输出的程序每次都会有静态特征变化 绕过QVM 将代码段熵值降到最低 在此基础上修改
07-11
你遇到的错误: ``` error: 'class Ui::MainWindow' has no member named 'mainToolBar' ui->mainToolBar->addAction(action_print); ``` 说明:`ui->mainToolBar` 不存在,即在你的 `.ui` 设计文件中没有定义名为 `mainToolBar` 的工具栏对象。 --- ### 🔍 错误原因分析 `Ui::MainWindow` 是由 Qt 的 **UI 编译器(uic)** 根据你的 `mainwindow.ui` 文件自动生成的类。 所有你在 Qt Designer 中添加的控件、菜单、工具栏等都会变成 `ui->xxx` 成员变量。 所以这个错误的根本原因是: > ❌ 你试图访问一个名为 `mainToolBar` 的 `QToolBar` 对象,但它 **并未在 .ui 文件中创建**,或它的名字不是 `mainToolBar`。 --- ## ✅ 解决方案 ### ✅ 方法一:使用 Qt Designer 添加 ToolBar 并命名为 `mainToolBar` #### 步骤 1:打开 `.ui` 文件(如 `mainwindow.ui`) 在 Qt Creator 中双击打开 `mainwindow.ui`。 #### 步骤 2:添加 ToolBar - 在左侧“对象面板”找到 `Main Window` 下的 “Tool Bars” - 右键点击 → “Add Toolbar”,会自动创建一个工具栏 - 默认名称可能是 `toolBar` 或类似名称 #### 步骤 3:修改工具栏对象名为 `mainToolBar` - 在右侧“对象检查器”中找到刚添加的工具栏(例如叫 `toolBar`) - 右键 → “Change objectName…” 或直接双击改名 - 将其 `objectName` 改为:`mainToolBar` ✅ 这样生成的 `Ui::MainWindow` 类就会包含成员变量: ```cpp QToolBar *mainToolBar; ``` #### 步骤 4:保存并重新构建项目 - 保存 `.ui` 文件 - 在 Qt Creator 中右键项目 → **Run qmake** - 清理并重建项目(Build → Rebuild) 此时代码应能正常编译: ```cpp ui->mainToolBar->addAction(action_print); ``` --- ### ✅ 方法二:手动创建 QToolBar(推荐灵活控制) 如果你不想依赖 UI 文件中的工具栏,也可以完全通过代码动态创建和管理工具栏。 #### 示例代码(推荐写法): ```cpp // mainwindow.cpp #include "mainwindow.h" #include "ui_mainwindow.h" #include <QAction> #include <QToolBar> MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) , ui(new Ui::MainWindow) { ui->setupUi(this); // 加载 UI 元素(即使没有 toolBar) // ✅ 手动创建工具栏 QToolBar *mainToolBar = addToolBar("Main Toolbar"); // 使用 QMainWindow::addToolBar() // 创建打印动作(假设你已经有 action_print) QAction *action_print = new QAction("Print", this); connect(action_print, &QAction::triggered, this, &MainWindow::on_printButton_clicked); // 添加到工具栏 mainToolBar->addAction(action_print); } ``` 📌 关键点: - 使用 `addToolBar(...)` 来创建工具栏,它是 `QMainWindow` 提供的方法。 - 不需要依赖 `.ui` 文件中是否存在 `mainToolBar`。 - 更加灵活,适合程序化布局。 --- ### ✅ 方法三:确认实际名称(避免拼写错误) 有时候你以为叫 `mainToolBar`,但实际是 `toolBar` 或其他名字。 #### 检查方法: 打开你的 `ui_mainwindow.h` 文件(这是自动生成的),搜索: ```cpp QToolBar *xxx; ``` 看看它到底叫什么名字。比如可能是: ```cpp QToolBar *toolBar; ``` 如果是这样,那你应该改为: ```cpp ui->toolBar->addAction(action_print); // 注意:不是 mainToolBar! ``` 或者去 `.ui` 文件中把名字改成 `mainToolBar`。 --- ### 🛠️ 如何查看 ui_mainwindow.h? 路径一般为: ``` build-myprint-Desktop_Qt_...-Debug/ui_mainwindow.h ``` 打开后查找: ```cpp class Ui_MainWindow { public: QAction *action_print; QMenuBar *menuBar; QToolBar *toolBar; // ← 看看是不是这个名字? QWidget *centralWidget; ... }; ``` --- ### ✅ 最佳实践建议 | 做法 | 推荐程度 | 说明 | |------|--------|------| | 使用 `addToolBar()` 动态添加工具栏 | ⭐⭐⭐⭐⭐ | 灵活、可控、不依赖 UI 文件 | | 在 `.ui` 文件中设计工具栏并命名正确 | ⭐⭐⭐⭐ | 适合可视化设计流 | | 强行修改 `ui_mainwindow.h` | ❌ 绝对禁止 | 自动生成文件,会被覆盖 | ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值