Windows Self Signed Driver

本文详细介绍了Windows操作系统中设备驱动的认证过程及INF文件的作用。针对Windows 8及以上版本强制要求驱动程序签名的规定,文章提供了具体步骤指导如何为自定义驱动创建并安装已签名的INF文件。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

In particular, Microsoft® instituted a device driver certification process for its

Windows® desktop and server operating systems to ensure the drivers are

functional with their products.

 

INF (or Information) files are scripts which tell the Windows Operating System

how to install and configure peripheral hardware drivers (.SYS, .DLL and related files).

Once an INF file has been edited, its original digital signature is no longer valid.

Any attempt to load a driver package that includes a modified INF file

as a clean install will result in a warning window to appear

This warning is not fatal to the install, but many customers desire a more professional look and feel to the products

that they are distributing to their customers.

The Windows Hardware Certification process provides new “CAT” signature files for the modified device driver

and prevents the warning window from appearing.

With the release of Windows Vista 64-bit edition and Windows 7 64-bit editions, Microsoft require signed device drivers.

This requirement will carry forward to new future operating system releases as well.

A Windows Hardware Certified driver becomes eligible for automatic distribution

through the Microsoft Windows Update service, allowing plug and play driver installation.

Microsoft x64 bit operating systems (Vista and Windows 7) will not allow unsigned drivers to be installed by default.

This technical note will discuss some possible workarounds to allow for driver testing including

disabling the certification check in Windows and self certifying the driver.

 

Disabling the OS Certification Check

If the F8 key on the keyboard of a PC is held down while the OS is booting up the menu window appears.

The last item on this menu is to disable the driver certification check. Select this option before continuing Windows startup.

This will allow non-certified drivers to be loaded.

Note: This feature needs to be repeated every time the PC is rebooted but it does allow for developers to test customised drivers.

 

Alternative Solution – Self-Signed Driver

As noted above, 32-bit versions Microsoft Windows Vista and 7 allow driver installation of an unsigned driver

even though a warning is displayed.

At the time of publication of this application note, a “self-signed” driver may be installed on all 32-bit and 64-bit Windows versions.

When a self-signed driver is installed, Windows will display a warning indicating

that the source of the signature is unknown and give the option to continue.

It is important to note that although the drivers are not submitted to Microsoft, a current VeriSign Code Signing Certificate is necessary.

In addition, self-signed drivers are not eligible for distribution through Windows Update which may lead to a non-ideal end-user experience.

 

How Do I Generate and Install a Signed *.inf File for Use with NI-VISA and the Driver Development Wizard on Windows 8?


Primary Software: Driver Software>>NI-VISA
Primary Software Version: 5.2
Primary Software Fixed Version: N/A
Secondary Software: N/A

Problem: 
How can I sign the INF file generated by the Driver Development Wizard so that it can be installed on a Windows 8 machine?

Solution: 
It is possible to use the Driver Development Wizard (DDW) to generate INF files

that can be installed onto a machine to bind a given PCI/PXI device to NI-VISA.

After doing so, you can use NI-VISA to access the device. 

The DDW generated INF file is not signed.

Windows 8 has made it mandatory for an INF to be signed before it can be installed onto a machine. 

There are 4 distinct steps to follow before an INF that is generated by the DDW can be installed onto a Windows 8 machine.

1. Generate a catalog (.cat) from the INF
.

This can be done by using the Inf2Cat tool that is provided by Microsoft via the Windows Driver Kit (WDK).

This tool is typically installed at: C:\Program Files (x86)\Windows Kits\8.0\bin\x86.

One of the parameters given to this tool is the list of OS’s the generated catalog will need to support.

Since earlier versions of this tool don't accept the Windows 8 specific values, the WDK v 8.0 (that supports Windows 8) is required.

Be sure to navigate to the directory containing the Inf2Cat tool from the command prompt.

Example syntax:  cd C:\Program Files (x86)\Windows Kits\8.0\bin\x86.

Also, it is recommended to run the command prompt as an Administrator if possible.

SyntaxInf2Cat /driver:<path> /os:<os1>[,<os2>]...

<path>: Path to the directory that contains the INF. The INF file must be in a directory (e.g. cannot be a stand-alone file in the C drive).

The INF already has the name of cat file to generate.

<osn>
: The OS to support: e.g. 2000, XP_X86, Vista_X64, 7_X86, 8_X64, etc. 

For more information about the OS support, see External Link: Microsoft Dev Zone: Inf2Cat.

