[32位汇编系列]005 - 定时器的使用(2)

本文详细分析了一段32位汇编代码,涉及定时器的使用。程序通过对话框显示实时时钟,重点讨论了处理WM_TIMER消息的窗口过程,包括调用GetLocalTime获取当前时间,使用wsprintf格式化日期和时间,并通过SetTimer和KillTimer设置及销毁定时器。此外,提到了函数参数和wsprintf的__cdecl调用约定注意事项。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

上一篇文章 中, 说了定时器的使用, 程序中用一个对话框来显示一个实时时钟, 本节主要来看看这个程序的反汇编代码。

返汇编代码和汇编代码一样, 也主要分成2个部分, 一个是程序入口, 利用对话框资源来显示一个对话框;另一个是对话框的窗口过程,处理了3个我们感兴趣的消息。

 

下面是反汇编代码:

 

00401000  /.  55            push    ebp
00401001  |.  8BEC          mov     ebp, esp
00401003  |.  81C4 70FFFFFF add     esp, -90

保存堆栈寄存器,并预留局部变量空间

 

00401009  |.  8B45 0C       mov     eax, dword ptr [ebp+C]

mov eax, uMsg

 

0040100C  |.  3D 13010000   cmp     eax, 113                         ;  Switch (cases 10..113)

cmp eax, WM_TIMER 看看是不是WM_TIMER消息

 

00401011  |.  75 51         jnz     short 00401064

不是, 则转入下一个消息的比较

 

00401013  |.  8D45 F0       lea     eax, dword ptr [ebp-10]          ;  Case 113 (WM_TIMER) of switch

lea eax, @stTime  获取结构@stTime地址

 

0040100C
00401016  |.  50            push    eax                              ; /pLocaltime
00401017  |.  E8 E2000000   call    <jmp.&kernel32.GetLocalTime>     ; /GetLocalTime

将结构@stTime地址作为参数, 调用GetLocalTime获取当前的时间

 

0040101C  |.  0FB745 FC     movzx   eax, word ptr [ebp-4]
00401020  |.  50            push    eax                              ; /<%02d>
00401021  |.  0FB745 FA     movzx   eax, word ptr [ebp-6]            ; |
00401025  |.  50            push    eax                              ; |<%02d>
00401026  |.  0FB745 F8     movzx   eax, word ptr [ebp-8]            ; |
0040102A  |.  50            push    eax                              ; |<%02d>
0040102B  |.  0FB745 F6     movzx   eax, word ptr [ebp-A]            ; |
0040102F  |.  50            push    eax                              ; |<%02d>
00401030  |.  0FB745 F2     movzx   eax, word ptr [ebp-E]            ; |
00401034  |.  50            push    eax                              ; |<%02d>
00401035  |.  0FB745 F0     movzx   eax, word ptr [ebp-10]           ; |
00401039  |.  50            push    eax                              ; |<%04d>

将@stTime结构的其中6个成员的word类型数据转换为dword类型,并且按照

秒分时日月年的顺序入栈

 

0040103A  |.  68 2C204000   push    0040202C                         ; |Format = "%04d-%02d-%02d %02d:%02d:%02d"

将结构化字符串的地址入栈

 

0040103F  |.  8D85 70FFFFFF lea     eax, dword ptr [ebp-90]          ; |

获取局部变量@szBuf的地址

 

00401045  |.  50            push    eax                              ; |s

将局部变量@szBuf地址入栈

 

00401046  |.  E8 89000000   call    <jmp.&user32.wsprintfA>          ; /wsprintfA

调用wsprintf 这个唯一的采用__cdecl调用约定的win32 api, 格式化字符串, 保存在@szBuf中

 

0040104B  |.  83C4 20       add     esp, 20

因为wsprintf 采用__cdecl调用约定,故调用者必须自己清理栈空间, 维持栈的平衡

 

0040104E  |.  8D85 70FFFFFF lea     eax, dword ptr [ebp-90]
00401054  |.  50            push    eax                              ; /Text
00401055  |.  68 E8030000   push    3E8                              ; |ControlID = 3E8 (1000.)
0040105A  |.  FF75 08       push    dword ptr [ebp+8]                ; |hWnd
0040105D  |.  E8 8A000000   call    <jmp.&user32.SetDlgItemTextA>    ; /SetDlgItemTextA

