watermelon 发表于 2018-11-16 02:57:17

【Win32Asm】生成GUID的对话框

本帖最后由 watermelon 于 2018-11-16 02:59 编辑

不知道什么时候开始,好像是前两天,群里的QQ小冰29号大佬开始给自己的ID上了一串“乱七八糟”的字符串,随之系统消息(这里要指明是管理员那个系统消息)大佬也给自己的ID后面上了一串字符串。
当时我不明白这个是什么,感觉看起来很晦涩,好像密码一样,后来从他们吹水的过程中了解到这个原来是GUID。

GUID全称为Globally Unique Identifier,翻译为:全局唯一标识符。百度百科说:“全局唯一标识符(GUID,Globally Unique Identifier)是一种由算法生成的二进制长度为128位的数字标识符。GUID主要用于在拥有多个节点、多台计算机的网络或系统中。在理想情况下,任何计算机和计算机集群都不会生成两个相同的GUID。GUID 的总数达到了2^128(3.4×10^38)个,所以随机生成两个相同GUID的可能性非常小,但并不为0。所以,用于生成GUID的算法通常都加入了非随机的参数(如时间),以保证这种重复的情况不会发生。” “在 Windows 平台上,GUID 广泛应用于微软的产品中,用于标识如注册表项、类及接口标识、数据库、系统目录等对象。”   ----百度百科GUID

现在了解了,原来QQ小冰29号和系统消息大佬们给自己上的是全局唯一标识符,意思就是独一无二呗。
所以小弟就想写一个能生成GUID的对话框,一个目的是温习罗云彬大大给教的Win32Asm,另一个目的是我想弄出来。

我们从网上百度可以知道要弄GUID可以用API函数CoCreateGuid和GUID转化为字符串的函数StringFromGUID2,这个就常规invoke调用就行。但是我写好后发现结果不对,他是乱码啊,只出现几个汉字,这显然是错误的。后来百度发现原来还要进行字符集之间的转换,好吧。

这个程序的一大费力的事情就是自己对资源文件进行编写。什么坐标,长度,宽度都要考虑进去,为了对称美观小弟花了好长时间功夫(实际上UI的设计我还是没有长进)

下面小弟就放上程序,希望各位大佬多多批评指针。

资源文件:
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
#include                <resource.h>
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
#define        ICO_MAIN                0x1000        //图标
#define        DLG_MAIN                1
#define        IDC_GUIDTEXT        101
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
ICO_MAIN        ICON                "Main.ico"
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
DLG_MAIN DIALOG 280, 180, 240, 100
STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
CAPTION "watermelon GUID generator"
FONT 9, "宋体"
{
CTEXT "Passion Coding, Yeah!!!", -1, 125, 80, 120, 20
EDITTEXT IDC_GUIDTEXT, 40, 20, 160, 15
DEFPUSHBUTTON "开始生成(&S)", IDOK, 95, 48, 50, 20
}
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>


源程序:
;本程序由watermelon进行编写,目的是生成GUID
                .386
                .model flat, stdcall
                option casemap :none
               
include                windows.inc
include                user32.inc
includelib        user32.lib
include                kernel32.inc
includelib        kernel32.lib
include                gdi32.inc
includelib        gdi32.lib
include                advapi32.inc
includelib        advapi32.lib
include                comctl32.inc
includelib         comctl32.lib
include         shell32.inc
includelib        shell32.lib
include         ws2_32.inc
includelib        ws2_32.lib
include         ole32.inc
includelib        ole32.lib


;等值定义
ICO_MAIN        equ                1000h        ;图标
DLG_MAIN        equ                1
IDC_GUIDTEXT        equ                101


                .data
hInstance        dd                ?


                .code
