The MASM Forum

General => The Workshop => Topic started by: clamicun on February 02, 2017, 02:58:59 AM

Title: The good old cmd.exe
Post by: clamicun on February 02, 2017, 02:58:59 AM
If I use this in a cmd console
tasklist.exe /? > help.txt

it works of course

If I use this in an exefile

.data
exe_file  db "C:\windows\system32\tasklist.exe",0
param1   db "/? > help.txt",0
sei         SHELLEXECUTEINFO <?>

.code

    mov     esi,offset sei
    xor     eax,eax
    mov     SHELLEXECUTEINFO.cbSize[esi],SIZEOF SHELLEXECUTEINFO
    mov     SHELLEXECUTEINFO.fMask[esi], SEE_MASK_NOCLOSEPROCESS
    mov     SHELLEXECUTEINFO.hwnd[esi],eax
    mov     SHELLEXECUTEINFO.lpVerb[esi],offset fOpen
    mov     SHELLEXECUTEINFO.lpFile[esi],offset exe_file
    mov     SHELLEXECUTEINFO.lpParameters[esi],offset param1
    mov     SHELLEXECUTEINFO.lpDirectory[esi],eax
    mov     SHELLEXECUTEINFO.nShow[esi],SW_SHOWNORMA
    mov     SHELLEXECUTEINFO.hInstApp[esi],eax
    INVOKE ShellExecuteEx,esi

It opens tasklist.exe (returns 1 ) but does not write the textfile

Where is the secret ? 
Title: Re: The good old cmd.exe
Post by: TWell on February 02, 2017, 04:18:48 AM
piping belongs to console...
exe_file  db "C:\windows\system32\cmd.exe",0
param1   db "/c tasklist.exe /? > help.txt",0
...
Title: Re: The good old cmd.exe
Post by: jj2007 on February 02, 2017, 04:26:50 AM
include \masm32\MasmBasic\MasmBasic.inc      ; download (http://masm32.com/board/index.php?topic=94.0)
  Init

  FileWrite "help1.txt", Launch$("C:\windows\system32\tasklist.exe /?")
  Let esi=FileRead$("help1.txt")
  PrintLine "Method A: [", Left$(esi, 200), "...] **", CrLf$, CrLf$

  Launch Chr$("C:\windows\system32\cmd.exe /c tasklist.exe /? ", 62, " help2.txt")
  Let esi=FileRead$("help2.txt")
  PrintLine "Method B: [", Left$(esi, 200), "...] **"

EndOfCode


Method A: [
TASKLIST [/S sistema [/U nomeutente [/P [password]]]]
         [/M [modulo] | /SVC | /V] [/FI filtro] [/FO formato] [/NH]

Descrizione:
    Questo strumento visualizza un elenco dei processi in ...] **


Method B: [
TASKLIST [/S sistema [/U nomeutente [/P [password]]]]
         [/M [modulo] | /SVC | /V] [/FI filtro] [/FO formato] [/NH]

Descrizione:
    Questo strumento visualizza un elenco dei processi in ...] **


;)
Title: Re: The good old cmd.exe
Post by: clamicun on February 02, 2017, 06:02:40 AM
TWell,
no - checked that out before. Using a computer since 1984 I am quite ok. with batch style files.

JJ, I check your code out   
Title: Re: The good old cmd.exe
Post by: clamicun on February 02, 2017, 06:13:07 AM
TWELL,
excuse me - your code works...
Thanks
Title: Re: The good old cmd.exe
Post by: clamicun on February 02, 2017, 06:58:28 AM
TWELL thanks again,

my aim was to check if mysqld.exe is running.
There are various methods to do this.

This is the shortest and easiest.

.data
exe_file db "C:\windows\system32\cmd.exe",0
param1  db "/c tasklist.exe | FINDSTR mysqld.exe > mysql.txt",0
fOpen   db "open",0

.code
start:
INVOKE ShellExecute,0,offset fOpen,offset exe_file,offset param1,NULL,SW_HIDE   
INVOKE ExitProcess,0
   
end start

