VMProtect HWID 解析(C++)

0、VMProtect HWID是什么

  • VMProtect:一款商业软件加壳工具,保护软件不被破解
  • HWID:硬件码,设备的唯一标识,常常用于软件绑定白名单或黑名单

VMProtectSDK提供了生成HWID的API,但是没提供HWID分别对应每个设备的ID,所以得自己解析HWID

1、分析HWID组成字段

首先看看VMP Ultimate软件显示的样子

硬件ID(实际上就是Base64):eENCrBVf28czwzPH3pgmMMInHQVGM3aPguQjAGIAkpc=

解码之后:

通过观察可以发现:

  1. 4个字节为1组,即uint32_t
  2. 数据是小端存储
  3. 字段存在偏移

再做一个表简单分析一下

item 解码 实际 offset
CPU AC424378 AC424378 0
Host C7DB5F15 C7DB5F14 -1
HDD C733C333 C733C330 -3
以太网 302698DE 302698DC -2
以太网 ... ... -2
以太网 ... ... -2
以太网 ... ... -2

通过上表一眼盯真,CPU、Host、HDD、以太网(即网卡)的偏移各有不同,但都很简单

2、源码

根据以上结论,编写了用于解析HWID的C++代码

可以去godbolt进行C++代码线上编译测试

GCC 14.2+,参数是:-std=c++23 -g -O0

cpp 复制代码
#include <iostream>
#include <format>
#include <vector>
#include <string>
#include <span>
#include <ranges>

using namespace std;

struct HWID
{
    static constexpr size_t STRIDE = 4;
    using ItemType = std::array<uint8_t, STRIDE>;

    template <typename T>
    HWID(std::span<T> data)
    {
        auto bytes = std::span<uint8_t>(reinterpret_cast<uint8_t*>(data.data()), data.size_bytes());
        auto begin = bytes.begin();
        std::copy(begin, begin + STRIDE, cpu.begin());
        std::copy(begin + STRIDE, begin + STRIDE * 2, host.begin());
        std::copy(begin + STRIDE * 2, begin + STRIDE * 3, hdd.begin());
        const auto num_network_adapters = bytes.size_bytes() / STRIDE - 3;
        network_adapters.reserve(num_network_adapters);
        for (ItemType tmp_item; size_t i : std::views::iota(12llu, bytes.size_bytes()) | std::views::stride(STRIDE))
        {
            std::copy(begin + i, begin + i + STRIDE, tmp_item.begin());
            tmp_item[0] -= 2;
            network_adapters.push_back(tmp_item);
        }
        cpu[0] -= 0;
        host[0] -= 1;
        hdd[0] -= 3;
    }

    auto ToString() noexcept -> std::string
    {
        std::string str = std::format("{:08X}\n{:08X}\n{:08X}",
                                      *reinterpret_cast<uint32_t*>(cpu.data()),
                                      *reinterpret_cast<uint32_t*>(host.data()),
                                      *reinterpret_cast<uint32_t*>(hdd.data()));
        for (const auto& network_adapter : network_adapters)
        {
            str += std::format("\n{:08X}", *reinterpret_cast<const uint32_t*>(network_adapter.data()));
        }
        return str;
    }

    ItemType cpu, host, hdd;
    std::vector<ItemType> network_adapters;
};

unsigned char hwid_bytes[32] = {
	// Offset 0x00000000 to 0x0000001E
	0x78, 0x43, 0x42, 0xAC, 0x15, 0x5F, 0xDB, 0xC7, 0x33, 0xC3, 0x33, 0xC7,
	0xDE, 0x98, 0x26, 0x30, 0xC2, 0x27, 0x1D, 0x05, 0x46, 0x33, 0x76, 0x8F,
	0x82, 0xE4, 0x23, 0x00, 0x62, 0x00, 0x92, 0x97
};

int main() {
  std::span<uint8_t> data{hwid_bytes, 32};
  HWID hwid{data};
  std::cout << hwid.ToString() <<std::endl;

  return 0;
}
相关推荐
星火开发设计10 分钟前
C++ queue 全面解析与实战指南
java·开发语言·数据结构·c++·学习·知识·队列
橘颂TA16 分钟前
【剑斩OFFER】算法的暴力美学——力扣 394 题:字符串解码
数据结构·c++·结构与算法
txinyu的博客1 小时前
结合游戏场景理解,互斥锁,读写锁,自旋锁,CAS / 原子变量,分段锁
开发语言·c++·游戏
hugerat1 小时前
在AI的帮助下,用C++构造微型http server
linux·c++·人工智能·http·嵌入式·嵌入式linux
-森屿安年-1 小时前
unordered_map 和 unordered_set 的实现
数据结构·c++·散列表
九久。2 小时前
手动实现std:iterator/std:string/std::vector/std::list/std::map/std:set
c++·stl
小羊羊Python2 小时前
Sound Maze - 基于 SFML+C++14 的音效迷宫开源游戏 | MIT 协议
c++·游戏·开源
txinyu的博客2 小时前
HTTP服务实现用户级窗口限流
开发语言·c++·分布式·网络协议·http
代码村新手2 小时前
C++-类和对象(上)
开发语言·c++
txinyu的博客2 小时前
map和unordered_map的性能对比
开发语言·数据结构·c++·算法·哈希算法·散列表