我的第一个shell code -- hello world

尝试了好久,终于成功输出了hello world

实验环境

$uname -a
Linux archlinux 4.2.5-1-ARCH #1 SMP PREEMPT Tue Oct 27 08:13:28 CET 2015 x86_64 GNU/Linux

 $gcc --version
  gcc (GCC) 5.2.0
  Copyright (C) 2015 Free Software Foundation, Inc.
  This is free software; see the source for copying conditions. There is NO
  warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

核心代码

hello.s

 1 section     .text
 2 global      _start
 3
 4 _start:
 5
 6   jmp msg
 7
 8 code:
 9   xor rax, rax    ;clean up the registers
10   xor rbx, rbx
11   xor rdx, rdx
12   xor rcx, rcx
13
14   mov al, 4       ;syscall write
15   mov bl, 1       ;stdout is 1
16   pop rcx         ;save string address
17   mov dl, 12      ;length of the string
18   int 0x80
19
20   xor rax, rax
21   mov al, 1       ;exit the shellcode
22   xor rbx,rbx
23   int 0x80
24 msg:
25   call code
26   db ‘hello world‘, 10

这里有几个值得注意的地方:

1. 由于c语言中的字符串以‘\0‘为结尾,我们生成的shell code就不能包含00字节,所以能用al就绝不用ax or eax or rax,bl,dl同理。

2. 注意到代码里有个莫名奇妙的pop rcx没有?有没有发现代码的组织很奇怪?为什么要先jmp到msg在call code呢?事实上这也是为了去掉00字节。

call 指令会将返回的地址(这里就是第26行)push到栈上,之后再pop到rcx。

$nasm -f elf64 hello.s -o hello.o
$ld -s -o hello hello.o
$./hello
hello world
$objdump -d hello

hello: file format elf64-x86-64


Disassembly of section .text:


0000000000400080 <.text>:
400080: eb 1f            jmp 0x4000a1
400082: 48 31 c0          xor %rax,%rax
400085: 48 31 db          xor %rbx,%rbx
400088: 48 31 d2          xor %rdx,%rdx
40008b: 48 31 c9          xor %rcx,%rcx
40008e: b0 04            mov $0x4,%al
400090: b3 01          mov $0x1,%bl
400092: 59            pop %rcx
400093: b2 0c          mov $0xc,%dl
400095: cd 80          int $0x80
400097: 48 31 c0         xor %rax,%rax
40009a: b0 01          mov $0x1,%al
40009c: 48 31          db xor %rbx,%rbx
40009f: cd 80          int $0x80
4000a1: e8 dc ff ff ff    callq 0x400082
4000a6: 68 65 6c 6c 6f    pushq $0x6f6c6c65
4000ab: 20 77 6f        and %dh,0x6f(%rdi)
4000ae: 72 6c          jb 0x40011c
4000b0: 64 fs
4000b1: 0a            .byte 0xa

可以看到没有00字节

可以写个小程序从objdump的输出中得到shellcode

 1 #include <stdio.h>
 2 char code[] = "\xeb\x1f\x48\x31\xc0\x48\x31\xdb\x48\x31\xd2\x48\x31\xc9\xb0\x04\xb3" 3 "\x01\x59\xb2\x0b\xcd\x80\x48\x31\xc0\xb0\x01\x48\x31\xdb\xcd\x80\xe8" 4 "\xdc\xff\xff\xff\x68\x65\x6c\x6c\x6f\x20\x77\x6f\x72\x6c\x64";
 5
 6
 7 int main()
 8 {
 9 void (*hello)();
10 hello = (void (*)())code;
11 (*hello)();
12 return 0;}

编译选项很重要,现代编译器似乎有保护

$gcc -z execstack hello.c
$./a.out
hello world

大功告成。

时间: 2024-08-07 21:16:57

我的第一个shell code -- hello world的相关文章

Windows Shell Code编写中级拔高

标 题: Windows Shell Code编写中级拔高 时 间: 2013-05-28,23:59:54 一.基础知识&基本原理&一些思想方法 关于Windows Shell Code的文章论坛里的介绍也不少了,不过授之以鱼不如授之以渔,虽然有部分文章也做了大量讲解,但是几乎都是对照一份现成的代码来介绍为何那样写,为何这样写.所以如果Windows系统原理的知识相对薄弱的同学看起来还是云里雾里,也没弄懂,干脆把代码照抄走了,结果会遇到各种意想不到的异常,这篇文章叫中级拔高,而没有叫高级

