• 各种小巧的Hello World


    在Reddit看到这篇文章:Hello from a libc-free world! ,觉得挺有趣,然后又想起以前看过的各种相关资料,在此做一个整理。注意所有实验环境都为Linux。

    版本一:

    实际上是用汇编重写_start入口,具体说明请看文章开头提供的连接,汇编代码如下,命名为stubstart.S

    [cpp] view plaincopy
     
    1. _start:  
    2.     call main  
    3.     movl $1, %eax  
    4.     xorl %ebx, %ebx  
    5.     int $0x80  
    然后与普通hello.c连接(hello.c)的代码我就不用写出来了吧。。命令如下:
    gcc -nostdlib stubstart.S -o hello hello.c
    OK,一个不需要libc的helloworld程序就完成了。只是简单的跳过了_start的各种初始化

    版本二:

    与版本一其实差不多,只是用shellcode来完成了,代码如下
    [cpp] view plaincopy
     
    1. typedef int (*sc_fun)(int,int,int,int,int,int,int);  
    2.   
    3. void _start(void) {  
    4.   
    5.     char syscall[] = "/x60/x83/xc4/x24/x58/x5b/x59/x5a/x5e/x5f/x5d/xcd/x80/x83/xec/x40/x61/xc3";  
    6.   
    7.     ((sc_fun)syscall)(4, 0, "Hello, World/n", 13, 0, 0, 0);  
    8.   
    9.     ((sc_fun)syscall)(1, 0, 0, 0, 0, 0, 0);  
    10.   
    11. }  



    连接命令如下:
    gcc -o nostdlib hello.c -m32 -z execstack –nostdlib
    嗯,完成了,也是-nostdlib,至于shellcode调用的是什么系统函数,我猜是write吧:)

    版本三:

    [cpp] view plaincopy
     
    1. char *str = "Hello world!/n";  
    2. void print()  
    3. {  
    4.     asm( "movl $13, %%edx /n/t"  
    5.         "movl %0, %%ecx /n/t"  
    6.         "movl $0, %%ebx /n/t"  
    7.         "movl $4, %%eax /n/t"  
    8.         "int $0x80 /n/t"  
    9.         :: "r"(str):"edx","ecx","ebx");  
    10. }  
    11. void exit()  
    12. {  
    13.     asm( "movl $42,%ebx /n/t"  
    14.          "movl $1,%eax /n/t"  
    15.          "int $0x80 /n/t");  
    16. }  
    17. void nomain()  
    18. {  
    19.     print();  
    20.     exit();  
    21. }  

    关于gcc内联汇编,可参考下相关书籍,代码大概意思是nomain()是入口,然后调用print()函数,打印"Hello world”,接着调用exit()函数,结束进程。这里的print函数使用了Linux的WRITE系统调用,exit使用了EXIT系统调用,都是用内联汇编实现。

    连接命令如下:

    gcc –c hello.c

    ld –static –e nomain –o hello hello.o

    注意,这里控制了连接器的行为,用-e指定了入口函数为nomain

    版本四:

    接着版本三,我们用objdump来查看hello,会发现他有四个段:.text .rodata .data .comment。

    那么可不可以把他们都合并到一个段里面,该段的属性是可执行,可读的,包含程序的数据和指令? 可以的,此时需要使用ld连接脚本创建脚本hello.lds如下:

    [c-sharp] view plaincopy
     
    1. ENTRY(nomain)  
    2. SECTIONS  
    3. {  
    4.     . = 0x804800 + SIZEOF_HEADERS;  
    5.     tinytext : { *(.text) *(.data) *(.rodata) }  
    6.     /DISCARD/ : { *(.comment) }  
    7. }  

    这是很简单的连接脚本,就是设置当前位置0x804800 + SIZEOF_HEADERS,后面紧跟着tinytext段,没有其他段了。使用入下命令连接

    gcc –c  hello.c

    ld –static – T hello.lds –o hello hello.o

    OK,一个更小巧的HelloWorld完成了。

    版本五:

    版本四是最小的了吗?差远了。。。早就有人专门研究过最小的可执行文件了,从ELF文件的各个字节下手。。点这里:Size Is Everything 。。很牛B,很geek的东西。。理论上那就是最小的可执行文件了。

    以上各个版本的helloworld大小,自己生成后用wc –c hello看吧:)。再配合objdump能学到更多~

  • 相关阅读:
    linux 下查看网速的方法 (不需要安装任何软件)
    Raspberry Pi Kernel Compilation 内核编译官方文档
    Kernel compiling for Pi 2
    从源码编译rpi的内核
    设备驱动调试和移植的一般方法
    爸爸的歌
    表扬?批评?
    日历插件js,jquery
    zepto jquery和zepto的区别?
    怎么学习PS快?
  • 原文地址:https://www.cnblogs.com/SZLLQ2000/p/5102228.html
Copyright © 2020-2023  润新知