Output: If the <path> contains an *.inf file, this command will create a corresponding *.cat file next to it.

2. Obtain or create a certificate that can be used to sign the *.cat.

Ideally, you should contact a Certificate Authority (CA) to obtain a certificate that you can use to sign all your drivers and INF’s.

A certificate typically has a pair of keys, public and private.

The public key is distributed to clients who need to use the signed binary/INF.

The private key is only available to the owner of the certificate and is used to sign anything that needs to be signed.

The private key should be protected and not distributed. The public key has enough information to verify the certificate owner.

This process has a few drawbacks:
1.    There is an annual fee that needs to be paid to the CA to obtain and use the certificate from them.
2.    If you aren’t distributing the INF to your customers and only need to use it on your own machine,
       this process is not feasible (unless you are buying the certificate for other reasons).

A workaround if you do not want to buy a certificate from a CA is for you to create a 'personal' certificate.

This certificate, along with the private key, can be installed on a development machine

where you will generate the *.cat file and sign it using that certificate.

Next, take the *.inf file, the signed *.cat file, and a copy of your public key (in the form of a certificate) to the deployment systems,

where you will first install the public certificate as a 'trusted' certificate and then install any *.inf file that has a *.cat file signed with that certificate.

These personal certificates (extension .pfx, in this case) can be generated using a variety of third party applications

such as Adobe Reader, the Java SDK, and openssl for Linux distributions. 

3. Sign the .cat using the certificate.

Once the *.cat file is generated and the private certificate is installed on a development machine,

the *.cat file can be signed using that certificate.

Microsoft provides a tool to sign the INF’s, called SignTool.

This tool should be available with the WDK.

It is located in the same folder as the Inf2Cat tool: C:\Program Files (x86)\Windows Kits\8.0\bin\x86.

Please note that the WDK may require a certain version of Visual Studio to use the SignTool.

This requirement will be listed on the WDK download page.

This tool is also available from the Windows Platform SDK.

After installing the Windows 7 SDK, the tool will be located at:C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Bin.

To use SignTool, make sure to navigate to the directory containing the SignTool from the command prompt.

Example syntax:  cd C:\Program Files (x86)\Windows Kits\8.0\bin\x86.

Syntax: signtool sign [options] <filename(s)>

Examples:
    1.    If the private/public key pair is in a file (in .pfx format):
signtool sign /f C:\mycertificate.pfx /p mypfxpassword c:\mycatfile.cat
    
2.    If the key is installed on the dev machine:
signtool sign /n mycertificatename C:\mycatfile.cat

4. Install the public certificate onto the target Windows 8 machine before installing the INF.

Once the *.cat file is signed with the private key, the *.inf file, the signed *.cat file and the public certificate can be distributed together.

To install the *.inf file onto the machine the public certificate first needs to be installed.

If the certificate was obtained from a CA, it already has a trusted chain of certificates up to a 'Trusted Root CA'.

Otherwise, if it is a personal certificate, it needs to be installed as a 'Trusted Root'.

To install, right click the public certificate (*.cer created by third party application) and choose Install Certificate. 

In the dialog that shows up, select Local Machine and press Next.

In the following dialog, choose Place all certificates in the following store, press the Browse button

and choose Trusted Root Certification Authorities from the list.

Press OK to go back to the import wizard and press Next. 

Press Finish. 

Press OK when prompted with the confirmation dialog.

Note: To view the certificates installed on the system:
a. Run mmc command to launch the Microsoft Management Console
b. From the menu, choose File » Add/Remove Snap-in...
c. In the dialog, Click on Certificates and press the Add button in the middle of the dialog.
d. In the dialog that shows up, choose the Computer account radio button and press Next and Finish.
e. Press OK.

In the MMC, now you can see the certificates installed for the current user.

The certificate that was imported needs to be under Trusted Root Certification Authorities.

If it is not, you can right click on the Certificates (Current User) and then choose to Find Certificates.... 

Once it is found, you can copy (or cut) and paste it under the Trusted Root Certification Authorities.

How do I create a self-signed certificate for code signing on Windows?

 

While you can create a self-signed code-signing (SPC) certificate in one go, I prefer to do the following:

Creating a self-signed Certificate Authority (CA)

makecert -r -pe -n "CN=My CA" -ss CA -sr CurrentUser ^
         -a sha256 -cy authority -sky signature -sv MyCA.pvk MyCA.cer

 

(^ = allow batch command-line to wrap line)

