首页
社区
课程
招聘
求助两个win32汇编的问题,实在搞不明白了。
2007-4-24 01:20 6721

求助两个win32汇编的问题,实在搞不明白了。

2007-4-24 01:20
6721
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; Sample code for < Win32ASM Programming 2nd Edition>
; by 罗云彬, http://asm.yeah.net
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; ProcessList.asm
; 列出系统中当前运行的进程
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 使用 nmake 或下列命令进行编译和链接:
; ml /c /coff ProcessList.asm
; rc ProcessList.rc
; Link /subsystem:windows ProcessList.obj ProcessList.res
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
                .386
                .model flat, stdcall
                option casemap :none
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; Include 文件定义
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
include                windows.inc
include                user32.inc
includelib        user32.lib
include                kernel32.inc
includelib        kernel32.lib
includelib        msvcrt.lib
strrchr                        PROTO C : dword,:dword
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; Equ 等值定义
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
ICO_MAIN        equ        1000
DLG_MAIN        equ        1000
IDC_PROCESS        equ         1001
IDC_REFRESH        equ         1002
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 数据段
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
                .data?
hInstance        dd        ?
hWinList        dd        ?

                .const
szProcessName        db        'svchost.exe',0
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 代码段
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

                .code
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
_GetProcessList        proc        _hWnd                                                                                                                                                                                                                        ;
                local        @stProcess:PROCESSENTRY32                                                                                                                                                                        ;声明stProcess局部变量,类型为PROCESSENTRY32结果
                local        @hSnapShot                                                                                                                                                                                                                                                ;声明hSnapShot局部变量
                invoke        RtlZeroMemory,addr @stProcess,sizeof @stProcess                                                                        ;在内存中初始化@stProcess局部变量为0
                invoke        SendMessage,hWinList,LB_RESETCONTENT,0,0                                                                                                ;给hWinList对象发消息,重置内容为空。hWinList在上一函数中已被赋值为ListBox的句柄
                mov        @stProcess.dwSize,sizeof @stProcess                                                                                                                                        ;@stProcess的dwSize等于自身结构的尺寸
                invoke        CreateToolhelp32Snapshot,TH32CS_SNAPPROCESS,0                                                                                ;调用CreateToolhelp32Snapshot函数,TH32CS_SNAPPROCESS指明对系统范围中的进程进行枚举
                mov        @hSnapShot,eax                                                                                                                                                                                                                        ;返回快照句柄到eax,并赋值给@hSnapShot
                invoke        Process32First,@hSnapShot,addr @stProcess                                                                                                ;第一次从快照中取进程信息要调用Process32First。
                .while        eax                                                                                                                                                                                                                                                        ;当没有下一个进程信息,则返回FALSE到EAX,即跳出while循环
                        pushad
                        invoke        strrchr,addr @stProcess.szExeFile,szProcessName
                        popad
                                invoke        SendMessage,hWinList,LB_ADDSTRING,0,addr @stProcess.szExeFile
                                invoke        Process32Next,@hSnapShot,addr @stProcess
                .endw
                invoke        CloseHandle,@hSnapShot
                invoke        GetDlgItem,_hWnd,IDOK
                invoke        EnableWindow,eax,FALSE
                ret

_GetProcessList        endp
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
_ProcDlgMain        proc        uses ebx edi esi hWnd,wMsg,wParam,lParam

                mov        eax,wMsg                                                                                                                                                                                                                                                ;wMsg消息类型赋给eax
                .if        eax == WM_CLOSE                                                                                                                                                                                                                        ;比较eax是否等于WM_CLOSE
                        invoke        EndDialog,hWnd,NULL                                                                                                                                                                                ;等于则关闭程序
                .elseif        eax == WM_INITDIALOG                                                                                                                                                                                ;如果等于WM_INITDIALOG则继续
                        invoke        GetDlgItem,hWnd,IDC_PROCESS                                                                                                                                                ;取得名为IDC_PROCESS控件的句柄,hWnd指名被哪个窗口包含
                        mov        hWinList,eax                                                                                                                                                                                                                        ;返回IDC_PROCESS的句柄到eax,并赋给全局变量hWinList
                        invoke        _GetProcessList,hWnd                                                                                                                                                                        ;将窗口句柄作为参数,调用_GetProcessList
