The importance of the FORMAT_MESSAGE_IGNORE_INSERTS flag - The Old New Thing (microsoft.com)https://devblogs.microsoft.com/oldnewthing/20071128-00/?p=24353
Raymond Chen?2007年11月28日
FORMAT_MESSAGE_IGNORE_INSERTS 標志的重要性
簡要
文章討論了使用
FormatMessage
函數獲取Win32錯誤代碼對應的錯誤消息時,必須使用FORMAT_MESSAGE_IGNORE_INSERTS
標志,以避免因消息中的插入序列導致的潛在錯誤和安全風險。
?
正文
????????你可以使用 FormatMessage
函數,并帶上 FORMAT_MESSAGE_FROM_SYSTEM
標志,以指明你傳遞的消息編號是一個錯誤代碼,并且消息應該在系統消息表中查找。這是一個更具體情況的特例,即你不能控制消息內容,而當你不能控制消息內容時,你最好傳遞 FORMAT_MESSAGE_IGNORE_INSERTS
標志。
????????讓我們看看如果你不這么做會發生什么。
#include <windows.h>
#include <stdio.h>
#include <tchar.h>
int __cdecl main(int argc, char **argv)
{TCHAR buffer[1024];DWORD dwError = ERROR_BAD_EXE_FORMAT;DWORD dwFlags = FORMAT_MESSAGE_FROM_SYSTEM;DWORD dwResult = FormatMessage(dwFlags, NULL, dwError,0, buffer, 1024, NULL);if (dwResult) {_tprintf(_T("Message is \"%s\"\n"), buffer);} else {_tprintf(_T("Failed! Error code %d\n"), GetLastError());}return 0;
}
????????如果你運行這個程序,你會得到:
Failed! Error code 87
?
????????錯誤 87 是 ERROR_INVALID_PARAMETER
(無效參數錯誤)。出了什么問題呢?
讓我們傳遞 FORMAT_MESSAGE_IGNORE_INSERTS
標志來看看消息是什么。
????????將 dwFlags
的值更改為:
DWORD dwFlags = FORMAT_MESSAGE_FROM_SYSTEM |FORMAT_MESSAGE_IGNORE_INSERTS;
????????再次運行程序。這次你會得到:
Message is "%1 is not a valid Win32 application."
?
????????啊哈,現在我們看到了問題所在。
????????對應 ERROR_BAD_EXE_FORMAT
的消息包含一個插入符 %1
。
????????如果你不傳遞 FORMAT_MESSAGE_IGNORE_INSERTS
標志,FormatMessage
函數將會在參數列表(或參數數組)中插入第一個參數。但我們沒有傳遞參數列表,所以函數失敗了。
????????實際上,我們很幸運。
????????如果我們傳遞了參數列表或參數數組,函數會插入相應的字符串,即使我們傳遞的參數列表中第一個位置沒有字符串。
????????如果你不能控制格式字符串,那么你必須傳遞 FORMAT_MESSAGE_IGNORE_INSERTS
來防止 %1
造成麻煩。
????????如果有人特別惡劣,他們可能會決定給你一個包含 %9
的格式字符串,這幾乎可以肯定是你提供的插入符數量的多倍。
????????結果是緩沖區溢出,很可能是崩潰。
????????這對一些人來說可能是顯而易見的,就像你不應該傳遞你不能控制的字符串作為 printf
函數的格式字符串一樣,但我覺得有必要提一下。
????????凌晨 2 點