Linux 下如何隱藏自己不被髮現?

来源:https://www.cnblogs.com/liwugang/archive/2020/04/14/12701360.html
-Advertisement-
Play Games

可能在某些情況下,自己運行的程式不想或者不方便被其他人看到,就需要隱藏運行的進程。或者某些攻擊者採用了本文介紹的隱藏技術,也可以讓大家看到如何進行對抗。 隱藏有兩種方法: 1. kernel 層面,不對用戶層暴露該進程的信息,進程不被看見; 2. 用戶層可以看到該進程信息,但不是以真實的身份出現,而 ...


可能在某些情況下,自己運行的程式不想或者不方便被其他人看到,就需要隱藏運行的進程。或者某些攻擊者採用了本文介紹的隱藏技術,也可以讓大家看到如何進行對抗。
隱藏有兩種方法:

  1. kernel 層面,不對用戶層暴露該進程的信息,進程不被看見;
  2. 用戶層可以看到該進程信息,但不是以真實的身份出現,而是偽造成別的程式出現,達到隱藏自己的目的。

方法一是需要修改內核,本文主要是講第二種方法。

常用獲取進程信息工具

在 Linux 環境下,主要是通過 top、ps 等工具來查看當前運行的進程,他們主要是通過讀取 /proc/ 文件系統來獲取進程信息,讀取哪些內容,我們可以通過 strace (該工具用於監控系統調用和信號) 工具查看,我們以 296277 進程為例。

top 獲取進程信息

296277 進程信息

   PID USER      PR  NI    VIRT    RES    SHR S  %CPU  %MEM     TIME+ COMMAND                                                                                                              
 296277 wangshu+  20   0    2272   1380   1300 S   0.0   0.0   0:00.00 bash 

top 查看到 296277 進程的信息,我們一般主要關心的是最後一列,進程名。

strace 跟蹤結果

stat("/proc/296277", {st_mode=S_IFDIR|0555, st_size=0, ...}) = 0
openat(AT_FDCWD, "/proc/296277/stat", O_RDONLY) = 9
read(9, "296277 (bash) S 296271 296271 23"..., 1024) = 322
close(9)                                = 0
openat(AT_FDCWD, "/proc/296277/statm", O_RDONLY) = 9
read(9, "568 355 335 2 0 78 0\n", 1024) = 21
close(9)

從上面可以看到,主要是讀取了 /proc/296277/stat 和 /proc/296277/statm 文件。

  • /proc/296277/stat 內容
296277 (bash) S 296271 296271 230491 34840 296271 4194304 94 155 0 0 0 0 0 0 20 0 1 0 94413592 2326528 345 18446744073709551615 94055941185536 94055941191257 140723269084624 0 0 0 0 4096 0 0 0 0 17 11 0 0 0 0 0 94055941201384 94055941202080 94055956852736 140723269087783 140723269087820 140723269087820 140723269091283 0
  • /proc/296277/statm 內容
568 345 325 2 0 78 0

可以看到 top 中的進程名是使用 /proc/296277/stat 中的第二項 (bash)。

ps -aux 獲取進程信息

296277 進程信息

wangshu+  296277  0.0  0.0   2272  1380 pts/24   S+   18:59   0:00 /bin/bash

ps -aux 查看到 296277 進程的信息,最後一列是 bash 的完整路徑名。

strace 跟蹤結果

stat("/proc/296277", {st_mode=S_IFDIR|0555, st_size=0, ...}) = 0
openat(AT_FDCWD, "/proc/296277/stat", O_RDONLY) = 6
read(6, "296277 (bash) S 296271 296271 23"..., 2048) = 322
close(6)                                = 0
openat(AT_FDCWD, "/proc/296277/status", O_RDONLY) = 6
read(6, "Name:\tbash\nUmask:\t0022\nState:\tS "..., 2048) = 1095
close(6)                                = 0
openat(AT_FDCWD, "/proc/296277/cmdline", O_RDONLY) = 6
read(6, "/bin/bash\0", 131072)          = 10
read(6, "", 131035)                     = 0
close(6)                                = 0
stat("/dev/pts24", 0x7ffe4ce31630)      = -1 ENOENT (No such file or directory)
stat("/dev/pts/24", {st_mode=S_IFCHR|0620, st_rdev=makedev(0x88, 0x18), ...}) = 0
stat("/etc/localtime", {st_mode=S_IFREG|0644, st_size=545, ...}) = 0
stat("/etc/localtime", {st_mode=S_IFREG|0644, st_size=545, ...}) = 0
write(1, "wangshu+  296277  0.0  0.0   227"..., 104) = 104

