Basic differences between x86 Assembly and X86-64 Assembly

EDB-ID:

13136

CVE:

N/A

Author:

hophet

Type:

papers

Platform:

Multiple

Published:

2006-11-10

[ -
[ - Basic differences between x86 Assembly and X86-64 Assembly
[ -
[ - By Gustavo C. aka hophet <hophet[at]gmail.com>
[ -
[ - http://www.openvms-rocks.com/~hophet/
[ -

Rex1 - Introduction
Rex2 - Registers
Rex3 - Memory
Rex4 - Debugging
Rex5 - Examples
Rex6 - More information
                    

-[ Introduction

Heys guys, the interests here is showing you the basic differences 
between x86 assembly and X86-64 assembly, more information about
assembly see the end of the file. The architecture tested here is 
AMD64.


-[ Registers

Now we have more space :

%ah/al	- 8 bits
%ax	- 16 bits
%eax	- 32 bits
%rax	- 64 bits

And more eight integer registers, r8-r15:

%rXb	- 8 bits
%rXw	- 16 bits
%rXd	- 32 bits
%rX	- 64 bits

Where X is from 8 to 15

Now the registers are: %rax, %rbx, %rcx, %rdx, %rsi, %rdi, %rbp, %rsp, 
%r8-%r15, %rip, %eflags, %cs, %ss, %ds, %es, %fs, %gs:

(gdb) i r
rax            0x8      8
rbx            0x0      0
rcx            0x4000d7 4194519
rdx            0x8      8
rsi            0x5000d8 5243096
rdi            0x1      1
rbp            0x0      0x0
rsp            0x7fffffff7a90   0x7fffffff7a90
r8             0x0      0
r9             0x0      0
r10            0x0      0
r11            0x302    770
r12            0x0      0
r13            0x0      0
r14            0x0      0
r15            0x0      0
rip            0x4000d7 0x4000d7
eflags         0x202    514
cs             0x33     51
ss             0x2b     43
ds             0x0      0
es             0x0      0
fs             0x0      0
gs             0x0      0

To write 64 bits instructions use quad-word suffix 'q':

movq $0x4, %rax

Exception for stack operations (pop, push, call, ret, enter, leave).

32 bits operations are translated to 64 bits values with zeros. In 8 and 16 bits 
operations are used the lower part of registers.

The used sequence of registers are:

%rax, for number of syscall, %rdi, %rsi, %rdx, %rcx, %r8, %9, for arguments.

The kernel interface uses %rdi, %rsi, %rdx, %r10, %r8 and %r9.

If the object is memory , pass the argument on the stack.

A called function preserve %rbp, %rbx, from %r12 up to %r15 registers.

A system-call is done via the 'syscall' instruction. The kernel destroys
registers %rcx and %r11.

The returning of functions are stored on %rax.

Before we used the 'int $0x80' for calling the kernel, now we use the
'syscall' for the same.

Here are a table of usage of the registers:
                                                                Preserved across
Register                         Usage                          function calls

             temporary register; with variable arguments        No
%rax
             passes information about the number of SSE reg-
             isters used; 1st return register
             callee-saved register; optionally used as base     Yes
%rbx
             pointer
             used to pass 4th integer argument to functions     No
%rcx
             used to pass 3rd argument to functions; 2nd return No
%rdx
             register
             stack pointer                                      Yes
%rsp
             callee-saved register; optionally used as frame    Yes
%rbp
             pointer
             used to pass 2nd argument to functions             No
%rsi
             used to pass 1st argument to functions             No
%rdi
             used to pass 5th argument to functions             No
%r8
             used to pass 6th argument to functions             No
%r9
             temporary register, used for passing a functions  No
%r10
             static chain pointer
             temporary register                                 No
%r11
             callee-saved registers                             Yes
%r12-r15
             used to pass and return floating point arguments    No
%xmm0 %xmm1
             used to pass floating point arguments               No
%xmm2 %xmm7
             temporary registers                                No
%xmm8 %xmm15
             temporary registers                                No
%mmx0 %mmx7
             temporary registers; used to return long           No
%st0,%st1
             double arguments
             temporary registers                                No
%st2 %st7
             Reserved for system (as thread specific data register No
%fs
             SSE2 control and status word                       partial
mxcsr
             x87 status word                                    No
x87 SW
             x87 control word                                   Yes
x87 CW


-[ Memory

It is only necessary to handle 48-bit addresses: "0x00007fff ffffffff"

The page size may have between 4KB and 64KB.

Begin of memory:	0 (Process Segment)
Dynamic Segments:	0x80000000000
End of memory:		0xffffffffffffffff (Reserved System Area)


Image of memory:

---------------------------------
                     ...	
0x80000000000  Dynamic segments 

               Stack segment
                     ...
                     ...
               Data segments
                     ...
0x400000       Text segments

0              Unmapped

---------------------------------


-[ Debugging


Some information about debugging process, here we are going to see the internal
parts of a X86-64 binaries.

See the ELF Header for AMD64:

For AMD64 information, use "e_ident[]" from Elf64_Ehdr (/usr/include/elf.h)

Just to see the changes:

$ readelf -h write
ELF Header:
  Magic:   7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
  Class:                             ELF64
  Data:                              2's complement, little endian
  Version:                           1 (current)
  OS/ABI:                            UNIX - System V
  ABI Version:                       0
  Type:                              EXEC (Executable file)
  Machine:                           Advanced Micro Devices X86-64
  Version:                           0x1
  Entry point address:               0x4000b0
  Start of program headers:          64 (bytes into file)
  Start of section headers:          272 (bytes into file)
  Flags:                             0x0
  Size of this header:               64 (bytes)
  Size of program headers:           56 (bytes)
  Number of program headers:         1
  Size of section headers:           64 (bytes)
  Number of section headers:         5
  Section header string table index: 2

$ objdump -D write

1:     file format elf64-x86-64

Disassembly of section .text:

00000000004000b0 <_start>:
  4000b0:       eb 28                   jmp    4000da <stack>

00000000004000b2 <write>:
  4000b2:       5e                      pop    %rsi
  4000b3:       48 c7 c0 01 00 00 00    mov    $0x1,%rax
  4000ba:       48 c7 c7 01 00 00 00    mov    $0x1,%rdi
  4000c1:       48 c7 c2 08 00 00 00    mov    $0x8,%rdx
  4000c8:       0f 05                   syscall
  4000ca:       48 c7 c0 3c 00 00 00    mov    $0x3c,%rax
  4000d1:       48 c7 c7 01 00 00 00    mov    $0x1,%rdi
  4000d8:       0f 05                   syscall

00000000004000da <stack>:
  4000da:       e8 d3 ff ff ff          callq  4000b2 <write>

00000000004000df <N>:
  4000df:       31 32                   xor    %esi,(%rdx)
  4000e1:       33 34 35 36 37 0a 00    xor    0xa3736(,%rsi,1),%esi

$ strace ./write
execve("./write", ["./write"], [/* 33 vars */]) = 0
write(1, "1234567\n", 81234567
)                = 8
_exit(1)                                = ?


Remember, the number of syscalls has changed, see your syscalls numbers in:

/usr/include/asm-x86_64/unistd.hash

Convert the decimal numbers to hex numbers for use in your code (see: man ascii)

Here are my "unistd.h" on X86_64:

#define __NR_read                                0
#define __NR_write                               1
#define __NR_open                                2
#define __NR_close                               3
#define __NR_stat                                4
#define __NR_fstat                               5
#define __NR_lstat                               6
#define __NR_poll                                7
#define __NR_lseek                               8
#define __NR_mmap                                9
#define __NR_mprotect                           10
#define __NR_munmap                             11
#define __NR_brk                                12
#define __NR_rt_sigaction                       13
#define __NR_rt_sigprocmask                     14
#define __NR_rt_sigreturn                       15
#define __NR_ioctl                              16
#define __NR_pread64                            17
#define __NR_pwrite64                           18
#define __NR_readv                              19
#define __NR_writev                             20
#define __NR_access                             21
#define __NR_pipe                               22
#define __NR_select                             23
#define __NR_sched_yield                        24
#define __NR_mremap                             25
#define __NR_msync                              26
#define __NR_mincore                            27
#define __NR_madvise                            28
#define __NR_shmget                             29
#define __NR_shmat                              30
#define __NR_shmctl                             31
#define __NR_dup                                32
#define __NR_dup2                               33
#define __NR_pause                              34
#define __NR_nanosleep                          35
#define __NR_getitimer                          36
#define __NR_alarm                              37
#define __NR_setitimer                          38
#define __NR_getpid                             39
#define __NR_sendfile                           40
#define __NR_socket                             41
#define __NR_connect                            42
#define __NR_accept                             43
#define __NR_sendto                             44
#define __NR_recvfrom                           45
#define __NR_sendmsg                            46
#define __NR_recvmsg                            47
#define __NR_shutdown                           48
#define __NR_bind                               49
#define __NR_listen                             50
#define __NR_getsockname                        51
#define __NR_getpeername                        52
#define __NR_socketpair                         53
#define __NR_setsockopt                         54
#define __NR_getsockopt                         55
#define __NR_clone                              56
#define __NR_fork                               57
#define __NR_vfork                              58
#define __NR_execve                             59
#define __NR_exit                               60
#define __NR_wait4                              61
#define __NR_kill                               62
#define __NR_uname                              63
#define __NR_semget                             64
#define __NR_semop                              65
#define __NR_semctl                             66
#define __NR_shmdt                              67
#define __NR_msgget                             68
#define __NR_msgsnd                             69
#define __NR_msgrcv                             70
#define __NR_msgctl                             71
#define __NR_fcntl                              72
#define __NR_flock                              73
#define __NR_fsync                              74
#define __NR_fdatasync                          75
#define __NR_truncate                           76
#define __NR_ftruncate                          77
#define __NR_getdents                           78
#define __NR_getcwd                             79
#define __NR_chdir                              80
#define __NR_fchdir                             81
#define __NR_rename                             82
#define __NR_mkdir                              83
#define __NR_rmdir                              84
#define __NR_creat                              85
#define __NR_link                               86
#define __NR_unlink                             87
#define __NR_symlink                            88
#define __NR_readlink                           89
#define __NR_chmod                              90
#define __NR_fchmod                             91
#define __NR_chown                              92
#define __NR_fchown                             93
#define __NR_lchown                             94
#define __NR_umask                              95
#define __NR_gettimeofday                       96
#define __NR_getrlimit                          97
#define __NR_getrusage                          98
#define __NR_sysinfo                            99
#define __NR_times                             100
#define __NR_ptrace                            101
#define __NR_getuid                            102
#define __NR_syslog                            103
#define __NR_getgid                            104
#define __NR_setuid                            105
#define __NR_setgid                            106
#define __NR_geteuid                           107
#define __NR_getegid                           108
#define __NR_setpgid                           109
#define __NR_getppid                           110
#define __NR_getpgrp                           111
#define __NR_setsid                            112
#define __NR_setreuid                          113
#define __NR_setregid                          114
#define __NR_getgroups                         115
#define __NR_setgroups                         116
#define __NR_setresuid                         117
#define __NR_getresuid                         118
#define __NR_setresgid                         119
#define __NR_getresgid                         120
#define __NR_getpgid                           121
#define __NR_setfsuid                          122
#define __NR_setfsgid                          123
#define __NR_getsid                            124
#define __NR_capget                            125
#define __NR_capset                            126
#define __NR_rt_sigpending                     127
#define __NR_rt_sigtimedwait                   128
#define __NR_rt_sigqueueinfo                   129
#define __NR_rt_sigsuspend                     130
#define __NR_sigaltstack                       131
#define __NR_utime                             132
#define __NR_mknod                             133
#define __NR_uselib                            134
#define __NR_personality                       135
#define __NR_ustat                             136
#define __NR_statfs                            137
#define __NR_fstatfs                           138
#define __NR_sysfs                             139
#define __NR_getpriority                       140
#define __NR_setpriority                       141
#define __NR_sched_setparam                    142
#define __NR_sched_getparam                    143
#define __NR_sched_setscheduler                144
#define __NR_sched_getscheduler                145
#define __NR_sched_get_priority_max            146
#define __NR_sched_get_priority_min            147
#define __NR_sched_rr_get_interval             148
#define __NR_mlock                             149
#define __NR_munlock                           150
#define __NR_mlockall                          151
#define __NR_munlockall                        152
#define __NR_vhangup                           153
#define __NR_modify_ldt                        154
#define __NR_pivot_root                        155
#define __NR__sysctl                           156
#define __NR_prctl                             157
#define __NR_arch_prctl                        158
#define __NR_adjtimex                          159
#define __NR_setrlimit                         160
#define __NR_chroot                            161
#define __NR_sync                              162
#define __NR_acct                              163
#define __NR_settimeofday                      164
#define __NR_mount                             165
#define __NR_umount2                           166
#define __NR_swapon                            167
#define __NR_swapoff                           168
#define __NR_reboot                            169
#define __NR_sethostname                       170
#define __NR_setdomainname                     171
#define __NR_iopl                              172
#define __NR_ioperm                            173
#define __NR_create_module                     174
#define __NR_init_module                       175
#define __NR_delete_module                     176
#define __NR_get_kernel_syms                   177
#define __NR_query_module                      178
#define __NR_quotactl                          179
#define __NR_nfsservctl                        180
#define __NR_getpmsg                           181
#define __NR_putpmsg                           182
#define __NR_afs_syscall                       183
#define __NR_tuxcall                           184
#define __NR_security                          185
#define __NR_gettid                            186
#define __NR_readahead                         187
#define __NR_setxattr           188
#define __NR_lsetxattr          189
#define __NR_fsetxattr          190
#define __NR_getxattr           191
#define __NR_lgetxattr          192
#define __NR_fgetxattr          193
#define __NR_listxattr          194
#define __NR_llistxattr         195
#define __NR_flistxattr         196
#define __NR_removexattr        197
#define __NR_lremovexattr       198
#define __NR_fremovexattr       199
#define __NR_tkill      200
#define __NR_time      201
#define __NR_futex     202
#define __NR_sched_setaffinity    203
#define __NR_sched_getaffinity     204
#define __NR_set_thread_area    205
#define __NR_io_setup   206
#define __NR_io_destroy 207
#define __NR_io_getevents       208
#define __NR_io_submit  209
#define __NR_io_cancel  210
#define __NR_get_thread_area    211
#define __NR_lookup_dcookie     212
#define __NR_epoll_create       213
#define __NR_epoll_ctl_old      214
#define __NR_epoll_wait_old     215
#define __NR_remap_file_pages   216
#define __NR_getdents64 217
#define __NR_set_tid_address    218
#define __NR_restart_syscall    219
#define __NR_semtimedop         220
#define __NR_fadvise64          221
#define __NR_timer_create               222
#define __NR_timer_settime              223
#define __NR_timer_gettime              224
#define __NR_timer_getoverrun           225
#define __NR_timer_delete       226
#define __NR_clock_settime      227
#define __NR_clock_gettime      228
#define __NR_clock_getres       229
#define __NR_clock_nanosleep    230
#define __NR_exit_group         231
#define __NR_epoll_wait         232
#define __NR_epoll_ctl          233
#define __NR_tgkill             234
#define __NR_utimes             235
#define __NR_vserver            236
#define __NR_vserver            236
#define __NR_mbind              237
#define __NR_set_mempolicy      238
#define __NR_get_mempolicy      239
#define __NR_mq_open            240
#define __NR_mq_unlink          241
#define __NR_mq_timedsend       242
#define __NR_mq_timedreceive    243
#define __NR_mq_notify          244
#define __NR_mq_getsetattr      245
#define __NR_kexec_load         246
#define __NR_waitid             247
#define __NR_add_key            248
#define __NR_request_key        249
#define __NR_keyctl             250


-[ Examples

Compile assembly code with:

$ as --64 code.s -o code.o
$ ld -m elf_x86_64 code.o -o code

Compile C code with: 

$ gcc -m64 code.c -o code


------ write1.s ------

.text
        .globl _start
_start:

        xor %rdx, %rdx
        pushq $0x8
        pop %rdx

        call STR
        N: .string "ABCDEFG\n"
        STR:
        pop %rsi

        pushq $0x1
        pop %rdi
        pushq $0x1      # write (1)
        pop %rax
        syscall

        pushq $0x1
        pop %rdi
        pushq $0x3c     # exit(3c)
        pop %rax
        syscall

------ write1.s ------

------ write2.s ------

.data
        N: .string "1234567\n"
.text
        .globl _start
_start:

        xor %rdx, %rdx
        pushq $0x8
        pop %rdx
        pushq $N
        pop %rsi
        pushq $0x1
        pop %rdi
        pushq $0x1      # write (1)
        pop %rax
        syscall

        pushq $0x1
        pop %rdi
        pushq $0x3c     # exit(3c)
        pop %rax
        syscall

------ write2.s ------

------ execve1.s ------

.data

SH: .string "/bin/sh"

.text
        .globl _start
_start:

        xorq    %rdx, %rdx
        movq    SH,%rbx
        push    %rbx
        movq    %rsp,%rdi
        xorq    %rax,%rax
        pushq   %rax
        pushq   %rdi
        movq    %rsp,%rsi
        movq    $0x3b,%rax      # execve(3b)
        syscall

        movq $0x1, %rdi
        movq $0x3c, %rax        # exit(3c)
        syscall

------ execve1.s ------

A dummy for shellcode writers:

------ execve2.s ------

# [Linux/X86-64]
# Dummy for shellcode:
# execve("/bin/sh", ["/bin/sh"], NULL)

.text
        .globl _start
_start:

        xorq    %rdx, %rdx
        movq    $0x68732f6e69622fff,%rbx	# /bin/shFF
        shr     $0x8, %rbx			# /bin/sh, without 8 bits (FF)
        push    %rbx
        movq    %rsp,%rdi
        xorq    %rax,%rax
        pushq   %rax
        pushq   %rdi
        movq    %rsp,%rsi
        mov     $0x3b,%al       # execve(3b)
        syscall

        pushq   $0x1
        pop     %rdi
        pushq   $0x3c           # exit(3c)
        pop     %rax
        syscall

------ execve.s ------

The shellcode for your fun moments:

------ shellcode.c ------

/*
 * [Linux/X86-64]
 * Shellcode for: execve("/bin/sh", ["/bin/sh"], NULL)
 * 33 bytes
 */

#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>

#include <err.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>

char shellcode[] =

"\x48\x31\xd2"                  // xor %rdx,%rdx
"\x48\xbb\xff\x2f\x62\x69\x6e"  // mov $0x68732f6e69622fff,%rbx
"\x2f\x73\x68"
"\x48\xc1\xeb\x08"              // shr $0x8,%rbx
"\x53"                          // push %rbx
"\x48\x89\xe7"                  // mov %rsp,%rdi
"\x48\x31\xc0"                  // xor %rax,%rax
"\x50"                          // push %rax
"\x57"                          // push %rdi
"\x48\x89\xe6"                  // mov %rsp,%rsi
"\xb0\x3b"                      // mov $0x3b,%al
"\x0f\x05";                     // syscall

int
main(void)
{
        void (*p)();
        int fd;

        printf("Lenght: %d\n", strlen(shellcode));

        fd = open("/tmp/. ", O_RDWR|O_CREAT, S_IRUSR|S_IWUSR);
        if (fd < 0)
                err(1, "open");

        write(fd, shellcode, strlen(shellcode));
        if ((lseek(fd, 0L, SEEK_SET)) < 0)
                err(1, "lseek");

        p = (void (*)())mmap(NULL, strlen(shellcode), PROT_READ|PROT_EXEC, MAP_SHARED, fd, 0);
        if (p == (void (*)())MAP_FAILED)
                err(1, "mmap");
        p();
        return 0;
}

------ shellcode.c ------


-[ More information

http://www.x86-64.org/documentation/assembly
http://www.x86-64.org/documentation/abi-0.98.pdf
http://www.amd.com/us-en/Processors/TechnicalResources/0,,30_182_739_7044,00.html
http://www.jorgon.freeserve.co.uk/GoasmHelp/64bits.htm


Thanks ZuM by revision!


          (__) 
  /-------(--)
 /   EOF   \/ 
* ||----|| 

# milw0rm.com [2006-11-10]