;对话框过程
_ProcDlgMain        proc        uses ebx edi esi hWnd,wMsg,wParam,lParam
                LOCAL        @szBuffer:byte        ;用于存放生成的GUID
                LOCAL        @guid:GUID                ;定义一个GUID结构体
                LOCAL        @result:byte        ;用于存放最终的结果

                mov        eax,wMsg
                .if        eax == WM_CLOSE
                        invoke        EndDialog,hWnd,NULL
                .elseif        eax == WM_INITDIALOG
                        invoke        LoadIcon,hInstance,ICO_MAIN
                        invoke        SendMessage,hWnd,WM_SETICON,ICON_BIG,eax
                        invoke        GetDlgItem,hWnd,IDC_GUIDTEXT                ;初始时候先灰化
                        invoke        EnableWindow,eax,FALSE
                .elseif        eax == WM_COMMAND
                        mov        eax,wParam
                        .if        ax == IDOK
                                ;TODO :这里开始写生成GUID的程序,运用CoCreateGuid
                                invoke        GetDlgItem,hWnd,IDC_GUIDTEXT
                                invoke        EnableWindow,eax,TRUE                ;将EDITTEXT激活
                               
                                ;下面开始获取GUID和最终的结果
                                invoke        CoCreateGuid,addr @guid
                                ;将GUID转化为字符串
                                invoke        StringFromGUID2,addr @guid,addr @szBuffer,sizeof @szBuffer
                                ;字符集之间的转化,否则会出现显示不全或者乱码的情况
                                .if        eax
                                        invoke        WideCharToMultiByte,CP_UTF8,0,\
                                                addr @szBuffer,-1,addr @result,\
                                                sizeof @result,NULL,NULL
                                        invoke        SetDlgItemText,hWnd,IDC_GUIDTEXT,addr @result
                                .else
                                        invoke        SetDlgItemText,hWnd,IDC_GUIDTEXT,addr @szBuffer
                                .endif
                        .endif
                .else
                        mov        eax,FALSE
                        ret
                .endif
                mov        eax,TRUE
                ret

_ProcDlgMain        endp

start:
                invoke        GetModuleHandle,NULL
                mov        hInstance,eax
                invoke        DialogBoxParam,hInstance,DLG_MAIN,NULL,offset _ProcDlgMain,NULL        ;模态对话框
                invoke        ExitProcess,NULL
end        start


附上运行时候的图片

EXE的图标来自歌曲:Alone   ---Wisp X/初音未来(QQ音乐),感谢深夜陪我一起passion coding

0xAA55 发表于 2018-11-19 12:15:09

watermelon 发表于 2018-11-19 12:07
站长好贴心把build.bat和nasm.exe都给了出来,移到当前目录双击bat就出来了EXE真的方便。
NASM写的程序很 ...

其实不是……而是我把.rdata段的内容合并到.text段了(虽然这样做并不好)少了一个段,就少了一个必须要对齐的东西,从而压缩了体积。

另外你对WideCharToMultiByte的调用让我看了觉得累得慌……如果是我,我就直接使用W系API了

0xAA55 发表于 2018-11-19 08:29:16

为了练手,我也用汇编写了一个自己的版本,用NASM写的。编译的时候需要nasm编译器,以及,随便找一个链接器就好。
不依赖任何lib(自己找出kernel32.dll的地址,然后从kernel32.dll里面找到LoadLibrary等各种函数,再加载需要的DLL使用)
整个程序只有2KB。




global _start

segment .text
_start:
;找到kernel32.dll的地址
mov eax,                 ; EAX = &PEB
mov eax,         ; EAX = &(PEB->Ldr)
mov eax,         ; EAX = PEB->Ldr.InMemOrder.Flink (当前exe)
mov ebx,         ; EBX = 当前EXE的基址
mov , ebx
mov eax,                         ; EAX = Flink(ntdll.dll)
mov eax,                         ; EAX = Flink(kernel32.dll)
mov ebx,         ; EBX = kernel32.dll的基址
mov , ebx

;找到导出表
mov edx,         ; EDX = DOS->e_lfanew
add edx, ebx                        ; EDX = PE头
mov edx,         ; EDX = 导出表偏移
add edx, ebx                        ; EDX = 导出表
mov esi,         ; ESI = 名字表偏移
add esi, ebx                        ; ESI = 名字表

;找到GetProcAddress的序号
xor ecx,ecx
.LoopGetFunc:
inc ecx
lodsd
add eax, ebx                        ; EAX = 函数名
cmp dword , 'GetP'
jnz .LoopGetFunc
cmp dword , 'rocA'
jnz .LoopGetFunc
cmp dword , 'ddre'
jnz .LoopGetFunc
cmp word , 'ss'
jnz .LoopGetFunc

;按着序号取得GetProcAddress的地址
mov esi,     ; ESI = 序号表偏移
add esi, ebx             ; ESI = 序号表
mov cx, ; CX = 函数序号
dec ecx
mov esi,     ; ESI = 地址表偏移
add esi, ebx             ; ESI = 地址表
mov edx, ; EDX = 指针(偏移)
add edx, ebx             ; EDX = GetProcAddress
mov ,edx

