C/C++ 實現常用的線程注入


各種API遠程線程注入的方法,分別是 遠程線程注入,普通消息鈎子注入,全局消息鈎子注入,APC應用層異步注入,ZwCreateThreadEx強力注入,純匯編實現的線程注入等。

簡單編寫DLL文件:

#include <Windows.h>

extern "C" __declspec(dllexport) void MsgBox(LPCWSTR szMsg, LPCWSTR Title)
{
	MessageBox(NULL, szMsg, Title, MB_OK);
}

BOOL APIENTRY DllMain(HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
	switch (ul_reason_for_call)
	{
	case DLL_PROCESS_ATTACH:
		// 進程被加載后執行
		break;
	case DLL_THREAD_ATTACH:
		// 線程被創建后加載
		break;
	case DLL_THREAD_DETACH:
		// 正常退出執行的代碼
		break;
	case DLL_PROCESS_DETACH:
		// 進程卸載本Dll后執行的代碼
		break;
	}
	return TRUE;
}
#include <Windows.h>
#include <iostream>

typedef VOID(*PFUNMSG)(LPCWSTR szMsg, LPCWSTR Title);

int main(int argc, char *argv[])
{

	HMODULE hModule = LoadLibrary("./hook.dll");

	if (hModule != NULL)
	{
		PFUNMSG pMsgBox = (PFUNMSG)GetProcAddress(hModule, "MsgBox");
		pMsgBox(L"hello lyshark", L"msgbox");
	}

	system("pause");
	return 0;
}

x86 實現遠程線程注入: 注入原理是利用了Windows系統中提供的CreateRemoteThread()這個API函數,該函數第四個參數是准備運行的線程,我們將LoadLibrary()函數填入其中,這樣就可以執行遠程進程中的LoadLibrary()函數,進而將我們自己准備的DLL加載到遠程進程空間中執行,DLL在被裝載后則會自動執行初始化部分,X86注入代碼如下.

#include <windows.h>
#include <stdio.h>

// 使用 CreateRemoteThread 實現遠線程注入
BOOL CreateRemoteThreadInjectDll(DWORD Pid, char *DllName)
{
	HANDLE hProcess = NULL;
	SIZE_T dwSize = 0;
	LPVOID pDllAddr = NULL;
	FARPROC pFuncProcAddr = NULL;

	// 打開注入進程,獲取進程句柄
	hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, Pid);
	if (NULL == hProcess)
	{
		return FALSE;
	}
	// 計算欲注入 DLL 文件完整路徑的長度
	dwSize = sizeof(char)+lstrlen(DllName);

	//  在目標進程申請一塊長度為 nDllLen 大小的內存空間
	pDllAddr = VirtualAllocEx(hProcess, NULL, dwSize, MEM_COMMIT, PAGE_READWRITE);
	if (NULL == pDllAddr)
	{
		return FALSE;
	}
	//  將欲注入 DLL 文件的完整路徑寫入在目標進程中申請的空間內
	if (FALSE == WriteProcessMemory(hProcess, pDllAddr, DllName, dwSize, NULL))
	{
		return FALSE;
	}
	// 獲得 LoadLibraryA()函數的地址
	pFuncProcAddr = GetProcAddress(GetModuleHandle("kernel32.dll"), "LoadLibraryA");
	if (NULL == pFuncProcAddr)
	{
		return FALSE;
	}
	// 使用 CreateRemoteThread 創建遠線程, 實現 DLL 注入
	HANDLE hRemoteThread = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)pFuncProcAddr, pDllAddr, 0, NULL);
	if (NULL == hRemoteThread)
	{
		return FALSE;
	}
	// 關閉句柄
	CloseHandle(hProcess);
	return TRUE;
}

int main(int argc, char *argv[])
{
	CreateRemoteThreadInjectDll(4668, "./x86.dll");
	system("pause");
	return 0;
}

