News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests
NB: Posting URL's See here: Posted URL Change

Main Menu

issues with dereferencing iteration of array of long elements in a loop

Started by cyrus, January 14, 2024, 12:20:40 PM

Previous topic - Next topic

sinsi

Quote from: NoCforMe on January 15, 2024, 01:33:04 PMAbout your question about using a static buffer (one declared in your .data section) instead of one allocated on the stack: pretty much 6 of one, half a dozen of the other. Not more or less efficient either way. It's true that you can initialize the static buffer when you declare it. But again, if you're using it multiple times with your Enum function, there's no need to "clear" it each time anyhow. A static buffer will take up space in your program; however, you can minimize the space it occupies in the .exe file by declaring it in your .data? section (uninitialized data), but then you can't initialize it in the declaration; you'll have to use code to initialize it if you need to do that.
Just to add to that, if your procedure is recursive, or gets called by multiple threads, you have to use the stack, otherwise each running procedure will clobber the other's buffer (since it is the same buffer).

jj2007

Quote from: NoCforMe on January 15, 2024, 01:33:04 PMdeclaring it in your .data? section (uninitialized data), but then you can't initialize it in the declaration
The OS loader will do that for you: .data? is always zeroed at program start. Of course, if you write to that buffer and come back later, you need to zero it again.

HSE

With little modifications for Masm64 SDK (and perhaps a couple of issues) apparently work correctly:
include \masm32\include64\masm64rt.inc

include \masm32\include64\psapi.inc
includelib \masm32\lib64\psapi.lib

.data
    aProcesses      DD 1024 DUP(0)  ;  unsigned long aProcesses[1024]
    cbNeeded        DQ ?
    cProcesses      DQ ?
    hProcess        DQ ?

;    pName db "notepad.exe",0
    pName db "qeditor.exe",0
    found db "pid found!",0
    not_found db "pid not found!",0

.code

