• C++代码注入


    一、C++代码注入原则:

    1. 在注入代码中不允许使用API。
    2. 在注入代码中不允许使用全局变量。
    3. 在注入代码中不允许使用字符串(编译时也被当做全局变量)。
    4. 在注入代码中不允许使用函数嵌套。

    二、注入代码编写思路:

    1. 在本进程通过获取 LoadLibraryA 与 GetProcess 函数的地址。
    2. 涉及一组参数,里面包括 {函数地址、模块地址、函数名、传递参数}。
    3. 传入进去后,利用LoadLibraryA 与 GetProcess 函数,在注入代码中直接现场"加载模块-获取函数-调用",来达到调用API的目的。

    三、编写过程的几个坑:

    1. 使用typedef定义函数指针,先在msdn搜索函数原型,复制过去,将名字定义成指针并大写。
    2. 申请内存时的权限,参数的内存使用 PAGE_READWRITE权限;代码的内存使用PAGE_EXECUTE_READWRITE权限,否则代码无法被执行。
    3. 一定要预先在msdn上搜索确定函数要加载的模块以及函数名,这一步很容易出错。如果出错只能调试被注入程序获取结果,比较麻烦。

    四、olldbg调试思路:

    1. 在 "选项-调试设置-事件"中勾选“中断于新线程”。
    2. 注入后就可以在新线程上一步步进行调试。

    五、源代码(练习了两套,一套是注入MessageBoxA,另一套是注入CreateFileA)

      1 // 代码注入.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
      2 // 代码注入,实现在任意进程注入 messagebox() 这段代码
      3 
      4 #include "pch.h"
      5 #include <stdio.h>
      6 #include <Windows.h>
      7 DWORD WINAPI ThreadProc(LPVOID lpParameter);
      8     // 定义传入参数
      9     typedef struct _THREAD_PARAM {
     10         FARPROC pFunc[2]; // 存放两个函数 LoadLibraryA ; GetProcess;
     11         char szBuff[4][128]; // 存放四个参数
     12     }THREAD_PARAM, *PTHREAD_PARAM;
     13 
     14 // LoadLibraryA函数
     15 typedef HMODULE(WINAPI *PFLOADLIBARAYA)(LPCSTR lpLibFileName);
     16 
     17 // GetProcAddress()函数
     18 typedef FARPROC(WINAPI *PGETPROCADDRESS)(HMODULE hModule, LPCSTR lpProcName);
     19 
     20 // MessageBox()函数
     21 typedef int(WINAPI *PMESSAGEBOXA)(HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType);
     22 
     23 // 注入目标进程的线程函数
     24 DWORD WINAPI ThreadProc(LPVOID lpParameter) {
     25     /*
     26         牢记:在代码注入中
     27         1. 不能使用系统函数。
     28         2. 不能使用全局变量。
     29         2. 不能使用字符串(因为这会被当成全局函数)
     30     */
     31 
     32 
     33     // 先将传入的参数值取出来
     34     PTHREAD_PARAM pParam = (PTHREAD_PARAM)lpParameter;
     35     HMODULE hMod = NULL;
     36     FARPROC pFunc = NULL; // messageBox这个函数
     37 
     38     // 先调用 LoadLibarayA函数来加载user32.dll
     39     hMod = ((PFLOADLIBARAYA)pParam->pFunc[0])(pParam->szBuff[0]); //LoadLibraryA(kernel32.dll) 先获取模块句柄,在获取 MessageBox这个函数。
     40     if (!hMod) return 1;
     41     // 再来调用 GetProcess 得到 MessageBox 这个函数
     42     pFunc = (FARPROC)((PGETPROCADDRESS)pParam->pFunc[1])(hMod, pParam->szBuff[1]);
     43     if (!pFunc) return 1;
     44     // 调用函数来弹出对话框
     45     ((PMESSAGEBOXA)pFunc)(NULL, pParam->szBuff[2], pParam->szBuff[3], MB_OK);
     46 
     47     return 0;
     48 }
     49 
     50 BOOL InjectCode(DWORD Pid) {
     51 
     52 
     53 
     54     THREAD_PARAM param = { 0, };
     55     LPVOID lpBuffer[2] = { 0, }; // 存储两块开辟内存,一块存储参数,另一块存储代码
     56 
     57     // 获取 kernel32.dll模块句柄,因为需要的函数全部存储在此
     58     HMODULE hModule = GetModuleHandleA(("kernel32.dll"));
     59     
     60     // 初始化传入线程的参数
     61     param.pFunc[0] = GetProcAddress(hModule, "LoadLibraryA");
     62     param.pFunc[1] = GetProcAddress(hModule, "GetProcAddress");
     63     strcpy_s(param.szBuff[0], "user32.dll"); //加载的模块名
     64     strcpy_s(param.szBuff[1], "MessageBoxA"); //加载的函数名
     65     strcpy_s(param.szBuff[2], "abc"); //传入的第一个参数
     66     strcpy_s(param.szBuff[3], "def"); // 传入的第二个参数
     67 
     68     //开辟内存,将线程参数传入内存中
     69     HANDLE hProcessHandle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, Pid);
     70     DWORD dwSize = sizeof(THREAD_PARAM);
     71 
     72     lpBuffer[0] = VirtualAllocEx(hProcessHandle, NULL, dwSize, MEM_COMMIT, PAGE_READWRITE);
     73 
     74     if (WriteProcessMemory(hProcessHandle, lpBuffer[0], (LPVOID)&param, dwSize, NULL)) {
     75         printf("第一段代码写入成功
    ");
     76     }
     77     else {
     78         printf("第一段代码写入失败,错误码:%d
    ", GetLastError());
     79         return FALSE;
     80     }
     81 
     82     // 开辟内存给线程,并将注入代码写入
     83     dwSize = (DWORD)InjectCode - (DWORD)ThreadProc;
     84     lpBuffer[1] = VirtualAllocEx(hProcessHandle, NULL, dwSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
     85     if (WriteProcessMemory(hProcessHandle, lpBuffer[1], (LPVOID)ThreadProc, dwSize, NULL)) {
     86         printf("第二段代码写入成功
    ");
     87     }
     88     else {
     89         printf("第二段代码写入失败,错误码:%d
    ", GetLastError());
     90         return FALSE;
     91     }
     92 
     93     // 开始创建远程线程
     94     HANDLE hThread = CreateRemoteThread(hProcessHandle, NULL, 0, (LPTHREAD_START_ROUTINE)lpBuffer[1], (LPVOID)lpBuffer[0], 0, NULL);
     95     if (hThread) {
     96         printf("线程开始执行!
    ");
     97     }
     98     else {
     99         printf("创建远程线程失败,错误码:%d
    ", GetLastError());
    100         return FALSE;
    101     }
    102     // 等待线程开始执行
    103     printf("到目前位置成功!");
    104     WaitForSingleObject(hThread, INFINITE);
    105     CloseHandle(hProcessHandle);
    106     CloseHandle(hThread);
    107 
    108 
    109     return TRUE;
    110 }
    111 
    112 // 拒绝访问时的提权代码
    113 BOOL SetPrivilege(LPCTSTR lpszPrivilege, BOOL bEnablePrivilege)
    114 {
    115     TOKEN_PRIVILEGES tp;
    116     HANDLE hToken;
    117     LUID luid;
    118 
    119     if (!OpenProcessToken(GetCurrentProcess(),
    120         TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
    121         &hToken))
    122     {
    123         wprintf(L"OpenProcessToken error: %u
    ", GetLastError());
    124         return FALSE;
    125     }
    126 
    127     if (!LookupPrivilegeValue(NULL,           // lookup privilege on local system
    128         lpszPrivilege,  // privilege to lookup 
    129         &luid))        // receives LUID of privilege
    130     {
    131         wprintf(L"LookupPrivilegeValue error: %u
    ", GetLastError());
    132         return FALSE;
    133     }
    134 
    135     tp.PrivilegeCount = 1;
    136     tp.Privileges[0].Luid = luid;
    137     if (bEnablePrivilege)
    138         tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
    139     else
    140         tp.Privileges[0].Attributes = 0;
    141 
    142     // Enable the privilege or disable all privileges.
    143     if (!AdjustTokenPrivileges(hToken,
    144         FALSE,
    145         &tp,
    146         sizeof(TOKEN_PRIVILEGES),
    147         (PTOKEN_PRIVILEGES)NULL,
    148         (PDWORD)NULL))
    149     {
    150         wprintf(L"AdjustTokenPrivileges error: %u
    ", GetLastError());
    151         return FALSE;
    152     }
    153 
    154     if (GetLastError() == ERROR_NOT_ALL_ASSIGNED)
    155     {
    156         wprintf(L"The token does not have the specified privilege. 
    ");
    157         return FALSE;
    158     }
    159 
    160     return TRUE;
    161 }
    162 
    163 int main(int argc,char *argv[])
    164 {
    165     //判断参数个数
    166     if (argc != 2) {
    167         printf("
     USAGE  : %s <pid>
    ", argv[0]);
    168         return 1;
    169     }
    170     if (!SetPrivilege(SE_DEBUG_NAME, TRUE)) {
    171         printf("提权失败!
    ");
    172     }
    173     else {
    174         printf("提权成功!
    ");
    175         //atol 将字符串转换为数字
    176         if (InjectCode(atol(argv[1]))) {
    177             printf("开启成功!
    ");
    178         }
    179         else {
    180             printf("开启失败!
    ");
    181         }
    182     }
    183 
    184     getchar();
    185 }
    注入调用MessageBoxA()
      1 // 代码注入CreateFile函数.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
      2 //
      3 
      4 #include "pch.h"
      5 #include <iostream>
      6 #include <Windows.h>
      7 
      8 // 构建参数
      9 typedef struct _thread_param {
     10     FARPROC pFunc[2];  // LoadLibrary / GetProcAddress 函数
     11     // 这里应该存放字符
     12     char szBuffer[3][128]; // 加载的模块名字 user32.dll / CreateFileA / szFilePath
     13 }THREAD_PARAM,*PTHREAD_PARAM;
     14 
     15 // 先来构建函数指针
     16 typedef HANDLE (WINAPI *PCREATEFILEA)(
     17     LPCSTR                lpFileName,
     18     DWORD                 dwDesiredAccess,
     19     DWORD                 dwShareMode,
     20     LPSECURITY_ATTRIBUTES lpSecurityAttributes,
     21     DWORD                 dwCreationDisposition,
     22     DWORD                 dwFlagsAndAttributes,
     23     HANDLE                hTemplateFile
     24 );
     25 
     26 // LoadLibrary
     27 typedef HMODULE (WINAPI* PLOADLIBRARYA)(
     28     LPCSTR lpLibFileName
     29 );
     30 
     31 
     32 // GetProcAddress
     33 typedef FARPROC (WINAPI* PGETPROCADDRESS)(
     34     HMODULE hModule,
     35     LPCSTR  lpProcName
     36 );
     37 
     38 // GetProcess
     39 DWORD WINAPI ThreadProc(_In_ LPVOID lpParameter) {
     40 
     41     // 先取出参数,注意:传入一个指针,对应的也应该生成一个指针变量
     42     PTHREAD_PARAM pParam = (PTHREAD_PARAM)lpParameter;
     43 
     44     // 注意:loadLibraryA与getprocaddress 在kernel32.dll,这个不用导出,因为我们直接传入其函数地址,直接根据函数指针调用即可
     45     
     46     // 调用 LoadLibarayA来获取存放CreateFile模块
     47     HMODULE hModule = (HMODULE)((PLOADLIBRARYA)pParam->pFunc[0])(pParam->szBuffer[0]);
     48     if (!hModule) return 1;
     49     
     50     
     51     // 调用GetPrcAddress来加载模块
     52     FARPROC pFunc = (FARPROC)((PGETPROCADDRESS)pParam->pFunc[1])(hModule, pParam->szBuffer[1]);
     53     if (!pFunc) return 1;
     54 
     55 
     56     // 现在调用CreateFileA函数
     57     ((PCREATEFILEA)pFunc)(pParam->szBuffer[2], GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
     58 
     59     return 0;
     60 }
     61 
     62 BOOL CodeInject(DWORD Pid) {
     63 
     64     // 我们的思路是获取目标进程句柄,分配-写入,最后再根据地址开启返回线程
     65     
     66 
     67     // 加载LoadLibraryA和GetProcAddress 两个函数的地址并且初始化参数
     68     THREAD_PARAM param;
     69     HMODULE hMoudle = LoadLibraryA("kernel32.dll");
     70     param.pFunc[0] = (FARPROC)GetProcAddress(hMoudle, "LoadLibraryA");
     71     param.pFunc[1] = (FARPROC)GetProcAddress(hMoudle, "GetProcAddress");
     72     strcpy_s(param.szBuffer[0], "Kernel32.dll");
     73     strcpy_s(param.szBuffer[1], "CreateFileA");
     74     strcpy_s(param.szBuffer[2], "OneFile.txt");
     75 
     76 
     77     LPVOID pBuffer[2]; // 两个存储目标进程地址的数组。
     78     int Res;
     79     HANDLE hProcessHandle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, Pid);
     80 
     81     // 向目标进程分配参数内存,参数内存可读写。
     82     DWORD dwSize = sizeof(THREAD_PARAM);
     83     pBuffer[0] = VirtualAllocEx(hProcessHandle, NULL, dwSize, MEM_COMMIT, PAGE_READWRITE);
     84     if (!WriteProcessMemory(hProcessHandle, pBuffer[0], (LPVOID)&param, dwSize, NULL)) {
     85         printf("写入参数失败,错误码:%d", GetLastError());
     86         return FALSE;
     87     }
     88 
     89     // 向目标进程分配代码内存,参数内存读写-可执行。
     90     dwSize = (DWORD)CodeInject - (DWORD)ThreadProc;
     91     pBuffer[1] = VirtualAllocEx(hProcessHandle, NULL, dwSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
     92     if (!WriteProcessMemory(hProcessHandle, pBuffer[1], (LPVOID)ThreadProc, dwSize, NULL)) {
     93         printf("写入代码失败,错误码:%d", GetLastError());
     94         return FALSE;
     95     }
     96 
     97     // 创建远程线程并执行
     98     HANDLE hThread = CreateRemoteThread(hProcessHandle, NULL, 0, (LPTHREAD_START_ROUTINE)pBuffer[1], (LPVOID)pBuffer[0], 0, (LPDWORD )&Res);
     99     if (!hThread) {
    100         printf("创建远程线程失败,错误码:%d", GetLastError());
    101         return FALSE;
    102     }
    103     printf("线程结果:%d
    ", Res);
    104     // 关闭资源句柄
    105     WaitForSingleObject(hThread, INFINITE);
    106     CloseHandle(hMoudle);
    107     CloseHandle(hThread);
    108     
    109 
    110     return TRUE;
    111 }
    112 
    113 BOOL SetPrivilege(LPCTSTR lpszPrivilege, BOOL bEnablePrivilege)
    114 {
    115     TOKEN_PRIVILEGES tp;
    116     HANDLE hToken;
    117     LUID luid;
    118 
    119     if (!OpenProcessToken(GetCurrentProcess(),
    120         TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
    121         &hToken))
    122     {
    123         wprintf(L"OpenProcessToken error: %u
    ", GetLastError());
    124         return FALSE;
    125     }
    126 
    127     if (!LookupPrivilegeValue(NULL,           // lookup privilege on local system
    128         lpszPrivilege,  // privilege to lookup 
    129         &luid))        // receives LUID of privilege
    130     {
    131         wprintf(L"LookupPrivilegeValue error: %u
    ", GetLastError());
    132         return FALSE;
    133     }
    134 
    135     tp.PrivilegeCount = 1;
    136     tp.Privileges[0].Luid = luid;
    137     if (bEnablePrivilege)
    138         tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
    139     else
    140         tp.Privileges[0].Attributes = 0;
    141 
    142     // Enable the privilege or disable all privileges.
    143     if (!AdjustTokenPrivileges(hToken,
    144         FALSE,
    145         &tp,
    146         sizeof(TOKEN_PRIVILEGES),
    147         (PTOKEN_PRIVILEGES)NULL,
    148         (PDWORD)NULL))
    149     {
    150         wprintf(L"AdjustTokenPrivileges error: %u
    ", GetLastError());
    151         return FALSE;
    152     }
    153 
    154     if (GetLastError() == ERROR_NOT_ALL_ASSIGNED)
    155     {
    156         wprintf(L"The token does not have the specified privilege. 
    ");
    157         return FALSE;
    158     }
    159 
    160     return TRUE;
    161 }
    162 
    163 int main(int argc,char*argv[])
    164 {
    165 
    166     // 在本地创建一个文件夹
    167     // HANDLE hFile = CreateFileA("一个文件", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
    168     //CloseHandle(hFile);
    169     // 现在实现代码注入,要求在notepad.exe中运行上段代码。
    170 
    171     //判断参数个数
    172     if (argc != 2) {
    173         printf("
     USAGE  : %s <pid>
    ", argv[0]);
    174         return 1;
    175     }
    176     
    177     if (!SetPrivilege(SE_DEBUG_NAME, TRUE)) {
    178         printf("提权失败!
    ");
    179     }
    180     else {
    181         printf("提权成功!
    ");
    182         if (CodeInject(atol(argv[1]))) {
    183             printf("开启成功1!
    ");
    184         }
    185         else {
    186             printf("开启失败!
    ");
    187         }
    188     }
    189 
    190 
    191     getchar();
    192     
    193 }
    注入调用CreateFileA()
  • 相关阅读:
    河南省第十届ACM省赛G:Plumbing the depth of lake
    南洋理工oj 题目92 图像有用区域
    初学欧拉图,知识总结,后续增加
    初学并查集知识总结后续增加
    南阳oj 题目42 一笔画问题
    南阳oj 题目 90 整数划分
    南阳oj题目20吝啬的国度 菜鸟的进阶之路
    南阳oj 题目21 三个水杯
    UVA-540 Team Queue
    HDU-1596 find the safest road
  • 原文地址:https://www.cnblogs.com/onetrainee/p/11648679.html
Copyright © 2020-2023  润新知