If mysql.txt is empty mysqld.exe does not run
Title: Re: The good old cmd.exe
Post by: jj2007 on February 02, 2017, 07:34:52 AM
include \masm32\MasmBasic\MasmBasic.inc      ; download (http://masm32.com/board/index.php?topic=94.0)
  Init
  .if Instr_(Launch$("tasklist.exe"), "svchost", 1)
      Inkey "There is at least one svchost active"
  .else
      Inkey "Sorry, no svchost here"
  .endif
EndOfCode


No file created. Replace svchost with mysqld.exe ...
Title: Re: The good old cmd.exe
Post by: TWell on February 02, 2017, 07:59:27 AM
Or just in RealBoy(tm) style#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <tlhelp32.h>

BOOL FindProc(TCHAR *pszExe)
{
HANDLE hSnapShot;
PROCESSENTRY32 pEntry;
BOOL bFound = FALSE;

hSnapShot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (hSnapShot) {
pEntry.dwSize = sizeof(pEntry);
if (Process32First(hSnapShot, &pEntry)) {
do {
//wsprintf(szTmp, "%d %s", pEntry.th32ProcessID, pEntry.szExeFile);
if (!lstrcmp(pEntry.szExeFile, pszExe)) {
// found it
bFound = TRUE;
break;
}
} while (Process32Next(hSnapShot, &pEntry));
}
CloseHandle(hSnapShot);
}
return bFound;
}


void __cdecl WinMainCRTStartup(void)
{
if (FindProc(TEXT("explorer.exe")))
MessageBox(0,TEXT("Found explorer.exe"),0,MB_OK);
ExitProcess(0);
}
Title: Re: The good old cmd.exe
Post by: jj2007 on February 02, 2017, 08:09:04 AM
 :t
Title: Re: The good old cmd.exe
Post by: hutch-- on February 02, 2017, 10:13:18 AM
With your original question, write the data to a batch file then run the batch file. Easy to do and it always works.
Title: Re: The good old cmd.exe
Post by: jj2007 on February 02, 2017, 12:00:46 PM
One more option:

include \masm32\MasmBasic\MasmBasic.inc
  Init
  mov ecx, GetProcessArray (http://www.webalice.it/jj2006/MasmBasicQuickReference.htm#Mb1361)(?)
  .Repeat
      dec ecx
      .Break .if Sign?
  .Until Instr_(MbProc$(ecx), "\Explorer.exe", 1)
  .if Sign?
      Inkey "Explorer not found"
  .else
      Inkey "Process found: ", MbProc$(ecx)
  .endif
EndOfCode
Title: Re: The good old cmd.exe
Post by: Vortex on February 03, 2017, 05:20:56 AM
Tested with the Cygwin terminal :

$ tasklist | grep explorer.exe
explorer.exe                   688 Console                    0     44.884 K
Title: Re: The good old cmd.exe
Post by: adeyblue on February 04, 2017, 06:06:55 AM
Quote from: TWell on February 02, 2017, 07:59:27 AM
Or just in RealBoy(tm) style
Let's round it out with the Puts-hairs-on-your-chest-Real-Men(TM) method in C++ & WMI  :P

Just so I'm not reiterating things above, and to make it maybe a bit useful, this also includes how to be notified of new and ending processes without manually checking for them yourself. That functionality requires running the program as admin though. There is a method that doesn't require admin, but I haven't done it this way before so I chose this over that.


#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <stdio.h>
#include <ole2.h>
#include <wbemidl.h>

#pragma comment(lib, "wbemuuid.lib")

#define CHECK_HR_AND_RETURN(x) \
    if(FAILED(hr = (x))) \
    { \
        printf(#x " failed with hr=%x\n", hr); \
        return 1; \
    }

#define CHECK_HR(x) \
    if(FAILED(hr = (x))) \
    { \
        printf(#x " failed with hr=%x\n", hr); \
    }

#define CONCAT_INT(a, b) a##b
#define CONCAT(a, b) CONCAT_INT(a, b)

#define STACK_BSTR(contents, varName) \
    struct CONCAT(StackBStr, __COUNTER__) \
    { \
        ULONG bstrSize; \
        WCHAR text[sizeof(contents) / sizeof(WCHAR)]; \
        operator BSTR() {return text;} \
    } varName = {sizeof(contents), contents}

class ProcessNotifier : public IWbemObjectSink
{
    STDMETHOD(QueryInterface)(REFIID iid, PVOID* ppv)
    {
        *ppv = NULL;
        if(iid == IID_IUnknown || iid == IID_IWbemObjectSink)
        {
            AddRef();
            *ppv = this;
        }
        return *ppv ? S_OK : E_NOINTERFACE;
    }
    // Implement proper ref counting if using for more than this
    STDMETHOD_(ULONG, AddRef) () { return 1; }
    STDMETHOD_(ULONG, Release) () { return 1; }
    STDMETHOD(Indicate)(long numObjs, IWbemClassObject** ppObjs)
    {
        if(numObjs == 0 || ppObjs == NULL) return WBEM_E_INVALID_PARAMETER;
        for(long i = 0; i < numObjs; ++i)
        {
            if(IWbemClassObject* pProc = ppObjs[i])
            {
                HRESULT hr;
                VARIANT vName = {VT_EMPTY}, vCmdLine = {VT_EMPTY}, vPid = {VT_EMPTY};
                CIMTYPE type;
                hr = pProc->Get(L"Name", 0, &vName, &type, NULL);
                hr = pProc->Get(L"CommandLine", 0, &vCmdLine, &type, NULL);
                hr = pProc->Get(L"ProcessId", 0, &vPid, &type, NULL);
                printf("Found existing pid %lu, %ws (%ws)\n", V_UI4(&vPid), V_BSTR(&vName), V_BSTR(&vCmdLine));
                VariantClear(&vName);
                VariantClear(&vCmdLine);
                VariantClear(&vPid);
            }
        }
        return WBEM_S_NO_ERROR;
    }

    STDMETHOD(SetStatus)(long, HRESULT hr, BSTR param, IWbemClassObject*)
    {
        if(hr == WBEM_E_CALL_CANCELLED)
        {
            puts("Ending notifications for process enum");
        }
        else if(hr != WBEM_S_NO_ERROR)
        {
            printf(__FUNCTION__ " called with param=%ws, hr=%#08x\n", param, hr);
        }
        return WBEM_S_NO_ERROR;
    }
};

class ProcessChangeNotifier : public ProcessNotifier
{
    IWbemServices* pServices;
public:
    ProcessChangeNotifier(IWbemServices* pSvc) : pServices(pSvc) {}
    STDMETHOD(Indicate)(long numObjs, IWbemClassObject** ppObjs)
    {
        if(numObjs == 0 || ppObjs == NULL) return WBEM_E_INVALID_PARAMETER;
        // offset to --- is hardcoded below, change that if changing this
        // have to use Handle (aka the PID) to find the process, since it's
        // the 'key property', whatever that means
        STACK_BSTR(L"Win32_Process.Handle=\"------------", parentPath);
        for(long i = 0; i < numObjs; ++i)
        {
            if(IWbemClassObject* pProc = ppObjs[i])
            {
                HRESULT hr, hrExitCode;
                VARIANT vName, vPid, vExitCode;
                CIMTYPE type;
                hrExitCode = pProc->Get(L"ExitStatus", 0, &vExitCode, &type, NULL);
                hr = pProc->Get(L"ProcessName", 0, &vName, &type, NULL);
                hr = pProc->Get(L"ProcessId", 0, &vPid, &type, NULL);
                if(SUCCEEDED(hrExitCode))
                {
                    // this is a stopped process
                    printf("Process %ws (PID %lu) exited with code %lu\n", V_BSTR(&vName), V_UI4(&vPid), V_UI4(&vExitCode));
                    VariantClear(&vExitCode);
                }
                else
                {
                    // this is a created process
                    VARIANT vParentId, vParentName = {VT_EMPTY};
                    hr = pProc->Get(L"ParentProcessID", 0, &vParentId, &type, NULL);

                    _snwprintf(parentPath.text + 22, 11, L"%lu\"", V_UI4(&vParentId));
                    IWbemClassObject* pParentProcess = NULL;
                    // apparently calling into WMI from Indicate is bad, I don't care
                    if(SUCCEEDED(hr = pServices->GetObject(parentPath, WBEM_FLAG_RETURN_WBEM_COMPLETE, NULL, &pParentProcess, NULL)))
                    {
                        hr = pParentProcess->Get(L"Name", 0, &vParentName, &type, NULL);
                        pParentProcess->Release();
                    }
                    PCWSTR pParentName = (V_VT(&vParentName) == VT_BSTR) ? V_BSTR(&vParentName) : L"Unknown";
                    printf("Process %ws (%lu) created by process %ws\n", V_BSTR(&vName), V_UI4(&vPid), pParentName);
                    VariantClear(&vParentName);
                    VariantClear(&vParentId);
                }
                VariantClear(&vName);
                VariantClear(&vPid);
            }
        }
        return WBEM_S_NO_ERROR;
    }

    STDMETHOD(SetStatus)(long, HRESULT hr, BSTR param, IWbemClassObject*)
    {
        if(hr == WBEM_E_CALL_CANCELLED)
        {
            puts("Ending process start/stop notifications");
        }
        else if(hr != WBEM_S_NO_ERROR)
        {
            printf(__FUNCTION__ " called with param=%ws, hr=%#08x\n", param, hr);
        }
        return WBEM_S_NO_ERROR;
    }
};

int __cdecl main(int, char**)
{
    HRESULT hr;
    CHECK_HR_AND_RETURN(CoInitializeEx(NULL, COINIT_MULTITHREADED | COINIT_DISABLE_OLE1DDE));
    CHECK_HR_AND_RETURN(
        CoInitializeSecurity(
            NULL,
            -1,
            NULL,
            NULL,
            RPC_C_AUTHN_LEVEL_DEFAULT,
            RPC_C_IMP_LEVEL_IMPERSONATE,
            NULL,
            EOAC_DISABLE_AAA,
            NULL
        )
    );
    IWbemLocator* pLocator = NULL;
    CHECK_HR_AND_RETURN(CoCreateInstance(CLSID_WbemLocator, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pLocator)));
    STACK_BSTR(L"root\\cimv2", cimName);
    IWbemServices* pNamespace = NULL;
    CHECK_HR_AND_RETURN(pLocator->ConnectServer(cimName, NULL, NULL, NULL, 0, NULL, NULL, &pNamespace));
    pLocator->Release();
    CHECK_HR_AND_RETURN(CoSetProxyBlanket(pNamespace, RPC_C_AUTHN_WINNT, RPC_C_AUTHN_NONE, NULL, RPC_C_AUTHN_LEVEL_CALL, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE));

    STACK_BSTR(L"WQL", wql);
    STACK_BSTR(L"SELECT * From Win32_Process", processQuery);
    STACK_BSTR(L"SELECT * From Win32_ProcessStartTrace", newProcessQuery);
    STACK_BSTR(L"SELECT * From Win32_ProcessStopTrace", deadProcessQuery);
    ProcessNotifier procNotifier;
    CHECK_HR_AND_RETURN(pNamespace->ExecQueryAsync(wql, processQuery, 0, NULL, &procNotifier));
    ProcessChangeNotifier newProcNotifier(pNamespace);
    // these two will fail with WBEM_E_ACCESS_DENIED unless running as admin
    CHECK_HR(pNamespace->ExecNotificationQueryAsync(wql, newProcessQuery, 0, NULL, &newProcNotifier));
    CHECK_HR(pNamespace->ExecNotificationQueryAsync(wql, deadProcessQuery, 0, NULL, &newProcNotifier));
    puts("Press enter to exit");
    getchar();
    pNamespace->CancelAsyncCall(&newProcNotifier);
    pNamespace->CancelAsyncCall(&procNotifier);
    pNamespace->Release();
    CoUninitialize();
}
Title: Re: The good old cmd.exe
Post by: jj2007 on February 08, 2017, 03:03:42 AM
Quote from: adeyblue on February 04, 2017, 06:06:55 AMLet's round it out with the Puts-hairs-on-your-chest-Real-Men(TM) method in C++ & WMI  :P

Just so I'm not reiterating things above, and to make it maybe a bit useful, this also includes how to be notified of new and ending processes without manually checking for them yourself.

Great code :t

In the meantime, I've implemented a lean-and-mean FindProcess() macro based on Tim's example, see here (http://masm32.com/board/index.php?topic=94.msg63598#msg63598).