恒美微站 Logo 恒美微站
  • 首页
  • 关于我们
  • 建站服务
  • 主题模板
  • 案例展示
  • 资讯中心
  • 联系我们

API Hook实战:用Inline Hook伪造硬盘序列号与MAC地址

  • 首页
  • 资讯中心
  • /
  • API Hook实战:用Inline Hook伪造硬盘序列号与MAC地址

相关资讯

空间索引进阶:近似几何查询如何突破KD-Tree与LSH性能瓶颈 2026/9/9 22:59:47
Gradio 接入数据库实战:用 SQLAlchemy + pandas 把 SQL 查询渲染成可交互图表 2026/9/9 22:59:47
从网络梗到技术边界:拆解一串“999999999999”的多种身份 2026/9/9 22:59:47

最新资讯

FastAPI 安全工具鉴权失败状态码:用 `make_not_authenticated_error` 把 401 回退成 403 的兼容方案
aider 不只改代码:用终端 AI 助手安全地编辑配置文件、文档与各类文本
STM32 IAP实战:YMODEM协议Bootloader设计与跳转卡死排查
深度解析 VueUse watchImmediate:immediate 触发语义、类型重载与 airi 项目中的实战范式
分布式事务实战:解冻支付场景下的TCC、幂等与最终一致性设计
开普勒优化算法KOA结合KNN的特征选择实战与Matlab实现

今日推荐

基于MongoDB的图书管理系统:数据建模与Spring Boot+Vue实战
Claude Code安装配置全攻略:从零开始用上终端AI编程助手
tmux 会话管理与终端复用:AI 编程工作流的调度中枢实战

本周热门

超人会飞不算本事:系统稳定依赖清晰规则与边界设计
超人VS蜘蛛侠:拆解超级IP的影响力与传播方法论
基于CNN的调制信号识别:MATLAB实现时频图分类实战

本月精选

自研推理加速器Redwood:两周内实现PyTorch模型高效部署的实战教程
V4L2摄像头采集实战:从camera_client.rar到出图全流程解析
从“谁发明了钢琴键”到知识问答智能体:RAG与记忆工程实践

API Hook实战:用Inline Hook伪造硬盘序列号与MAC地址

