你好,欢迎来到电脑编程技巧与维护杂志社! 杂志社简介广告服务读者反馈编程社区  
合订本订阅
 
 
您的位置:杂志经典 / 计算机安全与维护
6.17 用Win32汇编语言对PE格式的EXE文件进行口令加密(上)
 

一般程序员开发的软件并不希望别人随便使用,为了防止别人的非法使用,一般是通过加密的方法对软件进行保护,口令加密只是加密方式中的一种。虽然加密的方法对解密高手而言,并不能百分之百的保护,但对一般的使用者来说,加密保护软件的方法,仍是有效的。
Win32环境下PE格式的文件形式有EXE、DLL、OCX、SCR等,其中常用的可执行文件是EXE文件,对PE格式的EXE文件进行口令加密,就是在目标EXE文件上附加一段代码,通过附加代码中的对话框获取口令,并与附加代码里留存的口令进行比较,当口令一致时,表示用户是合法的,否则是非法用户。
本口令加密软件分为三个模块。模块1的功能是生成对话框,选择目标文件,输入口令及校核口令的正确性;模块2的功能是判断目标文件是否是PE格式的EXE文件,是否已口令加密,留存口令,修改目标文件头里的有关结构中的相关字段,并把加密代码附在目标文件上;模块3的功能是重定位,搜索加密代码中所要用到的API函数的地址,以便使用这些API函数生成对话框,并由对话框接收口令,校核口令的正确性,口令正确运行目标文件,口令错误则退出。由于模块1较简单,本文主要说明模块2和模块3的功能与作用。
一、在目标文件上附加口令加密代码
在对PE格式的EXE文件上附加代码的的方法常用的有三种方法。第一种方法是将附加代码插入在目标文件的代码节或其他节(如数据节)的空隙中,一般文件中节对齐在文件中的最大长度是512B(200H),如ML汇编器生成的文件默认文件对齐参数为512B,而代码至少要占用1B,所以最大空隙长度不超过511B。但也有一部分文件,如VC++编译器生成的文件其默认文件中节对齐的最大长度为4KB(1000H),因此,即使是加密代码较长,只要小于4KB,也完全可以插入其节中空隙。第二种方法是将附加代码分段插入文件中的不同节的空隙中,这种方法的优点是不会增加文件的长度,CIH病毒就是采用此法,但要求文件头部有足够的空隙来构建节表等。第三种方法是把附加代码附在目标文件的尾部,构成一个新代码节,这种方法的优点是附加代码的长度不受限制,但文件的长度会增加,另外,要求文件头有一定的空隙来构建节表。本文采用第一种和第三种方法,目的是提高加密的成功率。
要对PE文件进行口令加密,首先要对PE文件的结构有所了解,下图就是PE文件的基本结构,从这个PE文件的结构中,可以看到PE文件是由DOS头、PE文件头、节表和节等组成,每一个节表对应一个节,节表的排列顺序,也就是节的排列顺序。PE装载器就是根据PE文件头结构和节表结构中的相应字段将有关的节装入内存中,当然有些节如重定位节(.reloc节)是不必装入内存的。将加密代码附在目标PE文件后面,就是将加密代码做成一个代码节附在PE文件的后面,为了使PE装载器正确地加载附加的加密代码节,必须构建一个新节表使其指向加密代码节,而新添加的节表须位于原PE文件节表的末尾,这就要求文件头中的空隙要≥40B(因为节表结构的长度为28H),满足这个条件才能建立一个新的节表。而将加密代码插入节的空隙中,不用构建新节表。


                                   图 PE文件的基本结构


在口令加密中我们要用到文件头中的以下结构及相应字段:
1.DOS头结构
IMAGE_DOS_HEADER  STRUCT
……
e_magic   WORD  ?                      ;DOS头标志,“MZ”
e_lfanew  DWORD  ?                     ;指向PE文件头(或文件头偏移003ch)
      ……
