实验5:shellcode编写实验
- Task1a
nasm是一个针对Intel x86 和x64架构的汇编器和反汇编器,`-f elf32`表示我们要将代码编译成32位ELF二进制格式
`ld`表示链接外部库,`elf_i386`表示生成32位可执行二进制文件
objdump 命令可以用于反汇编可执行二进制文件,使用`-Mintel`选项表示在 Intel模式下生成汇编代码
xxd 是一个十六进制转储工具,可用于查看和修改二进制文件或数据的十六进制表示,-c 控制每行显示的字节数;-p 参数用于以纯粹的十六进制格式输出数据,而不包含行号、偏移量和ASCII 字符
使用 xxd 命令打印出二进制文件的内容,可以找到shellcode
复制进convert.py文件,获得shellcode在lab4中的格式
放入lab4中的实验环境中执行,成功打开了一个sh shell
- Task1b
实验手册先介绍了一些在shellcode中去掉\x00的方法
- 对寄存器赋值不使用"mov eax, 0",而是"xor eax, eax"
- 将0x00000099赋值给寄存器不能使用"mov eax, 0x99",因为0x99实际就是0x00000099,可以先将eax进行异或置零,然后为al寄存器分配1字节的数字0x99,al是eax的最低八位有效位
- 由于小端存储,"xyz#"在计算机中实际存储的形式是"#zyx",然后进行一次左移,#就被移出去了,再进行一次右移,变成"\0zyx,"后面的"zyx"就不会被截断了,即"xyz\0"
如果x,y,z,和#分别是0x78,0x79,0x7a,0x23
- Task1c
函数调用时,参数先入栈,然后返回地址才入栈,除非有恢复现场的要求,shellcode可以不用管函数返回的问题。
先构造一个参数字符串,压入栈,将地址放入一个通用寄存器,最后将所有参数的地址一并压入栈中
注意:这里将#写在字符串前面,直接右移就能得到单个字符串!但不能写在后面左移,因为左移虽然可以挤掉#,但原字符放到了高位上,计算机读取时改变了原始的值
- Task1d
经过尝试发现,可以在将"/usr/bin/env"参数入栈前就将环境变量入栈,这样在环境变量入栈时可以使用ebx等寄存器,不影响后面ebx等寄存器的赋值
- Task2
另一种通过记录参数地址的方法,即将所有参数都放入一个字符串中,通过将字符串作为函数调用时的返回地址的方式将这个字符串压入栈中
跳转到one时,会认为`call one`的下一条是返回地址,于是进入one时的栈顶就是db'/bin/sh*AAAABBBB',pop ebx即可将字符串放入ebx中
我们知道`ebx`应该指向可执行程序"/usr/bin/env",`ecx`应该指向参数数组的地址,`edx`应该指向环境变量。
mov [ebx+7], al ; 字符串的第七个位置的*变成0,相当于将"/bin/sh"分割出来,这样ebx指向的就是"/bin/sh"这一个字符串
mov [ebx+8], ebx ; 将ebx的值(字符串的地址)存在字符串的第八个位置处,占据四个字节(32位)
mov [ebx+12], eax ; 字符串的第十二个位置变成0,相当于将ebx的值(字符串的地址)分割出来
lea ecx, [ebx+8] ; 让ecx指向字符串中存着的ebx的值(字符串的地址)
xor edx, edx ; 将edx的值变成0,因为没有环境变量
由于ecx指向的数组通过0x00分割每一个参数,所以只用al置零不能分开ecx和edx分别指向的部分,所以ecx后要用eax置零,其他部分的置零都可以用al
和Task1b的区别就是一个只能传4或1字节,一个只能传8或1字节,先传"h",再传"/bin/bas",同样采用移位的方法
int指令的作用是引发中断,调用中断例程,后面的数字是中断号,代码将进入系统内核;`mov al 0x0b`是把execve系统调用号作为参数传入
函数在堆栈中传参的顺序是代码中相反的参数顺序(从右向左);函数调用时,返回地址先入栈,然后参数入栈,最后被调用函数的地址入栈,不同的参数之间通常通过0来分割(将eax赋成0,push eax)
标签:攻防,shellcode,eax,地址,参数,字符串,编写,ebx From: https://www.cnblogs.com/leo1017/p/17936743