C - CreateProcess returning data from child process - c

I've done some research looking for the best method for retrieving data from a process created by CreateProcess(), but unfortunately, I have not had much luck. If anyone can point me in the proper direction that would be much appreciated.
I have a very basic console application in C. Here is the source,
int main() {
STARTUPINFO si;
PROCESS_INFORMATION pi;
char CommandLine[1024] = "\"\" \"501 Willow\" \"\" \"Greenville\" \"AL\" \"36037\"";
memset (&si, 0, sizeof(si));
memset (&pi, 0, sizeof(pi));
GetStartupInfo(&si);
si.cb = sizeof(si);
si.dwFlags = STARTF_USESHOWWINDOW;
if (CreateProcess (("C:\\pathTO\\ValidateRDI.exe"), CommandLine, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi) != 0) {
printf("Separate Process created\n");
}
else {
printf("Separate Process not created. Error occurred\n");
}
WaitForSingleObject( pi.hProcess, INFINITE );
return 0;
}
The CreateProcess runs another C console application that calls a DLL like so,
typedef void (CALLBACK* LPFNDLLFUNC1)(char*,char*,char*,char*,char*,char*,char*,char*,char*,char*,char*);
int main(int argc, char* argv[]){
HMODULE hDLL;
LPFNDLLFUNC1 lpfnDllFunc;
char name[35+1] = "";
char addr1[35+1] = "";
char addr2[35+1] = "";
char city[20+1] = "";
char state[2+1] = "";
char zip[10+1] = "";
char rdi[1+1] = "";
char returnCode[2+1] = "";
char returnText[101] = "";
char errorWarningCode[2+1] = "";
char errorWarningText[100+1] = "";
sprintf(name, argv[0]);
sprintf(addr1, argv[1]);
sprintf(addr2, argv[2]);
sprintf(city, argv[3]);
sprintf(state, argv[4]);
sprintf(zip, argv[5]);
hDLL = LoadLibraryA((LPCSTR)"ValidateRDI.dll");
if (hDLL != NULL)
{
lpfnDllFunc = (LPFNDLLFUNC1)GetProcAddress(hDLL,"ValidateAddress");
if(lpfnDllFunc)
{
lpfnDllFunc(name,addr1,addr2,city,state,zip,rdi,returnCode,returnText,errorWarningCode,errorWarningText);
}
// free library
FreeLibrary(hDLL);
}
return 1;
}
Just for a heads up, I removed some error checking to slim down the code. How would I pass back the following values (or share the variables) to the console application that calls CreateProcess():
name
addr1
addr2
city
state
zip
rdi
returnCode
returnText
errorWarningCode
errorWarningText
Any and all help is appreciated. I've thought of writing the values to a file and then accessing the data once WaitForSingleObject( pi.hProcess, INFINITE ); returns, but there must be a more efficient/better method.

Related

Windows CreateProcess and output redirection

I'm working in a C project, windows environment using WinAPI.
My function execs a command (e.g. : "dir C:\Users") it received as a param, and returns its output.
It is ran from a DLL so it must not spawn a cmd.exe windows, which means I can't use _popen. So I use CreateProcessA, and a pipe to catch stdout.
Here is the code :
char *runExec(char *command, int *contentLen) {
char *ret=NULL,*tmp=NULL;
DWORD readBytes;
int size=0;
char buffer[128],cmdBuf[4096];
HANDLE StdOutHandles[2];
CreatePipe(&StdOutHandles[0], &StdOutHandles[1], NULL, 4096);
STARTUPINFOA si;
memset(&si, 0, sizeof(si));
si.cb = sizeof(si);
si.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
si.wShowWindow = SW_HIDE;
si.hStdOutput = StdOutHandles[1];
si.hStdError = StdOutHandles[1];
PROCESS_INFORMATION pi;
snprintf(cmdBuf,4096,"cmd /C %s", command);
if (!CreateProcessA(NULL, cmdBuf, NULL, NULL, FALSE, CREATE_NO_WINDOW | DETACHED_PROCESS, NULL, NULL, &si, &pi)) {
printf("Error createProcess : %d\n",GetLastError());
return NULL;
}
CloseHandle(StdOutHandles[1]);
printf("Before read\n");
while (ReadFile(StdOutHandles[0], buffer, 127, &readBytes, NULL)){
printf("IN WHILE\n");
buffer[readBytes] = 0;
printf("read %d bytes\n", readBytes);
size += readBytes;
tmp = (char *)realloc(ret, size + 1);
if (tmp == NULL) {
free(ret);
return NULL;
}
ret = tmp;
strncpy(ret + (size - readBytes), buffer, readBytes);
ret[size] = 0;
}
printf("Readfile returned with %d, read %d\n", GetLastError(),readBytes);
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
CloseHandle(StdOutHandles[0]);
printf("#%s#\n", ret);
return ret;
}
And the output is :
Before read
Readfile returned with 109, read 0
#(null)#
So from that I understand that :
- My loop isn't even executed once
- ReadFile reads nothing and returns Broken Pipe immediately
I have read various stackoverflow and MSDN pages, but I can't seem to make it work.
As pointed out in the comment, handles must be inheritable, which means replacing the CreatePipe like this :
SECURITY_ATTRIBUTES pipeAttrib;
memset(&pipeAttrib, 0, sizeof(pipeAttrib));
pipeAttrib.nLength = sizeof(SECURITY_ATTRIBUTES);
pipeAttrib.bInheritHandle = NULL;
pipeAttrib.bInheritHandle = TRUE;
if (!CreatePipe(&StdOutHandles[0], &StdOutHandles[1],&pipeAttrib, 4096)) {
printf("Create pipe error %d\n", GetLastError());
return NULL;
}
And setting CreateProcess 5th parameter (bInheritHandles) to TRUE instead of FALSE.

