UPX SHELL DEMO -- 管道控制示例
相关的例子:下载>>> 作者:yuexidong 于2008-1-17上传 

By yuexidong  mail to: pb1977@163.com

    管道的应用非常广泛,比较常用的是与 CONSOLE控制台程序的交互,比如各类IDE,大部分都是通过建立 管道来达到与ML LINK 等程序的交互。UPX ,大家都知道是一个比较优秀的压缩程序,它本身是个控制台程序,平常我们使用它只能通过 CMD 等程序来使用,非常不方便。今天带来一个小程序UPX SHELL,与大家一起学习管道的应用。  

基础知识

    1.管道分为两种,有名管道和匿名管道,匿名管道就是没有名字的管道,而有名管道正好相反。从特性上 来分,又分为单向的和双向的,单向管道,数据只能沿一个方向移动,从一端流向另一端;而双向管道数据可以在两端间自由交换 。

     匿名管道通常是单向的,而有名管道通常是双向的。匿名管道经常使用在重定向子进程的标准输入和标准输出。有名管道常用于一个服务器联络多个客户端的网 络环境。

   2.控制台应用程序有三个用于输入输出的标准句柄, 它们是标准输入、标准输出和标准错误句柄。标准输入用于从控制台读或取信息,而标准输出用于往控制台写或打印信息,标准错 误用于汇报输出不能重定向的错误。

核心的核心

     做程序,我们通常都是先完成程序的核心功能,然后再添加辅助功能的。那这个程序的核心就在于创建一个匿名管道,得到它的标 准输入和输出句柄,然后创建子进程,这样就可以通过标准输入和输出句柄与子进程交互了。

BOOL CreateProcess(
  LPCTSTR lpApplicationName,                 // name of executable module
  LPTSTR lpCommandLine,                      // command line 

string
  LPSECURITY_ATTRIBUTES lpProcessAttributes, // SD
  LPSECURITY_ATTRIBUTES lpThreadAttributes,  // SD
  BOOL bInheritHandles,                      // handle 

inheritance option
  DWORD dwCreationFlags,                     // creation 

flags
  LPVOID lpEnvironment,                      // new 

environment block
  LPCTSTR lpCurrentDirectory,                // current 

directory name
  LPSTARTUPINFO lpStartupInfo,               // startup 

information
  LPPROCESS_INFORMATION lpProcessInformation // process information
);
BOOL CreatePipe(
  PHANDLE hReadPipe,                       // read handle
  PHANDLE hWritePipe,                      // write handle
  LPSECURITY_ATTRIBUTES lpPipeAttributes,  // security attributes
  DWORD nSize                              // pipe size
);

我们通过 CreatePipe 这个函数创建管道,通过 CreateProcess 这个函数创建子进程,具体请查MSDN.

_CompressFile	proc
	LOCAL	@stSu : STARTUPINFO
	LOCAL @stPi : PROCESS_INFORMATION
	LOCAL @stSa : SECURITY_ATTRIBUTES
	LOCAL @hStdIn
	LOCAL @hStdOut
	LOCAL @bytesRead
	
		invoke	SetDlgItemText,hWinMain,IDC_OUTPUT,NULL
	
		mov	@stSa.nLength, sizeof SECURITY_ATTRIBUTES
		mov	@stSa.lpSecurityDescriptor, NULL
		mov	@stSa.bInheritHandle, TRUE
		invoke CreatePipe,addr @hStdIn,addr @hStdOut,addr @stSa,NULL
				.if eax==NULL
					invoke MessageBox,hWinMain,addr  szText4,addr szErrCaption,MB_ICONERROR+MB_OK
				.else
               mov	@stSu.cb, sizeof STARTUPINFO
	       invoke GetStartupInfo,addr @stSu
		mov eax,@hStdOut
		mov @stSu.hStdOutput, eax
		mov @stSu.hStdError, eax
		mov @stSu.dwFlags, STARTF_USESHOWWINDOW+STARTF_USESTDHANDLES
		mov @stSu.wShowWindow, SW_HIDE
					
		invoke	CreateProcess, NULL, addr szBufCmdParam, NULL, NULL, TRUE, NULL, NULL, NULL, addr @stSu, addr @stPi
					
			.if eax==NULL
				invoke MessageBox, hWinMain,addr szText5,addr szErrCaption,MB_ICONERROR+MB_OK
			.else
				invoke CloseHandle,@hStdOut
				.while TRUE
					invoke RtlZeroMemory, addr  szBufOut, sizeof szBufOut
					invoke ReadFile, @hStdIn, addr  szBufOut, 4095, addr @bytesRead, NULL
							
					.if eax==NULL
							.break
					.else
							invoke SendMessage,  hOutPut,EM_SETSEL,-1,0
							invoke SendMessage,hOutPut,EM_REPLACESEL, FALSE, addr szBufOut
					.endif
				.endw
			.endif
				invoke CloseHandle, @hStdIn
			.endif
	
	ret
_CompressFile	endp

程序分析

    首先填写 SECURITY_ATTRIBUTES 结构,

    mov @stSa.nLength, sizeof SECURITY_ATTRIBUTES
    mov @stSa.lpSecurityDescriptor, NULL
    mov @stSa.bInheritHandle, TRUE

然后就可以创建管道了

    invoke CreatePipe,addr @hStdIn,addr @hStdOut,addr @stSa,NULL

创建成功后,就可以填写 STARTUPINFO 结构,并得到标准输入和输出句柄

    mov @stSu.cb, sizeof STARTUPINFO
    invoke GetStartupInfo,addr @stSu
    mov eax,@hStdOut
    mov @stSu.hStdOutput, eax
    mov @stSu.hStdError, eax
    mov @stSu.dwFlags, STARTF_USESHOWWINDOW+STARTF_USESTDHANDLES
    mov @stSu.wShowWindow, SW_HIDE

下面就可以创建子进程了

    invoke CreateProcess, NULL, addr szBufCmdParam, NULL, NULL, TRUE, NULL, NULL, NULL, addr @stSu, addr @stPi

创建子进程时,我们没有用第一个参数 lpApplicationName,而是将它连接到第二个参数当中,这样可以防止这个函数对命令行参数 的错误解析。

创建完后,要立即关闭管道的写端,不然是不会正常工作的:

    invoke CloseHandle,@hStdOut

下面就可以从子进程的标准输出读取数据了,并输出到我们所需要的地方了。

.while TRUE
    invoke RtlZeroMemory, addr szBufOut, sizeof szBufOut
    invoke ReadFile, @hStdIn, addr szBufOut, 4095, addr @bytesRead, NULL

    .if eax==NULL
        .break
    .else
        invoke SendMessage, hOutPut,EM_SETSEL,-1,0
        invoke SendMessage,hOutPut,EM_REPLACESEL, FALSE, addr szBufOut
    .endif
.endw

最后,当然要扫尾了。

invoke CloseHandle, @hStdIn

关闭管道的读端。

这样程序的核心就搞完了,当然你在源代码中,还可以学习到其他的知识,比如INI 文件的读写,常用控件的使用。

参考:罗云彬 和 icztutes 的例程。

题外音:首先对 Zoologist 、 Aogo和其他投稿的作者表示感谢,感谢他们能始终如一的带来如此好的东东。其次,当然希望 高手们能出一下手,投稿就是对汇编通讯最大的支持。我的话讲完了,希望大家对这个小程序多提宝贵意见。



<<<上一篇
欢迎访问AoGo汇编小站:http://www.aogosoft.com
下一篇>>>