#include "stdio.h"
void print()
{
*
}
void main()
{
}
在*号处加一段代码,显示出"hello,world".
1)用defiene方法:
#include “stdio.h”
void print()
{
#define main main(){printf(“Hello World!\n”);} void empty
}
void main()
{
}
这是真正经典且正确的解法。这个宏构造的十分经典。void main(){}展开则为:
void main(){printf(“Hello World!\n”);} void empty{}
2)再一个正确解法:利用全局或静态变量在main函数运行前初始化。此时调用全局变量的构造函数才输出hell world!
#include "stdio.h"
void print()
{
}
class cls{
public:
cls(){
printf("hello world\n") ;
}
} ;
cls mycls ;
void fun(){
}
void main()
{
}
3)精简的答案:(在vc6下可以正常运行,vs2008就不行了,这里毕竟没有仿造编译器来构造程序:没有用CRT启动函数来做初始化工作,并调用我们的main函数,之后清理资源)
#include <stdio.h>
void print()
{
#pragma comment(linker, "/entry:print")
#pragma comment(lib, "msvcrt.lib")
printf("hello world");
}
void main()
{
}
4)在3)的基础上更改,不过依然通不过vs2008.通过vc6还是没有问题:
#include "stdio.h"
void print()
{
#pragma comment(linker, "/entry:print")
#pragma comment(linker, "/SECTION:.text,REW" )
int mainCRTStartup();
void main();
__asm
{
MOV EAX, OFFSET main
MOV BYTE PTR[EAX], 0xB8 //MOV EAX, 0x
MOV DWORD PTR[EAX+1], OFFSET SHOWSTRING
MOV WORD PTR[EAX+5], 0xE0FF // JMP EAX
}
mainCRTStartup();//这里面直接调用了exit函数退出线程。不会顺序执行下面的程序。只是由上面的代码会转向下面。运行完下面代码就不会返回到SHOWSTRING了。
SHOWSTRING:
printf ("hello world!\n");
__asm
{
mov eax,1;//这里是设置main函数返回值,让其正常返回
ret
}
}
void main()
{
}
衷心希望网上各位高手,能完善第四个,vs2008增加了一些检验代码。要保证堆栈平衡,还是要花费一点心思的。
5)再来一个正确代码,不同的跳转构造方式,但是却没有错误
#include<stdio.h>
extern "C" int __cdecl mainCRTStartup(void);
void print()
{
#pragma comment(linker, "/entry:print")
#pragma comment(linker, "/SECTION:.text,ERW")
#pragma comment(lib, "msvcrt.lib")
int mainCRTStartup();
void main();
__asm
{
MOV EAX, OFFSET main
MOV BYTE PTR[EAX], 0xE9 //构造jmp 相对地址 指令并放在main函数处
MOV ecx,OFFSET SHOWSTRING;
sub ecx, offset main;
sub ecx,5
MOV DWORD PTR[EAX+1], ecx //将printf语句地址放在eax+1处
}
mainCRTStartup();
__asm
{
ret
}
SHOWSTRING:
printf("hello,world!\n");
__asm
{
ret
}
}
void main()
{
}
以下是分析过程,分析出了两种jmp指令构造的不同
本人原文:http://hi.baidu.com/hanjdud8606/item/42ef8127c9a1479db732632f