이 난독 화 된 C 코드는 main ()없이 실행된다고 주장하지만 실제로 어떤 역할을합니까?
#include <stdio.h>
#define decode(s,t,u,m,p,e,d) m##s##u##t
#define begin decode(a,n,i,m,a,t,e)
int begin()
{
printf("Ha HA see how it is?? ");
}
이것은 간접적으로 호출 main
합니까? 어떻게?
C 언어는 독립형 및 호스트 형의 두 가지 범주로 실행 환경을 정의합니다 . 두 실행 환경 모두에서 프로그램 시작을 위해 환경에 의해 함수가 호출됩니다.
A의 자립 환경 프로그램 기동 기능 구현 중에 정의 될 수 호스팅 환경이 있어야한다 main
. 정의 된 환경에서 프로그램 시작 기능 없이는 C 프로그램을 실행할 수 없습니다.
귀하의 경우 main
에는 전 처리기 정의에 의해 숨겨져 있습니다. begin()
에 확장됩니다 decode(a,n,i,m,a,t,e)
더 확장 될 것이다 main
.
int begin() -> int decode(a,n,i,m,a,t,e)() -> int m##a##i##n() -> int main()
decode(s,t,u,m,p,e,d)
7 개의 매개 변수가있는 매개 변수화 된 매크로입니다. 이 매크로의 대체 목록은 m##s##u##t
입니다. m, s, u
및 t
(4)이다 일 , 1 일 , 3 번째 및 2 차 교체리스트에 사용되는 파라미터.
s, t, u, m, p, e, d
1 2 3 4 5 6 7
나머지는 쓸모가 없습니다 ( 단지 난독 화하기 위해 ). 에 전달 인자 decode
"이다 , N , I는 , m이 때문에, 식별자, A, t, E는" 과는 인수로 대체 하고 각각.m, s, u
t
m, a, i
n
m --> m
s --> a
u --> i
t --> n
을 사용해보십시오 gcc -E source.c
. 출력은 다음으로 끝납니다.
int main()
{
printf("Ha HA see how it is?? ");
}
따라서 main()
함수는 실제로 전처리기에 의해 생성됩니다.
문제의 프로그램은 수행 전화를 main()
인해 매크로 확장에, 그러나 당신의 가정은 결함이 - 그것은 하지 않습니다 호출 할 필요가 main()
전혀!
엄밀히 말하면 C 프로그램을 가지고 있고 main
심볼 없이 컴파일 할 수 있습니다 . 자체 초기화를 마친 후에서 점프 main
할 c library
것으로 예상되는 것입니다 . 일반적으로 main
libc 기호에서 _start
. main없이 어셈블리를 실행하는 매우 유효한 프로그램을 항상 가질 수 있습니다. 이것 좀보세요 :
/* This must be compiled with the flag -nostdlib because otherwise the
* linker will complain about multiple definitions of the symbol _start
* (one here and one in glibc) and a missing reference to symbol main
* (that the libc expects to be linked against).
*/
void
_start ()
{
/* calling the write system call, with the arguments in this order:
* 1. the stdout file descriptor
* 2. the buffer we want to print (Here it's just a string literal).
* 3. the amount of bytes we want to write.
*/
asm ("int $0x80"::"a"(4), "b"(1), "c"("Hello world!\n"), "d"(13));
asm ("int $0x80"::"a"(1), "b"(0)); /* calling exit syscall, with the argument to be 0 */
}
위를로 컴파일하고 인라인 어셈블리에서 시스템 호출 (인터럽트)을 실행하여 화면에 gcc -nostdlib without_main.c
인쇄 Hello World!
되는 것을 확인하십시오 .
For more information about this particular issue, check out the ksplice blog
Another interesting issue, is that you can also have a program that compiles without having the main
symbol correspond to a C function. For instance you can have the following as a very valid C program, that only makes the compiler whine when you up the Warnings level.
/* These values are extracted from the decimal representation of the instructions
* of a hello world program written in asm, that gdb provides.
*/
const int main[] = {
-443987883, 440, 113408, -1922629632,
4149, 899584, 84869120, 15544,
266023168, 1818576901, 1461743468, 1684828783,
-1017312735
};
The values in the array are bytes that correspond to the instructions needed to print Hello World on the screen. For a more detailed account of how this specific program works, take a look at this blog post, which is where I also read it first.
I want to make one final notice about these programs. I do not know if they register as valid C programs according to the C language specification, but compiling these and running them is certainly very possible, even if they violate the specification itself.
Someone is trying to act like Magician. He thinks he can trick us. But we all know, c program execution begins with main()
.
The int begin()
will be replaced with decode(a,n,i,m,a,t,e)
by one pass of preprocessor stage. Then again, decode(a,n,i,m,a,t,e)
will be replaced with m##a##i##n. As by positional association of macro call, s
will has a value of character a
. Likewise, u
will be replaced by 'i' and t
will be replaced by 'n'. And, that's how, m##s##u##t
will become main
Regarding, ##
symbol in macro expansion, it is the preprocessing operator and it performs token pasting. When a macro is expanded, the two tokens on either side of each ‘##’ operator are combined into a single token, which then replaces the ‘##’ and the two original tokens in the macro expansion.
If you don't believe me, you can compile your code with -E
flag. It will stop compilation process after preprocessing and you can see the result of token pasting.
gcc -E FILENAME.c
decode(a,b,c,d,[...])
shuffles the first four arguments and joins them to get a new identifier, in the order dacb
. (The remaining three arguments are ignored.) For instance, decode(a,n,i,m,[...])
gives the identifier main
. Note that this is what the begin
macro is defined as.
Therefore, the begin
macro is simply defined as main
.
In your example, main()
function is actually present, because begin
is a macro which the compiler replaces with decode
macro which in turn replaced by the expression m##s##u##t. Using macro expansion ##
, you will reach the word main
from decode
. This is a trace:
begin --> decode(a,n,i,m,a,t,e) --> m##parameter1##parameter3##parameter2 ---> main
It's just a trick to have main()
, but using the name main()
for the program's entry function is not necessary in C programming language. It depends on your operating systems and the linker as one of its tools.
In Windows, you don't always use main()
, but rather WinMain
or wWinMain
, although you can use main()
, even with Microsoft's toolchain. In Linux, one can use _start
.
It's up to the linker as an operating system tool to set the entry point, and not the language itself. You can even set our own entry point, and you can make a library that is also executable!
'programing tip' 카테고리의 다른 글
browserify 오류 / usr / bin / env : 노드 : 해당 파일 또는 디렉토리가 없습니다. (0) | 2020.09.15 |
---|---|
'python'은 내부 또는 외부 명령으로 인식되지 않습니다. (0) | 2020.09.15 |
Sqlite 파일 위치 핵심 데이터 (0) | 2020.09.15 |
a +++++ b가 작동하지 않는 이유는 무엇입니까? (0) | 2020.09.15 |
다른 html이없는 angularjs 개행 필터 (0) | 2020.09.15 |