R-R, 发表于 2024-1-12 19:34

一个比较完整稳定的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编译的主程序,其他的没什么了。

zhaode 发表于 2024-1-15 21:22

不错的教程   谢谢                                                

ianlcc 发表于 2024-1-15 12:34

很感谢楼主的分享!
这样子让没有源码的人可以试着用这个方式达到一机一码的方式…
希望有人可以分享一下创建的vmp.dll for x86&x64

95877133 发表于 2024-1-12 19:39

一直想找这个教程的

HUHU666 发表于 2024-1-12 20:00

这个软件非常好!

ssw12500 发表于 2024-1-12 20:04

感谢大佬分享

Hou 发表于 2024-1-12 20:36

请教一下安全性如何?

yuangao 发表于 2024-1-12 20:39

这样干, 就是文件很大..

CQGaxm 发表于 2024-1-12 20:40

感谢分享,不错的教程

lies2014 发表于 2024-1-12 20:44

谢谢分享!

95877133 发表于 2024-1-12 21:00

有脱vmp的教程吗

yaoguen 发表于 2024-1-12 21:00

多谢分享,希望支持x64
页: [1] 2 3 4 5 6 7 8 9
查看完整版本: 一个比较完整稳定的VMP授权添加工具,有码。