IMAGE_DOS_HEADER  ENDS
2.PE文件头(NT映像头)结构
IMAGE_NT_HEADERS   STRUCT
Signature   DWORD   ?                    ;PE文件头标志,“PE00”
FileHeader  IMAGE_FILE_HEADER < >
OptionalHeader  IMAGE_OPTIONAL_HEADER32 < >
IMAGE_NT_HEADERS   ENDS
3.映像文件头(FileHeader)结构
IMAGE_FILE_HEADER  STRUCT
……
NumberOfSections  WORD  ?                ;节表(节)的数量
……
IMAGE_FILE_HEADER  ENDS
4.可选映像头(OptionalHeader)结构
IMAGE_OPTIONAL_HEADER32  STRUCT
……
SizeOfCode           DWORD  ?    ;所有含代码的节的总长度
AddressOfEntryPoint   DWORD   ?            ;程序开始执行的入口地址RVA
SectionAlignment      DWORD   ?            ;内存中节对齐的粒度
FileAlignment    DWORD   ?            ;文件中节对齐的粒度
SizeOfImage          DWORD   ?            ;内存中整个PE文件映像的大小
SizeOfHeaders         DWORD   ?            ;DOS头+PE文件头+节表的大小
DataDirectory  IMAGE_DATA_DIRECTORY 16 dup(<>)     ;数据目录结构数组
……
IMAGE_OPTIONAL_HEADER32  ENDS
5.节表结构
IMAGE_SECTION_HEADER  STRUCT
Name1  db  IMAGE_SIZEOF_SHORT_NAME  dup(?)   ;节的名称,长度8字节
union Misc
……
VirtualSize         dd  ?      ;节的实际大小
ends
VirtualAddress      dd  ?      ;节装入内存后的偏移地址RVA
SizeOfRawData     dd  ?      ;节在文件中按FileAlignment对齐后的大小
PointerToRawData   dd  ?      ;节在文件中的偏移地址
Characteristics      dd  ?      ;节的属性
IMAGE_SECTION_HEADER  ENDS
    本口令加密算法采用将代码插入节中优先,这样可保证文件的长度不变;当节空隙不够时,再采用构建一新代码节。在目标PE文件中附加口令加密代码的主要过程如下:
(1)判断是否是PE格式的EXE文件,不是则退出;
(1)判断该PE格式EXE文件是否已加密,加密标志设为“zz”,已加密则退出;
(3)循环检查节的空隙是否足够,如空隙足够则将加密代码插入对应节空隙中,修改对应节表中的相应字段VirtualSize、Characteristics,修改文件的入口地址AddressOfEntryPoint,指向加密代码的开始执行点,将修改后的文件头写入目标PE文件的头部,将返回地址和口令写入加密代码中,加密完成后退出。
(4)当节的空隙不够时,判断文件头是否有足够的空隙容纳新的节表(节表长度28H),不足退出,放弃口令加密;
(5)有新的节表空隙,修改NT映像头中的相关字段;
由于新建了一个节(节表),所以要节数+1,即NumberOfSections+1,并修改SizeOfCode 和SizeOfImage;另外,要修改文件的入口地址AddressOfEntryPoint,使其指向加密代码的开始执行点;
(6)在文件头中的空隙处建立一新节表,并为新节表的相关字段赋值,使其指向新建的加密代码节;
有Name1、VirtualSize、VirtualAddress、SizeOfRawData、PointerToRawData、Characteristics。
其中新代码节的VirtualAddress=末节的VirtualAddress+末节的VirtualSize并按SectionAlignment对齐,新代码节的SizeOfRawData=加密代码的长度按FileAlignment对齐,新代码节的PointerToRawData=末节的PointerToRawData+末节的SizeOfRawData;
(7)将修改后的文件头写入目标PE文件的头部;
(8)将口令加密代码作为一新建代码节附加在目标PE文件的尾部;
(9)将返回地址写入加密代码中;
(10)将口令写入加密代码中。
下面是附加口令加密代码的主要过程源程序,为了方便阅读加了必要的注释;另一点要注意的是PE文件的头部在磁盘文件里和在内存映射中是完全一致的,所以我们另外申请了一内存块把它装在内存中来修改又快又方便,然后将其重新写入目标文件的头部来完成对文件头的修改,实现代码如下:
handlePeFile    proc   
  ;定义过程所要用的局部变量
        local @hFile,@hMapFile,@lpMemory,@lpAlloc,@dwRet,@SizeOfHeader
        local @dwEntry,@dwPE_Header_off,@FileAlign,@SectionAlign,@SectionNum
        local @NewSection_off,@AppCodeSize,@AddCodeVirt,@AddCodeFile   
        pushad
 ;创建处理异常的SHE结构
        assume  fs:nothing
  push ebp
  push offset _ErrFormat
  push offset _Handler
  push fs:[0]
  mov fs:[0],esp
