木马编程DIY之文本语音
冷风 德州科技职业学院
在黑防的第2期上天涯衰草(是电脑报上黑客营的老大吧呵呵)对“寿鼠”远程控制程序进行了介绍,其中有一个
功能就是“跟对方讲英语”感觉很有意思,就试着自己做了一个发现也不是太难,效果如图1所示

程序在VC6.0+WIN2000下编写分为服务端(SDK)和客户端两个文件,在其它机器的运行服务端后,就可以通过客户端让它“说话”了,如果目标
地址为空的话,会在自己的电脑上朗读。
关于文本语音
寿鼠的朗读功能就是通过文本语音实现的,文本语音又称为TTS(Text-to-Speech)它的作用就是把文本转化为语音,如果我们想
开发这种程序,需要使用软提供的软件开发包Microsoft Speech SDK,目前使用最为广泛的版本是5.1,这个包大小在65M左右在
天空,军华都可以下载到,它本身带有十分详细的开发资料,和可执行程序如图2图3所示,参考帮助文档提供的例子我们可以
很方便的做出自己的程序了。
准备工作
在开始前应该把Microsoft Speech SDK安装好,装好后进入安装目录把INCLUDE和LIB目录中的头文件与库文件复制到VC的开发目录里面
我这里是C:/Microsoft Visual Studio/VC98/Include跟LIB目录,当然你也可以在VC中设置路径(我喜欢直接复制过去)现在就可
以编写程序了
服务端编写
服务端运行后就一直在5555端口监听,收到数据就读出来,实现代码如下
#include
<
sapi.h
>
//
TTS所需要的头文件
#include < windows.h >
#include < winsock.h >
#pragma comment (lib,"ws2_32") // 加载库函数
const int buffer_len = 2048 ;
int APIENTRY WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
WSADATA wsadata;
SOCKET server;
SOCKET client;
SOCKADDR_IN serveraddr;
SOCKADDR_IN clientaddr;
int port = 5555 ;
char buffer[buffer_len];
WCHAR wbuffer[buffer_len];
memset(wbuffer, 0 , sizeof (WCHAR) * buffer_len);
memset( buffer, 0 , sizeof ( char ) * buffer_len);
WORD ver = MAKEWORD( 2 , 2 ); // 判断winsock版本
WSAStartup(ver, & wsadata); // 初始SOCKET
server = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
serveraddr.sin_family = AF_INET;
serveraddr.sin_port = htons(port);
serveraddr.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
bind(server,(SOCKADDR * ) & serveraddr, sizeof (serveraddr));
listen(server, 5 );
int len = sizeof (clientaddr);
while ( 1 ) // 循环接受连接
{
client = accept(server,(sockaddr * ) & clientaddr, & len);
while ( 1 ) // 循环接受数据
{
if (recv(client,buffer,buffer_len, 0 ) != 0 ) // 有数据则播放
{
memset(wbuffer, 0 , sizeof (WCHAR) * buffer_len);
// 必须先转换成宽字符
MultiByteToWideChar( CP_ACP,
MB_PRECOMPOSED, // character-type options
buffer, // address of string to map
buffer_len, // number of bytes in string
wbuffer, // address of wide-character buffer
buffer_len // size of buffer
);
memset( buffer, 0 , sizeof ( char ) * buffer_len);
ISpVoice * pVoice = NULL;
if (FAILED(CoInitialize(NULL))) // 处始化COM接口
{
MessageBox(NULL, " ERROR " , " Error to intiliaze COM " , 0 );
}
// 获取ISpVoice接口
HRESULT hr = CoCreateInstance(CLSID_SpVoice, NULL,CLSCTX_ALL, IID_ISpVoice, ( void ** ) & pVoice);
if ( SUCCEEDED( hr ) )
{
hr = pVoice -> Speak(wbuffer, 0 , NULL); // 开始朗读
pVoice -> Release(); // 完成后释放声音对象
pVoice = NULL;
}
CoUninitialize(); // 释放
}
else
break ; // 接受数据为0退出
}
}
closesocket(server);
closesocket(client);
WSACleanup();
return 0 ;
}
#include < windows.h >
#include < winsock.h >
#pragma comment (lib,"ws2_32") // 加载库函数
const int buffer_len = 2048 ;
int APIENTRY WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
WSADATA wsadata;
SOCKET server;
SOCKET client;
SOCKADDR_IN serveraddr;
SOCKADDR_IN clientaddr;
int port = 5555 ;
char buffer[buffer_len];
WCHAR wbuffer[buffer_len];
memset(wbuffer, 0 , sizeof (WCHAR) * buffer_len);
memset( buffer, 0 , sizeof ( char ) * buffer_len);
WORD ver = MAKEWORD( 2 , 2 ); // 判断winsock版本
WSAStartup(ver, & wsadata); // 初始SOCKET
server = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
serveraddr.sin_family = AF_INET;
serveraddr.sin_port = htons(port);
serveraddr.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
bind(server,(SOCKADDR * ) & serveraddr, sizeof (serveraddr));
listen(server, 5 );
int len = sizeof (clientaddr);
while ( 1 ) // 循环接受连接
{
client = accept(server,(sockaddr * ) & clientaddr, & len);
while ( 1 ) // 循环接受数据
{
if (recv(client,buffer,buffer_len, 0 ) != 0 ) // 有数据则播放
{
memset(wbuffer, 0 , sizeof (WCHAR) * buffer_len);
// 必须先转换成宽字符
MultiByteToWideChar( CP_ACP,
MB_PRECOMPOSED, // character-type options
buffer, // address of string to map
buffer_len, // number of bytes in string
wbuffer, // address of wide-character buffer
buffer_len // size of buffer
);
memset( buffer, 0 , sizeof ( char ) * buffer_len);
ISpVoice * pVoice = NULL;
if (FAILED(CoInitialize(NULL))) // 处始化COM接口
{
MessageBox(NULL, " ERROR " , " Error to intiliaze COM " , 0 );
}
// 获取ISpVoice接口
HRESULT hr = CoCreateInstance(CLSID_SpVoice, NULL,CLSCTX_ALL, IID_ISpVoice, ( void ** ) & pVoice);
if ( SUCCEEDED( hr ) )
{
hr = pVoice -> Speak(wbuffer, 0 , NULL); // 开始朗读
pVoice -> Release(); // 完成后释放声音对象
pVoice = NULL;
}
CoUninitialize(); // 释放
}
else
break ; // 接受数据为0退出
}
}
closesocket(server);
closesocket(client);
WSACleanup();
return 0 ;
}
实现代码挺简单的,需要注意的是在
pVoice->Speak(const WCHAR *pwcs,DWORD dwFlags,ULONG *pulStreamNumber);中pwcs是WCHAR类型的也就是Unicode编码
所以从网络收到数据后要进行Unicode转换,编码转换可以用MultiByteToWideChar API来实现,这是一个很好用的API看看上文
的代码就会用了。
客户端实现
客户端实现同样很简单,所以我就不再浪费感情了呵呵

































需要的话,还可以扩充一下,让它读中文日文什么的,不过你还得专门去下载发声补丁......而且也可以指定男音或女音
朗读不过我感觉女音比较好听嘿嘿,本文实现的功能比较简单,如果想编写功能强大的程序还是请参考Microsoft Speech SDK
的帮助文档,