【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
watermelon 发表于 2018-11-19 12:07
站长好贴心把build.bat和nasm.exe都给了出来,移到当前目录双击bat就出来了EXE真的方便。
NASM写的程序很 ...
其实不是……而是我把.rdata段的内容合并到.text段了(虽然这样做并不好)少了一个段,就少了一个必须要对齐的东西,从而压缩了体积。
另外你对WideCharToMultiByte的调用让我看了觉得累得慌……如果是我,我就直接使用W系API了 为了练手,我也用汇编写了一个自己的版本,用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
你可以把“标识符”理解为“名字”,把“生成标识符”理解为“起名字”。
我造了个com类我应该叫它什么呢?起个GUID吧。有个用户注册了新账号我应该怎么代表这个用户呢?用GUID吧。我生产了一万台设备,它和服务器交互的时候,服务器怎么分出谁是谁呢?用GUID作为机器码吧。 0xAA55 发表于 2018-11-16 07:00
你可以把“标识符”理解为“名字”,把“生成标识符”理解为“起名字”。
我造了个com类我应该叫它什么呢 ...
感谢站长鼓励和指导,小弟我get到啦:D 挺想说的是,Visual Studio一直是自带GUID生成器的,而且还可以辅助格式化。
tangptr@126.com 发表于 2018-11-18 11:34
挺想说的是,Visual Studio一直是自带GUID生成器的,而且还可以辅助格式化。
...
啊,果然是啊,谢谢tangptr大佬指导 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 0xAA55 发表于 2018-11-19 08:29
为了练手,我也用汇编写了一个自己的版本,用NASM写的。编译的时候需要nasm编译器,以及,随便找一个链接器 ...
小弟我还得再仔细研读一下程序,看看这个手动找到kernel32.dll和里面函数的:D 0xAA55 发表于 2018-11-19 12:15
其实不是……而是我把.rdata段的内容合并到.text段了(虽然这样做并不好)少了一个段,就少了一个必须要 ...
:-O,有道理 没钱好痛苦啊啊啊啊
页:
[1]