;取目标PE文件的扩展名,判断是否是.exe
invoke  lstrlen,addr szFileName
lea ecx,szFileName
mov edx,dword ptr [ecx+eax-4]
or  edx,20202020h    ;将大写字符转换为小写
.if edx != 'exe.'     ;不是.exe则退出
    invoke MessageBox,NULL,addr szTexttip,addr szCaptionTip,MB_OK
    jmp _Ret
.endif
;以可读、可写方式打开已存在的目标PE文件,如打开只读文件或不存在的文件会报错
invoke CreateFile,addr szFileName,GENERIC_READ or GENERIC_WRITE,FILE_SHARE_READ or \
   FILE_SHARE_WRITE,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_ARCHIVE,NULL
.if eax != INVALID_HANDLE_VALUE
 mov @hFile,eax
   ;创建内存映射对象
      invoke CreateFileMapping,@hFile,NULL,PAGE_READWRITE,0,0,NULL
    .if eax
   mov @hMapFile,eax
   ;创建内存映射文件
   invoke MapViewOfFile,eax,FILE_MAP_READ or FILE_MAP_WRITE,0,0,0
            .if eax
   mov @lpMemory,eax
            mov ebx,eax
            assume ebx :ptr IMAGE_DOS_HEADER
            .if word ptr [ebx] !="ZM"          ;判断DOS头标记,‘MZ’
            invoke MessageBox,NULL,addr szError,addr szCaptionTip,MB_OK
            jmp _ErrFormat       ;不是PE格式文件,退出
            .endif
            mov eax,[ebx].e_lfanew
            mov @dwPE_Header_off,eax
            add ebx,[ebx].e_lfanew             ;ebx-->指向PE文件头
            assume ebx :ptr IMAGE_NT_HEADERS
            .if word ptr [ebx]!='EP'   ;判断PE文件头标记,‘PE’
            invoke MessageBox,NULL,addr szError,addr szCaptionTip,MB_OK
            jmp _ErrFormat      ; 不是PE格式文件,退出
            .endif
   ;‘zz’已加密标志,判断是否已加密,用于防止重复加密
            .if word ptr [ebx+1ah] == 'zz'  
            invoke MessageBox,NULL,addr szCodeText,addr szCaptionTip,MB_OK
            jmp _ErrFormat      ;已加密退出
            .endif
            push [ebx].OptionalHeader.FileAlignment ;将后面要用的参数赋给局部变量
            pop @FileAlign
            push [ebx].OptionalHeader.SectionAlignment
            pop @SectionAlign
            push [ebx].OptionalHeader.SizeOfHeaders
            pop @SizeOfHeader
            push [ebx].OptionalHeader.AddressOfEntryPoint
      pop  @dwEntry
            movzx eax,[ebx].FileHeader.NumberOfSections
            dec eax
            mov @SectionNum,eax
            mov ecx,sizeof IMAGE_SECTION_HEADER
            mul ecx
            add eax,@dwPE_Header_off
            add eax,sizeof IMAGE_NT_HEADERS
            add eax,sizeof IMAGE_SECTION_HEADER
            mov @NewSection_off,eax
   ;申请一块内存,长度为SizeOfHeaders,用于文件头的修改
            invoke GlobalAlloc,GPTR,[ebx].OptionalHeader.SizeOfHeaders
      mov @lpAlloc,eax
      mov edi,eax