x64 實現遠程線程注入: 如果想要注入X64程序,則需要在編譯時指定為64位編譯模式,並且使用LoadLibraryW()來加載動態鏈接庫,我們只需要在上面代碼的基礎上稍加改進就可以實現64位進程的注入了.

#include <windows.h>
#include <stdio.h>

// 使用 CreateRemoteThread 實現遠線程注入
BOOL CreateRemoteThreadInjectDll(DWORD Pid, PCWSTR DllName)
{
	BOOL ret = FALSE;
	HANDLE hProcess, hThread = NULL;
	FARPROC pfnThreadRtn = NULL;
	PWSTR pwszPara = NULL;

	// 打開注入進程,獲取進程句柄
	hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, Pid);
	if (NULL == hProcess)
	{
		return FALSE;
	}

	// 計算欲注入 DLL 文件完整路徑的長度
	size_t iProxyFileLen = wcslen(DllName) * sizeof(WCHAR);

	//  在目標進程申請一塊長度為 nDllLen 大小的內存空間
	pwszPara = (PWSTR)VirtualAllocEx(hProcess, NULL, iProxyFileLen, MEM_COMMIT, PAGE_READWRITE);
	if (NULL == pwszPara)
	{
		return FALSE;
	}

	//  將欲注入 DLL 文件的完整路徑寫入在目標進程中申請的空間內
	if (FALSE == WriteProcessMemory(hProcess, pwszPara, (PVOID)DllName, iProxyFileLen, NULL))
	{
		return FALSE;
	}

	// 獲得 LoadLibraryW()函數的地址
	pfnThreadRtn = GetProcAddress(GetModuleHandle(TEXT("Kernel32")), "LoadLibraryW");
	if (NULL == pfnThreadRtn)
	{
		return FALSE;
	}

	// 使用 CreateRemoteThread 創建遠線程, 實現 DLL 注入
	hThread = CreateRemoteThread(hProcess, NULL, 1024, (LPTHREAD_START_ROUTINE)pfnThreadRtn, pwszPara, 0, NULL);
	WaitForSingleObject(hThread, INFINITE);
	if (NULL != hThread)
	{
		CloseHandle(hThread);
		CloseHandle(hProcess);
		VirtualFreeEx(hProcess, pwszPara, 0, MEM_RELEASE);
		return TRUE;
	}
	return FALSE;
}

int main(int argc, char *argv[])
{
	CreateRemoteThreadInjectDll(8224, L"./x64.dll");
	system("pause");
	return 0;
}

實現普通消息鈎子注入: Windows提供的鈎子類型非常多,其中一種類型的鈎子非常實用,那就是WH_GETME SSAGE鈎子,它可以很方便地將DLL文件注入到所有的基於消息機制的目標程序中,代碼非常簡單,這里直接給出DLL文件的代碼,具體如下:

#include <windows.h>

extern "C" __declspec(dllexport) VOID SetHookOn();
extern "C" __declspec(dllexport) VOID SetHookOff();

HHOOK g_HHook = NULL;
HINSTANCE g_hInst = NULL;

VOID DoSomeThing()
{
	MessageBoxA(0, "hello lyshark", 0, 0);
}

BOOL WINAPI DllMain(HINSTANCE hinstDLL,DWORD fdwReason,LPVOID lpvReserved)
{
	switch (fdwReason)
	{
		case DLL_PROCESS_ATTACH:
		{
			g_hInst = hinstDLL;
			DoSomeThing();
			break;
		}
	}
	return TRUE;
}

LRESULT CALLBACK GetMsgProc(int code,WPARAM wParam,LPARAM lParam)
{
	return CallNextHookEx(g_HHook, code, wParam, lParam);
}

VOID SetHookOn()
{
	g_HHook = SetWindowsHookEx(WH_GETMESSAGE, GetMsgProc, g_hInst, 0);
}

VOID SetHookOff()
{
	UnhookWindowsHookEx(g_HHook);
}

