[编程工具]masm32(9.00)+RadAsm2.2.0.9
[调试工具]OD1.10  VC++6.0
[调试平台]WinXP/SP2+QQ2006

  在这里我首先感谢看雪给我们提供的许多强大的编程及调试工具,对于我们新手来说,有RadAsm这样的工具简直就是天大的幸运,RadAsm友好的界面与提示功能很容易上手,而OD的强大的分析能力让我调试更方便,OD所加的注释比我写的注释还要详细。
  以前我一直用VC++,觉得他十分强大,只有你想不到的,没有他做不到的,在坛子里泡久了,发现也有VC不容易做到的事情。而坛子中的许多高手编写的东西都用了asm,我看起来有点吃力,就想学学asm编程。真是难者不会,会者不难,想起来容易,做起来难啊,我可是吃了许多苦头才完成的,谁叫我太$#@*呢。写出来只是想给一些想学asm编程而又没能开始的新手增加一点信心,我这样的大笨都开始学了,你们那些大聪怎么能不学呢?另外,也想听听大牛们给我指出不足,教我两招^O^.
  去年的这个时候不小心中了流氓广告的招,它就是每隔几分钟就给所有QQ聊天者发一条广告。我觉得既好气又好玩,后来就用VC++6.0编了一个。现在我就把那个用VC写的东西,改写成asm语言的。用VC写的时候用了MFC,用静态链接竟然有200KB以上,用动态链接也有24KB之多,而用asm编出来只有不到6KB的大小。比一比,这VC&MFC在代码中加了多少垃圾啊!
  代码中用到的都是一些初级的技术,但在给EnumWindows函数写EnumWindowsProc回调函数的时候,由于我没经验遇到了个大麻烦,花去了我半天的时间。试运行时发现,每当我点击“发送”按钮的时候程序就失去了响应,用OD和VC调试忙了半天也没有找到原因。后来我重启系统,再运行,系统提示非法操作,点击“调试”之后进入VC中停在系统领空中有 ds[edi] 字样的一行上,我恍然大悟:因为我在_EnumWindowsProc代码中用了edi寄存器而又没有用“uses edi”或“push edi/pop edi”保护edi!看来EnumWindows内部没有把重要的数据保存起来,应该是自己的东西自己保护吧?这个现在却要我来保护?我怎么知道你api内部哪些寄存器不能改变?总不能每次函数开始前先来一段push之类的吧?其它的一些函数就不是这样的呀,之前我在编写_SaveMsg proc时没保存edi不是一直没有出错嘛。我很想知道象EnumWindows函数这样自己不保护自己的api函数还有哪些。这不但可以防止编程出错,还可以用来保护我们的软件不被破解吧?!比如你的代码中用到了这样的函数,你就可以把edi的值取出来加密之后保存在某个地方,等你的函数退出之前再取出edi的值解密,如果软件未被破解,edi解出原来的值程序不会出问题,一但被破解,会解出错误的edi值,从而使程序变得很不稳定,不是失去响应就是非法操作的。我这样的想法是不是很荒唐?请大家指教。找到出错原因后我一气之下改了代码,不用那个edi了,也没去保护它,正常运行了。主要的代码在下面:

.386
.model flatstdcall  ;32 bit memory model
option casemap :none  ;case sensitive

include QQ自动群发器.inc

.code

start:
    invoke    InitCommonControls
    invoke    GetModuleHandle,NULL
    invoke    DialogBoxParam,eax,IDD_MAINDIALOG,NULL,addr DlgProc,NULL
    invoke    ExitProcess,0

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; _rand    随机数产生子程序
; 输入:要产生的随机数的最大值,输出:小于_dwMax的随机数
; 根据:
; 1. 数学公式 Rnd=(Rnd*I+J) mod K 循环回带生成 K 次以内不重复的
;    伪随机数,但K,I,J必须为素数
; 2. 2^(2n-1)-1 必定为素数(即2的奇数次方减1)
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
_Random16    proc

        push    edx
        mov    eax,dwRandom
        mov    ecx,32768-1    ;2^15-1
        mul    ecx
        add    eax,2048-1    ;2^11-1
        adc    edx,0
        mov    ecx,2147483647    ;2^31-1
        div    ecx
        mov    eax,dwRandom
        mov    dwRandom,edx
        and    eax,0000ffffh
        pop    edx
        ret