;将打开的内存映射文件的头部,长度为SizeOfHeaders,传送到申请的内存块里
      invoke RtlMoveMemory,edi,@lpMemory,[ebx].OptionalHeader.SizeOfHeaders
            invoke UnmapViewOfFile,@lpMemory   ;关闭内存映射文件,后面不用了。
            invoke CloseHandle,@hMapFile    ;关闭内存映射对象,后面不用了。
            add edi,dword ptr [edi+3ch]           ;edi-->指向PE文件头
            assume edi :ptr IMAGE_NT_HEADERS
            mov esi,edi                          
            add esi,sizeof IMAGE_NT_HEADERS
            assume esi :ptr IMAGE_SECTION_HEADER
      mov ecx,offset APPEND_CODE_END-offset APPEND_CODE
            push ecx
            pop @AppCodeSize ;加密代码的长度
            xor ebx,ebx
   ;循环检查每个节中是否有足够的空隙来插入代码
            .repeat   
            mov edx,[esi].SizeOfRawData
            .if !edx ;判断SizeOfRawData是否为0,为0表示该节是未初始化数据的节,跳过
            inc ebx
            add esi,sizeof IMAGE_SECTION_HEADER
            .continue
            .endif
            sub edx,[esi].Misc.VirtualSize 
   ;如果[esi].SizeOfRawData <[esi].Misc.VirtualSize,则CF=1,跳过。
            .if CARRY?
            inc ebx
            add esi,sizeof IMAGE_SECTION_HEADER
            .continue
            .endif
            .if edx >= ecx ;节中空隙足够,则将加密代码插入节的空隙中。
            jmp insert_code
            .endif
            add esi,sizeof IMAGE_SECTION_HEADER
            inc ebx
            .until ebx > @SectionNum
            ;当各节空隙都不够插入加密代码时,添加新节(表)。
            mov edi,@lpAlloc
            mov ebx,edi
            add ebx,@NewSection_off  ;ebx--->指向最后一个节表的尾部(新节表的头部)。
            pushad
   ;检查文件头是否有足够空隙构建新节表
            mov edi,ebx
            mov al,0
            mov ecx,sizeof IMAGE_SECTION_HEADER
            cld
            repe scasb
            popad
            .if !ZERO?
            invoke MessageBox,NULL,addr szNoRoom,addr szCaptionTip,MB_OK
            invoke GlobalFree,@lpAlloc
            jmp _NoRoomRet  ;文件头没有足够空隙构建节表,退出口令加密。
            .endif
            mov edx,ebx                          
            sub edx,sizeof IMAGE_SECTION_HEADER   ;edx--->指向最后一个节表的头部。
            assume ebx :ptr IMAGE_SECTION_HEADER,edx :ptr IMAGE_SECTION_HEADER
            add edi,dword ptr [edi+3ch]           ;edi--->指向PE文件头
            assume edi :ptr IMAGE_NT_HEADERS
            inc [edi].FileHeader.NumberOfSections ;节数+1
          mov eax,[edx].PointerToRawData   
   add eax,[edx].SizeOfRawData
   mov [ebx].PointerToRawData,eax   ;新节在文件中的偏移
   mov ecx,offset APPEND_CODE_END-offset APPEND_CODE
            mov [ebx].Misc.VirtualSize,ecx   ;新节的实际大小
          invoke _Align,ecx,@FileAlign   
   mov [ebx].SizeOfRawData,eax    ;新节按FileAlignment对齐后的大小
          invoke _Align,ecx,@SectionAlign   ;新节按SectionAlignment对齐后的大小
   add [edi].OptionalHeader.SizeOfCode,eax   ;修正SizeOfCode
   add [edi].OptionalHeader.SizeOfImage,eax  ;修正SizeOfImage
   invoke _Align,[edx].Misc.VirtualSize,@SectionAlign
   add eax,[edx].VirtualAddress
   mov [ebx].VirtualAddress,eax   ;新节在内存中的偏移地址RVA
   ;新节的属性设置为可读、可写、可执行含有代码
   mov [ebx].Characteristics,0e0000020h 
            mov dword ptr [ebx+0h],'czz.'   ;新节名Name1命名为’.zzcode’
            mov dword ptr [ebx+4h],' edo'
            mov word ptr [edi+1ah],"zz"    ;设置加密标志为"zz"
          invoke SetFilePointer,@hFile,[ebx].PointerToRawData,NULL,FILE_BEGIN
   ;将口令加密代码作为一个新节,附加在文件的尾部
   invoke WriteFile,@hFile,offset APPEND_CODE,[ebx].Misc.VirtualSize,\
    addr @dwRet,NULL
   mov eax,[ebx].PointerToRawData
   add eax,[ebx].SizeOfRawData
   invoke SetFilePointer,@hFile,eax,NULL,FILE_BEGIN
   invoke SetEndOfFile,@hFile   ;将目标PE文件的长度扩展到加密后的长度
            push [ebx].VirtualAddress
            pop  @AddCodeVirt
            push [ebx].PointerToRawData
            pop  @AddCodeFile
            jmp append_code
   ;以下程序段将加密代码插入节的空隙中
   ;将节的属性设置为可读、可写、可执行含有代码
