;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 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的值呢?
谢谢
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)