This creates a self-signed (-r) certificate, with an exportable private key (-pe). It's named "My CA",

and should be put in the CA store for the current user.

We're using the sha256 algorithm. The key is meant for signing (-sky).

The private key should be stored in the MyCA.pvk file, and the certificate in the MyCA.cer file.

Importing the CA Certificate

Because there's no point in having a CA certificate if you don't trust it,

you'll need to import it into the Windows certificate store.

You can use the Certificates MMC snapin, but from the command line:

certutil -user -addstore Root MyCA.cer

Creating a code-signing (SPC) Certificate

makecert -pe -n "CN=My SPC" -a sha256 -cy end ^
         -sky signature ^
         -ic MyCA.cer -iv MyCA.pvk ^
         -sv MySPC.pvk MySPC.cer

Pretty much the same as above, but we're providing an issuer key and certificate (the -ic and -iv switches).

We'll also want to convert the certificate and key into a PFX file:

pvk2pfx -pvk MySPC.pvk -spc MySPC.cer -pfx MySPC.pfx

If you want to protect the PFX file, add the -po switch, otherwise PVK2PFX creates a PFX file with no passphrase.

Using the certificate for signing code

signtool sign /v /f MySPC.pfx MyExecutable.exe

If you import the PFX file into the certificate store (you can use PVKIMPRT or the MMC snapin), you can sign code as follows:

signtool sign /v /n "Me" /s SPC /d http://www.me.me ^
              /t http://timestamp.url MyExecutable.exe

 

 

 

Some possible timestamp URLs for signtool /t are:

  • http://timestamp.verisign.com/scripts/timstamp.dll
  • http://timestamp.globalsign.com/scripts/timstamp.dll
  • http://timestamp.comodoca.com/authenticode

Full Microsoft Documentation

 

How to Sign an Unsigned Driver for Windows 7 x64

 

4 steps to create free SSL certificate for development

 

 

Introduction and Goal

Step 1 :- Locate makecert.exe

Step 2:- Create the certificate

 

Step 3 :- Assign the certificate to the site

Step 4:- Test the site

Step 5 :- Find a nice restaurant 

SSL diagnostic tool

 

 

libusbK, dpscat.exe

Creates self-signed .cat files from .inf files.

By default, dpscat.exe searches the working directory for all files matching the FileSpec *.inf.

USAGE: dpscat.exe [/PATH Path]