insert_code: or  [esi].Characteristics,IMAGE_SCN_MEM_READ or IMAGE_SCN_MEM_WRITE\
                      or IMAGE_SCN_MEM_EXECUTE or IMAGE_SCN_CNT_CODE
            mov ebx,[esi].PointerToRawData
            add ebx,[esi].Misc.VirtualSize
            invoke SetFilePointer,@hFile,ebx,NULL,FILE_BEGIN
   ;将加密代码插入节的空隙中
   invoke WriteFile,@hFile,offset APPEND_CODE,@AppCodeSize,\
    addr @dwRet,NULL
      mov eax,[esi].VirtualAddress
            add eax,[esi].Misc.VirtualSize
            mov @AddCodeVirt,eax
            mov ecx,[esi].PointerToRawData
            add ecx,[esi].Misc.VirtualSize
            mov @AddCodeFile,ecx
            mov eax,@AppCodeSize
            add [esi].Misc.VirtualSize,eax  ;修改节的实际大小
            mov word ptr [edi+1ah],"zz"   ;设置加密标志为"zz"
   ;以下是二种附加加密代码的公用程序部分,这样设计是为了减小程序的长度
   ;修改目标PE文件的入口地址,使其指向口令加密代码的开始执行处
append_code:  mov eax,@AddCodeVirt
      add eax,(offset _NewEntry-offset APPEND_CODE)
      mov [edi].OptionalHeader.AddressOfEntryPoint,eax
       invoke SetFilePointer,@hFile,0,NULL,FILE_BEGIN
   ;将修改后的文件头写入目标PE文件的头部
      invoke WriteFile,@hFile,@lpAlloc,@SizeOfHeader,\
   addr @dwRet,NULL
            mov eax,@AddCodeVirt
      add eax,(offset RetOldEntry-offset APPEND_CODE+4)
      sub @dwEntry,eax  ;@dwEntry—加密代码执行完后,返回原程序执行的地址
            mov ecx,@AddCodeFile
      add ecx,(offset RetOldEntry-offset APPEND_CODE)
      invoke SetFilePointer,@hFile,ecx,NULL,FILE_BEGIN
   ;将返回地址写在加密代码中0e9h(jmp机器码)的后面
      invoke WriteFile,@hFile,addr @dwEntry,4,addr @dwRet,NULL
            mov ecx,@AddCodeFile
      add ecx,(offset APPEND_PASSWD_CODE-offset APPEND_CODE)
      invoke SetFilePointer,@hFile,ecx,NULL,FILE_BEGIN
   ;将校核后的口令(最大长度为30个字符),写入附加的加密代码留存口令处
      invoke WriteFile,@hFile,offset szPwdBuffer2,30,addr @dwRet,NULL
      invoke GlobalFree,@lpAlloc  ;关闭申请的内存块
      invoke CloseHandle,@hFile  ;关闭打开的目标文件
            assume edi : nothing,esi : nothing
            invoke MessageBox,NULL,addr szOkCode,addr szCaptionTip,MB_OK
            jmp _Ret
_ErrFormat:
              assume ebx : nothing
              invoke UnmapViewOfFile,@lpMemory  ;关闭内存映射文件
              .endif
              invoke CloseHandle,@hMapFile   ;关闭内存映射对象
          .endif
_NoRoomRet:   invoke CloseHandle,@hFile    ;关闭打开的目标PE文件
.else
    invoke MessageBox,NULL,addr szErrCreate,addr szCaptionTip,MB_OK
.endif
_Ret:
        pop fs:[0]
        add esp,0ch        
        popad
        ret