entry_point proc

    sub rsp, 28h                    ;reserve stack space for called functions
    and rsp, 0fffffffffffffff0h    ;make sure stack 16-byte aligned

    begin:

    ; if(!EnumProcesses(aProcesses, sizeof(aProcesses), &cbNeeded))
    ;    return false;

    lea r8, cbNeeded      ; &cbNeeded; use lea whenever var is [out]
    mov rdx, 1000h        ; sizeof(aProcesses); 4096
    lea rcx, aProcesses    ; long aProcesses[1024] array to hold 1024 pids; use lea whenever var is [out]; pointers are passed by reference; like &
    sub rsp, 20h
    call EnumProcesses
    add rsp, 20h            ; >>> this was missing

    xor rax, rax
    xor rbx, rbx
    mov ax, WORD PTR [cbNeeded]  ; dereferenced; do not use lea
    sar eax, 2                    ; does the same thing as the division below. i've debugged this
    ;mov bl, 4h                  ; size of long
    ;div bl
    mov cProcesses, rax          ; ax contains quotient; dx contains remainder


    ; for(unsigned int i = 0; i < cProcesses; i++)
    ; {
    ;    if(aProcesses[i] == 0)
    ;        continue;

    mov r14, cProcesses      ; cProcesses contains the number of total processes
    lea rbx, aProcesses      ; all processes;  the entire array
 
    find_pid:
        mov eax, DWORD PTR [rbx] ; this should be the PID but having trouble getting this to work
        add rbx, 4h              ; incrementing to the next element; long is 4 bytes each
        cmp eax, 0              ; check if null
        je continue

        jmp open_process

        continue:
            dec r14              ; (while --ecx) in c; r14 is the counter
            cmp r14, 0
            je no__match

            jmp find_pid         


    open_process:
    ;    HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, 0, aProcesses[i]);

    mov r8d, eax            ; eax = aProcesses[i] ; each element is 4 bytes, not 1
    xor rdx, rdx            ; arg2 = NULL
    mov rcx, 410h          ; PROCESS_QUERY_INFORMATION: 400h;  PROCESS_VM_READ 10h; add them both = 410h
    sub rsp, 20h
    call OpenProcess
    mov hProcess, rax
    add rsp, 20h

    ;    char buf[256];
    ; we add 256 bytes on the stack since we want a clean buffer generated for each loop
    xor rax, rax
    xor rcx, rcx
    mov al, 20h  ; 32 bytes x 8 (push rcx) = 0x100 (256) bytes is needed for 'char buf[256]'
    init_buf:
        push rcx
        dec al
        cmp al, cl
        jne init_buf


    lea r15, [rsp]    ; must use a register because we will need to load it into rdx for GetModuleBaseName

    ;    GetModuleBaseName(hProcess, 0, buffer, 50);

    xor r8, r8
    xor r9, r9
    mov r9, 100h              ; 256 bytes for our buffer to write information into: [out] buffer
    mov r8, r15              ; r15 has the address of our buffer on the stack
    xor rdx, rdx              ; 2nd arg = NULL
    mov rcx, hProcess
    sub rsp, 20h
    call GetModuleBaseNameA
    add rsp, 20h

    ;    CloseHandle(hProcess);
    xor rcx, rcx
    mov rcx, hProcess
    sub rsp, 20h
    call CloseHandle
    add rsp, 20h


    ;    if(strcmp(pName, buffer) == 0)
    ;        return true;
    ;   
    ;                >>  Note here where used rsi and rdi ???
    ;
    lea rcx, pName
    lea rdx, QWORD PTR [r15]  ; r15 has the address of our buffer on the stack but [r15] is the dereferenced buffer
    call szCmp
    add rsp, 100h          ; add buffer stack space back to avoid stack overflow
    cmp rax, 0
    jne match

    ; if current pid does not match, resume loop to next pid
    jmp find_pid            ; resumes loop for next pid (aProcesses[i])

    no__match:              ; none of the pids matched the string pName
    lea rcx, not_found
    sub rsp, 20h
    call vc_printf
    add rsp, 20h
    jmp exit

    match:
    lea rcx, found
    sub rsp, 20h
    call vc_printf
    add rsp, 20h

    exit:
    sub rsp, 20h
    call ExitProcess

entry_point endp

end

Equations in Assembly: SmplMath

lingo


It has to stop using MASMx86 and don't waste newbies time with it.

About EnumProcessModules:

"If this function is called from a 32-bit application running on WOW64,
it can only enumerate the modules of a 32-bit process.
If the process is a 64-bit process, this function fails and the last error code is ERROR_PARTIAL_COPY (299)."
https://learn.microsoft.com/en-us/windows/win32/api/psapi/nf-psapi-enumprocessmodules


Thank you HSE for code!
Why so complicated and incomprehensible for such a trifle!? :biggrin:


;***************************************************;
include  \masm32\include64\masm64rt.inc
include   \masm32\include64\psapi.inc
includelib \masm32\lib64\psapi.lib
include     \masm32\include64\ntdll.inc
includelib   \masm32\lib64\ntdll.lib
;***************************************************;

.data

SaveRBX     dq 0
SaveRSI     dq 0
SaveRDI     dq 0
lphModule   dq 0
aProcesses  dd 1024 DUP(0)   
uModuleName db 520 Dup(0)
cbNeeded    dd 0
hProcess    dd 0
lpcbNeeded  dd 0 
uName       dw "n","o","t","e","p","a","d",".","e","x","e",0,0,0,0
szMessTitle dw "n","o","t","e","p","a","d",".","e","x","e"," ","i","s"," ","f","o","u","n","d","!",0,0,0,0
uString     dw "%","l","u",0,0,0,0 
szMess      dw "P","I","D",":"," "
szUBuff     db 56 Dup(0)
;****************************************************;

.code
;****************************************************;
main              proc
                    sub     rsp, 48 

