Author: Benina
Download: [Source]
Tuts này tôi chỉ tổng kết một số cách liệt kê processes đang thực thi hiện hành trong Windows. Mục đích chính cũng là để tôi lưu trữ vì vậy các đoạn code trong tuts này không chuẩn mực (ko có kiểm tra lỗi xảy ra bằng cách dùng hàm GetLastError), có nhiều điểm cần phải bổ sung. Nhưng dù sao đi nữa nó cũng có ích phần nào cho các bạn nghiên cứu lập trình masm.
Tôi thực hành trên Windows XP SP2. Trên các Windows khác code có thể ko thực thi.
1.Phương pháp 1: Using Process Status Helper Library
Đầu tiên ta dùng hàm EnumProcesses để liệt kê các PIDs (chỉ mục process) các processes đang running trong system. Giá trị trả về của hàm là một con trỏ đến mảng array dword chứa các PIDs (tham số pProcessIDs) và tổng số bytes chứa mảng array trả về (tham số pBytesReturned).
Sau đó ta dùng một vòng lặp duyệt qua từng thành phần trong mảng array dword, tức là duyệt qua từng PID trong array để đọc tên processes.
Muốn đọc được name process ta phải dùng một loạt các hàm APIs như sau:
-Mở process bằng hàm OpenProcess với flag là PROCESS_QUERY_INFORMATION or PROCESS_VM_READ. Với flag như vậy chúng ta mới truy vấn được thông tin của processes.
-Liệt kê Modules của process vừa mở bằng hàm EnumProcessModules. Hàm này sẽ trả về một mảng array chứa tên các modules (ascii) và tổng số bytes chứa mảng array đó.
-Sau đó ta dùng hàm GetModuleBaseName để đọc tên base name module. Tức là tên module thực thi process.
-Cuối cùng ta nhớ CloseHandle process mở trước đó
Sau đây là một số bước thực hiện tóm tắt:
Bước 1: Liệt kê các PIDs bằng cách dùng hàm EnumProcesses
Hàm EnumProcesses nhận các PIDs của các processes trong system.
Syntax
C++
BOOL WINAPI EnumProcesses(
__out DWORD *pProcessIds,
__in DWORD cb,
__out DWORD *pBytesReturned
);
Parameters
pProcessIds [out]
Con trỏ trỏ đến một array nhận danh sách các chỉ mục process (list of process identifiers).
cb [in]
Kích thước (bytes) của mãng pProcessIds array.
pBytesReturned [out]
Số bytes trả về trong pProcessIds array.
Return Value
Nếu hàm thành công thì giá trị trả về là nonzero.
Nếu hàm sai, giá trị trả về là zero. Để lấy thông tin lỗi, call GetLastError.
Bước 2a: Dùng hàm OpenProcess mở process để ta truy vấn thông tin từ nó
Mở process bằng hàm OpenProcess với flag là PROCESS_QUERY_INFORMATION or PROCESS_VM_READ. Với flag như vậy chúng ta mới truy vấn được thông tin của processes.
Bước 2b:Dùng hàm EnumProcessModules để liệt kê các modules trong process được mở trước đó
Gọi hàm EnumProcessModules để nhận một handle cho mỗi module trong process được chỉ định.
Syntax
C++
BOOL WINAPI EnumProcessModules(
__in HANDLE hProcess,
__out HMODULE *lphModule,
__in DWORD cb,
__out LPDWORD lpcbNeeded
);
Parameters
hProcess [in]
handle của process cần liệt kê các modules.
lphModule [out]
Một array nhận danh sách các module handles.
cb [in]
size of lphModule array, đơn vị bytes.
lpcbNeeded [out]
số bytes cần thiết để chứa tất cả các module handles trong lphModule array.
Return Value
Nếu hàm thành công trả về giá trị là nonzero.
Nếu hàm fails, return value là zero. To get extended error information, call GetLastError.
Bước 3:Dùng hàm GetModuleBaseName để lấy addr chứa name của module
GetModuleBaseName Function
Nhận địa chỉ đầu tiên chứa name of module được chỉ định.
Syntax
C++
DWORD WINAPI GetModuleBaseName(
__in HANDLE hProcess,
__in_opt HMODULE hModule,
__out LPTSTR lpBaseName,
__in DWORD nSize
);
Parameters
hProcess [in]
handle của process chứa module.
handle phải có quyền truy xuất PROCESS_QUERY_INFORMATION và PROCESS_VM_READ. Để có nhiều thông tin hơn, hảy xem chủ đề Process Security and Access Rights.
hModule [in, optional]
handle của module. Nếu tham số này là NULL, hàm này trả về name of file được sử dụng để cài đặt process đang calling.
lpBaseName [out]
Con trỏ đến buffer nhận base name of module. Nếu base name lớn hơn maximum number of characters được chỉ định bởi tham số nSize parameter, base name sẽ bị cắt bỏ.
nSize [in]
size of lpBaseName buffer, đơn vị characters.
Return Value
Nếu hàm thành công, giá trị trả về chỉ định chiều dài length of string được copy đến buffer, in characters.
Nếu hàm sai, return value là zero. Để biết thông tin lỗi xảy ra, call GetLastError.
Thực hành:
-Tạo project Dialog
-Trong rc tạo Listview, với Type là Report
push esi push edi
lea eax,buffer mov pbuf,eax invoke EnumProcesses,pbuf,4096,ADDR breq
shr breq, 2 ; get process count
mov esi, pbuf mov edi, breq
.while edi>0
push esi push edi
mov eax,dword ptr [esi] mov pid,eax
invoke OpenProcess,PROCESS_QUERY_INFORMATION \ or PROCESS_VM_READ,FALSE,eax
mov hProcess,eax
.if hProcess != 0 invoke EnumProcessModules,hProcess,ADDR hMod,\ 4,ADDR cbNeeded .if eax!=0 invoke GetModuleBaseName,hProcess,hMod,\ addr buf2,260 .if eax==0 invoke lstrcpy,addr buf2,chr$("System0")
.endif
.elseif invoke lstrcpy,addr buf2,chr$("System1") .endif .elseif invoke lstrcpy,addr buf2,chr$("System2")
.endif ;add to Item of listview
invoke wsprintf,addr buf3, addr template,pid lea eax,buf2 mov lvi.imask, LVIF_TEXT mov lvi.iItem,0 mov lvi.iSubItem,0 mov lvi.pszText, eax invoke SendMessage, hList, LVM_INSERTITEM,\ 0, ADDR lvi
;add to SubItem of Item lea eax,buf3 mov lvi.imask, LVIF_TEXT inc lvi.iSubItem mov lvi.pszText,eax invoke SendMessage, hList, LVM_SETITEM, \ 0, ADDR lvi
invoke RtlZeroMemory,addr buf2,260 invoke RtlZeroMemory,addr buf3,260 invoke CloseHandle,hProcess
pop edi pop esi add esi, 4 sub edi, 1
.endw
pop edi pop esi
invoke MessageBox,0,chr$("Method 1"),chr$("Method"),MB_OK |
2.Phương pháp 2: Using the ZwQuerySystemInformation function
Dùng hàm ZwQuerySystemInformation để liệt kê processes:
Hàm này nhận các thông tin đặc biệt của hệ thống.
Hàm này là hàm được export bởi thư viện ntdll.dll, vì vậy muốn sử dụng nó chúng ta phải GetProcAddress địa chỉ hàm này.
mov ZwQuerySystemInformation, FUNC(GetProcAddress,FUNC(GetModuleHandle,chr$("ntdll.dll")),CTXT("ZwQuerySystemInformation"))
Mô tả hàm ZwQuerySystemInformation:
NTSTATUS WINAPI ZwQuerySystemInformation(
__in SYSTEM_INFORMATION_CLASS SystemInformationClass,
__inout PVOID SystemInformation,
__in ULONG SystemInformationLength,
__out_opt PULONG ReturnLength
);
SystemInformationClass [in] : tham số này chỉ định loại thông tin cần nhận được khi gọi hàm này. Vì ở đây chúng ta cần biết thông tin về các processes và threads của chúng nên chúng ta dùng tham số có giá trị sau để chỉ định loại thông tin cần lấy:
SystemProcessesAndThreadsInformation equ 5
SystemInformation [in, out] : là con trỏ trỏ đến buffer nhận thông tin theo yêu cầu. Kích thước và cấu trúc của thông tin này thay đổi dựa trên giá trị của tham số SystemInformationClass. Vì thông tin cần lấy là process nên cấu trúc nhận được sẽ như sau:
SYSTEM_PROCESS_INFORMATION struct
NextEntryDelta dd ?
ThreadCount dd ?
Reserved1 dd 6 dup (?)
CreateTime dq ?
UserTime dq ?
KernelTime dq ?
ProcessName UNICODE_STRING
BasePriority dd ?
ProcessId dd ?
InheritedFromProcessId dd ?
HandleCount dd ?
Reserved2 dd 2 dup (?)
VmCounters VM_COUNTERS
IoCounters IO_COUNTERS
Threads SYSTEM_THREAD_INFORMATION
SYSTEM_PROCESS_INFORMATION ends
Chú thích các thành phần trong cấu trúc này:
# NextEntryOffset
Offset from begining of output buffer to next process entry. On last entry contains zero.
# NumberOfThreads
Number of process'es threads. Also number of members in Threads array descripted below.
# Reserved[3]
Reserved.
# CreateTime
Process creation time, in 100-ns units.
# UserTime
Effective time in User Mode.
# KernelTime
Effective time in Kernel Mode.
# ImageName
Process name, based on executable file name.
# BasePriority
Process base priority.
# ProcessId
Unique identifier of process.
# InheritedFromProcessId
Creator's identifier.
# HandleCount
Nr of open HANDLEs.
# Reserved2[2]
Reserved.
# PrivatePageCount
Number of memory pages assigned to process.
# VirtualMemoryCounters
Memory performance counters.
# IoCounters
IO performance counters.
# Threads[0]
Array of SYSTEM_THREAD structures descripting process's threads.
Chú ý:
-Chúng ta phải khai báo con trỏ này là một biến trên Heap thì hàm mới thực hiện được. Nếu dùng biến toàn cục thì hàm sẽ trả về sai.
LOCAL SystemInformation:DWORD
-Con trỏ này cũng có thể dùng con trỏ được cấp phát bằng lệnh VirtualAlloc
SystemInformationLength [in] : Kích thước bytes của buffer được trỏ đến bởi tham số SystemInformation.
ReturnLength [out, optional] : Là con trỏ đến vị trí mà ở đó hàm viết ra kích thước thật sự của thông tin yệu cầu. Nếu kích thước lớn hơn hoặc bằng tham số SystemInformationLength thì hàm sẽ copy thông tin vào trong SystemInformation buffer. Nếu khác, thì hàm sẽ trả về NTSTATUS error code và trả về kích thước của buffer cần thiết trong ReturnLength mà thông tin yêu cầu cần.
Chú ý: Con trỏ tham số này cũng phải khai báo là một biến trong Heap:
LOCAL cb_x : DWORD
-Vậy đầu tiên chúng ta không thể biết thông tin chúng ta cần bao nhiêu bytes đế chứa, do đó chúng ta sẽ gọi hàm ZwQuerySystemInformation với kích thước buffer chỉ 4byte để hàm bị sai và trả về kích thước thật thụ thông tin muốn lấy trong tham số ReturnLength. Sau đó chúng ta sẽ cấp phát mới (dùng hàm VirtualAlloc ) một vùng nhớ có kích thước bằng với ReturnLength. Cuối cùng chúng ta sẽ gọi lại hàm ZwQuerySystemInformation với các tham số phù hợp.
lea eax,cb_x
push eax
push 4
lea eax,SystemInformation
push eax
push SystemProcessesAndThreadsInformation
call [ZwQuerySystemInformation]
mov SystemInformation, FUNC(VirtualAlloc,NULL,\
[cb_x],MEM_COMMIT,PAGE_READWRITE)
push NULL
push [cb_x]
push eax
push SystemProcessesAndThreadsInformation
call [ZwQuerySystemInformation]
Sau đó chúng ta sẽ dùng một vòng lặp để lấy thông tin trong buffer của SystemInformationClass ra. Thông tin này có cấu trúc SYSTEM_PROCESS_INFORMATION. Chúng ta sẽ trích xuất nó và cho hiển thị:
invoke RtlZeroMemory,addr lvi,sizeof lvi
mov lvi.imask,LVIF_TEXT
lea eax,lpBuffer
mov lvi.pszText,eax
invoke RtlZeroMemory,addr lpBuffer,260
mov esi,[SystemInformation]
assume esi:ptr SYSTEM_PROCESS_INFORMATION
.while ([esi].NextEntryDelta)
add esi,[esi].NextEntryDelta
mov lvi.iSubItem,0
mov eax,[esi].ProcessName.Buffer
invoke wsprintf,addr lpBuffer,CTXT("%ls"),eax
invoke SendMessage,hList,LVM_INSERTITEM,NULL,addr lvi inc lvi.iSubItem
invoke wsprintf,addr lpBuffer,CTXT("%ld"),\
[esi].ProcessId
invoke SendMessage,hList,LVM_SETITEM,NULL,addr lvi
inc n
.endw
Cuối cùng chúng ta sẽ free vùng nhớ đã cấp phát trước đó
assume esi:nothing
invoke VirtualFree,[SystemInformation],10000h,MEM_DECOMMIT
invoke MessageBox,0,chr$("Method 2"),chr$("Method"),MB_OK
Sau đây là các macros cần tham khảo thêm khi coding trong project này
1/-FUNC: tương đương macro rv
Macro này sẽ gọi một hàm API và giá trị trả về trong eax, được dùng như sau:
FUNC
mov rval, FUNC(AnyProcedureCall,args ......)
Description
Call bất kỳ procedure nào với một giá trị trả về return value.
Parameters
Any procedure call complete with arguments that returns a value.
Return Value
The return value from a procedure call which is normally the EAX register.
Comments
This macro utilises (sử dụng) the "invoke" syntax and the EXITM
mov retval, FUNC(APIcall,arguments ...)
test FUNC(YourProc,arguments ...), eax
cmp FUNC(AnyProc,arguments ...), 1234
add edx, FUNC(APIcall,arguments ...)
Ví dụ 1:
mov ZwQuerySystemInformation, FUNC(GetProcAddress,FUNC(GetModuleHandle,CTXT("ntdll.dll")),CTXT("ZwQuerySystemInformation"))
Tương đương:
invoke GetModuleHandle,CTXT("ntdll.dll")
invoke GetProcAddress,eax, CTXT("ZwQuerySystemInformation")
mov ZwQuerySystemInformation,eax
Ví dụ 2:
mov hProcess, rv(OpenProcess,PROCESS_QUERY_INFORMATION or PROCESS_VM_READ,FALSE,pid)
2/-CTXT : tương đương macro chr$ hoặc SADD
chr$
mov pstr, chr$("quoted text",13,10)
Description
Write mixed text and byte data to the .DATA section and return the starting address of that data.
Parameters
A variable number of items of quoted text and byte data.
Return Value
The return value is the starting address of the data written to the .DATA section.
Comments
This macro writes directly to the .DATA section and it can use either quoted text or byte data in the normal format for the .DATA section. It can be used in places where the internal MASM reserve characters interfere with quoted text or byte data being used.
fn MessageBox,hWnd,chr$("one",13,10,"two",13,10"three",13,10),lpTitle,MB_OK
Ví dụ:
invoke GetModuleHandle,CTXT("ntdll.dll")
Tương đương:
.data
szntdll db "ntdll.dll",0
.code
invoke GetModuleHandle,addr szntdll
3/- ptr$ : tính địa chỉ một biến local
ptr$
mov lpstring, ptr$(buffer)
Description
Tính address of một biến local variable đến một biến con trỏ (pointer variable).
Parameters
1. buffer Một buffer được chỉ định trên stack.
Return Value
address of buffer.
Comments
Macro này loads address of một biến stack vào trong một register and sets the first two (2) bytes to zero. Assigning the return value to a variable makes the value into a pointer which is generally easier to use that repeatedly using LEA to obtain the address.
Ví dụ:
LOCAL pbuf :DWORD
LOCAL buffer[4096]:BYTE
mov pbuf, ptr$(buffer)
Tương đương:
lea eax, buffer
mov pbuf,eax
4/- cat$: nối nhiều string
cat$
mov lpbuffer, cat$(lpBuffer,[variable number of strings])
Mô tả
Nối nhiều string vào trong một buffer.
Tham số
1. lpBuffer The address of the source buffer to append other strings to.
2. A variable number of string addresses được gắn vào source buffer.
Return Value
Giá trị trả về là addr của source buffer mà nó có thể được quy trở lại chính nó hay đến con trỏ khác (string handle).
Comments
This is a very flexible and useful macro that can handle multiple strings in different formats. If the source buffer does not already have string data in it, the first byte MUST be set to a zero byte so it is seen as a zero length string. The source string buffer must be large enough to receive all of the string data appended to it.
Example
mov lpbuffer, cat$(lpbuffer,"The result is ",ustr$(count)," bytes in length")
Ví dụ:
mov ptxt, cat$(ptxt,"pid ",str$(pid)," ",pbuf)
5/- ustr$: chuyển một số 32bit int thành một str kết thúc zero
ustr$
mov lpResult, ustr$(uInteger)
Description
Convert an unsigned 32 bit integer to a zero terminated string.
Parameters
1. uInteger An unsigned 32 bit integer.
Return Value
The return value is the address of the zero terminated string that holds the result as an OFFSET.
Comments
Each macro call in the assembler source code provides a 20 byte long buffer in the data section to hold the results of the conversion.
3.Phương pháp 3: Using ToolHelp32 API
Một process đang running trong system sẽ được Windows lưu trữ các thông tin liên quan đến process đó như heaps, modules, threads. Tại một thời điềm nào đó, Windows sẽ lưu trữ toàn bộ các thông tin của các processes đang chạy hiện hành. Toàn bộ dữ liệu lưu trữ của các processes hiện hành tại một thời điểm gọi là một snapshot. Chúng ta sẽ dùng hàm API CreateToolhelp32Snapshot để bắt lấy snapshot của các processes hiện hành. Sau đó dùng hàm Process32First đề lấy thông tin process đầu tiên trong snapshot. Để lấy thông tin process kế tiếp trong snapshot ta dùng hàm Process32Next. Như vậy là ta có thể lấy tất cả thông tin của toàn bộ processes đang running. Thông tin lấy được chứa trong mọt cấu trúc có tên là PROCESSENTRY32. Phương pháp này là rõ ràng nhất, và có thể thấy nó là phương pháp chính quy mà Windows khuyến cáo sử dụng.
Sau đây là một số thông tin về các hàm API liên quan sử dụng.
CreateToolhelp32Snapshot Function Bắt lấy một snapshot of các processes được chỉ định, giống như heaps, modules, và threads được sử dụng bởi các processes này. Syntax HANDLE WINAPI CreateToolhelp32Snapshot( __in DWORD dwFlags, __in DWORD th32ProcessID ); Parameters dwFlags [in] Các phần of system được included trong snapshot. Tham số này có thể là một hay nhiều giá trị sau đây.
th32ProcessID [in] process identifier of process được bao hàm trong snapshot. Tham số này có thể là zero để cho biết current process. Tham số này được sử dụng khi TH32CS_SNAPHEAPLIST, TH32CS_SNAPMODULE, TH32CS_SNAPMODULE32, hay TH32CS_SNAPALL value được chỉ định. Nói cách khác, nó được bỏ qua và tất cả các processes được included vào trong snapshot. Nếu process được chỉ định là một 64-bit process và caller là một 32-bit process, thì hàm này fails và last error code là ERROR_PARTIAL_COPY (299). Return Value Nếu function thành công, nó returns một open handle của snapshot được chỉ định. Nếu function fails, nó returns INVALID_HANDLE_VALUE. Để có được thông tin phần báo error, call GetLastError. Remarks Snapshot được bắt lấy bởi hàm này được kiểm tra bởi các tool help functions khác để cung cấp các results của chúng. Truy xuất đến snapshot chỉ được read . Snapshot handle hành động như một object handle và lệ thuộc vào các quy tắc tương tự liên quan đến các processes nào và threads nào trong đó mà nó hợp lệ. Để liệt kê các trạng thái heap hay module cho tất cả processes, chỉ định TH32CS_SNAPALL và set th32ProcessID là zero. Rồi, đối với process thêm vào trong snapshot, call CreateToolhelp32Snapshot một lần nữa, chỉ định process identifier của nó và TH32CS_SNAPHEAPLIST or TH32_SNAPMODULE value. Hủy snapshot, sử dụng hàm CloseHandle function. Chú ý rằng bạn có thể sử dụng QueryFullProcessImageName function để nhận full name of một executable image cho cả hai 32- và 64-bit processes từ một 32-bit process. Example Code Cho ví dụ, xem Taking a Snapshot and Viewing Processes. Requirements
See Also CloseHandle
Send comments about this topic to Microsoft
|
Process32First Function Nhận thông tin về first process bắt gặp trong một system snapshot. Syntax BOOL WINAPI Process32First( __in HANDLE hSnapshot, __inout LPPROCESSENTRY32 lppe ); Parameters hSnapshot [in] Một handle của snapshot trả về từ hàm gọi trước đó là hàm CreateToolhelp32Snapshot function. lppe [in, out] Một pointer trỏ đến một PROCESSENTRY32 structure. Nó chứa thông tin process như là name of executable file, process identifier, và process identifier of parent process. Return Value Returns TRUE nếu thành phần đầu tiên của process list được copy đến buffer hay khác là FALSE. ERROR_NO_MORE_FILES error value được trả về bởi GetLastError function nếu ko có processes tồn tại hay snapshot ko chứa thông tin process . Remarks Ứng dụng gọi hàm phải set dwSize member of PROCESSENTRY32 là size, đơn vị bytes, of structure. Để nhận thông tin về các processes khác đã được ghi trong snapshot tương tự, ta sử dụng hàm Process32Next function. Example Code Chi ví dụ, xem Taking a Snapshot and Viewing Processes. Requirements
See Also CreateToolhelp32Snapshot
Send comments about this topic to Microsoft
|
Process32Next Function Nhận thông tin về next process được ghi trong một system snapshot. Syntax BOOL WINAPI Process32Next( __in HANDLE hSnapshot, __out LPPROCESSENTRY32 lppe ); Parameters hSnapshot [in] Một handle của snapshot returned từ một hàm trước đó là CreateToolhelp32Snapshot function. lppe [out] Một pointer trỏ đến một PROCESSENTRY32 structure. Return Value Returns TRUE nếu phần tử kế tiếp of process list được copy đến buffer hay khác thì FALSE . Gía trị ERROR_NO_MORE_FILES error value được returned bởi GetLastError function nếu ko có processes tồn tại hay snapshot ko chứa thông tin process information. Remarks Nhận thông tin về first process thu được trong một snapshot, sử dụng Process32First function. Example Code Cho một ví dụ, xem Taking a Snapshot and Viewing Processes. Requirements
See Also CreateToolhelp32Snapshot
Send comments about this topic to Microsoft
|
PROCESSENTRY32 Structure Mô tả một entry từ list of các processes cư trú trong system address space khi một snapshot đước bắt lấy. Syntax typedef struct tagPROCESSENTRY32 { } PROCESSENTRY32, Members dwSize Size of structure, đơn vị bytes. Trước khi gọi hàm Process32First function, set thành phần này là sizeof(PROCESSENTRY32). Nếu bạn ko khởi trị đầu dwSize, thì Process32First fails. cntUsage Thành phần này ko được sử dụng và luôn set là zero. th32ProcessID Process identifier. th32DefaultHeapID Thành phần này ko được sử dụng và luôn set là zero. th32ModuleID Thành phần này ko được sử dụng và luôn set là zero. cntThreads Số execution threads được bắt đầu bởi process. th32ParentProcessID Identifier of process mà nó được cài đặt process này (its parent process). pcPriClassBase The base priority (quyền ưu tiên cơ bản) of các threads nào đó được cài đặt bởi process này. dwFlags Thành phần này ko được sử dụng, và luôn set thành zero. szExeFile Name of executable file cho process. Để nhận full path đến executable file, call Module32First function và check szExePath member of MODULEENTRY32 structure mà nó được trả về. Tuy nhiên, nếu calling process là một 32-bit process, bạn phải call QueryFullProcessImageName function để nhận full path of executable file cho một 64-bit process. Example Code Cho ví dụ, xem Taking a Snapshot and Viewing Processes. Requirements
See Also |
Thực hành:
invoke SendMessage,hList,LVM_DELETEALLITEMS,NULL,NULL
invoke CreateToolhelp32Snapshot, TH32CS_SNAPALL, 0
mov hSnapShot, eax ; store the snapshot handle
mov myProcess.dwSize, sizeof myProcess
invoke RtlZeroMemory,addr lvi,sizeof lvi
mov lvi.imask,LVIF_TEXT
invoke Process32First,hSnapShot, ADDR myProcess
.while eax
mov lvi.iSubItem,0
mov lvi.iSubItem,0
lea eax,myProcess.szExeFile
mov lvi.pszText,eax
invoke SendMessage,hList,LVM_INSERTITEM,NULL,addr lvi
inc lvi.iSubItem
lea eax,lpBuffer
mov lvi.pszText,eax
invoke wsprintf,addr lpBuffer,CTXT("%ld"),\
myProcess.th32ProcessID
invoke SendMessage,hList,LVM_SETITEM,NULL,addr lvi
invoke Process32Next,hSnapShot, ADDR myProcess
.endw
invoke CloseHandle,hSnapShot ; close snapshot handle
invoke MessageBox,0,chr$("Method 3"),chr$("Method"),MB_OK
HÉT PHẦN 1
BENINA