PDA

View Full Version : new VNC client in quickbasic.. video demo, and also question!



Mike Chambers
July 29th, 2008, 09:44 AM
http://www.youtube.com/watch?v=1rAurls9-G0

i started working on this yesterday. excuse the unprofessional demo.

i have a question for you ASM guys. i want to dynamically "assemble" some binary code into a string in QB that will let me CALL ABSOLUTE to it. i need it to copy a memory block of arbitrary size from a specified seg : ptr to another specified seg : ptr

you probably see where i'm going with this.. string variables to segment A000h for fast video writes. :p

what would be the simplest way of implementing this binary code??

if you need this info, here's the CALL ABSOLUTE info from the QBX help file:


│CALL Absolute ([argumentlist,] integervariable%)

│ ■ argumentlist Arguments passed to a machine-language
│ procedure as offsets (near pointers) from the
│ current data segment.
│ ■ integervariable% The offset from the current code segment, set
│ by DEF SEG, to the starting location of the
│ procedure.

so, ideally i could do it like this:

lets say i have 320 bytes of pixel data to write starting at 0, 0 in 320x200x8.. for simplicity's sake, we'll just make them all of value 255 here:

bincode$ = asmcodeformemoryblahblahineedhelpwiththat
pixels$ = string$(320, chr$(255))
vidoffset% = 0
pixelcount% = len(pixels$)
CALL ABSOLUTE VARSEG(pixels$), VARPTR(pixels$), &HA000, vidoffset%, pixelcount%, VARPTR(bincode$)

obviously, i could do stuff like change vidoffset% to 320 and it'd copy the pixel data to the SECOND line rather than the first. you get what i'm doing here, you guys are smart that's why i'm here :p


how would the binary code handle the 5 variables i'm feeding it? if i know that, i can probably just write the code myself with MOVs and stuff.

hargle
July 29th, 2008, 01:13 PM
I think this will get you going in the right direction:



push bp
push ds
push es
mov bp, sp
mov ax, [bp+6] ; argument #1 segment of source
mov bx, [bp+8] ; argument #2 segment of destination
mov si, [bp+0ah] ; argment #3 offset of source
mov di, [bp+0ch] ; argument #4 offset of destination
mov cx, [bp+0eh] ; # of bytes to copy
mov ds, ax ; load segments
mov es, bx
rep movsb ; do the copy
pop es
pop ds
pop bp
retf 2


I took a portion of this from one of my early qbasic programs where I passed a variable into the asm code. Not sure how or where I found out it was passed in at bp+6, but whatever. From there, I assumed that each argument passed in was a 16bit value, and should be stacked up one after another.

You very well may want to code an INT 3 at the top of that routine, load up soft-ice in the background, and have it pop up whenever int 3 is called so you can debug this and follow the register loading to make sure it's putting things in the order you think they are.

edit: Ah, I see you're calling absolute in a slightly different order than I'm expecting them to come in. I think you can adjust either your code or mine to make it work...

-jeff!

Trixter
July 29th, 2008, 04:16 PM
You are killing me. What you're able to do in a short amount of time just kills me because you are totally being held back by your language.

The fact that you were able to do it has now inspired me to do a CGA version in assembler.

Mike Chambers
July 29th, 2008, 04:56 PM
I think this will get you going in the right direction:



push bp
push ds
push es
mov bp, sp
mov ax, [bp+6] ; argument #1 segment of source
mov bx, [bp+8] ; argument #2 segment of destination
mov si, [bp+0ah] ; argment #3 offset of source
mov di, [bp+0ch] ; argument #4 offset of destination
mov cx, [bp+0eh] ; # of bytes to copy
mov ds, ax ; load segments
mov es, bx
rep movsb ; do the copy
pop es
pop ds
pop bp
retf 2


I took a portion of this from one of my early qbasic programs where I passed a variable into the asm code. Not sure how or where I found out it was passed in at bp+6, but whatever. From there, I assumed that each argument passed in was a 16bit value, and should be stacked up one after another.

