selph
selph
发布于 2022-02-11 / 407 阅读
0
0

重启验证

  最近遇到一个程序有一个很有趣的认证方式--重启验证,这里根据本人对重启验证的猜想进行实现一下看看

重启验证简介

  重启验证:在程序启动的时候验证注册信息,重启验证有一个特点就是会保存注册信息,在启动的时候验证这个注册信息

  这个注册信息可以以多种形式保存:比如注册表和文件

  执行流程如下图所示:

image-20220210235443390

代码实现

  实验环境:Win10 + VS2022 + Qt6

验证注册信息

  首先是验证注册信息,这里的验证逻辑是通过用户名计算出一个序列号,然后通过比对用户输入的用户名对应的序列号是否相同,来进行验证

这里以实现功能流程为主,为了图省事,注册信息直接保存在当前目录下了

void VaC_reboot::Verify()
{
    // 打开文件
    HANDLE hFile = CreateFileW(L"Serial.txt", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_WRITE | FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);

    // 读取文件
    char buf[0x100] = { 0 };
    DWORD readSize = 0;
    ReadFile(hFile, buf, 0x100, &readSize, NULL);
    if (readSize == 0) {
        CloseHandle(hFile);
        return;
    }
    CloseHandle(hFile);

    std::string sbuf = buf;
    std::string Uname = sbuf.substr(0, sbuf.find(':'));
    std::string USerial = sbuf.substr(sbuf.find(':')+1, sbuf.length());
    std::string RealSerial = CalcSerial(Uname);

    // 如果文件读取到内容了,比对序列号是否正确,否则进入重启环节
    if (readSize) {
        if (!strcmp(USerial.c_str(), RealSerial.c_str())) {
            QMessageBox::about(this, "Error", "Verify Success!");
            ExitProcess(0);
        }
        else {
            QMessageBox::about(this, "Error", "Verify Failed!");
        }
    }
}

序列号生成

  这里就简单随便写一个计算序列号的算法(verifyKey初始为0):

std::string VaC_reboot::CalcSerial(std::string Uname)
{
    std::string UserName = Uname;
    std::string Serial;

    for(auto a:UserName)
    {
        verifyKey += a;
    }

    Serial = "VaC_";
    Serial += UserName[0] ^ verifyKey;
    for (int i = 1; UserName[i]; i++) {
        Serial += (UserName[i - 1] ^ UserName[i])%10 + '0';
    }
    return Serial;
}

保存验证信息

  创建文件写入输入的用户名和序列号:

    HANDLE hFile = CreateFileW(L"Serial.txt", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_WRITE | FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
    char writeBuf[0x100] = { 0 };
    strcpy(writeBuf, ui.lineEdit_UserName->text().toStdString().c_str());
    strcat(writeBuf, ":");
    strcat(writeBuf, ui.lineEdit_Serial->text().toStdString().c_str());
    DWORD dwRet;
    WriteFile(hFile, writeBuf, strlen(writeBuf), &dwRet, NULL);
    CloseHandle(hFile);

重启程序

  所谓重启,无非就是关闭和打开两个基本操作的组合:

    // 重启环节
    // 获取进程路径
    char filePath[MAX_PATH] = { 0 };
    GetModuleFileNameA(NULL, filePath, MAX_PATH);
    // 创建进程
    PROCESS_INFORMATION pi = { 0 };
    STARTUPINFOA si = { 0 };
    si.cb = sizeof(STARTUPINFOA);
    BOOL bRet = CreateProcessA(filePath,
        NULL, NULL, NULL, FALSE,
        NULL, NULL, NULL, &si, &pi);
    // 退出当前进程
    ExitProcess(1);

效果展示

  打开程序,输入用户名和序列号之后,将输入的信息保存到当前目录下,弹窗提示重启,点击确定后程序重启

  image.png

  因为输入的序列号是胡乱输入的,所以这里一定是认证失败的,之后会再次弹出认证输入窗口

  image.png

  当输入正确的用户名序列号组合之后:(selph:VaC_o2984)提示认证成功,并退出认证窗口

  image.png

  

示例程序

参考资料

  (6条消息) 重启验证的三种形式及其解决方法_星⁠辞归野的博客-CSDN博客_重启验证

  


评论