實現全局消息鈎子注入: 該注入的原理是利用系統中的SetWindowHookEx()這個API函數,該函數可以攔截目標進程的消息到指定DLL中的導出函數上,利用這個特性,我們可以將DLL注入到全局進程中,但是在使用SetWindowsHookEx()之前首先需要將HOOK的DLL加載到本身的進程中,以此得到DLL的模塊句柄,再使用GetProcAddress()得到DLL中公開的函數地址,最后遍歷出待注入進程的線程ID,這樣SetWindowHookEx()就可以利用這些參數進行HOOK了.

我們先來編寫DLL文件,創建Dll工程hook.cpp然后將SetHook()函數導出,由於該注入方式是全局注入,所以如果我們想要注入到指定進程中,則需要在DllMain()也就是動態鏈接庫開頭位置進行判斷,如果是我們需要Hook的進程,則加載Dll到指定進程中,如果不是則不執行任何操作,這樣一來即可實現指定進程注入.

#include <windows.h>
HHOOK Global_Hook;

// 設置全局消息回調函數
LRESULT CALLBACK MyProc(int nCode, WPARAM wParam, LPARAM lParam)
{
	return CallNextHookEx(Global_Hook, nCode, wParam, lParam);
}
// 安裝全局鈎子,此處的hook.dll可以是外部其他的dll
extern "C" __declspec(dllexport) void SetHook()
{
	Global_Hook = SetWindowsHookEx(WH_CBT, MyProc, GetModuleHandle(TEXT("hook.dll")), 0);
}
// 卸載全局鈎子
extern "C" __declspec(dllexport) void UnHook()
{
	if(Global_Hook)
		UnhookWindowsHookEx(Global_Hook);
}

bool APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
	HWND hwnd = FindWindowW(L"valve001",NULL);
	DWORD pid;
	GetWindowThreadProcessId(hwnd, &pid);
	if (GetCurrentProcessId() == pid)
	{
		MessageBox(hwnd, TEXT("hello lyshark"), 0, 0);
	}
	return true;
}

調用代碼:注意必須將上方編譯好的hook.dll與下方工程放到同一個目錄下,通過LoadLibrary()函數獲取到模塊句柄,然后通過GetProcAddress()獲取到導出函數地址,並通過函數指針調用,由於全局注入依賴於父進程,所以下面的代碼必須一直運行.

#include <windows.h>

int main(int argc, char *argv[])
{
	HMODULE hMod = LoadLibrary(TEXT("hook.dll"));

	typedef void(*pSetHook)(void);
	pSetHook SetHook = (pSetHook)GetProcAddress(hMod, "SetHook");
	SetHook();
	while (1)
	{
		Sleep(1000);
	}
	return 0;
}

APC應用層異步注入: APC 是異步過程調用,在Windows下每個線程在可被喚醒時在其APC鏈中的函數將有機會執行被執行,每一個線程都具有一個APC鏈,那么只要在可以在APC鏈中添加一個APC,就可以完成我們所需要的DLL注入的功能.

1.將需要加載的DLL的完整路徑寫入目標進程空間.
2.獲得LoadLibraryA()函數的地址,當然也可以是LoadLibraryW()函數的地址.
3.枚舉目標進程中的所有線程,為每個線程添加一個APC函數,這樣增加了注入成功的機會.

該注入的原理是利用當線程被喚醒時APC中的注冊函數會被執行的機制,並以此去執行我們的DLL加載代碼,進而完成DLL注入的目的,通過APC注入的流程步驟大致如下

1.當EXE里某個線程執行到SleepEx()或者WaitForSingleObjectEx()時,系統就會產生一個軟中斷.
2.當線程再次被喚醒時,此線程會首先執行APC隊列中的被注冊的函數.
3.利用QueueUserAPC()這個API可以在軟中斷時向線程的APC隊列插入一個函數指針,如果我們插入的是Loadlibrary()執行函數的話,就能達到注入DLL的目的,不論如何目標程序必須有執行SleepEx()或者WaitForSingleObjectEx()否則DLL不會加載.