_Random16    endp

_rand    proc     _dwMax:DWORD  ;uses ebx ecx edx

        invoke    _Random16
        mov    edx,eax
        invoke    _Random16
        shl    eax,16
        or    ax,dx
        mov    ecx,_dwMax
        or    ecx,ecx
        jz    @f
        xor    edx,edx
        div    ecx
        mov    eax,edx
        @@:
        ret

_rand    endp

;*********************************************************************************
;初始化工作:读文件内容填入列表;设默认值;初始化随机数
;*********************************************************************************
_initDlg proc
    LOCAL    @hMem:HANDLE
    LOCAL    @hFile:HANDLE
    LOCAL    @pMem:HANDLE
    LOCAL    @FileSize:DWORD
    LOCAL    @hwnd:HWND
    LOCAL    @SizeRead:DWORD
    LOCAL    @str:DWORD
    LOCAL    systime:SYSTEMTIME

    invoke    GetDlgItem,hWndDlg,IDC_FILEMSG
    mov    @hwnd,eax
    invoke    SendMessage,eax, CB_ADDSTRING, 0,addr lpWRJ
    
    invoke    CreateFile,ADDR lpFileName,GENERIC_READ or GENERIC_WRITE,FILE_SHARE_READ or FILE_SHARE_WRITE,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_ARCHIVE,NULL
        .if    eax==INVALID_HANDLE_VALUE
            invoke    SendMessage,@hwnd, CB_ADDSTRING, 0,addr lpString
        .else
            mov    @hFile,eax
            invoke GetFileSizeEx,@hFile,addr @FileSize
            add    @FileSize,4
            invoke GlobalAlloc,GMEM_MOVEABLE or GMEM_ZEROINIT,@FileSize
                mov    @hMem,eax 
                invoke GlobalLock,eax
                mov    @pMem,eax 

             invoke    ReadFile,@hFile,@pMem,@FileSize,ADDR @SizeRead,NULL
        mov eax,@pMem
        mov @str,eax
               
               .while  @SizeRead>0
        .if dword ptr[eax]==0a0d0a0dh    ;查找空行
            mov dword ptr[eax],0
            push eax
                invoke    SendMessage,@hwnd,CB_ADDSTRING,0,@str
                   pop eax
                   add eax,4
                   sub @SizeRead,4
                   mov @str,eax
               .else
            inc eax
            dec @SizeRead
        .endif
               .endw
               invoke    SendMessage,@hwnd,CB_ADDSTRING,0,@str
               
            invoke GlobalUnlock,@pMem 
                invoke GlobalFree,@hMem 

            invoke    CloseHandle,@hFile 
            
            invoke  SendMessage,@hwnd, CB_SETCURSEL, 0, 0
            
            invoke  CheckDlgButton,hWndDlg,IDC_RBN2,BST_CHECKED
        .endif
    invoke    GetSystemTime,addr systime
    push    systime.wSecond        ;初始化随机数
    and    eax,dwRandom
    xor    ax,systime.wMilliseconds
    mov    dwRandom,eax
    ret
_initDlg endp

;*********************************************************************************
;响应 IDC_SAVE 按钮点击消息,保存文字到文件中
;*********************************************************************************
_SaveMsg proc    ;uses edi
    LOCAL    @hFile        :HANDLE
    LOCAL    @hMem        :HANDLE
    LOCAL    @pMem        :HANDLE
    LOCAL    @nWritten    :DWORD
    LOCAL    @nLen        :DWORD
    
    invoke    GetDlgItem,hWndDlg,IDC_SAVE
    invoke    EnableWindow,eax,FALSE
    
    invoke    GetDlgItem,hWndDlg,IDC_MESSAGE
    invoke    GetWindowTextLength,eax
    or    eax,eax
    jz    @F
    add    eax,5
    mov    @nLen,eax
    
    invoke    GlobalAlloc,GMEM_MOVEABLE or GMEM_ZEROINIT,eax
    mov    @hMem,eax 
    invoke    GlobalLock,eax
    mov    @pMem,eax
    mov    edi,eax
    mov    eax,0a0d0a0dh    ;先加一个空行
    cld
    stosd
    push    edi    
    invoke    GetDlgItemText,hWndDlg,IDC_MESSAGE,edi,@nLen    ;读文本框内容到换行符之后
    add    eax,4
    mov    @nLen,eax
    invoke    GetDlgItem,hWndDlg,IDC_FILEMSG
    push    0
    push    CB_ADDSTRING    ;并且把读入的文本框内容加入列表中
    push    eax
    call    SendMessage
    
    invoke    CreateFile,ADDR lpFileName,GENERIC_READ or GENERIC_WRITE,FILE_SHARE_READ or FILE_SHARE_WRITE,NULL,OPEN_ALWAYS,FILE_ATTRIBUTE_ARCHIVE,NULL
        .if    eax!=INVALID_HANDLE_VALUE
            mov    @hFile,eax
            invoke    SetFilePointer,@hFile,0,0,FILE_END    ;移动文件指针到文件尾
            invoke    WriteFile,@hFile,@pMem,@nLen,addr @nWritten,NULL    ;内容添加到文件尾

        invoke    CloseHandle,@hFile
    .endif

    invoke GlobalUnlock,@pMem 
    invoke GlobalFree,@hMem 

    @@:
    ret

_SaveMsg endp

;*********************************************************************************
;调用 EnumWindows 找所有的窗口
;*********************************************************************************
_SendMsg proc
    LOCAL    @nLen        :DWORD
    LOCAL    @pMem        :HANDLE
    LOCAL    @hMem        :HANDLE
    
    invoke    GetDlgItem,hWndDlg,IDC_MESSAGE
    invoke    GetWindowTextLength,eax
    .if eax==0
        invoke    _OnCBSelChange
    .endif
    inc    eax
    mov    @nLen,eax
    invoke    GlobalAlloc,GMEM_MOVEABLE or GMEM_ZEROINIT,eax
    mov    @hMem,eax 
    invoke    GlobalLock,eax
    mov    @pMem,eax 
    invoke    GetDlgItemText,hWndDlg,IDC_MESSAGE,eax,@nLen    ;取文本框内容
    invoke    SetDlgItemText,hWndDlg,IDC_MESSAGE,NULL    ;把文本框清空

    invoke    EnumWindows,_EnumWindowsProc,@pMem    ;@pMem 中为要发的内容,所有窗口都找一遍才返回

    invoke    GlobalUnlock,@pMem 
    invoke    GlobalFree,@hMem     
    
    ret

_SendMsg endp

;*********************************************************************************
;找到窗口,判断是否是QQ的聊天窗口,是则给他发送文字,不是就让EnumWindows继续找
;*********************************************************************************
_EnumWindowsProc proc  hWndQQ:HWND,@pMem:DWORD ;uses edi 如果用了edi,必须要它,否则会出错,切记切记
    LOCAL    @hWndSend    :HWND
    LOCAL    @hWndPro    :HWND

    invoke    GetWindowText,hWndQQ,addr lpBuf,21    ;取窗口标题文字
    mov    ecx,eax
    mov    ax,0ebd3h    ;"与"的内码倒置
    lea    edx,lpBuf
    .while    ax!=word ptr [edx]    ;标题中有“与”这个字吗?
        .if    ecx==0
            jmp    FINDNEXTWND
        .endif
        dec    ecx
        inc    edx
    .endw

    invoke    FindWindowEx,hWndQQ,NULL,addr lpQQWindow,NULL    ;对话框的类为“#32770”
    mov    @hWndPro,eax
    invoke    FindWindowEx,eax,NULL,addr lpQQDlg,NULL        ;找QQ的窗口
    invoke    FindWindowEx,eax,NULL,addr lpQQMsg,NULL        ;找QQ中写消息的文本框
    .if    eax!=NULL    ;判断一下是否找到。如果前面的条件都满足,就应该能找到
        invoke    SendMessage,eax,EM_REPLACESEL,0,@pMem    ;把要发的内容先送进这个文本框
        invoke    FindWindowEx,@hWndPro,NULL,NULL,NULL    ;找那个“发送”按钮
        .while    eax!=NULL    ;慢慢找吧^O^,里面的子窗口很多
            mov    @hWndSend,eax
            invoke    GetWindowText,eax,addr lpBuf,20    ;取子窗口内容
            mov    ecx,eax
            mov    ax,0a2b7h    ;"发"的内码倒置
            lea    edx,lpBuf
            .while    ax!=word ptr [edx]    ;有“发”字吗?
                .if    ecx==0
                    invoke    FindWindowEx,@hWndPro,@hWndSend,NULL,NULL    ;不是就找下一个子窗口
                    jmp    GETNEXT_DLGITEM
                .endif
                dec    ecx
                inc    edx
            .endw
            invoke    SendMessage,@hWndSend,BM_CLICK,0,0    ;找到就模拟鼠标点击动作,发送完成
            .break    ;本窗口处理完成,准备去找下一个QQ窗口
GETNEXT_DLGITEM:
        .endw
    .endif
FINDNEXTWND:
    mov    eax,TRUE    ;告诉 EnumWindows 函数,我要继续找下一个窗口,挨个找,一个都不能少^O^
    ret
    
_EnumWindowsProc endp

;*********************************************************************************
;响应 WM_TIMER 消息,把列表中的内容按照某种顺序自动发送到QQ窗口
;*********************************************************************************
_Timer proc timer:DWORD
    LOCAL    @hWndCB:HWND
    LOCAL    @Count    :DWORD

    .if timer==ID_TIMER
        invoke    _SendMsg    ;发送当前内容,然后预设下一次要发的内容

        invoke    GetDlgItem,hWndDlg,IDC_FILEMSG
        mov    @hWndCB,eax
        invoke    SendMessage,eax, CB_GETCOUNT, 0, 0
        mov    @Count,eax
        
        invoke    IsDlgButtonChecked,hWndDlg,IDC_RBN2
        .if    eax==TRUE    ;循环发送方式
            invoke    SendMessage,@hWndCB,CB_GETCURSEL,0,0
            inc    eax
            .if    eax>=@Count
                mov    eax,1
            .endif
        .else
            invoke    IsDlgButtonChecked,hWndDlg,IDC_RBN3
            .if    eax==TRUE    ;随机发送方式
                dec    @Count
                invoke    _rand,@Count
                inc    eax
            .else
                jmp    SETSELMSG    ;固定发送方式,就不用选了,但文本框中已清空,得去补上
            .endif
        .endif
        invoke  SendMessage,@hWndCB, CB_SETCURSEL,eax, 0    ;选中下一个要发的条目
SETSELMSG:
        invoke    _OnCBSelChange    ;把选中项填入文本框中
    .endif

    ret 

_Timer endp

;**************************************************************************************
;响应 IDC_AUTOSEND 按钮点击消息,设置时钟开关,按要求设置时钟,如果已经设过,则停止时钟
;**************************************************************************************
_AutoSend proc
    LOCAL    @hWnd:HWND
    
    invoke    GetDlgItem,hWndDlg,IDC_TIME
    mov    @hWnd,eax
    invoke    IsDlgButtonChecked,hWndDlg,IDC_AUTOSEND
    xor    eax,1    ;取反
    push    eax
    invoke    EnableWindow,@hWnd,eax    ;如果是设时钟,则不让改时间,否则恢复为可改写状态
    pop    eax
    .if    eax==FALSE    ;意思是:点击之前没选中,说明没有启动时钟
        invoke    GetDlgItemInt,hWndDlg,IDC_TIME,NULL,TRUE
        .if    eax<=0    ;时间不能少于1
            invoke    SetDlgItemInt,hWndDlg,IDC_TIME,6,TRUE    ;太小则设为默认值
            mov    eax,6
        .endif
        mov    edx,1000    ;换算为秒
        mul    edx    
        invoke    SetTimer,hWndDlg,ID_TIMER,eax,NULL    ;启动时钟
    .else
        invoke    KillTimer,hWndDlg,ID_TIMER    ;关闭时钟
    .endif
    
    ret

_AutoSend endp

;*********************************************************************************
;响应 CBN_SELCHANGE 消息,也就是手动改变列表选项时,把选中项的内容送入文本框中
;*********************************************************************************
_OnCBSelChange proc
    LOCAL    @hWnd:HWND
    LOCAL    @nSel:DWORD
    LOCAL    @hMem:HANDLE
    LOCAL    @pMem:HANDLE

    invoke    GetDlgItem,hWndDlg,IDC_SAVE
    invoke    EnableWindow,eax,FALSE    ;让保存按钮变灰
    invoke    GetDlgItem,hWndDlg,IDC_FILEMSG
    mov    @hWnd,eax
    invoke    SendMessage,eax,CB_GETCURSEL,0,0
    mov    @nSel,eax
    invoke    SendMessage,@hWnd,CB_GETLBTEXTLEN,eax,0
    push    eax
    inc    eax
    invoke    GlobalAlloc,GMEM_MOVEABLE or GMEM_ZEROINIT,eax
    mov    @hMem,eax 
    invoke    GlobalLock,eax
    mov    @pMem,eax 
    
    invoke    SendMessage,@hWnd,CB_GETLBTEXT,@nSel,eax    ;取出
    invoke    SetDlgItemText,hWndDlg,IDC_MESSAGE,@pMem    ;填入

    invoke    GlobalUnlock,@pMem 
    invoke    GlobalFree,@hMem 
    pop    eax

    ret
    
