📄 main.asm
字号:
;*********************************************************
;程序名称:可执行文件加密锁
;本文件是主文件的源代码
;本程序可以对有效的PE文件进行加锁,使程序运行以前必须通过密码验证
;作者:牛博威
;日期:2003-12-10
;整理:2003-12-11
;出处:http://nboy.cnwlt.com
;注意事项:如欲转载,请保持本程序的完整,并注明出处
;在此特别感谢罗聪大侠和他的论坛上的朋友们.同时感谢孙灭给我提供罗云彬老师的win32汇编书,这本书确实不错
;说明:
;1、被本程序加锁后的程序代码长度会增加4096字节,我对此表示抱歉,以后我会考虑把添加的代码嵌入到原来的程序中.
;2、我的加密水平不高,没有对密码进行加密处理,本来想进行一下异或处理,后来想想还是不献丑了,等以后会了CRC再说吧.
;4、解锁的时候在上面的文本框中写一个密码就可以了,下面的密码框不用管
;5、本程序主要供技术研究,所以很多地方作的不全面。如果哪位有兴趣改进,不妨交流一下
;*********************************************************
.386
.model flat, stdcall
option casemap :none
include windows.inc
include user32.inc
includelib user32.lib
include kernel32.inc
includelib kernel32.lib
include comdlg32.inc
includelib comdlg32.lib
ICO_MAIN equ 1000
DLG_MAIN equ 1000
IDC_INFO equ 1001
IDM_MAIN equ 2000
IDM_OPEN equ 2001
IDM_EXIT equ 2002
IDC_PATH equ 2003 ;显示指定文件的对话框
IDC_PASS1 equ 2004 ;用户密码框
IDC_PASS2 equ 2005 ;用户密码确定框
IDC_BROWSE equ 2006 ;浏览文件按钮
IDC_CHANGE equ 2007 ;文件加锁按钮
IDC_UNCHAN equ 2008 ;文件解锁按钮
.data?
hInstance dd ?
hRichEdit dd ?
hWinMain dd ?
hWinEdit dd ?
szFileName db MAX_PATH dup (?)
szNewFile db ?
_pass1 db 9 dup(?) ;存储用户输入的密码,共8位密码,占9个字节
_pass2 db 9 dup(?)
_szErr db ?
.const
szz db "修改完毕!请保存好密码.请检查bak备份文件.....",0
szzz db "解锁完毕,请检查!请检查bak备份文件....",0
szDllEdit db 'RichEd20.dll',0
szClassEdit db 'RichEdit20A',0
szFont db '宋体',0
szBak db '.bak',0
szExtPe db 'PE Files',0,'*.exe;*.dll;*.scr;*.fon;*.drv',0
db 'All Files(*.*)',0,'*.*',0,0
szErr db '文件格式错误!',0
_Introduce db ' 欢迎使用nbw文件加密锁', 13, 10
db '你可以去http://nboy.cnwlt.com下载源代码.', 13, 10
db '作者 : 牛博威', 13, 10
db 'QQ : 37122085', 13, 10
db 'Email: advice107@sina.com', 13, 10
db '欢迎和我联系!',0
szErrPass db '两次输入的密码不一样或密码长度超出了8位,请核查!',0
szErrCheck db '您输入的密码错误!',0
szErr1 db '文件无法打开!',0
szErr2 db '无法创建文件内存映像!',0
szErr3 db '这不是有效的PE格式文件!',0
szErr4 db '这个文件已经被加过锁了!',0
szErr5 db '文件没有足够空间再添加新的节表,如您想加锁,请和我联系!',0
szErr6 db '这个文件没有被加过锁!',0
_SehM db '发生错误,请确定操作或找我联系!',0
_SehT db '提示',0
.code
;********************************************************************
_Handler proc _lpExceptionRecord,_lpSEH,_lpContext,_lpDispatcherContext
local @szBuffer[256]:byte
pushad
mov esi,_lpExceptionRecord
mov edi,_lpContext
assume esi:ptr EXCEPTION_RECORD,edi:ptr CONTEXT
mov [edi].regEip,offset _SafePlace
assume esi:nothing,edi:nothing
popad
mov eax,ExceptionContinueExecution
ret
_Handler endp
;********************************************************************
_Init proc
local @stCf:CHARFORMAT
invoke GetDlgItem,hWinMain,IDC_INFO
mov hWinEdit,eax
invoke LoadIcon,hInstance,ICO_MAIN
invoke SendMessage,hWinMain,WM_SETICON,ICON_BIG,eax
invoke SendMessage,hWinEdit,EM_SETTEXTMODE,TM_PLAINTEXT,0
invoke SetWindowText,hWinEdit,addr _Introduce
invoke RtlZeroMemory,addr @stCf,sizeof @stCf
mov @stCf.cbSize,sizeof @stCf
mov @stCf.yHeight,9 * 20
mov @stCf.dwMask,CFM_FACE or CFM_SIZE or CFM_BOLD
invoke lstrcpy,addr @stCf.szFaceName,addr szFont
invoke SendMessage,hWinEdit,EM_SETCHARFORMAT,0,addr @stCf
invoke SendMessage,hWinEdit,EM_EXLIMITTEXT,0,-1
ret
_Init endp
;********************************************************************
_OpenFileA proc uses eax,hWnd ;打开文件,找出指定的文件路径,指向szFileName
LOCAL @stOF:OPENFILENAME
invoke RtlZeroMemory,addr @stOF,sizeof @stOF
mov @stOF.lStructSize,sizeof @stOF
push hWinMain
pop @stOF.hwndOwner
mov @stOF.lpstrFilter,offset szExtPe
mov @stOF.lpstrFile,offset szFileName
mov @stOF.nMaxFile,MAX_PATH
mov @stOF.Flags,OFN_PATHMUSTEXIST or OFN_FILEMUSTEXIST
invoke GetOpenFileName,addr @stOF
invoke SetDlgItemText,hWnd,IDC_PATH,addr szFileName
;**********;保存原来的文件
invoke lstrcat, addr szNewFile, addr szFileName
invoke lstrcat, addr szNewFile, addr szBak
invoke CopyFile, addr szFileName, addr szNewFile, FALSE
;**********
xor eax,eax
ret
_OpenFileA endp
;********************************************************************
_ChangeFile proc hwnd
LOCAL hFile : DWORD
LOCAL hMapping : DWORD
LOCAL pMapping : DWORD
LOCAL ByteWrite: DWORD
LOCAL HostEntry: DWORD
pushad
invoke CreateFile,addr szFileName,GENERIC_READ+GENERIC_WRITE,FILE_SHARE_READ + \
FILE_SHARE_WRITE,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL
.if eax == INVALID_HANDLE_VALUE
invoke MessageBox,hwnd,addr szErr1,NULL,MB_OK or MB_ICONWARNING
jmp _exit
.endif
mov hFile,eax
invoke CreateFileMapping,hFile,NULL,PAGE_READWRITE,0,0,NULL
or eax,eax
jz IF_F3
mov hMapping , eax
xor edi,edi
push edi
push edi
push edi
push FILE_MAP_READ+FILE_MAP_WRITE
push hMapping
call MapViewOfFile
or eax,eax
jnz @F
invoke MessageBox,hwnd,addr szErr2,NULL,MB_OK or MB_ICONWARNING
jmp IF_F2
@@:
mov pMapping,eax
mov esi,eax
assume esi:ptr IMAGE_DOS_HEADER
cmp [esi].e_magic,IMAGE_DOS_SIGNATURE
jnz IF_F1
cmp [esi].e_lfarlc,040h
jnz IF_F1
add esi,[esi].e_lfanew
assume esi:ptr IMAGE_NT_HEADERS
cmp [esi].Signature,IMAGE_NT_SIGNATURE ;是PE文件吗?
jnz IF_F1
cmp [esi].OptionalHeader.Subsystem,2
jnz IF_F1
cmp [esi].OptionalHeader.CheckSum,0 ;判断文件校验和,由于这个加密锁目前在XP或2000下不支持,所以这里的校验和可以不用判断
jz @F ;合法性判断完毕,开始修改文件
invoke MessageBox,hwnd,addr szErr3,NULL,MB_OK or MB_ICONWARNING
jmp IF_F1
@@:
mov eax,[esi].OptionalHeader.AddressOfEntryPoint
add eax,[esi].OptionalHeader.ImageBase
mov HostEntry,eax ;保存原入口
movzx eax,[esi].FileHeader.NumberOfSections
mov ecx,sizeof IMAGE_SECTION_HEADER
mul ecx ;计算所有节表的长度
add eax,sizeof IMAGE_NT_HEADERS
add eax,esi
;******************
;令eax指向文件最后一个节表,并判断节表名称是不是77626e2e(即.nbw)
sub eax,sizeof IMAGE_SECTION_HEADER
push eax
mov eax,[eax]
cmp eax,77626e2eh
pop eax
jnz @F
invoke MessageBox,hwnd,addr szErr4,NULL,MB_OK or MB_ICONWARNING
jmp IF_F1
@@:
add eax,sizeof IMAGE_SECTION_HEADER
;******************
mov edi,eax ;edi指向文件头的尾部
add eax,sizeof IMAGE_SECTION_HEADER
sub eax,pMapping
cmp eax,[esi].OptionalHeader.SizeOfHeaders ;判断文件头是否可以再添加一个节表.
jna @F
invoke MessageBox,hwnd,addr szErr5,NULL,MB_OK or MB_ICONWARNING
jmp IF_F1
@@:
;***************************************** ;下面正式修改文件
inc [esi].FileHeader.NumberOfSections
assume edi:ptr IMAGE_SECTION_HEADER
mov dword ptr[edi],'wbn.' ;填写新的节表名称"nbw."
push VEnd-VStart
pop [edi].Misc.VirtualSize ;填写要添加的代码的长度
push [esi].OptionalHeader.SizeOfImage
pop [edi].VirtualAddress ;新节(注意不是节表)的地址
mov eax,[edi].Misc.VirtualSize
mov ecx,[esi].OptionalHeader.FileAlignment
div ecx
inc eax
mul ecx
mov [edi].SizeOfRawData,eax ;按文件粒度对齐
lea eax,[edi-28h+14h] ;上一个节的文件地址(OA)
mov eax,[eax]
lea ecx,[edi-28h+10h] ;上一个节的大小
add eax,[ecx]
mov [edi].PointerToRawData,eax ;填写新节的OA
mov [edi].Characteristics,0E0000020h ;可读可写可执行
;*****************************************
;更新文件头,使新节可以正确加载并首先执行
push _NewEntry-VStart ;使新的eop定位到newentry而不是VStart,这样做是因为新的代码部分定义了变量,
;我们要为这些代码预留出相应的空间
pop ecx
mov eax,[edi].VirtualAddress
add eax,ecx
push eax
pop [esi].OptionalHeader.AddressOfEntryPoint ;修改文件eop
mov eax,[edi].Misc.VirtualSize
mov ecx,[esi].OptionalHeader.SectionAlignment
div ecx
inc eax
mul ecx
add eax,[esi].OptionalHeader.SizeOfImage
mov [esi].OptionalHeader.SizeOfImage,eax
;********************************
;把新节的内容写到文件中
push FILE_BEGIN
push 0
push [edi].PointerToRawData
push hFile
call SetFilePointer
push 0
lea eax,ByteWrite
push eax
push [edi].SizeOfRawData
push offset VStart
push hFile
call WriteFile ;设置文件指针到结尾后,写入从VStart开始的代码,大小已经计算过了
push FILE_BEGIN
push 0
push [edi].PointerToRawData
push hFile
call SetFilePointer ;重新把文件指针指到新节的开始,把程序原来的入口地址写入新节中的return变量处
invoke WriteFile,hFile,addr HostEntry,4,addr ByteWrite,NULL
invoke WriteFile,hFile,addr _pass1,8,addr ByteWrite,NULL ;把8位密码写入文件中的password变量(看下面的变量定义)处
assume esi:nothing ;消对esi的定义.这里如果不写,编译器或许不出问题,但是当程序写大的时候,编译时候会发生意外难以查找的错误
;**********************************
invoke SetWindowText,hWinEdit,addr szz
IF_F1:
push pMapping
call UnmapViewOfFile
IF_F2:
push hMapping
call CloseHandle
IF_F3:
push hFile
call CloseHandle
IF_Exit:
popad
jmp _exit
;********************************************
;********************************************
;下面是添加到文件中的内容
_ProtoGetProcAddress typedef proto :dword,:dword
_ProtoLoadLibrary typedef proto :dword
_ProtoInitialize typedef proto :dword,:dword
_ApiGetProcAddress typedef ptr _ProtoGetProcAddress
_ApiLoadLibrary typedef ptr _ProtoLoadLibrary
_ApiInitialize typedef ptr _ProtoInitialize
VStart equ this byte
return dd 1 dup(?) ;保存原来的入口地址
password dd 9 dup(?)
_GetProcAddress _ApiGetProcAddress ? ;声明用到的函数
_LoadLibrary _ApiLoadLibrary ?
_Initialize _ApiInitialize ?
hDllCounter dd ?
_hModule dd ? ;模块基址
_lpszApi dd ? ;指向目的函数名
@dwReturn dd ? ;保存查找到的函数入口地址
@dwStringLength dd ? ;保存函数的长度
szLoadLibrary db 'LoadLibraryA',0
szGetProcAddress db 'GetProcAddress',0
szCounter db 'Counter',0
szInitialize db 'szInitialize',0
_NewEntry:
call @F
@@:
pop ebp
sub ebp,offset @B ;重定位,不用说了吧
;********获取Kernel32.dll的模块首地址
mov edi,[esp]
mov [ebp+@dwReturn],0
and edi,0ffff0000h
.while TRUE
.if word ptr [edi] == IMAGE_DOS_SIGNATURE
mov esi,edi
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -