绕过#define'd 宏?

Posted

技术标签:

【中文标题】绕过#define\'d 宏?【英文标题】:Bypassing a #define'd macro?绕过#define'd 宏? 【发布时间】:2014-09-12 17:05:24 【问题描述】:

假设你有宏

#define TOKEN1 <arbitrary sequence of characters>

但是假设,在某些情况下,您的真正意思是 TOKEN1,而不是它的定义。有没有一个技巧可以让预处理文件包含“TOKEN1”,而不用#undef'ining TOKEN1,并且在#define'd之后出现TOKEN1?

上下文:

我正在通过重新定义new 来添加内存跟踪。但是,我遇到了一个问题,我在几个类中也重载了operator new,并且不得不在所有这些地方取消定义 new ,然后重新包含具有魔力的标头是很尴尬的。

【问题讨论】:

没办法,在编译之前预处理器会盲目地替换文本,所以如果你不#undef它,你不能要求编译器忽略预处理器。 @vsoftco 没有办法编写一个评估为 TOKEN1 的宏,而预处理器不会评估它? 好吧,我猜你可以做#define TOKEN2 TOKEN1,然后当你写TOKEN1时,预处理器会用TOKEN2替换它,然后用TOKEN1替换它,此时它将停止替换... @T.C.:看起来你在我回答的同时发表了这条评论。请注意,只要 TOKEN2 尚未重新定义为其他内容,它就可以工作。 因此对于宏和实际语言标识符使用不同命名约定的通用编码约定。 【参考方案1】:

一般的方法是将所有需要“不替换 TOKEN1”的代码放入一个单独的源文件中,然后不将定义替换的头文件包含在该文件中。

如果任意字符序列是单个标记(就像在您编辑问题之前一样),您可以这样做:

#define TOKEN2 TOKEN1
if (you_really_mean(TOKEN1)) 
    //...

#undef TOKEN2

但是,这个解决方案是有限的,因为如果 TOKEN2 之前已经被重新定义为其他东西,你就会遇到问题。

如果您可以完全控制定义的内容和不定义的内容,您可以这样做:

#define TOKEN1 TOKEN2
#define TOKEN2 <arbitrary sequence formerly assigned to TOKEN1>

然后,在你的代码中转义TOKEN1

#undef TOKEN1
//... code where you don't want TOKEN1 replaced
#define TOKEN1 TOKEN2

对于您处理重载new 的特殊问题,我发现在很大程度上,重载new 实现大多相同(因为它们通常只是样板代码,将分配器更改为使用系统堆以外的东西)。如果您也是这种情况,您可以将重载定义放入无保护的头文件中。这个头文件可以#undef定义new然后重载定义后再重新定义。

那么任何类都可以包含这个头文件。

【讨论】:

另一种方法是要求项目使用除new 之外的某种机制来分配内存,并且该机制具有您的调试功能。然后您可以尝试禁用常规new 分配器的用户。见this question。【参考方案2】:

如果你可以访问语言扩展,a GCC/Clang extension 可以做这样的事情(我认为 MSVC 也有类似的):

#define TOKEN1 123
#pragma push_macro("TOKEN1")
#undef TOKEN1
TOKEN1     // inserts TOKEN1 into the program text
#pragma pop_macro("TOKEN1")
TOKEN1     // inserts 123 into the program source text

它允许您独立于输入文本保存和恢复宏定义,仅用于此目的。

不过,jxh 的解决方案更简洁;但从根本上说,您应该重新考虑尝试使单个术语具有多种含义的原因。宏语言应该帮助您抽象单个统一程序的元素;不要在一个文件中创建两个相互竞争的战斗源。

【讨论】:

【参考方案3】:

如果&lt;arbitrary sequence of characters&gt; 作为宏调用有效(它具有标识符或id( args ) 的形式),您可以通过添加“反向”宏暂时绕过定义。

#define TOKEN1 arbitrary_identifier

TOKEN1 // expands to arbitrary_identifier

...
// Now we really want to say TOKEN1

#define arbitrary_identifier TOKEN1

TOKEN1 // TOKEN1 => arbitrary_identifier => TOKEN1 and stop expanding

// Finished with TOKEN1 override

#undef arbitrary_identifier

TOKEN1 // expands to arbitrary_identifier again.

我认为对于真正任意的扩展标记序列不存在解决方法。而且,这种变通方法确实不比#undef TOKEN1 再做#define 好,因为绕过代码仍然需要知道扩展。

【讨论】:

【参考方案4】:

如果您有权更改 TOKEN1 的定义,您可以这样做:

#define TOKEN1() arbitrary stuff...

然后TOKEN1 后面没有( 不会进行扩展。即使有追随者(,您仍然可以通过写(TOKEN1) 来压制它。

【讨论】:

以上是关于绕过#define'd 宏?的主要内容,如果未能解决你的问题,请参考以下文章

如何绕过csrf保护,并在burp suite中使用intruder?

SQL注入进阶练习常见绕过手段防御的解决方案

sql注入 form过滤怎么绕过

如何使用SQLMap绕过WAF

如何使用SQLMap绕过WAF

刷里程碑 怎样绕过MD5验证