從上面可以看到,主要是讀取了 /proc/296277/stat、/proc/296277/status 和 /proc/296277/cmdline。

  • /proc/296277/cmdline 內容
/bin/bash

ps -aux 中進程名可以看到是從 /proc/296277/cmdline 讀取到的。

上面列出來proc信息,可以從proc文件內容介紹獲取更詳細的介紹。

小結

從上面實驗中可以看到,進程名主要是通過 /proc/進程號/stat 和 /proc/進程號/cmdline 文件中獲取。

隱藏技術實現

/proc/進程號/stat 和 /proc/進程號/cmdline 這些介面都是內核實現的,通過閱讀內核代碼得到:

  • /proc/進程號/stat 中的進程名對應的可執行文件的文件名;
  • /proc/進程號/cmdline 內容對應的是啟動該進程的使用的路徑,對應的是入口函數 main(int argc, char *argv[]) 中的 argv[0]。

為了實現隱藏,我們將偽造為 bash 進程, bash 進程比較常見,並且一般不會被過多關註。所以需要進行的操作有:

  1. 文件名修改為 bash;
  2. 運行時將 argv[0] 修改成 /bin/bash;
  3. 為了防止從 /proc/進程號/maps 中發現沒有包含 /bin/bash,我們將 /bin/bash 文件 mmap 進我們的進程中。

{:.warning}
2中 Android 環境中不能直接拿到argv[0] 怎麼辦? 在 Unix 環境下,有定義全局變數 __progname_full, 該變數指向了 argv[0],可以直接使用 __progname_full 進行修改,當然在 Linux 下同樣適用。

代碼示例

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/mman.h>

extern const char *__progname_full; // 引入該變數

int main(int argc, char **argv)
{
	int pid = getpid();
	printf("current pid: %d\n", pid);
	char buffer[100] = {0};
	char cmdline[100] = {0};
	sprintf(cmdline, "cat /proc/%d/cmdline", pid);
	system(cmdline);
	printf("\n");
	scanf("%s", &buffer);
	printf("%d change the name: %s\n", getpid(), buffer);

	//int size = strlen(__progname_full);      // 使用 __progname_full 進行修改 cmdline
	//printf("name len: %d\n", size);
	//memset((char *)__progname_full, 0, size);
	//strcpy((char *)__progname_full, buffer);

	int size = strlen(argv[0]);   // 使用 argv[0] 進行修改 cmdline
	printf("name len: %d\n", size);
	memset((char *)argv[0], 0, size);
	strcpy((char *)argv[0], buffer);

	int fd = open(buffer, O_RDONLY);     // 打開偽造後的可執行文件, mmap 到我們進程中
	if (fd < 0) {
		printf("not found the file:%s\n", buffer);
		return -1;
	}
	struct stat st;
	fstat(fd, &st);
	void *addr = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0); // 可讀 map
	if (addr == MAP_FAILED) {
		printf("mmap failed\n");
	}
	void *addr1 = mmap(NULL, st.st_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); // 讀寫 map
	if (addr1 == MAP_FAILED) {
		printf("mmap1 failed\n");
	}
	void *addr2 = mmap(NULL, st.st_size, PROT_READ | PROT_EXEC, MAP_PRIVATE, fd, 0); // 讀可執行 map
	if (addr2 == MAP_FAILED) {
		printf("mmap2 failed\n");
	}
	system(cmdline);
	printf("\n");
	scanf("%s", &buffer);
	munmap(addr, st.st_size);
	munmap(addr1, st.st_size);
	munmap(addr2, st.st_size);
	close(fd);

	return 0;
}

執行結果

current pid: 301929  # 當前進程
/home/f/doing/linux/change_name/bash  # 偽造前 cmdline
/bin/bash # 要偽造的可執行文件
301929 change the name: /bin/bash
name len: 36
/bin/bash # 偽造後的 cmdline

工具查看結果

ps -aux 查看

top 查看

可以看到都已經是 bash。

技術對抗

上述隱藏方式可以騙過 ps 和 top 工具,但是只是修改了名字,但可執行文件等信息沒有改變,所以從其他信息可以推斷出是進程名是偽造的,下麵闡述幾種方式。

