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
  • 示例項目結構 在 Visual Studio 中創建一個 WinForms 應用程式後,項目結構如下所示: MyWinFormsApp/ │ ├───Properties/ │ └───Settings.settings │ ├───bin/ │ ├───Debug/ │ └───Release/ ...
  • [STAThread] 特性用於需要與 COM 組件交互的應用程式,尤其是依賴單線程模型(如 Windows Forms 應用程式)的組件。在 STA 模式下,線程擁有自己的消息迴圈,這對於處理用戶界面和某些 COM 組件是必要的。 [STAThread] static void Main(stri ...
  • 在WinForm中使用全局異常捕獲處理 在WinForm應用程式中,全局異常捕獲是確保程式穩定性的關鍵。通過在Program類的Main方法中設置全局異常處理,可以有效地捕獲並處理未預見的異常,從而避免程式崩潰。 註冊全局異常事件 [STAThread] static void Main() { / ...
  • 前言 給大家推薦一款開源的 Winform 控制項庫,可以幫助我們開發更加美觀、漂亮的 WinForm 界面。 項目介紹 SunnyUI.NET 是一個基於 .NET Framework 4.0+、.NET 6、.NET 7 和 .NET 8 的 WinForm 開源控制項庫,同時也提供了工具類庫、擴展 ...
  • 說明 該文章是屬於OverallAuth2.0系列文章,每周更新一篇該系列文章(從0到1完成系統開發)。 該系統文章,我會儘量說的非常詳細,做到不管新手、老手都能看懂。 說明:OverallAuth2.0 是一個簡單、易懂、功能強大的許可權+可視化流程管理系統。 有興趣的朋友,請關註我吧(*^▽^*) ...
  • 一、下載安裝 1.下載git 必須先下載並安裝git,再TortoiseGit下載安裝 git安裝參考教程:https://blog.csdn.net/mukes/article/details/115693833 2.TortoiseGit下載與安裝 TortoiseGit,Git客戶端,32/6 ...
  • 前言 在項目開發過程中,理解數據結構和演算法如同掌握蓋房子的秘訣。演算法不僅能幫助我們編寫高效、優質的代碼,還能解決項目中遇到的各種難題。 給大家推薦一個支持C#的開源免費、新手友好的數據結構與演算法入門教程:Hello演算法。 項目介紹 《Hello Algo》是一本開源免費、新手友好的數據結構與演算法入門 ...
  • 1.生成單個Proto.bat內容 @rem Copyright 2016, Google Inc. @rem All rights reserved. @rem @rem Redistribution and use in source and binary forms, with or with ...
  • 一:背景 1. 講故事 前段時間有位朋友找到我,說他的窗體程式在客戶這邊出現了卡死,讓我幫忙看下怎麼回事?dump也生成了,既然有dump了那就上 windbg 分析吧。 二:WinDbg 分析 1. 為什麼會卡死 窗體程式的卡死,入口門檻很低,後續往下分析就不一定了,不管怎麼說先用 !clrsta ...
  • 前言 人工智慧時代,人臉識別技術已成為安全驗證、身份識別和用戶交互的關鍵工具。 給大家推薦一款.NET 開源提供了強大的人臉識別 API,工具不僅易於集成,還具備高效處理能力。 本文將介紹一款如何利用這些API,為我們的項目添加智能識別的亮點。 項目介紹 GitHub 上擁有 1.2k 星標的 C# ...