_OnCBSelChange endp

;*********************************************************************************
;根据给定的QQ号,打开临时聊天对话框
;*********************************************************************************
_OpenQQWnd proc
    LOCAL    posBuffer[255]:byte

    invoke GetDlgItemText,hWndDlg,IDC_QQNUM ,addr lpBuf,20  ;取用户输入到文本
    invoke wsprintf,addr posBuffer,addr lptemp,addr lpBuf ;连接文本串
    invoke ShellExecute,NULL,NULL,addr posBuffer,NULL,NULL,SW_HIDE  ;执行IE命令
    
    ret

_OpenQQWnd endp

;*********************************************************************************
;窗口主调函数,判断并处理各种消息
;*********************************************************************************
DlgProc proc hWin:HWND,uMsg:UINT,wParam:WPARAM,lParam:LPARAM

    mov    eax,uMsg
    .if eax==WM_INITDIALOG
        mov    eax,hWin
        mov    hWndDlg,eax
        call    _initDlg
    .elseif eax==WM_COMMAND
        mov eax,wParam 
            .if lParam!=0 
                   mov edx,eax
                   shr edx,16 
                    .if dx==BN_CLICKED ;按钮消息处理
                        .if ax==IDC_SEND ;发送
                    call _SendMsg
                        .elseif ax==IDC_SAVE  ;保存
                    call _SaveMsg
                .elseif ax==IDC_AUTOSEND  ;自动项开关
                    call _AutoSend
                .elseif ax==IDC_OPENQQWND ;打开临时QQ聊天对话框
                    call _OpenQQWnd
                           .endif
                       .elseif dx==EN_CHANGE  ;文本框内容改变
                           .if ax==IDC_MESSAGE
                    invoke GetDlgItem,hWndDlg,IDC_SAVE
                    invoke EnableWindow,eax,TRUE
                           .endif
                       .elseif dx==CBN_SELCHANGE  ;手动改变列表选项
                           call _OnCBSelChange
                    .endif 
            .endif 
        
    .elseif eax==WM_CLOSE
        invoke KillTimer,hWndDlg,ID_TIMER
        invoke EndDialog,hWin,0
    .elseif eax==WM_TIMER  ;时钟消息
        invoke _Timer,wParam
    .else
        mov    eax,FALSE
        ret
    .endif
    mov    eax,TRUE
    ret

DlgProc endp

end start

×××××××××××××××××××××××××××××××××××××××××××××××××××××××××
感谢4stOne的指正,我改过的内容放在24楼了,有兴趣的给测试一下。
******************************************************************************************************************
新改过的群发器可以让你随便指定一个QQ号,然后打开临时聊天窗口,自动发消息给他,编译后的exe文件在27楼。

  • 标 题:答复
  • 作 者:王仁军
  • 时 间:2007-04-04 20:28

引用:
最初由 4st0ne发布 查看帖子
能发下inc和rc文件吗?...
QQ自动群发器.Inc文件:

include windows.inc
include kernel32.inc
include user32.inc
include Comctl32.inc
include shell32.inc

includelib kernel32.lib
includelib user32.lib
includelib Comctl32.lib
includelib shell32.lib

DlgProc      PROTO  :HWND,:UINT,:WPARAM,:LPARAM
_OnCBSelChange    PROTO
_EnumWindowsProc  PROTO   :HWND,:HANDLE

.const

IDD_MAINDIALOG      equ 101
IDC_FILEMSG      equ 1001
IDC_MESSAGE      equ 1002
IDC_TIME      equ 1005
IDC_AUTOSEND      equ 1006
IDC_RBN2      equ 1007
IDC_RBN3      equ 1008
IDC_SAVE      equ 1009
IDC_SEND      equ 1010
;

