views:

114

answers:

3

I would like to clear the command line of my process from within. For example, when viewing my process in Task Manager/Process Explorer, the command line entry would be empty.

I would like to do this within the currently running process rather than restarting the process if possible.

+2  A: 

You might try calling the GetCommandLine API function and then setting the first byte to 0. That is:

LPTSTR cmdline = GetCommandLine();
*cmdline = '\0';

I honestly don't know if that'll work or what the possible ramifications are, but it might be worth a shot.

Jim Mischel
I verified this. It is not work.
Oleg
+3  A: 

I suppose you have to modify the RTL_USER_PROCESS_PARAMETERS part of the PEB of your process (see http://en.wikipedia.org/wiki/Process_Environment_Block for example and http://undocumented.ntinternals.net/UserMode/Undocumented%20Functions/NT%20Objects/Process/PEB.html). You can try to use NtQueryInformationProcess to get PEB. Then you can modify ProcessParameters.CommandLine. I hope it will work.

UPDATED: I verified my suggestion. It works. The following test program demonstrate this:

#include <Windows.h>
#include <Winternl.h> // for PROCESS_BASIC_INFORMATION and ProcessBasicInformation
#include <stdio.h>
#include <tchar.h>

typedef NTSTATUS (NTAPI *PFN_NT_QUERY_INFORMATION_PROCESS) (
    IN HANDLE ProcessHandle,
    IN PROCESSINFOCLASS ProcessInformationClass,
    OUT PVOID ProcessInformation,
    IN ULONG ProcessInformationLength,
    OUT PULONG ReturnLength OPTIONAL);

int main()
{
    HANDLE hProcess = OpenProcess (PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
                                   FALSE, GetCurrentProcessId());
    PROCESS_BASIC_INFORMATION pbi;
    ULONG ReturnLength;
    PFN_NT_QUERY_INFORMATION_PROCESS pfnNtQueryInformationProcess =
        (PFN_NT_QUERY_INFORMATION_PROCESS) GetProcAddress (
            GetModuleHandle(TEXT("ntdll.dll")), "NtQueryInformationProcess");
    NTSTATUS status = pfnNtQueryInformationProcess (
        hProcess, ProcessBasicInformation,
        (PVOID)&pbi, sizeof(pbi), &ReturnLength);
    // remove full information about my command line
    pbi.PebBaseAddress->ProcessParameters->CommandLine.Length = 0;

    getchar(); // wait till we can verify the results
    return 0;
}

If we start the program with some parameters we will see

alt text

instead of the following seen before

alt text

Oleg
@Joe: I updated my answer to make you more easy to use `NtQueryInformationProcess`.
Oleg
Oleg, was finally able to try this (Win7-64), and it appears to work fully when run as admin, but when run with standard user permissions, TaskManager can still display the command line. Interestingly, Process Explorer does not display the passed command line in either permission scenario.
Joe
@Joe: Are you sure that you **restarted** the TaskManager process?
Oleg
Sure did. Also just noticed that when I click 'Show processes from all users' (which restarts TaskManager in admin mode) it is able to also recall the command line arguments for the admin process. I will test a few other scenarios and post back.
Joe
Update: It appears that this works on 32-bit Windows (tested on XP-32 and 7-32), but not on 64-bit Windows (tested on 7-64 and Vista-64). Perhaps because the _PEB structure is different on 64-bit Windows? http://msdn.microsoft.com/en-us/library/aa813706%28VS.85%29.aspx
Joe
@Joe: I could now reproduce the problem which you describe in the following situation: 1) the program is compiled as 32-bit application 2) the program is started on 64-bit OS (Windows 7 x64) as not administrator 3) one use 64-bit TaskManager. If one use "C:\Windows\SysWOW64\taskmgr.exe" or Process Explorer or one compile the program for X64 **without any chnages in the code** the program parameters can be deleted in my test program. Is the usage of 64-bit exe an option for you? You can test with `IsWow64Process` whether you run on 64-bit and restart another exe for example.
Oleg
Oleg: unfortunately, using a 64-bit exe is not an option (re-writing this for a VB6 app. I know...). Any thoughts on how this might be coerced to work with a 32-bit executable on 64-bit Windows?
Joe
@Joe: Could you describe more what you application do? I am sure that one could find more options to hide the parameters which you need **without** any tricks, but I should know which program start another program or be started from another program and which program should wait for the end of another program. Moreover which from the programs you can change and which can't be changed.
Oleg
I have a service-like app that runs in the background. When a hotkey is pressed, it creates a log-in window. Upon successful password entry, it stores a secret key and loads its user-interface app with the secret key in the command line. This is done to ensure that the UI-app was started by the service app via successful password, rather than an end user launching the UI-app directly via Explorer. The clearing of the cmdline was a nicety that I wanted to add to somewhat obfuscate how the two apps were talking to each other.
Joe
@Joe: There are a lot of other ways how application can communicate. The child UI-app can get a handle to an object as a parameter, like a handle to the Pipe or a handle to a Memory-Mapped Object. After the child UI-app read the information the object can be deleted. So nobody will see the secret key as a clear text. You can follow the example http://msdn.microsoft.com/en-us/library/ms682499(VS.85).aspx, but make some changes because the child process in GUI and not console application. If you will have problem to implement this scenario I could post you a small example in C which do this.
Oleg
A: 

Based on your comment above, you may wish to consider passing the secret key via an environment variable. If you set the key in the parent process environment, it will be inherited by the child process and won't be visible to outsiders quite as easily as the command line.

Greg Hewgill
You would be able to see them in process explorer. You could set it to a dummy value after reading it I suppose
Anders