文章目录
- nasm - BasicWindow_64
- 概述
- 笔记
- nasm_main.asm
- my_build.bat
- END
nasm - BasicWindow_64
概述
学个demo, 这个demo最主要学到了:
不用在调用每个API前都准备阴影区,在API调用后栈平衡。
可以在函数入口处考虑到所用的栈尺寸最大值(16字节对齐,阴影区,函数的所有局部变量,调用API时用的参数最多的栈尺寸),开栈;在函数出口进行栈平衡。
其他细节地方,自己对着VS2019release版的x64反汇编就能搞。
说到底,要想拿汇编代码来写东西,要知道正向怎么写,然后才能参考反汇编代码来写NASM的工程。要不谁知道对应的汇编代码怎么弄。
NASM代码和x64反汇编出来的代码基本一样,稍微改一下就能拿来用。
笔记
nasm_main.asm
; @file nasm_main.asm
; @brief 用NASM实现一个64bits的基本窗口扩展
; nasm - BasicWindow_64
; ----------------------------------------
; 宏定义
; ----------------------------------------
; Basic Window Extended, 64 bit. V1.05
ANSI_CHARSET EQU 0 ; Constants
BLACKNESS EQU 42h
CLIP_DEFAULT_PRECIS EQU 0
CS_BYTEALIGNWINDOW EQU 2000h
CS_HREDRAW EQU 2
CS_VREDRAW EQU 1
DEFAULT_PITCH EQU 0
ES_AUTOHSCROLL EQU 80h
ES_CENTER EQU 1
FALSE EQU 0
GRAY_BRUSH EQU 2
IDC_ARROW EQU 7F00h
IDI_APPLICATION EQU 7F00h
IDNO EQU 7
IMAGE_CURSOR EQU 2
IMAGE_ICON EQU 1
LR_SHARED EQU 8000h
MB_DEFBUTTON2 EQU 100h
MB_YESNO EQU 4
NULL EQU 0
NULL_BRUSH EQU 5
OPAQUE EQU 2
PROOF_QUALITY EQU 2
SM_CXFULLSCREEN EQU 10h
SM_CYFULLSCREEN EQU 11h
SS_CENTER EQU 1
SS_NOTIFY EQU 100h
SW_SHOWNORMAL EQU 1
TRUE EQU 1
WM_CLOSE EQU 10h
WM_COMMAND EQU 111h
WM_CREATE EQU 1
WM_CTLCOLOREDIT EQU 133h
WM_CTLCOLORSTATIC EQU 138h
WM_DESTROY EQU 2
WM_PAINT EQU 0Fh
WM_SETFONT EQU 30h
OUT_DEFAULT_PRECIS EQU 0
WS_CHILD EQU 40000000h
WS_EX_COMPOSITED EQU 2000000h
WS_OVERLAPPEDWINDOW EQU 0CF0000h
WS_TABSTOP EQU 10000h
WS_VISIBLE EQU 10000000hWindowWidth EQU 640
WindowHeight EQU 170
Static1ID EQU 100
Static2ID EQU 101
Edit1ID EQU 102
Edit2ID EQU 103; ----------------------------------------
; 外部函数声明
; ----------------------------------------
extern AdjustWindowRectEx ; Import external symbols
extern BeginPaint ; Windows API functions, not decorated
extern BitBlt
extern CreateFontA
extern CreateSolidBrush
extern CreateWindowExA
extern DefWindowProcA
extern DeleteObject
extern DestroyWindow
extern DispatchMessageA
extern EndPaint
extern ExitProcess
extern GetDlgCtrlID
extern GetStockObject
extern GetMessageA
extern GetModuleHandleA
extern GetSystemMetrics
extern InvalidateRect
extern IsDialogMessageA
extern LoadImageA
extern MessageBoxA
extern PostQuitMessage
extern RegisterClassExA
extern SendMessageA
extern SetBkColor
extern SetBkMode
extern SetTextColor
extern ShowWindow
extern TranslateMessage
extern UpdateWindowglobal fn_Start ; Export symbols. The entry point; ----------------------------------------
; 区段定义
; ----------------------------------------
section .data ; Initialized data segment
; // 常量是不需要字节对齐的Static1Colour dd 0F0F0F0h ; Colour (0BBGGRRh)Static1ColourA dd 020A0F0hStatic2Colour dd 000FFFFhStatic2ColourA dd 08000FFhEdit1TextColour dd 0F590F5hEdit1BackColour dd 0A00000hEdit2TextColour dd 0A56E3BhEdit2BackColour dd 0FEFE8EhBackgroundColour dd 0A56E3Bh WindowName db "Basic Window Extended 64", 0ClassName db "Window", 0SegoeUI db "Segoe UI", 0StaticClass db "STATIC", 0EditClass db "EDIT", 0Text1 db "ABCDEFGHIJKLMNOPQRSTUVWXYZ_0123456789", 0Text2 db "abcdefghijklmnopqrstuvwxyz_0123456789", 0ExitText db "Do you want to exit?", 0section .bss ; Uninitialized data segmentalignb 8 ; 8字节对齐hInstance resq 1BackgroundBrush resq 1Font resq 1Static1 resq 1Static2 resq 1Edit1 resq 1Edit2 resq 1section .text ; Code segment
; ----------------------------------------
; 函数定义
; ----------------------------------------
fn_Start:; 16字节对齐; 进了函数之后,默认就是8字节对齐(因为系统调用fn_Start时, 栈上有调用fn_Start后的返回地址8个字节), 将栈顶再减去8, 就是16字节对齐sub RSP, 8 ; Align stack pointer to 16 bytes; // 在一个函数中,如果调用的API比较少,则需要在API调用的前后进行单独的栈平衡sub RSP, 32 ; 32 bytes of shadow spacexor ECX, ECXcall GetModuleHandleAmov qword [REL hInstance], RAXadd RSP, 32 ; Remove the 32 bytes; 如果是自己实现的函数, 就不用特意做(阴影区, 16字节对齐, 栈平衡)都在自己的函数内做了就行call fn_WinMain.Exit:xor ECX, ECXcall ExitProcess ; 退出的函数是API, 为什么不做栈平衡, 是ExitProcess内部不用阴影区么? ExitProcess是特例?
; ----------------------------------------
fn_WinMain:push RBP ; Set up a stack frame; 返回地址 + push RBP 就已经是16字节对齐了mov RBP, RSP; 函数内栈开多大,也不用精确计算,差不多就行(32字节的阴影区 + 函数内局部变量的字节数 + 多开一点,够函数调用时用的临时入参变量的赋值); 这里有一个技巧,在一个函数中调用API, 不用每次都在前后准备栈(阴影区)/清除栈(阴影区); 只需要在函数入口出口处准备足够栈空间(16字节对齐 + 阴影区 + 函数的局部变量区 + 调用API时最多的参数变量空间)/栈平衡; 调用API时, 只需要准备API需要的参数就行(RCX,RDX,R8,R9; 其余参数从RBP + 32开始, 参数5,参数6, ...)sub RSP, 160 + 64 + 32 ; 160 bytes for local variables; + 64 (8 * 8 byte) parameters ; + 32 shadow space; Kept to a multiple of 16 for API functions%define Screen.Width RBP - 160 ; 4 bytes
%define Screen.Height RBP - 156 ; 4 bytes%define ClientArea RBP - 152 ; RECT structure. 16 bytes
%define ClientArea.left RBP - 152 ; 4 bytes. Start on a 4 byte boundary
%define ClientArea.top RBP - 148 ; 4 bytes
%define ClientArea.right RBP - 144 ; 4 bytes
%define ClientArea.bottom RBP - 140 ; 4 bytes. End on a 4 byte boundary%define wc RBP - 136 ; WNDCLASSEX structure, 80 bytes
%define wc.cbSize RBP - 136 ; 4 bytes. Start on an 8 byte boundary
%define wc.style RBP - 132 ; 4 bytes
%define wc.lpfnWndProc RBP - 128 ; 8 bytes
%define wc.cbClsExtra RBP - 120 ; 4 bytes
%define wc.cbWndExtra RBP - 116 ; 4 bytes
%define wc.hInstance RBP - 112 ; 8 bytes
%define wc.hIcon RBP - 104 ; 8 bytes
%define wc.hCursor RBP - 96 ; 8 bytes
%define wc.hbrBackground RBP - 88 ; 8 bytes
%define wc.lpszMenuName RBP - 80 ; 8 bytes
%define wc.lpszClassName RBP - 72 ; 8 bytes
%define wc.hIconSm RBP - 64 ; 8 bytes. End on an 8 byte boundary%define msg RBP - 56 ; MSG structure, 48 bytes
%define msg.hwnd RBP - 56 ; 8 bytes. Start on an 8 byte boundary
%define msg.message RBP - 48 ; 4 bytes
%define msg.Padding1 RBP - 44 ; 4 bytes. Natural alignment padding
%define msg.wParam RBP - 40 ; 8 bytes
%define msg.lParam RBP - 32 ; 8 bytes
%define msg.time RBP - 24 ; 4 bytes
%define msg.py.x RBP - 20 ; 4 bytes
%define msg.pt.y RBP - 16 ; 4 bytes
%define msg.Padding2 RBP - 12 ; 4 bytes. Structure length padding%define hWnd RBP - 8 ; 8 bytesmov ECX, dword [REL BackgroundColour]call CreateSolidBrush ; Create a brush for the window backgoundmov qword [REL BackgroundBrush], RAXmov dword [wc.cbSize], 80 ; [RBP - 136]mov dword [wc.style], CS_HREDRAW | CS_VREDRAW | CS_BYTEALIGNWINDOW ; [RBP - 132]lea RAX, [REL fn_WndProc]mov qword [wc.lpfnWndProc], RAX ; [RBP - 128]mov dword [wc.cbClsExtra], NULL ; [RBP - 120]mov dword [wc.cbWndExtra], NULL ; [RBP - 116]mov RAX, qword [REL hInstance]mov qword [wc.hInstance], RAX ; [RBP - 112]xor ECX, ECXmov EDX, IDI_APPLICATIONmov R8D, IMAGE_ICONxor R9D, R9Dmov qword [RSP + 4 * 8], NULLmov qword [RSP + 5 * 8], LR_SHAREDcall LoadImageA ; Large program iconmov qword [wc.hIcon], RAX ; [RBP - 104]xor ECX, ECXmov EDX, IDC_ARROWmov R8D, IMAGE_CURSORxor R9D, R9Dmov qword [RSP + 4 * 8], NULLmov qword [RSP + 5 * 8], LR_SHAREDcall LoadImageA ; Cursormov qword [wc.hCursor], RAX ; [RBP - 96]mov RAX, qword [REL BackgroundBrush]mov qword [wc.hbrBackground], RAX ; [RBP - 88]mov qword [wc.lpszMenuName], NULL ; [RBP - 80]lea RAX, [REL ClassName]mov qword [wc.lpszClassName], RAX ; [RBP - 72]xor ECX, ECXmov EDX, IDI_APPLICATIONmov R8D, IMAGE_ICONxor R9D, R9Dmov qword [RSP + 4 * 8], NULLmov qword [RSP + 5 * 8], LR_SHAREDcall LoadImageA ; Small program iconmov qword [wc.hIconSm], RAX ; [RBP - 64]lea RCX, [wc] ; [RBP - 136]call RegisterClassExAmov ECX, SM_CXFULLSCREENcall GetSystemMetrics ; Get the current screen widthmov dword [Screen.Width], EAX ; [RBP - 160]mov ECX, SM_CYFULLSCREENcall GetSystemMetrics ; Get the current screen heightmov dword [Screen.Height], EAX ; [RBP - 156]mov dword [ClientArea.left], 0 ; [RBP - 152]mov dword [ClientArea.top], 0 ; [RBP - 148]mov dword [ClientArea.right], WindowWidth ; [RBP - 144]mov dword [ClientArea.bottom], WindowHeight ; [RBP - 140]lea RCX, [ClientArea] ; [RBP - 152]mov EDX, WS_OVERLAPPEDWINDOW ; Stylexor R8D, R8Dmov R9D, WS_EX_COMPOSITED ; Extended stylecall AdjustWindowRectEx ; Get window size for the desired client size; Size is returned in ClientAreamov EAX, dword [ClientArea.top] ; [RBP - 148]sub dword [ClientArea.bottom], EAX ; New Height = ClientArea.bottom - ClientArea.topmov EAX, dword [ClientArea.left] ; [RBP - 152]sub dword [ClientArea.right], EAX ; New Width = ClientArea.right - ClientArea.leftmov ECX, WS_EX_COMPOSITEDlea RDX, [REL ClassName]lea R8, [REL WindowName]mov R9D, WS_OVERLAPPEDWINDOWxor R10D, R10Dmov EAX, dword [Screen.Width] ; [RBP - 160]sub EAX, dword [ClientArea.right] ; Corrected window width. [RBP - 144]cmovs EAX, R10D ; Clamp to 0 (left) if negativeshr EAX, 1 ; EAX = (Screen.Width - window height) / 2mov dword [RSP + 4 * 8], EAX ; X position, now centredmov EAX, dword [Screen.Height] ; [RBP - 156]sub EAX, dword [ClientArea.bottom] ; Corrected window height. [RBP - 140]cmovs EAX, R10D ; Clamp to 0 (top) if negativeshr EAX, 1 ; EAX = (Screen.Height - window height) / 2mov dword [RSP + 5 * 8], EAX ; Y position, now centredmov EAX, dword [ClientArea.right] ; [RBP - 144]mov dword [RSP + 6 * 8], EAX ; Widthmov EAX, dword [ClientArea.bottom] ; [RBP - 140]mov dword [RSP + 7 * 8], EAX ; Heightmov qword [RSP + 8 * 8], NULLmov qword [RSP + 9 * 8], NULLmov RAX, qword [REL hInstance]mov qword [RSP + 10 * 8], RAXmov qword [RSP + 11 * 8], NULLcall CreateWindowExAmov qword [hWnd], RAX ; [RBP - 8]mov RCX, qword [hWnd] ; [RBP - 8]mov EDX, SW_SHOWNORMALcall ShowWindowmov RCX, qword [hWnd] ; [RBP - 8]call UpdateWindow.MessageLoop:lea RCX, [msg] ; [RBP - 56]xor EDX, EDXxor R8D, R8Dxor R9D, R9Dcall GetMessageAcmp RAX, 0je .Donemov RCX, qword [hWnd] ; [RBP - 8]lea RDX, [msg] ; [RBP - 56]call IsDialogMessageA ; For keyboard strokescmp RAX, 0jne .MessageLoop ; Skip TranslateMessage and DispatchMessageAlea RCX, [msg] ; [RBP - 56]call TranslateMessagelea RCX, [msg] ; [RBP - 56]call DispatchMessageAjmp .MessageLoop.Done:xor EAX, EAXmov RSP, RBP ; Remove the stack framepop RBPret
; ----------------------------------------
fn_WndProc:push RBP ; Set up a stack framemov RBP, RSPsub RSP, 80 + 80 + 32 ; 80 bytes for local variables; + 80 (10 * 8 byte) parameters; + 32 shadow space; Kept to a multiple of 16 for API functions%define hWnd RBP + 16 ; Location of the shadow space setup by
%define uMsg RBP + 24 ; the calling function
%define wParam RBP + 32
%define lParam RBP + 40%define ps RBP - 80 ; PAINTSTRUCT structure. 72 bytes
%define ps.hdc RBP - 80 ; 8 bytes. Start on an 8 byte boundary
%define ps.fErase RBP - 72 ; 4 bytes
%define ps.rcPaint.left RBP - 68 ; 4 bytes
%define ps.rcPaint.top RBP - 64 ; 4 bytes
%define ps.rcPaint.right RBP - 60 ; 4 bytes
%define ps.rcPaint.bottom RBP - 56 ; 4 bytes
%define ps.Restore RBP - 52 ; 4 bytes
%define ps.fIncUpdate RBP - 48 ; 4 bytes
%define ps.rgbReserved RBP - 44 ; 32 bytes
%define ps.Padding RBP - 12 ; 4 bytes. Structure length padding%define hdc RBP - 8 ; 8 bytesmov qword [hWnd], RCX ; Free up RCX RDX R8 R9 by spilling themov qword [uMsg], RDX ; 4 passed parameters to the shadow spacemov qword [wParam], R8 ; We can now access these parameters by namemov qword [lParam], R9cmp qword [uMsg], WM_CLOSE ; [RBP + 24]je proc.WMCLOSEcmp qword [uMsg], WM_COMMAND ; [RBP + 24]je proc.WMCOMMANDcmp qword [uMsg], WM_CREATE ; [RBP + 24]je proc.WMCREATEcmp qword [uMsg], WM_CTLCOLOREDIT ; [RBP + 24]je proc.WMCTLCOLOREDITcmp qword [uMsg], WM_CTLCOLORSTATIC ; [RBP + 24]je proc.WMCTLCOLORSTATICcmp qword [uMsg], WM_DESTROY ; [RBP + 24]je proc.WMDESTROYcmp qword [uMsg], WM_PAINT ; [RBP + 24]je proc.WMPAINTproc.DefaultMessage:mov RCX, qword [hWnd] ; [RBP + 16]mov RDX, qword [uMsg] ; [RBP + 24]mov R8, qword [wParam] ; [RBP + 32]mov R9, qword [lParam] ; [RBP + 40]call DefWindowProcAjmp proc.Returnproc.WMCLOSE:mov RCX, qword [hWnd] ; [RBP + 16]lea RDX, [REL ExitText]lea R8, [REL WindowName]mov R9D, MB_YESNO | MB_DEFBUTTON2call MessageBoxAcmp RAX, IDNOje proc.Return.WM_Processedmov RCX, qword [hWnd] ; [RBP + 16]call DestroyWindow ; Send a WM_DESTROY messagejmp proc.Return.WM_Processedproc.WMCOMMAND:mov RAX, qword [wParam] ; RAX = ID. [RBP + 32]cmp AX, Static1IDje .Static1cmp AX, Static2IDje .Static2jmp proc.Return.WM_Processed.Static1:mov EAX, dword [REL Static1Colour]mov ECX, dword [REL Static1ColourA]mov dword [REL Static1Colour], ECXmov dword [REL Static1ColourA], EAX ; Swap coloursmov RCX, qword [lParam] ; Static1 handle. [RBP + 40]xor EDX, EDXmov R8D, TRUEcall InvalidateRect ; Redraw controljmp proc.Return.WM_Processed.Static2:mov EAX, dword [REL Static2Colour]mov ECX, dword [REL Static2ColourA]mov dword [REL Static2Colour], ECXmov dword [REL Static2ColourA], EAX ; Swap coloursmov RCX, qword [lParam] ; Static2 handle. [RBP + 40]xor EDX, EDXmov R8D, TRUEcall InvalidateRect ; Redraw controljmp proc.Return.WM_Processedproc.WMCREATE:xor ECX, ECXlea RDX, [REL StaticClass]lea R8, [REL Text1] ; Default textmov R9D, WS_CHILD | WS_VISIBLE | SS_NOTIFY | SS_CENTERmov qword [RSP + 4 * 8], 120 ; Xmov qword [RSP + 5 * 8], 10 ; Ymov qword [RSP + 6 * 8], 400 ; Widthmov qword [RSP + 7 * 8], 20 ; Heightmov RAX, qword [hWnd] ; [RBP + 16]mov qword [RSP + 8 * 8], RAX mov qword [RSP + 9 * 8], Static1ID mov RAX, qword [REL hInstance] mov qword [RSP + 10 * 8], RAXmov qword [RSP + 11 * 8], NULLcall CreateWindowExAmov qword [REL Static1], RAXxor ECX, ECXlea RDX, [REL StaticClass]lea R8, [REL Text2] ; Default textmov R9D, WS_CHILD | WS_VISIBLE | SS_NOTIFY | SS_CENTERmov qword [RSP + 4 * 8], 120 ; Xmov qword [RSP + 5 * 8], 40 ; Ymov qword [RSP + 6 * 8], 400 ; Widthmov qword [RSP + 7 * 8], 20 ; Heightmov RAX, qword [hWnd] ; [RBP + 16]mov qword [RSP + 8 * 8], RAX mov qword [RSP + 9 * 8], Static2ID mov RAX, qword [REL hInstance] mov qword [RSP + 10 * 8], RAXmov qword [RSP + 11 * 8], NULLcall CreateWindowExAmov qword [REL Static2], RAXxor ECX, ECXlea RDX, [REL EditClass]lea R8, [REL Text1] ; Default textmov R9D, WS_CHILD | WS_VISIBLE | ES_CENTER | WS_TABSTOP | ES_AUTOHSCROLLmov qword [RSP + 4 * 8], 120 ; Xmov qword [RSP + 5 * 8], 70 ; Ymov qword [RSP + 6 * 8], 400 ; Widthmov qword [RSP + 7 * 8], 20 ; Heightmov RAX, qword [hWnd] ; [RBP + 16]mov qword [RSP + 8 * 8], RAX mov qword [RSP + 9 * 8], Edit1ID mov RAX, qword [REL hInstance] mov qword [RSP + 10 * 8], RAXmov qword [RSP + 11 * 8], NULLcall CreateWindowExAmov qword [REL Edit1], RAXxor ECX, ECXlea RDX, [REL EditClass]lea R8, [REL Text2] ; Default textmov R9D, WS_CHILD | WS_VISIBLE | ES_CENTER | WS_TABSTOP | ES_AUTOHSCROLLmov qword [RSP + 4 * 8], 120 ; Xmov qword [RSP + 5 * 8], 100 ; Ymov qword [RSP + 6 * 8], 400 ; Widthmov qword [RSP + 7 * 8], 20 ; Heightmov RAX, qword [hWnd] ; [RBP + 16]mov qword [RSP + 8 * 8], RAX mov qword [RSP + 9 * 8], Edit2ID mov RAX, qword [REL hInstance] mov qword [RSP + 10 * 8], RAXmov qword [RSP + 11 * 8], NULLcall CreateWindowExAmov qword [REL Edit2], RAXmov ECX, 20 ; Sizexor EDX, EDXxor R8D, R8D xor R9D, R9Dmov qword [RSP + 4 * 8], 400 ; Weightmov qword [RSP + 5 * 8], NULLmov qword [RSP + 6 * 8], NULLmov qword [RSP + 7 * 8], NULLmov qword [RSP + 8 * 8], ANSI_CHARSETmov qword [RSP + 9 * 8], OUT_DEFAULT_PRECISmov qword [RSP + 10 * 8], CLIP_DEFAULT_PRECISmov qword [RSP + 11 * 8], PROOF_QUALITYmov qword [RSP + 12 * 8], DEFAULT_PITCHlea RAX, [REL SegoeUI]mov qword [RSP + 13 * 8], RAXcall CreateFontAmov qword [REL Font], RAXmov RCX, qword [REL Static1]mov EDX, WM_SETFONTmov R8, qword [REL Font]xor R9D, R9Dcall SendMessageA ; Set Static1 fontmov RCX, qword [REL Static2]mov EDX, WM_SETFONTmov R8, qword [REL Font]xor R9D, R9Dcall SendMessageA ; Set Static2 fontmov RCX, qword [REL Edit1]mov EDX, WM_SETFONTmov R8, qword [REL Font]xor R9D, R9Dcall SendMessageA ; Set Edit1 fontmov RCX, qword [REL Edit2]mov EDX, WM_SETFONTmov R8, qword [REL Font]xor R9D, R9Dcall SendMessageA ; Set Edit2 fontjmp proc.Return.WM_Processedproc.WMCTLCOLOREDIT: ; For colouring edit controlsmov RCX, qword [lParam] ; [RBP + 40]call GetDlgCtrlID ; RAX = IDcmp RAX, Edit1IDje .Edit1cmp RAX, Edit2IDje .Edit2.Default:mov ECX, NULL_BRUSHcall GetStockObject ; Return a brushjmp proc.Return.Edit1:mov RCX, qword [wParam] ; [RBP + 32]mov EDX, dword [REL Edit1TextColour]call SetTextColormov RCX, qword [wParam] ; [RBP + 32]mov EDX, OPAQUEcall SetBkModemov RCX, qword [wParam] ; [RBP + 32]mov EDX, dword [REL Edit1BackColour]call SetBkColormov ECX, NULL_BRUSHcall GetStockObject ; Return a brushjmp proc.Return.Edit2:mov RCX, qword [wParam] ; [RBP + 32]mov EDX, dword [REL Edit2TextColour]call SetTextColormov RCX, qword [wParam] ; [RBP + 32]mov EDX, OPAQUEcall SetBkModemov RCX, qword [wParam] ; [RBP + 32]mov EDX, dword [REL Edit2BackColour]call SetBkColormov ECX, NULL_BRUSHcall GetStockObject ; Return a brushjmp proc.Returnproc.WMCTLCOLORSTATIC: ; For colouring static controlsmov RCX, qword [lParam] ; [RBP + 40]call GetDlgCtrlID ; RAX = IDcmp RAX, Static1IDje .Static1cmp RAX, Static2IDje .Static2.Default:mov ECX, NULL_BRUSHcall GetStockObject ; Return a brushjmp proc.Return.Static1:mov RCX, qword [wParam] ; [RBP + 32]mov EDX, dword [REL Static1Colour]call SetTextColormov RCX, qword [wParam] ; [RBP + 32]mov EDX, OPAQUEcall SetBkModemov RCX, qword [wParam] ; [RBP + 32]mov EDX, 0604060hcall SetBkColormov ECX, NULL_BRUSHcall GetStockObject ; Return a brushjmp proc.Return.Static2:mov RCX, qword [wParam] ; [RBP + 32]mov EDX, dword [REL Static2Colour]call SetTextColormov RCX, qword [wParam] ; [RBP + 32]mov EDX, OPAQUEcall SetBkModemov RCX, qword [wParam] ; [RBP + 32]mov EDX, 0005000hcall SetBkColormov ECX, GRAY_BRUSHcall GetStockObject ; Return a brushjmp proc.Returnproc.WMDESTROY:mov RCX, qword [REL BackgroundBrush]call DeleteObjectmov RCX, qword [REL Font]call DeleteObjectxor ECX, ECXcall PostQuitMessagejmp proc.Return.WM_Processedproc.WMPAINT:mov RCX, qword [hWnd] ; [RBP + 16]lea RDX, [ps] ; [RBP - 80]call BeginPaintmov qword [hdc], RAX ; [RBP - 8]mov RCX, qword [hdc] ; Destination device context. [RBP - 8]mov EDX, 120 ; Destination Xmov R8D, 130 ; Destination Ymov R9D, 400 ; Widthmov qword [RSP + 4 * 8], 20 ; Heightmov RAX, qword [hdc] ; [RBP - 8]mov qword [RSP + 5 * 8], RAX ; Source device contextmov qword [RSP + 6 * 8], 0 ; Source Xmov qword [RSP + 7 * 8], 0 ; Source Ymov qword [RSP + 8 * 8], BLACKNESS ; Operationcall BitBlt ; Blit a black rectanglemov RCX, qword [hWnd] ; [RBP + 16]lea RDX, [ps] ; [RBP - 80]call EndPaintproc.Return.WM_Processed:xor EAX, EAX ; WM_ has been processed, return 0proc.Return:mov RSP, RBP ; Remove the stack framepop RBPret
my_build.bat
@echo off
clsrem ----------------------------------------
rem my_build.batrem env
rem NASM version 2.16.03 compiled on Apr 17 2024
rem GoLink.Exe Version 1.0.4.6 Copyright Jeremy Gordon 2002-2025set path=C:\Program Files\NASM;C:\soft\Golink;%path%rem . bat默认是不支持中文的 .
rem echo full path name - %~f0
rem echo full path - %~dp0
rem echo file name - %~nx0
rem echo work path - %cd%
rem all param - %*rem . rem注释的第1个字符和最后1个字符,不能是中文,否则有概率会当作命令来执行 .
rem . 调试.bat的方法 .
rem . 如果.bat写的不对,又不容易看出来,只能在每行后面加pause, 然后执行.bat, 然后按一下空格执行一行 .set prj_src_name_1=nasm_main.asm
set prj_obj_name_1=nasm_main.obj
set prj_exe_name=BasicWindow_ext_64.exerem win32 or win64
set prj_build_type=win64rem /console or /SUBSYSTEM:WINDOWS
set prj_sub_sys=/SUBSYSTEM:WINDOWSecho [%~nx0 %*]if "%1" == "build" (call :fn_build
) else if "%1" == "clear" (call :fn_clear
) else (call :fn_usage
)goto endrem ----------------------------------------
rem function
rem ----------------------------------------:fn_usage
echo usage my_build.bat [option]
echo build - build asm to EXE
echo clear - clear trush on the project
exit /brem ----------------------------------------
:fn_build
echo build ...rem find file on work path
call :fn_del_file "%prj_obj_name_1%"nasm -f %prj_build_type% %prj_src_name_1% -o %prj_obj_name_1%
rem 用IDA打开.obj 已经可以看到实现逻辑了call :fn_del_file "%prj_exe_name%"rem 如果不指定要连接的dll, 会报错
golink /entry:fn_Start '%prj_sub_sys%' kernel32.dll user32.dll gdi32.dll %prj_obj_name_1% /fo %prj_exe_name%call :fn_exec "%prj_exe_name%"
exit /brem ----------------------------------------
:fn_clear
echo clear ...
call :fn_del_file "%prj_obj_name_1%"
call :fn_del_file "%prj_exe_name%"
exit /brem ----------------------------------------
:fn_del_file
if exist "%~1" (echo del "%~1" del "%~1"
)
exit /b:fn_exec
if exist "%~1" (echo exec "%~1"%~1
)
exit /brem ----------------------------------------
:end
echo END
rem pause
rem call cmd