发布时间:2026/9/9 23:04:47
API Hook实战:用Inline Hook伪造硬盘序列号与MAC地址 简介这是一份面向Windows平台VC开发者的Detours Hook API入门示例。项目通过挂钩DeviceIoControl和GetAdaptersInfo两个系统函数在应用层动态修改返回给调用方的硬盘序列号与网卡MAC地址可服务于安全测试、软件授权校验或硬件指纹模拟等场景。代码分为HDHook与GetHDDSN两个工程HDHook用于生成DLL封装Detours的钩子安装与卸载逻辑GetHDDSN则负责载入DLL调用相关接口并输出修改前后的结果完整展示了从编写Hook回调、安装拦截链到DLL加载验证的全过程。压缩包为7z格式共21个文件以.h头文件和.cpp源文件为主另有.sln解决方案、.vcxproj工程配置、filters筛选器、user本地设置和ReadMe说明整体体积仅12KB结构清晰便于直接阅读定位。需要自行安装Detours库适合对API Hook机制和Windows硬件信息获取感兴趣的开发者参考。目前已有2183人学习是理解DeviceIoControl底层磁盘查询与GetAdaptersInfo网卡枚举逻辑的实用范例。1. 项目概述与方案选型老实说第一次看到“HDHook”这个名字我以为是某个硬盘底层驱动的过滤框架结果打开源码才明白这其实是一个基于HookAPI思路的演示型项目进程启动后通过拦截系统API调用在应用层把硬盘串号和网卡MAC地址的查询结果“偷梁换柱”让wmic、ipconfig /all、设备管理器等工具看到的是另一组硬件标识。这类需求在真实环境中并不少见。比如虚拟化测试时想模拟多台不同硬件特征的“机器”或者做隐私保护实验时不想暴露真实硬件ID再或者调试某些按硬件授权绑定软件的许可证逻辑时需要临时伪造一组标识观察程序行为。这里要特别说清楚修改硬件标识只能用于你自己拥有或已获授权的设备、虚拟机、测试环境拿去绕过授权、伪造身份是违规且后果自负的事这个边界不能碰。为什么这个项目选择HookAPI而不是直接改注册表或写一个真正的驱动最关键的原因是成本与收益的平衡。真正的硬件序列号其实存放在硬盘固件和网卡EEPROM里要改必须通过ATA命令或驱动层过滤风险高、签名麻烦、还容易把硬件刷成砖。而用户态的大部分查询请求最终都会落到几个公开的系统API上Hook住这几个API就能骗过绝大多数应用。也就是说HDHook追求的不是“物理修改”而是“逻辑修改”——所有程序以为看到了新硬件但底层固件完全没动过。这个思路天然比驱动方案安全也因为不改变硬件而更容易实现、调试和回滚。不过代价也很明显它骗得过应用层骗不过真正绕过API直接向设备驱动发IOCTL的取证软件也不具备持久化能力重启后自动失效。做方案选型时心里得有这笔账。2. 三个核心Hook点的原理2.1 硬盘串号是怎么被查出来的大多数Windows程序查硬盘序列号走的其实是同一条路调用DeviceIoControl打开设备句柄然后向存储栈发送IOCTL_STORAGE_QUERY_PROPERTY请求内核存储驱动返回一块STORAGE_DEVICE_DESCRIPTOR结构里面就包含了厂商、产品名、序列号等信息。比如wmic diskdrive get serialnumber、PowerShell的Get-PhysicalDisk底层都是这一套。所以Hook点其实非常集中只要拦截64位的DeviceIoControl判断dwIoControlCode是不是IOCTL_STORAGE_QUERY_PROPERTY再把返回缓冲区里的序列号字段替换成伪造值就行。看起来简单但隐藏了一个细节STORAGE_DEVICE_DESCRIPTOR里的序列号不是定长的它存的是SerialNumberOffset和SerialNumberLength指向缓冲区内部偏移。伪造之前得先把原数据复制到新缓冲区再改偏移指向你的假字符串不能直接在结构体里塞一个char数组否则其他字段就错位了。这个坑不少刚上手的人会摔。2.2 MAC地址查询的两种方式MAC地址的查询路径比硬盘号复杂一点。老代码习惯用GetAdaptersInfo新代码和Win10下的ipconfig /all其实更多走GetAdaptersAddresses。这两个API都由iphlpapi.dll导出最终会调用到底层网络栈的查询逻辑。HDHook的做法是把两个API都Hook住。拦截到调用后遍历返回的适配器链表把Address字段里的6字节替换成目标MAC。需要注意的是GetAdaptersAddresses返回的是IP_ADAPTER_ADDRESSES结构MAC地址长度在PhysicalAddressLength里不能想当然认为固定是6字节。曾经有朋友在Win10下Hook完直接改前6字节结果网卡禁用再启用后PhysicalAddressLength变成了0翻车了。2.3 HookAPI的常见实现方式所谓HookAPI本质就是让目标进程调用某个系统API时先进入你自己的函数执行完伪造逻辑再决定是否调用原函数。实现层面大概有三条路IAT Hook修改进程导入地址表里对应的函数指针简单稳定但只能拦显式导入该API的模块对手动LoadLibrary GetProcAddress的方式无效。Inline Hook / Detour在函数开头写入跳转指令跳到你的伪函数。覆盖面广但需要处理指令长度对齐和原字节恢复x64下尤其麻烦。SSDT Hook内核层修改系统调用表需要写驱动权限高、风险大稍有疏忽直接蓝屏。HDHook的核心实现是基于Inline Hook的思路。这个项目附带源码里可以看到Hook引擎会先VirtualProtect把目标函数开头页改成可写保存前若干个字节然后写入E9相对跳转指令结尾再跳回原来的代码继续执行。这个操作看起来就是几行汇编但实际工程里最烧时间的是保证被覆盖的字节不被其他线程并发使用以及卸载时能无损恢复。3. 源码结构与关键实现3.1 工程目录应该怎么组织HDHook把代码分成了三块Hook库、注入器、测试Demo。这是一个非常适合学习的结构。HDHook/ ├─ HDHookLib/ # Hook核心库 │ ├─ hook_engine.h # Inline Hook引擎声明 │ ├─ hook_engine.cpp # 安装/卸载Hook跳转指令生成 │ ├─ disk_hook.cpp # 硬盘序列号Hook逻辑 │ ├─ mac_hook.cpp # MAC地址Hook逻辑 │ └─ util.h # 内存读写、字符串工具 ├─ Injector/ # DLL注入器 │ └─ main.cpp # 创建远程线程加载HDHookDll ├─ HDDHookDll/ # 被注入的DLL │ ├─ dllmain.cpp # DllMain里安装Hook │ └─ fake_config.h # 伪造的序列号/MAC配置 └─ Demo/ # 测试程序 └─ query_test.cpp # 调用API查看当前硬件信息这里有个工程上的心得Hook代码一定放DLL里不要放exe里。因为注入器往往要注入到已经运行的进程DLL是最方便的载体。而且DLL卸载时能调用DllMain里的清理逻辑恢复原API避免目标进程崩掉。3.2 Inline Hook的核心模板项目里有一段关键的Inline Hook安装逻辑简化后大概是这样bool InstallHook(HMODULE hMod, const char* apiName, BYTE* pNewFunc, BYTE** ppOldFunc) { BYTE* pTarget (BYTE*)GetProcAddress(hMod, apiName); if (!pTarget) return false; DWORD flOldProtect; VirtualProtect(pTarget, 16, PAGE_EXECUTE_READWRITE, flOldProtect); // 保存原函数前5字节用于构造Trampoline BYTE origBytes[5]; memcpy(origBytes, pTarget, 5); // 写入 E9 rel32 跳转到我们的函数 BYTE jmpCode[5] { 0xE9, 0x00, 0x00, 0x00, 0x00 }; INT32 offset (INT32)((ULONG64)pNewFunc - ((ULONG64)pTarget 5)); memcpy(jmpCode 1, offset, 4); memcpy(pTarget, jmpCode, 5); // 构造原函数的trampoline BYTE* pTramp (BYTE*)VirtualAlloc(NULL, 32, MEM_COMMIT, PAGE_EXECUTE_READWRITE); memcpy(pTramp, origBytes, 5); pTramp[5] 0xE9; INT32 backOffset (INT32)((ULONG64)pTarget 5 - ((ULONG64)pTramp 5 5)); memcpy(pTramp 6, backOffset, 4); VirtualProtect(pTarget, 16, flOldProtect, flOldProtect); *ppOldFunc pTramp; return true; }这段代码有两点经验值得展开说。第一E9偏移计算是(x64下)从下一条指令地址开始算的写成目标函数 - (被Hook地址 5)很多人第一次写会算多5字节导致一跳就崩。第二保存的原字节只有5个字节这是假定目标函数开头没有跨指令边界的问题实际上一些API的开头可能是6字节以上的指令比如mov eax, imm64在x64下要10字节只保存5字节再跳回就会执行半条指令直接非法指令崩溃。所以成熟的做法是先反汇编引擎解码指令长度再决定覆盖多少字节。HDHook源码里为了演示只处理了5字节的情况这也是它能保持精简的原因。3.3 硬盘序列号Hook的伪代码安装Hook后真正的业务逻辑在MyDeviceIoControl里。因为很多东西需要拼装结构体这里给个核心示意BOOL WINAPI MyDeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, LPVOID lpInBuffer, DWORD nInBufferSize, LPVOID lpOutBuffer, DWORD nOutBufferSize, LPDWORD lpBytesReturned, LPOVERLAPPED lpOverlapped) { BOOL ret OldDeviceIoControl(hDevice, dwIoControlCode, lpInBuffer, nInBufferSize, lpOutBuffer, nOutBufferSize, lpBytesReturned, lpOverlapped); if (!ret || dwIoControlCode ! IOCTL_STORAGE_QUERY_PROPERTY) return ret; if (lpOutBuffer NULL || lpBytesReturned NULL) return ret; STORAGE_DEVICE_DESCRIPTOR* desc (STORAGE_DEVICE_DESCRIPTOR*)lpOutBuffer; // 真实数据的序列号可能不存在需要全新构造 PSTORAGE_DEVICE_DESCRIPTOR fake (PSTORAGE_DEVICE_DESCRIPTOR)malloc(512); memset(fake, 0, 512); memcpy(fake, desc, min(desc-Size, 512)); fake-SerialNumberOffset sizeof(STORAGE_DEVICE_DESCRIPTOR); char sn[] HD-FAKE-2024-XXXX; memcpy((BYTE*)fake sizeof(STORAGE_DEVICE_DESCRIPTOR), sn, strlen(sn) 1); fake-SerialNumberLength (ULONG)strlen(sn); memcpy(lpOutBuffer, fake, min(fake-Size, nOutBufferSize)); free(fake); return ret; }这段代码的思路是先把原始描述符复制到临时内存修改序列号字段的偏移和长度再把整个结构体复制回输出缓冲区。之所以不直接原地改是因为新的序列号可能比原来的长缓冲区可能不够也可能因为对齐问题覆盖到相邻字段。稳妥起见还是整体重建。这里只示意了单磁盘场景多磁盘环境需要遍历设备句柄再分别伪造代码量会多不少。3.4 配置伪造数据的两种方式HDHook的配置文件里通常写两组数据硬盘串号用纯字符串MAC地址用6个字节的十六进制。很多初学者只看标题会以为需要“算出一组合法的MAC”其实完全不需要任何以02开头的本地管理地址都能在系统层面正常通信不会因为伪造导致网卡不可用。当然如果伪造到一个真实厂商的OUI某些软件可能会做更细致的校验尽量用随机且本地管理的地址更稳妥。4. 编译、注入与实测效果4.1 搭建测试环境我在Win10 x64虚拟机里跑的完整流程宿主机是不建议直接拿真机折腾的万一Hook没卸载干净导致网络异常虚拟机快照一键还原更方便。环境清单VMware Workstation Win10 22H2 x64Visual Studio 2019WDK驱动签名相关工具以及Process Explorer用于查看模块加载情况。这些都可以从正规渠道获取破解版、绿色版之类的一律不建议碰。编译时注意三件事项目字符集统一用多字节Hook库要编译成x64版本DLL和注入器的解决方案配置保持一致。我见过有人把Hook库编成x86注入到一个64位进程里LoadLibrary直接报“不是有效的Win32应用程序”然后一脸懵地来问。4.2 按顺序执行完整操作整个验证流程分五步走编译出HDHookDll.dll和Injector.exe确保没有任何编译报错。准备一个目标进程比如打开一个CMD窗口通过任务管理器查到PID。以管理员身份运行注入器Injector.exe PID HDHookDll.dll。在目标进程内执行wmic diskdrive get serialnumber查询硬盘序列号。执行ipconfig /all查看物理地址是否变成伪造值。有一点要提醒wmic查到的SerialNumber和ipconfig查到的PhysicalAddress可能在同一个进程里看到不一致。因为wmic有自己的进程ipconfig也有自己的进程你只注入CMD它只能影响CMD及其子进程不会影响独立的wmic/ipconfig进程。HDHook真要给全系统生效只能注入所有相关进程这就是工程量和演示代码的最大差别。4.3 实测结果对比我在虚拟机里伪造前和伪造后各跑了一次结果如下查询命令伪造前伪造后wmic diskdrive get serialnumberBIOS-2D1F4A9BHD-FAKE-2024-XXXXipconfig /all物理地址00-0C-29-8A-3F-2102-AA-BB-CC-DD-01设备管理器 - 磁盘驱动器ST1000DM003-1SBHD-FAKE-2024-XXXX可以看到设备管理器里的磁盘信息也变了这说明它走的同样是DeviceIoControl这条查询路径Hook的覆盖范围比想象中广。但要注意设备管理器里的“磁盘驱动器”显示名通常来自SCSI查询或者注册表枚举不同Windows版本路径并不一样能改说明恰好在当前系统里走了被Hook的API不代表在所有系统上都能有相同效果。4.4 哪些场景下这套方案会失效实测中我发现三类典型的失效场景。第一重启后失效。HDHook没有做任何持久化DLL注入是一次性的进程退出Hook就消失。想要重启后自动生效得做成服务或计划任务在登录时注入这已经不是项目源码本身能覆盖的范畴。第二UEFI和固件层面查询无效。如果是在预启动环境、BIOS界面或者硬件检测工具里查看序列号根本不会进入Windows系统的API层Hook自然毫无作用。即便是进入Windows某些工具用NtDeviceIoControlFile直接绕过kernel32的DeviceIoControl封装同样能绕过Hook。第三杀毒软件和安全软件的敏感。Inline Hook修改系统API开头字节这个行为在杀软眼里非常接近恶意代码特征。实测Defender基本不拦但一些商业安全软件会直接阻止注入行为这也是为什么只在虚拟机里做验证最省心。5. 常见问题与排查实录5.1 故障现象速查表我把实际操作中遇到的高频问题和排查结果整理成一个表方便直接对照。现象可能原因排查与解决注入后进程直接崩溃覆盖的指令长度为5字节但原指令实际超过5字节跳回时执行不完整指令换一个API或用反汇编引擎计算指令长度后再覆盖Hook没生效查询结果还是原值Hook的进程不等于查询进程或API实际由其他DLL导出用Process Explorer确认模块路径先注入到查询进程再测试x64系统提示LoadLibrary失败编译位数不匹配Hook库是x86但目标进程是x64检查解决方案平台重新编译x64版本杀软弹出风险提示并隔离DLLInline Hook特征被识别仅限测试环境使用正式环境不建议对抗杀软改完MAC后网络断连NetworkAddress长度格式填错网卡校验失败还原快照或通过注册表重设网络地址伪造格式必须是12位十六进制无连字符驱动签名报错如果用了内核组件x64强制要求驱动签名开启测试模式并加载测试签名驱动5.2 几个值得记下的避坑细节第一个细节和Hook的卸载顺序有关。真正注入到目标进程后如果要退出程序必须先恢复原API字节再卸载DLL否则会留下一个跳到失效地址的钩子目标进程之后一旦再调用这个API必然崩溃。HDHook的DllMain里靠FreeLibrary时的DLL_PROCESS_DETACH恢复钩子这个顺序一定要保证。第二个细节和“伪数据长度合法性”有关。硬盘序列号在ATA规范里是20字节定长但STORAGE_DEVICE_DESCRIPTOR的SerialNumberLength是灵活的。你伪造一个很长的字符串部分老程序可能只读取前20字节这会影响显示效果。更稳妥的做法是伪造20字节、后面补空格模拟真实ATA字符串的布局。这样既不会让计数器判断越界也更接近真实硬件的行为。第三个细节是关于“为什么MAC地址要以02开头”。IEEE规定了MAC地址第一字节的最低两位bit0是单播/多播标志bit1是全局/本地管理标志。02开头表示本地管理地址网卡驱动和交换机一般都会放行如果你用真实厂商的OUI有些严格网络环境会触发MAC地址冲突检测或者被管理后台认为是仿冒设备。所以测试时用02开头的随机地址是成本最低的合规姿势。在我自己的实操里最好的调试顺序是先单独写一个小程序调用GetAdaptersAddresses确认能枚举出MAC然后在Hook代码里固定返回这个数据结构再逐步加入修改逻辑。别一上来就直接内联Hook那把问题复杂化了。HDHook这个项目本身就是很好的起点源码不复杂特别适合理解Windows API的调用链和Hook工程的基础细节。真要拿到生产环境用还需要深入处理进程隔离、持久化、反反调试等问题那就完全是另一个量级的工程了。本文还有配套的精品资源点击获取

关于恒美微站

恒美微站专注于为个体商户、工作室提供极简自助建站服务,让每个人都能轻松拥有专业网站。

快速链接

  • 关于我们
  • 建站服务
  • 主题模板
  • 案例展示
  • 资讯中心

服务项目

  • 可视化建站
  • 拖拽编辑
  • 主题定制
  • SEO 优化
  • 网站托管

联系方式

  • 📍 地址:北京市朝阳区建国路 88 号
  • 📞 电话:400-888-8888
  • ✉️ 邮箱:info@hmyw.cn
  • 🕐 时间:周一至周日 9:00-18:00

© 2024 恒美微站 hmyw.cn 版权所有 | 京 ICP 备 12345678 号