翻译《The Old New Thing》- The importance of the FORMAT_MESSAGE_IGNORE_INSERTS flag

The significance of the FORMAT_MESSAGE_IGNORE_INSERTS flag - ONT (microsoft.com)

The significance of the FORMAT_MESSAGE_IGNORE_INSERTS flag is a key topic discussed in this article. The Old New Thing (microsoft.com) explores its importance and implications in detail.
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;
}
cpp

如果你这个程序,你会得到:
> Failed! Error code 87
>
> ```
>
>
错误 87 是 `ERROR_INVALID_PARAMETER`(无效参数错误)。出了什么问题呢?
让我们传递 `FORMAT_MESSAGE_IGNORE_INSERTS` 标志来看看消息是什么。
将 `dwFlags` 的值更改为:
DWORD dwFlags = FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS;
cpp
再次程序。这次你会得到:
>
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 点
