日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪(fǎng)問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 运维知识 > windows >内容正文

windows

windows-CODE注入(远程线程注入)

發(fā)布時(shí)間:2025/6/17 windows 39 豆豆
生活随笔 收集整理的這篇文章主要介紹了 windows-CODE注入(远程线程注入) 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
遠(yuǎn)程線(xiàn)程注入(先簡(jiǎn)單說(shuō),下面會(huì)詳細(xì)說(shuō))
今天整理下代碼注入(遠(yuǎn)程線(xiàn)程注入),所謂代碼注入,可以簡(jiǎn)單的理解為是在指定內(nèi)進(jìn)程里申請(qǐng)一塊內(nèi)存,然后把我們自己的執(zhí)行代碼和一些變量拷貝進(jìn)去(通常是以啟線(xiàn)程的方式),然后直接調(diào)用對(duì)方內(nèi)存里我們拷貝進(jìn)去的那部分代碼(創(chuàng)建一個(gè)線(xiàn)程)。這樣就行了,此時(shí)我們的這個(gè)線(xiàn)程就是目標(biāo)進(jìn)程的子線(xiàn)程了。但是要注意一點(diǎn),代碼注入之所以能成功重點(diǎn)是:有些系統(tǒng)常用的dll里的某些函數(shù),在不同的進(jìn)程里面獲取到的地址是一樣的(此處注意,一樣的概念是指數(shù)值一樣,但是這個(gè)數(shù)值存的地方不一樣。也就是A里面的b變量的值等于C里面的d變量的值。這個(gè)要清楚,不然在學(xué)習(xí)API劫持的時(shí)候可能會(huì)迷茫)。

首先先介紹幾個(gè)需要的API

1.LoadLibrary() ?和 ?GetProcAddress()?
? ? 這兩個(gè)函數(shù),一個(gè)是加載dll庫(kù),一個(gè)是從已經(jīng)加載的庫(kù)句柄里拿出來(lái)某個(gè)函數(shù)的地址,可以理解成是把一個(gè)dll加到內(nèi)存里,然后獲取里面某個(gè)函數(shù)的地址,得到這個(gè)地址后就可以直接調(diào)用了,這兩個(gè)簡(jiǎn)單的函數(shù)經(jīng)常用到,無(wú)論是常規(guī)調(diào)用還是靜態(tài)免殺都經(jīng)常用。
2.OpenProcess()?
? ? 根據(jù)進(jìn)程id獲取進(jìn)程的句柄,也就是獲取進(jìn)程操控權(quán)。
3.VirtualAllocEx()
? ? 在指定進(jìn)程里開(kāi)辟一塊內(nèi)存,用于存放自己的代碼和參數(shù)。
4.WriteProcessMemory()
? ? 3里面的函數(shù)會(huì)在一個(gè)進(jìn)程里開(kāi)辟一塊內(nèi)存,然后在那個(gè)內(nèi)存里直接用本函數(shù)4進(jìn)行數(shù)據(jù)寫(xiě)入,就是在別人那開(kāi)一塊內(nèi)存然后寫(xiě)自己的東西。
5.CreateRemoteThread()
? ? 最核心的函數(shù),在指定進(jìn)程的某個(gè)內(nèi)存位置存儲(chǔ)的函數(shù)為線(xiàn)程函數(shù),啟動(dòng)一個(gè)線(xiàn)程,當(dāng)然被啟動(dòng)的這個(gè)線(xiàn)程屬于指定的這個(gè)進(jìn)程。
? ? OK上面那5個(gè)API就是代碼注入需要的幾個(gè)基本的了,接下來(lái)我說(shuō)一下我對(duì)線(xiàn)程注入的理解:

? ? 線(xiàn)程注入其實(shí)很好理解,就是說(shuō)我們通過(guò)一定的手段在宿主也就是需要被注入的進(jìn)程那獲取權(quán)限,得到權(quán)限之后我們要在這個(gè)進(jìn)程上開(kāi)辟一定的內(nèi)存,然后把自己的線(xiàn)程函數(shù)內(nèi)容以及參數(shù)什么的全都拷貝過(guò)去,這樣目標(biāo)進(jìn)程上有我們的函數(shù),我們的參數(shù),我們這個(gè)時(shí)候只是需要"幫"它啟動(dòng)一下這個(gè)線(xiàn)程就OK了,直接用CreateRemoteThread函數(shù)在對(duì)方進(jìn)程的某個(gè)內(nèi)存位置的某個(gè)線(xiàn)程函數(shù)作為線(xiàn)程函數(shù)啟動(dòng)。

