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("第一段代碼寫入成功\n");
 76     }
 77     else {
 78         printf("第一段代碼寫入失敗,錯誤碼:%d\n", 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("第二段代碼寫入成功\n");
 87     }
 88     else {
 89         printf("第二段代碼寫入失敗,錯誤碼:%d\n", 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("線程開始執行!\n");
 97     }
 98     else {
 99         printf("創建遠程線程失敗,錯誤碼:%d\n", 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\n", 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\n", 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\n", 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. \n");
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("\n USAGE  : %s <pid>\n", argv[0]);
168         return 1;
169     }
170     if (!SetPrivilege(SE_DEBUG_NAME, TRUE)) {
171         printf("提權失敗!\n");
172     }
173     else {
174         printf("提權成功!\n");
175         //atol 將字符串轉換為數字
176         if (InjectCode(atol(argv[1]))) {
177             printf("開啟成功!\n");
178         }
179         else {
180             printf("開啟失敗!\n");
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\n", 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\n", 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\n", 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\n", 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. \n");
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("\n USAGE  : %s <pid>\n", argv[0]);
174         return 1;
175     }
176     
177     if (!SetPrivilege(SE_DEBUG_NAME, TRUE)) {
178         printf("提權失敗!\n");
179     }
180     else {
181         printf("提權成功!\n");
182         if (CodeInject(atol(argv[1]))) {
183             printf("開啟成功1!\n");
184         }
185         else {
186             printf("開啟失敗!\n");
187         }
188     }
189 
190 
191     getchar();
192     
193 }
注入調用CreateFileA()

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM