鱼C论坛

 找回密码
 立即注册
查看: 2061|回复: 2

[技术交流] 管道学习(一)

[复制链接]
发表于 2015-7-5 12:54:55 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
0x00
环境:win7 & VC++6.0
管道是一种特殊的进程,通常我们使用它进行线程之间的通信。管道是单向的,也就说管道中的数据传递方向只能是一个方向。
1.下面给出创建管道的函数原型:
BOOL WINAPI CreatePipe(
  _Out_    PHANDLE               hReadPipe,
  _Out_    PHANDLE               hWritePipe,
  _In_opt_ LPSECURITY_ATTRIBUTES lpPipeAttributes,
  _In_     DWORD                 nSize
);
hReadPipe :管道读句柄
hWritePipe :管道写句柄
lpPipeAttributes:确定返回的句柄是否可以被子进程继承
nSize:管道缓冲区大小,如果设置为0,则使用系统默认值

2.管道的读写可以使用ReadFile和WriteFile两个函数:
BOOL WINAPI ReadFile(
  _In_        HANDLE       hFile,
  _Out_       LPVOID       lpBuffer,
  _In_        DWORD        nNumberOfBytesToRead,
  _Out_opt_   LPDWORD      lpNumberOfBytesRead,
  _Inout_opt_ LPOVERLAPPED lpOverlapped
);

BOOL WINAPI WriteFile(
  _In_        HANDLE       hFile,
  _In_        LPCVOID      lpBuffer,
  _In_        DWORD        nNumberOfBytesToWrite,
  _Out_opt_   LPDWORD      lpNumberOfBytesWritten,
  _Inout_opt_ LPOVERLAPPED lpOverlapped
);
将文件句柄改成管道句柄就可以实现管道读写。

0x01
双管道实现读写。我们建立两个管道,一个管道循环读,一个管道循环写。
RTX截图未命名.png

我们本地端通过socket连接到远程端的一个Win32 Console Application程序,该远程端程序中实现一个Winsock和一对读写管道链接到cmd。
首先来建立两个线程函数,分别实现管道读写。
DWORD WINAPI ThreadWrite(LPVOID lpParam){
        SECURITY_ATTRIBUTES sa;
        sa.nLength = sizeof(SECURITY_ATTRIBUTES);
        sa.lpSecurityDescriptor = NULL;
        sa.bInheritHandle = TRUE;

        DWORD nByteToWrite, nByteWritten;
        char recv_buff[1024];

        //create a pipe
        CreatePipe(&hReadPipe, &hWriteFile, &sa, 0);
        while(true){
                Sleep(250);
                
                //recv client host's command
                nByteToWrite = recv(sClient, recv_buff, 1024, 0);

                //Write the pipe
                WriteFile(hWriteFile, recv_buff, nByteToWrite, &nByteWritten, NULL);
        }
        return 0;
}

DWORD WINAPI ThreadRead(LPVOID lpParam){

        SECURITY_ATTRIBUTES sa;
        sa.nLength = sizeof(SECURITY_ATTRIBUTES);
        sa.lpSecurityDescriptor = NULL;
        sa.bInheritHandle = TRUE;

        DWORD len;
        char send_buff[2048];

        CreatePipe(&hReadFile, &hWritePipe, &sa, 0);
        while(true){
                // read data from the pipe
                ReadFile(hReadFile, send_buff, 2048, &len, NULL);
                
                //send data to client host
                send(sClient, send_buff, len, 0);
        }

        return 0;
}
0x02
接下来我们启动一个cmd进程,可以使用函数:
BOOL WINAPI CreateProcess(
  _In_opt_    LPCTSTR               lpApplicationName,
  _Inout_opt_ LPTSTR                lpCommandLine,
  _In_opt_    LPSECURITY_ATTRIBUTES lpProcessAttributes,
  _In_opt_    LPSECURITY_ATTRIBUTES lpThreadAttributes,
  _In_        BOOL                  bInheritHandles,
  _In_        DWORD                 dwCreationFlags,
  _In_opt_    LPVOID                lpEnvironment,
  _In_opt_    LPCTSTR               lpCurrentDirectory,
  _In_        LPSTARTUPINFO         lpStartupInfo,
  _Out_       LPPROCESS_INFORMATION lpProcessInformation
);
但我们得将该cmd进程与我们的管道相关联,这样管道和cmd之间才能传输数据。实现它们的管理,可以在CreateProcess函数的倒数第二个参数LPSTARTUPINFO中设置,这个结构体如下:
typedef struct _STARTUPINFO {
  DWORD  cb;
  LPTSTR lpReserved;
  LPTSTR lpDesktop;
  LPTSTR lpTitle;
  DWORD  dwX;
  DWORD  dwY;
  DWORD  dwXSize;
  DWORD  dwYSize;
  DWORD  dwXCountChars;
  DWORD  dwYCountChars;
  DWORD  dwFillAttribute;
  DWORD  dwFlags;
  WORD   wShowWindow;
  WORD   cbReserved2;
  LPBYTE lpReserved2;
  HANDLE hStdInput;
  HANDLE hStdOutput;
  HANDLE hStdError;
} STARTUPINFO, *LPSTARTUPINFO;
成员很多,一个一个地去填写,很麻烦,我们可以使用一个函数返回本进程的STARTUPINFO信息,然后我们再修改一些参数以实现它与管道相关联。
VOID WINAPI GetStartupInfo(
  _Out_ LPSTARTUPINFO lpStartupInfo
);
STARTUPINFO中需要修改的参数:
dwFlags=STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES; // enable
hStdInput = hReadPipe; //read data from ThreadWrite pipe
hStdError = hWritePipe; //write data to ThreadRead pipe
hStdOutput = hWritePipe;
wShowWindow = SW_HIDE; //hide cmd window

0x03
下面给出全部的code:

这里应该是有代码的,,但鉴于上面的排版全乱了,那么给出一个word版的附件,排版稍微好点。
管道学习(一).zip (11.17 KB, 下载次数: 2)

0x04
将它在远程机上运行,作者测试使用自己的虚拟机(192.168.0.8),然后在本地启用一个telnet:
telnet 192.168.0.8 4500
这样在本地机上会得到一个shell,直接可以操控远程机。

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

 楼主| 发表于 2015-7-5 12:55:49 | 显示全部楼层
我还以为排版乱了,,结果没乱,,下次直接code了
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2015-7-5 14:06:30 | 显示全部楼层
管道有什么作用呢     
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2024-11-26 04:24

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表