? ? 然后上面的那個(gè)解釋是宏觀的,也就是泛泛而談,最最核心的思路是這樣:對(duì)于每個(gè)進(jìn)程,他們調(diào)用的API大多都是自己隨時(shí)調(diào)用隨時(shí)獲取的,地址也不一樣,但是只有極少數(shù)的幾個(gè)系統(tǒng)核心dll他們不一樣,系統(tǒng)為了優(yōu)化和統(tǒng)一管理,使得每個(gè)人load的dll然后從里面獲取的函數(shù)地址是一樣的,也就是大家共用一套已經(jīng)被載入的dll地址,可以用的也是用的最多的就是User32.dll,kernel32.dll(我目前就知道這兩個(gè),但是不重要只要知道一個(gè)kernel32.dll然后在里面做一個(gè)工廠(chǎng)就行了),既然大家用的地址都一樣,那么也就是說(shuō)我在我本地直接獲取里面某個(gè)函數(shù)的地址,那么你的地址也是這個(gè),那我直接幫你“慫恿”你去執(zhí)行就行了唄。這樣代碼注入的思路可以總結(jié)成是:我們以所有進(jìn)程加載的某些DLL地址是相同的,通過(guò)這個(gè)相同為跳板,“跳過(guò)去,然后幫宿主進(jìn)程做事”,這樣想來(lái)有點(diǎn)局限,因?yàn)橹挥心敲纯蓱z的幾個(gè)dll大家的地址一樣,但是不用擔(dān)心,我下面會(huì)介紹一個(gè)我自創(chuàng)的思路,就是在宿主里面建造一個(gè)工廠(chǎng),然后加載任意想加載的東西,如果我們每個(gè)產(chǎn)品都要自己生產(chǎn),然后送貨,但是因?yàn)橛泻芏?/span>貨是不合格的,都被扣押了,那么我們?yōu)槭裁床恢苯由a(chǎn)一個(gè)合格的工廠(chǎng)送過(guò)去,只要工廠(chǎng)被接受了,那么他所生產(chǎn)的所有產(chǎn)品都被接受了,也就是在宿主進(jìn)程上加載的dll里面的api肯定和他自己加載的一樣啊,這樣突破了常規(guī)代碼注入函數(shù)受限制的弊端,下面注意問(wèn)題的4還會(huì)說(shuō)這個(gè)問(wèn)題。

需要注意的問(wèn)題:
1.
? ? 參數(shù)結(jié)構(gòu)體的結(jié)構(gòu)體名字有說(shuō)道,我之前沒(méi)注意這個(gè)問(wèn)題,造成一定概率的注入失敗。
2.
? ? 注意64位32位問(wèn)題,目前的經(jīng)驗(yàn)是64位的話(huà)就用64位程序注入,32位就用32位程序注入,這個(gè)應(yīng)該可以解決,問(wèn)題出現(xiàn)在獲取進(jìn)程pid那。
3.
? ? 注意一個(gè)非常關(guān)鍵的問(wèn)題,在代碼注入的時(shí)候,你所需要的任何變量最好自己以?xún)?nèi)存拷貝的方式傳過(guò)去,比如我直接在線(xiàn)程函數(shù)里開(kāi)了一個(gè)變量 char[512] = "00000",當(dāng)你把這個(gè)函數(shù)地址拷貝到指定進(jìn)程里面去的時(shí)候,個(gè)"00000"所占的內(nèi)容并沒(méi)有被拷貝過(guò)去,這樣你在調(diào)用的時(shí)候內(nèi)存就會(huì)出錯(cuò)。
4.
? ? 代碼注入限制非常多,被注入的線(xiàn)程函數(shù)里面內(nèi)容非常有講究,大小有限制,存儲(chǔ)方式有限制,不能隨便調(diào)用API函數(shù),比如直接在里面來(lái)了一個(gè)Sleep(1000),你覺(jué)得這個(gè)函數(shù)是系統(tǒng)的,在那都能調(diào)用,然而并不是,直接就內(nèi)存錯(cuò)誤,如果需要,你需要找到對(duì)應(yīng)的API然后加載進(jìn)去,然后調(diào)用,但是又不是所有的AIP函數(shù)地址都是統(tǒng)一的,那么怎么辦?我之前有一個(gè)解決辦法是直接導(dǎo)入兩個(gè)固定的地址LoadLibrary() ?和 ?GetProcAddress(),通常的代碼注入者的固定思路是靠這兩個(gè)函數(shù)獲取地址然后傳過(guò)去,然而大家很容易忽略一個(gè)思路,就是既然我們知道所有程序的LoadLibrary() ?和 ?GetProcAddress() 地址是一樣的,那么我們就直接本地獲取這兩個(gè)函數(shù)的地址,然后把這兩個(gè)地址傳到線(xiàn)程函數(shù)里,然后在里面在本地生產(chǎn)相應(yīng)的函數(shù),這樣我們加載的API都是目標(biāo)線(xiàn)程能接受的API地址了,這個(gè)思路是當(dāng)時(shí)睡覺(jué)時(shí)候想的,媽的激動(dòng)地差點(diǎn)失眠(雖然現(xiàn)在回頭整理這些的時(shí)候已經(jīng)不怎么激動(dòng)了)。
5.
? ? 還有很多限制和注意問(wèn)題,這里就不多說(shuō)了,需要的可以自己去查一查,我知道的也不多,有的時(shí)候也是現(xiàn)用現(xiàn)查。
? ? OK上面是需要知道的思路和基礎(chǔ),下面就直接說(shuō)實(shí)現(xiàn)。
? ? 思路大體分這么幾個(gè)階段
1.提權(quán) ? ? ? ? ? ? ?權(quán)限不夠的話(huà)可能到導(dǎo)致敏感函數(shù)執(zhí)行失敗。
2.獲取pid ? ? ? ? 獲取宿主進(jìn)程的pid
3.打開(kāi)宿主進(jìn)程 ? ?可以理解成是獲取宿主進(jìn)程的操控權(quán),當(dāng)然這一步依賴(lài)于1的提權(quán)和2獲取的pid
4.初始化參數(shù)數(shù)據(jù) ?這一步就是得到一些AIP地址了,參數(shù)了什么的,然后把它存在參數(shù)的結(jié)構(gòu)體里。
5.在宿主進(jìn)程里分配內(nèi)存用于存放參數(shù)
6.把需要的參數(shù)全都拷貝到宿主繼承內(nèi)存里(第4步獲取的內(nèi)存位置)
7.在宿主進(jìn)程里分配內(nèi)存用于存放線(xiàn)程函數(shù)代碼
8.把線(xiàn)程函數(shù)直接拷到7獲取的內(nèi)存里
9.啟動(dòng)注入宿主進(jìn)程的線(xiàn)程
10.善后,釋放一下垃圾什么的。

