本人小白水準,内容中有看不懂的地方請直接在留言中詢問,如果代碼中有錯誤或者用法不正确的地方還請立刻指出,本人QQ号 : 3216393922
對于 CreateRemoteThread,比較簡單的用法是用LoadLibrary在目标程序中注入dll,也可以在遠端線程中注入代碼,并将它運作,不過,有一下幾個注意點:
1、如何在遠端線程中調用字元串?
所有的字元串必須在目标程序的位址空間中,是以我在目标程序内開辟了兩個空間,一個用來存放代碼,一個用來存放資料。将資料打包成結構體REMOTE_DATA,一次性運到目标程序中去,再将該結構體資料在目标程序中的位址作為線程函數的參數,這樣就可以線上程函數中調用結構體中的字元串資料。
2、如何在遠端線程中任意調用系統函數?
為了在遠端線程中可以調用任何想調用的函數,必須擁有LoadLibraryW和GetProcAddress這兩個函數,調用某一個函數時,先用LoadLibraryW得到函數所在的dll子產品句柄,再用GetProcAddress得到函數位址。
例如:想要在遠端線程函數内調用MessageBoxW函數,它在User32.dll中
先在資料結構體中定義函數名和dll名
CHAR szMessageBoxW[20] = “MessageBoxW”;
WCHAR szUser32[20] = TEXT(“user32.dll”);
再在遠端線程函數中得到dll子產品句柄
HMODULE hUser32 = LOADLIBRARYW(myData->szUser32);
然後申明MessageBoxW函數
typedef int(WINAPI* Func1)(HWND hwnd,LPCWSTR lpText,LPCWSTR lpCaption,UINT uType);
Func1 MESSAGEBOXW = (Func1)GETPROCADDRESS(hUser32, myData->szMessageBoxW);
最後調用MessageBoxW函數
MESSAGEBOXW(NULL, myData->szText, myData->szCaption, MB_OK);
3、如何得到函數代碼在記憶體中的大小?
#pragma check_stack(off)
void test()
{
//你的代碼
}
void AfterFunc()
{
return;
}
#pragma check_stack
調用SIZE_T cbSize = ((BYTE )(DWORD)AfterFunc - (BYTE )(DWORD)RemoteThreadFunc) + 10就可以得到函數test()的大小,該方法在Debug下無法使用,在Release中才可以使用。
目标是在程序PEView.exe中建立一個線程,線程中建立一個MessageBoxW
下面是代碼:
#include <Windows.h>
#include <TlHelp32.h>
#include <stdlib.h>
#include <string>
#include <string.h>
#include <stdio.h>
#include <tchar.h>
#include <Psapi.h>
using namespace std;
//1.定義程序名稱
const wstring& wsProcessName = TEXT("PEView.exe");
//2.定義遠端線程中使用的資料
typedef struct
{
WCHAR szCaption[] = TEXT("123");
WCHAR szText[] = TEXT("456");
//2.1需要使用的dll
WCHAR szKernel32[] = TEXT("kernel32.dll");
WCHAR szUser32[] = TEXT("user32.dll");
WCHAR szGdi32[] = TEXT("gdi32.dll");
//2.2需要使用的函數
CHAR szMessageBoxW[] = "MessageBoxW";
CHAR szLoadCursorW[] = "LoadCursorW";
CHAR szSetCursor[] = "SetCursor";
CHAR szSleep[] = "Sleep";
//2.3兩個函數LoadLibraryW和GetProcAddressW的位址
DWORD dwLoadLibraryW = ;
DWORD dwGetProcAddress = ;
}REMOTE_DATA, *PREMOTE_DATA;
REMOTE_DATA remoteData;
//3.定義遠端線程的函數
#pragma check_stack(off)
DWORD __stdcall RemoteThreadFunc(PREMOTE_DATA myData)
{
//LoadLibraryW-->LOADLIBRARYW
typedef HMODULE(WINAPI* LoadLibraryWFunc)(
LPCWSTR lpFileName
);
LoadLibraryWFunc LOADLIBRARYW = (LoadLibraryWFunc)myData->dwLoadLibraryW;
//GetProcAddress-->GETPROCADDRESS
typedef FARPROC(WINAPI* GetProcAddressFunc)(
HMODULE hModule,
LPCSTR lpProcName
);
GetProcAddressFunc GETPROCADDRESS = (GetProcAddressFunc)myData->dwGetProcAddress;
//加載hUser32.dll并得到其句柄
HMODULE hKernel32 = LOADLIBRARYW(myData->szKernel32);
HMODULE hUser32 = LOADLIBRARYW(myData->szUser32);
HMODULE hGdi32 = LOADLIBRARYW(myData->szGdi32);
//調用MessageBoxW
typedef int(WINAPI* Func1)(
HWND hwnd,
LPCWSTR lpText,
LPCWSTR lpCaption,
UINT uType
);
Func1 MESSAGEBOXW = (Func1)GETPROCADDRESS(hUser32, myData->szMessageBoxW);
MESSAGEBOXW(NULL, myData->szText, myData->szCaption, MB_OK);
return ;
}
void AfterFunc()
{
return;
}
#pragma check_stack
BOOL 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 = ;
tkp.Privileges[].Luid = luidTmp;
tkp.Privileges[].Attributes = SE_PRIVILEGE_ENABLED;
if (!::AdjustTokenPrivileges(hToken, FALSE, &tkp, sizeof(tkp), NULL, NULL))
{
::CloseHandle(hToken);
return FALSE;
}
return TRUE;
}
BOOL Camp2str(wstring wsStrA, wstring wsStrB)
{
int nSize = wsStrA.length();
for (int i = ; i < nSize; ++i)
{
if (wsStrA[i] >= 'A'&&wsStrA[i] <= 'Z')
wsStrA[i] += 'a' - 'A';
}
nSize = wsStrB.length();
for (int i = ; i < nSize; ++i)
{
if (wsStrB[i] >= 'A'&&wsStrB[i] <= 'Z')
wsStrB[i] += 'a' - 'A';
}
return wsStrA == wsStrB;
}
DWORD GetProcessIdByName(const wstring& wsProcessName)
{
HANDLE hProcess = ;
DWORD dwProcess[], dwNeeded;
TCHAR tcProcName[MAX_PATH] = { };
wstring wsNowProcessName = L"";
int nTempSize = ;
int nPos = ;
//将所有程序的ID儲存在數組dwProcess中,共dwNeeded個程序
EnumProcesses(dwProcess, sizeof(dwProcess), &dwNeeded);
//用ID打開每一個程序
for (int i = ; i < (dwNeeded / sizeof(DWORD)); ++i)
{
if (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 + ));
if (Camp2str(wsProcessName, wsNowProcessName))
{
DWORD aa = dwProcess[i];
return aa;
}
}
}
}
return ;
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)
{
//1.提權
if (!AdjustProcessTokenPrivilege())
{
MessageBox(NULL, TEXT("無法提升權限"), TEXT("Fail"), MB_ICONERROR);
return -;
}
DWORD dwProID = ;
HANDLE hProcess = NULL;
HANDLE hModuleSnap = INVALID_HANDLE_VALUE;
HANDLE hThread = NULL;
void* pRemoteData = NULL;
void* pRemoteThread = NULL;
__try
{
//2.擷取程序ID dwProPID
if ((dwProID = GetProcessIdByName(wsProcessName)) == )
{
MessageBox(NULL, TEXT("無法由程序名找到程序"), TEXT("Fail"), MB_ICONERROR);
__leave;
}
//3.打開程序句柄hProcess
if ((hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProID)) == NULL)
{
MessageBox(NULL, TEXT("無法打開程序"), TEXT("Fail"), MB_ICONERROR);
__leave;
}
//4.在宿主程序中找到LoadLibraryW函數和GetProcAddressW函數的位址
//并分别賦給remoteData.dwLoadLibraryW和remoteData.dwGetProcAddress
MODULEENTRY32W me32 = { sizeof(MODULEENTRY32W) };
hModuleSnap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, dwProID);
if (hModuleSnap == INVALID_HANDLE_VALUE)
{
MessageBox(NULL, TEXT("無法擷取子產品快照"), TEXT("Fail"), MB_ICONERROR);
__leave;
}
if (!Module32FirstW(hModuleSnap, &me32))
{
MessageBox(NULL, TEXT("無法擷取子產品快照"), TEXT("Fail"), MB_ICONERROR);
__leave;
}
do
{
//找到目标程序中的Kernel32.dll
if (lstrcmpiW(me32.szModule, TEXT("Kernel32.dll"))==)
{
//獲得本地hKernel32.dll或LoadLibraryW或GetProcAddress的位址
HANDLE hKernel32 = GetModuleHandleW(TEXT("Kernel32.dll"));
DWORD loadlibraryw = (DWORD)GetProcAddress((HMODULE)hKernel32, (LPCSTR)"LoadLibraryW");
DWORD getprocaddress = (DWORD)GetProcAddress((HMODULE)hKernel32, (LPCSTR)"GetProcAddress");
if (hKernel32 == NULL || loadlibraryw == || getprocaddress == )
{
MessageBox(NULL, TEXT("無法獲得本地hKernel32.dll或LoadLibraryW或GetProcAddress的位址"), TEXT("Fail"), MB_ICONERROR);
__leave;
}
//獲得目标程序hKernel32.dll或LoadLibraryW或GetProcAddress的位址
remoteData.dwLoadLibraryW = loadlibraryw - (DWORD)hKernel32 + (DWORD)me32.hModule;
remoteData.dwGetProcAddress = getprocaddress - (DWORD)hKernel32 + (DWORD)me32.hModule;
break;
}
} while (Module32NextW(hModuleSnap, &me32));
CloseHandle(hModuleSnap);
hModuleSnap = INVALID_HANDLE_VALUE;
if (remoteData.dwLoadLibraryW == || remoteData.dwGetProcAddress == )
{
MessageBox(NULL, TEXT("未能在目标程序中找到kernel32.dll"), TEXT("Fail"), MB_ICONERROR);
__leave;
}
//5.1在宿主程序裡配置設定記憶體,用于存參數remoteData
pRemoteData = VirtualAllocEx(hProcess, NULL, sizeof(remoteData), MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
if (pRemoteData == NULL)
{
MessageBox(NULL, TEXT("無法在宿主程序中配置設定記憶體"), TEXT("Fail"), MB_ICONERROR);
__leave;
}
//5.2把remoteData寫入到目标程序的記憶體pRemoteData中去
if (!WriteProcessMemory(hProcess, pRemoteData, &remoteData, sizeof(remoteData), NULL))
{
MessageBox(NULL, TEXT("無法将資料remoteData寫入宿主程序中"), TEXT("Fail"), MB_ICONERROR);
__leave;
}
//6.1在宿主程序裡配置設定記憶體,用于寫線程函數RemoteThreadFunc
SIZE_T cbSize = ((BYTE *)(DWORD)AfterFunc - (BYTE *)(DWORD)RemoteThreadFunc) + ;
if (cbSize <= )
{
cbSize = ;
}
pRemoteThread = VirtualAllocEx(hProcess, NULL, cbSize, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
if (pRemoteThread == NULL)
{
MessageBox(NULL, TEXT("無法在宿主程序中配置設定記憶體"), TEXT("Fail"), MB_ICONERROR);
__leave;
}
//6.2.把RemoteThread指向的函數寫入到目标程序的記憶體pRemoteThread中去
if (!WriteProcessMemory(hProcess, pRemoteThread, &RemoteThreadFunc, cbSize, NULL))
{
MessageBox(NULL, TEXT("無法将線程函數RemoteThread寫入宿主程序中"), TEXT("Fail"), MB_ICONERROR);
__leave;
}
//7.啟動注入宿主程序的線程
hThread = CreateRemoteThread(hProcess, NULL, , (LPTHREAD_START_ROUTINE)pRemoteThread, pRemoteData, , NULL);
if (!hThread)
{
MessageBox(NULL, TEXT("無法在宿主程序中建立遠端線程"), TEXT("Fail"), MB_ICONERROR);
__leave;
}
//8.等待線程結束,然後清理記憶體
WaitForSingleObject(hThread, INFINITE);
}
__finally
{
if (hProcess != NULL)
{
CloseHandle(hProcess);
}
if (hModuleSnap != INVALID_HANDLE_VALUE)
{
CloseHandle(hModuleSnap);
}
if (hThread != NULL)
{
CloseHandle(hThread);
}
if (pRemoteThread != NULL)
{
VirtualFreeEx(hProcess, pRemoteThread, , MEM_RELEASE);
}
if (pRemoteData != NULL)
{
VirtualFreeEx(hProcess, pRemoteData, , MEM_RELEASE);
}
}
return ;
}