#include <windows.h>
#include <tlhelp32.h>
#include <stdio.h>

// APC注入
BOOL ApcInjectDll(DWORD dwPid, char * szDllName)
{
	// 計算欲注入 DLL 文件完整路徑的長度
	int nDllLen = lstrlen(szDllName) + sizeof(char);

	// 打開目標進程
	HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS,FALSE, dwPid);
	if (hProcess == NULL)
	{
		return FALSE;
	}
	// 在目標進程申請一塊長度為 nDllLen 大小的內存空間
	PVOID pDllAddr = VirtualAllocEx(hProcess,NULL, nDllLen,MEM_COMMIT,PAGE_READWRITE);
	if (pDllAddr == NULL)
	{
		CloseHandle(hProcess);
		return FALSE;
	}
	DWORD dwWriteNum = 0;
	// 將欲注入 DLL 文件的完整路徑寫入在目標進程中申請的空間內
	WriteProcessMemory(hProcess, pDllAddr, szDllName,nDllLen, &dwWriteNum);
	CloseHandle(hProcess);

	THREADENTRY32 te = { 0 };
	te.dwSize = sizeof(THREADENTRY32);
	//得到線程快照
	HANDLE handleSnap = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
	if (INVALID_HANDLE_VALUE == handleSnap)
	{
		CloseHandle(hProcess);
		return FALSE;
	}
	// 獲得 LoadLibraryA()函數的地址
	FARPROC pFunAddr = GetProcAddress(GetModuleHandle("kernel32.dll"), "LoadLibraryA");
	DWORD dwRet = 0;
	//得到第一個線程
	if (Thread32First(handleSnap, &te))
	{
		do
		{
			//進行進程 ID 對比
			if (te.th32OwnerProcessID == dwPid)
			{
				//得到線程句柄
				HANDLE hThread = OpenThread(THREAD_ALL_ACCESS,FALSE,te.th32ThreadID);
				if (hThread)
				{
					//向線程插入 APC
					dwRet = QueueUserAPC((PAPCFUNC)pFunAddr,hThread,(ULONG_PTR)pDllAddr);
					//關閉句柄
					CloseHandle(hThread);
				}
			}
			//循環下一個線程
		} while (Thread32Next(handleSnap, &te));
	}
	CloseHandle(handleSnap);
	return TRUE;
}

int main(int argc, char *argv[])
{
	ApcInjectDll(9608, "c:/x86.dll");
	system("pause");
	return 0;
}

ZwCreateThreadEx強力注入: 在前面的注入方式中,我們使用了CreateRemoteThread()這個函數來完成線程注入,此方式可以注入普通的進程,但卻無法注入到系統進程中,因為系統進程是處在SESSION0高權限級別的會話層.

由於CreateRemoteThread()底層會調用ZwCreateThreadEx()這個未公開的內核函數,所以我們必須手動調用ZwCreateThread()這一內核函數,將第七個參數設置為0即可,ZwCreateThreadEx函數在ntdll.dll中並未聲明,所以必須手動使用GetProcAddress函數將其地址導出.

#include <windows.h>
#include <stdio.h>

// 使用 ZwCreateThreadEx 實現遠線程注入
BOOL ZwCreateThreadExInjectDll(DWORD dwProcessId, char * pDllName)
{
	HANDLE hProcess = NULL;
	SIZE_T dwSize = 0;
	LPVOID pDllAddr = NULL;
	FARPROC pFuncProcAddr = NULL;
	HANDLE hRemoteThread = NULL;
	DWORD dwStatus = 0;

	// 打開注入進程,獲取進程句柄
	hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcessId);
	if (NULL == hProcess)
	{
		return FALSE;
	}
	// 在注入進程中申請內存
	dwSize = sizeof(char)+lstrlen(pDllName);
	pDllAddr = ::VirtualAllocEx(hProcess, NULL, dwSize, MEM_COMMIT, PAGE_READWRITE);
	if (NULL == pDllAddr)
	{
		return FALSE;
	}
	// 向申請的內存中寫入數據
	if (FALSE == ::WriteProcessMemory(hProcess, pDllAddr, pDllName, dwSize, NULL))
	{
		return FALSE;
	}
	// 加載 ntdll.dll
	HMODULE hNtdllDll = ::LoadLibrary("ntdll.dll");
	if (NULL == hNtdllDll)
	{
		return FALSE;
	}
	// 獲取LoadLibraryA函數地址
	pFuncProcAddr = ::GetProcAddress(::GetModuleHandle("Kernel32.dll"), "LoadLibraryA");
	if (NULL == pFuncProcAddr)
	{
		return FALSE;
	}
	// 獲取ZwCreateThread函數地址
