本文是配合上文學習和使用的。上文中,最後,我們生成了可以hook api的dll,那麼怎麼把它發射到其他進程中,讓其他進程調用運行我們的dll呢?
遠程線程注入技術可以解決這個問題。
原理:
遠程線程注入是這樣的,首先在當前運行的進程中找到目標進程,然後將我們的dll的內容寫入目標進程的私有空間中,最後通過關鍵的API:CreateRemoteThread創建線程。該線程只執行一個任務:loadlibrary加載我們的dll。
下面通過實例解釋,例子中注入的進程是“explorer.exe”(個人認爲玩弄這個進程異常的舒爽~~~~吼吼吼吼~~~~~~)
具體實現:
1.找到目標
原理簡單,我們首先獲得目前時刻正在運行的進程的列表,然後通過遍歷搜索,找到列表中我們想要的進程,然後記錄下進程的ID號。
hProcessSnap=CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0);
這個函數用來獲得當前進程的快照。(啪!說人話!)哦,就是獲得當前進程的列表啊。
然後通過下面的代碼按順序遍歷這個列表,通過字符串對比,找到我們的目標:explorer.exe。上代碼!
//獲取目標進程的ID
if(Process32First(hProcessSnap,&pe32)) //獲取第一個進程
{
do{
char te[MAX_PATH];
strcpy(te,pe32.szExeFile);
if(strcmp(te, INJECT_PROCESS_NAME) == 0)
{
dwRemoteProcessId=pe32.th32ProcessID;
printf("%d\n",dwRemoteProcessId);
break;
}
}
while(Process32Next(hProcessSnap,&pe32));//獲取下一個進程
}
else
{
return -1;
}
找到目標進程後,用dwRemoteProcessId記錄下進程ID。還是一樣,大家不用深究看不懂的變量(畢竟變量搞懂也沒大意思),先看清原理,完整的代碼會在最後給出下載地址。
上面這個代碼段中關鍵函數分別是Process32First,Process32Next兩個可以沿着列表搜索的函數還有一個字符串對比函數strcmp覈對當前搜索的進程對象的名稱是不是explorer.exe。
2.打開進程,把我們的dll寫進去!
(1)打開
在上一步獲得目標進程的id後我們就可以打開進程,然後對進程進行操作。打開進程如下:
hProcess = OpenProcess(PROCESS_ALL_ACCESS, TRUE, dwProcessId);
參數中的第一個是表明我們在打開進程的時候想要獲得的權限,第三個是目標進程的ID。成功打開後,我們用hProcess存放打開的句柄。句柄嘛,大家都懂的,windows裏都是用句柄訪問和操作對象的嘛~~
(2)寫入
既然要往目標進程的私有空間寫入數據,我們就要先在目標進程中申請和我們的dll一樣大,或者更大的空間。申請如下:
pszLibRemoteFile = VirtualAllocEx(hProcess,NULL,cb,MEM_COMMIT,PAGE_READWRITE);
參數中的cb是我們想要申請的尺寸,最後一個參數是讀寫權限。
我們怎麼獲得cb呢?look:
int cch = 1 + lstrlenW(lpwLibFile); //這裏的lpwLibFile其實就是我們的dll
int cb = cch * sizeof(WCHAR);
上面第一步得到的是我們dll的文件尺寸,單位是“個”,代表我們的文件有cch個字符。
第二步得到真正的字節大小,我們把字符數乘以每一個寬字符所佔的字節空間即可。這裏爲什麼是寬字符?是windows文件都是寬字符形式嗎?還是。。。不也不懂,大家一起查查,知道了別忘告訴我下,先謝過各位親~~~
空間申請好了,空間的首地址用pszLibRemoteFile存着,然後就可以寫數據了:
WriteProcessMemory(hProcess, pszLibRemoteFile,(PVOID)lpwLibFile, cb, &dwWritten);
這個沒啥好解釋的,就是一個寫內存的API。
至此在目標進程中已經有了我們dll邪惡的身影,最後當然是逼着目標進程加載我們的dll(不加載就是垃圾數據佔空間來的,難道佔空間也是一種攻擊方式???額。。。)
3.加載
windows允許我們做什麼,我們就以什麼爲突破口。
windows提供給我們一個API叫做CreateRemoteThread。。。。說實話,微軟爲什麼要給程序員這中完全不安全的API,我不能猜到內幕。只能壞笑着說“微軟~~~你真壞”
不過這裏要說下,win7沒那麼好欺負,直接調用CreateRemoteThread好像不行,我沒有認真研究具體是哪裏被拒絕了,不過網上找到資料,這個函數最終會調用NtCreateThreadEx。
呵呵,各位菜鳥朋友們,當大家看到nt開頭的函數應該很興奮吧,對windows來說,對幾乎所有的API調用最後都會調用對應nt開頭的API,這些是底層的函數,既然win7不讓我們創建線程,那我們自己強行調用這個nt函數。
這裏真的有點像hook api裏的操作:
找到NtCreateThreadEx所在dll,然後從這個dll中獲得NtCreateThreadEx的位置,然後定義一個返回值和參數表和NtCreateThreadEx一樣的函數的指針存放NtCreateThreadEx的地址,直接調用指針指向的位置裏存放的代碼(廢話一堆。。其實就是用地址調用了NtCreateThreadEx)。
程序如下:
pFunc = GetProcAddress(GetModuleHandle(L"ntdll.dll"), "NtCreateThreadEx");
//下面就是用地址執行了NtCreateThreadEx
((PFNTCREATETHREADEX)pFunc)(
&hThread,
0x1FFFFF,
NULL,
hProcess,
pThreadProc,
pRemoteBuf,
FALSE,
NULL,
NULL,
NULL,
NULL);
OK,目前線程能創建了,那麼別忘了我們付給這個線程的艱鉅使命:出賣它所屬的進程,調用我們的dll庫(這是擬人的修辭手法啊有木有!)
回頭看下這個創建線程的函數,裏面有個參數叫做pThreadProc,呵呵,能猜到吧,這裏放的就是線程起來後負責運行的程序。我們果斷把這個值附成LoadLibrary,然後在哪裏傳入LoadLibrary的參數呢?pRemoteBuf!新的線程會從這裏讀取它要執行的函數的參數。我們前面在寫入dll數據的時候不是記錄了一個地址嗎?那個地址變量不也是Buff嗎?把那個變量放到這個參數的位置就OK了。
我的程序裏這樣創建線程:
MyCreateRemoteThread(hProcess, pfnThreadRnt,pszLibRemoteFile);
第二個參數在前面有個處理:
pfnThreadRnt = (LPTHREAD_START_ROUTINE)GetProcAddress(GetModuleHandle(L"Kernel32"), "LoadLibraryW");
懂了吧?嘿嘿。。
第三個參數是存了我們dll的buff頭指針。
當這個函數順利執行完的時候,我們dll的工作也順利完成了。
提醒下廣大和我一樣的菜鳥朋友,如果要把你的dll注入64位系統的explorer.exe,別忘了把dll編程成x64的,然後這個注入程序也編譯生成x64的可執行文件哦,否則會發現注入了木有任何反應哦~親~
本文的源碼在http://download.csdn.net/detail/arvon2012/4441040
技術相關更多文章猛擊:哇啦天堂論壇技術區