? ? 下面我給出一個(gè)最基本的代碼注入的代碼,功能是在qq或者explorer里面注入一個(gè)線(xiàn)程,線(xiàn)程就只是彈出來(lái)一個(gè)對(duì)話(huà)框(我資源里整理了一個(gè)測(cè)試項(xiàng)目http://download.csdn.net/detail/u013761036/9603026)。

.H #pragma once #include <Windows.h> #include <stdlib.h> #include <tlhelp32.h> #include <Psapi.h> #include <string>using std::string; using std::wstring;#pragma comment (lib,"Psapi.lib")#pragma warning(disable:4996)class CInjection { private:bool AdjustProcessTokenPrivilege();//提權(quán)bool Camp2str(wstring wsStrA ,wstring wsStrB);DWORD GetProcessIdByName(const wstring &wsProcessName);//獲取pidpublic:bool InjectionExeAndShowMessage(const wstring &wsProcessName); };.CPP #include "stdafx.h" #include "Injection.h"typedef struct _REMOTE_PARAMETER {CHAR cTitle[64];CHAR cBody[64];DWORD dwMessAgeBoxShowAddress; }RemotePara ,* PRemotePara;bool CInjection::AdjustProcessTokenPrivilege() {LUID luidTmp;HANDLE hToken;TOKEN_PRIVILEGES tkp;if(!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))return false;if(!LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &luidTmp)){ CloseHandle(hToken);return FALSE;}tkp.PrivilegeCount = 1;tkp.Privileges[0].Luid = luidTmp;tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;if(!AdjustTokenPrivileges(hToken, FALSE, &tkp, sizeof(tkp), NULL, NULL)){CloseHandle(hToken);return FALSE;}return true; }bool CInjection::Camp2str(wstring wsStrA ,wstring wsStrB) {int nSize = wsStrA.length();for(int i = 0 ;i < nSize ;i ++){if(wsStrA[i] >= 'A' && wsStrA[i] <= 'Z')wsStrA[i] += 'a'- 'A';}nSize = wsStrB.length();for(int i = 0 ;i < nSize ;i ++){if(wsStrB[i] >= 'A' && wsStrB[i] <= 'Z')wsStrB[i] += 'a'- 'A';}return wsStrA == wsStrB; }DWORD CInjection::GetProcessIdByName(const wstring &wsProcessName) {HANDLE hProcess = 0;DWORD dwProcess[2048] ,dwNeeded;TCHAR tcProcName[MAX_PATH] = {0};wstring wsNowProcessName = L"";int nTempSize = 0;int nPos = 0;EnumProcesses(dwProcess, sizeof(dwProcess), &dwNeeded);for(int i = 0 ;i < dwNeeded / sizeof(DWORD) ;i++){if(0 != dwProcess[i]){hProcess = OpenProcess( PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, dwProcess[i]);GetModuleFileNameEx(hProcess, NULL, tcProcName, MAX_PATH);nPos = wstring(tcProcName).find_last_of(L'\\');if(nPos != wstring::npos){wsNowProcessName = wstring(wstring(tcProcName).substr(nPos + 1));if(Camp2str(wsProcessName ,wsNowProcessName)){DWORD aa = dwProcess[i];return aa;}//if(wsProcessName == wsNowProcessName)// return dwProcess[i];}}}return 0; }//注入的線(xiàn)程函數(shù) static DWORD __stdcall RemoteThread(PRemotePara myData) {typedef int (WINAPI *_MessageBoxA)(_In_opt_ HWND hWnd,_In_opt_ LPCSTR lpText,_In_opt_ LPCSTR lpCaption,_In_ UINT uType);_MessageBoxA mbAdd = (_MessageBoxA)myData->dwMessAgeBoxShowAddress;mbAdd(NULL ,myData->cBody ,myData->cTitle ,MB_OK);return 0; }bool CInjection::InjectionExeAndShowMessage(const wstring &wsProcessName) { //1.提權(quán)if(!AdjustProcessTokenPrivilege())return false;//2.獲取pidDWORD dwProPID = 0;if((dwProPID = GetProcessIdByName(wsProcessName)) == 0)return false;//3.打開(kāi)進(jìn)程HANDLE hProcess = NULL;if((hProcess=OpenProcess(PROCESS_ALL_ACCESS,FALSE ,dwProPID)) == NULL)return false;//4.初始化參數(shù)數(shù)據(jù)RemotePara rpData = {0};ZeroMemory(&rpData,sizeof(RemotePara));HINSTANCE hInst=NULL;hInst=LoadLibrary(L"User32.dll");if(hInst == NULL)return false;rpData.dwMessAgeBoxShowAddress = 0;rpData.dwMessAgeBoxShowAddress = (DWORD)GetProcAddress(hInst,"MessageBoxA");if(rpData.dwMessAgeBoxShowAddress == 0)return false;FreeLibrary(hInst);strcat(rpData.cTitle ,"title");strcat(rpData.cBody ,"body");//RemoteThread(&rpData);//5.在宿主進(jìn)程里分配內(nèi)存,用于存參數(shù)PRemotePara pPara = NULL;pPara = (PRemotePara)VirtualAllocEx(hProcess , 0 ,sizeof(RemotePara) ,MEM_COMMIT,PAGE_READWRITE);if(pPara == NULL) return false;//6.把參數(shù)寫(xiě)入宿主進(jìn)程里,注意結(jié)構(gòu)體的命名(_REMOTE_PARAMETER)if(!WriteProcessMemory(hProcess ,pPara ,&rpData ,sizeof(RemotePara) ,0))return false;//7.在宿主進(jìn)程里分配內(nèi)存,用于寫(xiě)線(xiàn)程函數(shù) 1024這個(gè)值是我隨意填寫(xiě)的,我覺(jué)得這么大可以存下上面那個(gè)線(xiàn)程函數(shù)void *pRemoteThr = VirtualAllocEx(hProcess , NULL ,1024 ,MEM_COMMIT | MEM_RESERVE ,PAGE_EXECUTE_READWRITE);if(pRemoteThr == NULL) return false;//8.把進(jìn)程函數(shù)寫(xiě)入分配的內(nèi)存里if(!WriteProcessMemory(hProcess ,pRemoteThr ,&RemoteThread ,1024 ,0))return false;//9.啟動(dòng)注入宿主進(jìn)程的進(jìn)程DWORD dwThreadId = 0;HANDLE hThread = CreateRemoteThread(hProcess ,0 ,0 ,(DWORD (WINAPI *)(LPVOID))pRemoteThr ,pPara ,0 ,&dwThreadId);if(!hThread) return false;//10.等待線(xiàn)程結(jié)束,然后清理內(nèi)存 WaitForSingleObject(hThread ,INFINITE);CloseHandle(hThread);VirtualFreeEx(hProcess ,pPara ,0 ,MEM_RELEASE);VirtualFreeEx(hProcess ,pRemoteThr ,0 ,MEM_RELEASE);CloseHandle(hProcess);return true; }USER #include "stdafx.h" #include "ZZZTest.h" #include "Injection.h"int APIENTRY _tWinMain(_In_ HINSTANCE hInstance,_In_opt_ HINSTANCE hPrevInstance,_In_ LPTSTR lpCmdLine,_In_ int nCmdShow) {UNREFERENCED_PARAMETER(hPrevInstance);UNREFERENCED_PARAMETER(lpCmdLine);CInjection *pciTest = new CInjection();pciTest->InjectionExeAndShowMessage(L"qq.exe"); //explorer.exedelete pciTest;return 0; }

總結(jié)

以上是生活随笔為你收集整理的windows-CODE注入(远程线程注入)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。