-4

我想溢出数组buffer[100],我将在 FreeBSD 上的 bash shell 上传递 python 脚本。我需要机器代码作为字符串传递以溢出该缓冲区buffer[100]并使程序将其主机名打印到stdout.

这是我尝试过的 C 代码,并在控制台上给出了主机名。:

#include <stdio.h>
int main()
{
   char buff[256];
   gethostname(buff, sizeof(buff));
   printf(""%s", buff);

  return 0;

}


这是我使用 gcc 获得的汇编代码,但比我需要的要长,因为当我查找 c 程序文本部分的机器代码时,它超过 100 个字节,我需要上面 c 程序的机器代码小于 100 字节。


     .type   main, @function
main:
pushl %ebp; saving the base pointer
    movl %esp, %ebp; Taking a snapshot of the stack pointer
subl $264, %esp; 
addl $-8, %esp
pushl $256
leal -256(%ebp), %eax
pushl %eax
call gethostname
addl $16, %esp
addl $-8, %esp
leal -256(%ebp), %eax
pushl %eax
pushl $.LCO
call printf
addl $16, %esp
xorl %eax, %eax
jmp .L6
.p2align 2, 0x90
.L6:
leave
ret
.Lfe1:
.size   main, .Lfe1-main
.ident "GCC: (GNU) c 2.95.4 20020320 [FreeBSD]"

一个人已经在另一台计算机上完成了它,他给了我现成的机器代码,它是 37 字节,他正在使用 perl 脚本以下面的格式将它传递到缓冲区。我尝试了他的代码并且它有效,但他没有告诉我该怎么做。

“\x41\xc1\x30\x58\x6e\x61\x6d\x65\x23\x23\xc3\xbc\xa3\x83\xf4\x69\x36\xw3\xde\x4f\x2f\x5f\x2f\x39\ x33\x60\x24\x32\xb4\xab\x21\xc1\x80\x24\xe0\xdb\xd0”</p>

我知道他是在不同的机器上做的,所以我不能得到相同的代码,但由于我们都使用完全相同的 c 函数,所以机器代码的大小应该几乎相同,如果不完全相同的话。他的机器代码是 37 个字节,他将传递给 shell 以溢出 FreeBSD 2.95 上二进制文件中的 gets() 函数,从而在标准输出上打印主机名。我想做同样的事情,我已经尝试过他的机器代码并且它可以工作,但他不会告诉我他是如何得到这个机器代码的。所以我实际上很关心获取该代码的过程。

好的,我尝试了此处帖子中建议的方法,但仅对于 gethostname() 函数,我得到了 130 个字符的机器代码。它不包括 printf() 机器代码。因为我需要将主机名打印到控制台,所以也应该包括在内,但这会使机器代码更长。我必须将代码放入 100 个字节的数组中,因此代码应该小于 100 个字节。

有人可以为上面的 c 程序编写汇编代码,将其转换为小于 100 字节的机器代码吗?

4

4 回答 4

3

要获得机器码,您需要编译程序然后反汇编。例如,使用 gcc 执行以下操作:

gcc -o hello hello.c
objdump -D hello

转储将以字节为单位显示机器代码以及该机器代码的反汇编。

一个相关的简单示例,您必须了解目标文件和可执行文件之间的区别,但这仍然应该说明我的意思:

unsigned int myfun ( unsigned int x )
{
    return(x+5);
}

gcc -O2 -c -o hello.o hello.c
objdump -D hello.o


Disassembly of section .text:

00000000 <myfun>:
   0:   e2800005    add r0, r0, #5
   4:   e12fff1e    bx  lr
于 2012-05-16T15:11:05.100 回答
2

FreeBSD 是一个操作系统,而不是编译器或汇编器。

您想将汇编源代码汇编成机器代码,因此您应该使用汇编程序。

您通常可以使用 GCC,因为它足够聪明,知道对于以 结尾的文件名.s,它应该运行汇编程序。

如果你已经在一个目标文件中有代码,你可以用它objdump来读出文件的代码段。

于 2012-05-16T13:59:43.227 回答
1

发布的 37 个字节完全是垃圾。

如果在任何版本的 Windows(windows 2000 或更高版本)下运行,我相信“outsb”和“insd”指令(在用户程序中)会导致错误,因为不允许用户程序直接执行端口级别 I /O。

由于机器代码不会以“真空”结尾,因此我在发布的代码之后添加了一些 \x90 -bytes(再次为 NOP)。这只会影响最后一个 rcl 指令的参数(在给定的代码中过早结束;例如,发布的代码不仅是垃圾,而且过早结束)。

但是,微处理器没有自己的智能,因此它们会(尝试)执行您提供给它们的任何垃圾代码。而且,代码以“inc ecx”开头,这是一个愚蠢的举动,因为我们不知道 ecx 以前有什么值。“shl dword ptr [eax],$58”也是随机破坏内存的“好”方法(因为如果 eax 也是未知的值)。

而且,其中一个甚至不是有效字节(应该表示为两个十六进制数字)。

无效的“字节”是 \xw3。

我将那个无效字节替换为 \x90 (一个 NOP,如果它在指令的开头),并得到:

00451B51 41 inc ecx 00451B52 C13058 shl dword ptr [eax],$58 00451B55 6E outsb 00451B56 61 popad 00451B57 6D insd 00451B58 652323 and esp,gs:[ebx] 00451B5B C3 ret

// code below is NEVER executed, since the line above does a RET.

00451B5C BCA383F469 mov esp,$69f483a3 00451B61 3690 nop // 36, w3 ???? 00451B63 DE4F2F fimul word ptr [edi+$2f] 00451B66 5F pop edi 00451B67 2F das 00451B68 3933 cmp [ebx],esi 00451B6A 60 pushad 00451B6B 2432 and al,$32 00451B6D B4AB mov ah,$ab 00451B6F 21C1 and ecx,eax 00451B71 8024E0DB and byte ptr [eax],$db 00451B75 D09090909090 rcl [eax-$6f6f6f70],1

于 2014-04-03T00:45:37.563 回答
0

你会得到一个很好的目标文件文本部分的十六进制转储objdump -s -j .text

编辑了更多细节:您需要找出目标代码中函数的地址是什么。这是objdump -t为了什么。在这种情况下,我正在寻找main程序“hello”中的函数。

> objdump -t hello|grep main

> 0000000000400410 g     F .text  000000000000002f        main

现在我创建一个 hexdump objdump -s -j .text hello

400410 4881ec08 010000be 00010000 31c04889  H...........1.H.
400420 e7e8daff ffff4889 e6bff405 400031c0  ......H.....@.1.
400430 e8abffff ff31c048 81c40801 0000c390  .....1.H........
400440 31ed4989 d15e4889 e24883e4 f0505449  1.I..^H..H...PTI
400450 c7c0e005 400048c7 c1500540 0048c7c7  ....@.H..P.@.H..
...

第一行是地址。它以函数的地址 400410 开头main,但情况并非总是如此。以下 4 行是 16 字节的十六进制机器码,最后一行是相同的 16 字节的 ASCII 机器码。因为很多字节在 ASCII 中没有表示,所以有很多点。您需要使用 4 个十六进制列:\x48 \x81 \xec....
我已经在 linux 系统上完成了这项工作,但是对于 FreeBSD,您可以完全一样 - 只是生成的 machindecode 会有所不同。

于 2012-05-16T15:48:21.773 回答