;********************************************************************
                .elseif        eax == WM_COMMAND
                        mov        eax,wParam
                        .if        ax ==        IDOK
                                invoke        SendMessage,hWinList,LB_GETCURSEL,0,0
                                invoke        SendMessage,hWinList,LB_GETITEMDATA,eax,0
                                invoke        OpenProcess,PROCESS_TERMINATE,FALSE,eax
                                .if        eax
                                        mov        ebx,eax
                                        invoke        TerminateProcess,ebx,-1
                                        invoke        CloseHandle,ebx
                                        invoke        Sleep,200
                                        invoke        _GetProcessList,hWnd
                                        jmp        @F
                                .endif
                                invoke        MessageBox,hWnd,addr szErrTerminate,NULL,MB_OK or MB_ICONWARNING
                                @@:
;********************************************************************
                        .elseif        ax ==        IDC_REFRESH
                                invoke        _GetProcessList,hWnd
;********************************************************************
                        .elseif        ax ==        IDC_PROCESS
                                shr        eax,16
                                .if        ax ==        LBN_SELCHANGE
                                        invoke        GetDlgItem,hWnd,IDOK
                                        invoke        EnableWindow,eax,TRUE
                                .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                        ;创建对话框,_ProcDlgMain开始处理消息
                invoke        ExitProcess,NULL
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
                end        start

先说调用C函数的问题吧。查看msdn,里面有一个strrchr函数,可以从字符串右边开始比较第二个参数指定的字符串在源字符串中的位置。在网上查了资料,有的说要想调用一定要包含库文件,然后还要声明strrchr proto c,我试了一下,如果只include 库文件,而不声明 strrchr proto c的话,提示找不到函数。可是我看罗老师的书上代码,却从没有生命过任何一个proto c,也照样掉库里的函数。

第二个问题

                .while        eax                                                                                                                                                                                                                                                                pushad
                        invoke        strrchr,addr @stProcess.szExeFile,szProcessName
                        popad
                                invoke        SendMessage,hWinList,LB_ADDSTRING,0,addr @stProcess.szExeFile
                                invoke        Process32Next,@hSnapShot,addr @stProcess
                .endw

我的本意是通过调用strrchr方法,判断常量szProcessName是否存在于@stProcess.szExeFile中。调用strrchr方法前,所有寄存器入栈,调用方法后,所有寄存器恢复。这样不会影响invoke        Process32Next,@hSnapShot,addr @stProcess的调用,可是总是抱错,说xx内存不可读。打开OD跟了一下,呈现如下代码

00401065  |> /60            /PUSHAD
00401066  |. |6A 00         |PUSH 0
00401068  |. |A0 73204000   |MOV AL,BYTE PTR DS:[402073]
0040106D  |. |66:0FB6C0     |MOVZX AX,AL
00401071  |. |66:50         |PUSH AX                                 ; /c
00401073  |. |8D85 FCFEFFFF |LEA EAX,DWORD PTR SS:[EBP-104]          ; |
00401079  |. |50            |PUSH EAX                                ; |s
0040107A  |. |E8 EF010000   |CALL <JMP.&MSVCRT.strrchr>              ; \strrchr
0040107F  |. |83C4 08       |ADD ESP,8
00401082  |. |61            |POPAD

程序头部声明了stdcall,那么应该是被调用者恢复堆栈。反汇编后,也确实有ADD ESP,8。但问题是从OD跟的情况看,PUSHAD后,ESP=0012FBA4。但是跟到ADD ESP,8之后,ESP=0012FBA2,很明显调用strrchr函数后,堆栈没有被自动恢复正确。所以出现了程序错。问题就是,为什么strrchr没有正确恢复ESP的值呢?

谢谢

