非同期プロシージャ呼び出し(APC)によるモジュール注入


from:http://blog.csdn.net/evi10r/article/details/6745138
Windowsプログラミングの逐次漸進             非同期プロシージャ呼び出しは、特定のスレッド環境で非同期で実行できるシステムメカニズムです.スレッドAPCキューにAPCを追加すると、ソフトブレークが発生します.スレッドが次にスケジューリングされるとAPC関数が実行され、APCには2つの形式があり、システムによって生成されるAPCをカーネルモードAPC、アプリケーションによって生成されるAPCをユーザモードAPCと呼ぶ.       各スレッドには独自のAPCキューがあります.アプリケーションは、指定したスレッドのAPCキューに関数を使用してAPCを追加できます.関数の定義は次のとおりです.
DWORD WINAPI QueueUserAPC(
  __in          PAPCFUNC pfnAPC,//APC    
  __in          HANDLE hThread,//    
  __in          ULONG_PTR dwData//APC     
);
APC関数のプロトタイプは次のとおりです.
VOID CALLBACK APCProc(
  [in]                 ULONG_PTR dwParam
);
ユーザモードAPCが追加されると、スレッドは直接APC関数を呼び出すことはなく、スレッドが「可変待機状態」にある場合にのみ呼び出されます.スレッドがAPC関数を実行する場合は、スレッドを可変待機状態にします.スレッドがSleepEx、SignalObjectAndWait、M s g WaitForMultipleObjectEx、WaitForMultipleObjectsExまたはWaitForSingleObjectExを呼び出すと、可変待機状態になります.
       ReadFileEx、WriteFileEx、およびSetWaitableTimerなどは、いずれもAPCを完了ルーチンとして使用するコールバック機構である.
  
原理:Qを使う
ueueUserAPCはターゲットプロセスのスレッドにAPC関数を追加し、このAPC関数はモジュールのロード機能を実現することができる.この方法を使用するには、ターゲットプロセスが可変待機状態に入ることを前提とします.そうしないと、APCが追加されても実行する機会がありません.
手順:
1.入力するモジュール名を宛先プロセスに書き込む
2.ターゲットプロセスのすべてのスレッドを列挙します.(各スレッドが可変待機状態に入る機会があるわけではないので、APCの機会を増やすために、ターゲットプロセスの各スレッドにAPCを追加するのが比較的安全です)
3.APCを追加し、LoadLibraryをAPCProcとし、第1ステップにおけるDLLパス名の所在するアドレスをそのパラメータとする
コード:
// QueueApc.cpp :              。
//

#include "stdafx.h"


#define _WIN32_WINNT 0x0400
#include <windows.h>
#include <TlHelp32.h>

#include <iostream>
#include <string>
using namespace std;

#define DEF_BUF_SIZE 1024

//         DLL     
char szDllPath[DEF_BUF_SIZE] = {0} ;

//   APC     ID       
BOOL InjectModuleToProcessById ( DWORD dwProcessId )
{
	DWORD	dwRet = 0 ;
	BOOL	bStatus = FALSE ;
	LPVOID	lpData = NULL ;
	UINT	uLen = strlen(szDllPath) + 1;
	//       
	HANDLE hProcess = OpenProcess ( PROCESS_ALL_ACCESS, FALSE, dwProcessId ) ;
	if ( hProcess )
	{
		//     
		lpData = VirtualAllocEx ( hProcess, NULL, uLen, MEM_COMMIT, PAGE_EXECUTE_READWRITE ) ;
		if ( lpData )
		{
			//              
			bStatus = WriteProcessMemory ( hProcess, lpData, szDllPath, uLen, &dwRet ) ;
		}
		CloseHandle ( hProcess ) ;
	}

	if ( bStatus == FALSE )
		return FALSE ;

	//       
	THREADENTRY32 te32 = { sizeof(THREADENTRY32) } ;
	HANDLE hThreadSnap = CreateToolhelp32Snapshot ( TH32CS_SNAPTHREAD, 0 ) ;
	if ( hThreadSnap == INVALID_HANDLE_VALUE ) 
		return FALSE ; 

	bStatus = FALSE ;
	//       
	if ( Thread32First ( hThreadSnap, &te32 ) )
	{
		do{
			//             
			if ( te32.th32OwnerProcessID == dwProcessId )
			{
				//     
				HANDLE hThread = OpenThread ( THREAD_ALL_ACCESS, FALSE, te32.th32ThreadID ) ;
				if ( hThread )
				{
					//        APC
					DWORD dwRet = QueueUserAPC ( (PAPCFUNC)LoadLibraryA, hThread, (ULONG_PTR)lpData ) ;
					if ( dwRet > 0 )
						bStatus = TRUE ;
					CloseHandle ( hThread ) ;
				}
			} 

		}while ( Thread32Next ( hThreadSnap, &te32 ) ) ;
	}

	CloseHandle ( hThreadSnap ) ;
	return bStatus;
}

int _tmain(int argc, _TCHAR* argv[])
{
	//           
	GetCurrentDirectoryA ( DEF_BUF_SIZE, szDllPath ) ;

	//       DLL     
	strcat ( szDllPath, "\\DLLSample.dll" ) ;

	DWORD dwProcessId = 0 ;
	//            ID
	while ( cout << "       ID:" && cin >> dwProcessId && dwProcessId > 0 ) 
	{
		BOOL bRet = InjectModuleToProcessById ( dwProcessId ) ;
		cout << (bRet ? "    !":"    !") << endl ;
	}
	return 0;
}