본문 바로가기
Programming/System Programming

[WIN32 / C] pipe를 통한 command prompt연결(console) - Remote Shell

by Winduck 2016. 11. 16.
반응형

이 글은 파이프 통신을 공부하며 진행하게된 코드를 기재한다. 블로그 운영도 처음이고 첫글이니 만큼 어수룩한면이 많아 이해해주길 바랍니다.^^

앞으로 나아지겠죠? ㅎㅎ

최근 개인적으로 진행하고 있는 프로젝트를 진행하기 위해 파이프를 공부하며 작성하게된 코드를 소개하겠습니다. 잡담은 여기까지~~


코드를 소개하면 작성된 프로그램은 Child프로세스로 cmd.exe를 실행 이후 부모프로세스(작성된 프로그램)와 child process사이에 파이프통신을 연결한다.

이 파이프를 통하여 부모프로세스는 child process인 cmd.exe에 cmd명령어(ipconfig,ping등)를 내릴수 있게 된다.

아래의 코드중 색으로 하이라이팅된 코드들은 진행하며 알게 되거나 삽질하게된 부분이다.


 코드

 #include<stdio.h>
#include<Windows.h>
int main(int argc, char *argv[])
{
 HANDLE hCmdIn_rd = NULL;
 HANDLE hCmdIn_wd = NULL;
 HANDLE hCmdOut_rd = NULL;
 HANDLE hCmdOut_wd = NULL;


 STARTUPINFO si = { NULL, };
 SECURITY_ATTRIBUTES sa = { NULL, };
 PROCESS_INFORMATION pi = { NULL, };


 DWORD dwsize = NULL;
 DWORD dwRead = 0;
 DWORD dwOut = 0;
 BOOL shutdown_flag = FALSE;
 char cmd[1000] = { "", };
 char result[1000] = { "", };
 sa.nLength = sizeof(PSECURITY_ATTRIBUTES);
 sa.lpSecurityDescriptor = NULL;
 sa.bInheritHandle = TRUE;


 CreatePipe(&hCmdIn_rd, &hCmdIn_wd, &sa, 0);
 CreatePipe(&hCmdOut_rd, &hCmdOut_wd, &sa, 0);
 si.cb = sizeof(STARTUPINFO);
 si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
 si.hStdOutput = hCmdOut_wd;
 si.hStdError = hCmdOut_wd;
 si.hStdInput = hCmdIn_rd;
 si.wShowWindow = SW_SHOW;
 if (!CreateProcess(NULL, "cmd.exe", NULL, NULL, TRUE, CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi))
 {
  printf("CreateProcess Fail : %d", GetLastError());
 }
 while (PeekNamedPipe(hCmdOut_rd, NULL, 0, NULL, &dwOut, NULL) && dwOut>0)
 {
  if (!ReadFile(hCmdOut_rd, result, sizeof(result), &dwsize, NULL))
  {
   printf("ReadFile Fail : %d\n", GetLastError());
   break;
  }
  puts(result);
 }
 ZeroMemory(result, sizeof(result));
 while (!shutdown_flag) {
  printf("명령어를 입력하시오 : ");
  scanf("%s", cmd);
  strcat(cmd, "\r\n");
  fflush(stdin);
  if (!WriteFile(hCmdIn_wd, cmd, strlen(cmd), &dwsize, NULL))
  {
   printf("WriteFile Fail : %d", GetLastError());
  }
  while (PeekNamedPipe(hCmdOut_rd, NULL, 0, NULL, &dwOut, NULL))
  {
   if (WaitForSingleObject(pi.hProcess, 0) != WAIT_TIMEOUT)
   {
    printf("프로세스 종료됨\n");
    shutdown_flag = TRUE;
    break;
   }
   if (dwOut <= 0) // 결과를 다 읽어온 경우
   {
    break;
   }
   while (PeekNamedPipe(hCmdOut_rd, NULL, 0, NULL, &dwOut, NULL) && dwOut > 0)
   {
    if (!ReadFile(hCmdOut_rd, result, sizeof(result), &dwsize, NULL))
    {
     printf("ReadFile Fail : %d\n", GetLastError());
     break;
    }
    puts(result);
    ZeroMemory(result, sizeof(result));
   }
  }
  ZeroMemory(cmd, sizeof(cmd));
 }
 CloseHandle(hCmdOut_rd);
 CloseHandle(hCmdOut_wd);
 CloseHandle(hCmdIn_rd);
 CloseHandle(hCmdIn_wd);
 return 0;


※빨간색 하이라이팅

- SECURITY_ATTRIBUTES.bInheritHandle(TRUE)

 : TRUE로 설정이후 CreatePipe를 할 경우 이후 설정된 값(TRUE)을 통해 생성된 파이프는 핸들테이블에서 상속가능한 핸들로 설정된다.

-CreateProcess 5 Parameter(TRUE)

 : TRUE로 설정될 경우 핸들테이블의 상속가능한 핸들들을 하위 프로세스에게 상속한다.

 (즉 위 SECURITY_ATTRIBUTES.bInheritHandle가 TRUE로 생성된 리소스(파이프등)의 핸들이 상속된다.)


※연두색 하이라이팅

-표준 입출력관련 핸들로써 이를 파이프로 연결하여 마우스,모니터를 통해 명령어를 주고 결과값을 읽어올 수 있게 된다.


※파란색 하이라이팅

-"\r\n"를 통하여 명령어의 끝을 알수있다. 즉 "\r\n"은 키보드 Enter로 인식하여 넘겨야 된다.

 (이것때문에 명령어가 넘어가도 Enter를 치지 않기때문에 ReadFile을 통하여 명령어가 실행되지 않았다. ㅠㅠ 삽질업청했네요...)


위 코드를 통하여 프로세스간통신(IPC)를 연결해보았고 공부하며 더불어 커널오브젝트 핸들상속에 대해 공부하게되었습니다. 이 게시판은 코드게시판으

로 파이프에 대해 알게 된 사실들(커널오프젝트 핸들상속)은 Windows게시판에 게시합니다.

이상으로 부족한 첫 게시글을 봐주셔서 감사합니다~^^ 열공합시닷!!!  

반응형

댓글