You very well may want to code an INT 3 at the top of that routine, load up soft-ice in the background, and have it pop up whenever int 3 is called so you can debug this and follow the register loading to make sure it's putting things in the order you think they are.

edit: Ah, I see you're calling absolute in a slightly different order than I'm expecting them to come in. I think you can adjust either your code or mine to make it work...

-jeff!

thank you! i compiled it in emu8086 and moved it over to the 286, but it locks up. it doesn't look like it even writes the screen. you're probably right on about the soft-ice thing. the vars could be in different places than you wrote this for.

also, would it be safe to just use PUSHA and POPA instead of the separate PUSH and POP operations?

also, maybe i should use RET instead of RETF since it's a near call? not sure. i don't know ASM well enough to know if that even matters.

Mike Chambers
July 29th, 2008, 04:58 PM
You are killing me. What you're able to do in a short amount of time just kills me because you are totally being held back by your language.

The fact that you were able to do it has now inspired me to do a CGA version in assembler.

lol. i agree. i am killing myself.

this code will be worth continuing though, if i get the ASM bit working. screen writes should be extremely fast. (obviously)

Mike Chambers
July 29th, 2008, 05:09 PM
yeah, if you used the old QBasic 1.1 that came with DOS 5, there will probably be some differences between that and QB 7.1 PDS. i'm looking up info on it. i think basically your code will work if i can figure out how to modify it correctly.

Trixter
July 29th, 2008, 06:06 PM
also, would it be safe to just use PUSHA and POPA instead of the separate PUSH and POP operations?


Not if you want it to run on 8086. Those are 286 instructions.

Mike Chambers
July 29th, 2008, 06:08 PM
Not if you want it to run on 8086. Those are 286 instructions.

yep, i don't plan to run this on an 8088 lol. at least not for now. i thought it was 186 btw?

is the 186 a fairy tale? i've NEVER seen one. 80186 (c)1979 The Tooth Fairy

i understand there was a tandy that used em.

Druid6900
July 29th, 2008, 06:43 PM
The Tandy 2000.

Not compatible with practically everything.

They got suckered in by Intel, as did a few other companies, as the 80286 came out very shortly thereafter.

kb2syd
July 30th, 2008, 05:00 AM
The Tandy 2000.

Not compatible with practically everything.

They got suckered in by Intel, as did a few other companies, as the 80286 came out very shortly thereafter.

And more than just a little "suckering" by Microsoft.

"Just make it BIOS comapatible. No one will write directly to hardware."

There's even an ad out there somewhere with Bill G himselft touting the benefits of the 2000.

hargle
July 30th, 2008, 05:59 AM
maybe i should use RET instead of RETF since it's a near call? not sure. i don't know ASM well enough to know if that even matters.

The code snippet I have has opcodes of "ca 02 00" and that's retf 02, and mine works, but mine is compiled under qbasic 7.1, so maybe it is a near call as you say.

Drop an INT 3 as the first line of that subroutine, compile it and PM me a link to the .exe and I'll debug here.

The nice thing is that we're slowly teaching you assembly language as we work through these programs, and one day you'll just make the jump altogether!

-jeff!

Mike Chambers
July 30th, 2008, 06:04 AM
The code snippet I have has opcodes of "ca 02 00" and that's retf 02, and mine works, but mine is compiled under qbasic 7.1, so maybe it is a near call as you say.

Drop an INT 3 as the first line of that subroutine, compile it and PM me a link to the .exe and I'll debug here.

The nice thing is that we're slowly teaching you assembly language as we work through these programs, and one day you'll just make the jump altogether!

-jeff!

yes! i appreciate the help. :)

do you have qb 7.1? this should work fine in 4.5 also. i can give you the dosvnc.bas code as well if you'd like.

if i can get good with both ASM and C i think i could start having a lot of fun. QB is actually a very flexible language though, when you get down these absolute calls. you can basically make it do anything. you can do far calls as well if you use DEF SEG to specify a segment before the call absolute line.

btw does it have to be EXE, or should i just make BIN files like i've been doing? i figured that was the way to go.

