2017-01-12 3 views
0

У меня возникли проблемы с записью WString в STDIN дочернего процесса. Если у меня есть только строка символов acii (например: @ WSX3edc), код работает нормально, но если он содержит символ не ascii (например: @ WSX3edcß), он терпит неудачу.Как отправить буфер wstring в stdin дочернего процесса?

Детский процесс - 7zr.exe (версия 7Zip cmd). Вход, который я пишу в STDIN, является паролем для извлечения файла.

// inject password 
wPassword.append(password); 
wPassword.append(L"\n"); \\For carriage return 
... 
DWORD dwBytesToWrite = wPassword.length()*sizeof(wchar_t); 
DWORD dwBytesWritten = 0; 
char szBuffer[1024] = "\0"; 
wcstombs(szBuffer, wPassword.c_str(),wcslen(wPassword.c_str())+1); 
dwBytesToWrite = strlen(szBuffer); 
if (!WriteFile(hInput, szBuffer, dwBytesToWrite, &dwBytesWritten, NULL)) { 
    std::cout<<"write file failed"<<GetLastError()<<std::endl; 
    goto Cleanup; 
} 

Файл записи всегда преуспевает, но некоторые из них, как извлечение файла не удается из-за неправильного ввода пароля.

CreateProcess для этого выглядит следующим образом: (объект си имеет STDIN и STDOUT потоков с использованием набора CreatePipe ранее)

if(!CreateProcess((LPWSTR)cmd, (LPWSTR)cmdArgs, NULL, NULL, TRUE, NORMAL_PRIORITY_CLASS, 
     NULL, NULL, &si, &pi)) { 
     std::cout<<"7zr.exe process creation failed "<<GetLastError()<<std::endl; 
     goto Cleanup; 
} 

Примечание: 7zr.exe прекрасно работает с этим конкретным паролем, если мы запустим в командной строке и вставьте этот пароль. Добыча отлично работает.

ответ

2

Если узкий набор символов не имеет соответствующего символа пароля, вы не можете использовать этот подход. Вместо этого найдите, какой параметр 7zr имеет для указания пароля. У меня нет исполняемого файла 7zr, но у меня есть 7z, и команда 7z | find /i "pass" работала красиво.


В других новостях:

  • dwBytesToWrite переменная инициализируется с одним значением, только переназначить несколько строк позже, не будучи использованы.

  • goto Cleanup в целом непродуктивен в C++. Если вы хотите, чтобы гарантированная очистка использовала деструктор (метод RAII, читайте на нем).

  • Венгерская нотация Microsoft с префиксами, такими как sz и dw, как правило, мерзость. В 1980-х годах он поддерживал систему помощи в Workbench Microsoft Programmer. AFAIK, что продукт не существовал последние 30 лет или около того.

  • C cast in (LPWSTR)cmd может легко ввести ошибку. Используйте const_cast, где вы хотите использовать константу. Тогда было бы более ясно, что это приведение неверно: вам нужен изменяемый буфер.

  • Вместо сообщения о неисправности в стандартный выходной поток, с помощью std::cout, рекомендуется использовать стандартный поток ошибок, либо через std::cerr или std::clog. Лучше, не делайте i/o в том месте, где обнаруживается сбой, но генерируйте исключение, чтобы связать код вызова с ним. Вызывающий код не может удалить вывод, который уже есть, uh, output.

+0

Если добавить пароль к команде самостоятельно, используя -p, этот пароль можно увидеть на процесс проводниковых инструментов. Это проблема безопасности. следовательно, непосредственно отдавая предпочтение stdin. 7zr.exe отлично работает с этим конкретным паролем, если мы запустим его в командной строке и вставим этот пароль. Добыча отлично работает. – gkns

+0

Проблема безопасности должна быть отдельным вопросом. Пожалуйста, не аннулируйте текущие ответы, добавив это требование к вопросу. Но я отвечу на него здесь, так как это так просто: если кто-то контролирует доступ к компьютеру, все ставки не действуют. злоумышленника. Остается только защититься от обычных пользователей, которые спотыкаются о пароле и ненадлежащим образом используют его. Вы можете защититься от этого с суровым предупреждением. Да, это один хороший ответ. Потому что это не проблема безопасности. Точно так же, как Microsoft UAC - это раздражение, а не безопасность, а маркетинг. –

+1

Ох. Обратите внимание, что в командной строке кодируется UTF-16. Обычно стандартный поток ввода, по заявлению, считается кодировкой Windows ANSI. Где Windows ANSI - это кодовая страница, заданная API-интерфейсом GetACP. –

1

wcslen(wide) возвращает количество широких символов в качестве аргумента wide (see).

wcstombs(narrow,wide,len) пишет не более lenбайт для narrow (see).

Теперь, если бы у нас всегда был один широкий символ = один узкий символ = один байт, у него не было бы смысла иметь две разновидности персонажей, не так ли?

Как только у вас есть широкий символ, который переводится более чем на один узкий символ, существует неопределенное поведение.

Поскольку ваш szBuffer имеет фиксированного размера, вы можете просто написать, а

wcstombs(szBuffer, wPassword.c_str(), sizeof(szBuffer)); 
+0

нет удача. с модификацией sizeof (szBuffer). Кроме того, я не понимал неопределенного поведения, вы имеете в виду, что мы не должны пытаться ничего подобного? – gkns

+0

В вашем коде есть более одной проблемы, я только указал, что в другом ответе не упоминается. –