Turn from: http://blog.csdn.net/masefee/article/details/6606813
Hey, haven't written a blog for months, too tight time, energy and limited. Today is the time to write a question that was discussed online today.
I think we all have heard of the International C Language Chaos Code Contest (IOCCC, the International obfuscated C code Contest), and today I have no intention of discussing it online. I intentionally changed the main function and actually compiled it, so I wanted to use this feature to write a "weird" code. (after writing to find that, IOCCC incredibly also has a similar competition award-winning works, tragedy, early know I also went to the competition ... )
Let's get to the point where the code is like this: View plain #include <stdio.h> int main[] = {232,-1065134080,5138447,285147200,50008, (int) printf};
The two code copy into the XXX.C, with VC compile, can pass, and execute, the output result is:
This program cannot is run in DOS mode.
$
Or another way of writing: View plain #include <stdio.h> int ___ = (int) printf; int main[] = {232,-394045440,5138441,285147200,50008};
The output is consistent.
So, why are these two weird pieces of code going to compile and run? Can be summed up to two questions:
1. Why it can be done by compiling.
2. Why can I output such a string. It's no use to see call printf, much less to see the string.
One of us solves, for the first question:
First, both pieces of code must be compiled using the. c file, which cannot be compiled under the. cpp file, which means that the C compiler must be compiled and the C + + compiler cannot pass.
Second, because it is the C compiler and the Visual Studio environment, the check for the number of functions, types, and so on is not very strict, for the entry function main, the compiler is looking for the main function symbol and link, will not be strictly checked. Therefore, in this place the main function in the form of an array can also be smoothly linked. GCC also can be compiled smoothly, just to change the code to run successfully, this article is no longer tired, this is not the focus.
By this, the first question will be solved. So the second question is a lot more complicated, and we'll step through it.
First, the main array is linked to the main function, then the integer inside the main array (int,4 byte) is the code byte (machine code) that the main function executes, which is somewhat similar to the shellcode principle. As for what is machine code, here is no explanation, you can find the answer in my previous blog or on the Internet. Since the machine code, then these integers must represent the specific execution logic, because it is the machine code directly written (integer), we can only look at the disassembly code, we take the first example as an example:
00492000 E8 call _main+5 (492005h)
00492005 pop eax
00492006 C0 0F Add eax,0fh
00492009 4E Push 40004Eh
0049200E FF call DWORD ptr [EAX]
00492010 pop eax
00492011 C3 RET
00492012 add byte ptr [eax],al
00492014 E0 B0 Loopne 00491fc6
00492016/INC EdX
00492017 E0 Add Al,ah
Looking at the memory of the main array:
0x00492000 E8 C0 0f c3 e0 B0 (?....), at 4e a m. X??. hn.@ ... X?..?? B.
0x00492018 E0 b0 —————————————————————————------?? B.............. Hi.....
The horizontal bar for omitting part of the memory, you can find that the first row of 24 bytes (6 int) is exactly the 6 integers in the main array, the last 4 bytes is the first address of the printf function: 0x0042b0e0 (usually different under your platform). So let's look at the disassembly code above, the previous machine code is also 24 bytes in memory, let's analyze the disassembly code:
First two sentences red assembly code:
Call 0x00492005
Pop eax
The functions of these two sentences are mainly to obtain the value of EIP registers, when the completion of the pop EAX this code, the EAX value of 0x00492005, so that the EIP to obtain the address.
As for the two code why can obtain EIP address in the previous Bovenri also have related explanations, we know that the call command understanding is divided into two steps, one is the call command the next instruction code address pressure stack, the second is to jump.
The next code for the call command here is the pop eax, whose code address is 0x00492005. The call command jumps to the pop eax after pressing the address value into the stack. At the moment, pop eax will just press the code address (0x00492005) popped into the eax, so that eax get the pop eax code address. Why so troublesome, because the introverted assembly does not support MOV Eax,eip such operations, so the use of call characteristics to obtain EIP.
So why get this address, the purpose is to get the location of the address of the back printf function (that is, the offset from the first address of the main array, the memory address of the last int in the main array), which is 0x00492014. This address is the previously obtained EIP value 0x00492005 + 0x0f. Therefore, the above green sentence assembly code add eax, 0fh no longer explain it, add, after the EAX value is 0x00492014.
Here, the location of the address value of the printf function is also known, and it is time to consider how to invoke the string of characters in the front of printf output. At first glance, this string of characters seems familiar, right. Indeed very familiar, this string of characters is the PE file in the head of the information, EXE file has such a message, then we go to where to find this string of characters memory address and then passed to printf.
Usually when debugging the program should be able to notice that the EXE often default will be from 0x00400000 this memory address to start loading, of course, sometimes not this address began, for example, in Win7 and Vista, if the compiler opened the random base Address option, then each time the EXE runs, A random base site is loaded, which is not necessarily loaded from the memory address of 0x00400000. This article is only for the analysis of the situation from the 0x00400000 this address loading.
Okay, let's take a look at the memory 0x00400000 this memory address:
0x00400000 a B8 of the 4d for the MZ of all the other "FF" $?.............? .......
40 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 @ ...... .......
0x00400030 0e 1f BA 0e b4 cd ...?????????????????. .....?..?.?
0X00400048 B8 4c CD-A/6f to be, 6d, 6e, 6e 6f