あしょこと一緒にぷろぐらみんぐを学ぼう



おにいちゃ~ん、あしょこもツール作りたいよう。

よしよし、パンツを一枚くれたら教えてあげるよ。

こないだ部屋から盗んで行ったやつがあるでしょ。

ばれてたのか……。

ちゃんと洗って返してね。


それでどんなツールが作りたいの?

あしょこね、みやもどきっていう変態につきまとわれて困ってるの。

会話無視をしたらどう?

でも何回も部屋に出入りするからめんどくさいの。

あいつは筋金入りのロリコンだからね。

だからみやもどきを永久に無視できるツールを作りたいな。

うん、教えてあげる。


どうやったら作れるのかな。

まず会話無視というものについて詳しく考えよう。

チャットで話したことが見えなくなること!

そう。だから会話無視をするにはチャットがメッセージを表示する前に……。

表示する前に誰の会話かを調べて、みやもどきだったら表示しなかったらいいんだ!

うんうん、あしょこは賢いね。


それにはどうしたらいいの。

チャットの中で流れているメッセージを捕まえないといけない。

パケットをキャプチャするのがいいのかな。

ちょっと大がかりすぎるし、そもそもチャットの通信は暗号化されてるんだ。

わかった! メッセージフックだ!!

うんうん、近づいてきたよ。

え、違うの?

実際メッセージフックするプログラムを作って試してみよう。

フックならまずは DLL を書かないとね。

とりあえず今日は C++ で書こう。一部だけを書くよ。

BOOL WINAPI DllMain( HINSTANCE hInstDLL, DWORD fdwReason, LPVOID lpReserved )
{
 if( fdwReason == DLL_PROCESS_ATTACH )
 {
  hInstance = hInstDLL;
 }

 return TRUE;
}

EXPORT BOOL APIENTRY setHook( DWORD hThread, HWND hWnd )
{
 hHookCallWnd = SetWindowsHookEx( WH_CALLWNDPROC, CallWndProc, hInstance, hThread );
 hHostWnd = hWnd;

 return TRUE;
}

チャットの表示は EM_REPLACESEL メッセージだったよ。

リッチエディットは直接ウィンドウプロシージャに流れるから、WH_CALLWNDPROC だよ。

LRESULT CALLBACK CallWndProc( int nCode, WPARAM wParam, LPARAM lParam )
{
 if( nCode == HC_ACTION )
 {
  CWPSTRUCT *cwp = (CWPSTRUCT *)lParam;

  if( cwp->message == EM_REPLACESEL )
  {
   SendMessage( hHostWnd, TEST_MESSAGE, NULL, NULL );
  }

 }
 
 return CallNextHookEx( hHookCallWnd, nCode, wParam, lParam );
}

これでいいね。SendMessage でフック元プロセスにメッセージが表示されるようにしたよ。

じゃあ実際にフックさせてみよう。


できた! 簡単だね!!

本当にそうかな?今度はメッセージの書き換えを試してごらん。

えっとー、メッセージを無効にすればいいんだからこうかな?

if( cwp->message == EM_REPLACESEL )
{
 if ( SendMessage( hHostWnd, TEST_MESSAGE, NULL, NULL ) ) cwp->message = WM_NULL;
}

うん、普通に考えるとそうだね。でも試してみると……。

あれ、そのまま表示されてる……。


実は WH_CALLWNDPROC ではメッセージの書き換えはできないんだ。

ええええー、じゃあどうするの?

ヒントを出そう。ウィンドウプロシージャのフックはできないから……。

あ、わかった。サブクラス化するんだね!

そう。あしょこはお利口さんだね。ナデナデ。

お兄ちゃん、さっきオナニーしてから手洗ってないでしょ。

じゃあさっそくサブクラス化してごらん。

SetWindowLong( hWnd, GWL_WNDPROC, (LONG)CbProc );
fnCbProc = (WNDPROC)GetWindowLong( hWnd, GWL_WNDPROC );

LRESULT CALLBACK CbProc( HWND hWnd,UINT uMsg ,WPARAM wParam, LPARAM lParam )
{

 switch( uMsg )

 {

  case EM_REPLACESEL:

   
if ( SendMessage( hHostWnd, TEST_MESSAGE, NULL, NULL ) ) uMsg = WM_NULL;
 }

 
 return CallWindowProc( fnCbProc, hWnd, uMsg, wParam, lParam );
}

これでいいはずだけど…… あれれ、できないよ?

うん、Windows では外部プロセスだからのサブクラス化は禁止されてるんだ。

えー、サブクラス化ができないならどうにもならないじゃん。

そうだね。サブクラス化できなければ方法はないよ。

お兄ちゃん、あしょこを騙したんでしょ! うえーん、ばかばか。

いててっ。ちょっと釘バットはやめてくれよ。騙してなんかないよ。

だってサブクラス化できないんでしょ。

外部プロセスからはって言っただろ?

そうか。チャット自体にコードを注入して実行させればいいんだ!


そうだね。それにはいくつかの方法があるのはあしょこでもわかるね。

VirtualAllocEx でメモリを確保させて、そこに書き込むのかな?

それはトロイを作るときによく使われる手法だね。コードは次のようになるよ。

push ebp
push ebx
push esi
push edi
sub esp, 40h
mov ebp, esp

mov byte ptr[ebp+0], 'd'
mov byte ptr[ebp+1], 'l'
mov byte ptr[ebp+2], 'l'
mov byte ptr[ebp+6], 0

call dword ptr[LoadLibrary]

アセンブラ……。

うん。C言語ではセグメントの制限があるからね。

あしょこアセンブラわかんないよう。

それにこの手法はジャンプアドレスを事前に計算しておく必要もでてくる。


じゃあ、どうしたらいいの?

Windows には最初から DLL をロードさせる機能があったよね。

そっか! ここでもグローバルフックを使えばいいんだね!

よくわかったね。まずはフックをセットして、そこからサブクラス化を行うんだ。


それならここをこうして……。

. o O( うーん、襟元からおっぱい覗けそうだなぁ。 )

できた! わーい、できたよ。

よかったね。あとは WM_COPYDATA とかで内容をチェックさせるだけだよ。

うんうん。できたらハンゲのみんなに公開するね!





みやもどき無視ツール 近日公開!!

< おだやかになw