0632955255184 发表于 2025-1-10 20:45:51

完整稳定的VMP授权添加工具

<0>这是一个还算完整的VMP添加授权工具,比之前开源的版本修复了稳定性和不便性。和支持DLL。
<1>首先打开VMP_LIC工具如下图,然后选择要加密的文件。


<2>选择可执行文件后,目录下会多出一个new.exe或者dll的修改文件,目录下的VMSDK是在vmp目录下的 因为不加密的话打不开加密后的文件,
需要放置dll进去,加密后可以不需要这个vmpsdk的dll了,VMProtectSDK32.dll可以在论坛里面的3.x里面获取
可以看到下图,我构建了一段汇编,在里面添加了
VMProtectSetSerialNumber函数,并用PEB+0x500的地址作为参数用来传递key,这样做的好处是我可以写一个dll,dll用来获取机器码和key,
然后把key的地址放到PEB+0X500传进去,这样就达到了一键授权。


<3>再得到new.exe后用vmp加密,加密时锁定原来的oep,也可以自己添加任意地址锁定序列号。如下图


<4>这样加密后序列号锁定了,但由于没有获取到机器码和置入序列号,以下代码是一个获取机器码和置入序列号简版,你们可以用来修改。
// dllmain.cpp : 定义 DLL 应用程序的入口点。
#include "stdafx.h"
#include "VMProtectSDK.h"
#pragma comment(lib, "VMProtectSDK32.lib")

char ** LicAddr = NULL;

void __stdcall GetFs()
{
    __asm
    {
      mov eax, dword ptr fs :
      lea eax, dword ptr ds :
      mov LicAddr, eax;
    }

}

void ReadLicense()
{
    HANDLE hLicFile = CreateFileA("License.Lic", GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
    if (INVALID_HANDLE_VALUE == hLicFile)
    {
      MessageBoxA(NULL, "Lic文件出错!", "Error", MB_OK);
    }
    DWORD LicSize;
    LicSize = GetFileSize(hLicFile, NULL);
    if (0 == LicSize)
    {
      MessageBoxA(NULL, "Lic文件内容为空!", "Error", MB_OK);
    }
    char* LicBuf = new char;
    DWORD ReadSize;
    ReadFile(hLicFile, LicBuf, LicSize, &ReadSize, NULL);
    CloseHandle(hLicFile);
    GetFs();
    *LicAddr = LicBuf;
}


void GetHwid_()
{
    DWORD HwidSize = VMProtectGetCurrentHWID(NULL, 0);
    char * HwidStr = new char;
    VMProtectGetCurrentHWID(HwidStr, HwidSize);
    MessageBoxA(NULL, HwidStr, "机器码", MB_OK);
    ReadLicense();
}

BOOL APIENTRY DllMain(HMODULE hModule,
    DWORDul_reason_for_call,
    LPVOID lpReserved
    )
{
    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
      GetHwid_();
    case DLL_THREAD_ATTACH:
    case DLL_THREAD_DETACH:
    case DLL_PROCESS_DETACH:
      break;
    }
    return TRUE;
}
<5>代码里面的VMProtectSDK.h和VMProtectSDK32.lib 都可以再论坛的VMP3.X里面获取得到,dll编译出来后需要加密以下,因为调用了vmp的sdk,需要加密来获取机器码,
再加密的时候,保护选项全部选否,这个可以只加密一次,因为这个只是获取机器码和置入key的工具,如下图,


<6>在dll弄好之后,可以用vmp的dllbox来封装他,如果你不喜欢有外置dll来获取机器码那些,这样就达到了对exe或dll加密后仍然是一个单文件的形式,
在放置dll进去的时候选择启动时载入,如下图


<7>加密出来后就是一个单文件的new.vmp.exe了,当你运行时会弹出机器码,没有key时会写出License.Lic文件,
你在vmp里面算号后把key放入License.Lic里即可(KEY不要有换行符)
如下图


<8>主程序代码如下,是控制台代码,我编译了一份MFC的程序。
// Lic.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include "windows.h"
#include <Shlwapi.h>
#pragma comment(lib, "Shlwapi.lib")

#define AddSize 0x20000


