Assembly Language nasm error - linux

I have written the following assembly code as prescribed by my text book in the intel 64 bit syntax
Section .text
global _short
_start:
jmp short Gotocall
shellcode:
pop rcx
xor eax,eax
mov byte [rcx+8], al
lea rdi, [rax]
mov long [rcx+8], rdi
mov long [rcx+12], eax
mov byte al, 0x3b
mov rsi, rax
lea rdi, [esi+8]
lea edx, [esi+12]
int 0x80
Gotocall:
call shellcode
db '/bin/shJAAAAKKKK'
but i get a nasm error in line 10 like this
asmshell.asm:10: error: mismatch in operand sizes
Can anybody tell me what mistake is their in my code.
And can anybody please tell me some good references to the 64 bit intel assembly instructions.

If you mean the error is on line 10
mov long [rcx+8], rdi
I was about to ask you what size long qualifier is, but the next line
mov long [rcx+12], eax
shows that you are moving two different sizes of register to the same size destination. In the first case the 64-bit register rdi, in the second case the 32-bit register eax, and long cannot satisfy them both.
Why not just drop the long since by specifying the register, the assembler knows the size of the destination? But sadly, you have only allowed 4 bytes memory to store a 64-bit register, given away by the [rcx+8] followed by [rcx+12].
Perhaps you intended
mov long [rcx+8], edi

Related

How can i copy an array in nasm x86 assembly for Linux, porting 16-bit DOS code?

I have to write a program which copy an array in other array, using x86 assembler
The original code is written in MSDOS' TASM for 8086 processor, but I want port this to Linux NASM using i386 processor
The code in TASM is this:
.MODEL SMALL
.DATA
TABLE_A DB 10, 5, 1
TABLE_B DB 0, 0, 0
.CODE
MOV AX, SEG TABLE_B
MOV DS, AX
MOV SI, 0
LOOP:
MOV AL, TABLE_A[SI]
MOV TABLE_B[SI], AL
INC SI
CMP SI, 2
JBE LOOP
MOV AH, 4Ch
INT 21h
END
I'm trying to rewrite this in nasm, but I don't get to sit in the correct array position, similar to TABLE_A[SI] instruction
How can I do it?
The final code in nasm is this
section .text
global _start
cpu 386
_start:
MOV ESI, TABLE_A
MOV EDI, TABLE_B
MOV CX, 3
COPY_LOOP:
MOV AL, [ESI]
MOV [EDI], AL
INC SI
INC DI
LOOP COPY_LOOP
MOV AX,1
INT 80h
section .data
TABLE_A DB 10, 5, 1
TABLE_B DB 0, 0, 0
How could I do it?
(question from comments on self-answer)
Well, first you read Instruction reference guide to understand what the instruction does, and then you can use it, if it fits your purpose. This is the important step, keep re-reading instruction details every so often, to verify it does modify registers and flags in a way you expect it. Especially if in debugger you see the CPU state of change you didn't expect.
As you are in linux, the ds/es segment registers are very likely already set to reasonably values (covering .data section), so after setting eSi to Source address, eDi to Destination address, and eCx to Count, you write instead of COPY_LOOP: just rep movsb ... and then exit trough int 80h (eax=1). (notice the emphasized letters in register names, Intel picked those intentionally to make it easy to recall)
BTW, just now I noticed, you wrote in your code sort of bugs:
inc si/di should be inc esi/edi, because you use esi/edi to address. If you would be copying array over 64k memory boundary, inc si would wrap around on it.
set ecx to 3, in 32b mode the loop instruction does use whole 32b ecx, not 16b part cx only. If the code ahead of copy would use some large number in ecx setting some of upper 16 bits, your loop would copy many more bytes than only 3.
ahead of calling int 80h again you must set whole eax with the function number, otherwise you risk to have some garbage in upper 16 bits of eax from previous code, requesting invalid function.
So after applying these your code may look like this:
section .text
global _start
cpu 386
_start:
MOV ESI, TABLE_A
MOV EDI, TABLE_B
MOV ECX, 3
REP MOVSB ; copy ECX bytes from DS:ESI to ES:EDI
MOV EAX,1 ; call sys_exit, again FIXED to EAX!
INT 80h
section .data
TABLE_A DB 10, 5, 1
TABLE_B DB 0, 0, 0
If you did read the docs about registers, you should already understand what is difference between eax and ax. In Linux you are in 32b mode (when you link the binary as 32b elf, nowadays the 64b may be default on 64b system, which differs a bit from 32b mode), so by default use the 32b register variants. Unless you really want the 16b/8b variant for particular reason, and you make sure the code doesn't work later with 32b register while you set only less of it (like loop, rep movsb and int 80h do).
Also it makes the code usually faster, as using 16b ax in 32b mode requires additional opcode byte ahead of instruction, for example mov eax,ebx is 2 bytes opcode 89 D8, mov ax,bx is 3 bytes opcode 66 89 D8.
In response to marc
I tried this form, without successful result:
MOV SI, 0
MOV AX, 0
LOOP:
MOV AX, [TABLE_A + SI]
MOV [TABLE_B + SI], AX
INC SI
CMP SI, 2
JBE LOOP
Use pointers (SI, DI) to the arrays and CX as counter :
MOV SI, Table_A ;POINTER TO TABLE_A.
MOV DI, Table_B ;POINTER TO TABLE_B.
MOV CX, 3 ;ARRAY LENGTH.
REPEAT:
MOV AL, [SI]
MOV [DI], AL
INC SI
INC DI
LOOP REPEAT ;CX-1. IF CX>0 JUMP TO REPEAT.

I'm getting a segmentation fault in my assembly program [duplicate]

The tutorial I am following is for x86 and was written using 32-bit assembly, I'm trying to follow along while learning x64 assembly in the process. This has been going very well up until this lesson where I have the following simple program which simply tries to modify a single character in a string; it compiles fine but segfaults when ran.
section .text
global _start ; Declare global entry oint for ld
_start:
jmp short message ; Jump to where or message is at so we can do a call to push the address onto the stack
code:
xor rax, rax ; Clean up the registers
xor rbx, rbx
xor rcx, rcx
xor rdx, rdx
; Try to change the N to a space
pop rsi ; Get address from stack
mov al, 0x20 ; Load 0x20 into RAX
mov [rsi], al; Why segfault?
xor rax, rax; Clear again
; write(rdi, rsi, rdx) = write(file_descriptor, buffer, length)
mov al, 0x01 ; write the command for 64bit Syscall Write (0x01) into the lower 8 bits of RAX
mov rdi, rax ; First Paramter, RDI = 0x01 which is STDOUT, we move rax to ensure the upper 56 bits of RDI are zero
;pop rsi ; Second Parameter, RSI = Popped address of message from stack
mov dl, 25 ; Third Parameter, RDX = Length of message
syscall ; Call Write
; exit(rdi) = exit(return value)
xor rax, rax ; write returns # of bytes written in rax, need to clean it up again
add rax, 0x3C ; 64bit syscall exit is 0x3C
xor rdi, rdi ; Return value is in rdi (First parameter), zero it to return 0
syscall ; Call Exit
message:
call code ; Pushes the address of the string onto the stack
db 'AAAABBBNAAAAAAAABBBBBBBB',0x0A
This culprit is this line:
mov [rsi], al; Why segfault?
If I comment it out, then the program runs fine, outputting the message 'AAAABBBNAAAAAAAABBBBBBBB', why can't I modify the string?
The authors code is the following:
global _start
_start:
jmp short ender
starter:
pop ebx ;get the address of the string
xor eax, eax
mov al, 0x20
mov [ebx+7], al ;put a NULL where the N is in the string
mov al, 4 ;syscall write
mov bl, 1 ;stdout is 1
pop ecx ;get the address of the string from the stack
mov dl, 25 ;length of the string
int 0x80
xor eax, eax
mov al, 1 ;exit the shellcode
xor ebx,ebx
int 0x80
ender:
call starter
db 'AAAABBBNAAAAAAAABBBBBBBB'0x0A
And I've compiled that using:
nasm -f elf <infile> -o <outfile>
ld -m elf_i386 <infile> -o <outfile>
But even that causes a segfault, images on the page show it working properly and changing the N into a space, however I seem to be stuck in segfault land :( Google isn't really being helpful in this case, and so I turn to you stackoverflow, any pointers (no pun intended!) would be appreciated
I would assume it's because you're trying to access data that is in the .text section. Usually you're not allowed to write to code segment for security. Modifiable data should be in the .data section. (Or .bss if zero-initialized.)
For actual shellcode, where you don't want to use a separate section, see Segfault when writing to string allocated by db [assembly] for alternate workarounds.
Also I would never suggest using the side effects of call pushing the address after it to the stack to get a pointer to data following it, except for shellcode.
This is a common trick in shellcode (which must be position-independent); 32-bit mode needs a call to get EIP somehow. The call must have a backwards displacement to avoid 00 bytes in the machine code, so putting the call somewhere that creates a "return" address you specifically want saves an add or lea.
Even in 64-bit code where RIP-relative addressing is possible, jmp / call / pop is about as compact as jumping over the string for a RIP-relative LEA with a negative displacement.
Outside of the shellcode / constrained-machine-code use case, it's a terrible idea and you should just lea reg, [rel buf] like a normal person with the data in .data and the code in .text. (Or read-only data in .rodata.) This way you're not trying execute code next to data, or put data next to code.
(Code-injection vulnerabilities that allow shellcode already imply the existence of a page with write and exec permission, but normal processes from modern toolchains don't have any W+X pages unless you do something to make that happen. W^X is a good security feature for this reason, so normal toolchain security features / defaults must be defeated to test shellcode.)

How to take a string as a input in Assembly x64

I am writing a program to check if a string is Palindrome or not. I want to take a string as input from user. The string can contain any character ranging from digits to special characters. How can I take input from user. I have tried the following code.
global _start
section .bss
string resb 9
section .text
_start:
mov rax,0 ;Am I doing this correct ?
mov rdi,0
mov rsi,string
mov rdx,8
syscall
xor rax,rax
mov rdx,[string]
mov rax,1
mov rdi,1
mov rsi,rdx
mov rdx,8
syscall
mov rax,0
mov rdi,0
syscall
Is the above code correct because when I output the string it shows segmentation fault. The error is
Segmentation fault (core dumped)
I am coding in nasm in Linux(Ubuntu 14.04)
For printing you also need to pass the address so mov rdx, [string] is wrong, you need mov rdx, string or lea rdx, [string]. Also, your final syscall is wrong, because that's a read again. You probably want mov rax, 60 to make it exit.
See, that's why you should post a Minimal, Complete, and Verifiable example.
Usually Linux requires you to use the exit
mov rax, 60
xor rdi, rdi
syscall

NASM x86_64 having trouble writing command line arguments, returning -14 in rax

I am using elf64 compilation and trying to take a parameter and write it out to the console.
I am calling the function as ./test wooop
After stepping through with gdb there seems to be no problem, everything is set up ok:
rax: 0x4
rbx: 0x1
rcx: pointing to string, x/6cb $rcx gives 'w' 'o' 'o' 'o' 'p' 0x0
rdx: 0x5 <---correctly determining length
after the int 80h rax contains -14 and nothing is printed to the console.
If I define a string in .data, it just works. gdb shows the value of $rcx in the same way.
Any ideas? here is my full source
%define LF 0Ah
%define stdout 1
%define sys_exit 1
%define sys_write 4
global _start
section .data
usagemsg: db "test {string}",LF,0
testmsg: db "wooop",0
section .text
_start:
pop rcx ;this is argc
cmp rcx, 2 ;one argument
jne usage
pop rcx
pop rcx ; argument now in rcx
test rcx,rcx
jz usage
;mov rcx, testmsg ;<-----uncomment this to print ok!
call print
jmp exit
usage:
mov rcx, usagemsg
call print
jmp exit
calclen:
push rdi
mov rdi, rcx
push rcx
xor rcx,rcx
not rcx
xor al,al
cld
repne scasb
not rcx
lea rdx, [rcx-1]
pop rcx
pop rdi
ret
print:
push rax
push rbx
push rdx
call calclen
mov rax, sys_write
mov rbx, stdout
int 80h
pop rdx
pop rbx
pop rax
ret
exit:
mov rax, sys_exit
mov rbx, 0
int 80h
Thanks
EDIT: After changing how I make my syscalls as below it works fine. Thanks all for your help!
sys_write is now 1
sys_exit is now 60
stdout now goes in rdi, not rbx
the string to write is now set in rsi, not rcx
int 80h is replaced by syscall
I'm still running 32-bit hardware, so this is a wild asmed guess! As you probably know, 64-bit system call numbers are completely different, and "syscall" is used instead of int 80h. However int 80h and 32-bit system call numbers can still be used, with 64-bit registers truncated to 32-bit. Your tests indicate that this works with addresses in .data, but with a "stack address", it returns -14 (-EFAULT - bad address). The only thing I can think of is that truncating rcx to ecx results in a "bad address" if it's on the stack. I don't know where the stack is in 64-bit code. Does this make sense?
I'd try it with "proper" 64-bit system call numbers and registers and "syscall", and see if that helps.
Best,
Frank
As you said, you're using ELF64 as the target of the compilation. This is, unfortunately, your first mistake. Using the "old" system call interface on Linux, e.g. int 80h is possible only when running 32-bit tasks. Obviously, you could simply assemble your source as ELF32, but then you're going to lose all the advantages if running tasks in 64-bit mode, namely the extra registers and 64-bit operations.
In order to make system calls in 64-bit tasks, the "new" system call interface must be used. The system call itself is done with the syscall instruction. The kernel destroys registers rcx and r11. The number of the system is specified in the register rax, while the arguments of the call are passed in rdi, rsi, rdx, r10, r8 and r9. Keep in mind that the numbers of the syscalls are different than the ones in 32-bit mode. You can find them in unistd_64.h, which is usually in /usr/include/asm or wherever your distribution stores it.

Can anyone help me understand this asm code (It's short)

I'm trying to learn shellcode for a project
in comp science
but I’m having a bit of a problem writing it
I’m reading a book called The Shellcoder's Handbook
and it gives me a code that wont work properly
This is the code:
section .text
global _start
_start:
jmp short GotoCall
shellcode:
pop rsi
xor rax, rax
mov byte [rsi + 7], al
lea rbx, [rsi]
mov [rsi + 8], rbx
mov [rsi + 14], rax
mov byte al, 0x0b
mov rbx, rsi
lea rcx, [rsi + 8]
lea rdx, [rsi + 14]
int 0x80
GotoCall:
Call shellcode
db '/bin/shJAAAAAAKKKKKK'
simply put this is supposed to spawn a shell...
but it wont work and when i use gdb to debug it
i get a weird code and a segmentation fault error at
mov byte [rsi + 7], al
this is the gdb output:
gdb ./sclivro
Program received signal SIGSEGV, Segmentation fault.
0x0000000000400085 in _start ()
(gdb) disas _start
Dump of assembler code for function _start:
0x0000000000400080 <_start+0>: jmp 0x4000a2 <_start+34>
0x0000000000400082 <_start+2>: pop %rsi
0x0000000000400083 <_start+3>: xor %rax,%rax
0x0000000000400085 <_start+5>: mov %al,0x7(%rsi)
0x0000000000400088 <_start+8>: lea (%rsi),%rbx
0x000000000040008b <_start+11>: mov %rbx,0x8(%rsi)
0x000000000040008f <_start+15>: mov %rax,0xe(%rsi)
0x0000000000400093 <_start+19>: mov $0xb,%al
0x0000000000400095 <_start+21>: mov %rsi,%rbx
0x0000000000400098 <_start+24>: lea 0x8(%rsi),%rcx
0x000000000040009c <_start+28>: lea 0xe(%rsi),%rdx
0x00000000004000a0 <_start+32>: int $0x80
0x00000000004000a2 <_start+34>: callq 0x400082 <_start+2>
0x00000000004000a7 <_start+39>: (bad)
0x00000000004000a8 <_start+40>: (bad)
0x00000000004000a9 <_start+41>: imul $0x414a6873,0x2f(%rsi),%ebp
0x00000000004000b0 <_start+48>: rex.B
0x00000000004000b1 <_start+49>: rex.B
0x00000000004000b2 <_start+50>: rex.B
0x00000000004000b3 <_start+51>: rex.B
0x00000000004000b4 <_start+52>: rex.B
0x00000000004000b5 <_start+53>: rex.WXB
0x00000000004000b6 <_start+54>: rex.WXB
0x00000000004000b7 <_start+55>: rex.WXB
0x00000000004000b8 <_start+56>: rex.WXB
0x00000000004000b9 <_start+57>: rex.WXB
0x00000000004000ba <_start+58>: rex.WXB add %bpl,(%r14)
End of assembler dump.
I compile the code using yasm and ld
yasm -f elf64 sclivro.asm
ld -o sclivro sclivro.o
My OS is Debian 6.0 x64
I have a Intel Celeron processor
I wanted to know why am I getting a seg fault error
and explain to me.
Thanks for your time.
Also the book tells me to follow these steps:
Fill EAX with nulls by xoring EAX with itself.
Terminate our /bin/sh string by copying AL over the last byte of the
string. Remember that AL is null because we nulled out EAX in the previ-
ous instruction. You must also calculate the offset from the beginning of
the string to the J placeholder.
Get the address of the beginning of the string, which is stored in ESI,
and copy that value into EBX.
Copy the value stored in EBX, now the address of the beginning of the
string, over the AAAA placeholders. This is the argument pointer to the
binary to be executed, which is required by execve. Again, you need to
calculate the offset.
Copy the nulls still stored in EAX over the KKKK placeholders, using the
correct offset.
EAX no longer needs to be filled with nulls, so copy the value of our
execve syscall (0x0b) into AL.
Load EBX with the address of our string.
Load the address of the value stored in the AAAA placeholder, which is a
pointer to our string, into ECX.
Load up EDX with the address of the value in KKKK, a pointer to null.
Execute int 0x80.
The shellcode you've posted is for Linux running on a 32bit x86 processor - as can be seen from the use of "int 0x80" as system call instruction.
You've compiled it in 64bit mode, though, and attempted to run that. Which fails at the first memory access, because you're not using the real address of the "/bin/sh" string (which is in RSI) but only the explicitly truncated lower 32bit of it (since your code explicitly stated ESI). The latter is invalid, in 64bit mode, where your stack is somewhere at the upper end 0xffff....(64bit addr) of the address space.
The pop rsi instruction is getting the address of the string.
You are overwriting a write protected area when you try to put the nul byte after /bin/sh. I'm not sure why this code is supposed to be special: IT just looks like an obfuscated call to execve().

Resources