/proc/進程名/exe

在 /proc/進程名/exe 中保存的真正執行的可執行文件,所以可以將該文件和偽造後的 /bin/bash 文件對比,若發現不同可以證明進程名是偽造的,但此時還不能確認真正的可執行文件,只能和文件系統中的其他可執行文件對比進行確認。

/proc/進程名/maps

Linux 中記憶體的佈局是有一定的規律的,如下圖,地址從低到高,分別是ELF可執行文件、Data和Bss區域、HEAP、memory map區域、stack等。我們可以根據這些信息來確認真正的可執行文件。

來看下偽造進程的記憶體佈局:

從上面可以看出來,紅色框是ELF可執行文件、Data和Bss區域,其實就是進程的真正可執行文件,接著是 HEAP,後面是我們 mmap 偽造的 bash 文件,所以通過 /proc進程名/maps 可以確認出真正的可執行文件為 /home/f/doing/linux/change_name/bash。

小結

上面中 /proc/進程名/exe 能簡單判斷出進程名是否偽造,但不能確認真正的可執行文件,而通過 /proc/進程名/maps 可以非常直觀的看到可執行文件的信息。除了這兩種方式外,可能還有其他方法,比如 /proc/進程名/status 中 VmExe 欄位,該欄位是記錄 text 段大小,和顯示的可執行文件進行對比,確認是否有偽造。

總結

雖然原理上比較簡單,但是提醒我們有這麼一種方式,可以簡單的騙過我們通過ps和top看到的信息。若發現系統中有異常,也可以通過技術對抗中提到的方式,確認是否有惡意程式存在。

PS

關註公眾號,瞭解更多信息!


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 前言:新的的封裝類,增加了單元格映射深度更新和讀取的功能,預留了標題映射的深度更新介面待擴展。。。(以後有時間和精力再完善吧) 【深度更新】:我這裡定義的深度更新策略,指的是:假如我們需要讀取一組單元格的映射數據為一個對象,但是有不止一組這樣的單元格數據對象,且這些對象的單元格位置排列是有規律的! ...
  • 解決NET Core發佈iis項目覆蓋原有的項目時"另一個程式正在使用此文件,進程無法訪問" 現在net core運用的多了,一系列的問題接踵而來,更新項目發佈到iis時就有一個坑。 應急辦法是直接停站點進行發佈。 但是這樣做會導致,部署項目停的時間過長,網站暫時沒法訪問。(項目發佈完成後記得“啟動 ...
  • 1. 創建新項目-ASP.NET Core Web 應用程式 2. 3. 右鍵項目-管理 NuGet 程式包(N)... 4. 搜索 Pomelo.EntityFrameworkCore.MySql 安裝 5. 在appsettings.json文件添加 資料庫連接字元串 "AllowedHosts ...
  • 本文介紹通過C#程式代碼來添加OLE對象到PPT幻燈片的方法。這裡以將Excel文檔為對象插入到PPT幻燈片中的指定位置;添加時,將Excel中的單元格範圍保存為圖片,將圖片以嵌入的方式添加到幻燈片,添加成功後,可通過雙擊圖片來編輯、打開等動作對Excel源文檔進行操作。 使用工具:Free Spi ...
  • 1、在此次先進行定義 public static AOC aoc = null; aoc = this; 2、在窗體中寫入 Control.CheckForIllegalCrossThreadCalls = false; private void Form1_Load(object sender, ...
  • System.Net.Http.Json Json的序列化和反序列化是我們日常常見的操作,通過 System.Net.Http.Json 我們可以用少量的代碼實現上述操作.正如在github設計文檔中所描述 Serializing and deserializing JSON payloads fr ...
  • 在Linux上進行上傳下載時很容易就會用到壓縮和解壓操作,其中用的較多的算是tar命令了,其他命令也可以瞭解下。 gzip/gunzip命令gzip 文件:以.gz格式壓縮文件。壓縮完成後文件名預設是以.gz結尾的(但是註意Linux中是沒有尾碼名一說的)。gunzip 壓縮文件:解壓.gz格式的壓 ...
  • 轉載請註明原文地址: "程式員的 Ubuntu 19.10 配置與優化指南" 0x00 環境 CPU: Intel Core i9 9900k GPU: GeForce RTX 2070 SUPER RAM: DDR4 16GBx2 OS 1: Ubuntu 19.10 eoan OS 2: Win ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...