NASM - The Netwide Assembler
NASM Forum => Using NASM => Topic started by: nobody on January 30, 2009, 03:50:46 PM
-
Hello,
I want to read information about the cursor position (x,y) on the screen or to set by myself the coordinates for it. In good old C you could do that quite easy with functions like void gotoxy(int,int), int wherex(), int wherey() and in DOS/Windows it's also quite simple using TASM and int 010h with the right values in the register.
But how can I successfully manage, to read and set information about the cursor position in Linux using NASM ?
I'm almost ashamed to ask for help, but I didn't find anything about this topic. It is all about DOS and anthing else.
Is there a syscall in Linux, I still haven't found, or a speciall way (direct BIOS) without using the OS ?
Thank you in advane for your helpfull answer with best wishes
Michel
-
Ah, yes... Linux is "different"... :) AFAIK, there's no "magic sys_call" that will help, but the common ones can be used in the "right combination" to do what you want, I think...
AFAIK, the "right" way is to use the "ncurses" library (my take is that you "might as well use C", if you're going to do it "that" way :)
Another way would be to use the "VT100 escape sequences" - like ansi.sys in dos, if you're familiar with that... Start with an "escape" character, 1Bh or 27 decimal. Most, but not all, follow with '['. Just write 'em to stdout. You can "query cursor position" with "db 1Bh, '[6n'". Reports the position to stdout(?) and messes up the display - maybe there's a way to "capture" this - if so,I haven't figured it out. You can "save current cursor poition [and attributes]" and "unsave" it - lord knows where it's stored. Unless you need cursor position for some reason other than "unsaving" it, this may help. Setting the position, colors, etc. is easy. This assumes that VT100 emulation is available... which it "usually" is, IME. There are escape sequences to check if the device is present and functioning (suspect they report to stdout, too)... This is the first of many that google found:
http://www.termsys.demon.co.uk/vtansi.htm (http://www.termsys.demon.co.uk/vtansi.htm)
Then... you may have heard that, in Unix "everything's a file". If you open "/dev/vcsa0", you can read/write what's on screen. First 4 bytes are screen size and cursor position. I have not had any success *setting* cursor position by writing those bytes, though. After those bytes, it's char, attr, char, attr,... just like a "direct screen write" to B800:???? in dos. Gotta be root to write that file (or, as root, "chown root:root mygem", "chmod +s mygem" - then the program runs as root, even if the user isn't). There are /dev/vsc? devices that use just characters - never tried that one. Note that there are several /dev/vcsa? numbers - 0 may not always be right. (I opened /dev/mouse in a console, and could read it, but it screwed up the mouse in my GUI as long as I had that file open - I don't know what the solution is) Possible issue with dev/vcsa0, too - but it "seems to work"...
As you know, bios ints are 16-bit code, and won't run in 32-bit Linux... unless... You can set up a v86 task in Linux which *will* allow you to use bios (etc.). There's a "linux real mode interface" library - http://lmri.sf.net (http://lmri.sf.net) - to assist with this. Their example (setting video modes) works for me, but I haven't had any luck using it in my own code. I suspect that's the "hard way"...
A guy who goes by "Richard Cooper", also known as "PJ", has written a thing called "softer" which implements the "orange" protocol (??? like ansi.sys? a BBS thing, I think). This uses ports to set and run vga "mode 13" graphics - pretty chunky - and also has text/cursor manipulation routines. I *think* getcursor is in there, setcursor definitely is. I can dig up that code, if you want to look at it...
Don't be ashamed to ask for help. As you've found out, any kind of "graphics" - even get/set cursor - is a murky area in Linux - "here there be dragons"! We've gotta share any tidbit we find, or it'll remain murky.
In that spirit, here are a couple "rudimentary experiments" I've got. Not very useful, as is.
Ncurses (I named this "ncursed.asm"):
;-------------------
; nasm -f elf mygem.asm
; ld -o mygem mygem.o -I/lib/ld-linux.so.2 -lncurses
global _start
extern initscr
extern endwin
section .text
_start:
call initscr
; ???
; if all else fails, RTFM
; ???
call endwin
mov eax, 1
int 80h
;---------------------
VT100:
;---------------------------
; nasm -f elf mygem.asm
; ld -o mygem mygem.o
global _start
section .data
savecursor db 1Bh, '[s'
.len equ $ - savecursor
unsavecursor db 1Bh, '[u'
.len equ $ - unsavecursor
getcursor db 1Bh, '[6n'
.len equ $ - getcursor
setcursor db 1Bh, '[10;20H'
.len equ $ - setcursor
msg db "Hello, new cursor position!"
.len equ $ - msg
section .text
_start:
mov ecx, savecursor
mov edx, savecursor.len
call write_stdout
mov ecx, setcursor
mov edx, setcursor.len
call write_stdout
mov ecx, msg
mov edx, msg.len
call write_stdout
mov ecx, unsavecursor
mov edx, unsavecursor.len
call write_stdout
mov eax, 1
xor ebx, ebx
int 80h
;----------------
write_stdout:
push eax
push ebx
mov eax, 4
mov ebx, 1
int 80h
pop ebx
pop eax
ret
;---------------------
/dev/vcsa0 (especially crude):
;-------------------------
; nasm -f elf mygem.asm
; ld -o mygem mygem.o
;
; (as root)
; chown root:root mygem
; chmod +s mygem
; (don't forget to "exit"!)
; (if you want to run it as "user"
;
global _start
SCREEN_SIZE equ 80 * 25 * 2 + 4
section .text
_start:
nop
mov eax, 5 ; __NR_open
mov ebx, screen_dev
mov ecx, 2 ; O_rdwr
int 80h
test eax, eax
js error
mov [screen_fd], eax
mov eax, 3 ; __NR_read
mov ebx, [screen_fd]
mov ecx, old_screen
mov edx, SCREEN_SIZE
int 80h
test eax, eax
js error
mov eax, [old_screen]
mov [new_screen], eax
mov eax, 19 ; __NR_lseek
mov ebx, [screen_fd]
mov ecx, 0
mov edx, 0
int 80h
test eax, eax
js error
mov byte [new_screen + 2], 20
mov byte [new_screen + 3], 5
mov eax, 4 ; __NR_write
mov ebx, [screen_fd]
mov ecx, new_screen
mov edx, SCREEN_SIZE
int 80h
test eax, eax
js error
mov eax, [old_screen]
call showeaxh
mov eax, 3 ; __NR_read
mov ebx, 0 ; STDIN
mov ecx, key_buf
mov edx, 1
int 80h
mov eax, 19 ; __NR_lseek
mov ebx, [screen_fd]
mov ecx, 0
mov edx, 0
int 80h
test eax, eax
js error
mov eax, 4 ; __NR_write
mov ebx, [screen_fd]
mov ecx, old_screen
mov edx, SCREEN_SIZE
int 80h
test eax, eax
js error
xor eax, eax
error:
neg eax
mov ebx, eax
mov eax, 1 ; __NR_exit
int 80h
;------------------------------
showeaxh:
push eax
push ebx
push ecx
push edx
sub esp, 10h
mov ecx, esp
xor edx, edx
mov ebx, eax
.top:
rol ebx, 4
mov al, bl
and al, 0Fh
cmp al, 0Ah
sbb al, 69h
das
mov [ecx + edx], al
inc edx
cmp edx, 8
jnz .top
; stuff a newline in there
mov byte [ecx + edx], 10
inc edx
mov ebx, 1
mov eax, 4
int 80h
add esp, 10h
pop edx
pop ecx
pop ebx
pop eax
ret
;------------------------------
section .data
screen_dev db "/dev/vcsa0", 0
new_screen db 0, 0, 10, 10
times 100 db 20h, 10h
db "P", 7,"r", 7, "e", 7, "s", 7, "s", 7, " ",7, "e", 7, "n", 7, "t", 7, "e", 7, "r", 7, "!", 15
section .bss
screen_fd resd 1
old_screen resb SCREEN_SIZE
key_buf resb 1
;------------------------
That's about all I know right now. Always willing to learn...
Best,
Frank
-
This is only a short message, cause I've been working at that problem for a couple of days now and can't get rid of it - I wonder how this works...
Many thanks for your help, Frank; your information was not only very interessting for me - I also found related to what you mentioned something that may work.
I found something about exploits and shellcodes, what I didn't know before.
http://bash-hackers.org/wiki/doku.php/scripting/terminalcodes (http://bash-hackers.org/wiki/doku.php/scripting/terminalcodes)
http://wiki.hackerboard.de/index.php/Shellcode_(Exploit) (http://wiki.hackerboard.de/index.php/Shellcode_(Exploit)) (sorry, only in german)
Below is a small programm I wrote after studying the links above. It's still not really successfull, cause I don't know exactly how it works, although it's compareable with programm parameters you use at the start of a prog. like:
./programm Param1 Param2 Param3 .... (in assembler or c)
Her like there you find an unconventionell organisation of stack. As you know normally you have to use in subroutines and in main prog as well the same number of pop- and push-instructions. Otherwise it leads to a "segmention default error" . But here not, cause you push something on the stack, what another programm, that will deal with your results, can use. But hat's the point: when do I get segmentation errors and when not and why? I still don't know exactly how it works and I've been trying for a couple of days now to understand the mechanism:
------------------->>>>
; Intention : programm shall call the bash (or any other shell) and give
; the parmaters to it, so that the shell can execute the commands like 'ls' or
; the 'terminfo' commands, wich shall be compatible to every terminal type and
; better than the Ansi/VST100)
BITS 32
jmp short two
one:
pop ebx
call next
db 'ls' ; or use db 'ls',0 and you get other results
next:
pop esi
; execve("/bin/sh", NULL)
mov eax, 11
push 0
push esi
push ebx
mov ecx, esp
mov edx, 0
int 0x80
two:
call one
db '/bin/bash',0
<<<<<----------------------
-------------------->>>>>>>>>>
; Here's the example from the link I found:
; It leads to a peculiar result: It jumps to another shell (sh) and it changes my
; promt from
; "... @ ...:~/nasm>" to "sh-3.2$" till I return with exit - very obscure, cause it
; doesn't happen, if I change the shell normally, typing /bin/sh and enter
BITS 32
jmp two
one:
pop ebx
; execve("/bin/sh", NULL)
mov eax, 11
push 0
push ebx
mov ecx, esp
mov edx, 0
int 0x80
two:
call one
db '/bin/sh',0
-------->>>>>>
Yor wrote:
As you know, bios ints are 16-bit code, and won't run in 32-bit Linux... unless... You can set up a v86 task in Linux which *will* allow you to use bios (etc.). There's a "linux real mode interface" library - http://lmri.sf.net (http://lmri.sf.net) - to assist with this. Their example (setting video modes) works for me, but I haven't had any luck using it in my own code. I suspect that's the "hard way"...
A guy who goes by "Richard Cooper", also known as "PJd", has written a thing called "softer" which implements the "orange" protocol (??? like ansi.sys? a BBS thing, I think). This uses ports to set and run vga "mode 13" graphics - pretty chunky - and also has text/cursor manipulation routines. I *think* getcursor is in there, setcursor definitely is. I can dig up that code, if you want to look at it...
Yeah, that is very, very, very interesting. To know how to use terminfo or any other
command with linux int 080h is allright and should normally good enough. (With C,NASM or any other languagfe) But what if I want to use the direct way, to go (for example) to $0040:$0050 to read the word, which contains the cursor position? Another article I found says, you can call BIOS without any problem, if you use DOS - this I knew before -, but never (multiuser, safety) if you work with linux or unix. - I think that's not the whole true.
So Richard Coopers thing and any other similar is very imoprtant for me
(The link above didn't work - what a pitty: "linux real mode interface" library is perhaps a very good tool, cause it should also be possible to have access to the whole system (normally) without using such "crazy hacker weapons" (pardon, I don't want to say anything against it, I think I can learn al lot from those tools and I like them too)
Thank you again for your help
Best Michel
P.S. You also would allow a little question (for you, I'm quiet shure) in that nasm forum later about kdevelop (using c++, problemes with the linker ?)
-
Can't (won't) help ya with the "exploits", sorry. Segfault is the best damn thing for 'em! Doubt if I can help with the kdevelop/c++ question, either. Feel free to post it here, but there might be a more appropriate forum.
What I've got for "softer" is here:
http://home.comcast.net/~fbkotler/softer-125-preview.tgz (http://home.comcast.net/~fbkotler/softer-125-preview.tgz)
I may have an example or two that isn't included there. I'll look, if you're interested in it (IIRC, PJ's examples are in Perl). It's just "hello world" with a different message...
For the Linux Real Mode Interface library, try:
http://sf.net/projects/lrmi (http://sf.net/projects/lrmi)
I doubt if you'll find an updated cursor position at 0040:0050, even if you can access that physical address... might be...
You should be able to open and read those "terminfo" files by ordinary int 80h methods. I have *no* idea how to use the information therein, or which one(s) you want.
If you really want access to the whole system, use dos. These "protected mode" OSen are protected from *us*!
Best,
Frank