Given I have PID and Process handle, can I write to stdin of existing process using C in WINAPI

I am trying to send a message to stdin of an existing process. This process writes to stdout, and therefore a command prompt is visible when the process is running.
I have looked here, but it is specific to .net. I would like to use C with the winapi.
Here is what I have tried:
I launch an exe that runs in a command prompt. When launched, the Process ID and Process Handle for the exe are captured by calling GetHandleOfProcessByExeName() (below). My understanding , through reading the MSDN page on WriteFile(), that I should be able to pass the handle of the process along with some text to the process pointed to by the handle. Say "prg.exe", is running on Windows 7. I get its process handle, then pass it along with a message to WriteToProcess().
I expect to see text appear on the command prompt, but this has not happened yet.
Relevant code:
int main(void)
{
HANDLE h = GetHandleOfProcessByExeName("prg.exe");
//this continually fails (returns FALSE)
BOOL status = WriteToProcess("test message", sizeof("test message"));
return 0;
}
HANDLE GetHandleOfProcessByExeName(char *exe)
{
PROCESSENTRY32 entry;
HANDLE hProcess=0;
entry.dwSize = sizeof(PROCESSENTRY32);
HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (Process32First(snapshot, &entry) == TRUE)
{
while (Process32Next(snapshot, &entry) == TRUE)
{
if (stricmp(entry.szExeFile, exe) == 0)
{
hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, entry.th32ProcessID);
CloseHandle(hProcess);
}
}
}
CloseHandle(snapshot);
return hProcess;
}
BOOL WriteToProcess(char *msg, size_t size)
{
BOOL status = FALSE;
status = WriteFile(gStdinWrite, msg, size, NULL, NULL);
return status; //TRUE for success
}
Edit to response to comments:
defined as file globals:
HANDLE gStdinRead = NULL;
HANDLE gStdinWrite = NULL;
int SystemX(char *cmd, int index)
{
STARTUPINFO sj;
PROCESS_INFORMATION pj;
SECURITY_ATTRIBUTES saAttr;
HANDLE h = 0;
int exit;
saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
saAttr.bInheritHandle = TRUE;
saAttr.lpSecurityDescriptor = NULL;
ZeroMemory( &sj, sizeof(sj) );
sj.cb = sizeof(sj);
ZeroMemory( &pj, sizeof(pj) );
//create pipe and pass read end to CreateProcess
CreatePipe(&gStdinRead, &gStdinWrite, &saAttr, 0);
sj.hStdInput = gStdinRead;
sj.hStdOutput = gStdinWrite;
if(!CreateProcess(NULL, cmd, NULL, NULL, FALSE, 0, NULL, NULL, &sj, &pj))
{
return h;
}
//Wait until child processes exit.
WaitForSingleObject( pj.hProcess, IGNORE ); //ingnore signal
//Get exit code
GetExitCodeProcess(pj.hProcess, (LPDWORD)(&exit));
return exit;
}

Why don't I have to make malloc for my const variables?

I'm working on this command shell program and I wonder why I use malloc in one place and not the others? I use malloc for the tmpvariable, why not for the other variables? Why is it that one variable needs dynamic memory and not the others?
struct command
{
const char **argv;
};
int
spawn_proc (int in, int out, struct command *cmd)
{
pid_t pid;
if ((pid = fork ()) == 0)
{
if (in != 0)
{
dup2 (in, 0);
close (in);
}
if (out != 1)
{
dup2 (out, 1);
close (out);
}
return execvp (cmd->argv [0], (char * const *)cmd->argv);
}
return pid;
}
int
fork_pipes (int n, struct command *cmd)
{
int i;
pid_t pid;
int in, fd [2];
/* The first process should get its input from the original file descriptor 0. */
in = 0;
/* Note the loop bound, we spawn here all, but the last stage of the pipeline. */
for (i = 0; i < n - 1; ++i)
{
pipe (fd);
/* f [1] is the write end of the pipe, we carry `in` from the prev iteration. */
spawn_proc (in, fd [1], cmd + i);
/* No need for the write and of the pipe, the child will write here. */
close (fd [1]);
/* Keep the read end of the pipe, the next child will read from there. */
in = fd [0];
}
/* Last stage of the pipeline - set stdin be the read end of the previous pipe
and output to the original file descriptor 1. */
if (in != 0)
dup2 (in, 0);
/* Execute the last stage with the current process. */
return execvp (cmd [i].argv [0], (char * const *)cmd [i].argv);
}
int
main (int argc, char ** argv)
{
printf("in main...");
int i;
if (argc == 1) {
const char *printenv[] = { "printenv", 0};
const char *sort[] = { "sort", 0 };
const char *less[] = { "less", 0 };
struct command cmd [] = { {printenv}, {sort}, {less} };
return fork_pipes (3, cmd);
}
if (argc > 1) {
char *tmp;
// Compute required buffer length
int len = 1; // adds 1 to the length to account for the \0 terminating char
for( i=1; i<argc; i++)
{
len += strlen(argv[i]) + 2; // +2 accounts for length of "\\|"
}
// Allocate buffer
tmp = (char*) malloc(len);
tmp[0] = '\0';
// Concatenate argument into buffer
int pos = 0;
for( i=1; i<argc; i++)
{
pos += sprintf(tmp+pos, "%s%s", (i==1?"":"|"), argv[i]);
}
printf("tmp:%s", tmp);
fflush(stdout); // force string to be printed
const char *printenv[] = { "printenv", 0};
const char *grep[] = { "grep", "-E", tmp, NULL};
const char *sort[] = { "sort", 0 };
const char *less[] = { "less", 0 };
struct command cmd [] = { {printenv}, {grep}, {sort}, {less} };
return fork_pipes (4, cmd);
free(tmp);
}
}
Since the other pointers point to constant values, the data is already put into memory by the compiler. You cannot change them or the data they point to (the data is literal and resides in read-only memory block). The tmp variable will point into a mutable part of memory so you need to allocate it as such.
Of course you could allocate the memory statically so that you wouldn't need malloc for that either, but dynamic allocations are, as the name says, dynamic so you can allocate whatever amount you need defined run time and nor compile time. Like in this case, the amount of memory is not known while compiling.

How to use ldap_sasl_bind in WinLDAP?