[一] 编写第一个 Shell 脚本

什么是 Shell 脚本? 最简单的解释,一个 shell 脚本就是一个包含一系列命令的文件.shell 读取这个文件,然后执行 文件中的所有命令,就好像这些命令已经直接被输入到了命令行中一样. Shell 有些独特,因为它不仅是一个功能强大的命令行接口,也是一个脚本语言解释器.我们将会看到, 大多数能够在命令行中完成的任务也能够用脚本来实现,同样地,大多数能用脚本实现的操作也能够 在命令行中完成. 虽然我们已经介绍了许多 shell 功能,但只是集中于那些经常直接在命令行中使用的功能. She

第一个shell脚本——修改配置文件

有需求,可以让自己偷懒才是学习的真正动力.由于测试环境在构建代码之后总是需要手动修改配置文件,因此边学习边完成了一个shell脚本,可以一键修改. 定义了一个函数,输出信息以绿色字体显示. function echo_green { echo -e "\033[32m$1\033[0m" } 输出提示信息 echo_green "是否一键修改xxx?(y/n)" 读取键盘输入 read answer 要修改的配置文件有两类:一类是明确清楚应该修改哪些字符串,直接用替

shell脚本,通过一个shell程序计算n的阶乘。

[[email protected] ~]# cat jiechen.sh #!/bin/bash #设计一个shell程序计算n的阶乘,要求: #1.从命令行接收参数n; #2.在程序开始后立即判断n的合法性,即是否有参数,若有是否为正整数,若非法请给错误提示. #3.最后出计算的结果 num=$1 expr $num + 1 &>/dev/null [ $? -ne 0 ] && echo "please input a number." &&

shell脚本中执行另一个shell脚本

分类: 可以在一个shell脚本中执行另一个shell脚本(或非可执行文件,主要用于取得一些变量的值),方法是: . 文件名(包括路径) 或 变量=文件名(包括路径) . $变量 注意,圆点后面有个空格. 这样,在本shell脚本的后面部分就可以引用其他文件中声明的一些变量. 当再用这些变量去执行第3个脚本时,我不知是怎么回事,总是有些莫名其妙的错误,发现只有这个文件中不存在空行才行,哪怕只有一个注释符,都不会出错,就是不能有空行. 其实我想应该也不是这个问题,而是windows和linux处理

shell脚本,怎么实现每次新开一个shell都输出一个提示语?

[[email protected] wyb]# cat test.sh echo -e "\033[32mhello,This is wangyuebo's shell\033[0m" echo -e "\033[32m`date`\033[0m" LANG=en echo -e "\033[32m`date` login at `hostname` `w`\033[0m" >>/etc/wangyuebo.log [[email 

shell脚本,一个shell的启动流程。

#一个shell的启动流程 #shell有一些变量,叫做环境变量,这些变量是可以继承的, #比如父shell有$UID,子shell也可以有,而且继承父shell的. #正常我们声明一个变量,a=1,在子shell里,a是空,自己声明的变量不能被继续. 如果我们自己声明变量,想让子shell也可以用 [[email protected] wyb]# cat a.sh #!/bin/bash echo $a #如果我们自己声明变量,想让子shell也可以用,#export 是内置变量,通过它声明的

Linux shell脚本中调用另一个shell(exec、source、fork)

  在运行shell脚本时候,有三种方式来调用外部的脚本,exec(exec script.sh).source(source script.sh).fork(./script.sh) exec(exec /home/script.sh): 使用exec来调用脚本相当于在当前shell执行了一条命令,不会产生新的进程,被执行的脚本会继承当前shell的环境变量.但是当exec调用完毕后,当前shell也会结束,剩下的代码不会执行. source(source /home/script.sh) 使

手把手教你做一个Shell命令窗口

这是一个类似于win下面的cmd打开后的窗口,可以跨平台使用,可以在win和linux下面同时使用,主要功能如下: 首先我们需要把这些功能的目录写出来,通过写一个死循环,让其每次回车之后都可以保持同样的标题:如,/home/admin1>: <span style="white-space:pre"> </span>String userPath = System.getProperty("user.home"); <span s