Mike Chambers
July 30th, 2008, 10:50 AM
i just slightly (okay, alot) modified the code and created a VNC stream recorder. i wrote a win32 player for the files. :)

here, download this and check it out. it's the vncplay.exe player for windows and a TEST.VNC file that is a demo of me doing stuff in XP for the playback lol.

http://www.rubbermallet.org/vncplay.zip

note: you will need MSVBVM60.DLL but XP comes with it, starting with i believe SP1.

i'm working on making it full 24bpp color right now, and it'll have timing so it doesn't play so fast. i also plan to have it support compressed VNC encoding methods instead of just the HUGE "raw" method. :p

tell me what you think!

something like this would be awesome for tutorials of whatever, or demonstations, um spying on people and recording evidence (if you're a jerkface), or what have you.

EDIT: here's a new, much longer test .VNC file that you can play with vnc play. zipped.. http://www.rubbermallet.org/TEST2.zip

Mike Chambers
July 30th, 2008, 11:00 AM
what i would REALLY like to program next, is a "passthrough" app to act as a middleman between the VNC server and client. it would be able to record the stream, while allowing you to actually use the VNC client.

this would of course, be a windows program.

hargle
July 31st, 2008, 07:56 AM
yes! i appreciate the help. :)
do you have qb 7.1? this should work fine in 4.5 also. i can give you the dosvnc.bas code as well if you'd like.


Yeah, I have qb7.1 here at my disposal.
that would be great if I can get the source, then I can hack on it til it works and get back to you with the fixed source.

Mike Chambers
July 31st, 2008, 11:40 AM
Yeah, I have qb7.1 here at my disposal.
that would be great if I can get the source, then I can hack on it til it works and get back to you with the fixed source.

awesome! i appreciate the help. i'm going to add mouse support real quick-like than post the code. :)

btw, once we get this ASM bit working i am adding full VESA support! you can select either 320x200 256-color or 640x480 16-color when you connect to a server, but while you're playing with the mem copy code you will obviously probably want to use 320x200. 8 bit per pixel = friendlier for testing.

Mike Chambers
July 31st, 2008, 01:39 PM
okay, here you go http://www.rubbermallet.org/dosvnc.zip

use the command line arg /ASM to enable it reading MEMCOPY.BIN to RAM and try to screen write with it... doesn't work right now obviously. :p

Mike Chambers
July 31st, 2008, 03:02 PM
i'm using it as is on a celeron 300 mhz (i think 300, something like that anyway) and believe it or not, it's actually pretty fast! i am amazed, but it still needs ASM writes for sure. it'd be useble on a 286 or 386 methinks. if you have a VESA card anyway.

MattHacker
July 31st, 2008, 04:01 PM
I tested it on a Pentium 1@233MHz with 64MB RAM. It's quite fast compared to your 286, but the inverted colors in VGA mode and wrong colors in EGA mode combined with no right mouse or modifier key support make it somewhat hard to use. :P

Nice work, though! :D

here's a picture of the computer (the picture shows it running windows 98 and using a wireless card, but I tested the VNC client in DOS with a Xircom ethernet card, then rebooted into windows before taking the picture. :P):
http://img518.imageshack.us/img518/2677/83792207gt8.png

Chuck(G)
July 31st, 2008, 04:29 PM
What version of MASM are you guys using? In 6.x, calling conventions and parameter passing (as well as local variables) are all nicely handled automatically for you.

And 6.x is free for the download from Micros~1.

There were more 186 boxes than you think, and a fair number of 188 ones also. (The USR Courier Dual Standard modem has one under the hood). You can find them in all sorts of embedded applications.

In many ways, the 186 is superior to the 8086/88. 20 bit DMA, built-in chip selects, timers, etc.

There were chips beyond the NEC V20/V30 that were used in PCs. Didn't some of the Epson boxes use a V40?

Terry Yager
August 4th, 2008, 06:52 PM
There's also the PC Radio, which came along at a time when IBM knew, or should have known better.

--T

hargle
August 6th, 2008, 02:11 PM
Sorry mike, been busy on other tasks to do much debugging, but here's where I'm at:

I moved some of the source around so the program would immediately load the .bin file and try calling it.

I compiled the program to an .exe

it ran, loaded the bin file into memory, in my case it was at 8e80:72. The data appeared to be fine, so the program is able to load in direct binary.

I then traced through the program til it crashed and I discovered that the code it tried to call in memory was no where near 8e80:72. So it looked like the setup for the call absolute isn't getting setup and it's just calling some random chunk of memory. It's really strange.

I then restarted it, and changed the call routine to 8e80:72 by hand, and it successfully jumped into our code and returned back to the basic program without a problem, so the retf 2 at the end is exactly what it should be.

Unfortunately the dstSeg of a000h didn't show up, nor did any of the other variables we tried to get set up prior to the call, so basically the entire call absolute routine was a complete failure- no parameter passing and not calling the correct segment or offset in memory.

There's certainly a possibility that I broke it when I tried to make the program as simple as possible, so if you'd be willing to write up a new program that does nothing else than load the bin and then execute it, that could be handy for me to continue with, otherwise I don't know what to say.


(BTW, if you ever want to make a program hacker-unfriendly, code it in basic. It SUCKS trying to trace through it-lots of weird interrupt calls which confuse soft-ice)

-jeff!

Trixter
August 7th, 2008, 08:54 AM
I hate to keep harping on this but there are many quickbasic sites on the web that have solved this problem (marrying assembly with quickbasic), have you checked them? It's much more simple than you're making it.

I'll ask a quickbasic friend of mine to give me a quick example.

Mike Chambers
August 7th, 2008, 09:08 AM
yeah, i've been looking around the web a bit. not much uber-detailed info that i've found. i haven't worried about it much recently, but i need to figure it out still.

that said, it should be a non-issue soon enough!

http://rubbermallet.org/thanksmike.jpg

Mike Chambers
August 7th, 2008, 09:12 AM
Sorry mike, been busy on other tasks to do much debugging, but here's where I'm at:

I moved some of the source around so the program would immediately load the .bin file and try calling it.

I compiled the program to an .exe

it ran, loaded the bin file into memory, in my case it was at 8e80:72. The data appeared to be fine, so the program is able to load in direct binary.

I then traced through the program til it crashed and I discovered that the code it tried to call in memory was no where near 8e80:72. So it looked like the setup for the call absolute isn't getting setup and it's just calling some random chunk of memory. It's really strange.

I then restarted it, and changed the call routine to 8e80:72 by hand, and it successfully jumped into our code and returned back to the basic program without a problem, so the retf 2 at the end is exactly what it should be.

Unfortunately the dstSeg of a000h didn't show up, nor did any of the other variables we tried to get set up prior to the call, so basically the entire call absolute routine was a complete failure- no parameter passing and not calling the correct segment or offset in memory.

There's certainly a possibility that I broke it when I tried to make the program as simple as possible, so if you'd be willing to write up a new program that does nothing else than load the bin and then execute it, that could be handy for me to continue with, otherwise I don't know what to say.


(BTW, if you ever want to make a program hacker-unfriendly, code it in basic. It SUCKS trying to trace through it-lots of weird interrupt calls which confuse soft-ice)

-jeff!

thanks for all that testing jeff! maybe i could write a small memory scanner util that looks for exactly what it's written for the absolute call and then print me out info on it..

mbbrutman
August 7th, 2008, 09:56 AM
Now that is too funny ...

Get off the damn QB and start using C!


:-)

Mike Chambers
August 7th, 2008, 10:19 AM
Now that is too funny ...

Get off the damn QB and start using C!


:-)

i'm reading the manual as i type this. :D

i don't think i'm going to come out with a C++ IRCd for my first program, but learning takes time... eventually i will be rocking the C hardcore.

speaking of damn QB, take a look at my e-mail client if you haven't. :p it's in the vintage software section.

Trixter
August 7th, 2008, 02:23 PM
Here is what my qbasic friend replied with in terms of how to interface asm with qb:

Check out:

http://doorknobsoft.com/tutorial/combining-asm-and-qbasic-code/

http://www.petesqbsite.com/sections/tutorials/zines/qbnews/3-asm.txt

The short of it, either running Call Absolute on a string with machine language, or linking the ASM code (.obj) into a Quick Library (.qlb) for within QB and a library (.lib) for EXE compiling, and calling it as a function/sub from QB. I've used 3rd party QLB/LIB functions made from ASM code.

Mike Chambers
August 8th, 2008, 07:36 AM
yeah absolute is the way i'd rather do it


mov ax, [bp+6] ; get the color
mov dx, [bp+8] ; get y value
mov cx, [bp+10] ; get x value

jeff was right about where the values should be. i wonder what the problem is.

hargle
August 11th, 2008, 10:34 AM
just to prolong your delve into C, here's a qbasic program that prints strings directly to the screen. I started with the call absolute example program and then tweaked it 'til I was able to figure out how to pass in all the goodies.



'$INCLUDE: 'qbx.bi'

'AsmBytes is a label; nASMBYTES is a symbolic constant.
CONST nASMBYTES = 36
DEFINT A-Z
DIM AsmProg(1 TO (nASMBYTES / 2))
CLS

'The machine-language program stored as data to read into the array.
AsmBytes:
'DATA &hcc :' int 3 - use for debugging
DATA &H55 : 'PUSH BP Save base pointer.
DATA &H8B, &HEC : 'MOV BP,SP Get our own.
DATA &h06 : 'push es
DATA &h1e : 'push ds
DATA &h8b, &h4e, &h06 : 'mov cx, [bp+6] 'length
DATA &h8b, &h5e, &h08 : 'mov bx, [bp+8] 'destSeg
DATA &h8b, &h56, &h0a : 'mov dx, [bp+a] 'srcSeg
DATA &h8b, &h7e, &h0c : 'mov di, [bp+c] 'destOff
DATA &h8b, &h76, &h0e : 'mov si, [bp+e] 'srcOff
DATA &h8a, &h46, &h10 : 'mov ah, [bp+10]'color/attributes
DATA &h8e, &hda : 'mov ds, dx ; set destination segment
DATA &h8e, &hc3 : 'mov es, bx ; set source segment
DATA &ha4 : 'movsb ; copy character of string
DATA &haa : 'stosb ; put color/attribute
DATA &he2, &hfc : 'Loop back ; do it again
DATA &h1f : 'pop ds
DATA &h07 : 'pop es
DATA &H5D : 'POP BP Restore base pointer.
DATA &HCA, &H02, &H00 : 'RET 2 Pop argument off stack
' and make far return.

'Get the starting offset of the array.
P = VARPTR(AsmProg(1))
'Poke the machine-language program into the array.
DEF SEG = VARSEG(AsmProg(1)) 'Change the segment.
FOR i = 0 TO nASMBYTES - 1
READ J
POKE (P + i), J
NEXT i

' print a sample
msg$ = "This is a message to display"


srcSeg% = SSEG(msg$) ' point to the physical address of this string
srcOff% = SADD(msg$)

destSeg% = &HB800 ' point to the destination (upper left corner)
destOff% = 0

length% = LEN(msg$) ' get the size
attrib% = &H30 ' make it black on blue.

'Execute the program.
CALL Absolute(BYVAL attrib%, BYVAL srcOff%, BYVAL destOff%, BYVAL srcSeg%, BYVAL destSeg%, BYVAL length%, VARPTR(AsmProg(1)))
DEF SEG ' Restore the segment.



END


This should (it does for me) print "This is a message to display" in black on light blue in the upper left corner of the screen. I was able to compile it, and even run the .exe file under XP's dos shell.

Hopefully this will work for too, in case you need it.

-jeff!

mbbrutman
August 11th, 2008, 04:02 PM
Jeff Dude ! Stop feeding these guys so that they can finally get to a real language!

hargle
August 12th, 2008, 05:29 AM
hehe, I know, I know!

I was just feeling guilty that I hadn't fully explored why it didn't work when I knew that it was possible, and I was bored at work yesterday. I didn't want to work on anything, but did want to look busy. :)

(I get a LOT of stuff done this way)

-jeff!