ID_TIMER      equ 8888
;#########################################################################

.data?
hWndDlg        dd ?
lpBuf        db 21 dup(?)
dwRandom      dd ?

;#########################################################################与
.data
lpString   DB  '未找到消息文件:'
lpFileName   DB  'FileMsg.txt',0
lpWRJ     DB  '程序编者:王仁军',0
lpQQWindow  DB  '#32770',0
lpQQDlg    DB  'AfxWnd42',0
lpQQMsg    DB  'RICHEDIT',0

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
QQ自动群发器.Rc文件:
#include "Res/QQ自动群发器Dlg.rc"
#define MY_ICON 10
MY_ICON ICON "QQ群发器.ico"

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
QQ自动群发器.dlg文件:
#define IDD_MAINDIALOG 101
#define IDC_GRP1 1003
#define IDC_FILEMSG 1001
#define IDC_MESSAGE 1002
#define IDC_TIME 1005
#define IDC_AUTOSEND 1006
#define IDC_RBN3 1008
#define IDC_SAVE 1009
#define IDC_SEND 1010
#define IDC_STC1 1011
#define IDC_RBN2 1007
#define IDC_RBN1 1004
IDD_MAINDIALOG DIALOGEX 150,110,191,145
CAPTION "QQ自动群发器"
FONT 12,"宋体",400,0
STYLE 0x14CA0800
EXSTYLE 0x00000000
BEGIN
  CONTROL "",IDC_FILEMSG,"ComboBox",0x50210043,3,1,185,164,0x00000000
  CONTROL "我可以自动把消息发给多个人",IDC_MESSAGE,"Edit",0x50211004,3,15,183,99,0x00020000
  CONTROL "",IDC_GRP1,"Button",0x50000007,3,112,80,30,0x00000000
  CONTROL "6",IDC_TIME,"Edit",0x50010001,6,118,17,9,0x00020000
  CONTROL "秒自动发一次",IDC_AUTOSEND,"Button",0x50014C23,22,118,57,9,0x00020000
  CONTROL "固定",IDC_RBN1,"Button",0x50030009,4,129,25,11,0x00000000
  CONTROL "循环",IDC_RBN2,"Button",0x50010009,30,129,25,11,0x00000000
  CONTROL "随机",IDC_RBN3,"Button",0x50010009,57,129,25,11,0x00000000
  CONTROL "保存[&F]",IDC_SAVE,"Button",0x58010000,85,117,48,15,0x00000000
  CONTROL "发送[&S]",IDC_SEND,"Button",0x50010001,136,117,48,15,0x00000000
  CONTROL "Email:673759017@qq.com",IDC_STC1,"Static",0x50000000,88,132,96,11,0x00000000
END

  • 标 题:答复
  • 作 者:王仁军
  • 时 间:2007-04-10 18:49

下面是我改过的代码
;*********************************************************************************
;找到窗口,判断是否是QQ的聊天窗口,是则给他发送文字,不是就让EnumWindows继续找
;*********************************************************************************
_EnumWindowsProc proc  hWndQQ:HWND,@pMem:DWORD

  invoke  GetWindowText,hWndQQ,addr lpBuf,21  ;取窗口标题文字
  mov  ecx,eax
  mov  ax,0ebd3h  ;"与"的内码倒置
  lea  edx,lpBuf
  .while  ax!=word ptr [edx]  ;标题中有“与”这个字吗?
      or  ecx,ecx
      je  FINDNEXTWND
      dec  ecx
      inc  edx
  .endw

  invoke  GetDlgItem,hWndQQ,0h;开始获取输入框句柄
  invoke  GetDlgItem,eax,0h
  invoke  GetDlgItem,eax,37Eh
  invoke  SendMessage,eax,EM_REPLACESEL,0,@pMem ;向QQ输入框粘贴字符
  invoke  GetDlgItem,hWndQQ,0h ;开始获取发送按钮句柄
  invoke  GetDlgItem,eax,1h
  invoke  SendMessage,eax,BM_CLICK,0,0;点击发送按钮
FINDNEXTWND:
  mov  eax,TRUE  ;告诉 EnumWindows 函数,我要继续找下一个窗口,挨个找,一个都不能少^O^
  ret
  
_EnumWindowsProc endp