進行DLL注入的一種方法
- 發布于:2020-12-29
- 共 255 人圍觀
這種方法只能在WIN2000中使用(XP,和最新的2003不知道)。具體步驟如下:
1)、取得遠程進程的進程ID;
2)、在遠程進程空間中分配一段內存用來存放要注入的DLL完整路徑;
3)、將要注入的DLL的路徑寫到剛才分配的遠程進程空間;
4)、從Kernel32.dll中取得LoadLibray的地址;
5)、調用CreateRemoteThread函數以從Kernel32.dll中取得的LoadLibrary函數的地址為線程函數的地址,以我們要注入的DLL文件名為參數,創建遠程線程;
在第二三步中,為什么要把我們要注入的DLL的文件名寫到遠程進程的地址空間進行*作,《WINDOWS核心編程》中是這樣描述的:
“(要注入的DLL文件名)字符串是在調用進程的地址空間中。該字符串的地址已經被賦予新創建的遠程線程,該線程將它傳遞給L o a d L i b r a r y A。但是,當L o a d L i b r a r y A取消對內存地址的引用時, D L L路徑名字符串將不再存在,遠程進程的線程就可能引發訪問違規”;
至于第四步中為什么不直接對LoadLibrary進行調用,《WINDOWS核心編程》中是這樣描述的:
“如果在對C r e a t e R e m o t e T h r e a d的調用中使用一個對L o a d L i b r a r y A的直接引用,這將在你的模塊的輸入節中轉換成L o a d L i b r a r y A的形實替換程序的地址。將形實替換程序的地址作為遠程線程的起始地址來傳遞,會導致遠程線程開始執行一些令人莫名其妙的東西。其結果很可能造成訪問違規。”
好了,下面開始我們的例子。
1、同上面應用HOOK來進行DLL注入一樣,我們先創建一個DLL工程,這個DLL完全可以不編寫任何代碼,因為我們只想將DLL注入到指定進程就達到目的了,但為了好看,我還是隨便在其中寫一個API函數。代碼如下:
extern "C" __declspec(dllexport) __stdcall void About();
int WINAPI DllEntryPoint(HINSTANCE hinst, unsigned long reason, void* lpReserved)
{
return 1;
}
//---------------------------------------------------------------------------
void __declspec(dllexport) __stdcall About()
{
MessageBox(NULL,"這個DLL模塊演示了DLL的注入技術。\n"
"通過程序的調用LoadLibrary將本模塊注入到指定的"
"進程的地址空間中。", "DLL注入技術",
MB_ICONINFORMATION + MB_OK);
}
編譯它,就得到我們用來注入的DLL文件了。接下來是測試工程。
2、編寫測試工程。用BCB建立一個應用程序工程,在窗體中放入兩個按鈕,一個用來注入,一個用來撤消,另外還有一個文本框控件,用來等待用戶輸入進程ID號。代碼如下:
//---------------------------------------------------------------------------
// DLL注入函數
BOOL WINAPI LoadLib(DWORD dwProcessId, LPWSTR lpszLibName)
{
HANDLE hProcess = NULL,
hThread = NULL;
LPWSTR lpszRemoteFile = NULL;
// 打開遠程進程
hProcess = OpenProcess(PROCESS_CREATE_THREAD
| PROCESS_VM_OPERATION
| PROCESS_VM_WRITE,
FALSE,
dwProcessId);
if (hProcess == NULL)
{
MessageBox(NULL, ("OpenProcess failed with error "
+ IntToStr(GetLastError())).c_str(), "Error",
MB_ICONINFORMATION + MB_OK);
return FALSE;
}
// 在遠程進程中分配存貯DLL文件名的空間
lpszRemoteFile = (LPWSTR)VirtualAllocEx(hProcess, NULL,
sizeof(WCHAR) * lstrlenW(lpszLibName) + 1,
MEM_COMMIT, PAGE_READWRITE);
if (lpszRemoteFile == NULL)
{
MessageBox(NULL, ("VirtualAllocEx failed with error "
+ IntToStr(GetLastError())).c_str(), "Error",
MB_ICONINFORMATION + MB_OK);
return FALSE;
}
// 復制DLL文件名到遠程剛分配的進程空間
if (!WriteProcessMemory(hProcess, lpszRemoteFile,
(PVOID)lpszLibName, sizeof(WCHAR) * lstrlenW(lpszLibName) + 1,
NULL))
{
MessageBox(NULL, ("WriteProcessMemory failed with error "
+ IntToStr(GetLastError())).c_str(), "Error",
MB_ICONINFORMATION + MB_OK);
return FALSE;
}
// 取得LoadLibrary函數在Kennel32.dll中的地址
PTHREAD_START_ROUTINE pfnThreadRtn =
(PTHREAD_START_ROUTINE)GetProcAddress(
GetModuleHandle("Kernel32.dll"),"LoadLibraryW");
if (pfnThreadRtn == NULL)
{
MessageBox(NULL, ("GetProcAddress failed with error "
+ IntToStr(GetLastError())).c_str(), "Error",
MB_ICONINFORMATION + MB_OK);
return FALSE;
}
// 創建遠程線程
hThread = CreateRemoteThread(hProcess,
NULL,
0,
pfnThreadRtn, // LoadLibrary地址
lpszRemoteFile, // 要加載的DLL名
0,
NULL);
if (hThread == NULL)
{
MessageBox(NULL, ("CreateRemoteThread failed with error "
+ IntToStr(GetLastError())).c_str(), "Error",
MB_ICONINFORMATION + MB_OK);
return FALSE;
}
// 等待線程返回
WaitForSingleObject(hThread, INFINITE);
// 釋放進程空間中的內存
VirtualFreeEx(hProcess, lpszRemoteFile, 0, MEM_RELEASE);
// 關閉句柄
CloseHandle(hThread);
CloseHandle(hProcess);
return TRUE;
}
// 在進程空間釋放注入的DLL
BOOL WINAPI FreeLib(DWORD dwProcessId, LPTSTR lpszLibName)
{
HANDLE hProcess = NULL,
hThread = NULL,
hthSnapshot = NULL;
MODULEENTRY32 hMod = {sizeof(hMod)};
BOOL bFound;
// 取得指定進程的所有模塊映象
hthSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE,
dwProcessId);
if (hthSnapshot == NULL)
{
MessageBox(NULL, ("CreateRemoteThread failed with error "
+ IntToStr(GetLastError())).c_str(), "Error",
MB_ICONINFORMATION + MB_OK);
return FALSE;
}
// 取得所有模塊列表中的指定的模塊
BOOL bMoreMods = Module32First(hthSnapshot, &hMod);
if (bMoreMods == FALSE)
{
MessageBox(NULL, ("Module32First failed with error "
+ IntToStr(GetLastError())).c_str(), "Error",
MB_ICONINFORMATION + MB_OK);
return FALSE;
}
// 循環取得想要的模塊
for (;bMoreMods; bMoreMods = Module32Next(hthSnapshot, &hMod))
{
//ShowMessage(String(hMod.szExePath) + " | " + String(lpszLibName));
if ((strcmp(hMod.szExePath, lpszLibName) == 0) ||
(strcmp(hMod.szModule, lpszLibName) == 0))
break;
}
// 打開進程
hProcess = OpenProcess(PROCESS_CREATE_THREAD | PROCESS_VM_OPERATION,
FALSE, dwProcessId);
if (hProcess == NULL)
{
MessageBox(NULL, ("OpenProcess failed with error "
+ IntToStr(GetLastError())).c_str(), "Error",
MB_ICONINFORMATION + MB_OK);
return FALSE;
}
// 取得FreeLibrary函數在Kernel32.dll中的地址
PTHREAD_START_ROUTINE pfnThreadRtn =
(PTHREAD_START_ROUTINE)GetProcAddress(
GetModuleHandle("Kernel32.dll"), "FreeLibrary");
if (pfnThreadRtn == NULL)
{
MessageBox(NULL, ("GetProcAddress failed with error "
+ IntToStr(GetLastError())).c_str(), "Error",
MB_ICONINFORMATION + MB_OK);
return FALSE;
}
// 創建遠程線程來執行FreeLibrary函數
hThread = CreateRemoteThread(hProcess,
NULL,
0,
pfnThreadRtn,
hMod.modBaseAddr,
0,
NULL);
if (hThread == NULL)
{
MessageBox(NULL, ("CreateRemoteThread failed with error "
+ IntToStr(GetLastError())).c_str(), "Error",
MB_ICONINFORMATION + MB_OK);
return FALSE;
}
// 等待線程返回
WaitForSingleObject(hThread, INFINITE);
// 關閉句柄
CloseHandle(hThread);
CloseHandle(hthSnapshot);
CloseHandle(hProcess);
return TRUE;
}
//---------------------------------------------------------------------------
void __fastcall TfrmMain::btLoadClick(TObject *Sender)
{
m_szDllFile = Application->ExeName;
m_szDllFile = m_szDllFile.SubString(0, m_szDllFile.Length()
- String(StrRScan(m_szDllFile.c_str(),'\\')).Length());
m_szDllFile = m_szDllFile + "\\DllLib.dll";
m_dwProcessId = StrToInt(Edit->Text);
LoadLib(m_dwProcessId, WideString(m_szDllFile).c_bstr());
}
//---------------------------------------------------------------------------
void __fastcall TfrmMain::btUnloadClick(TObject *Sender)
{
FreeLib(m_dwProcessId, m_szDllFile.c_str());
}
//---------------------------------------------------------------------------
好了,把上面的工程編譯成生EXE文件,接下來我們就可以進行DLL的注入測試了。先打開記事本(當然你也可以打開其它的進程,或直接在已經加載的進程測試),通過WINDOWS的任務管理器,找到它的進程ID。然后運行我們的測試工程,在文本框中輸入進程ID,點擊注入。這時我們就可以通過我們最先寫的小工具來查看它的進程空間中所包含的模塊了,你會發現,我們的DLL已經成功加載到了它的進程空間中。點擊卸載,取消DLL的注入。
標簽: