Author Topic: Find & set cursor position with NASM / Linux  (Read 14256 times)

nobody

  • Guest
Find & set cursor position with NASM / Linux
« 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

Offline Frank Kotler

  • NASM Developer
  • Hero Member
  • *****
  • Posts: 2667
  • Country: us
Re: Find & set cursor position with NASM / Linux
« Reply #1 on: February 01, 2009, 01:25:26 AM »
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

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

nobody

  • Guest
Re: Find & set cursor position with NASM / Linux
« Reply #2 on: February 03, 2009, 02:57:35 PM »
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://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 - 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 ?)

Offline Frank Kotler

  • NASM Developer
  • Hero Member
  • *****
  • Posts: 2667
  • Country: us
Re: Find & set cursor position with NASM / Linux
« Reply #3 on: February 03, 2009, 05:32:20 PM »
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

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

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