handlePeFile    endp
二、口令加密的主要功能
1.重定位
   由于加密代码是在编译、连接之后附加在目标PE文件的尾部或节的空隙中,而各个目标文件的长度又是可变的,导致附加代码中的变量或过程名偏移地址在装入内存后发生变化,使之在目标文件中运行时寻址错误,为了使附加代码中的变量地址正确,必须进行重定位。其重定位的标准格式如下:
call @F
@@:
pop  ebx        ;这个寄存器不一定非用ebx,也可使用其他不常用的寄存器
sub  ebx,offset @B
2.动态获取API函数地址
由于加密代码是附在各种目标文件的尾部或节的空隙中,所需要的API函数地址,各个目标PE文件不可能为你准备好,因此,加密代码必须自己想法解决。这就是要用LoadLibrary函数来动态装入某个DLL模块,然后再用GetProcAddress函数从装入的DLL模块中获取所需要的API函数的入口地址。但是这二个函数都位于Kernel32.dll中,注意到当Kernel32.dll把目标程序装入内存后,堆栈的顶部存放有程序的返回地址,而这个返回地址正好位于Kernel32.dll中;因此,加密代码一开始执行,就从堆栈中取出该地址[esp](如果程序一开始就压栈后再取出返回地址,那应是此形式[esp+xxxx]),搜索Kernel32.dll的基地址,然后再搜索GetProcAddress的入口地址,获得GetProcAddress的入口地址后,再调用GetProcAddress函数获取LoadLibrary函数的入口地址,有了这二个函数后加密代码所需要的API就可以轻松获得。
3.在加密代码中生成对话框
   对于普通的对话框程序来说生成对话框较简单,只要在Link的时候把程序的目标文件.obj和资源文件.res连接起来就可实现。而对于加密代码而言,生成对话框就不那么简单了,不单是需要API函数,而且还需要资源文件,对话框能否实现是口令加密的关键问题也是最难的问题,因为加密代码需要用对话框来接收输入的口令。当然用命令行输入口令也可以。好在Win32汇编提供了对话框模板结构,使我们的问题得以解决。无论是模态对话框还是非模态对话框,其建立的过程都会用到模板,而模板就是具有相对固定格式的内存块,其中的数据用以建立对话框的资源和控件,如菜单、子窗口控件、标题栏等,专供代码调用。