; Get the list of process identifiers.
;BOOL EnumProcesses( [out] DWORD *lpidProcess,[in] DWORD cb, [out] LPDWORD lpcbNeeded

                    lea     r8,  cbNeeded            ; Result
                    mov     edx, 1000h               ; cb ->   The size of the pProcessIds array, in bytes.
                    lea     rcx, aProcesses          ; A pointer to an array that receives the list of process identifiers
                    call    EnumProcesses 
                    test    eax, eax 
                    je      Ret_0

; Calculate how many process identifiers were returned.

                    mov     eax, cbNeeded            ; cbNeeded bytes / 4 = cProcesses
                    shr     eax,2                    ; cProcesses = cbNeeded / sizeof(DWORD);   

; Print the name and process identifier for each process.

                    test    eax, eax 
                    je      Ret_0   

                    mov     SaveRBX, rbx
                    mov     SaveRSI, rsi
                    mov     SaveRDI, rdi
                   
                    lea     rbx, aProcesses          ; rbx -> DWORD aProcesses[1024]                         
                    mov     edi, eax                 ; edi->cProcesses
     
;****************************************************;
@Loop:
                    mov     r8d,dword ptr [rbx]      ; edi->get current PID   
                    test    r8d,r8d 
                    je      @Next       

;HANDLE OpenProcess(  [in] DWORD dwDesiredAccess,  [in] BOOL  bInheritHandle,  [in] DWORD dwProcessId);

                    xor     edx,edx                  ; BOOL  bInheritHandle 
                    mov     ecx,410h                 ; dwDesiredAccess 
                    call    OpenProcess 
                    mov     rsi,rax                  ; rsi=rax=open handle to the specified process
                    test    rax,rax                  ; If rax=0 -> not every process can be opened !!!
                    je      @Skip                    ; and skip it
                       
;BOOL EnumProcessModules( [in]  HANDLE  hProcess, [out] HMODULE *lphModule,[in] DWORD cb,[out] LPDWORD lpcbNeeded);

                    lea     r9, lpcbNeeded           ; lpcbNeeded -> The number of bytes required to store all module handles in the lphModule array
                    mov     r8d,8             ; cb -> The size of the lphModule array, in bytes
                    lea     rdx,lphModule            ; Result -> *lphModule
                    mov     rcx,rax                  ; rcx = rax = hProcess
                    call    EnumProcessModules 
                    test    eax,eax                  ; If eax = zero->Error
                    je      @Skip                    ; 

;DWORD GetModuleBaseNameW( [in] HANDLE  hProcess, [in, optional] HMODULE hModule,[out] LPWSTR lpBaseName, [in] DWORD nSize);

                    mov     rdx, lphModule           ; rdx -> *lphModule
                    lea     r8,  uModuleName         ; Buffer for currebt ModulName
                    mov     r9d, 104h             ; nSize of lpBaseName in bytes
                    mov     rcx, rsi             ; rcx=rsi -> hProcess
                    call    GetModuleBaseNameW
                    test    eax, eax
                    je      @Skip
;...Compare...
                    lea     rcx, uModuleName 
                    lea     rdx, uName
                    call    _wcsicmp
                    test    eax, eax
                    jne     @Skip
;....Found it...
                    xor     r9d, r9d
                    mov     r8d, dword ptr[rbx]      ; PID
                    lea     rdx, uString
                    lea     rcx, szUBuff
                    call    wsprintfW
                    xor     r9d, r9d
                    lea     r8,  szMessTitle
                    lea     rdx, szMess
                    xor     ecx, ecx
                    call    MessageBoxW
                    mov     eax, dword ptr [rbx]
                    jmp     Ret_1
@Skip:
                    mov     rcx,rsi                   ; rcx=rsi -> hProcess
                    call    CloseHandle
@Next:
                    add     rbx,4                     ; rbx-> next ID from array aProcesses   
                    sub     rdi,1                     ; one less for rdi->cProcesses
                    jne     @Loop     
                    xor     eax,eax 
Ret_1:                                           
                    mov     rbx, SaveRBX
                    mov     rsi, SaveRSI
                    mov     rdi, SaveRDI
                    add     rsp,48 
                    ret 
Ret_0:
                    xor     eax,eax 
                    add     rsp,48 
                    ret     
main              endp
;***************************************************;
End

Quid sit futurum cras fuge quaerere.

NoCforMe

Quote from: lingo on January 16, 2024, 07:52:14 AMIt has to stop using MASMx86 and don't waste newbies time with it.

No. Just no.

(They're talking about 32-bit X86 programming here.)

I'm committed to Win32/x86, and there are a hell of a lot of others here who are as well. So please don't go around making blanket prohibitions like this.

I would fight you on this but I don't want to pollute this thread.

Now back to the OP's problems. I don't know if you've already seen this stuff, but you might want to look at the Microsoft Learn pages on the 64-bit ABI, here and here (the 2nd page covers stack usage).
Assembly language programming should be fun. That's why I do it.

HSE

Hi Lingo!

Quote from: lingo on January 16, 2024, 07:52:14 AMWhy so complicated and incomprehensible for such a trifle!? :biggrin:

It's cyrus's code. He is testing things, and code is working  :thumbsup:

HSE
Equations in Assembly: SmplMath

jj2007

Quote from: lingo on January 16, 2024, 07:52:14 AMuName       dw "n","o","t","e","p","a","d",".","e","x","e",0,0,0,0
szMessTitle dw "n","o","t","e","p","a","d",".","e","x","e"," ","i","s"," ","f","o","u","n","d","!",0,0,0,0

I sincerely hope you have a tool that generates this crap, Lingo :biggrin:

I recommend wChr$(), wData or Ole$().

cyrus

I wanted to mention that I am reading these posts from you gentlemen but I have been testing another program that keeps crashing due to a stack overflow despite the fact I am adding 'add rsp, 20h' to every call and adding the correct stack space. This one was a tough one, dealing with iterating structures which I have done successfully. I will post that code shortly. I am pretty frustrated about it.

cyrus

Quote from: HSE on January 15, 2024, 11:11:02 PMWith little modifications for Masm64 SDK (and perhaps a couple of issues) apparently work correctly:
include \masm32\include64\masm64rt.inc

include \masm32\include64\psapi.inc
includelib \masm32\lib64\psapi.lib

.data
    aProcesses      DD 1024 DUP(0)  ;  unsigned long aProcesses[1024]
    cbNeeded        DQ ?
    cProcesses      DQ ?
    hProcess        DQ ?

;    pName db "notepad.exe",0
    pName db "qeditor.exe",0
    found db "pid found!",0
    not_found db "pid not found!",0

.code

entry_point proc

    sub rsp, 28h                    ;reserve stack space for called functions
    and rsp, 0fffffffffffffff0h    ;make sure stack 16-byte aligned

    begin:

    ; if(!EnumProcesses(aProcesses, sizeof(aProcesses), &cbNeeded))
    ;    return false;

    lea r8, cbNeeded      ; &cbNeeded; use lea whenever var is [out]
    mov rdx, 1000h        ; sizeof(aProcesses); 4096
    lea rcx, aProcesses    ; long aProcesses[1024] array to hold 1024 pids; use lea whenever var is [out]; pointers are passed by reference; like &
    sub rsp, 20h
    call EnumProcesses
    add rsp, 20h            ; >>> this was missing

    xor rax, rax
    xor rbx, rbx
    mov ax, WORD PTR [cbNeeded]  ; dereferenced; do not use lea
    sar eax, 2                    ; does the same thing as the division below. i've debugged this
    ;mov bl, 4h                  ; size of long
    ;div bl
    mov cProcesses, rax          ; ax contains quotient; dx contains remainder


    ; for(unsigned int i = 0; i < cProcesses; i++)
    ; {
    ;    if(aProcesses[i] == 0)
    ;        continue;

    mov r14, cProcesses      ; cProcesses contains the number of total processes
    lea rbx, aProcesses      ; all processes;  the entire array
 
    find_pid:
        mov eax, DWORD PTR [rbx] ; this should be the PID but having trouble getting this to work
        add rbx, 4h              ; incrementing to the next element; long is 4 bytes each
        cmp eax, 0              ; check if null
        je continue

        jmp open_process

        continue:
            dec r14              ; (while --ecx) in c; r14 is the counter
            cmp r14, 0
            je no__match

            jmp find_pid         


    open_process:
    ;    HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, 0, aProcesses[i]);

    mov r8d, eax            ; eax = aProcesses[i] ; each element is 4 bytes, not 1
    xor rdx, rdx            ; arg2 = NULL
    mov rcx, 410h          ; PROCESS_QUERY_INFORMATION: 400h;  PROCESS_VM_READ 10h; add them both = 410h
    sub rsp, 20h
    call OpenProcess
    mov hProcess, rax
    add rsp, 20h

    ;    char buf[256];
    ; we add 256 bytes on the stack since we want a clean buffer generated for each loop
    xor rax, rax
    xor rcx, rcx
    mov al, 20h  ; 32 bytes x 8 (push rcx) = 0x100 (256) bytes is needed for 'char buf[256]'
    init_buf:
        push rcx
        dec al
        cmp al, cl
        jne init_buf


    lea r15, [rsp]    ; must use a register because we will need to load it into rdx for GetModuleBaseName

    ;    GetModuleBaseName(hProcess, 0, buffer, 50);

    xor r8, r8
    xor r9, r9
    mov r9, 100h              ; 256 bytes for our buffer to write information into: [out] buffer
    mov r8, r15              ; r15 has the address of our buffer on the stack
    xor rdx, rdx              ; 2nd arg = NULL
    mov rcx, hProcess
    sub rsp, 20h
    call GetModuleBaseNameA
    add rsp, 20h

    ;    CloseHandle(hProcess);
    xor rcx, rcx
    mov rcx, hProcess
    sub rsp, 20h
    call CloseHandle
    add rsp, 20h


    ;    if(strcmp(pName, buffer) == 0)
    ;        return true;
    ;   
    ;                >>  Note here where used rsi and rdi ???
    ;
    lea rcx, pName
    lea rdx, QWORD PTR [r15]  ; r15 has the address of our buffer on the stack but [r15] is the dereferenced buffer
    call szCmp
    add rsp, 100h          ; add buffer stack space back to avoid stack overflow
    cmp rax, 0
    jne match

    ; if current pid does not match, resume loop to next pid
    jmp find_pid            ; resumes loop for next pid (aProcesses[i])

    no__match:              ; none of the pids matched the string pName
    lea rcx, not_found
    sub rsp, 20h
    call vc_printf
    add rsp, 20h
    jmp exit

    match:
    lea rcx, found
    sub rsp, 20h
    call vc_printf
    add rsp, 20h

    exit:
    sub rsp, 20h
    call ExitProcess

entry_point endp

end



This works now because I modified my original post. Instead of RBX for holding the address of aProcesses, I used RSI. I even modified it again to use R12 instead of RBX just in case I use RBX somewhere else. Although no functions ever use it, it is still a volatile register and it isn't wise to store the address of a pointer in there through a large loop like I have with multiple function calls within it.

jj2007

Quote from: cyrus on January 16, 2024, 02:32:30 PMAlthough no functions ever use it, it is still a volatile register

No, rbx/ebx is a non-volatile register. Windows will not modify it, with one exception: callbacks like WndProc.

HSE

Equations in Assembly: SmplMath


HSE

Equations in Assembly: SmplMath

jj2007

Quote from: cyrus on January 16, 2024, 02:32:30 PMI even modified it again to use R12 instead of RBX just in case I use RBX somewhere else. Although no functions ever use it, it is still a volatile register

1. The phrase could refer to rbx or r12, it's ambiguous
2. Both are non-volatile registers

BugCatcher