在linux如何生成32位的程序
在linux下默认生成的是64位的,并且ubuntu中没有安装32位的库,因此如果想要在ubuntu中运行或者生成32位的程序需要安装32位的库。
gcc test.c -m32 生成32位的程序
sun@ubuntu:~/Desktop$ gcc test.c -m32
sun@ubuntu:~/Desktop$ file a.out
a.out: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-, for GNU/Linux 2.6.32, BuildID[sha1]=bb9a90c1c149ca64c5cf230c05e4ffdf2a0013e4, not stripped
sun@ubuntu:~/Desktop$
下面是一段32位的反汇编
gdb-peda$ disassemble
Dump of assembler code for function main:
0x080484aa <+0>: lea ecx,[esp+0x4]
0x080484ae <+4>: and esp,0xfffffff0
0x080484b1 <+7>: push DWORD PTR [ecx-0x4]
0x080484b4 <+10>: push ebp
0x080484b5 <+11>: mov ebp,esp
0x080484b7 <+13>: push ecx
0x080484b8 <+14>: sub esp,0x14
=> 0x080484bb <+17>: mov DWORD PTR [ebp-0x14],0x1
0x080484c2 <+24>: mov DWORD PTR [ebp-0x10],0x2
0x080484c9 <+31>: sub esp,0x8
0x080484cc <+34>: push DWORD PTR [ebp-0x10]
0x080484cf <+37>: push DWORD PTR [ebp-0x14]
0x080484d2 <+40>: call 0x804846b <add>
0x080484d7 <+45>: add esp,0x10
0x080484da <+48>: mov DWORD PTR [ebp-0xc],eax
0x080484dd <+51>: mov eax,0x0
0x080484e2 <+56>: mov ecx,DWORD PTR [ebp-0x4]
0x080484e5 <+59>: leave
0x080484e6 <+60>: lea esp,[ecx-0x4]
0x080484e9 <+63>: ret
End of assembler dump.
gdb-peda$
64位的汇编
gdb-peda$ disassemble
Dump of assembler code for function main:
0x00000000004005e7 <+0>: push rbp
0x00000000004005e8 <+1>: mov rbp,rsp
=> 0x00000000004005eb <+4>: sub rsp,0x10
0x00000000004005ef <+8>: mov DWORD PTR [rbp-0xc],0x1
0x00000000004005f6 <+15>: mov DWORD PTR [rbp-0x8],0x2
0x00000000004005fd <+22>: mov edx,DWORD PTR [rbp-0x8]
0x0000000000400600 <+25>: mov eax,DWORD PTR [rbp-0xc]
0x0000000000400603 <+28>: mov esi,edx
0x0000000000400605 <+30>: mov edi,eax
0x0000000000400607 <+32>: call 0x400596 <add>
0x000000000040060c <+37>: mov DWORD PTR [rbp-0x4],eax
0x000000000040060f <+40>: mov eax,0x0
0x0000000000400614 <+45>: leave
0x0000000000400615 <+46>: ret
End of assembler dump.
gdb-peda$
区别:
1.在64位程序中每个push和pop指令sp减8,而32位的则减4,入栈的最小单位不同。
2.表示的地址范围不同,64位的使用8字节表示,32位的用4字节表示。
3.call指令和ret指令分别会有入栈和出栈的作用,在64位中call指令相当于push rip,jmp 目的地址,第一个入栈的返回地址是8字节,而32位中相当于push eip,jmp 目的地址,入栈的返回地址是4字节。
4.传递参数的方式不同,32位的将参数入栈来传递参数,64位的使用寄存器进行传递参数,用来传递参数的寄存器为rdi,rsi,rdx,rcx,r8,r9,这六个寄存器分别用来存储第一至第六个参数,如果参数多余6个会先将后面的参数先入栈,前六个参数放在对应的寄存器中,在上面的例子中32位的使用了将参数放入栈中的方式 eg:
0x080484cc <+34>: push DWORD PTR [ebp-0x10]
0x080484cf <+37>: push DWORD PTR [ebp-0x14]
64位的将参数放入rdi和rsi寄存器中eg:
0x0000000000400603 <+28>: mov esi,edx
0x0000000000400605 <+30>: mov edi,eax
下面是一个当参数多于6个的例子:
源代码:
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
int add(int a,int b,int c,int d,int e,int f,int g,int h)
{
int j=a+b+c+d+e+f+g+h;
return j;
}
int main()
{
int a=1,b=2,c=3,d=4,e=5,f=6,g=7,h=8;
int sum=add(a,b,c,d,e,f,g,h);
return 0;
}
64位的主函数的汇编代码
b-peda$ disassemble
Dump of assembler code for function main:
0x000000000040051c <+0>: push rbp
0x000000000040051d <+1>: mov rbp,rsp
=> 0x0000000000400520 <+4>: sub rsp,0x30
0x0000000000400524 <+8>: mov DWORD PTR [rbp-0x24],0x1
0x000000000040052b <+15>: mov DWORD PTR [rbp-0x20],0x2
0x0000000000400532 <+22>: mov DWORD PTR [rbp-0x1c],0x3
0x0000000000400539 <+29>: mov DWORD PTR [rbp-0x18],0x4
0x0000000000400540 <+36>: mov DWORD PTR [rbp-0x14],0x5
0x0000000000400547 <+43>: mov DWORD PTR [rbp-0x10],0x6
0x000000000040054e <+50>: mov DWORD PTR [rbp-0xc],0x7
0x0000000000400555 <+57>: mov DWORD PTR [rbp-0x8],0x8
0x000000000040055c <+64>: mov r9d,DWORD PTR [rbp-0x10]
0x0000000000400560 <+68>: mov r8d,DWORD PTR [rbp-0x14]
0x0000000000400564 <+72>: mov ecx,DWORD PTR [rbp-0x18]
0x0000000000400567 <+75>: mov edx,DWORD PTR [rbp-0x1c]
0x000000000040056a <+78>: mov esi,DWORD PTR [rbp-0x20]
0x000000000040056d <+81>: mov eax,DWORD PTR [rbp-0x24]
0x0000000000400570 <+84>: mov edi,DWORD PTR [rbp-0x8]
0x0000000000400573 <+87>: push rdi
0x0000000000400574 <+88>: mov edi,DWORD PTR [rbp-0xc]
0x0000000000400577 <+91>: push rdi
0x0000000000400578 <+92>: mov edi,eax
0x000000000040057a <+94>: call 0x4004d6 <add>
0x000000000040057f <+99>: add rsp,0x10
0x0000000000400583 <+103>: mov DWORD PTR [rbp-0x4],eax
0x0000000000400586 <+106>: mov eax,0x0
0x000000000040058b <+111>: leave
0x000000000040058c <+112>: ret
End of assembler dump.
32位的主函数的汇编代码
gdb-peda$ disassemble
Dump of assembler code for function main:
0x0804840f <+0>: push ebp
0x08048410 <+1>: mov ebp,esp
0x08048412 <+3>: sub esp,0x30
=> 0x08048415 <+6>: mov DWORD PTR [ebp-0x24],0x1
0x0804841c <+13>: mov DWORD PTR [ebp-0x20],0x2
0x08048423 <+20>: mov DWORD PTR [ebp-0x1c],0x3
0x0804842a <+27>: mov DWORD PTR [ebp-0x18],0x4
0x08048431 <+34>: mov DWORD PTR [ebp-0x14],0x5
0x08048438 <+41>: mov DWORD PTR [ebp-0x10],0x6
0x0804843f <+48>: mov DWORD PTR [ebp-0xc],0x7
0x08048446 <+55>: mov DWORD PTR [ebp-0x8],0x8
0x0804844d <+62>: push DWORD PTR [ebp-0x8]
0x08048450 <+65>: push DWORD PTR [ebp-0xc]
0x08048453 <+68>: push DWORD PTR [ebp-0x10]
0x08048456 <+71>: push DWORD PTR [ebp-0x14]
0x08048459 <+74>: push DWORD PTR [ebp-0x18]
0x0804845c <+77>: push DWORD PTR [ebp-0x1c]
0x0804845f <+80>: push DWORD PTR [ebp-0x20]
0x08048462 <+83>: push DWORD PTR [ebp-0x24]
0x08048465 <+86>: call 0x80483db <add>
0x0804846a <+91>: add esp,0x20
0x0804846d <+94>: mov DWORD PTR [ebp-0x4],eax
0x08048470 <+97>: mov eax,0x0
0x08048475 <+102>: leave
0x08048476 <+103>: ret
End of assembler dump.
在32位的汇编指令中将全部的参数入栈,进行传参
0x0804844d <+62>: push DWORD PTR [ebp-0x8]
0x08048450 <+65>: push DWORD PTR [ebp-0xc]
0x08048453 <+68>: push DWORD PTR [ebp-0x10]
0x08048456 <+71>: push DWORD PTR [ebp-0x14]
0x08048459 <+74>: push DWORD PTR [ebp-0x18]
0x0804845c <+77>: push DWORD PTR [ebp-0x1c]
0x0804845f <+80>: push DWORD PTR [ebp-0x20]
0x08048462 <+83>: push DWORD PTR [ebp-0x24]
在64位的汇编指令中将前六个参数放入寄存器中,后面两个入栈进行传参
0x000000000040055c <+64>: mov r9d,DWORD PTR [rbp-0x10]
0x0000000000400560 <+68>: mov r8d,DWORD PTR [rbp-0x14]
0x0000000000400564 <+72>: mov ecx,DWORD PTR [rbp-0x18]
0x0000000000400567 <+75>: mov edx,DWORD PTR [rbp-0x1c]
0x000000000040056a <+78>: mov esi,DWORD PTR [rbp-0x20]
0x000000000040056d <+81>: mov eax,DWORD PTR [rbp-0x24]
0x0000000000400570 <+84>: mov edi,DWORD PTR [rbp-0x8]
0x0000000000400573 <+87>: push rdi
0x0000000000400574 <+88>: mov edi,DWORD PTR [rbp-0xc]
0x0000000000400577 <+91>: push rdi
在做pwn题时分清64位和32位的不同是很重要的,这两种分别需要覆盖的返回值的位数是不同的。