异步过程调用是一种能在特定线程环境中异步执行的系统机制。往线程APC队列添加APC,系统会产生一个软中断。在线程下一次被调度的时候,就会执行APC函数,APC有两种形式,由系统产生的APC称为内核模式APC,由应用程序产生的APC被称为用户模式APC。每个线程都拥有自己的APC队列。应用程序可以使用函数把APC添加到指定线程的APC队列,函数定义如下:
1 2 3 4 5
| DWORD WINAPI QueueUserAPC( _In_ PAPCFUNC pfnAPC, _In_ HANDLE hThread, _In_ ULONG_PTR dwData );
|
当用户模式APC被添加后,线程并不会直接调用APC函数,只有当线程处于“可变等待状态”时才会调用。如果希望线程执行APC函数,就要让线程进入可变等待状态。当线程调用SleepEx、SignalObjectAndWait、MsgWaitForMultipleObjectEx、WaitForMultipleObjectsEx或WaitForSingleObjectEx时就会进入可变等待状态。 ReadFileEx、WriteFileEx、和SetWaitableTimer等都是使用APC作为完成例程的回调机制。
原理:使用QueueUserAPC向目标进程的线程添加APC函数,而这个APC函数能够实现模块的加载功能。要使用这种方法的前提是目标进程能够进入可变等待状态,否则即便添加了APC也没有执行的机会
步骤:
1.向目标进程写入待注入的模块名称
2.枚举目标进程所有线程。(由于并不是每个线程都有机会进入可变等待状态,为了增加APC的机会,向目标进程的每个线程都添加APC是个比较保险的做法)
3.增加APC,把LoadLibrary作为APCProc,把第一步中DLL路径名称所在地址作为其参数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71
| int InjectDllWithApc(WCHAR* DllFullPath, ULONG ProcessId) { HANDLE hTatgetProcessHandle; hTatgetProcessHandle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, ProcessId); if (hTatgetProcessHandle == NULL) { printf("Failed To Open Process!!\n"); return 0; } ULONG32 ulDllLength = (ULONG32)_tcslen(DllFullPath) + 1; WCHAR* pRemoteAddress = (WCHAR*)VirtualAllocEx(hTatgetProcessHandle, NULL, ulDllLength * sizeof(WCHAR), MEM_COMMIT, PAGE_READWRITE); if (pRemoteAddress == NULL) { printf("Alloc Virtual Address Failed!\n"); CloseHandle(hTatgetProcessHandle); return 0; } if (WriteProcessMemory(hTatgetProcessHandle, pRemoteAddress, (LPVOID)DllFullPath, ulDllLength * sizeof(WCHAR), NULL) == FALSE) { VirtualFreeEx(hTatgetProcessHandle, pRemoteAddress, ulDllLength, MEM_DECOMMIT); CloseHandle(hTatgetProcessHandle); return 0; } THREADENTRY32 ThreadEntry32 = { 0 }; HANDLE hThreadSnap = INVALID_HANDLE_VALUE; ThreadEntry32.dwSize = sizeof(THREADENTRY32); HANDLE hThreadHandle; BOOL bStatus; DWORD dwReturn; hThreadSnap = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0); if (hThreadSnap == INVALID_HANDLE_VALUE) { return 0; } if (!Thread32First(hThreadSnap, &ThreadEntry32)) { CloseHandle(hThreadSnap); return 1; } do { if (ThreadEntry32.th32OwnerProcessID == ProcessId) { printf("TID:%d\n", ThreadEntry32.th32ThreadID); hThreadHandle = OpenThread(THREAD_ALL_ACCESS, FALSE, ThreadEntry32.th32ThreadID); if (hThreadHandle) { dwReturn = QueueUserAPC( (PAPCFUNC)LoadLibrary, hThreadHandle, (ULONG_PTR)pRemoteAddress); if (dwReturn > 0) { bStatus = TRUE; } CloseHandle(hThreadHandle); } } } while (Thread32Next(hThreadSnap, &ThreadEntry32)); VirtualFreeEx(hTatgetProcessHandle, pRemoteAddress, ulDllLength, MEM_DECOMMIT); CloseHandle(hThreadSnap); CloseHandle(hTatgetProcessHandle); return 0; }
|