unsigned char OepData =
{
    0xeb, 0x10, 0x56, 0x4d, 0x50, 0x72, 0x6f, 0x74, 0x65, 0x63, 0x74, 0x20, 0x62, 0x65, 0x67, 0x69,
    0x6e, 0x00, 0x60, 0x9c, 0x64, 0xa1, 0x30, 0x00, 0x00, 0x00, 0x8b, 0x80, 0x00, 0x05, 0x00, 0x00,
    0x83, 0xf8, 0x00, 0x74, 0x07, 0x50, 0xff, 0x15, 0x33, 0x71, 0x4b, 0x00, 0x9d, 0x61, 0xe9, 0xda,
    0x55, 0xfa, 0xff, 0xeb, 0x0e, 0x56, 0x4d, 0x50, 0x72, 0x6f, 0x74, 0x65, 0x63, 0x74, 0x20, 0x65,
    0x6e, 0x64
};

DWORD rva2offset(LPVOID base, DWORD rva)
{
    IMAGE_DOS_HEADER* dosHeader = (IMAGE_DOS_HEADER*)base;
    IMAGE_NT_HEADERS32* ntHeader = (IMAGE_NT_HEADERS32*)(dosHeader->e_lfanew + (DWORD)base);
    IMAGE_SECTION_HEADER* sectionHeader = (IMAGE_SECTION_HEADER*)((DWORD)ntHeader + sizeof(IMAGE_NT_HEADERS32));
    if (rva<ntHeader->OptionalHeader.SizeOfHeaders)
    {
      return rva;
    }
    for (DWORD i = 1; i <= ntHeader->FileHeader.NumberOfSections; i++)
    {
         
      if (i == ntHeader->FileHeader.NumberOfSections)
      {
            return rva - sectionHeader->VirtualAddress + sectionHeader->PointerToRawData;
      }
      else if (rva >= sectionHeader->VirtualAddress && rva < (sectionHeader + 1)->VirtualAddress)
      {
            return rva - sectionHeader->VirtualAddress + sectionHeader->PointerToRawData;
      }
      sectionHeader++;
    }
    return 0;
}

