Che*_*uid 8 c obfuscation deobfuscation
这段引人入胜的代码出现在第一届(1984 年)国际混淆 C 代码竞赛中:
http://www.ioccc.org/years.html#1984 (decot)
在清除了由 goto 和一些偷偷摸摸的注释引起的预处理器滥用和未使用代码的碎片后,您最终得到以下幸存代码(如果我错了,请纠正我!):
#include <stdio.h> //used to suppress warnings
#include <math.h> //used to suppress warnings
extern int fl00r; //renamed to not clash with floor from math.h - unless it's part of the trickery???
int b, k['a'] = {
sizeof(int(*)()),
};
struct tag {int x0,*xO;}
*main(int i, int dup, int signal) { //int added to suppress warnings
for(signal=0;*k *= * __FILE__ *i;) {
printf(&*"'\",=); /*\n\\", (*((int(*)())&fl00r))(i)); //see line 3
if(b&&k+sin(signal)/ * ((main) (b)-> xO));
}
}
Run Code Online (Sandbox Code Playgroud)
有一个编译器错误需要克服:
decot.c: In function 'main':
decot.c:12:28: error: too few arguments to function 'main'
12 | if(b&&k+sin(signal)/ * ((main) (b)-> xO));
| ^
decot.c:9:2: note: declared here
9 | *main(int i, int dup, int signal) {
| ^~~~
Run Code Online (Sandbox Code Playgroud)
我怀疑当时编译器的工作方式意味着您可以以某种方式只用 1 个参数调用 main,即使它在这种情况下是用 3 专门定义的。
这是准确的吗?我错过了什么吗?如今,使此代码能够编译所需的最少更改是什么?
我使用 GCC 9.2.0 和 Makefile 中建议的构建命令。
如果我错过了一些非常明显的内容,请提前致谢并道歉!
您无法再按原样编译原始代码。GCC声称支持的最早的C标准是C89,本次比赛的代码是在此之前的。您已经在将其移植到更现代的编译器方面做得很好。但剩下的问题不仅仅是 的参数数量main():
sin()返回 a double(即使您不知道#include <math.h>),并且拒绝将 a 添加double到子int *表达式中的 an 中k+sin(signal)。不过, TCC似乎接受了这一点。fl00r已声明但未定义,链接器将抱怨对它的未定义引用。请注意,原始代码可以通过 TCC 进行编译,只需避免使用诸如(预处理器现在仅替换完整标记,并算作一个标记)x之类的组合,并使用三个参数进行调用即可。<<x<<xmain()
您的代码版本可以通过删除#include语句、返回到 using来由 GCC 编译floor(),但向前声明如下:
floor();
Run Code Online (Sandbox Code Playgroud)
为了避免抱怨sin(),请使用-fno-builtin编译器标志。main()然后通过像这样调用它来解决问题(main) (b,b,b)。
tl;博士; 你的错误是给main函数一个 ANSI C 原型(即更改i为int i等),它指示编译器检查它被调用的参数并导致该too few arguments错误。
例子:
echo 'int foo(a,b){return a+b;} int main(){return foo(3);}' |
cc -Wall -std=c89 -xc -
# K&R C function OK, no errors
echo 'int foo(int a, int b){return a+b;} int main(){return foo(3);}' |
cc -Wall -std=c89 -xc -
...
<stdin>:1:54: error: too few arguments to function ‘foo’
Run Code Online (Sandbox Code Playgroud)
该代码应该使用传统的C 预处理器进行预处理,而不是使用“ANSI C”预处理器。使用标准预处理器会导致一些工件,例如<< =代替<<=、* =代替*=等。
cpp -traditional-cpp -P decot.c > decot1.c
Run Code Online (Sandbox Code Playgroud)
添加正确的函数声明并添加强制转换后——请参阅本答案末尾的差异和结果——您会得到一些在 c89 中编译时带有单个警告的内容(以及在 c99 中的几个警告),并且,如所述, 将一些垃圾打印到标准输出:
$ cc -std=c89 decot1.c -lm -o decot1
decot1.c: In function ‘main’:
decot1.c:13:33: warning: function called through a non-compatible type
(printf(&*"'\",x); /*\n\\", (*((int(*)())&floor))(i)));
~^~~~~~~~~~~~~~~~~~~~
$ ./decot1
'",x); /*
\
Run Code Online (Sandbox Code Playgroud)
这与我在 V7 Unix 上编译和运行原始版本时得到的完全相同,所以它应该是正确的 ;-)
double floor(double);
double sin(double);
int printf(const char*, ...);
int b,
k['a'] = {sizeof(
int(*)())
,};
struct tag{int x0,*xO;}
*main(i, dup, signal) {
{
for(signal=0;*k *= * "decot.c" *i;) do {
(printf(&*"'\",x); /*\n\\", (*((int(*)())&floor))(i)));
goto _0;
_O: while (!(k['a'] <<= - dup)) {
static struct tag u ={4};
}
}
while(b = 3, i); {
k['a'] = b,i;
_0:if(b&&k+
(int)(sin(signal) / * ((main) (b)-> xO)));}}}
Run Code Online (Sandbox Code Playgroud)
$ diff -u decot1.c~ decot1.c
--- decot1.c~
+++ decot1.c
@@ -1,4 +1,6 @@
-extern int floor;
+double floor(double);
+double sin(double);
+int printf(const char*, ...);
int b,
k['a'] = {sizeof(
int(*)())
@@ -20,4 +22,4 @@
while(b = 3, i); {
k['a'] = b,i;
_0:if(b&&k+
- sin(signal) / * ((main) (b)-> xO));}}}
+ (int)(sin(signal) / * ((main) (b)-> xO)));}}}
Run Code Online (Sandbox Code Playgroud)