[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

收藏
免费 0
打赏
分享
最新回复 (10)
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
点点 2007-4-24 10:47
2
0
第一个问题:
includelib  msvcrt.lib
strrchr      PROTO C : dword,:dword
//============================
以上为调用C运行时库中的方式

第二个问题
invoke  strrchr,addr @stProcess.szExeFile,szProcessName
//======================================
应为invoke  strrchr,addr @stProcess.szExeFile,addr szProcessName

我没有编译这个程序,只能看到最基本的问题,不好意思
雪    币: 203
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
leokingr 2007-4-24 12:49
3
0
回点点,谢谢

修改为addr szProcessName后,仍然提示xx内存不能读
雪    币: 625
活跃值: (1062)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
xzchina 1 2007-4-24 13:49
4
0
_GetProcessList        proc        _hWnd
                local        @stProcess:PROCESSENTRY32
                local        @hSnapShot

                invoke        RtlZeroMemory,addr @stProcess,sizeof @stProcess
                invoke        SendMessage,hWinList,LB_RESETCONTENT,0,0
                mov        @stProcess.dwSize,sizeof @stProcess
                invoke        CreateToolhelp32Snapshot,TH32CS_SNAPPROCESS,0
                mov        @hSnapShot,eax
                invoke        Process32First,@hSnapShot,addr @stProcess
                .while        eax
                        invoke        SendMessage,hWinList,LB_ADDSTRING,0,addr @stProcess.szExeFile
                        invoke        SendMessage,hWinList,LB_SETITEMDATA,eax,@stProcess.th32ProcessID
                        invoke        Process32Next,@hSnapShot,addr @stProcess
                .endw
                invoke        CloseHandle,@hSnapShot
                invoke        GetDlgItem,_hWnd,IDOK
                invoke        EnableWindow,eax,FALSE
                ret

_GetProcessList        endp
雪    币: 203
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
leokingr 2007-4-24 15:23
5
0
兄弟,我不是要书上的源码,我问的是为什么调用了strrchr以后,该函数不能自动恢复正确的堆栈。
雪    币: 625
活跃值: (1062)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
xzchina 1 2007-4-24 15:48
6
0
0040105B  |> /60            /pushad
0040105C  |. |68 50204000   |push    00402050                        ; /c = 50  ('P')
00401061  |. |8D85 FCFEFFFF |lea     eax, dword ptr [ebp-104]        ; |
00401067  |. |50            |push    eax                             ; |s
00401068  |. |E8 EB010000   |call    <jmp.&msvcrt.strrchr>           ; \strrchr
0040106D  |. |83C4 08       |add     esp, 8
00401070  |. |61            |popad
问题出在
invoke  strrchr,addr @stProcess.szExeFile,szProcessName
雪    币: 203
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
leokingr 2007-4-24 16:03
7
0
是啊。我跟出来了问题在strrchr调用上。问题是为什么strrchr函数没有正确恢复堆栈?
雪    币: 203
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
leokingr 2007-4-24 16:41
8
0
又仔细看了一下msdn对strrchr的说明,是搞错了strrchr的用法
Scan a string for the last occurrence of a character.

char *strrchr( const char *string, int c );

由以上说明可知,strrchr函数只用于单字符的查找。但是我给出的是一个字符串,改成单字符为第二个参数后,strrchr可以正常恢复堆栈了。

错误调用strrchr函数是的od情况如下
00401066  |. |6A 00         |PUSH 0
00401068  |. |A0 73204000   |MOV AL,BYTE PTR DS:[402073]
0040106D  |. |66:0FB6C0     |MOVZX AX,AL
00401071  |. |66:50         |PUSH AX                                 ; /c
00401073  |. |8D85 FCFEFFFF |LEA EAX,DWORD PTR SS:[EBP-104]          ; |
00401079  |. |50            |PUSH EAX                                ; |s
0040107A  |. |E8 EF010000   |CALL <JMP.&MSVCRT.strrchr>              ; \strrchr
0040107F  |. |83C4 08       |ADD ESP,8

正确调用strrchr函数后

00401066  |.  6A 64         |PUSH 64                                 ; /c = 64  ('d')
00401068  |.  8D85 FCFEFFFF |LEA EAX,DWORD PTR SS:[EBP-104]          ; |
0040106E  |.  50            |PUSH EAX                                ; |s
0040106F  |.  E8 F2010000   |CALL <JMP.&MSVCRT.strrchr>              ; \strrchr
00401074  |.  83C4 08       |ADD ESP,8

我自己能解释的是,因为给出的第二个参数是地址,所以要先取地址中第一个字符到AL。如果是正确的调用,只给一个字符的话,则直接PUSH。因为错误的调用,所以多了一个取到AL的过程。

我自己不能解释的是,为什么做了错误的调用,程序要自身先PUSH 0。请高手解答。谢谢。
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
点点 2007-4-24 16:43
9
0
你在跟踪时,运行到哪一条指令时才弹出内存不可访问的对话框呢?能不能把这块的信息贴出来看一下
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
点点 2007-4-24 16:48
10
0
我自己不能解释的是,为什么做了错误的调用,程序要自身先PUSH 0。请高手解答。谢谢。
//=============================================================================
这是编译器决定的,没有一定有原理,只是ms喜欢这样处理而以

你错误时,相当于在C语言中写int i = "asdf";此时i的值在标准中是未定义的,i的值取决于编译器的实现
雪    币: 203
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
leokingr 2007-4-24 18:43
11
0
invoke Process32Next,@hSnapShot,addr @stProcess 这句出错。

原因是错误的调用了strrchr,导致strrchr不能正确恢复ESP.因为invoke Process32Next,@hSnapShot,addr @stProcess 会调用寄存器的值,来访问下一条进程信息。所以报错。

如果如点点所说,错误的调用会导致先PUSH 0,且这是MS喜欢这样做。那就没有办法深究了。

最后感谢,两位对我问题的关注。
游客
登录 | 注册 方可回帖
返回