freebsd下c语言编程,FreeBSD上编写x86 Shellcode初学者指南

介绍

本教程的目的是帮助你熟悉如何在FreeBSD操作系统上编写shellcode。虽然我会尽力在这里叙述所有有关的内容,但并不打算把本文写成汇编代码编程的入门读物。在反汇编中,你会注意到汇编代码采用AT&T语法,而我更喜欢使用Intel语法(无论是哪一种,nasm的工作原理是一样的)。如果你担心这些差异会带来困扰,请使用谷歌搜索并了解这些差异。请注意我只是一个编写shellcod的初学者,本文并不意味着是编写shellcode的全部内容;相反,本文对于全新的shellcoders来说是一个简单的介绍。换句话说,如果你以及编写过shellcode,本文的内容可能不会让你感兴趣。

其中的代码改编自The Shellcoders Handbook中的linux代码示例。

我引用的资源:

· Unix系统编程http://vip.cs.utsa.edu/usp/

· Shellcod编写参考手册http://www.wiley.com/WileyCDA/WileyAncillary/productCd-0764544683,typeCd-NOTE.html

· G. Adam Stanislav的FreeBSD汇编语言程序设计http://www.int80h.org/bsdasm/

所需工具:

· objdump

· NASM(Netwide Assembler)

· GCC

· GDB

在正式开始之前,让我们节省一些时间来获取/usr/src/sys/kern/syscalls.master的副本,这是系统调用及其相关编号的列表。将副本保存在编码目录中可以节省后续的时间,你需要在以root身份登录时打开文件并进行更改,否则可能会发生错误。让我们谨慎一点,复制一份副本。

既然我们已经完成了这一步,接下来我们继续深入,随着内容的深入,我会逐步解释更多的事情。我们要做的第一个shellcode是非常简单的,它用于exit()函数调用。我们首先在C代码中创建exit(),然后我们分析反汇编,以便我们可以将其重写为asm。先编译这个文件:

gcc -o myexit myexit.c

/* As easy as it gets */

#include

main()

{

exit(0); // exit with "0" for successful exit

}

现在我们已经编译了代码,我们希望使用gdb来查看函数内部。之后我们能够看到计算机自动生成了我们的代码对应的汇编代码。只需按照说明的步骤操作,就能得到下面的结果:

bash$ gdb myexit

(gdb) disas main

Dump of assembler code for function main:

0x80481d8

: push %ebp

0x80481d9 : mov %esp,%ebp

0x80481db : sub $0x8,%esp

0x80481de : add $0xfffffff4,%esp

0x80481e1 : push $0x0

0x80481e3 : call 0x80498dc

0x80481e8 : add $0x10,%esp

0x80481eb : nop

0x80481ec : leave

0x80481ed : ret

End of assembler dump.

让我们一行一行的来分析一下。不要担心任何事情,也不要担心内存地址,因为我的地址很可能和你的不一样。现在继续看看汇编代码,这是本文内容的第一个重要部分。传递给exit()函数的参数只有一个。接下来是退出了实际的调用。这是我们需要搞清楚的两件主要的事情。在我们进入代码之前,让我们检查syscalls.master来获取sysexit()的值,grep这个文件后,我们找到了这行:1 STD NOHIDE {void sys exit(int rval);exit sysexitargs void 。重要的信息是1,它是系统调用号的值和rval(返回值)参数。这表明sys_exit()接受一个参数,我们应该知道返回值是’0’代表这是一个成功的退出。

好的,将它放入汇编代码中。

section .text

global _start

_start:

xor eax, eax

push eax

push eax

mov eax, 1

int 80h

通过上面的代码,在我们进一步深入解释为什么代码会以这种方式有序的完成调用执行前,我会做个简短的说明。在FreeBSD(或NetBSD,OpenBSD)中,系统调用的参数是以相反的顺序被压入堆栈的,实际的系统调用号放入eax寄存器然后中断80 会调用内核来执行我们的代码。

现在继续, 'xor eax,eax’代码,如果eax有任何值的话,就会将eax清零。然后我们'push eax’两次。(我不知道是什么技术原因导致的,但如果零被push堆栈一次,退出调用将返回1,我们不希望这样的返回值,只需将零push两次就行。)现在我们加载eax 调用exit的系统调用值为1.最后我们要做的是用'int 80h’来实际调用内核。

不错!现在我们已经编写了了一些东西了,我们可以从中获得shellcode!我们需要组装然后链接这个文件。

bash$ nasm -f elf myexit.asm

bash$ ld -s -o myexit myexit.o

现在它已经组装和链接好了,让我们使用objdump来获取shellcode。

bash$ objdump -d myexit

shortexit: file format elf32-i386

/usr/libexec/elf/objdump: shortexit: no symbols

Disassembly of section .text:

08048080 :

8048080: 31 c0 xor %eax,%eax

8048082: 50 push %eax

8048083: 50 push %eax

8048084: b8 01 00 00 00 mov $0x1,%eax

8048089: cd 80 int $0x80

这段代码对某些人来说可能已经很好了,但它对我们来说很糟糕。看看代码中的那些NULL(00),我们不能直接使用这段代码,因为当我们尝试在我们之前编写的C程序中执行代码时就会发生中断。在C语言和其他编程语言中,NULL会终止一个字符串。这意味着如果我们尝试将其加载到C语言数组中,程序就会崩溃。所以我们不能那样做。也许有其他的方法可以处理这段asm代码,我想出的办法如下:

Section .text

global _start

_start:

xor eax, eax

push eax

push eax

inc eax

int 80h

这里唯一不同的是'inc eax’,让eax 增加1(记住eax是从零开始的,我们需要返回1(退出系统调用的返回值)),所以在这种情况下它与’mov eax,1'是等价的。

再次,如上一个示例所示组装并链接它,然后使用objdump。

bash$ objdump -d myexit

/usr/libexec/elf/objdump: exit_shellcode: no symbols

Disassembly of section .text:

08048080 :

8048080: 31 c0 xor %eax,%eax

8048082: 50 push %eax

8048083: 50 push %eax

8048084: 40 inc %eax

8048085: cd 80 int $0x80

现在看一下!没有NULL了,这段代码就是很好的shellcode,我们保存一下!那么现在我们有了正确的,没有NULL值的shellcode,现在是时候将它加载到C程序中来执行了。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值