I currently use ldap_bind_s to bind to the server in my C application with SEC_WINNT_AUTH_IDENTITY struct, but the function is marked as deprecated. For this reason I would like to change it to the ldap_sasl_bind_s function.
int main(void) {
LDAP *ld;
int rc = 0;
char *binddn = "cn=admin,dc=local";
const int version = LDAP_VERSION3;
SEC_WINNT_AUTH_IDENTITY wincreds;
struct berval saslcred;
wincreds.User = "admin";
wincreds.UserLength = 5;
wincreds.Password = "secret";
wincreds.PasswordLength = 6;
wincreds.Domain = NULL;
wincreds.DomainLength = 0;
wincreds.Flags = SEC_WINNT_AUTH_IDENTITY_ANSI;
ld = ldap_initA("localhost", LDAP_PORT);
ldap_set_optionA(ld, LDAP_OPT_PROTOCOL_VERSION, &version);
rc = ldap_bind_sA(ld, binddn, (PCHAR)&wincreds, LDAP_AUTH_DIGEST);
printf("0x%x\n", rc); // It's OK (0x0)
ldap_unbind(ld);
saslcred.bv_val = "secret";
saslcred.bv_len = 6;
rc = ldap_sasl_bind_sA(ld, binddn, "DIGEST-MD5", &saslcred, NULL, NULL, NULL);
printf("0x%x\n", rc); // Returns with 0x59
ldap_unbind(ld)
return 0;
}
The ldap_sasl_bind_s returns with LDAP_PARAM_ERROR code. Clearly, the function parameters are wrong above, but I can't find a working sample code with winldap and SASL binding.
I would be grateful for some guide, how to make this code working.
The last parameter of ldap_sasl_bind_sA cannot be NULL. It has to point to a place the function can put the server's response (struct berval*).
...
struct berval* serverResponse = NULL;
rc = ldap_sasl_bind_sA(ld, binddn, "DIGEST-MD5", &saslcred, NULL, NULL, &serverResponse);
...
So finally, after some research and debugging in the past two weeks, I've managed to write a working example code that uses DIGEST-MD5 authentication with WinLDAP's ldap_sasl_bind_s function. The corresponding RFC, this answer and the official SSPI documentation gave me a lot of helps.
Some gotchas that I ran into:
Regardless what documentation says about the ldap_connect function: If you would like to use the ldap_sasl_bind_s function it is not just a "good programming practice" to call it first, it is necessary. Without it the ldap_sasl_bind_s returns with LDAP_SERVER_DOWN (0x51) error code.
The valid pszTargetName (digest-uri) parameter is crucial for the InitializeSecurityContext function to avoid invalid token error.
I hope it will help others to spend less time about figuring out how to use SASL binding mechanisms with WinLDAP.
#include <stdio.h>
#include <windows.h>
#include <winldap.h>
#define SECURITY_WIN32 1
#include <security.h>
#include <sspi.h>
int _tmain(int argc, _TCHAR* argv[]) {
LDAP *ld;
int rc = 0;
const int version = LDAP_VERSION3;
SEC_WINNT_AUTH_IDENTITY wincreds;
struct berval *servresp = NULL;
SECURITY_STATUS res;
CredHandle credhandle;
CtxtHandle newhandle;
SecBufferDesc OutBuffDesc;
SecBuffer OutSecBuff;
SecBufferDesc InBuffDesc;
SecBuffer InSecBuff;
unsigned long contextattr;
ZeroMemory(&wincreds, sizeof(wincreds));
// Set credential information
wincreds.User = (unsigned short *)L"root";
wincreds.UserLength = 4;
wincreds.Password = (unsigned short *)L"p#ssword";
wincreds.PasswordLength = 8;
wincreds.Domain = NULL;
wincreds.DomainLength = 0;
wincreds.Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE;
res = AcquireCredentialsHandle(NULL, L"WDigest", SECPKG_CRED_OUTBOUND,
NULL, &wincreds, NULL, NULL, &credhandle, NULL);
// Buffer for the output token.
OutBuffDesc.ulVersion = 0;
OutBuffDesc.cBuffers = 1;
OutBuffDesc.pBuffers = &OutSecBuff;
OutSecBuff.BufferType = SECBUFFER_TOKEN;
OutSecBuff.pvBuffer = NULL;
ld = ldap_init(L"localhost", LDAP_PORT);
rc = ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION, (void*)&version);
rc = ldap_connect(ld, NULL); // Need to connect before SASL bind!
do {
if (servresp != NULL) {
InBuffDesc.ulVersion = 0;
InBuffDesc.cBuffers = 1;
InBuffDesc.pBuffers = &InSecBuff;
/* The digest-challenge will be passed as an input buffer to
InitializeSecurityContext function */
InSecBuff.cbBuffer = servresp->bv_len;
InSecBuff.BufferType = SECBUFFER_TOKEN;
InSecBuff.pvBuffer = servresp->bv_val;
/* The OutBuffDesc will contain the digest-response. */
res = InitializeSecurityContext(&credhandle, &newhandle, L"ldap/localhost", ISC_REQ_MUTUAL_AUTH | ISC_REQ_ALLOCATE_MEMORY,
0, 0, &InBuffDesc, 0, &newhandle, &OutBuffDesc, &contextattr, NULL);
}
else {
res = InitializeSecurityContext(&credhandle, NULL, L"ldap/localhost", ISC_REQ_MUTUAL_AUTH, 0, 0, NULL, 0, &newhandle, &OutBuffDesc, &contextattr, NULL);
}
switch (res) {
case SEC_I_COMPLETE_NEEDED:
case SEC_I_COMPLETE_AND_CONTINUE:
case SEC_E_OK:
case SEC_I_CONTINUE_NEEDED:
break;
case SEC_E_INVALID_HANDLE:
return -2;
case SEC_E_INVALID_TOKEN:
return -1;
default:
break;
}
struct berval cred;
cred.bv_len = OutSecBuff.cbBuffer;
/* The digest-response will be passed to the server
as credential after the second (loop)run. */
cred.bv_val = (char *)OutSecBuff.pvBuffer;
// The servresp will contain the digest-challange after the first call.
rc = ldap_sasl_bind_s(ld, L"", L"DIGEST-MD5", &cred, NULL, NULL, &servresp);
ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &res)
} while (res == LDAP_SASL_BIND_IN_PROGRESS);
if (rc != LDAP_SUCCESS) {
printf("Bind failed with 0x%x\n", rc);
} else {
printf("Bind succeeded\n");
}
return 0;
}