;调用GetProcAddress取得LoadLibrary的地址
push _name_of_LoadLibraryA
push ebx                ; Kernel32基址
call edx                ; GetProcAddress
mov , eax

;取得ExitProcess的地址
push _name_of_ExitProcess
push dword
call
mov , eax

;使用LoadLibrary加载user32.dll
push _name_of_user32
call
mov , eax

;使用LoadLibrary加载ole32.dll
push _name_of_ole32
call
mov , eax

;使用LoadLibrary加载gdi32.dll
push _name_of_gdi32
call
mov , eax

;从User32导入需要的符号
mov esi, _NameList_User32
mov edi, _imp_from_user32
mov ecx, _num_imp_user32
mov ebp,
.ImpFromUser32:
push ecx
lodsd
push eax
push ebp
call
or eax,eax
jnz .store_user32
int3
.store_user32:
stosd
pop ecx
loop .ImpFromUser32

;从Ole32导入需要的符号
mov esi, _NameList_Ole32
mov edi, _imp_from_ole32
mov ecx, _num_imp_ole32
mov ebp,
.ImpFromOle32:
push ecx
lodsd
push eax
push ebp
call
or eax,eax
jnz .store_ole32
int3
.store_ole32:
stosd
pop ecx
loop .ImpFromOle32

;从Gdi32导入需要的符号
mov esi, _NameList_Gdi32
mov edi, _imp_from_gdi32
mov ecx, _num_imp_gdi32
mov ebp,
.ImpFromGdi32:
push ecx
lodsd
push eax
push ebp
call
or eax,eax
jnz .store_gdi32
int3
.store_gdi32:
stosd
pop ecx
loop .ImpFromGdi32


;====创建窗口====
mov dword , 48
mov dword , _wnd_proc
mov dword , 16
mov dword , _ClassName

push 32512 ; IDC_ARROW
push 0
call
mov , eax

;用新的GUID当作窗口类名
call _update_guid
mov esi, _StringGUID
mov edi, _ClassName
mov ecx, 20
rep movsd

;把开头的{替换为c,把中间的横杠替换为下划线,把最后的}替换为'\0'
mov word , 'c'
mov ax,'_'
mov , ax
mov , ax
mov , ax
mov , ax
mov word , 0

push _WCEx
call

;创建窗口
push 0                                                ;lpParam
push dword        ;hInstance
push 0                                                ;hMenu
push 0                                                ;hWndParent
push 200                                        ;Height
push 320                                        ;Width
push 0x80000000                                ;Y
push 0x80000000                                ;X
push 0x00CA0000                                ;dwStyle
push _WindowTitle                        ;lpWindowName
push eax                                        ;lpClassName
push 0                      ;dwExStyle
call
mov ,eax

push 1
push dword
call

push dword
call

;====消息循环====
.msgloop:
push 0
push 0
push 0
push _msg
call
or eax, eax
jz .loopout

push _msg
call
push _msg
call

jmp .msgloop
.loopout:

push dword
call
ret

;====函数:生成GUID====
_update_guid:
;生成二进制的GUID
push dword _BinGUID
call

;生成GUID的字符串
push dword 40
push dword _StringGUID
push dword _BinGUID
call
ret

;====消息处理函数====
_wnd_proc:
mov eax, ;读取消息
;然后判断是啥
cmp eax, 1
je .wm_create

cmp eax, 2
je .wm_destroy

cmp eax, 0x111
je .wm_command

.default_msg:
jmp

.wm_create:
;取得系统默认字体
push 17 ;DEFAULT_GUI_FONT
call
mov , eax

;创建控件——文本标签
push 0                                                ;lpParam
push dword        ;hInstance
push 100                                        ;hMenu
push dword                        ;hWndParent
push 17                                                ;Height
push 273                                        ;Width
push 24                                                ;Y
push 16                                                ;X
push 0x50000000                                ;dwStyle
push _StaticTitle                        ;lpWindowName
push _Ctrl_Static                        ;lpClassName
push 0                      ;dwExStyle
call

push 1
push dword
push 0x0030 ; WM_SETFONT
push eax
call

