So, code I can't change calls an executable, and I need to give it different commandline args than what the black box code calls. I was figuring I could make an executable to serve as a proxy. proc.exe sits where the black box section is expecting, takes the commandline arguments, modifies them, then calls procReal.exe, the original file.
Unfortunately CreateProcess seems to fail to start, returning status 183. I've looked up everything I can and can't find out much about this. Have tried flipping things around, setting the handle inheritance to true, manually specifying the working directory, not doing either of those things. No luck. I assume there's something going on here with inheriting the proper security context of the calling application so the wrapper works as a proper passthrough, but I can't figure out how to do it...
Code below, irrelevant sections pruned.
EDIT Put the full code here after request. This isn't making any sense anymore. It now will partially work, but only if the fopen section for traceFile isn't there. Not even the fprintfs removed, specifically the whole section has to be cut out.
I've tried to respond to everyone's comments and I think I've ruled out most of those things as an issue, but am left with the current anomalous behavior. What little more I could read up on this says that some forms of copying the strings around could lead to memory overflows, is that possible at all?
#include <iostream>
#include <fstream>
#include <windows.h>
#include <string>
#include <vector>
#include <stdio.h>
#include <tchar.h>
#include <algorithm>
#include <string>
using namespace std;
bool caseInsensitiveStringCompare( const std::string& str1, const std::string& str2 );
int main(int argc, char* argv[]) {
const string path = "E:\\util\\bin\\";
const string procName = "procReal.exe";
const string argToFilter = "-t";
string origValue;
string passedValue;
for(int i = 1; i < argc; i++)
{
origValue.append(" ").append(argv[i]);
}
for(int i = 1; i < argc; i++)
{
if (!caseInsensitiveStringCompare(argv[i],argToFilter))
{
passedValue.append(" ").append(argv[i]);
}
else
{
i++; // skip over argument and it's value
}
}
const LPCTSTR exeModule = (path+procName).c_str();
std::vector<char> chars(passedValue.c_str(), passedValue.c_str() + passedValue.size() + 1u);
LPTSTR exeArgs = &chars[0];
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory( &si, sizeof(si) );
si.cb = sizeof(si);
ZeroMemory( &pi, sizeof(pi) );
GetStartupInfo(&si);
FILE* traceFile;
traceFile = fopen ((path+"lastRun.txt").c_str(), "w"); // This causes exeModule to change value for unknown reasons???
fprintf(traceFile, "orig: %s%s\n", exeModule, origValue.c_str());
fprintf(traceFile, "%s%s\n", exeModule, exeArgs);
SetLastError(0);
// Start the child process.
if( !CreateProcess( exeModule, // use module name with args for exeArgs
exeArgs, // Command line
NULL, // Process handle not inheritable
NULL, // Thread handle not inheritable
TRUE, // Set handle inheritance to FALSE
0, // No creation flags
NULL, // Use parent's environment block
NULL, // use parent's starting directory
&si, // Pointer to STARTUPINFO structure
&pi ) // Pointer to PROCESS_INFORMATION structure
)
{
FILE* myfile;
myfile = fopen ((path+"error.txt").c_str(), "w");
fprintf(myfile, "CreateProcess failed (%d).\n", int(GetLastError()));
fclose(myfile);
}
// Wait until child process exits.
WaitForSingleObject( pi.hProcess, INFINITE );
DWORD exit_code;
GetExitCodeProcess(pi.hProcess, &exit_code);
fprintf(traceFile, "Exit Code: %d\n", int(exit_code));
fclose(traceFile);
// Close process and thread handles.
CloseHandle( pi.hProcess );
CloseHandle( pi.hThread );
return exit_code;
}
bool caseInsensitiveStringCompare( const std::string& str1, const std::string& str2 ) {
std::string str1Cpy( str1 );
std::string str2Cpy( str2 );
std::transform( str1Cpy.begin(), str1Cpy.end(), str1Cpy.begin(), ::tolower );
std::transform( str2Cpy.begin(), str2Cpy.end(), str2Cpy.begin(), ::tolower );
return ( str1Cpy == str2Cpy );
}
The most obvious problem is that you can't say (path+procName).c_str() because the temporary string object it builds is discarded immediately, invalidating the returned pointer. I'm also very dubious about assuming that the elements of a vector are necessarily consecutive.
The corrected string handling code should look something like this:
string passedValue(procName); // First element of command line MUST be module name
...
const string exeModuleString(path + procName);
const LPCTSTR exeModule = exeModuleString.c_str();
LPTSTR exeArgs = new char[passedValue.size() + 1];
passedValue.copy(exeArgs, passedValue.size());
exeArgs[passedValue.size()] = '\0';
(That might not be the best way to do it; I don't use C++ often. But it should work correctly.)
The corrected error handling code, ensuring that the last error code is read immediately, should look something like this:
{
DWORD err = GetLastError();
FILE* myfile;
myfile = fopen ((path+"error.txt").c_str(), "w");
fprintf(myfile, "CreateProcess failed (%d).\n", int(err));
fclose(myfile);
}
Your code was reporting the wrong error code, because calling fopen() changes it. (When a new file is created that overwrites an existing file, the last error code is set to ERROR_ALREADY_EXISTS.)
There are two broader issues, which may or may not matter in your context. Firstly, you're using argv[] to build the command line for the new process; that means that the command line parsing (as described in Parsing C Command-Line Arguments) will be applied twice (once by your process and once by the child) which may cause trouble if the command line contains any special characters such as quote marks or backslashes. Ideally, in the general case, you would call GetCommandLine() instead. (Granted, this makes parsing the string to remove the extra argument quite a bit harder.)
Secondly, you're obviously building the code in ANSI mode. This may cause problems if the command line ever contains any wide ("Unicode") characters. It is generally accepted that best practice is to always build in Unicode mode. The only major change you'll need to make to the code is to replace string with wstring, so it should be straightforward enough.
I have the same problem.
The problem seems to be there when i call executables with no window.
I found 2 solutions:
1.
Create a bat file with the name of thet exe, followed by the arguments,
and then execute the bat file:
CreateProcess( "temp.bat" , NULL , ....etc
2.
use _spawnl
Related
I want to delete all the files which begin with sub string.
CString Formatter = _T("C:\\logs\\test\\test_12-12-2018_1*.*");
DeleteFile(Formatter);
I intend to delete following files with above code
C:\logs\test\test_12-12-2018_1_G1.txt
C:\logs\test\test_12-12-2018_1_G2.txt
C:\logs\test\test_12-12-2018_1_G3.txt
C:\logs\test\test_12-12-2018_1_G4.txt
When I check error from GetLastError, I get ERROR_INVALID_NAME.
Any idea how to fix this?
DeleteFile doesn't take wildcards. It looks like what you need is a FindFirstFile/FindNextFile/FindClose loop to turn your wildcard into a list of full file names.
#include <windows.h>
#include <pathcch.h>
#pragma comment(lib, "pathcch.lib")
// (In a function now)
WIN32_FIND_DATAW wfd;
WCHAR wszPattern[MAX_PATH];
HANDLE hFind;
INT nDeleted = 0;
PathCchCombine(wszPattern, MAX_PATH, L"C:\\Logs\\Test", L"test_12-12-2018_1*.*");
SetCurrentDirectoryW(L"C:\\Logs\\Test");
hFind = FindFirstFileW(wszPattern, &wfd);
if(hFind == INVALID_HANDLE_VALUE)
{
// Handle error & exit
}
do
{
DeleteFileW(wfd.cFileName);
nDeleted++;
}
while (FindNextFileW(hFind, &wfd));
FindClose(hFind);
wprintf(L"Deleted %d files.\n", nDeleted);
Note that PathCchCombine, FindFirstFileW, and DeleteFileW can all fail, and robust code would check their return values and handle failures appropriately. Also, if FindNextFileW returns 0 and the last error code is not ERROR_NO_MORE_FILES, then it failed because of an actual error (not because there was nothing left to find), and that needs to be handled as well.
Also, if speed is a concern of yours (your example in your post about deleting four files in the same directory doesn't seem like it needs it), replace the line hFind = FindFirstFileW(...) with:
hFind = FindFirstFileExW(wszPattern, FindExInfoBasic, (LPVOID)&wfd, FindExSearchNameMatch, NULL, FIND_FIRST_EX_LARGE_FETCH);
Although you can search for the file names, and then call DeleteFile individually for each, my advice would be to use one of the Windows shell functions to do the job instead.
For example, you could use code something like this:
#define _WIN32_IE 0x500
#include <windows.h>
#include <shellapi.h>
#include <shlobj.h>
#include <iostream>
#include <string>
static char const *full_path(std::string const &p) {
static char path[MAX_PATH+2] = {0};
char *ignore;
GetFullPathName(p.c_str(), sizeof(path), path, &ignore);
return path;
}
static int shell_delete(std::string const &name) {
SHFILEOPSTRUCT op = { 0 };
op.wFunc = FO_DELETE;
op.pFrom = full_path(name);
op.fFlags = FOF_ALLOWUNDO | FOF_SILENT | FOF_WANTNUKEWARNING | FOF_NOCONFIRMATION;
return !SHFileOperation(&op);
}
int main(int argc, char **argv) {
if ( argc < 2) {
fprintf(stderr, "Usage: delete <filename> [filename ...]");
return 1;
}
for (int i=1; i<argc; i++)
shell_delete(argv[i]);
}
One obvious advantage to this is that you can pass the FOF_ALLOWUNDO flag (as I have in the code above), which moves the files to the recycle bin instead of removing it permanently. Of course, you can omit that flag if you want to the files nuked.
Depending on what you're doing, there are a few other flags that might be handy, such as FOF_FILESONLY, to delete only files, not directories that might match the wildcard you specify, and FOF_NORECURSION to have it not recurse into subdirectories at all.
Microsoft considers SHFileOperation obsolescent, and has (in Windows Vista, if memory serves) "replaced" it with IFileOperation. IFileOperation is a COM interface though, so unless you're using COM elsewhere in your code, chances are pretty good that using it will add a fair amount of extra work for (at least in this case) little or no real advantage. Especially you're already using COM, however, this might be worth considering.
I have to execute a class file by providing the jar file path.Below is my program,
But createprocess is returning 0 with getlasterror set to 2.
Tried using sysnative instead of system32 still its not working.
Can anyone point me what is going wrong here:
char *command;
char *cmdname = "c:\\windows\\system32\\cmd.exe /C ";
char *p = " java -cp ";
char *p1 = " com.ge.med.terra.eaaa.server.EA3Server %*";
command = (char *)malloc(50);
env = getenv("GEHC_SECURITY_HOME");
strcpy(command, cmdname);
strcat(command, "\"");
strcat(command, p);
strcat(command, "\"");
strcat(command,env);
strcat(command,"\\eat\\jar\\eat.jar\";");
strcat(command, p1);
strcat(command, "\"");
result = CreateProcessA( NULL, // No module name (use command line)
command, // Command line
NULL, // Process handle not inheritable
NULL, // Thread handle not inheritable
FALSE, // Set handle inheritance to FALSE
0, // No creation flags
NULL, // Use parent's environment block
NULL, // Use parent's starting directory
&si, // Pointer to STARTUPINFO structure
&pi ) ;
You tagged this question with c++. For this reason, I would suggest you use C++ std::string class. That way, you can easily concatenate the strings necessary to create you command. It is much more concise, easier to read, all memory management is done by the class in the background (no need for malloc), and you do not need to worry about terminating the string with (maybe not for this example but in general). Here is how you do it:
std::string command = "c:\\windows\\system32\\cmd.exe /C \" java -cp \"" + std::string(env)
+ "\\eat\\jar\\eat.jar\";\"";
result = CreateProcessA(NULL, // No module name (use command line)
command.c_str(), // Command line
NULL, // Process handle not inheritable
NULL, // Thread handle not inheritable
FALSE, // Set handle inheritance to FALSE
0, // No creation flags
NULL, // Use parent's environment block
NULL, // Use parent's starting directory
&si, // Pointer to STARTUPINFO structure
&pi);
You're overflowing the buffer you allocated. You allocate space for 50 characters, but you write 105 plus whatever is in GEHC_SECURITY_HOME. When this happens, you write into some other allocated block, which will produce unspecified but undesirable behavior.
Using std::string will eliminate this, but the + operator is slow. Using std::stringstream is better if you care about the performance. But to test out whether this is the only problem, you can change your 50 to something like 500 and try again.
In the following code if I comment out the call to "GetCurrentDirectory" everything works fine, but if I don't then the code breaks after it, no child windows show up, but the program don't crash. The compiler doesn't give any error.
char *iniFilePath;
int lenWritten = GetCurrentDirectory( MAX_PATH, iniFilePath );
if( lenWritten )
{
lstrcat( iniFilePath, iniFileName.c_str() );
char *buffer;
GetPrivateProfileString( iniServerSectionName.c_str(), serverIp.c_str(), "", buffer, MAX_PATH, iniFilePath );// server ip
MessageBox( 0, buffer, 0, 0 );
}
else
{
MessageBox( 0,0,0,0 );
}
iniFilePath is an unintialised pointer which GetCurrentDirectory() is attempting to write to, causing undefined behaviour. GetCurrentDirectory() does not allocate a buffer for the caller: it must be provided.
Change to:
char iniFilePath[MAX_PATH]; // or similar.
Instead of using lstrcat(), which has Warning Do not use message on its reference page, construct the path use a std::string instead to avoid potential buffer overruns:
const std::string full_file_path(std::string(iniFilePath) + "/" + iniFileName);
Note similar issue with buffer, as pointed out by Wimmel.
I would do this in order to get the current directory -
int pathLength = GetCurrentDirectory(0, NULL);
std::vector<char> iniFilePath(pathLength);
GetCurrentDirectory(pathLength, iniFilePath.data());
Note however that this won't be thread safe as the directory could change from another thread between the two calls but as far as I know few programs change the current directory so it's unlikely to be an issue.
I've disabled line input with the following code:
DWORD dwConsoleMode;
GetConsoleMode(hStdIn, &dwConsoleMode);
dwConsoleMode ^= ENABLE_LINE_INPUT;
SetConsoleMode(hStdIn, dwConsoleMode);
Then I am calling ReadConsole in a loop...in a loop:
wchar_t cBuf;
while (1) {
/* Display Options */
do {
ReadConsole(hStdIn, &cBuf, 1, &dwNumRead, NULL);
} while (!iswdigit(cBuf));
putwchar(cBuf);
if (cBuf == L'0') break;
}
If I run the program and press 0 right away, it exists cleanly.
But if I press a bunch of keys, then press 0, when the program exists it crashes with:
Run-Time Check Failure #2 - Stack around the variable 'cBuf' was corrupted.
Why is this causing the stack to become corrupt? The code is simple, so I can't figure out what is wrong.
Little program that I can reproduce the problem with:
#include <windows.h>
#include <stdio.h>
int wmain(int argc, wchar_t *argv[])
{
DWORD dwNumRead;
wchar_t cBuf;
HANDLE hStdIn = GetStdHandle(STD_INPUT_HANDLE);
DWORD dwConsoleMode;
GetConsoleMode(hStdIn, &dwConsoleMode);
dwConsoleMode ^= ENABLE_LINE_INPUT;
SetConsoleMode(hStdIn, dwConsoleMode);
while (true)
{
wprintf(L"\nEnter option: ");
do {
ReadConsoleW(hStdIn, &cBuf, 1, &dwNumRead, NULL);
} while (!iswdigit(cBuf));
putwchar(cBuf);
if (cBuf == L'0') break;
}
return 0;
}
You have to kind of mash your keyboard after you run it, then press 0, and it crashes with the stack corruption.
I also can't reproduce the problem every time, it takes a few tries.
I was running it under Visual Studio 2010, after creating a new empty console project and adding a file with that code.
As far as I can tell, this is a bug in Windows. Here is a slightly simpler program that demonstrates the problem:
#include <windows.h>
#include <crtdbg.h>
int wmain(int argc, wchar_t *argv[])
{
DWORD dwNumRead;
wchar_t cBuf[2];
cBuf[0] = cBuf[1] = 65535;
HANDLE hStdIn = GetStdHandle(STD_INPUT_HANDLE);
SetConsoleMode(hStdIn, 0);
while (true)
{
_ASSERT(ReadConsoleW(hStdIn, &cBuf[0], 1, &dwNumRead, NULL));
_ASSERT(dwNumRead == 1);
_ASSERT(cBuf[1] == 65535);
Sleep(5000);
}
}
The sleep makes it a bit easier to trigger the issue, which occurs whenever more than one character is waiting at the time you call ReadConsoleW.
Looking at the content of cBuf[1] at the time the relevant assertion fails, it appears that ReadConsoleW is writing one extra byte at the end of the buffer.
The workaround is straightforward: make sure your buffer has at least one extra byte. In your case, use the first character of a two-character array.
Hello I have the following code but it isn't working as expected, can't figure out what the problem is.
Basically, I'm executing a process (a .NET process) and passing it command line arguments, it is executed successfully by CreateProcess() but CreateProcess() isn't passing the command line arguments
What am I doing wrong here??
int main(int argc, char* argv[])
{
PROCESS_INFORMATION ProcessInfo; //This is what we get as an [out] parameter
STARTUPINFO StartupInfo; //This is an [in] parameter
ZeroMemory(&StartupInfo, sizeof(StartupInfo));
StartupInfo.cb = sizeof StartupInfo ; //Only compulsory field
LPTSTR cmdArgs = "name#example.com";
if(CreateProcess("D:\\email\\smtp.exe", cmdArgs,
NULL,NULL,FALSE,0,NULL,
NULL,&StartupInfo,&ProcessInfo))
{
WaitForSingleObject(ProcessInfo.hProcess,INFINITE);
CloseHandle(ProcessInfo.hThread);
CloseHandle(ProcessInfo.hProcess);
printf("Yohoo!");
}
else
{
printf("The process could not be started...");
}
return 0;
}
EDIT: Hey one more thing, if I pass my cmdArgs like this:
// a space as the first character
LPTSTR cmdArgs = " name#example.com";
Then I get the error, then CreateProcess returns TRUE but my target process isn't executed.
Object reference not set to an instance of an object
You should specify also the module name in parameters: LPTSTR cmdArgs = "App name#example.com";
It should be the whole command line (including argv[0]).
If the first parameter to CreateProcess() is non-NULL, it will use that to locate the image to launch.
If it is NULL, it will parser the 2nd argument to try to get the executable to launch from the 1st token.
In either case, the C runtime will use the second argument to populate the argv array. So the first token from that parameter shows up in argv[0].
You probably want something like the following (I've change the smtp.exe program to echoargs.exe - a simple utility I have to help figure out just this kind of issue):
int main(int argc, char* argv[])
{
PROCESS_INFORMATION ProcessInfo; //This is what we get as an [out] parameter
STARTUPINFO StartupInfo; //This is an [in] parameter
char cmdArgs[] = "echoargs.exe name#example.com";
ZeroMemory(&StartupInfo, sizeof(StartupInfo));
StartupInfo.cb = sizeof StartupInfo ; //Only compulsory field
if(CreateProcess("C:\\util\\echoargs.exe", cmdArgs,
NULL,NULL,FALSE,0,NULL,
NULL,&StartupInfo,&ProcessInfo))
{
WaitForSingleObject(ProcessInfo.hProcess,INFINITE);
CloseHandle(ProcessInfo.hThread);
CloseHandle(ProcessInfo.hProcess);
printf("Yohoo!");
}
else
{
printf("The process could not be started...");
}
return 0;
}
Here's the output I get from that program:
echoargs.exe name#example.com
[0]: echoargs.exe
[1]: name#example.com
Yohoo!
It doesn't look like you are using CreateProcess correctly, see http://msdn.microsoft.com/en-us/library/ms682425%28VS.85%29.aspx.
The command line to be executed. The maximum length of this string is 32,768 characters, including the Unicode terminating null character. If lpApplicationName is NULL, the module name portion of lpCommandLine is limited to MAX_PATH characters.
The lpCommandLine parameter can be NULL. In that case, the function uses the string pointed to by lpApplicationName as the command line.
If both lpApplicationName and lpCommandLine are non-NULL, the null-terminated string pointed to by lpApplicationName specifies the module to execute, and the null-terminated string pointed to by lpCommandLine specifies the command line. The new process can use GetCommandLine to retrieve the entire command line. Console processes written in C can use the argc and argv arguments to parse the command line. Because argv[0] is the module name, C programmers generally repeat the module name as the first token in the command line.
So in your case, you need this as the command argument and should probably pass a NULL for the first parameter to get the behaviour your want.
// NOTE THE Null-Terminated string too!
LPTSTR cmdArgs = "D:\\email\\smtp.exe name#example.com\0";
Below is a cut down version of the code used by the Zeus IDE to run external processes:
bool createProcess(const char *pszTitle, const char *pszCommand)
{
STARTUPINFO StartInfo;
memset(&StartInfo, 0, sizeof(StartInfo));
StartInfo.cb = sizeof(StartInfo);
StartInfo.lpTitle = (pszTitle) ? (char *)pszTitle : (char *)pszCommand;
StartInfo.wShowWindow = SW_NORMAL;
StartInfo.dwFlags |= STARTF_USESHOWWINDOW;
if (CreateProcess(0, (char *)pszCommand,
0, 0, TRUE,
CREATE_NEW_PROCESS_GROUP, 0, 0,
&StartInfo, &ProcessInfo))
{
lErrorCode = 0;
}
else
{
lErrorCode = GetLastError();
}
return (lErrorCode == 0);
}
The pszCommand would be the full executable path and file name and arguments so for example:
pszCommand = "D:\\email\\smtp.exe name#example.com";
From what I can tell, the only real difference between the two is that in the Zeus example, the dwCreationFlags argument is set to the CREATE_NEW_PROCESS_GROUP value.
You can add a space as first character of the cmdArgs string:
LPTSTR cmdArgs = " name#example.com";
Apparently Windows appends the 2nd argument string to the application name represented by the first argument, and the result is passed as command line arguments to the executable. So adding a space will properly separate the arguments.
Try this:
LPTSTR cmdArgs = "name#example.com";
CString szcmdline("D:\\email\\smtp.exe");
szcmdline += _T(" ") + cmdArgs ;
//Leave first param empty and pass path + argms in
if(CreateProcess(NULL, szcmdline, second
The Unicode version of this function, CreateProcessW, can modify the contents of this string. Therefore, this parameter cannot be a pointer to read-only memory (such as a const variable or a literal string). If this parameter is a constant string, the function may cause an access violation.
Therefore you can try using LPTSTR cmdArgs = _tcsdup("name#example.com").
Another problem is: how does the target process reads the arguments? using argv[0] as application name? Then you shoud append the application name as the first parameter too.
You are not allocating memory for your string.
Instead of:
LPTSTR cmdArgs = "name#example.com";
try:
TCHAR cmdArgs[] = "name#example.com";
Edit:
then call:
CreateProcess("D:\\email\\smtp.exe", &cmdArgs[0], ...
This will create a local array on the stack and then pass a pointer to that array.