2016-11-27 407 views
0

所以,我不能改变调用一个可执行文件,我需要给它不同的命令行参数比黑盒代码调用。我在想我可以制作一个可执行文件作为代理。 proc.exe位于黑盒部分所期望的位置,接受命令行参数,修改它们,然后调用原始文件procReal.exeCreateProcess失败 - 错误183

不幸的是,CreateProcess似乎无法启动,返回状态183。我查了一切,我无法找到这个。已经尝试翻转事物,将句柄继承设置为true,手动指定工作目录,而不是执行其中任何一项。没有运气。我以为有一些事情在这里的继承调用应用,使得包装作品适当直通的适当的安全上下文,但我想不出该怎么办呢?下面

代码,不相关的部分修剪。

编辑将请求后的完整代码放在这里。这没有任何意义了。它现在将部分工作,但仅限traceFilefopen部分不存在。甚至没有删除fprintfs,特别是整个部分不得不被删除。

我试着回复所有人的评论,我认为我已经排除了大部分这些问题,但是我留下了当前的异常行为。我可以从这个角度再读一点,就是说某些形式的字符串复制可能导致内存溢出,这可能吗?

#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); 
} 
+0

错误代码183名的意思是“ERROR_ALREADY_EXISTS” –

+0

是您的计算机上启用UAC?难道procReal.exe需要管理员权限?是否proc.exe有呢?你有没有尝试运行它UAC禁用? – z32a7ul

+0

基本过程可以直接运行而不需要管理员权限leges,是的。 – Vigilant

回答

2

最明显的问题是,你不能说(path+procName).c_str()因为它建立了临时字符串对象被立即丢弃,返回指针无效。 我也很怀疑假设 vector的元素必然是连续的。

修正字符串处理的代码应该是这个样子:

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'; 

(这也许不是做到这最好的方式,我不使用C++常常但它应该正常工作。 。)

修正错误处理代码,以确保最后一个错误代码读取立即,应该是这个样子:

{ 
     DWORD err = GetLastError(); 
     FILE* myfile; 
     myfile = fopen ((path+"error.txt").c_str(), "w"); 
     fprintf(myfile, "CreateProcess failed (%d).\n", int(err)); 
     fclose(myfile); 
    } 

您的代码报告错误的错误代码,因为调用fopen()会更改它。 (创建覆盖现有文件的新文件时,最后的错误代码设置为ERROR_ALREADY_EXISTS。)

存在两个更广泛的问题,这些问题在您的上下文中可能相关,也可能不重要。首先,您正在使用argv []为新进程构建命令行;这意味着命令行解析(如Parsing C Command-Line Arguments中所述)将被应用两次(一次通过您的进程并且一次通过子进程),如果命令行包含任何特殊字符(例如引号或反斜杠),则可能会造成麻烦。理想情况下,在一般情况下,您可以调用GetCommandLine()。 (当然,这使得解析字符串以去除额外的参数要困难得多。)

其次,你显然在ANSI模式下构建代码。如果命令行中包含任何宽字符(“Unicode”),则这可能会导致问题。通常认为最佳实践是始终以Unicode模式构建。您需要对代码进行的唯一重大更改是将string替换为wstring,因此它应该足够简单。

+1

从C++ 11开始,向量的元素保证是连续的。 – Buster

+0

@Buster:谢谢。据我了解,最新版本的Visual Studio *主要是* C++ 11兼容,所以部分原始代码可能是好的。 –

+0

这整理了我的所有或大部分问题,特别是GetCommandLine()部分,谢谢! – Vigilant

0

我有同样的问题。 问题似乎在那里,当我打电话可执行文件没有窗口。 我发现2个解决方案:

1. 创建泰德exe文件名的bat文件,其次是参数, 然后执行批处理文件: 的CreateProcess( “temp.bat”,NULL,.. ..等

2. 使用_spawnl