我想溢出数组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”
我知道他是在一台不同的机器上做的,所以我不能得到相同的代码,但因为我们都使用完全相同的c函数,所以机器代码的大小应该几乎相同,如果不完全相同的话。他的机器代码是37个字节,他将在shell上传递以溢出FreeBSD 2.95上的二进制文件中的gets()函数,以在stdout上打印主机名。我想做同样的事情,我已经尝试过他的机器代码并且它有效,但他不会告诉我他是如何得到这个机器代码的。所以我实际上关心的是获取该代码的过程。
好的我尝试了这里的帖子中建议的方法,但只是为了函数gethostname()我得到了130个字符的机器码。它不包含printf()机器代码。因为我需要将主机名打印到控制台,所以也应该包含它,但这会使机器代码更长。我必须将代码放在一个100字节的数组中,因此代码应小于100字节。
有人可以为上面的c程序编写汇编代码,转换成小于100字节的机器代码吗?
答案 0 :(得分: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
答案 1 :(得分:2)
FreeBSD是一个操作系统,而不是编译器或汇编程序。
您希望汇编汇编源代码到机器代码中,因此您应该使用汇编程序。
你通常可以使用GCC,因为它足够聪明,知道对于以.s
结尾的文件名,它应该运行汇编程序。
如果您已在目标文件中包含代码,则可以使用objdump
读取文件的代码段。
答案 2 :(得分:1)
发布的37个字节完全是垃圾。
如果在任何版本的Windows(Windows 2000或更高版本)下运行,我相信,那 “outsb”和“insd”指令(在用户程序中)会导致错误, 因为不允许用户程序直接执行port -level I / O.
由于机器代码不会以“真空”结束,我在发布的代码后添加了一些\ x90 -bytes(再次为NOP)。这只会影响最后一个rcl -instruction的参数(在给定的代码中过早地结束;例如,发布的代码不仅是垃圾,而且还过早结束)。
但是,微处理器没有自己的智能,所以他们会(尝试)执行你提供的任何垃圾代码。并且,代码以“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
答案 3 :(得分:0)
使用objdump -s -j .text
得到目标文件的文本部分的一个很好的hexdump。
编辑了更多细节:
您需要找出目标代码中函数的地址。这是objdump -t
的用途。在这种情况下,我在程序“hello”中寻找函数main
。
> objdump -t hello|grep main
> 0000000000400410 g F .text 000000000000002f main
现在我使用objdump -s -j .text hello
创建一个hexdump:
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字节机器码,最后一行是ASCII中相同的16字节机器码。因为很多字节在ASCII中没有表示,所以有很多点。您需要使用4个十六进制列:\x48 \x81 \xec...
我在linux系统上做过这个,但是对于FreeBSD你可以完全一样 - 只有生成的machindecode才会有所不同。