DWORD AddImprot(char *ModulePath)
{


    HANDLE hFile = CreateFileA(ModulePath, GENERIC_WRITE | GENERIC_READ, 0, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
    if (hFile == 0 || hFile == INVALID_HANDLE_VALUE)
    {
      return 0;
    }
    DWORD fileSize = GetFileSize(hFile, 0);
    char* buf = new char;
    DWORD ReadSize;
    ReadFile(hFile, buf, fileSize, &ReadSize, NULL);
    CloseHandle(hFile);

    DWORD New_File_Size = fileSize + AddSize;
    PVOID pNewTempBuffer = (PVOID)malloc(New_File_Size);
    memset(pNewTempBuffer, 0, New_File_Size);
    memcpy(pNewTempBuffer, buf, fileSize);

    PIMAGE_NT_HEADERS32 ntHeader = (PIMAGE_NT_HEADERS32)((DWORD)pNewTempBuffer + ((PIMAGE_DOS_HEADER)(pNewTempBuffer))->e_lfanew);
    if ((ntHeader->FileHeader.NumberOfSections + 1)*sizeof(IMAGE_SECTION_HEADER)>ntHeader->OptionalHeader.SizeOfHeaders)
    {
      printf("剩余空间不足.");
      return 0;
    }

   
    PIMAGE_SECTION_HEADER newSection = (PIMAGE_SECTION_HEADER)(ntHeader + 1) + ntHeader->FileHeader.NumberOfSections;
    memcpy(newSection->Name, "VMPLic", 8);
    newSection->Characteristics = 0xE0000020;
    newSection->Misc.VirtualSize = AddSize;
    newSection->NumberOfLinenumbers = 0;
    newSection->NumberOfRelocations = 0;
    newSection->PointerToLinenumbers = 0;
    newSection->PointerToRelocations = 0;
    newSection->SizeOfRawData = AddSize;

    DWORD NewAddSize = (newSection - 1)->Misc.VirtualSize > (newSection - 1)->SizeOfRawData ?
      (newSection - 1)->Misc.VirtualSize : (newSection - 1)->SizeOfRawData;

    newSection->VirtualAddress = (newSection - 1)->VirtualAddress + NewAddSize;
    if (newSection->VirtualAddress % ntHeader->OptionalHeader.SectionAlignment)
    {
      newSection->VirtualAddress = newSection->VirtualAddress / ntHeader->OptionalHeader.SectionAlignment *
            ntHeader->OptionalHeader.SectionAlignment + ntHeader->OptionalHeader.SectionAlignment;
    }
    newSection->PointerToRawData = (newSection - 1)->PointerToRawData + (newSection - 1)->SizeOfRawData;
    if (newSection->PointerToRawData% ntHeader->OptionalHeader.FileAlignment)
    {
      newSection->PointerToRawData = newSection->PointerToRawData / ntHeader->OptionalHeader.FileAlignment *
            ntHeader->OptionalHeader.FileAlignment + ntHeader->OptionalHeader.FileAlignment;
    }


    DWORD ImprotAddress = rva2offset(pNewTempBuffer, ntHeader->OptionalHeader.DataDirectory.VirtualAddress);
    DWORD ImprotSize = ntHeader->OptionalHeader.DataDirectory.Size;


    char* DLLname = "VMProtectSDK32.dll";
    char* FunctionName = "VMProtectSetSerialNumber";


    memcpy(PVOID((DWORD)pNewTempBuffer + fileSize), PVOID((DWORD)pNewTempBuffer + ImprotAddress), ImprotSize);


    PIMAGE_IMPORT_DESCRIPTOR AddIMpoetAddr = (PIMAGE_IMPORT_DESCRIPTOR)((DWORD)pNewTempBuffer + fileSize + ImprotSize - sizeof(IMAGE_IMPORT_DESCRIPTOR));


    AddIMpoetAddr->OriginalFirstThunk = newSection->VirtualAddress + ImprotSize + sizeof(IMAGE_IMPORT_DESCRIPTOR) + strlen(DLLname) + 1;
    AddIMpoetAddr->FirstThunk = AddIMpoetAddr->OriginalFirstThunk + sizeof(IMAGE_THUNK_DATA32) * 2;
    AddIMpoetAddr->ForwarderChain = 0;
    AddIMpoetAddr->Name = newSection->VirtualAddress + ImprotSize + sizeof(IMAGE_IMPORT_DESCRIPTOR);
    AddIMpoetAddr->TimeDateStamp = 0;



    memcpy((PVOID)((DWORD)pNewTempBuffer + fileSize + ImprotSize + sizeof(IMAGE_IMPORT_DESCRIPTOR)), DLLname, strlen(DLLname) + 1);
    memcpy((PVOID)((DWORD)pNewTempBuffer + fileSize + ImprotSize + sizeof(IMAGE_IMPORT_DESCRIPTOR) + strlen(DLLname) + 1 + 101 + 2), FunctionName, strlen(FunctionName) + 1);
    DWORD ByName = newSection->VirtualAddress + ImprotSize + sizeof(IMAGE_IMPORT_DESCRIPTOR) + strlen(DLLname) + 1 + 101;

    DWORD* OFT = PDWORD((DWORD)pNewTempBuffer + fileSize + ImprotSize + sizeof(IMAGE_IMPORT_DESCRIPTOR) + strlen(DLLname) + 1);
    DWORD* IAT = PDWORD((DWORD)pNewTempBuffer + fileSize + ImprotSize + sizeof(IMAGE_IMPORT_DESCRIPTOR) + strlen(DLLname) + 1 + sizeof(IMAGE_THUNK_DATA32) * 2);

    *OFT = ByName;
    *IAT = ByName;


    ntHeader->FileHeader.NumberOfSections++;
    ntHeader->OptionalHeader.SizeOfImage += AddSize;



    DWORD NewOep = newSection->VirtualAddress + ImprotSize + sizeof(IMAGE_IMPORT_DESCRIPTOR) + strlen(DLLname) + 1 + 101 + 200;
    memcpy(PVOID((DWORD)pNewTempBuffer + fileSize + ImprotSize + sizeof(IMAGE_IMPORT_DESCRIPTOR) + strlen(DLLname) + 1 + 101 + 200), OepData, 0x42);


    PDWORD CallIat = PDWORD((DWORD)pNewTempBuffer + fileSize + ImprotSize + sizeof(IMAGE_IMPORT_DESCRIPTOR) + strlen(DLLname) + 1 + 101 + 200 + 0x28);
    DWORD C_value = AddIMpoetAddr->FirstThunk + ntHeader->OptionalHeader.ImageBase;
    *CallIat = C_value;


    PDWORD JmpOep = PDWORD((DWORD)pNewTempBuffer + fileSize + ImprotSize + sizeof(IMAGE_IMPORT_DESCRIPTOR) + strlen(DLLname) + 1 + 101 + 200 + 0x2F);
    DWORD J_value = ntHeader->OptionalHeader.AddressOfEntryPoint -
      (newSection->VirtualAddress + ImprotSize + sizeof(IMAGE_IMPORT_DESCRIPTOR) + strlen(DLLname) + 1 + 101 + 200 + 0x2F) - 4;
    *JmpOep = J_value;


    ntHeader->OptionalHeader.AddressOfEntryPoint = NewOep;


    ntHeader->OptionalHeader.DataDirectory.Size = 0;
    ntHeader->OptionalHeader.DataDirectory.VirtualAddress = 0;

    ntHeader->OptionalHeader.DataDirectory.VirtualAddress = newSection->VirtualAddress;
    ntHeader->OptionalHeader.DataDirectory.Size = ImprotSize + sizeof(IMAGE_IMPORT_DESCRIPTOR);;

    if (0 != ntHeader->OptionalHeader.DataDirectory.VirtualAddress)
    {

      DWORD RelocAddr = rva2offset(pNewTempBuffer, ntHeader->OptionalHeader.DataDirectory.VirtualAddress);
      DWORD RelocSize = ntHeader->OptionalHeader.DataDirectory.Size;

      memcpy(PVOID((DWORD)pNewTempBuffer + fileSize + ImprotSize + 1000), PVOID((DWORD)pNewTempBuffer + RelocAddr), RelocSize);

      ntHeader->OptionalHeader.DataDirectory.VirtualAddress = newSection->VirtualAddress + +ImprotSize + 1000;
      ntHeader->OptionalHeader.DataDirectory.Size = ntHeader->OptionalHeader.DataDirectory.Size;

      DWORD* RelocBase = PDWORD((DWORD)pNewTempBuffer + fileSize + ImprotSize + 1000 + ntHeader->OptionalHeader.DataDirectory.Size);
      *RelocBase = newSection->VirtualAddress;
      *(RelocBase + 1) = 0xC;
      *(PWORD(RelocBase + 2)) = NewOep + 0x28 - newSection->VirtualAddress + 0x3000;
      ntHeader->OptionalHeader.DataDirectory.Size += 0xC;

    }


    char* newFileName = (ntHeader->FileHeader.Characteristics & IMAGE_FILE_DLL) ? "New.dll" : "New.exe";
    CHAR parentPath;
    CHAR newPath;
    PathRemoveFileSpecA(ModulePath);
    lstrcpyA(parentPath, ModulePath);
    PathCombineA(newPath, parentPath, newFileName);

    HANDLE hFile2 = CreateFileA(
      newPath, GENERIC_WRITE | GENERIC_READ,
      0,
      NULL,
      CREATE_ALWAYS,
      FILE_ATTRIBUTE_NORMAL,
      NULL);
    DWORD WriteSize = 0;
    WriteFile(hFile2, pNewTempBuffer, New_File_Size, &WriteSize, NULL);
    CloseHandle(hFile2);

}

int main(int argc, char *argv[])
{
    char * filepath = argv;
    AddImprot(filepath);
    return 0;
}
<9>大致总结,虽然我说了这么多,但使用起来应该很简单,
第一步:用VMP_LIC选择要加密的文件,然后写出new.exe的新文件后,放到vmp里加密,加密时要初始化授权,然后锁定源程序oep。
第二步:把dll编译好如我上加密后可以一只使用这个dll,你可以任意修改这个dll,甚至加上sdk等。
第三步:dll导入进去选择启动时载入,很简单的三步,其实很方便,在源代码的基础上也可以任意修改。
当然,也可以根据这个思路写一份x64的版本。
以下是我用MFC编译的主程序,其他的没什么了。
页: [1]
查看完整版本: 完整稳定的VMP授权添加工具