;创建控件——文本框
push 0                                                ;lpParam
push dword        ;hInstance
push 101                                        ;hMenu
push dword                        ;hWndParent
push 18                                                ;Height
push 273                                        ;Width
push 48                                                ;Y
push 16                                                ;X
push 0x50810800                                ;dwStyle
push _StringGUID                        ;lpWindowName
push _Ctrl_Edit                                ;lpClassName
push 0                      ;dwExStyle
call
mov , eax

push 1
push dword
push 0x0030 ; WM_SETFONT
push eax
call

;创建控件——按钮
push 0                                                ;lpParam
push dword        ;hInstance
push 102                                        ;hMenu
push dword                        ;hWndParent
push 33                                                ;Height
push 89                                                ;Width
push 128                                        ;Y
push 16                                                ;X
push 0x50000001                                ;dwStyle
push _ButtonTitle                        ;lpWindowName
push _Ctrl_Button                        ;lpClassName
push 0                      ;dwExStyle
call
mov , eax

push 1
push dword
push 0x0030 ; WM_SETFONT
push eax
call

xor eax, eax
ret 16

.wm_command:
mov eax,
cmp ax,102 ;按钮的ID
jnz .default_msg

shr eax,16
cmp ax,0 ;是否为按钮按下的消息
jnz .default_msg

;按钮按下,更新GUID
call _update_guid
push _StringGUID
push dword
call

xor eax,eax
ret 16

.wm_destroy:
push 0
call
xor eax,eax
ret 16


; segment .rdata
_name_of_LoadLibraryA db "LoadLibraryA", 0
_name_of_ExitProcess db "ExitProcess", 0

_name_of_user32 db "user32.dll", 0
_name_of_LoadCursor db "LoadCursorA", 0
_name_of_RegisterClassEx db "RegisterClassExW", 0
_name_of_CreateWindowExA db "CreateWindowExA", 0
_name_of_CreateWindowExW db "CreateWindowExW", 0
_name_of_SetWindowText db "SetWindowTextW", 0
_name_of_PostQuitMessage db "PostQuitMessage", 0
_name_of_ShowWindow db "ShowWindow", 0
_name_of_UpdateWindow db "UpdateWindow", 0
_name_of_GetMessage db "GetMessageA", 0
_name_of_PostMessage db "PostMessageA", 0
_name_of_TranslateMessage db "TranslateMessage", 0
_name_of_DispatchMessage db "DispatchMessageA", 0
_name_of_DefWindowProc db "DefWindowProcA", 0

_name_of_ole32 db "ole32.dll", 0
_name_of_CoCreateGuid db "CoCreateGuid", 0
_name_of_StringFromGUID2 db "StringFromGUID2", 0

_name_of_gdi32 db "gdi32.dll", 0
_name_of_GetStockObject db "GetStockObject", 0

_NameList_User32:
dd _name_of_LoadCursor
dd _name_of_RegisterClassEx
dd _name_of_CreateWindowExA
dd _name_of_CreateWindowExW
dd _name_of_SetWindowText
dd _name_of_PostQuitMessage
dd _name_of_ShowWindow
dd _name_of_UpdateWindow
dd _name_of_GetMessage
dd _name_of_PostMessage
dd _name_of_TranslateMessage
dd _name_of_DispatchMessage
dd _name_of_DefWindowProc
_num_imp_user32 equ ($ - _NameList_User32) / 4

_NameList_Ole32:
dd _name_of_CoCreateGuid
dd _name_of_StringFromGUID2
_num_imp_ole32 equ ($ - _NameList_Ole32) / 4

_NameList_Gdi32:
dd _name_of_GetStockObject
_num_imp_gdi32 equ ($ - _NameList_Gdi32) / 4

_Ctrl_Static db "STATIC", 0
_Ctrl_Edit dw "E", "D", "I", "T", 0 ;因为生成的GUID字符串是宽字符,所以用W方式的API来弄它相关的
_Ctrl_Button db "BUTTON", 0
_WindowTitle db "GUID Generator", 0
_StaticTitle db "New GUID:", 0
_ButtonTitle db "&Generate", 0

segment .bss
_addr_of_Kernel32 resd 1
_addr_of_User32 resd 1
_addr_of_Ole32 resd 1
_addr_of_Gdi32 resd 1

_addr_of_GetProcAddress        resd 1
_addr_of_LoadLibraryA resd 1
_addr_of_ExitProcess resd 1