调用SetDlgItemText函数

将格式化字符串也就是当前的时间 按照 yyyy-mm-dd HH:MM:SS 的形式显示在静态文本框中

 

00401062  |.  EB 3E         jmp     short 004010A2

处理完毕, 退出过程

 

00401064  |>  3D 10010000   cmp     eax, 110

cmp eax, WM_INITDIALOG   看看是不是WM_INITDIALOG消息

 

00401069  |.  75 13         jnz     short 0040107E

不是, 则转入下一个消息判断

 

0040106B  |.  6A 00         push    0                                ; /Timerproc = NULL; Case 110 (WM_INITDIALOG) of switch 0040100C
0040106D  |.  68 E8030000   push    3E8                              ; |Timeout = 1000. ms
00401072  |.  6A 01         push    1                                ; |TimerID = 1
00401074  |.  FF75 08       push    dword ptr [ebp+8]                ; |hWnd
00401077  |.  E8 76000000   call    <jmp.&user32.SetTimer>           ; /SetTimer

在WM_INITDIALOG消息中, 用SetTimer设置定时器, 时间间隔为1秒

 

0040107C  |.  EB 24         jmp     short 004010A2

WM_INITDIALOG处理完毕, 退出过程

 

0040107E  |>  83F8 10       cmp     eax, 10

cm eax, WM_CLOSE 看看是不是WM_CLOSE消息

 

00401081  |.  75 16         jnz     short 00401099

不是, 则转入默认消息处理

 

00401083  |.  6A 01         push    1                                ; /TimerID = 1; Case 10 (WM_CLOSE) of switch 0040100C
00401085  |.  FF75 08       push    dword ptr [ebp+8]                ; |hWnd
00401088  |.  E8 59000000   call    <jmp.&user32.KillTimer>          ; /KillTimer

调用KillTimer销毁定时器

 

0040108D  |.  6A 00         push    0                                ; /Result = 0
0040108F  |.  FF75 08       push    dword ptr [ebp+8]                ; |hWnd
00401092  |.  E8 49000000   call    <jmp.&user32.EndDialog>          ; /EndDialog

调用EndDialog结束对话框

 

00401097  |.  EB 09         jmp     short 004010A2

WM_CLOSE消息处理完毕,退出过程

 

00401099  |>  B8 00000000   mov     eax, 0                           ;  Default case of switch 0040100C
0040109E  |.  C9            leave
0040109F  |.  C2 1000       retn    10

默认消息处理

 

004010A2  |>  B8 01000000   mov     eax, 1
004010A7  |.  C9            leave
004010A8  /.  C2 1000       retn    10

处理完感兴趣的消息,窗口过程返回

 

以下是程序入口:

004010AB >/$  6A 00         push    0                                ; /pModule = NULL
004010AD  |.  E8 52000000   call    <jmp.&kernel32.GetModuleHandleA> ; /GetModuleHandleA
004010B2  |.  A3 00304000   mov     dword ptr [403000], eax
004010B7  |.  6A 00         push    0                                ; /lParam = NULL
004010B9  |.  68 00104000   push    00401000                         ; |DlgProc = clock.00401000
004010BE  |.  6A 00         push    0                                ; |hOwner = NULL
004010C0  |.  6A 65         push    65                               ; |pTemplate = 65
004010C2  |.  FF35 00304000 push    dword ptr [403000]               ; |hInst = NULL
004010C8  |.  E8 0D000000   call    <jmp.&user32.DialogBoxParamA>    ; /DialogBoxParamA
004010CD  |.  6A 00         push    0                                ; /ExitCode = 0
004010CF  /.  E8 24000000   call    <jmp.&kernel32.ExitProcess>      ; /ExitProcess


每个使用对话框资源的窗口的入口几乎都是一样, 所以, 在此就不再重复的去解释。

 

整个程序关键就在于四个api:

SetTimer

KillTimer

GetLocalTime

wsprintf

 

需要注意的有2点:

1. 在32位汇编中的函数参数数据类型以及返回值都是32位的, 如果不是32位的, 必须先用movzx或者movsx扩充为32位的

2. wsprintf采用的是__cdecl 调用约定, 需要调用者自己平衡堆栈

<script src="http://pagead2.googlesyndication.com/pagead/show_ads.js" type="text/javascript"></script>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值