主机序列号的修改方法与原理

主机序列号的修改方法与原理

🔍 什么是主机序列号?

主机序列号是设备出厂时烧录的唯一硬件ID,如同设备的"DNA身份证"。它被存储在:

  1. BIOS/UEFI芯片(主板固件)
  2. 设备树文件 (Linux系统路径:/proc/device-tree/serial-number
  3. DMI信息表 (系统硬件数据库,路径:/sys/class/dmi/id/

ℹ️ 通过终端命令 sudo dmidecode -s system-serial-number 可查看


❓ 为什么要修改序列号?

场景 说明 典型案例
隐私保护 防止设备被远程追踪 公共WiFi环境下避免设备指纹识别
软件授权 绕过硬件绑定限制 试用期结束后重装专业软件
测试兼容性 模拟不同硬件环境 验证软件在不同设备型号的表现
安全研究 隐藏真实设备指纹 渗透测试中规避目标系统检测

⚠️ 法律提示:修改序列号可能违反用户协议,仅限合法用途(如隐私保护、授权测试)


方法一:拦截read函数(用户空间修改)

原理图解

尝试读取序列号 匹配目标路径 不匹配 应用程序 系统调用read 拦截器检测路径 返回自定义序列号 返回真实数据

技术核心 :通过 LD_PRELOAD 环境变量优先加载自定义库,劫持系统读取函数

⚖️ 优缺点

  • 优点:无需重启、不修改硬件
  • 局限
    • 仅对动态链接程序有效
    • 终端关闭后失效
    • dmidecode 等命令仍读取原始值

操作步骤详解

c 复制代码
# 创建隔离的工作目录
rm serial_modifier_0 -rf
mkdir serial_modifier_0
cd serial_modifier_0

# 生成动态拦截库源码
cat > api_hook.c <<-'EOF'
#include <unistd.h>
#include <time.h>
#define __USE_GNU
#include <dlfcn.h>
#include <sys/syscall.h>
#include <signal.h>
#include <stdlib.h>
#include <malloc.h>
#include <stdarg.h>
#include <string.h>
#include <fcntl.h>
#include <set>
#include <map>

#define WITH_PTHREADS
#ifdef WITH_PTHREADS
#include <pthread.h>
static pthread_mutex_t mutex;
#  define LOCK (pthread_mutex_lock(&mutex));
#  define UNLOCK (pthread_mutex_unlock(&mutex));
#else
#  define LOCK ;
#  define UNLOCK ;
#endif

// 添加文件操作拦截相关函数指针
typedef int (*open_ptr)(const char *, int, ...);
typedef ssize_t (*read_ptr)(int, void *, size_t);
typedef int (*close_ptr)(int);
static open_ptr real_open = NULL;
static open_ptr real_open64 = NULL;
static read_ptr real_read = NULL;
static close_ptr real_close = NULL;

// 目标文件路径和固定返回值
static const char *target_path = "/proc/device-tree/serial-number";
static const char *fixed_serial = "2538922146412";
static const size_t fixed_serial_len = 13; // 不包括结尾的空字符

// 定义要替换的序列号
static const char *src_serial="f2a15610d4af3adf";
static const size_t src_serial_len = 16; // 不包括结尾的空字符

// 用于跟踪目标文件的文件描述符和读取位置
static std::set<int> target_fds;
static std::map<int, size_t> read_positions;

static void init()
{
    // 初始化文件操作函数指针
    if(NULL==real_read)
    {
        real_read = (read_ptr)dlsym(RTLD_NEXT, "read");
    }
}
// 拦截read函数
extern "C" ssize_t read(int fd, void *buf, size_t count)
{
    LOCK
    init();
    ssize_t ret = real_read(fd, buf, count);
	// 检测到目标序列号时进行替换
    if((ret>=src_serial_len) && strcmp((char*)buf, src_serial) == 0 )
    {
        memcpy(buf, fixed_serial, fixed_serial_len);
        UNLOCK
        return fixed_serial_len;  // 返回修改后的长度
    }
    UNLOCK
    return ret;
}
EOF

# 编译共享库(关键步骤解释)
unset LD_PRELOAD
g++ -fPIC -shared -o libapi_hook.so api_hook.c -ldl
# -fPIC: 生成位置无关代码
# -shared: 创建共享库
# -ldl: 链接动态加载库

# 测试原始序列号
cat /proc/device-tree/serial-number

# 加载拦截库(核心步骤)
export LD_PRELOAD=/opt/libapi_hook.so

# 验证修改效果
cat /proc/device-tree/serial-number

# 恢复原始环境
unset LD_PRELOAD

方法二:内核驱动修改

原理图解

用户 内核 DMI内存 硬件 加载驱动模块 禁用写保护 允许修改 写入新序列号 数据更新成功 重启后失效 用户 内核 DMI内存 硬件

⚠️ 风险提示

  • 操作不当可能导致系统崩溃
  • 需关闭Secure Boot等安全机制
  • 部分品牌机有硬件写保护

原理与适用场景

原理 :通过内核模块直接修改DMI内存区域,覆盖原始序列号
适用场景

  • 需绕过硬件级检测的场景

操作步骤详解

bash 复制代码
# 创建驱动开发目录
rm serial_modifier_1 -rf
mkdir serial_modifier_1
cd serial_modifier_1

# 生成内核模块源码
cat > serial_modifier.c <<-'EOF'
#include <linux/version.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/dmi.h>
#include <linux/string.h>
#include <linux/io.h>
#include <asm/pgtable.h>

#define NEW_SERIAL "2538922146412" // 替换为您需要的新序列号

static char *original_serial_addr = NULL;
static char *saved_serial = NULL;
static unsigned long original_cr0;

// 使内存页可写
static void make_rw(unsigned long address)
{
    unsigned int level;
    pte_t *pte = lookup_address(address, &level);
    if (pte) {
        set_pte(pte, pte_mkwrite(*pte));
    }
}

// 使内存页只读
static void make_ro(unsigned long address)
{
    unsigned int level;
    pte_t *pte = lookup_address(address, &level);
    if (pte) {
        set_pte(pte, pte_clear_flags(*pte, _PAGE_RW));
    }
}

void rewrite(int key)
{
    const char *dmi_serial = dmi_get_system_info(key);
    if (!dmi_serial) {
        printk(KERN_ERR "Failed to get DMI serial number\n");
        return;
    }

    printk(KERN_INFO "Original DMI serial: %s\n", dmi_serial);

    // 保存原始地址和值
   char * original_serial_addr = (char *)dmi_serial;

    // 禁用写保护
    original_cr0 = read_cr0();
    write_cr0(original_cr0 & ~X86_CR0_WP);

    // 使目标内存可写
    make_rw((unsigned long)original_serial_addr);

    // 写入新序列号
    strncpy(original_serial_addr, NEW_SERIAL, strlen(NEW_SERIAL));
    original_serial_addr[strlen(NEW_SERIAL)] = '\0'; // 确保终止

    // 恢复写保护
    make_ro((unsigned long)original_serial_addr);
    write_cr0(original_cr0);

    printk(KERN_INFO "DMI serial changed to: %s\n", NEW_SERIAL);
}

static int __init serial_mod_init(void)
{
    rewrite(DMI_PRODUCT_SERIAL);
    rewrite(DMI_CHASSIS_SERIAL);
    return 0;
}

static void __exit serial_mod_exit(void)
{
}

module_init(serial_mod_init);
module_exit(serial_mod_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Your Name");
MODULE_DESCRIPTION("DMI Serial Number Override");
EOF

# 创建Makefile
cat > Makefile <<-'EOF'
obj-m += serial_modifier.o
EXTRA_CFLAGS += -fno-pie
all:
		make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
clean:
		make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
EOF

# 编译内核模块
make

# 查看原始DMI信息
cat /sys/class/dmi/id/chassis_serial
cat /sys/class/dmi/id/product_serial

# 加载内核模块(需要root权限)
insmod serial_modifier.ko

# 验证修改结果
cat /sys/class/dmi/id/chassis_serial
cat /sys/class/dmi/id/product_serial

方法三:VirtualBox虚拟机修改

适用场景

适合测试多设备兼容性,无需触碰物理硬件

原理与适用场景

原理 :通过虚拟机管理程序修改虚拟硬件信息
适用场景

  • 虚拟机环境中的序列号修改
  • 快速切换不同硬件配置
  • 无需内核操作的解决方案

操作步骤详解

powershell 复制代码
# 删除现有序列号配置
.\VBoxManage.exe setextradata "ubuntu" "VBoxInternal/Devices/pcbios/0/Config/DmiSystemSerial" --delete

# 设置新序列号
.\VBoxManage.exe setextradata "ubuntu" "VBoxInternal/Devices/pcbios/0/Config/DmiSystemSerial" "string:2538922146412"

# 验证配置
.\VBoxManage.exe getextradata "ubuntu" enumerate

参数说明

参数 说明
setextradata 修改虚拟机额外配置
pcbios/0/Config/ BIOS配置路径
DmiSystemSerial DMI系统序列号键名
string:2538922146412 新序列号值

方法对比表

特性 用户拦截 内核修改 虚拟机配置
修改层级 用户层 内核层 虚拟化层
持久性 临时 重启失效 配置持久
难度 ⭐☆☆☆☆ ⭐⭐⭐⭐☆ ⭐⭐☆☆☆
风险
生效范围 部分应用 全系统 单虚拟机

结论

  1. 临时测试 → 选择方法一(LD_PRELOAD
  2. 物理机永久修改 → 方法二(需专业技术)
  3. 虚拟机环境 → 方法三(最安全便捷)
  4. 检测工具差异
    • cat /proc/... → 方法一、二有效
    • dmidecode → 仅方法三有效

道德提醒:技术应用需遵守法律法规,禁止用于软件盗版或欺诈行为

相关推荐
小馬佩德罗20 天前
Android系统的问题分析笔记 - Android上的调试方式 debuggerd
android·调试
小馬佩德罗20 天前
Android系统的问题分析笔记 - Android上的调试方式 bugreport
android·调试
迷路爸爸18021 天前
让 VSCode 调试器像 PyCharm 一样显示 Tensor Shape、变量形状、变量长度、维度信息
ide·vscode·python·pycharm·debug·调试
伊织code1 个月前
macOS - 根据序列号查看机型、保障信息
macos·mac·macbook·查看·序列号·机型·对应
TheBszk2 个月前
单片机如何快速实现查看实时数据
stm32·单片机·嵌入式硬件·调试
胡斌附体3 个月前
idea挂掉,会导致进程不结束,切换profile环境,导致token认证不通过
java·ide·intellij-idea·调试·token失效
胡斌附体3 个月前
微服务调试问题总结
java·微服务·架构·调试·本地·夸微服务联调
kaiyuanheshang3 个月前
关于VScode的调试
ide·vscode·编辑器·debug·调试
漫步企鹅4 个月前
【GDB】调试程序的基本命令和用法(Qt程序为例)
开发语言·qt·gdb·调试