对话框模板主要由二部分组成:模板头和模板控件。
(1)模板头
模板头定义对话框的大小、样式、菜单、CLASS、标题名称等。模板头开始的结构如下:
DLGTEMPLATE  STRUCT
style   DWORD ?   ;对话框样式,如WS_CAPTION、WS_SYSMENU等
dwExtendedStyle DWORD ?   ;扩展样式,对话框不使用
cdit   WORD ?   ;对话框中控件的数目
x    WORD ?
y    WORD ?   ;x、y对话框的屏幕坐标
lx    WORD ?
ly    WORD ? ;lx、ly对话框的宽和高
DLGTEMPLATE  ENDS
紧跟DLGTEMPLATE结构后面的是菜单、CLASS和对话框标题等组成的三种可变数组。
菜单数组:数组元素都是字,数组边界须字对齐。若数组第一个元素为0,则该对话框不带菜单,并且数组只有一个元素;若数组第一个元素为0ffffh,则第二个元素为菜单资源的序数值,接着就是Unicode字符集的菜单资源的字符串名。
CLASS数组:数组元素都是字,数组边界须字对齐。若数组的第一个元素为0,则为标准控件或通用控件类,并且数组只有一个元素;若数组第一个元素为0ffffh,则第二个元素为系统预定义窗口类的序数值,接着是Unicode字符集的窗口类的字符串名。
标题数组:紧跟在CLASS数组后的是Unicode字符集的标题栏名(以0结束),如果都是0则对话框无标题栏。注意,如果对话框指定了样式为DS_SETFONT,则紧跟在标题栏后的字指定字体的点阵大小,后面跟着Unicode字符集的字体名字符串。
(2)模板控件
模板控件定义控件的大小、样式、CLASS、控件标题、成形数据等。模板控件的开始结构如下:
DLGITEMTEMPLATE  STRUCT
style   DWORD ?       ;控件样式
dwExtendedStyle DWORD ?
x    WORD ?
y    WORD ?  ;x、y控件在对话框上的坐标
lx    WORD ?
cy    WORD ?       ;lx、cy控件的宽和高
id    WORD ?  ;控件标识符ID
DLGITEMTEMPLATE  ENDS
紧跟DLGITEMTEMPLATE结构之后的是CLASS、控件标题、成形数据等组成的三种可变数组,数组元素都是字。对话框有多少控件就应有多少个DLGITEMTEMPLATE结构,每个结构的起始地址必须是双字对齐,而每种数组边界必须字对齐。
CLASS数组:若数组第一个元素是0ffffh,则第二个元素是系统预定义的序数值(0080h/Button类、0081h/Edit类、0082h/Static类等);否则,其后是Unicode字符集的窗口类的字符串名。
标题数组:若数组第一个元素为0ffffh,则第二个元素为控件的资源标识。否则,则是Unicode字符集的标题字符串名。
成形数据数组:若数组的第一个元素不为0,则是指定该成形数据的大小。
实现口令加密的核心代码如下:
;加密代码所用的函数及函数指针定义
;定义函数和函数指针是为了用伪指令invoke来调用函数
_ProtoGetProcAddress typedef proto :dword,:dword
_ProtoLoadLibrary typedef proto :dword
_ProtoMessageBox typedef proto :dword,:dword,:dword,:dword
_ApiGetProcAddress typedef ptr _ProtoGetProcAddress
_ApiLoadLibrary  typedef ptr _ProtoLoadLibrary
_ApiMessageBox  typedef ptr _ProtoMessageBox
;对话框所用函数的定义及函数指针的定义
_ProtoGetModuleHandle   typedef proto :dword
_protoGlobalAlloc       typedef proto :dword,:dword
_ProtoMultiByteToWideChar   typedef proto :dword,:dword,:dword,:dword,:dword,:dword
_ProtoDialogBoxIndirectParam    typedef proto :dword,:dword,:dword,:dword,:dword
_ProtoGlobalFree        typedef proto :dword
_ProtoEndDialog         typedef proto :dword,:dword
_ProtoGetDlgItemText    typedef proto :dword,:dword,:dword,:dword
_ProtoSetWindowText     typedef proto :dword,:dword
_ProtoSendDlgItemMessage    typedef proto :dword,:dword,:dword,:dword,:dword
_ApiGetModuleHandle typedef ptr _ProtoGetModuleHandle  
_ApiGlobalAlloc typedef ptr _protoGlobalAlloc      
_ApiMultiByteToWideChar typedef ptr _ProtoMultiByteToWideChar
_ApiDialogBoxIndirectParam typedef ptr _ProtoDialogBoxIndirectParam
_ApiGlobalFree typedef ptr _ProtoGlobalFree       
_ApiEndDialog typedef ptr _ProtoEndDialog        
_ApiGetDlgItemText typedef ptr _ProtoGetDlgItemText   
_ApiSetWindowText typedef ptr _ProtoSetWindowText    
_ApiSendDlgItemMessage typedef ptr _ProtoSendDlgItemMessage
;附加到目标PE文件上的口令加密代码从这里开始
APPEND_CODE equ this byte
include  zz_GetKernel.asm
hDllKernel32 dd ?
hDllUser32 dd ?
_GetProcAddress _ApiGetProcAddress ?
_LoadLibrary _ApiLoadLibrary  ?
_MessageBox _ApiMessageBox  ?
szLoadLibrary db 'LoadLibraryA',0
szGetProcAddress db 'Get

  推荐精品文章

·2024年9月目录 
·2024年8月目录 
·2024年7月目录 
·2024年6月目录 
·2024年5月目录 
·2024年4月目录 
·2024年3月目录 
·2024年2月目录 
·2024年1月目录
·2023年12月目录
·2023年11月目录
·2023年10月目录
·2023年9月目录 
·2023年8月目录 

  联系方式
TEL:010-82561037
Fax: 010-82561614
QQ: 100164630
Mail:gaojian@comprg.com.cn

  友情链接
 
Copyright 2001-2010, www.comprg.com.cn, All Rights Reserved
京ICP备14022230号-1,电话/传真:010-82561037 82561614 ,Mail:gaojian@comprg.com.cn
地址:北京市海淀区远大路20号宝蓝大厦E座704,邮编:100089