#ifdef _WIN64
	typedef DWORD(WINAPI *typedef_ZwCreateThreadEx)(
		PHANDLE ThreadHandle,
		ACCESS_MASK DesiredAccess,
		LPVOID ObjectAttributes,
		HANDLE ProcessHandle,
		LPTHREAD_START_ROUTINE lpStartAddress,
		LPVOID lpParameter,
		ULONG CreateThreadFlags,
		SIZE_T ZeroBits,
		SIZE_T StackSize,
		SIZE_T MaximumStackSize,
		LPVOID pUnkown);
#else
	typedef DWORD(WINAPI *typedef_ZwCreateThreadEx)(
		PHANDLE ThreadHandle,
		ACCESS_MASK DesiredAccess,
		LPVOID ObjectAttributes,
		HANDLE ProcessHandle,
		LPTHREAD_START_ROUTINE lpStartAddress,
		LPVOID lpParameter,
		BOOL CreateSuspended,
		DWORD dwStackSize,
		DWORD dw1,
		DWORD dw2,
		LPVOID pUnkown);
#endif
	typedef_ZwCreateThreadEx ZwCreateThreadEx = (typedef_ZwCreateThreadEx)::GetProcAddress(hNtdllDll, "ZwCreateThreadEx");
	if (NULL == ZwCreateThreadEx)
	{
		return FALSE;
	}
	// 使用 ZwCreateThreadEx 創建遠線程, 實現 DLL 注入
	dwStatus = ZwCreateThreadEx(&hRemoteThread, PROCESS_ALL_ACCESS, NULL, hProcess, 
		(LPTHREAD_START_ROUTINE)pFuncProcAddr, pDllAddr, 0, 0, 0, 0, NULL);
	if (NULL == hRemoteThread)
	{
		return FALSE;
	}
	// 關閉句柄
	::CloseHandle(hProcess);
	::FreeLibrary(hNtdllDll);
	return TRUE;
}

int main(int argc, char *argv[])
{
	BOOL bRet = ZwCreateThreadExInjectDll(2940, "hook.dll");

	system("pause");
	return 0;
}

強制卸載進程中的DLL:

#include <Windows.h>
#include <stdio.h>
#include <TlHelp32.h>

BOOL UnLoad_Module(DWORD dwPID, LPCTSTR szDllName)
{
	BOOL bMore = FALSE, bFound = FALSE;
	HANDLE hSnapshot, hProcess, hThread;
	HMODULE hModule = NULL;
	MODULEENTRY32 me = { sizeof(me) };
	LPTHREAD_START_ROUTINE pThreadProc;

	hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, dwPID);
	bMore = Module32First(hSnapshot, &me);
	for (; bMore; bMore = Module32Next(hSnapshot, &me))
	{
		if (!_tcsicmp((LPCTSTR)me.szModule, szDllName) || !_tcsicmp((LPCTSTR)me.szExePath, szDllName))
		{
			bFound = TRUE;
			break;
		}
	}
	if (!(hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwPID)))
		return FALSE;

	hModule = GetModuleHandle(L"kernel32.dll");
	pThreadProc = (LPTHREAD_START_ROUTINE)GetProcAddress(hModule, "FreeLibrary");
	hThread = CreateRemoteThread(hProcess, NULL, 0, pThreadProc, me.modBaseAddr, 0, NULL);
	WaitForSingleObject(hThread, INFINITE);
	if (hThread != 0)
	{
		CloseHandle(hThread);
		CloseHandle(hProcess);
		CloseHandle(hSnapshot);
		return TRUE;
	}
	return FALSE;
}

