輕鬆審計代碼安全性,Windows 10有妙招

若是你是軟件開發人員,又但願本身開發的軟件安全性高一點,那麼當前的Windows 10企業內部預覽版(10.0.16253)中就有一個功能能夠作到。html

它的位置在「設置 – > Windows Defender – > Windows Defender安全中心 – >應用程序和瀏覽器控制 – >漏洞保護設置」中,你能夠爲整個系統或特定程序啓用自定義漏洞利用設置。其中有不少不一樣的保護特性而且許多均可以在審計模式下打開。在審計模式下,它不是在出現狀況時終止進程,而是將事件寫入事件日誌。對於管理員,這就意味着其會容許軟件繼續運行,同時可以使咱們意識到這一狀況是什麼時候發生的。對於但願經過了解這些狀況以此來改進產品的人來講,它實際上是提供了一個啓用安全功能的附加好處,即無需從新編譯(在某些狀況下),就能告訴你確切的程序代碼在當它在運行時遇到問題的位置。在版本10.0.16253中,能夠進行審計的保護特性包括:瀏覽器

任意代碼保護 - 防止非圖像支持的執行代碼和代碼頁修改(例如VirtualAlloc / VirtualProtect建立/修改的代碼)
阻止低完整性圖像
阻止遠程圖像
阻止不受信任的字體
代碼完整性守護者
禁用Win32k系統調用
不容許子進程
導出地址過濾 - 將功能修補到另外一個功能的一個常見方法中的一個步驟
導入地址過濾 - 將功能修補到另外一個功能的一個常見方法中的一個步驟
模擬執行
驗證API調用(CallerCheck)
驗證圖像依賴完整性
驗證堆棧完整性

要充分利用此功能,咱們須要安裝Windows Performance Toolkit。它是Windows SDK安裝程序的安裝選項之一。當您啓用了您感興趣的設置後,打開管理命令提示符並瀏覽到Windows Performance Toolkit目錄(一般爲Program Files(x86) Windows Kits {Version} Windows Performance Toolkit)。您能夠經過運行如下兩個命令(在替換文件名所需的任何路徑以後)啓動並開始收集上述漏洞保護設置的跟蹤以及解析堆棧跟蹤所需的數據:安全

xperf - 「PROC_THREAD + LOADER」-f「wdeg_klogger.etl」

xperf -start「WDEG」 - 「Microsoft-Windows-Security-Mitigations:0xFFFFFFFFFFFFFF:0xFF:'stack'」-f「wdeg_unmerged.etl」

在您運行任何想要收集的方案以後,您能夠中止跟蹤並將數據與如下內容合併(再次替換文件名所需的任何路徑):服務器

xperf -stop -stop「WDEG」-d「wdeg_merged.etl」

而後,您能夠刪除建立的前兩個文件,由於此時您將擁有第三個所需的全部數據。您能夠在Windows Performance Analyzer(WPA)中打開生成的etl文件,並查看數據。ide

您可使用wpaPreset文件擴展名保存它,在WPA中加載數據,轉到個人預設(在WPA的較新版本中的文件 – >窗口 – >個人存在),選擇導入,瀏覽到保存預設的任何地方,選擇它,並雙擊它以顯示視圖。另外,您還須要加載符號,以充分利用這一點。您能夠在WPA中在File-> Configure Symbols下設置符號; 您須要將其指向msdl.microsoft.com/download/symbols上的Microsoft符號服務器以及您的符號服務器(或您沒有符號服務器設置的符號文件的位置)。您能夠在加載跟蹤時自動配置WPA加載符號,但也能夠經過轉到文件 – >加載符號來手動加載符號。一旦完成,您將可以輕鬆地查看堆棧跟蹤。它就會像下面這樣:oop

如下是在建立上述過程當中我爲x64控制檯應用程序編譯的示例代碼:字體

#include #include using namespace std;void* CreateCodeInVirtualMemory(BOOL writable)
{ BYTE code[3] = { 0x33, 0xc0, 0xc3 }; LPVOID result = VirtualAlloc(NULL, sizeof(code), MEM_COMMIT | MEM_RESERVE, writable ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE); if (result)
{
  memcpy(result, code, sizeof(code));
} else cout << "VirtualAllocEx failed with error " << GetLastError() << endl; return result;
}void CreateCodeInVirtualMemoryAndExecute(BOOL useWritableMemory)
{ LPTHREAD_START_ROUTINE addr = (LPTHREAD_START_ROUTINE)CreateCodeInVirtualMemory(useWritableMemory); if (addr)
{  DWORD result = addr(NULL);
  cout << "Code at 0x" << hex << (void*)addr << " returned " << result << endl;
} else cout << "NULL address was not executed" << endl;
}void ExecuteIllegalMemory()
{
CreateCodeInVirtualMemoryAndExecute(FALSE);
} 
void PrintOptions()
{
cout << "Enter one of the following options:" << endl;
cout << "1 - Execute Memory Not Marked As Executable" << endl;
cout << "2 - Create Code in Virtual Memory" << endl;
cout << "3 - Create Code in Virtual Memory and Execute" << endl;
cout << "0 - Exit" << endl;

}void DecisionLoop()
{ while (true)
{  int selection;
  PrintOptions();
  cin >> selection;  switch (selection)
  {   case 0:    return;   case 1:
ExecuteIllegalMemory();    break;   case 2:
CreateCodeInVirtualMemory(TRUE);    break;   case 3:
CreateCodeInVirtualMemoryAndExecute(TRUE);    break;   default:
cout << "Invalid input" << endl;
  }
}
}int main()
{
DecisionLoop(); return 0;
}

在這裏我沒有去對它的應用作更多的介紹,但我相信個人拋磚引玉必定可以讓更多的人對這一功能產生興趣。
對於在事件查看器中的應用程序和服務日誌中找到的大多數內容,您也能夠以相同的方式完成此類操做——單擊特定日誌的屬性,它將具備Provider-Name-Parts / LogName形式的名稱。您只須要在xperf命令中使用「Provider-Name-Parts」部分便可。spa

相關文章
相關標籤/搜索