第一个基础的HelloWorld
.386
.model flat,stdcall
option casemap:none
include windows.inc
include user32.inc
includelib user32.lib
include kernel32.inc
includelib kernel32.lib
.data
szText db 'HelloWorld',0
.code
start:
invoke MessageBox,NULL,offset szText,NULL,MB_OK
invoke ExitProcess,NULL
end start
调试观察栈的变化
.386
.model flat,stdcall
option casemap:none
include windows.inc
include user32.inc
includelib user32.lib
include kernel32.inc
includelib kernel32.lib
.code
_add proc a:word,b:word
local @bl1:dword
ret
_add endp
start:
push 1
push 2
call _add
add eax,1
end start
第二章的几个小工具
太长太长了,而且书中代码有一些过时的部分,所以也就跟着敲了一部分。
pe.rc
#include <resource.h>
#define ICO_MAIN 1000
#define DLG_MAIN 1000
#define IDC_INFO 1001
#define IDM_MAIN 2000
#define IDM_OPEN 2001
#define IDM_EXIT 2002
#define IDM_1 4000
#define IDM_2 4001
#define IDM_3 4002
#define IDM_4 4003
ICO_MAIN ICON "saz.ico"
ICO_MAIN DIALOG 50,50,544,399
STYLE DS_MODALFRAME | WS_POPUP |WS_VISIBLE |WS_CAPTION| WS_SYSMENU
CAPTION "JIBEN XINXI"
MENU IDM_MAIN
FONT 9,"宋体"
BEGIN
CONTROL "",IDC_INFO,"RichEdit20A",196|ES_WANTRETURN|WS_CHILD
|WS_VISIBLE|WS_BORDER |WS_VSCROLL|WS_TABSTOP,0,0,540,396
END
IDM_MAIN menu discardable
BEGIN
POPUP "file(&F)"
BEGIN
menuitem "openFile(&O)",IDM_OPEN
menuitem separator
menuitem "quit(&X)",IDM_EXIT
END
POPUP "LOOK"
BEGIN
menuitem "oriFile",IDM_1
menuitem "touming",IDM_2
menuitem separator
menuitem "size",IDM_3
menuitem "width",IDM_4
END
END
pe.asm
.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
IDM_1 EQU 4000
IDM_2 EQU 4001
IDM_3 EQU 4002
.data
hInstance dd ?
hRichEdit dd ?
hWinMain dd ?
hWinEdit dd ?
szFileName db MAX_PATH dup(?)
.const
szDllEdit db 'RichEd20.dll',0
szClassEdit db 'RichEdit20A',0
szFont db '宋体',0
.code
_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 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
_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 eax==IDM_EXIT
invoke EndDialog,hWnd,NULL
.elseif eax==IDM_OPEN
.elseif eax==IDM_1
.elseif eax==IDM_2
.elseif eax==IDM_3
.endif
.else
mov eax,FALSE
ret
.endif
mov eax,TRUE
ret
_ProcDlgMain endp
start:
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
invoke ExitProcess,NULL
end start
导入表值导入多个user32的函数,稍微修改了一下,按照原文禁止窗口就不好玩了。
.386
.model flat,stdcall
option casemap:none
include windows.inc
include user32.inc
includelib user32.lib
include kernel32.inc
includelib kernel32.lib
.data
sz1 db 'Shell_TrayWnd',0
hTray dd ?
.code
start:
invoke FindWindow,addr sz1,0
mov hTray,eax
invoke ShowWindow,hTray,SW_SHOW
invoke EnableWindow,hTray,TRUE
invoke ExitProcess,NULL
end start
汇编写第一个窗口,可以作为模板使用。
.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
.data?
hInstance dd ?
hWinMain dd ?
.const
szClassName db 'MyClass',0
szCaptionMain db 'My First Window!',0
szText db 'Win32 Assembly,Simple and powerful!',0
.code
_ProcWinMain proc uses ebx edi esi,hWnd,uMsg,wParam,lParam
local @stPs:PAINTSTRUCT
local @stRect:RECT
local @hDc
mov eax,uMsg
.if eax == WM_PAINT
invoke BeginPaint,hWnd,addr @stPs
mov @hDc,eax
invoke GetClientRect,hWnd,addr @stRect
invoke DrawText,@hDc,addr szText,-1,addr @stRect,\
DT_SINGLELINE or DT_CENTER or DT_VCENTER
invoke EndPaint,hWnd,addr @stPs
.elseif eax == WM_CLOSE
invoke DestroyWindow,hWinMain
invoke PostQuitMessage,NULL
.else
invoke DefWindowProc,hWnd,uMsg,wParam,lParam
ret
.endif
xor eax,eax
ret
_ProcWinMain endp
_WinMain proc
local @stWndClass:WNDCLASSEX
local @stMsg:MSG
invoke GetModuleHandle,NULL
mov hInstance,eax
invoke RtlZeroMemory,addr @stWndClass,sizeof @stWndClass
invoke LoadCursor,0,IDC_ARROW
mov @stWndClass.hCursor,eax
push hInstance
pop @stWndClass.hInstance
mov @stWndClass.cbSize,sizeof WNDCLASSEX
mov @stWndClass.style,CS_HREDRAW or CS_VREDRAW
mov @stWndClass.lpfnWndProc,offset _ProcWinMain
mov @stWndClass.hbrBackground,COLOR_WINDOW + 1
mov @stWndClass.lpszClassName,offset szClassName
invoke RegisterClassEx,addr @stWndClass
invoke CreateWindowEx,WS_EX_CLIENTEDGE,\
offset szClassName,offset szCaptionMain,\
WS_OVERLAPPEDWINDOW,\
100,100,600,400,\
NULL,NULL,hInstance,NULL
mov hWinMain,eax
invoke ShowWindow,hWinMain,SW_SHOWNORMAL
invoke UpdateWindow,hWinMain
.while TRUE
invoke GetMessage,addr @stMsg,NULL,0,0
.break .if eax == 0
invoke TranslateMessage,addr @stMsg
invoke DispatchMessage,addr @stMsg
.endw
ret
_WinMain endp
start:
call _WinMain
invoke ExitProcess,NULL
end start
第6章无导入表的helloworld
.386
.model flat,stdcall
option casemap:none
include windows.inc
_QLGetProcAddress typedef proto :dword,:dword
_ApiGetProcAddress typedef ptr _QLGetProcAddress
_QLLoadLib typedef proto :dword
_ApiLoadLib typedef ptr _QLLoadLib
_QLMessageBoxA typedef proto :dword,:dword,:dword,:dword
_ApiMessageBoxA typedef ptr _QLMessageBoxA
.code
szText db 'HelloWorldPE',0
szGetProcAddr db 'GetProcAddress',0
szLoadLib db 'LoadLibraryA',0
szMessageBox db 'MessageBoxA',0
user32_DLL db 'user32.dll',0,0
_getProcAddress _ApiGetProcAddress ?
_loadLibrary _ApiLoadLib ?
_messageBox _ApiMessageBoxA ?
hKernel32Base dd ?
hUser32Base dd ?
lpGetProcAddr dd ?
lpLoadLib dd ?
_getKernelBase proc _dwKernelRetAddress
local @dwRet
pushad
mov @dwRet,0
mov edi,_dwKernelRetAddress
and edi,0ffff0000h
.repeat
.if word ptr [edi] == IMAGE_DOS_SIGNATURE
mov esi,edi
add esi,[esi+003ch]
.if word ptr [esi] == IMAGE_NT_SIGNATURE
mov @dwRet,edi
.break
.endif
.endif
sub edi,010000h
.break .if edi<070000000h
.until FALSE
popad
mov eax,@dwRet
ret
_getKernelBase endp
_getApi proc _hModule,_lpApi
local @ret
local @dwLen
pushad
mov @ret,0
mov edi,_lpApi
mov ecx,-1
xor al,al
cld
repnz scasb
mov ecx,edi
sub ecx,_lpApi
mov @dwLen,ecx
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,_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
@@:
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
start:
mov eax,dword ptr [esp]
invoke _getKernelBase,eax
mov hKernel32Base,eax
invoke _getApi,hKernel32Base,addr szGetProcAddr
mov lpGetProcAddr,eax
mov _getProcAddress,eax
invoke _getProcAddress,hKernel32Base,addr szLoadLib
mov _loadLibrary,eax
invoke _loadLibrary ,addr user32_DLL
mov hUser32Base,eax
invoke _getProcAddress,hUser32Base,addr szMessageBox
mov _messageBox,eax
invoke _messageBox,NULL,offset szText,NULL,MB_OK
ret
end start
自己修改,使用重定位的HelloWorld
.386
.model flat,stdcall
option casemap:none
include windows.inc
_QLGetProcAddress typedef proto :dword,:dword
_ApiGetProcAddress typedef ptr _QLGetProcAddress
_QLLoadLib typedef proto :dword
_ApiLoadLib typedef ptr _QLLoadLib
_QLMessageBoxA typedef proto :dword,:dword,:dword,:dword
_ApiMessageBoxA typedef ptr _QLMessageBoxA
.code
szText db 'HelloWorldPE',0
szGetProcAddr db 'GetProcAddress',0
szLoadLib db 'LoadLibraryA',0
szMessageBox db 'MessageBoxA',0
szExitProcess db 'ExitProcess',0
user32_DLL db 'user32.dll',0,0
_getProcAddress _ApiGetProcAddress ?
_loadLibrary _ApiLoadLib ?
_messageBox _ApiMessageBoxA ?
hKernel32Base dd ?
hUser32Base dd ?
lpGetProcAddr dd ?
lpLoadLib dd ?
_getKernelBase proc _dwKernelRetAddress
local @dwRet
pushad
mov @dwRet,0
mov edi,_dwKernelRetAddress
and edi,0ffff0000h
.repeat
.if word ptr [edi] == IMAGE_DOS_SIGNATURE
mov esi,edi
add esi,[esi+003ch]
.if word ptr [esi] == IMAGE_NT_SIGNATURE
mov @dwRet,edi
.break
.endif
.endif
sub edi,010000h
.break .if edi<070000000h
.until FALSE
popad
mov eax,@dwRet
ret
_getKernelBase endp
_getApi proc _hModule,_lpApi
local @ret
local @dwLen
pushad
mov @ret,0
mov edi,_lpApi
mov ecx,-1
xor al,al
cld
repnz scasb
mov ecx,edi
sub ecx,_lpApi
mov @dwLen,ecx
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,_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
@@:
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
start:
mov eax,dword ptr [esp]
push eax
call @F
@@:
pop ebx
sub ebx,offset @B
pop eax
;获取kernel32.dll的基址
invoke _getKernelBase,eax
mov [ebx + offset hKernel32Base],eax
;获取ProcAddress的函数地址
mov edx,ebx
add edx,offset szGetProcAddr
invoke _getApi,eax,edx
mov [ebx + offset _getProcAddress],eax
;获取LoadLibrary的函数地址
mov edx,ebx
add edx,offset szLoadLib
push edx
push [ebx + offset hKernel32Base]
call eax
;下面这一段和上面等效,其实自己写的_getApi和系统库的GetProcAddress一个效果
;mov edx,ebx
;add edx,offset szLoadLib
;invoke _getApi,[ebx + offset hKernel32Base],edx
mov [ebx+offset _loadLibrary],eax
;加载user32.dll
mov edx,ebx
add edx,offset user32_DLL
push edx
call eax
mov [ebx + offset hUser32Base],eax
;找到MessageBox的函数地址
mov edx,ebx
add edx,offset szMessageBox
invoke _getApi,eax,edx
;下面这一段和上面等效
;mov ecx,ebx
;add ecx,offset szMessageBox
;push ecx
;push eax
;call [ebx + offset _getProcAddress]
mov ecx,ebx
add ecx,offset szText
push MB_OK
push NULL
push ecx
push NULL
call eax
;不加上ExitProcess的话,关闭信息框后进程还挂在后台
mov edx,ebx
add edx,offset szExitProcess
invoke _getApi,[ebx + offset hKernel32Base],edx
push NULL
call eax
end start
栈溢出,配合OD调试观看栈的变化。
.386
.model flat,stdcall
option casemap:none
include windows.inc
include user32.inc
includelib user32.lib
include kernel32.inc
includelib kernel32.lib
.data
szText db 'HelloWorldPE',0
szText2 db 'Touch Me!',0
szShellCode dd 0fffffffh,0dddddddh,0040103ah,0
.code
_memCopy proc _lpSrc
local @buf[4]:byte
pushad
mov al,1
mov esi,_lpSrc
lea edi,@buf
.while al!=0
mov al,byte ptr [esi]
mov byte ptr [edi],al
inc esi
inc edi
.endw
popad
ret
_memCopy endp
start:
invoke _memCopy,addr szShellCode
invoke MessageBox,NULL,offset szText,NULL,MB_OK
invoke MessageBox,NULL,offset szText2,NULL,MB_OK
invoke ExitProcess,NULL
end start
编写dll的源代码以及过程
1.asm
.386
.model flat,stdcall
option casemap:none
include windows.inc
include user32.inc
includelib user32.lib
include kernel32.inc
includelib kernel32.lib
MAX_XYSTEPS equ 50
DELAY_VALUE equ 50
X_STEP_SIZE equ 10
Y_STEP_SIZE equ 9
X_START_SIZE equ 20
Y_START_SIZE equ 10
LMA_ALPHA equ 2
LMA_COLORKEY equ 1
WS_EX_LAYERED equ 80000h
.data
dwCount dd ?
Value dd ?
Xsize dd ?
Ysize dd ?
sWth dd ?
sHth dd ?
Xplace dd ?
Yplace dd ?
counts dd ?
pSLWA dd ?
User32 db 'user32.dll',0
SLWA db 'SetLayeredWindowAttributes',0
.code
DllEntry proc _hInstance,_dwReason,_dwReserved
mov eax,TRUE
ret
DllEntry endp
TopXY proc wDim:DWORD,sDim:DWORD
shr sDim,1
shr wDim,1
mov eax,wDim
sub sDim,eax
mov eax,sDim
ret
TopXY endp
AnimateOpen proc hWin:DWORD
LOCAL Rct:RECT
invoke GetWindowRect,hWin,ADDR Rct
mov Xsize,X_START_SIZE
mov Ysize,Y_START_SIZE
invoke GetSystemMetrics,SM_CXSCREEN
mov sWth,eax
invoke TopXY,Xsize,eax
mov Xplace,eax
invoke GetSystemMetrics,SM_CYSCREEN
mov sHth,eax
invoke TopXY,Ysize,eax
mov Yplace,eax
mov counts,MAX_XYSTEPS
aniloop:
invoke MoveWindow,hWin,Xplace,Yplace,Xsize,Ysize,FALSE
invoke ShowWindow,hWin,SW_SHOWNA
invoke Sleep,DELAY_VALUE
invoke ShowWindow,hWin,SW_HIDE
add Xsize,X_STEP_SIZE
add Ysize,Y_STEP_SIZE
invoke TopXY,Xsize,sWth
mov Xplace,eax
invoke TopXY,Ysize,sHth
mov Yplace,eax
dec counts
jnz aniloop
mov eax,Rct.left
mov ecx,Rct.right
sub ecx,eax
mov Xsize,ecx
mov eax,Rct.top
mov ecx,Rct.bottom
sub ecx,eax
mov Ysize,ecx
invoke TopXY,Xsize,sWth
mov Xplace,eax
invoke TopXY,Ysize,sHth
mov Yplace,eax
invoke MoveWindow,hWin,Xplace,Yplace,Xsize,Ysize,TRUE
invoke ShowWindow,hWin,SW_SHOW
ret
AnimateOpen endp
AnimateClose proc hWin:DWORD
LOCAL Rct:RECT
invoke ShowWindow,hWin,SW_HIDE
invoke GetWindowRect,hWin,ADDR Rct
mov eax,Rct.left
mov ecx,Rct.right
sub ecx,eax
mov Xsize,ecx
mov eax,Rct.top
mov ecx,Rct.bottom
sub ecx,eax
mov Ysize,ecx
invoke GetSystemMetrics,SM_CXSCREEN
mov sWth,eax
invoke TopXY,Xsize,eax
mov Xplace,eax
invoke GetSystemMetrics,SM_CYSCREEN
mov sHth,eax
invoke TopXY,Ysize,eax
mov Yplace,eax
mov counts,MAX_XYSTEPS
aniloop:
invoke MoveWindow,hWin,Xplace,Yplace,Xsize,Ysize,FALSE
invoke ShowWindow,hWin,SW_SHOWNA
invoke Sleep,DELAY_VALUE
invoke ShowWindow,hWin,SW_HIDE
sub Xsize,X_STEP_SIZE
sub Ysize,Y_STEP_SIZE
invoke TopXY,Xsize,sWth
mov Xplace,eax
invoke TopXY,Ysize,sHth
mov Yplace,eax
dec counts
jnz aniloop
ret
AnimateClose endp
FadeInOpen proc hWin:DWORD
invoke GetWindowLongA,hWin,GWL_EXSTYLE
or eax,WS_EX_LAYERED
invoke SetWindowLongA,hWin,GWL_EXSTYLE,eax
invoke GetModuleHandleA,ADDR User32
invoke GetProcAddress,eax,ADDR SLWA
mov pSLWA,eax
push LMA_ALPHA
push 0
push 0
push hWin
call pSLWA
mov Value,90
invoke ShowWindow,hWin,SW_SHOWNA
doloop:
push LMA_COLORKEY + LMA_ALPHA
push Value
push Value
push pSLWA
invoke Sleep,DELAY_VALUE
add Value,15
cmp Value,255
jne doloop
push LMA_ALPHA
push 255
push 0
push hWin
call pSLWA
ret
FadeInOpen endp
FadeOutClose proc hWin:DWORD
invoke GetWindowLongA,hWin,GWL_EXSTYLE
or eax,WS_EX_LAYERED
invoke SetWindowLongA,hWin,GWL_EXSTYLE,eax
invoke GetModuleHandleA,ADDR User32
invoke GetProcAddress,eax,ADDR SLWA
mov pSLWA,eax
push LMA_ALPHA
push 255
push 0
push hWin
call pSLWA
mov Value,255
doloop:
push LMA_COLORKEY + LMA_ALPHA
push Value
push Value
push hWin
call pSLWA
invoke Sleep,DELAY_VALUE
sub Value,15
cmp Value,0
jne doloop
ret
FadeOutClose endp
End DllEntry
1.def
EXPORTS AnimateOpen
AnimateClose
FadeInOpen
FadeOutClose
编译链接:
ml -c -coff 1.asm
link -subsystem:windows -DLL -def:1.def 1.obj
但是要在其他程序中使用这个dll,还需要编写inc文件
1.inc
AnimateOpen proto :dword
AnimateClose proto :dword
FadeInOpen proto :dword
FadeOutClose proto :dword
后面的例子,使用上一个dll
.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
include 1.inc
includelib 1.lib
.data?
hInstance dd ?
hWinMain dd ?
.const
szClassName db 'MyClass',0
szCaptionMain db '窗口特效演示',0
szText db '你好,认识我吗?^-^',0
.code
_ProcWinMain proc uses ebx edi esi,hWnd,uMsg,wParam,lParam
local @stPs:PAINTSTRUCT
local @stRect:RECT
local @hDc
mov eax,uMsg
.if eax==WM_PAINT
invoke BeginPaint,hWnd,addr @stPs
invoke DrawText,@hDc,addr szText,-1,\
addr @stRect,\
DT_SINGLELINE or DT_CENTER or DT_VCENTER
invoke EndPaint,hWnd,addr @stPs
.elseif eax==WM_CLOSE
invoke FadeOutClose,hWinMain
invoke DestroyWindow,hWinMain
invoke PostQuitMessage,NULL
.else
invoke DefWindowProc,hWnd,uMsg,wParam,lParam
ret
.endif
xor eax,eax
ret
_ProcWinMain endp
_WinMain proc
local @stWndClass:WNDCLASSEX
local @stMsg:MSG
invoke GetModuleHandle,NULL
mov hInstance,eax
invoke RtlZeroMemory,addr @stWndClass,sizeof @stWndClass
invoke LoadCursor,0,IDC_ARROW
mov @stWndClass.hCursor,eax
push hInstance
pop @stWndClass.hInstance
mov @stWndClass.cbSize,sizeof WNDCLASSEX
mov @stWndClass.style,CS_HREDRAW or CS_VREDRAW
mov @stWndClass.lpfnWndProc,offset _ProcWinMain
mov @stWndClass.hbrBackground,COLOR_WINDOW + 1
mov @stWndClass.lpszClassName,offset szClassName
invoke RegisterClassEx,addr @stWndClass
invoke CreateWindowEx,WS_EX_CLIENTEDGE,\
offset szClassName,offset szCaptionMain,\
WS_OVERLAPPEDWINDOW,\
100,100,600,400,\
NULL,NULL,hInstance,NULL
mov hWinMain,eax
invoke FadeInOpen,hWinMain
;invoke ShowWindow,hWinMain,SW_SHOWNORMAL
invoke UpdateWindow,hWinMain
.while TRUE
invoke GetMessage,addr @stMsg,NULL,0,0
.break .if eax == 0
invoke TranslateMessage,addr @stMsg
invoke DispatchMessage,addr @stMsg
.endw
ret
_WinMain endp
start:
call _WinMain
invoke ExitProcess,NULL
end start
延迟导入:
.386
.model flat,stdcall
option casemap:none
include windows.inc
include user32.inc
includelib user32.lib
include kernel32.inc
includelib kernel32.lib
include 7.inc
includelib 7.lib
include delayimp.inc
includelib delayimp.lib
.data
dwFlag dd 1
szText db 'HelloWorldPE',0
.code
start:
mov eax,dwFlag
.if eax==0
invoke AnimateOpen,NULL
.endif
invoke MessageBox,NULL,offset szText,NULL,MB_OK
invoke ExitProcess,NULL
end start
代码没问题,但是win10下的masm32链接就报错,所以想学习这个延迟导入,直接VS写个代码,然后配置里面添加延迟导入的dll就可以了。
第9章的使用TLS多线程的例子。
.386
.model flat,stdcall
option casemap:none
include windows.inc
include user32.inc
includelib user32.lib
include kernel32.inc
includelib kernel32.lib
MAX_THREAD_COUNT equ 4
.data
hTlsIndex dd ?
dwThreadID dd ?
hThreadID dd MAX_THREAD_COUNT dup(0)
dwCount dd ?
szBuffer db 500 dup(0)
szOut1 db 'xc%dstop use:%dms',0
szErr1 db 'read TLS errorr!',0
szErr2 db 'write TLS error!',0
.code
_initTime proc
local @dwStart
pushad
invoke GetTickCount
mov @dwStart,eax
invoke TlsSetValue,hTlsIndex,@dwStart
.if eax==0
invoke MessageBox,NULL,addr szErr2,NULL,MB_OK
.endif
popad
ret
_initTime endp
_getLostTime proc
local @dwTemp
pushad
invoke GetTickCount
mov @dwTemp,eax
invoke TlsGetValue,hTlsIndex
.if eax==0
invoke MessageBox,NULL,addr szErr2,NULL,MB_OK
.endif
sub @dwTemp,eax
popad
mov eax,@dwTemp
ret
_getLostTime endp
_tFun proc uses ebx ecx edx esi edi,lParam
local @dwCount
local @tID
pushad
invoke _initTime
mov @dwCount,1000*10000
mov ecx,@dwCount
.while ecx>0
dec @dwCount
dec ecx
.endw
invoke GetCurrentThreadId
mov @tID,eax
invoke _getLostTime
invoke wsprintf,addr szBuffer,addr szOut1,@tID,eax
invoke MessageBox,NULL,addr szBuffer,NULL,MB_OK
popad
ret
_tFun endp
start:
invoke TlsAlloc
mov hTlsIndex,eax
mov dwCount,MAX_THREAD_COUNT
mov edi,offset hThreadID
.while dwCount>0
invoke CreateThread,NULL,0,offset _tFun,NULL,NULL,addr dwThreadID
mov dword ptr [edi],eax
add edi,4
dec dwCount
.endw
mov dwCount,MAX_THREAD_COUNT
mov edi,offset hThreadID
.while dwCount>0
mov eax,dword ptr [edi]
mov dwThreadID,eax
push edi
invoke WaitForSingleObject,eax,INFINITE
invoke CloseHandle,dwThreadID
pop edi
add edi,4
dec dwCount
.endw
invoke TlsFree,hTlsIndex
invoke ExitProcess,NULL
end start
不带TLS的多线程例子
.386
.model flat,stdcall
option casemap:none
include windows.inc
include user32.inc
includelib user32.lib
include kernel32.inc
includelib kernel32.lib
MAX_THREAD_COUNT equ 4
.data
hTlsIndex dd ?
dwThreadID dd ?
hThreadID dd MAX_THREAD_COUNT dup(0)
dwCount dd ?
szBuffer db 500 dup(0)
szOut1 db 'xc %d terminated,use %d ms.',0
.code
_tFun proc uses ebx ecx edx esi edi,lParam
local @dwCount
local @dwStart
local @dwEnd
local @tID
pushad
invoke GetTickCount
mov @dwStart,eax
mov @dwCount,1000*10000
mov ecx,@dwCount
.while ecx>0
dec @dwCount
dec ecx
.endw
invoke GetCurrentThreadId
mov @tID,eax
invoke GetTickCount
mov @dwEnd,eax
mov eax,@dwStart
sub @dwEnd,eax
invoke wsprintf,addr szBuffer,addr szOut1,@tID,@dwEnd
invoke MessageBox,NULL,addr szBuffer,NULL,MB_OK
popad
ret
_tFun endp
start:
mov dwCount,MAX_THREAD_COUNT
mov edi,offset hThreadID
.while dwCount>0
invoke CreateThread,NULL,0,offset _tFun,NULL,NULL,addr dwThreadID
mov dword ptr [edi],eax
add edi,4
dec dwCount
.endw
mov dwCount,MAX_THREAD_COUNT
mov edi,offset hThreadID
.while dwCount>0
mov eax,dword ptr [edi]
mov dwThreadID,eax
push edi
invoke WaitForSingleObject,dwThreadID,INFINITE
invoke CloseHandle,dwThreadID
pop edi
add edi,4
dec dwCount
.endw
invoke ExitProcess,NULL
end start
TLS回调函数的例子
.386
.model flat,stdcall
option casemap:none
include windows.inc
include user32.inc
includelib user32.lib
include kernel32.inc
includelib kernel32.lib
.data
szText db 'HelloWorldPE',0,0,0,0
TLS_DIRR dd offset Tls1
dd offset Tls2
dd offset Tls3
dd offset TlsCallBack
dd 0
dd 0
Tls1 dd 0
Tls2 dd 0
Tls3 dd 0
TlsCallBack dd offset TLS
dd 0
dd 0
.data?
TLSCalled db ?
.code
start:
invoke ExitProcess,NULL
RET
TLS:
cmp byte ptr [TLSCalled],1
je @exit
mov byte ptr [TLSCalled],1
invoke MessageBox,NULL,addr szText,NULL,MB_OK
@exit:
RET
end start
需要注意的是,这里构造了数据目录表里面线程本地存储表的数据,需要自己修改exe的字节文件,让那个表指向代码段的数据。详情可见本人线程本地存储记录。
第11章,获取kernel32.dll地址(一)
.386
.model flat,stdcall
option casemap:none
include windows.inc
include user32.inc
includelib user32.lib
include kernel32.inc
includelib kernel32.lib
.data
szText db 'kernel32.dll的基地址为%08x',0
szOut db '%08x',0dh,0ah,0
szBuffer db 256 dup(0)
.code
start:
call loc0
db 'GetProcAddress',0
loc0:
pop edx
push edx
mov ebx,7ffe0000h
;mov ebx,75950000h
loc1:
cmp dword ptr [ebx],905A4Dh
JE loc2
loc5:
sub ebx,00010000h
pushad
invoke IsBadReadPtr,ebx,2
.if eax
popad
jmp loc5
.endif
popad
jmp loc1
loc2:
mov esi,dword ptr [ebx+3ch]
add esi,ebx
mov esi,dword ptr [esi+78h]
nop
.if esi==0
jmp loc5
.endif
add esi,ebx
mov edi,dword ptr [esi+20h]
add edi,ebx
mov ecx,dword ptr [esi+18h]
push esi
xor eax,eax
loc3:
push edi
push ecx
mov edi,dword ptr [edi]
add edi,ebx
mov esi,edx
xor ecx,ecx
mov cl,0eh
repe cmpsb
pop ecx
pop edi
je loc4
add edi,4
inc eax
loop loc3
jmp loc5
loc4:
invoke wsprintf,addr szBuffer,addr szText,ebx
invoke MessageBox,NULL,addr szBuffer,NULL,MB_OK
ret
end start
这里有坑,它写的地址太高了,不属于此进程,使用isbadreadptr就会抛出异常。个人认为,还不如直接查看栈顶地址,然后以10000H向下取整。。。因为执行到main的时候,是从kernel32.dll跳过来的。
(二)
.386
.model flat,stdcall
option casemap:none
include windows.inc
include kernel32.inc
includelib kernel32.lib
include user32.inc
includelib user32.lib
.data
szText db 'ksernel32.dll %08x',0
szOut db '%08x',0dh,0ah,0
szBuffer db 256 dup(0)
.code
start:
assume fs:nothing
mov eax,fs:[0]
inc eax
loc1:
dec eax
mov esi,eax
mov eax,[eax]
inc eax
jne loc1
lodsd
lodsd
xor ax,ax
jmp loc3
loc2:
sub eax,10000h
loc3:
cmp dword ptr [eax],905A4Dh
jne loc2
invoke wsprintf,addr szBuffer,addr szText,eax
invoke MessageBox,NULL,addr szBuffer,NULL,MB_OK
invoke ExitProcess,NULL
ret
end start
本人对此也不太熟悉,不过能确定的是,在win10上,运行结果是错的,不是kernel32.dll的地址。建议合并一和二。把一里面那个太高的地址改成二获得的地址就好了。
(三)
.386
.model flat,stdcall
option casemap:none
include windows.inc
include kernel32.inc
includelib kernel32.lib
include user32.inc
includelib user32.lib
.data
szText db 'ksernel32.dll %08x',0
szOut db '%08x',0dh,0ah,0
szBuffer db 256 dup(0)
.code
start:
assume fs:nothing
mov eax,fs:[30h]
mov eax,[eax+0ch]
mov esi,[eax+1ch]
lodsd
mov eax,[eax];这一句是win7/win10需要添加的,原文没有,运行结果不是对的
mov eax,[eax+8]
invoke wsprintf,addr szBuffer,addr szText,eax
invoke MessageBox,NULL,addr szBuffer,NULL,MB_OK
invoke ExitProcess,NULL
ret
end start
第10章SEH处理框架
代码:
.386
.model flat,stdcall
option casemap:none
include windows.inc
include user32.inc
includelib user32.lib
include kernel32.inc
includelib kernel32.lib
.data
szText db 'HelloWorldPE',0
szErr db 'SEH Error',0
.code
_handler proc _lpException,_lpSEH,\
_lpContext,_lpSidpatcherContext
nop
pushad
mov esi,_lpException
mov edi,_lpContext
assume edi:ptr CONTEXT
invoke MessageBox,NULL,addr szErr,NULL,MB_OK
mov [edi].regEip,offset _safePlace
assume edi:nothing
popad
mov eax,ExceptionContinueExecution
;mov eax,ExceptionContinueSearch
ret
_handler endp
start:
assume fs:nothing
push offset _handler
push fs:[0]
mov fs:[0],esp
xor eax,eax
mov dword ptr [eax],eax
_safePlace:
pop fs:[0]
pop eax
invoke MessageBox,NULL,addr szText,NULL,MB_OK
invoke ExitProcess,NULL
end start
刚开始还不明白xor eax,eax之前的语句,后来才发现,这是构造了一个ExceptionList结构。
ExceptionList指向一个EXCEPTION_REGISTRATION结构。
定义:
EXCEPTION_REGISTRATION STRUCT
Prev dd ?
Handler dd ?
EXCEPTION_REGISTRATION ENDS
8个字节,前4个字节对应链接的其他结构,后4个字节对应此结构的异常处理函数地址。
配置表
代码:
.386
.model flat,stdcall
option casemap:none
include windows.inc
include user32.inc
includelib user32.lib
include kernel32.inc
includelib kernel32.lib
.data
szText1 db 'safeHandler!',0
szText2 db 'nosafeHandler!',0
szText db 'HelloWorldPE',0
.code
;IMAGE_LOAD_CONFIG_STRUCT STRUCT
Characteristic dd 00000048h
TimeDateStamp dd 0
MajorVersion dw 0
MinorVersion dw 0
GlobalFlagsClear dd 0
GlobalFlagsSet dd 0
CriticalSectionDefaultTimeout dd 0
DeCommitFreeeBlockThreshold dd 0
DeCommitTotalFreeThreshold dd 0
LockPrefixTable dd 0
MaximumAllocationSize dd 0
VirtualMemoryThreshold dd 0
ProcessHeapFlags dd 0
ProcessAffinityMask dd 0
CSDVersion dw 0
Reserved1 dw 0
EditList dd 0
SecurityCookie dd 00000000h
SEHandlerTable dd offset safeHandler
SEHandlerCount dd 00000001h
;IMAGE_LOAD_CONFIG_STRUCT ENDS
safeHandler dd offset _handler1-00400000h
dd 0
_handler1 proc _lpException,lpSEH,_lpContext,_lpDispatcherContext
nop
pushad
mov esi,_lpException
mov edi,_lpContext
assume edi:ptr CONTEXT
invoke MessageBox,NULL,addr szText1,NULL,MB_OK
mov [edi].regEip,offset _safePlace
assume edi:nothing
popad
mov eax,ExceptionContinueExecution
ret
_handler1 endp
_handler2 proc _lpException,_lpSEH,_lpContext,_lpDispatcherContext
nop
pushad
mov esi,_lpException
mov edi,_lpContext
assume edi:ptr CONTEXT
invoke MessageBox,NULL,addr szText2,NULL,MB_OK
mov [edi].regEip,offset _safePlace
assume edi:nothing
popad
mov eax,ExceptionContinueExecution
ret
_handler2 endp
start:
assume fs:nothing
push offset _handler1
push fs:[0]
mov fs:[0],esp
xor eax,eax
mov dword ptr [eax],eax
_safePlace:
pop fs:[0]
pop eax
invoke MessageBox,NULL,addr szText,NULL,MB_OK
invoke ExitProcess,NULL
end start
这个也是把配置表写在代码段里面进行构造,需要修改exe文件的配置属性表。