int main(int argc, char *argv[])
{
	UnLoad_Module(2012, "lyshark.dll");

	system("pause");
	return 0;
}

純匯編實現遠程Dll注入:

.data
	szMyDll        db "\lyshark.dll",0h       ; 要注入的DLL
	szDllKernel    db "Kernel32.dll",0h
	szLoadLibrary  db "LoadLibraryA",0h
	lpFileName     db "Tutorial-i386",0h      ; 指定要注入進程
	lpDllName      dd ?
.data?
	szMyDllFull    db MAX_PATH dup (?)
	lpLoadLibrary  dd ?
	dwProcessID    dd ?     
	dwThreadID     dd ?
	hProcess       dd ?
.code
	main PROC
; 准備工作:獲取dll的全路徑文件名、獲取LoadLibrary函數地址等
		invoke GetCurrentDirectory,MAX_PATH,addr szMyDllFull
		invoke lstrcat,addr szMyDllFull,addr szMyDll
		invoke GetModuleHandle,addr szDllKernel
		invoke GetProcAddress,eax,offset szLoadLibrary
		mov lpLoadLibrary,eax

; 查找文件管理器窗口並獲取進程ID,然后打開進程
		invoke FindWindow,NULL,addr lpFileName
		invoke GetWindowThreadProcessId,eax,offset dwProcessID
  		mov dwThreadID,eax
  		invoke OpenProcess,PROCESS_ALL_ACCESS,FALSE,dwProcessID
		mov hProcess,eax

; 在進程中分配空間並將DLL文件名拷貝過去,然后創建一個LoadLibrary線程
		invoke VirtualAllocEx,hProcess,NULL,MAX_PATH,MEM_COMMIT,PAGE_READWRITE
		mov lpDllName,eax
		invoke WriteProcessMemory,hProcess,eax,offset szMyDllFull,MAX_PATH,NULL
		invoke CreateRemoteThread,hProcess,NULL,0,lpLoadLibrary,lpDllName,0,NULL
		ret
	main endp
end main

純匯編實現遠程代碼注入:

1.首先使用匯編編寫一個代碼注入器,其命名為main.asm

.data
	lpLoadLibrary      dd ?
	lpGetProcAddress   dd ?
	lpGetModuleHandle  dd ?
	dwProcessID        dd ?
	dwThreadID         dd ?
	hProcess           dd ?
	lpRemoteCode       dd ?
.const
	ProcHandle        db "lyshark.exe",0h
	KernelBase        db "Kernel32.dll",0h
	szLoadLibrary     db "LoadLibraryA",0h
	szGetProcAddress  db "GetProcAddress",0h
	szGetModuleHandle db "GetModuleHandleA",0h
.code
include Macro.inc
include ShellCode.asm
	main proc
		invoke GetModuleHandle,addr KernelBase
		mov ebx,eax
		invoke GetProcAddress,ebx,offset szLoadLibrary
		mov lpLoadLibrary,eax
		invoke GetProcAddress,ebx,offset szGetProcAddress
		mov lpGetProcAddress,eax
		invoke GetProcAddress,ebx,offset szGetModuleHandle
		mov lpGetModuleHandle,eax

		invoke FindWindow,NULL,addr ProcHandle
		invoke GetWindowThreadProcessId,eax,offset dwProcessID
		mov dwThreadID,eax
		invoke OpenProcess,PROCESS_ALL_ACCESS,FALSE,dwProcessID
		mov hProcess,eax

		invoke VirtualAllocEx,hProcess,NULL,2048,MEM_COMMIT,PAGE_EXECUTE_READWRITE
			.if eax
				mov lpRemoteCode,eax
				invoke WriteProcessMemory,hProcess,lpRemoteCode,offset REMOTE_CODE_START,1024,NULL
				invoke WriteProcessMemory,hProcess,lpRemoteCode,offset lpLoadLibrary,sizeof dword * 3,NULL
				mov eax,lpRemoteCode
				add eax,offset _RemoteThread - offset REMOTE_CODE_START
				invoke CreateRemoteThread,hProcess,NULL,0,eax,0,0,NULL
				invoke CloseHandle,eax
			.endif
			invoke CloseHandle,hProcess	
	invoke ExitProcess,NULL
	ret
	main endp