How to kill processes by name? (Win32 API)

Basically, I have a program which will be launched more than once. So, there will be two or more processes launched of the program.
I want to use the Win32 API and kill/terminate all the processes with a specific name.
I have seen examples of killing A process, but not multiple processes with the exact same name(but different parameters).
Try below code, killProcessByName() will kill any process with name filename :
#include <windows.h>
#include <process.h>
#include <Tlhelp32.h>
#include <winbase.h>
#include <string.h>
void killProcessByName(const char *filename)
{
HANDLE hSnapShot = CreateToolhelp32Snapshot(TH32CS_SNAPALL, NULL);
PROCESSENTRY32 pEntry;
pEntry.dwSize = sizeof (pEntry);
BOOL hRes = Process32First(hSnapShot, &pEntry);
while (hRes)
{
if (strcmp(pEntry.szExeFile, filename) == 0)
{
HANDLE hProcess = OpenProcess(PROCESS_TERMINATE, 0,
(DWORD) pEntry.th32ProcessID);
if (hProcess != NULL)
{
TerminateProcess(hProcess, 9);
CloseHandle(hProcess);
}
}
hRes = Process32Next(hSnapShot, &pEntry);
}
CloseHandle(hSnapShot);
}
int main()
{
killProcessByName("notepad++.exe");
return 0;
}
Note: The code is case sensitive to filename, you can edit it for case insensitive.
I just ran into a similar problem. Here's what I came up with...
void myClass::killProcess()
{
const int maxProcIds = 1024;
DWORD procList[maxProcIds];
DWORD procCount;
char* exeName = "ExeName.exe";
char processName[MAX_PATH];
// get the process by name
if (!EnumProcesses(procList, sizeof(procList), &procCount))
return;
// convert from bytes to processes
procCount = procCount / sizeof(DWORD);
// loop through all processes
for (DWORD procIdx=0; procIdx<procCount; procIdx++)
{
// get a handle to the process
HANDLE procHandle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, procList[procIdx]);
// get the process name
GetProcessImageFileName(procHandle, processName, sizeof(processName));
// terminate all pocesses that contain the name
if (strstr(processName, exeName))
TerminateProcess(procHandle, 0);
CloseHandle(procHandle);
}
}
void kill(std::string filename, int delay)
{
filename += ".exe";
HANDLE hSnapShot = CreateToolhelp32Snapshot(TH32CS_SNAPALL, NULL);
PROCESSENTRY32 pEntry;
pEntry.dwSize = sizeof(pEntry);
BOOL hRes = Process32First(hSnapShot, &pEntry);
while (hRes) {
if (filename.c_str() == pEntry.szExeFile) {
HANDLE hProcess = OpenProcess(PROCESS_TERMINATE, 0, (DWORD)pEntry.th32ProcessID);
if (hProcess != NULL) {
TerminateProcess(hProcess, 9);
CloseHandle(hProcess);
}
}
hRes = Process32Next(hSnapShot, &pEntry);
}
CloseHandle(hSnapShot);
}
// usage
int main()
{
kill("notepad");
}
I know this is old but i feel as if i should explain some of the issues and bad practice with the 2011 anwer. There is absolutely no reason for you to be writing c in c++ unless you need to. The use of const char array is unnecessary as std::string::c_str() already returns a pointer to the string. As you can see in my snippet... - filename is no longer a const char, instead its a string because its native c++ and good practice - strcmp check is removed as there is no reason to compare string differences. Instead we check if they're equivalent - We append ".exe" to filename so you can type the process name without the .exe There is simply no reason to write c in c++ unless its mandatory.

Resources