好友
阅读权限20
听众
最后登录1970-1-1
|
<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>这样加密后序列号锁定了,但由于没有获取到机器码和置入序列号,以下代码是一个获取机器码和置入序列号简版,你们可以用来修改。
[C++] 纯文本查看 复制代码 // 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 : [0x30]
lea eax, dword ptr ds : [eax + 0x500]
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[LicSize + 1];
DWORD ReadSize;
ReadFile(hLicFile, LicBuf, LicSize, &ReadSize, NULL);
CloseHandle(hLicFile);
GetFs();
*LicAddr = LicBuf;
}
void GetHwid_()
{
DWORD HwidSize = VMProtectGetCurrentHWID(NULL, 0);
char * HwidStr = new char[HwidSize + 1];
VMProtectGetCurrentHWID(HwidStr, HwidSize);
MessageBoxA(NULL, HwidStr, "机器码", MB_OK);
ReadLicense();
}
BOOL APIENTRY DllMain(HMODULE hModule,
DWORD ul_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的程序。
[C++] 纯文本查看 复制代码 // Lic.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include "windows.h"
#include <Shlwapi.h>
#pragma comment(lib, "Shlwapi.lib")
#define AddSize 0x20000
unsigned char OepData[0x0042] =
{
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[fileSize];
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[1].VirtualAddress);
DWORD ImprotSize = ntHeader->OptionalHeader.DataDirectory[1].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[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].Size = 0;
ntHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].VirtualAddress = 0;
ntHeader->OptionalHeader.DataDirectory[1].VirtualAddress = newSection->VirtualAddress;
ntHeader->OptionalHeader.DataDirectory[1].Size = ImprotSize + sizeof(IMAGE_IMPORT_DESCRIPTOR);;
if (0 != ntHeader->OptionalHeader.DataDirectory[1].VirtualAddress)
{
DWORD RelocAddr = rva2offset(pNewTempBuffer, ntHeader->OptionalHeader.DataDirectory[5].VirtualAddress);
DWORD RelocSize = ntHeader->OptionalHeader.DataDirectory[5].Size;
memcpy(PVOID((DWORD)pNewTempBuffer + fileSize + ImprotSize + 1000), PVOID((DWORD)pNewTempBuffer + RelocAddr), RelocSize);
ntHeader->OptionalHeader.DataDirectory[5].VirtualAddress = newSection->VirtualAddress + +ImprotSize + 1000;
ntHeader->OptionalHeader.DataDirectory[5].Size = ntHeader->OptionalHeader.DataDirectory[5].Size;
DWORD* RelocBase = PDWORD((DWORD)pNewTempBuffer + fileSize + ImprotSize + 1000 + ntHeader->OptionalHeader.DataDirectory[5].Size);
*RelocBase = newSection->VirtualAddress;
*(RelocBase + 1) = 0xC;
*(PWORD(RelocBase + 2)) = NewOep + 0x28 - newSection->VirtualAddress + 0x3000;
ntHeader->OptionalHeader.DataDirectory[5].Size += 0xC;
}
char* newFileName = (ntHeader->FileHeader.Characteristics & IMAGE_FILE_DLL) ? "New.dll" : "New.exe";
CHAR parentPath[MAX_PATH];
CHAR newPath[MAX_PATH];
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[1];
AddImprot(filepath);
return 0;
}
<9>大致总结,虽然我说了这么多,但使用起来应该很简单,
第一步:用VMP_LIC选择要加密的文件,然后写出new.exe的新文件后,放到vmp里加密,加密时要初始化授权,然后锁定源程序oep。
第二步:把dll编译好如我上加密后可以一只使用这个dll,你可以任意修改这个dll,甚至加上sdk等。
第三步:dll导入进去选择启动时载入,很简单的三步,其实很方便,在源代码的基础上也可以任意修改。
当然,也可以根据这个思路写一份x64的版本。
以下是我用MFC编译的主程序,其他的没什么了。
|
免费评分
-
查看全部评分
|