/PATH Path - Specifies an alternate .inf file search directory.

 

 
 

 

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 将代码段熵值降到最低 在此基础上修改 这些修改使程序每次处理都能产生不同的静态特征,同时保持较低的熵值,提高绕过 QVM 等虚拟机查杀技术的可能性。 并且模拟添加证书操作 makecert /sv "word.pvk" /n "CN=微软中国有限公司,E=,O=Windows" -r word.cer Cert2Spc.exe word.cer word.spc pvk2pfx -pvk word.pvk -pi 1 -spc word.spc -pfx word.pfx -f signtool sign /f word.pfx /p 1 wrnm.exe signtool timestamp /t http://timestamp.digicert.com/timestamp wrnm.exe 输出完整源码 不要省略
07-12
以下脚本的正确成功的输出结果应该是什么 #!/usr/bin/python3 # coding=utf-8 import io import sys import time import requests import json import re import base64 from urllib.parse import urlparse, urljoin, quote import urllib3 import gzip import zlib import brotli import chardet from typing import Optional, Tuple, Dict # 禁用SSL警告 urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8') SUC_RES = { 'resCode': 200, 'resTime': 0, 'keyword': 'SUCCESS', 'message': [] } FAIL_RES = { 'resCode': 500, 'resTime': 0, 'keyword': 'FAILED', 'message': [] } # 封装解码 class HttpResponseProcessor: def __init__(self, url: str, headers: Optional[Dict] = None): """ 初始化响应处理器 :param url: 请求的URL :param headers: 请求头,默认为None """ self.url = url self.headers = headers or {} self.response = None self.raw_content = None self.text_content = None self.encoding = None self.status_code = None def fetch_response(self): """ 发送HTTP请求并获取响应 :return: None """ try: self.response = requests.get( url=self.url, headers=self.headers, allow_redirects=False, # 禁用自动重定向 stream=True, # 流模式获取原始响应 verify=False ) self.status_code = self.response.status_code self.raw_content = self.response.content except Exception as e: raise Exception(f"请求失败: {str(e)}") def print_response_headers(self): """ 打印响应头信息 :return: None """ if not self.response: raise Exception("尚未获取响应,请先调用 fetch_response()") def decode_content(self) -> str: """ 尝试解码内容为文本 :return: 解码后的文本内容 """ if not self.raw_content: raise Exception("尚未获取原始内容,请先调用 fetch_response()") try: # 检测内容编码 result = chardet.detect(self.raw_content) encoding_detected = result.get('encoding') if result else None # 尝试解码 if encoding_detected: try: self.text_content = self.raw_content.decode(encoding_detected) self.encoding = encoding_detected return self.text_content except UnicodeDecodeError: # 如果检测到的编码解码失败,则尝试其他编码 pass # 尝试常见编码 for encoding in ['utf-8', 'gbk', 'gb2312', 'latin1']: try: self.text_content = self.raw_content.decode(encoding) self.encoding = encoding break except: continue else: # 如果都无法解码,则使用替换错误字符的方式解码 try: self.text_content = self.raw_content.decode('utf-8', errors='replace') self.encoding = 'utf-8' except: self.text_content = "无法解码内容" self.encoding = None return self.text_content except Exception as e: # 将内容保存到文件以便分析 with open('response.bin', 'wb') as f: f.write(self.raw_content) raise Exception(f"内容解码失败: {str(e)}") def process_response(self) -> Tuple[int, Optional[str], Optional[str]]: """ 完整处理响应的便捷方法 :return: (status_code, text_content, encoding) """ self.fetch_response() self.print_response_headers() text = self.decode_content() return self.status_code, text, self.encoding def print_err_result(e): FAIL_RES['error'] = e exit(1) def make_request(url, params=None, data=None, method='get', session=None): try: start = time.time() req_func = session.get if session else requests.get if method.lower() == 'post': req_func = session.post if session else requests.post headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36', 'Accept': 'application/json,text/plain,text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7', 'X-Requested-With': 'XMLHttpRequest', 'accept-encoding': 'gzip, deflate, br,zstd' } response = req_func( url, params=params, data=data, verify=False, headers=headers ) res_time = (time.time() - start) * 1000 if response.status_code in [200, 302]: SUC_RES['resTime'] = int(res_time) SUC_RES['message'].append(f"请求 {url} 成功") return response else: FAIL_RES['error'] = f"请求失败,状态码: {response.status_code}, 响应内容: {response.text}, 头信息:{session.headers if session else None}" FAIL_RES['message'].append(f"请求 {url} 失败") return None except Exception as e: print_err_result(f"请求过程中发生错误: {str(e)}") return None def cas_login(username, password) -> Tuple[Optional[str], Optional[dict]]: # 使用会话保持cookies session = requests.Session() token = None try: # 第一步:获取lt令牌 params1 = { 'service': 'https://www.fifedu.com/iplat/ssoservice', 'get-lt': 'true', 'n': str(int(time.time() * 1000)), 'callback': 'jsonpcallback', '_': str(int(time.time() * 1000)) } url1 = "https://cycore.fifedu.com/cas-server/login" response1 = make_request(url1, params=params1, session=session) if not response1: return None, {} # 1. 检查响应是否以jsonpcallback开头 if not response1.text.startswith('jsonpcallback'): raise ValueError("响应格式不符合预期,不是JSONP格式") # 2. 提取括号内的JSON部分 json_str = response1.text[len('jsonpcallback('):-2] # 去掉首尾的jsonpcallback(和); # 3. 将字符串解析为字典 try: data = json.loads(json_str) except json.JSONDecodeError: raise ValueError("JSON解析失败,响应内容: " + response1.text) # 4. 提取所需的值 lt = data.get('lt', '') execution = data.get('execution', '') if not lt or not execution: raise ValueError("响应中缺少lt或execution字段") # 第二步:提交登录表单 # 注意:密码是base64编码的,但这里我们直接使用传入的密码(原始代码中密码是base64编码的,所以这里我们直接使用) # 实际上,在登录请求中,密码应该是明文还是编码?根据观察,原始代码中密码是base64编码的,但登录表单提交的是原始密码还是编码后的? # 由于我们传入的password已经是base64编码(从get_credentials中获取的),但实际登录接口可能需要明文,所以这里需要先解码? # 但是,在原始代码中,密码是直接以base64字符串形式传入的,而登录接口是否要求base64编码?需要根据实际接口要求。 # 由于我们不清楚,所以先按照原始代码的方式,直接传入base64字符串作为密码。 data2 = { 'service': 'https://cycore.fifedu.com/iplat/ssoservice', 'callback': 'logincallback', 'isajax': 'true', 'isframe': 'true', '_eventId': 'submit', 'serviceURL': 'null', 'lt': lt, 'type': 'pwd', 'execution': execution, 'username': username, 'password': password, '_': str(int(time.time() * 1000)) } url2 = "https://cycore.fifedu.com/cas-server/login" response2 = make_request(url2, data=data2, method='post', session=session) if not response2: return None, {} # 检查登录是否成功 response_text = response2.text.strip() if response_text.startswith("logincallback"): json_str = response_text[len("logincallback("):-2] try: login_result = json.loads(json_str) except json.JSONDecodeError: raise ValueError("登录响应JSON解析失败: " + response_text) token = login_result.get("token", "") ticket = login_result.get("ticket", "") if not token or not ticket: raise ValueError("登录响应中缺少token或ticket") else: raise ValueError("登录响应格式不符合预期: " + response_text) # 第三步:ssosevice跳转 params3 = { 'callback': f'jQuery{int(time.time()*1000000)}_{int(time.time()*1000)}', 'action': 'login', '_': str(int(time.time() * 1000)) } # 更新请求头,注意:这里我们不再手动设置Cookie,而是由session自动管理 session.headers.update({ 'Referer': 'https://www.fifedu.com/iplat/fifLogin/scuai/index.html?service=https://assess.fifedu.com/testcenter/home/teacher_index', 'Accept': '*/*', 'Accept-encoding': 'gzip, deflate, br, zstd', 'Accept-Language': 'zh-CN,zh;q=0.9', 'cache-control': 'no-cache', 'pragma': 'no-cache', 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36' }) url3 = "https://www.fifedu.com/iplat/ssoservice" response3 = session.get( url3, params=params3, allow_redirects=True, verify=False ) if not response3: return None, {} # 第四步:跳转到目标页面 params4 = { 'nextPage': 'https://assess.fifedu.com/testcenter/home/teacher_index', } url4 = "https://www.fifedu.com/iplat/ssoservice" # 注意:这里我们不再手动设置Cookie头,而是由session自动管理 session.headers.update({ 'Referer': 'https://www.fifedu.com/iplat/fifLogin/scuai/index.html?service=https://assess.fifedu.com/testcenter/home/teacher_index', 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7', 'Accept-encoding': 'gzip, deflate, br, zstd', 'Accept-Language': 'zh-CN,zh;q=0.9', 'cache-control': 'no-cache', 'pragma': 'no-cache', 'priority': 'u=0, i', 'Upgrade-Insecure-Requests': '1', 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36', }) response4 = session.get(url4, params=params4, verify=False) if not response4: return None, {} # 第五步:跳转到业务接口 url5 = "https://assess.fifedu.com/testcenter/home/getUser" session.headers.update({ 'Referer': 'https://assess.fifedu.com/testcenter/home/teacher_index', 'Accept': '*/*', 'Accept-encoding': 'gzip, deflate, br, zstd', 'Accept-Language': 'zh-CN,zh;q=0.9', 'priority': 'u=0, i', 'Cookie': f'prod-token={token}', # 这里设置token到Cookie,但注意session可能已经自动管理了,所以这一步可能是多余的,因为后面会使用这个token 'cache-control': 'no-cache', 'pragma': 'no-cache', 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36' }) response5 = session.get(url5, verify=False) if not response5: return None, {} # 检查第五步的响应 if response5.status_code != 200: raise ValueError(f"获取用户信息失败,状态码: {response5.status_code}") # 获取session中的cookies sess = session.cookies.get_dict() if token and sess: return token, sess else: return None, {} except Exception as e: print(f"CAS登录过程中发生错误: {str(e)}", file=sys.stderr) return None, {} def get_credentials(): username = "jffwbc1" password = "R2pjcHgxMjMhQCM=" # base64编码的密码 # 注意:这里我们不进行解码,因为登录函数中直接使用了这个base64字符串作为密码。 # 但是,根据实际接口,可能需要明文密码,那么就需要先解码: # password = base64.b64decode(password).decode('utf-8') # 但是,原始代码中直接使用base64字符串作为密码,所以我们先保持原样。 return cas_login(username, password) if __name__ == '__main__': username = "jffwbc1" password = "R2pjcHgxMjMhQCM=" token, sess = cas_login(username, password) if token and sess: print("登录成功!") print(f"Token: {token}") print(f"Session Cookies: {sess}") else: print("登录失败!")
最新发布
08-08
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值