_imp_from_user32:
_addr_of_LoadCursor resd 1
_addr_of_RegisterClassEx resd 1
_addr_of_CreateWindowExA resd 1
_addr_of_CreateWindowExW resd 1
_addr_of_SetWindowText resd 1
_addr_of_PostQuitMessage resd 1
_addr_of_ShowWindow resd 1
_addr_of_UpdateWindow resd 1
_addr_of_GetMessage resd 1
_addr_of_PostMessage resd 1
_addr_of_TranslateMessage resd 1
_addr_of_DispatchMessage resd 1
_addr_of_DefWindowProc resd 1

_imp_from_ole32:
_addr_of_CoCreateGuid resd 1
_addr_of_StringFromGUID2 resd 1

_imp_from_gdi32:
_addr_of_GetStockObject resd 1

_BinGUID                resd 4
_StringGUID                resw 40
_ClassName                resw 40        ;窗口类名(直接用GUID来取)
_hWnd                        resd 1
_hWnd_TextBox        resd 1
_hWnd_Button        resd 1

_DefFont resd 1 ;默认字体

_WCEx:                        ;WNDCLASSEX结构
.cbSize                        resd 1
.style                        resd 1
.lpfnWndProc        resd 1
.cbClsExtra                resd 1
.cbWndExtra                resd 1
.hInstance                resd 1
.hIcon                        resd 1
.hCursor                resd 1
.hbrBackground        resd 1
.lpszMenuName        resd 1
.lpszClassName        resd 1
.hIconSm                resd 1

_msg:
.hwnd                        resd 1
.message                resd 1
.wParam                        resd 1
.lParam                        resd 1
.time                        resd 1
.ptx                        resd 1
.pty                        resd 1

0xAA55 发表于 2018-11-16 07:00:15

你可以把“标识符”理解为“名字”,把“生成标识符”理解为“起名字”。

我造了个com类我应该叫它什么呢?起个GUID吧。有个用户注册了新账号我应该怎么代表这个用户呢?用GUID吧。我生产了一万台设备,它和服务器交互的时候,服务器怎么分出谁是谁呢?用GUID作为机器码吧。

watermelon 发表于 2018-11-16 11:05:59

0xAA55 发表于 2018-11-16 07:00
你可以把“标识符”理解为“名字”,把“生成标识符”理解为“起名字”。

我造了个com类我应该叫它什么呢 ...

感谢站长鼓励和指导,小弟我get到啦:D

唐凌 发表于 2018-11-18 11:34:58

挺想说的是,Visual Studio一直是自带GUID生成器的,而且还可以辅助格式化。

watermelon 发表于 2018-11-18 18:34:48

tangptr@126.com 发表于 2018-11-18 11:34
挺想说的是,Visual Studio一直是自带GUID生成器的,而且还可以辅助格式化。

...

啊,果然是啊,谢谢tangptr大佬指导

watermelon 发表于 2018-11-19 12:07:08

0xAA55 发表于 2018-11-19 08:29
为了练手,我也用汇编写了一个自己的版本,用NASM写的。编译的时候需要nasm编译器,以及,随便找一个链接器 ...

站长好贴心把build.bat和nasm.exe都给了出来,移到当前目录双击bat就出来了EXE真的方便。
NASM写的程序很规矩,小弟我看了好像是站长没有写资源文件,把控件的一些特性(例如资源ID直接写成了数值)。还有就是站长一开始强调的不依赖任何lib,自己找出kernel32.dll的地址,然后只加载这个程序所需要的dll和各种导出函数来使用,我刚刚自己又把我的程序去掉图片编译了一下,发现我的大小是3.00KB(3,072字节),而站长的是2.00KB(2,048字节)。看来是站长的手动找kernel32.dll地址然后后面自己找函数起了作用。orz

watermelon 发表于 2018-11-19 12:10:30

0xAA55 发表于 2018-11-19 08:29
为了练手,我也用汇编写了一个自己的版本,用NASM写的。编译的时候需要nasm编译器,以及,随便找一个链接器 ...

小弟我还得再仔细研读一下程序,看看这个手动找到kernel32.dll和里面函数的:D

watermelon 发表于 2018-11-19 16:06:30

0xAA55 发表于 2018-11-19 12:15
其实不是……而是我把.rdata段的内容合并到.text段了(虽然这样做并不好)少了一个段,就少了一个必须要 ...

:-O,有道理

Si515 发表于 2018-11-20 18:06:36

没钱好痛苦啊啊啊啊
页: [1]
查看完整版本: 【Win32Asm】生成GUID的对话框