簡體   English   中英

一個程序中的兩個 shellcode 會導致段錯誤,如何將 shellcode 作為參數傳遞給函數?

[英]Two shellcodes in one program result in segfault, how can I pass shellcode as parameter to a function?

下面我有兩個與 C 編程和 shellcoding(匯編)相關的問題。

問題1:誰能回答為什么將兩個shellcode放在一個程序中不起作用? 我知道它與內存區域有關,但我需要知道確切的原因。 程序是使用帶有-zexecstack-fno-stack-protector選項的 gcc 編譯的。

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

main(int argc, char *argv[])
{

  unsigned char shellcode[] = "\x01\x02<SHELLCODE>";

  /* if the below line is uncommmented it will result in segault */ 
  /* unsigned char shellcode_[] = "\x01\x02<SHELLCODE>"; */

  int (*ret)() = (int(*)())shellcode;
  return 0;
}

那么如何將多個 shellcode 划分到不同的內存區域並調用它們而不中斷它們之間的執行流程,並決定調用哪一個呢? 我的意思是只存儲兩個 shellcode,而不是同時運行它們,如果可能的話)。

問題 2:如果必須將 shellcode 作為參數傳遞給函數,那么正確的方法是什么?

偽代碼:

unsigned char shellcode[]  = "\x01\x02...";

void call_shellcode(unsigned char shellcode[200]);
main()
{
   call_shellcode(shellcode);
}

void call_shellcode(unsigned char shellcode[200])
{
   ... print/call shellcode
}

更新:由於這個問題似乎存在一些誤解,這不是實際的 shellcode。 我確實知道 shellcode 是什么,它是如何生成的,以及它是如何工作的。 我沒有在 C 存根中提供實際的 shellcode 以使其處於可讀狀態。 值 "\x01\x01" 是一個偽代碼,指向問題的想法,而不是任何實際內容。

你的 shellcode 不能工作的原因很簡單:它以\x01\x02開頭:

unsigned char shellcode[] = "\x01\x02<SHELLCODE>";

我不確定為什么你認為你的 shellcode 必須以這兩個字節開頭:它真的沒有!

這兩個字節解碼以add DWORD PTR [rdx],eax (或edx ,如果在 32 位模式下運行)。 由於在調用 shellcode 時您無法控制 RDX/EDX 的值,因此很可能會立即導致分段錯誤,因為 RDX/EDX 不包含有效(和可寫)的內存地址。

從字面上更改 shellcode 周圍的任何內容,無論是在函數內部還是外部,都可能導致編譯器選擇不同的寄存器分配,這將導致 RDX/EDX 在運行時具有良好的值,不會導致崩潰,但這只是是一個幸運的巧合。 像這樣編寫和使用 shellcode 本質上是未定義的行為,或者至少是定義的實現(修復了操作系統和編譯器),因此必須格外小心。

那么如何將多個 shellcode 划分到不同的內存區域並調用它們而不中斷它們之間的執行流程,並決定調用哪一個呢?

好吧,您並沒有真正在“不同的內存區域”中划分任何東西……無論您使用一個數組還是兩個或十個數組,它們都在堆棧上聲明,並且它們在堆棧上將緊靠在一起。

如果你想從一個跳轉到另一個,這將是一項復雜的任務,因為通常你事先不知道變量在堆棧上的位置,所以你必須做一些數學計算你當前的位置,然后從一個 shellcode 塊到另一個的偏移量,最終執行相對調用/跳轉。

如果 shellcode 必須作為參數傳遞給函數,那么正確的方法是什么?

正確的方法是將mmap區域映射為 RWX,將 shellcode 寫入其中(memcpy、從標准輸入讀取等),然后將指向該內存區域的指針傳遞給您想要的函數。 您無法保證編譯器會將一段全局數據放入可執行內存區域。 事實上,沒有現代編譯器會這樣做,此外,即使 ELF 是使用-z execstack編譯的,也沒有現代內核會將這樣的區域映射為可執行文件。

在最近的內核中, -z execstack僅適用於堆棧本身,因此只有在堆棧上定義了變量時,才能通過變量將 shellcode 作為函數參數傳遞。

您不能在同一范圍內擁有兩個具有相同名稱的變量(這部分與變量是什么或它們的使用方式無關)。 只需給第二個 shellcode 一個不同的名稱。

請注意,我根本不會評論您正在嘗試做的事情,除了我不會將手動創建的機器代碼視為“shell代碼”(我通常會將其視為用於像 bash 這樣的命令 shell 的代碼)。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM