[COMPUTER BASIC] FASM+GDIP

效果图

完整代码

format PE GUI 4.0
;声明文件类型
entry start
;程序入口

include 'win32ax.inc'
;文件包头

struct GdiplusStartupInput
  GdiplusVersion dd ?
  DebugEventCallback dd ?
  SuppressBackgroundThread dd ?
  SuppressExternalCodecs dd ?
ends

DebugEventCallback 指向回调函数的指针,在调试中为声明和警告调用该回调函数(默认True)

SuppressBackgroundThread 若为True则结构体将返回指向hook函数的指针和指向unhook挂钩函数的指针(默认False)

SuppressExternalCodecs 是否抑制外部图像编解码器

GdiplusVersion dd ? 第三个位置用于表示默认值,如果该位置为 ?则说明这是一个没有初始化的数据

.idata部分

section '.idata' import data readable writeable

  library gdi, 'GDI.DLL',\
          gdiplus, 'GDIPLUS.DLL',\
          kernel32,'KERNEL32.DLL',\
          user32,'USER32.DLL'

  include 'api\gdi32.inc'
  include 'api\kernel32.inc'
  include 'api\user32.inc'

  import  gdiplus,\
                  GdiplusShutdown,'GdiplusShutdown',\
                  GdipCreateFromHDC, 'GdipCreateFromHDC',\
                  GdipCreatePen1, 'GdipCreatePen1',\
                  GdipDeleteGraphics, 'GdipDeleteGraphics',\
                  GdipDeletePen, 'GdipDeletePen',\
                  GdipGetPenBrushFill, 'GdipGetPenBrushFill',\
                  GdipFillEllipseI, 'GdipFillEllipseI',\
                  GdipDrawLineI, 'GdipDrawLineI',\
                  GdipSetSmoothingMode, 'GdipSetSmoothingMode',\
                  GdiplusStartup, 'GdiplusStartup',\
                  GdipDrawEllipseI, 'GdipDrawEllipseI',\
                  GdipDrawArcI, 'GdipDrawArcI',\
                  GdipDrawRectangleI, 'GdipDrawRectangleI',\
                  GdipFillEllipse, 'GdipFillEllipse'

.data部分

section '.data' data readable writeable

  _class TCHAR 'FASMWIN32',0
  _title TCHAR 'Example',0
  _error TCHAR 'Startup failed.',0

  wc WNDCLASS 0,WindowProc,0,0,NULL,NULL,NULL,COLOR_BTNFACE+1,NULL,_class
  ;注册一个windows类

  msg MSG
  input GdiplusStartupInput 1 ; GdiplusVersion = 1
  token dd ? 

该部分用于存放全局变量/常量等,用ida查看字符串可以看到上面这三个全局变量

WNDCLASS是一个系统支持的结构,用于储存窗口信息

.code部分

section '.code' code readable executable

  start:

        invoke  GetModuleHandle,0   
        mov     [wc.hInstance],eax
        invoke  LoadIcon,0,IDI_APPLICATION
        mov     [wc.hIcon],eax
        invoke  LoadCursor,0,IDC_IBEAM;IDC_ARROW
        mov     [wc.hCursor],eax
        invoke  RegisterClass,wc
        test    eax,eax
        jz      error

        invoke  GdiplusStartup, token, input, NULL 
        test    eax, eax
        jnz     error

        invoke  CreateWindowEx,0,_class,_title,WS_VISIBLE+WS_CAPTION+WS_SYSMENU+WS_THICKFRAME,128,100,740,576,NULL,NULL,[wc.hInstance],NULL
        test    eax,eax
        jz      error

  msg_loop:
        invoke  GetMessage,msg,NULL,0,0  
        cmp     eax,1 
        jb      end_loop  
        jne     msg_loop
        invoke  TranslateMessage,msg
        invoke  DispatchMessage,msg  
        jmp     msg_loop

  error:
        invoke  MessageBox,NULL,_error,NULL,MB_ICONERROR+MB_OK

  end_loop:
        invoke  GdiplusShutdown, [token]
        invoke  ExitProcess,[msg.wParam]  

GetModuleHandle 用于获取一个应用程序或动态链接库的模块句柄,前提是目的模块已映射到调用该函数的进程内

LoadCursor 从一个与相关的可执行文件中载入指定的光标资源

test用于将两个操作数进行逻辑与运算,并根据结果设置标志位(不影响进行运算的两个数本身

窗口进程相关

proc WindowProc hwnd,umsg,wparam,lparam
local ps:PAINTSTRUCT

        push    ebx esi edi

        cmp     [wmsg],WM_DESTROY
        je      .wmdestroy

        cmp     [wmsg], WM_PAINT
        je      .wmpaint

  .defwndproc:
        invoke  DefWindowProc,[hwnd],[wmsg],[wparam],[lparam]
        jmp     .finish

  .wmpaint:
        invoke  BeginPaint, [hwnd], addr ps 

        stdcall draw, eax, $FF000000
        invoke  EndPaint, [hwnd], addr ps
        jmp     .finish_ret_0

  .wmdestroy:
        invoke  PostQuitMessage,0

  .finish_ret_0:
        xor     eax,eax

  .finish:
        pop     edi esi ebx
        ret
endp

WindowProc 是一个用于处理发送给窗口消息的函数

其中的参数 hwnd 指向窗口的句柄,uMsg 为消息类型,wparamlparam 为其它的消息

画画

proc draw hdc, color
local pGraphics:DWORD, pPen:DWORD, pBrush:DWORD

  invoke  GdipCreateFromHDC, [hdc], addr pGraphics
  invoke  GdipCreatePen1, [color], 3.0, 2, addr pPen
  invoke  GdipGetPenBrushFill, [pPen], addr pBrush
  ;创建场景句柄/画笔兑现/刷子对象

  invoke  GdipSetSmoothingMode, [pGraphics], 2

  push ebx
  mov ebx, 1
  invoke  GdipDrawRectangleI, [pGraphics], [pPen], addr 250+ebx*8, addr 100+ebx*8, addr 200+ebx*8, addr 200+ebx*8
  invoke  GdipFillEllipseI, [pGraphics], [pBrush], addr 300+ebx*8, addr 140+ebx*8, addr 10+ebx*8, addr 25+ebx*8
  ;以下省略n条画画步骤
  ;[pGraphics]参数是指向对象的指针,[pPen]参数是指向画线的“笔”的指针,后面参数用于画图对象的具体长宽高等
  pop ebx
  ret
endp

invoke 用于使用第一个参数间接调用进程(fastcall用于直接调用)

lea Load effective address 加载有效地址,将有效地址传送到指定的寄存器

参考资料:
FASM官方文档