[comp.sys.ibm.pc] Unprotecting BASIC programs

c60c-4au@web-4f.berkeley.edu (10/16/88)

A while ago, someone posted a message asking about a way to deprotect
BASIC programs which were saved with the ",p" option.  (Actually, he
probably did not know that they were saved this way, but by his description
of being able to RUN a program, but not LIST it, I assume this is his
problem).  I tried E-Mailing him, but I can't seem to reach him, so I decided
to post this message, since it is short.

This program, UNPRO, is a short memory-resident program which will 
unprotect BASIC programs.  To run the program, just run UNPRO from the
DOS prompt, and it will be installed.  Now, load BASIC (I have only
tried it with GW-BASIC, but it should run with BASICA too), and load the
protected program.  Now, enter a control-D.  You should hear a beep. Now,
LIST the program and the program will be there.  It may now be saved 
normally.

The UUencoded program follows (since it is only 128 bytes long, I figured
I would put it here):

section 1 of uuencode 2.13 of file unpro.com    by R.E.M.

begin 644 unpro.com
MZSV`_`!U+E.<#KL0`5/K)3T$('4>45:^``.Y``B[``/\K#S^=0?&1/\`NP<B9
MXO)>68O#6\\N_RXZ`0``````'C/`CMB^6`#$//K'!`(!C$P"'XD^.@&,!CP!,
F^[H_`<TG&@``````````````````````````````````````````]
``
end
size     128



--
Erik Talvola               | "It's just what we need... a colossal negative 
c60c-4au@web.berkeley.edu  | space wedgie of great power coming right at us
                           | at warp speed." -- Star Drek

mattp@oakhill.UUCP (Matt Pressly) (03/15/89)

How can one go about making protected BASIC programs listable again?  I
thought I saw something in comp.sys.ibm.pc or comp...binaries about this
several days ago, but I can't find it now.

-- 
address: mattp@oakhill

mattp@oakhill.UUCP (Matt Pressly) (03/16/89)

Could the person who sent me the unprotect for GWBASIC programs using debug
please re-email that to me.  I inadvertently lost the mail.  Thanks.

-- 
address: mattp@oakhill

riley@ihuxv.ATT.COM (d. riley) (03/17/89)

Could the person (or anyone who may have such information) who sent Matt
Pressly (mattp@oakhill) the unprotect for GWBASIC programs using degug either
post that procedure here or at least email it to me (att!ihuxv!riley) also?

					Thanks in advance.

maa@nbires.nbi.com (Mark Armbrust) (03/17/89)

In article <3251@ihuxv.ATT.COM> riley@ihuxv.ATT.COM (d. riley) writes:
>Could the person (or anyone who may have such information) who sent Matt
>Pressly (mattp@oakhill) the unprotect for GWBASIC programs using degug either
>post that procedure here or at least email it to me (att!ihuxv!riley) also?
>
>					Thanks in advance.

Think that was me, so...

There is a feature (bug) of the GWBASIC interpreter that causes it to work a
bit strangely when it reads a null program (as opposed to an empty file).  This
null program is the two-byte sequence FF, 1A.  Create this file with the
debugger and call it U.BAS:

>debug
-e 100 ff 1a
-n u.bas
-r cx
CX 0000
:2
-w
-q
>

Now start basic and load the protected program and then load U.BAS.  The
protected program should now be unprotected:

LOAD "prot-prg
LIST
Illegal function call
LOAD "u
LIST
10 rem I used to be protected
20 rem but now I am not

(As a side note, it you make a file containing FE 1A, it will act as a 
protector!)

There is an algorithmic way to do this, and I have source to a .ASM program
to do it.  If there is enough interest, I'll post it.

Enjoy,
Mark

maa@nbires.nbi.com
maa@nbires.UUCP

wew@naucse.UUCP (Bill Wilson) (03/17/89)

I would like the information too, please.

-- 
Bill Wilson                          (Bitnet: ucc2wew@nauvm)
Northern AZ Univ
Flagstaff, AZ 86011
{These views are mine and do not necessarily reflect those of my employer}

jz0t+@andrew.cmu.edu (James Zurlo) (03/18/89)

This ought to do the trick for you.
10000 'LISTING 2, BUFFUNPR.BAS
10050 '
10100 'This program unprotects protected BASIC programs
10150 '
10200 'Copyright, 1985  VERSION 1.30
10250 '
10300 'By:       Jim Pottkotter
10350 '          3015 Kirby M'Liss Cove
10400 '          Memphis, TN 38115
10450 '
10500 '          (901) 795-2238
10550 '
10600 '=====>  Initialize environment
10650 '
10700 SCREEN 0,1,0,0                     'Text mode
10750 WIDTH 80                           '80 columns
10800 COLOR 10,0,0                       'Bright green on black background
10850 CLS                                'Clear the screen
10900 DEF SEG                            'Set default segment
10950 ON ERROR GOTO 17750                'General error handling
11000 '
11050 '=====>  Initialize variables and constants
11100 '
11150 PROTECTED.FILE$ = ""               'Drive and name of protected file
11200 PROTECTED% = 0                     'Boolean - initially false
11250 THIS.PROGRAM$ = "BUFFUNPR.BAS"     'The name of this program
11300 UNPROTECT.FILE$ = "UNPRBYTE.IMG"   'File containing unprotected status
11350 FIRST.LINE$ = ""                   'First line from protected file
11400 IK$ = ""                           'INKEY$ value
11450 LOOP% = 0                          'Loop counter
11500 MESG$ = ""                         'Error message
11550 EXTENSION% = 0                     'Boolean - true means user entered
11600                                    'an extension on input file name
11650 '
11700 '=====>  If this program is protected, save an unprotected version
11750 '
11800 WHILE PEEK(1124) <> 0
11850   POKE 1124,0
11900   PRINT
11950   PRINT "Saving unprotected version of "; THIS.PROGRAM$;" ";
12000   PRINT "on default drive."
12050   SAVE THIS.PROGRAM$
12100 WEND
12150 '
12200 PROTECTED.FILE$ = ""
12250 WHILE PROTECTED.FILE$ = ""
12300   COLOR 10,0,0
12350   PRINT "BASIC files on current drive and path: ";
12400   COLOR 7,0,0
12450   FILES "*.BAS"
12500   COLOR 10,0,0
12550   PRINT "Enter drive and name of protected file."
12600   PRINT
12650   PRINT "Example:   B:PROTECTD.BAS "
12700   PRINT
12750   PRINT "The default file extension is .BAS  "
12800   PRINT
12850   PRINT "Enter END to end program."
12900   PRINT
12950   PRINT
13000   WHILE PROTECTED.FILE$ = ""
13050     LOCATE CSRLIN - 1, 1
13100     GOSUB 20550                                   'Get file name
13150     IF PROTECTED.FILE$ = "" THEN GOSUB 17350      'Buzz
13200     WHILE PROTECTED.FILE$ = "END"
13250       COLOR 15,0
13300       PRINT
13350       PRINT "Bye!"
13400       PRINT
13450       END
13500     WEND
13550   WEND
13600   EXTENSION% = 0
13650   FOR LOOP% = 1 TO LEN(PROTECTED.FILE$)
13700     IF MID$(PROTECTED.FILE$,LOOP%,1) = "." THEN EXTENSION% = -1
13750   NEXT
13800   IF NOT EXTENSION% THEN PROTECTED.FILE$ = PROTECTED.FILE$ + ".BAS"
13850 WEND
13900 '
13950 PRINT
14000 PRINT "Opening "; PROTECTED.FILE$
14050 PRINT
14100 OPEN "I", 1, PROTECTED.FILE$
14150 INPUT #1, FIRST.LINE$
14200 CLOSE #1
14250 PROTECTED% = (ASC(LEFT$(FIRST.LINE$,1)) = 254)
14300 WHILE NOT PROTECTED%                      'If first byte = 254, then file
14350                                           'is a protected BASIC program
14400     GOSUB 17350                           'Low warning buzz
14450     COLOR 15,0                     'Bright white on black background
14500     PRINT PROTECTED.FILE$; " is not a protected BASIC program."
14550     GOSUB 16800                           'Press any key
14600 WEND
14650 '
14700 PRINT "Creating "; UNPROTECT.FILE$; " on default drive."
14750 BSAVE UNPROTECT.FILE$, 1124, 1
14800 '
14850 '
14900 ON ERROR GOTO 0
14950 CLS                                       'Clear the screen
15000 BUFF.1$ = STRING$(5,13)                   '5 carriage returns
15050 GOSUB 19150                               'Load the keyboard buffer
15100 LOCATE 2,1                                'Put cursor at row 2, col 1
15150 '-----  The following print statements display statements that are
15200 '-----  executable in direct mode.  When the program ends, we will
15250 '-----  be in direct mode, and the five carriage returns we save in
15300 '-----  the keyboard buffer will execute the statements.
15350 '-----
15400 '-----  The statements do the following:
15450 '-----
15500 '-----       1.  LOAD the protected program
15550 '-----
15600 '-----       2.  BLOAD a byte of data that identifies the currently
15650 '-----           loaded program as unprotected.
15700 '-----
15750 '-----       3.  KILL the file used in step 2.
15800 '-----
15850 '-----       4.  SAVE the previously protected program in unprotected
15900 '-----           format.
15950 '-----
16000 '-----       5.  LIST the now unprotected program.
16050 '-----
16100 PRINT "LOAD";  CHR$(34); PROTECTED.FILE$
16150 PRINT
16200 PRINT "BLOAD"; CHR$(34); UNPROTECT.FILE$
16250 PRINT
16300 PRINT "KILL";  CHR$(34); UNPROTECT.FILE$
16350 PRINT
16400 PRINT "SAVE";  CHR$(34); PROTECTED.FILE$
16450 PRINT
16500 PRINT "CLS:LIST"
16550 LOCATE 1,1                                'Put cursor at col 1, row 1
16600 END               'Cursor drops to col 1, row 2 after Ok prompt
16650 '
16700 '=====>  Wait for user to press a key
16750 '
16800 PRINT
16850 PRINT "Press any key to start over."
16900 IK$ = ""
16950 WHILE IK$ = ""
17000   IK$ = INKEY$
17050 WEND
17100 RUN
17150 RETURN                                    'You will never get here
17200 '
17250 '=====>  Low warning buzz
17300 '
17350 FOR LOOP% = 1 TO 4
17400   SOUND  40, .5
17450   SOUND 200, .5
17500 NEXT
17550 RETURN
17600 '
17650 '=====>  Error handling
17700 '
17750 COLOR 15,0                                'Bright white on black
17800 MESG$ = ""
17850 IF ERR = 52 THEN MESG$ = "Invalid file specification.          "
17900 IF ERR = 53 THEN MESG$ = "File not found.                      "
17950 IF ERR = 61 THEN MESG$ = "Disk full.                           "
18000 IF ERR = 62 THEN MESG$ = "File is empty.                       "
18050 IF ERR = 64 THEN MESG$ = "Bad file name.                       "
18100 IF ERR = 67 THEN MESG$ = "Too many files.                      "
18150 IF ERR = 70 THEN MESG$ = "Disk write protected.                "
18200 IF ERR = 71 THEN MESG$ = "Disk not ready.                      "
18250 IF ERR = 72 THEN MESG$ = "Disk media error.                    "
18300 IF ERR = 75 THEN MESG$ = "Path/file access error.              "
18350 IF ERR = 76 THEN MESG$ = "Path not found.                      "
18400 GOSUB 17350                               'Low warning buzz
18450 IF MESG$ = "" THEN ON ERROR GOTO 0        'Unexpected error
18500 PRINT MESG$
18550 PRINT
18600 PRINT "Please correct the problem."
18650 GOSUB 16800                               'Press any key to continue
18700 'LISTING 2
18750 '
18800 'BUFFLOAD.SUB clears and optionally loads the keyboard buffer
18850 '
18900 '=====>  Load Keyboard Buffer
18950 '
19000 '----  If BUFF.1$ and BUFF.2$ both contain a string,
19050 '----  BUFF.1$ overrides BUFF.2$.
19100 '
19150 POKE 1050, PEEK(1052)                      'Clear the buffer
19200 DEF SEG = 0                                'Set segment to 0
19250 WHILE BUFF.1$ <> ""                        'Case 1 - normal codes
19300   POKE 1050, 30                            'Address of 1st byte in buffer
19350   BUFF.LEN% = LEN(LEFT$(BUFF.1$,15))       'Get truncated string size
19400   POKE 1052, 30 + 2 * BUFF.LEN%            'Addr of 1st byte after buffer
19450   FOR BUFF.LOOP% = 1 TO BUFF.LEN%          'Loop BUFF.LEN% times
19500     POKE 1052 + 2 * BUFF.LOOP%, ASC(MID$(BUFF.1$,BUFF.LOOP%,1))    'ASCII
19550   NEXT                                     'End loop
19600   BUFF.2$ = ""                             'Prevent case 2
19650   BUFF.1$ = ""                             'Set exit condition
19700 WEND                                       'End case 1
19750 '
19800 WHILE BUFF.2$ <> ""                        'Case 2 - extended codes
19850   POKE 1050, 30                            'Address of 1st byte in buffer
19900   BUFF.LEN% = LEN(LEFT$(BUFF.2$,30))       'Limit is 30 characters
19950   BUFF.LEN% = (BUFF.LEN% \ 2) * 2          'Force even # of bytes
20000   POKE 1052, 30 + BUFF.LEN%                'Addr of 1st byte after buffer
20050   FOR BUFF.LOOP% = 1 TO BUFF.LEN%          'Loop BUFF.LEN% times
20100     POKE 1053 + BUFF.LOOP%, ASC(MID$(BUFF.2$,BUFF.LOOP%,1))        'ASCII
20150   NEXT                                     'End loop
20200   BUFF.2$ = ""                             'Set exit condition
20250 WEND                                       'End case 2
20300 '
20350 RETURN
20400 '
20450 '=====>  Get protected file name and shift string to upper case
20500 '
20550 INPUT "", PROTECTED.FILE$
20600 FOR LOOP% = 1 TO LEN(PROTECTED.FILE$)
20650   A.LETTER$ = MID$(PROTECTED.FILE$,LOOP%,1)
20700   LOWERCASE% = 0
20750   IF A.LETTER$ >= "a" AND A.LETTER$ <= "z" THEN LOWERCASE% = -1
20800   IF LOWERCASE% THEN A.LETTER$ = CHR$(ASC(A.LETTER$) - 32)
20850   MID$(PROTECTED.FILE$,LOOP%,1) = A.LETTER$
20900 NEXT
20950 RETURN