📄 main.asm
字号:
add esi,[esi+003ch]
.if word ptr [esi] == IMAGE_NT_SIGNATURE
mov eax,edi
.break
.endif
.endif
_PageError:
sub edi,010000h
.break .if edi < 070000000h
.endw
;********eax指向Kernel32.dll的模块首地址
;********查找GetProcAddress的入口地址
mov [ebp+_hModule],eax
lea eax,[ebp+szGetProcAddress]
mov [ebp+_lpszApi],eax
mov eax,[ebp+_hModule]
pushad
mov [ebp+@dwReturn],0
;********计算函数名称的长度
mov edi,[ebp+_lpszApi]
mov ecx,-1
xor al,al
cld
repnz scasb
mov ecx,edi
sub ecx,[ebp+_lpszApi]
mov [ebp+@dwStringLength],ecx
;********计算函数名称的长度
mov esi,[ebp+_hModule]
add esi,[esi + 3ch]
assume esi:ptr IMAGE_NT_HEADERS
mov esi,[esi].OptionalHeader.DataDirectory.VirtualAddress
add esi,[ebp+_hModule]
assume esi:ptr IMAGE_EXPORT_DIRECTORY
mov ebx,[esi].AddressOfNames
add ebx,[ebp+_hModule]
xor edx,edx
.repeat
push esi
mov edi,[ebx]
add edi,[ebp+_hModule] ;这里edi指向的是Kernel32的到处表中的函数名,可以动态调试看一下,增强对导出表的认识
mov esi,[ebp+_lpszApi]
mov ecx,[ebp+@dwStringLength]
repz cmpsb ;比较[edi]和[esi]的字符串,长度是ecx
.if ZERO?
pop esi
jmp @F
.endif
pop esi
add ebx,4
inc edx
.until edx >= [esi].NumberOfNames
jmp _Error
@@:
sub ebx,[esi].AddressOfNames
sub ebx,[ebp+_hModule]
shr ebx,1
add ebx,[esi].AddressOfNameOrdinals
add ebx,[ebp+_hModule]
movzx eax,word ptr [ebx]
shl eax,2
add eax,[esi].AddressOfFunctions
add eax,[ebp+_hModule]
mov eax,[eax]
add eax,[ebp+_hModule]
mov [ebp+@dwReturn],eax ;保存GetProcAddress的入口地址
assume esi:nothing ;取消对esi的定义,很容易忽略
popad
mov eax,[ebp+@dwReturn]
;*******通过动态连接库的导出表查找函数的入口地址
_goon:
mov [ebp+_GetProcAddress],eax
lea eax,[ebp+szLoadLibrary] ;获取LoadLibrary入口
push eax
push [ebp+_hModule]
call [ebp+_GetProcAddress]
mov [ebp+_LoadLibrary],eax
lea eax,[ebp+szCounter] ;获取Counter.dll基址
invoke [ebp+_LoadLibrary],eax
mov [ebp+hDllCounter],eax
lea eax,[ebp+szInitialize] ;获取Initialize入口
invoke [ebp+_GetProcAddress],[ebp+hDllCounter],eax
mov [ebp+_Initialize],eax
invoke [ebp+_Initialize],[ebp+return],addr [ebp+password]
test eax,eax
jnz _Error
ret
_Error:
; jmp [ebp+return] ;返回程序原来的入口,return变量已经在前面被写入了.在程序中我没有采取这种方法,而是由counter.dll来执行这个命令.
ret
VEnd equ this byte
_exit:
ret
_ChangeFile endp
;****************************************************************
_Repair proc hwnd ;把被需要解锁的文件中的密码和oep去掉.
LOCAL hFile : DWORD
push eax
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
xor eax,eax
sub eax,0CH
invoke SetFilePointer,hFile,eax,NULL,FILE_END
invoke SetEndOfFile,hFile
push hFile
call CloseHandle
_exit:
pop eax
ret
_Repair endp
;****************************************************************
;下面是给加锁文件进行解锁
;文件打开部分完全照搬上面的函数.
_ReChangeFile 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 ;判断文件校验和
jnz IF_F1 ;合法性判断完毕,开始修改文件
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
jz @F
invoke MessageBox,hwnd,addr szErr6,NULL,MB_OK or MB_ICONWARNING
jmp IF_F1
@@:
;******************
mov edi,eax ;edi指向文件头的尾部
assume edi:ptr IMAGE_SECTION_HEADER
mov eax,[edi].Misc.VirtualSize
push eax ;保存节区大小
mov ecx,[esi].OptionalHeader.SectionAlignment
div ecx
inc eax
mul ecx
sub [esi].OptionalHeader.SizeOfImage,eax ;文件NT头修改
push FILE_BEGIN
push 0
push [edi].PointerToRawData
push hFile
call SetFilePointer ;重新把文件指针指到新节的开始,把程序原来的入口地址写入新节中的return变量处
invoke ReadFile,hFile,addr HostEntry,4,addr ByteWrite,NULL
invoke ReadFile,hFile,addr _pass1,8,addr ByteWrite,NULL ;读入密码
;这里2次读取数据导致最后无法把这2个部分切除.
;因此本过程后面调用_Repair函数来解决这个问题
invoke GetDlgItemText,hwnd,IDC_PASS1,addr _pass2,8
invoke lstrcmp, addr _pass1, addr _pass2 ;比较用户输入的解锁密码和文件中的密码是否一样.这里没有用到text2
.if eax != 0 ;两次密码如果不相同便进行处理
invoke MessageBox,hwnd,addr szErrCheck,NULL,MB_OK or MB_ICONWARNING
pop eax
jmp IF_F1
.endif
lea eax, HostEntry
mov eax,[eax]
mov ebx, [esi].OptionalHeader.ImageBase
sub eax,ebx
push eax
pop [esi].OptionalHeader.AddressOfEntryPoint ;修改文件eop完毕
dec [esi].FileHeader.NumberOfSections
xor eax,eax
mov dword ptr[edi],eax ;把原来的".nbw"节表名称去掉
mov [edi].Misc.VirtualSize,eax ;填写要添加的代码的长度
mov [edi].VirtualAddress,eax
mov [edi].SizeOfRawData,eax
mov [edi].PointerToRawData,eax
mov [edi].Characteristics,eax ;把.nbw节表的一些属性都去掉,一般来说这些东西不删除也不影响程序的正确性
;但是别人看到这里不是0可能以为这里是有用信息而影响其工作.
pop eax ;重新获取节区大小,请看上面的那个push eax
mov ecx,eax
sub eax,ecx
sub eax,ecx ;求eax的相反数
push FILE_END
push eax
push [edi].PointerToRawData
push hFile
call SetFilePointer ;重新把文件指针指到新节的开始,把程序原来的入口地址写入新节中的return变量处
;用getfilesize找到函数大小再减去解表一样可以定位到.nbw街区,但我感觉这样不用api函数效率更高些
invoke SetEndOfFile,hFile ;把.nbw节区截去
invoke SetWindowText,hWinEdit,addr szzz
;*****************************************
;更新文件头,使新节可以正确加载并首先执行
IF_F1:
assume edi:nothing
assume esi:nothing
push pMapping
call UnmapViewOfFile
IF_F2:
push hMapping
call CloseHandle
IF_F3:
push hFile
call CloseHandle
IF_Exit:
popad
_exit:
invoke _Repair,hwnd
ret
_ReChangeFile endp
;****************************************************************
;****************************************************************
_ProcDlgMain proc uses ebx edi esi hWnd,wMsg,wParam,lParam
mov eax,wMsg
.if eax == WM_CLOSE
invoke EndDialog,hWnd,NULL
.elseif eax == WM_INITDIALOG
push hWnd
pop hWinMain
call _Init
.elseif eax == WM_COMMAND
mov eax,wParam
.if ax == IDM_OPEN
invoke _OpenFileA,hWnd
.elseif ax == IDM_EXIT
invoke EndDialog,hWnd,NULL
.elseif ax== IDC_BROWSE
invoke _OpenFileA,hWnd
.elseif ax== IDC_UNCHAN
invoke _ReChangeFile,hWnd
.elseif ax== IDC_CHANGE
invoke GetDlgItemText,hWnd,IDC_PASS1,addr _pass1,32
invoke GetDlgItemText,hWnd,IDC_PASS2,addr _pass2,32
invoke lstrcmp, addr _pass1, addr _pass2
.if eax != 0 ;两次密码如果不相同便进行处理
invoke MessageBox,hWnd,addr szErrPass,NULL,MB_OK or MB_ICONWARNING
.else
invoke _ChangeFile,hWnd
.endif
.endif
.else
mov eax,FALSE
ret
.endif
mov eax,TRUE
ret
_ProcDlgMain endp
;********************************************************************
start:
assume fs:nothing ;挂接seh
push offset _Handler
push fs:[0]
mov fs:[0],esp
invoke LoadLibrary,offset szDllEdit
mov hRichEdit,eax
invoke GetModuleHandle,NULL
mov hInstance,eax
invoke DialogBoxParam,hInstance,DLG_MAIN,NULL,offset _ProcDlgMain,NULL
invoke FreeLibrary,hRichEdit
jmp _Nexi
_SafePlace:
invoke MessageBox,NULL,addr _SehM,addr _SehT,MB_OK
pop fs:[0] ; 恢复原来的 SEH 链
pop eax
_Nexi:
invoke ExitProcess,NULL
;********************************************************************
end start
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -