写在前面:破解程序没错,转卖就会牵扯到相关的法律问题,出了问题与本人无关。这篇帖子仅供爱好者参考和学习。
我看不少破解者需要就放出来了。
主要功能就是在目标程序内添加一段Shell,然后加载DLL。Shell通过DLL的某导出函数反馈的结果来决定当前程序是否继续执行来达到验证的效果。
先满足伸手党的胃口,后面说原理性的东西:
AddVerify.zip
(4.7 KB, 下载次数: 176)
成品 AddVerify.exe。
上面这个程序就是关键了,运行 AddVerify.exe。选择已经破解的程序,选择后, AddVerify.exe会一闪而过然后退出, 这说明你破解的程序已经处理完毕了。
然后用任意编译型编程语言(易语言/C++等) 写一个DLL ,命名为 DataCore.dll。
DataCore.dll 有一个导出函数,名字为:verify,无参数。
AddVerify.exe处理后的程序会自动加载DataCore.dll,并调用verify函数。 如果verify返回1,被破解的程序就会继续跑,返回0就退出。 你可以在verify添加网络验证,本地验证什么的。
看看DLL的关键部分吧:
然后你可以给处理好的程序加一些壳,来保护你的劳动成果,嘻嘻!
好了,伸手党们可以把当前页面给关了。
下面我们来谈谈原理:
AddVerify.exe 的代码比较简单,主要是在PE文件中新建一个节表,然后把Shell写入。
[C++] 纯文本查看 复制代码 #include <windows.h>
#include "pe.h"
unsigned char data[428] = {
0xE9, 0xA2, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x65, 0x74, 0x4D, 0x6F, 0x64, 0x75,
0x6C, 0x65, 0x48, 0x61, 0x6E, 0x64, 0x6C, 0x65, 0x41, 0x00, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65,
0x54, 0x68, 0x72, 0x65, 0x61, 0x64, 0x00, 0x4B, 0x65, 0x72, 0x6E, 0x65, 0x6C, 0x33, 0x32, 0x2E,
0x64, 0x6C, 0x6C, 0x00, 0x4C, 0x6F, 0x61, 0x64, 0x4C, 0x69, 0x62, 0x72, 0x61, 0x72, 0x79, 0x41,
0x00, 0x44, 0x61, 0x74, 0x61, 0x43, 0x6F, 0x72, 0x65, 0x2E, 0x64, 0x6C, 0x6C, 0x00, 0x45, 0x78,
0x69, 0x74, 0x50, 0x72, 0x6F, 0x63, 0x65, 0x73, 0x73, 0x00, 0x76, 0x65, 0x72, 0x69, 0x66, 0x79,
0x00, 0x55, 0x8B, 0xEC, 0x83, 0xC4, 0xF8, 0x60, 0xC7, 0x45, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x8B,
0x7D, 0x0C, 0xB9, 0xFF, 0xFF, 0xFF, 0xFF, 0x32, 0xC0, 0xFC, 0xF2, 0xAE, 0x8B, 0xCF, 0x2B, 0x4D,
0x0C, 0x89, 0x4D, 0xF8, 0x8B, 0x75, 0x08, 0x03, 0x76, 0x3C, 0x8B, 0x76, 0x78, 0x03, 0x75, 0x08,
0x8B, 0x5E, 0x20, 0x03, 0x5D, 0x08, 0x33, 0xD2, 0x56, 0x8B, 0x3B, 0x03, 0x7D, 0x08, 0x8B, 0x75,
0x0C, 0x8B, 0x4D, 0xF8, 0xF3, 0xA6, 0x75, 0x03, 0x5E, 0xEB, 0x0C, 0x5E, 0x83, 0xC3, 0x04, 0x42,
0x3B, 0x56, 0x18, 0x72, 0xE3, 0xEB, 0x22, 0x2B, 0x5E, 0x20, 0x2B, 0x5D, 0x08, 0xD1, 0xEB, 0x03,
0x5E, 0x24, 0x03, 0x5D, 0x08, 0x0F, 0xB7, 0x03, 0xC1, 0xE0, 0x02, 0x03, 0x46, 0x1C, 0x03, 0x45,
0x08, 0x8B, 0x00, 0x03, 0x45, 0x08, 0x89, 0x45, 0xFC, 0x61, 0x8B, 0x45, 0xFC, 0xC9, 0xC2, 0x08,
0x00, 0x64, 0xA1, 0x30, 0x00, 0x00, 0x00, 0x8B, 0x40, 0x0C, 0x8B, 0x70, 0x1C, 0xAD, 0x8B, 0x40,
0x08, 0xC3, 0x55, 0x8B, 0xEC, 0x83, 0xC4, 0xDC, 0x60, 0xE8, 0x00, 0x00, 0x00, 0x00, 0x5B, 0x81,
0xEB, 0xFE, 0x10, 0x40, 0x00, 0x89, 0x5D, 0xF4, 0xE8, 0xD4, 0xFF, 0xFF, 0xFF, 0x89, 0x45, 0xFC,
0x8D, 0x83, 0x09, 0x10, 0x40, 0x00, 0x50, 0xFF, 0x75, 0xFC, 0xE8, 0x42, 0xFF, 0xFF, 0xFF, 0x89,
0x45, 0xF0, 0x8D, 0x83, 0x27, 0x10, 0x40, 0x00, 0x50, 0xFF, 0x55, 0xF0, 0x89, 0x45, 0xF8, 0x8D,
0x83, 0x1A, 0x10, 0x40, 0x00, 0x50, 0xFF, 0x75, 0xF8, 0xE8, 0x23, 0xFF, 0xFF, 0xFF, 0x89, 0x45,
0xEC, 0x8D, 0x83, 0x34, 0x10, 0x40, 0x00, 0x50, 0xFF, 0x75, 0xF8, 0xE8, 0x11, 0xFF, 0xFF, 0xFF,
0x89, 0x45, 0xE8, 0x8D, 0x83, 0x4E, 0x10, 0x40, 0x00, 0x50, 0xFF, 0x75, 0xF8, 0xE8, 0xFF, 0xFE,
0xFF, 0xFF, 0x89, 0x45, 0xE4, 0x8D, 0x83, 0x41, 0x10, 0x40, 0x00, 0x50, 0xFF, 0x55, 0xE8, 0x89,
0x45, 0xE0, 0x83, 0xF8, 0x00, 0x74, 0x2B, 0x8D, 0x83, 0x5A, 0x10, 0x40, 0x00, 0x50, 0xFF, 0x75,
0xE0, 0xE8, 0xDB, 0xFE, 0xFF, 0xFF, 0x83, 0xF8, 0x00, 0x74, 0x17, 0x89, 0x45, 0xDC, 0xFF, 0x55,
0xDC, 0x83, 0xF8, 0x01, 0x75, 0x0C, 0x8B, 0x83, 0x05, 0x10, 0x40, 0x00, 0x89, 0x45, 0x04, 0x61,
0xC9, 0xC3, 0x6A, 0xFF, 0xFF, 0x55, 0xE4, 0xE8, 0x46, 0xFF, 0xFF, 0xFF
};
int _tmain(int argc, char* argv[])
{
CPeFile mype;
char recvBuf[MAX_PATH];
PIMAGE_SECTION_HEADER psec;
DWORD * OEP;
char *filter="PE 文件(*.exe)\0";
OPENFILENAMEA of={0};
of.lStructSize=sizeof(OPENFILENAMEA);
of.lpstrFilter = filter;
of.Flags = OFN_FILEMUSTEXIST|OFN_PATHMUSTEXIST;
of.nMaxFile = MAX_PATH;
of.lpstrFile=recvBuf;
if (GetOpenFileNameA(&of)==IDOK)
{
if(!mype.LoadPe(recvBuf))
{
printf("打开文件:%s 失败\n",recvBuf);
exit(-1);
}
psec=mype.AddSection(".Core",sizeof(data));
if (!psec)
{
printf("创建节表失败!\n");
exit(-1);
}
OEP = (DWORD *)&data[5];
*OEP = mype.GetEntry()+mype.GetImageBase();
mype.SetNewEntry(psec->VirtualAddress);
mype.WriteDataByRaw(psec->PointerToRawData,(char *)&data,sizeof(data));
mype.FlushBuffer();
return 0;
}
}
pe.h是我写的PE类,篇幅有限,这里就不贴代码了。
data数组是一段16进制数据,这是什么鬼?别慌,这就是在目标程序体中的Shell。
下面代码用masm32编译后有一个节表,用PEID把.text dump出来,然后用winhex把数据复制成C语言数组的形式。
[Asm] 纯文本查看 复制代码 .386
.model flat, stdcall ;32 bit memory model
option casemap :none ;case sensitive
include windows.inc
GetModuleHandleA typedef proto :dword
CreateThread_t typedef proto :dword,:dword,:dword,:dword,:dword
LoadLibrary_t typedef proto :dword
verify_t typedef proto ;返回1放行,返回0退出
ExitProcess_t typedef proto :dword
.code
jmp _start
;VA
OEP dd 0
szGetModuleHandleA db 'GetModuleHandleA',0
szCreateThread db 'CreateThread',0
szKernel32 db 'Kernel32.dll',0
szLoadLibraryA db 'LoadLibraryA',0
szDll db 'DataCore.dll',0
szExitProcess db 'ExitProcess',0
szVerify db 'verify',0
_getApi proc _hModule,_lpApi
local @ret
local @dwLen
pushad
mov @ret,0
;计算API字符串的长度,含最后的零
mov edi,_lpApi
mov ecx,-1
xor al,al
cld
repnz scasb
mov ecx,edi
sub ecx,_lpApi
mov @dwLen,ecx
;从pe文件头的数据目录获取导出表地址
mov esi,_hModule
add esi,dword ptr[esi+3ch]
assume esi:ptr IMAGE_NT_HEADERS
mov esi,[esi].OptionalHeader.DataDirectory.VirtualAddress
add esi,_hModule
assume esi:ptr IMAGE_EXPORT_DIRECTORY
;查找符合名称的导出函数名
mov ebx,[esi].AddressOfNames
add ebx,_hModule
xor edx,edx
.repeat
push esi
mov edi,[ebx]
add edi,_hModule
mov esi,_lpApi
mov ecx,@dwLen
repz cmpsb
.if ZERO?
pop esi
jmp @F
.endif
pop esi
add ebx,4
inc edx
.until edx>=[esi].NumberOfNames
jmp _ret
@@:
;通过API名称索引获取序号索引再获取地址索引
sub ebx,[esi].AddressOfNames
sub ebx,_hModule
shr ebx,1
add ebx,[esi].AddressOfNameOrdinals
add ebx,_hModule
movzx eax,word ptr [ebx]
shl eax,2
add eax,[esi].AddressOfFunctions
add eax,_hModule
;从地址表得到导出函数的地址
mov eax,[eax]
add eax,_hModule
mov @ret,eax
_ret:
assume esi:nothing
popad
mov eax,@ret
ret
_getApi endp
_getKernelBase proc
assume fs:nothing
mov eax,fs:[30h] ;PEB的地址
mov eax, [eax + 0ch] ;Ldr的地址
mov esi, [eax + 01ch] ;Flink地址
lodsd
mov eax, [eax + 08h] ;eax就是kernel32.dll的地址
ret
_getKernelBase endp
main proc
LOCAL kernelBa
LOCAL kernel32
LOCAL loc
LOCAL getmodulehandlea:GetModuleHandleA
LOCAL CreateThread_m:CreateThread_t
LOCAL LoadLibraryA:LoadLibrary_t
LOCAL ExitProcessA:ExitProcess_t
LOCAL hInst:dword
LOCAL verify:verify_t
pushad
call @f
@@:
pop ebx
sub ebx,offset @b
mov loc,ebx
invoke _getKernelBase
mov kernelBa,eax
invoke _getApi,kernelBa,addr [ebx+szGetModuleHandleA] ;获取GetModuleHandleA
mov getmodulehandlea,eax
invoke getmodulehandlea,addr[ebx+szKernel32] ;获取Kernel32基址
mov kernel32,eax
invoke _getApi,kernel32,addr[ebx+szCreateThread];获取CreateThread
mov CreateThread_m,eax
invoke _getApi,kernel32,addr[ebx+szLoadLibraryA]
mov LoadLibraryA,eax
invoke _getApi,kernel32,addr[ebx+szExitProcess]
mov ExitProcessA,eax
invoke LoadLibraryA,addr[ebx+szDll]
mov hInst,eax
cmp eax,0
je exit1
invoke _getApi,hInst,addr[ebx+szVerify]
cmp eax,0
je exit1
mov verify,eax
invoke verify
cmp eax,1
jne exit1
mov eax,[ebx+OEP]
mov [ebp+4],eax
popad
ret
exit1:
invoke ExitProcessA,-1
main endp
_start:
invoke main
end _start
代码领取处:
AddDLL.zip
(515.62 KB, 下载次数: 213)
|