end main

為了后期編程方便,編寫一個反轉宏Macro.inc用來翻轉參數,使用定義_invoke調用更方便

; --------------------------------------------
; 翻轉參數字節序
reverseArgs macro arglist:VARARG
	LOCAL txt,count
	txt TEXTEQU <>
	count=0
	for i,<arglist>
		count = count+1
		txt TEXTEQU @CatStr(i,<!,>,<%txt>)
	endm
	if count GT 0
		txt SUBSTR txt,1,@SizeStr(%txt)-1
	endif
	exitm txt
endm
; --------------------------------------------
; 創建類似於INVOKE的宏代碼
_invoke macro _Proc,args:VARARG
	LOCAL count
	count = 0
%	for i,< reverseArgs( args ) >
		count = count+1
		push i
	endm
	call dword ptr _Proc    
endm

最后編寫注入代碼,此處命名為shellcode.asm該代碼包括了子定位功能.

REMOTE_CODE_START equ this byte
_lpLoadLibrary      dd ?
_lpGetProcAddress   dd ?
_lpGetModuleHandle  dd ?

; --------------------------------------------
; 存放靜態資源,比如常量,字符串等.
_hInstance          dd ?
_szShowTitle        db "hello lyshark",0h

; --------------------------------------------
; 存放獲取到的指針
_lpDllUser          dd ?
_lpMessageBox       dd ?
; --------------------------------------------
; 放入導入函數的字符串
_szDllUser		db	"user32.dll",0h
_szMessageBox           db      "MessageBoxA",0h,0
; --------------------------------------------
_RemoteThread proc uses ebx esi edi
		LOCAL @hModule
; --------------------------------------------
; 計算指令的偏移地址,用ebx作為基址指針
		call @F
		@@:
		pop ebx
		sub ebx,offset @B
; --------------------------------------------
		_invoke [ebx + _lpGetModuleHandle],NULL         ; 取當前模塊句柄
		mov [ebx + _hInstance],eax
		lea eax,[ebx + offset _szDllUser]           
		_invoke [ebx + _lpGetModuleHandle],eax          ; 取user32.dll模塊句柄
		mov @hModule,eax
; --------------------------------------------
; 循環獲取每個導入函數的地址,並放入指針變量保存
		lea esi,[ebx + offset _szMessageBox]            ; 循環獲取,從該函數起始地址處
		lea edi,[ebx + offset _lpMessageBox]
		.while TRUE
			_invoke	[ebx + _lpGetProcAddress],@hModule,esi
			mov [edi],eax       ; 獲取到函數地址后,放入導入函數字符串中
			add edi,4           ; 每次遞增4字節,指向下一個函數,遇到0則停止
			@@:
			lodsb
			or al,al
			jnz @B
			.break .if !byte ptr [esi]
		.endw
; --------------------------------------------
		;lea esi,[ebx+ offset _szMessageBox]            ; 取msgbox模塊地址
		;_invoke [ebx+_lpGetProcAddress],@hModule,esi   ; 獲取地址
		;mov [ebx+_lpMessageBox],eax                    ; 存入變量中
		lea esi,[ebx + offset _szShowTitle]             ; 獲取彈窗資源
		_invoke [ebx + _lpMessageBox],0,esi,eax,0       ; 調用信息框
		ret
_RemoteThread endp


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM