Welcome, Guest |
You have to register before you can post on our site.
|
Latest Threads |
PB 3.5 8-to-7 Bit Text Co...
Forum: Source Code Library
Last Post: Andy Dee
04-03-2025, 10:55 PM
» Replies: 0
» Views: 70
|
Bug found: →
Forum: PowerBASIC for DOS
Last Post: Andy Dee
03-12-2025, 02:50 PM
» Replies: 5
» Views: 405
|
$EOF when using Line Inpu...
Forum: PowerBASIC Console Compiler
Last Post: Albert Richheimer
03-12-2025, 08:25 AM
» Replies: 0
» Views: 114
|
The LeapYear
Forum: Programming
Last Post: Dale Yarker
03-09-2025, 09:18 PM
» Replies: 11
» Views: 678
|
Leap days (or not) in Feb...
Forum: Source Code Library
Last Post: Andy Dee
03-09-2025, 05:05 PM
» Replies: 2
» Views: 229
|
Turning http to https?
Forum: Suggestions and discussion about PUMP
Last Post: Andy Dee
03-06-2025, 07:50 PM
» Replies: 2
» Views: 226
|
PBDOS -- Where The Love A...
Forum: PowerBASIC for DOS
Last Post: Andy Dee
03-06-2025, 01:30 PM
» Replies: 9
» Views: 1,335
|
2003 Podcast featuring Po...
Forum: This and that - friendly chat
Last Post: Frank Ferrell
02-22-2025, 09:08 PM
» Replies: 0
» Views: 110
|
Promoting PowerBASIC docu...
Forum: PowerBASIC Documentation
Last Post: Frank Ferrell
02-10-2025, 02:02 AM
» Replies: 3
» Views: 760
|
Calling opcode string dis...
Forum: Programming
Last Post: Charles Pegge
02-06-2025, 06:42 AM
» Replies: 25
» Views: 2,298
|
|
|
PB 3.5 8-to-7 Bit Text Compression |
Posted by: Andy Dee - 04-03-2025, 10:55 PM - Forum: Source Code Library
- No Replies
|
 |
Hello everyone,
I developed a method to compress short texts by reducing 8-bit characters to 7-bit. While the compression ratio is low for large files, it efficiently reduces small strings.
Key Steps:
- Normalization: The input text is restricted to 7-bit ASCII (32–127).
- Offset Adjustment: Each character is decremented by 32 to fit within 0–95.
- Compression:
For every 8 bytes, extract bits 0–6 (discarding bit 7).Pack these 7-bit segments into 7 bytes, using all 8 bits per byte.
- Remaining Bytes: If the text length isn’t a multiple of 8, the last 1–7 bytes are copied uncompressed.
- Decompression:
Reverse the process: Expand 7-bit segments to 8 bits, then increment by 32.
Here is the code, including some testing:
Code: $Compile exe
$Dim All
$Lib All Off
$Error All Off
$String 2
$Com 0
$Float Procedure
$Optimize Size'Speed
$Cpu 80386
$Sound 1
$Stack 1536
'----------------------------------------------------------------------------
' Packe limitierten Text von 8 auf 7 Bit.
' Nutze dafür Zeiger zum Erhöhen der Geschwindigkeit
Declare _
FUNCTION PackTxt87 (sQuelle AS STRING) AS STRING
FUNCTION PackTxt87 (sQuelle AS STRING) AS STRING
' lokale Variablen
DIM iQlen AS LOCAL INTEGER ' Länge von sQuelle
DIM Q_ptr AS LOCAL BYTE PTR ' Zeichen-Pointer auf sQuelle
Dim sZiel As Local String ' Komprimiertes sZiel
DIM iZlen AS LOCAL INTEGER ' Länge von sZiel
DIM Z_ptr AS LOCAL BYTE PTR ' Zeichen-Pointer auf sZiel
DIM iZPos AS LOCAL INTEGER ' Position in sZiel
DIM iQPos AS LOCAL INTEGER ' Position in sQuelle
DIM iQLoop AS LOCAL INTEGER ' Anzahl KompressionsSchleifen
DIM iKompS AS LOCAL INTEGER ' Anzahl komprimierbarer Zeichen
Dim iRest As Local Integer ' Anzahl unkomprimierbarer Zeichen
Dim bWert As Local Byte ' ASCII-32-Wert eines Zeichens.
Dim iBitQ As Local Integer ' Aktuelle Bitbosition in sQuelle
Dim iBitZ As Local Integer ' Aktuelle Bitbosition in sZiel
Dim sTemp As Local String
'
iQlen = LEN(sQuelle) ' Hole Länge der Quelle
'--------------------------------------------------------------------------
' Fehler 1 abfangen
If iQlen < 8 Then _ ' String zu kurz?
Function = sQuelle: _ ' Gib Original zurück
Exit Function ' und raus
iQLoop = Fix(iQlen/8) ' Hole Anzahl KompressionsSchleifen
iRest = iQlen Mod 8 ' Hole Anzahl unkomprimierbarer Zeichen
iKompS = iQLoop * 8 ' Hole Anzahl komprimierbarer Zeichen
iZlen = iQLoop * 7 + iRest ' Hole Länge komprimierten Strings
'
DECR iQlen ' Null-basiert für Pointer
Q_ptr = STRPTR32( sQuelle ) ' Setze Pointer auf sQuelle
'--------------------------------------------------------------------------
' Fehler 2 abfangen
For iQPos = 0 To iQlen ' Überprüfe auf ungültige Zeichen
IF @Q_ptr[iQPos] < 32 _
Or @Q_ptr[iQPos] > 159 _
THEN
sZiel = sZiel _ ' sammle diese
+ Chr$(@Q_ptr[iQPos])
End If
Next iQPos
If Len(sZiel) Then _
Function = "Falsche Quelle: "+sZiel : _
Exit Function ' und gib sie zurück
sZiel = Repeat$(iZlen,Chr$(0)) ' Platz für Kompression in sZiel
Z_ptr = STRPTR32( sZiel ) ' Setze Pointer auf sZiel
iZPos = 0 ' Position im Pointer = 0
iBitQ = 0 ' Bitbosition in sQuelle auf 0
iBitZ = 0 ' Bitbosition in sZiel auf 0
DECR iKompS ' Null-basiert für Pointer
'--------------------------------------------------------------------------
' Kompression:
For iQPos = 0 To iKompS ' Für komprimierbare Zeichen in sQuelle:
' 1. Schritt:
bWert = @Q_ptr[iQPos] - 32 ' ASCII-Wert um 32 vermindern, dass
' ASCII zwischen 0-159 ist
For iBitQ = 0 To 6 ' Lies aus sQuelle Bit 0-6
If Bit(bWert,iBitQ) = 1 Then ' Schreibe Ziel-Bits 0-7
Bit Set @Z_ptr[iZPos], iBitZ '
Else '
Bit ReSet @Z_ptr[iZPos], iBitZ '
End If
If iBitZ < 7 Then ' Solange in Ziel zwischen Bit 0 und 7
Incr iBitZ ' Nächstes Bit
Else ' sonst
iBitZ = 0 ' Bit 0 in
Incr iZPos ' nächstem Zeichen
End If
Next iBitQ
Next iQPos
iZPos = iZlen-iRest ' Setze Zeiger auf erstes unpackbares
' Zeichen
For iQPos = iQlen-iRest+1 To iQlen ' Für unpackbare Zeichen in sQuelle
@Z_ptr[iZPos] = @Q_ptr[iQPos] ' Schreibe unpackbare Zeichen
Incr iZPos
Next iQPos
Function = sZiel
END FUNCTION
'----------------------------------------------------------------------------
' EntPacke limitierten Text von 8 auf 7 Bit.
' Nutze dafür Zeiger zum Erhöhen der Geschwindigkeit
Declare _
FUNCTION DePackTxt87 (sQuelle AS STRING) AS STRING
FUNCTION DePackTxt87 (sQuelle AS STRING) AS STRING
' lokale Variablen
DIM iQlen AS LOCAL INTEGER ' Länge von sQuelle
DIM Q_ptr AS LOCAL BYTE PTR ' Zeichen-Pointer auf sQuelle
Dim sZiel As Local String ' Komprimiertes sZiel
DIM iZlen AS LOCAL INTEGER ' Länge von sZiel
DIM Z_ptr AS LOCAL BYTE PTR ' Zeichen-Pointer auf sZiel
DIM iZPos AS LOCAL INTEGER ' Position in sZiel
DIM iQPos AS LOCAL INTEGER ' Position in sQuelle
DIM iQLoop AS LOCAL INTEGER ' Anzahl KompressionsSchleifen
DIM iKompS AS LOCAL INTEGER ' Anzahl komprimierbarer Zeichen
Dim iRest As Local Integer ' Anzahl unkomprimierbarer Zeichen
Dim bWert As Local Byte ' ASCII-32-Wert eines Zeichens.
Dim iBitQ As Local Integer ' Aktuelle Bitbosition in sQuelle
Dim iBitZ As Local Integer ' Aktuelle Bitbosition in sZiel
Dim sTemp As Local String
Dim bPack As Local Byte ' Gepackte Bytes an sQuelleEnde
iQlen = LEN(sQuelle) ' Hole Länge der Quelle
'--------------------------------------------------------------------------
' Fehler 1 abfangen
If iQlen < 7 Then _ ' String zu kurz?
Function = sQuelle: _ ' Gib Original zurück
Exit Function ' und raus
Q_ptr = STRPTR32( sQuelle ) ' Setze Pointer auf sQuelle
iQLoop = Fix(iQlen/7) ' Hole Anzahl EntPacksSchleifen
iRest = iQlen Mod 7 ' Anzahl ungepackte Zeichen?
'--------------------------------------------------------------------------
' Fehler 2 abfangen
If iRest = 0 Then ' Scheint alles gepackt zu sein, dann
bPack = 0 ' GePacktes = 0
For iQPos = iQlen - 7 To iQlen-1 ' Überprfe letzte 7 Zeichen auf
IF @Q_ptr[iQPos] < 32 _ ' komprimierte Zeichen
Or @Q_ptr[iQPos] > 127 _ ' Wenn welche da, dann
THEN Incr bPack ' Erhöhe Gepacktes (bPack)
Next iQPos
End If
If bPack = 0? _ ' Wenn keine gepackten Zeichen (bPack)
And iRest = 0 _ ' und keine ungepackten Zeichen (iRest)
Then ' dann
iRest = 7 ' ungepackte Zeichen (iRest) = 7
iKompS = iQlen - iRest ' Setze Anzahl entpackbarer Zeichen
Else ' sonst
iKompS = iQLoop * 7 ' Setze Anzahl entpackbarer Zeichen
End If
If IsFalse(bPack) _ ' Sind die iRest-lichen Zeichen
And iRest = 7 _ ' ungepackt, dann reduziere
Then Decr iQLoop ' die Anzahl der Entpackaufrufe
iZlen = iQLoop * 8 + iRest ' Hole Länge komprimierten Strings
'
DECR iQlen ' Null-basiert für Pointer
sZiel = Repeat$(iZlen,Chr$(0)) ' Platz für Kompression in sZiel
Z_ptr = STRPTR32( sZiel ) ' Setze Pointer auf sZiel
iZPos = 0 ' Position im Pointer = 0
iBitQ = 0 ' Bitbosition in sQuelle auf 0
iBitZ = 0 ' Bitbosition in sZiel auf 0
'--------------------------------------------------------------------------
' DeKompression: Rechne Zeichen in sQuelle auf ASCII 32-159 um
For iQPos = 0 To iKompS ' Fr entkomprimierbare Zeichen in sQuelle:
' 1. Schritt:
For iBitQ = 0 To 7 ' Lies aus sQuelle Bit 0-7
If Bit(@Q_ptr[iQPos],iBitQ) = 1 Then ' Schreibe Ziel-Bits 0-7
Bit Set @Z_ptr[iZPos], iBitZ '
Else '
Bit ReSet @Z_ptr[iZPos], iBitZ '
End If
If iBitZ < 6 Then ' Solange in Ziel zwischen Bit 0 und 6
Incr iBitZ ' Nächstes Bit
Else ' sonst
iBitZ = 0 ' Bit 0
Incr @Z_ptr[iZPos], 32 ' Erstelle das richtige ZielZeichen
Incr iZPos ' und nächstes ZielZeichen
End If
Next iBitQ
Next iQPos
iZPos = iZlen-iRest ' Setze Zeiger auf erstes unpackbares
' Zeichen
For iQPos = iQlen-iRest+1 To iQlen ' Für ungepackte Zeichen in sQuelle
@Z_ptr[iZPos] = @Q_ptr[iQPos] ' Schreibe ungepackte Zeichen
Incr iZPos
Next iQPos
Function = sZiel
END FUNCTION
' Test-Code'
DIM originalText AS STRING, _
compressedText AS STRING, _
decompressedText AS STRING, _
iIndex As Integer, _
iLOrg As Integer, _
iLPck As Integer, _
iLEpk As Integer
For iIndex = 07 To 19
'?
originalText = Left$("PowerBASIC 3.5 is a wonderful tool for writing fast and usefull programs.",iIndex)
iLOrg = Len(originalText)
compressedText = PackTxt87(originalText)
iLPck = Len(compressedText)
If Instr(compressedText, "Falsche Quelle: ") = 1 Then ?compressedText:end
decompressedText = DePackTxt87(compressedText)
iLEpk = Len(decompressedText)
'PRINT "Original: ";
PRINT "Original: ";
Print originalText;
$If 0
Print " ist =";iLOrg;" Byte lang"
PRINT "Komprimiert: ";
Print compressedText;
Print " ist =";iLPck;" Byte lang"
PRINT "Dekomprimiert: ";
Print decompressedText;
Print " ist =";iLEpk;" Byte lang"
$EndIf
? " --> Test verlief: [erfolg";
If originalText = decompressedText Then
Print "reich] :-) :";iLOrg;iLPck;iLEpk
Else
Print "los] ;-(";iLOrg;iLPck;iLEpk
?"Original und wieder Entpacktes unterscheiden sich an folgenden Stellen:"
For iIndex = 1 To iLOrg
If ASCII(originalText,iIndex) <> ASCII(decompressedText,iIndex) Then
?"Position";iIndex;" - Zeichen Original: ";Chr$(ASCII(originalText,iIndex)); _
" - Zeichen Entpackt: ";Chr$(ASCII(decompressedText,iIndex))
End If
Next iIndex
End If
Next iIndex
Sleep
originalText = "PowerBASIC 3.5 is a wonderful tool for writing fast, small and usefull programs under DOS."
iLOrg = Len(originalText)
compressedText = PackTxt87(originalText)
iLPck = Len(compressedText)
If Instr(compressedText, "Falsche Quelle: ") = 1 Then ?compressedText:end
decompressedText = DePackTxt87(compressedText)
iLEpk = Len(decompressedText)
PRINT "Original:"
Print originalText;
? " --> Test verlief: [erfolg";
If originalText = decompressedText Then
Print "reich] :-) :";iLOrg;iLPck;iLEpk
Else
Print "los] ;-(";iLOrg;iLPck;iLEpk
?"Original und wieder Entpacktes unterscheiden sich an folgenden Stellen:"
For iIndex = 1 To iLOrg
If ASCII(originalText,iIndex) <> ASCII(decompressedText,iIndex) Then
?"Position";iIndex;" - Zeichen Original: ";Chr$(ASCII(originalText,iIndex)); _
" - Zeichen Entpackt: ";Chr$(ASCII(decompressedText,iIndex))
End If
Next iIndex
End If
PRINT "Komprimiert:"
Print compressedText
Print "ist =";iLPck;" Byte lang"
PRINT "Dekomprimiert:"
Print decompressedText
Print "ist =";iLEpk;" Byte lang"
originalText = "PowerBASIC 3.5 ist ein wundervolles Werkzeug fr schnelle, kleine bis groáe und vor allen ¯ntzliche® Programme unter DOS."
?originalText
iLOrg = Len(originalText)
compressedText = PackTxt87(originalText)
iLPck = Len(compressedText)
If Instr(compressedText, "Falsche Quelle: ") = 1 Then ?compressedText:end
decompressedText = DePackTxt87(compressedText)
iLEpk = Len(decompressedText)
PRINT "Original:"
Print originalText;
? " --> Test verlief: [erfolg";
If originalText = decompressedText Then
Print "reich] :-) :";iLOrg;iLPck;iLEpk
Else
Print "los] ;-(";iLOrg;iLPck;iLEpk
?"Original und wieder Entpacktes unterscheiden sich an folgenden Stellen:"
For iIndex = 1 To iLOrg
If ASCII(originalText,iIndex) <> ASCII(decompressedText,iIndex) Then
?"Position";iIndex;" - Zeichen Original: ";Chr$(ASCII(originalText,iIndex)); _
" - Zeichen Entpackt: ";Chr$(ASCII(decompressedText,iIndex))
End If
Next iIndex
End If
PRINT "Komprimiert:"
Print compressedText
Print "ist =";iLPck;" Byte lang"
PRINT "Dekomprimiert:"
Print decompressedText
Print "ist =";iLEpk;" Byte lang"
This is the DOS-output:
Code: Original: PowerBA --> Test verlief: [erfolgreich] :-) : 7 7 7
Original: PowerBAS --> Test verlief: [erfolgreich] :-) : 8 7 8
Original: PowerBASI --> Test verlief: [erfolgreich] :-) : 9 8 9
Original: PowerBASIC --> Test verlief: [erfolgreich] :-) : 10 9 10
Original: PowerBASIC --> Test verlief: [erfolgreich] :-) : 11 10 11
Original: PowerBASIC 3 --> Test verlief: [erfolgreich] :-) : 12 11 12
Original: PowerBASIC 3. --> Test verlief: [erfolgreich] :-) : 13 12 13
Original: PowerBASIC 3.5 --> Test verlief: [erfolgreich] :-) : 14 13 14
Original: PowerBASIC 3.5 --> Test verlief: [erfolgreich] :-) : 15 14 15
Original: PowerBASIC 3.5 i --> Test verlief: [erfolgreich] :-) : 16 14 16
Original: PowerBASIC 3.5 is --> Test verlief: [erfolgreich] :-) : 17 15 17
Original: PowerBASIC 3.5 is --> Test verlief: [erfolgreich] :-) : 18 16 18
Original: PowerBASIC 3.5 is a --> Test verlief: [erfolgreich] :-) : 19 17 19
Original:PowerBASIC 3.5 is a wonderful tool for writing fast, small and usefull
programs under DOS. --> Test verlief: [erfolgreich] :-) : 90 79 90
Komprimiert:
░τ╡(§àf⌐◄`Γ¿ ÆS@►p}:ëE⌐▒╩♦PƒO&└°ö☻«╥$5Θ<☻î┴)ò☺ÿ6âL& Φ$☻¬╙ó▒╩d☻á╥τQ→lN☺U'▒(♣É^S.
ist = 79 Byte lang
Dekomprimiert:
PowerBASIC 3.5 is a wonderful tool for writing fast, small and usefull programs
under DOS.
ist = 90 Byte lang
PowerBASIC 3.5 ist ein wundervolles Werkzeug für schnelle, kleine bis große und
vor allen »nützliche« Programme unter DOS.
Falsche Quelle: ᯮ
Perhaps the code will also be of use to others...
|
|
|
$EOF when using Line Input# |
Posted by: Albert Richheimer - 03-12-2025, 08:25 AM - Forum: PowerBASIC Console Compiler
- No Replies
|
 |
Source code moved from PB DOS over here, in reply to @Andy Dee:
Code: #compile exe
#dim all
function pbmain () as long
local hFile as long
local sFile as string
local sTemp as string
'
' Setup strings
' -------------
'
sTemp = "ABCDEF" + $EOF + "abcdef"
sFile = "Data.txt"
'
' Create Data.txt
' ---------------
'
hFile = freefile
open sFile for output as #hFile
print #hFile,sTemp;
close #hFile
'
' Read Data.txt using get$
' ------------------------
'
hFile = freefile
open sFile for binary as #hFile
get$ #hFile,lof(hFile),sTemp
close #hFile
stdout "Using get$: "+sTemp
'
' Read Data.txt using line input#
' -------------------------------
'
hFile = freefile
open sFile for input as #hFile
line input #hFile,sTemp
close #hFile
stdout "Using line input#: "+sTemp
'
' Clean up
' --------
'
kill sFile
end function
|
|
|
Leap days (or not) in February for PBDOS |
Posted by: Dale Yarker - 03-08-2025, 08:48 AM - Forum: Source Code Library
- Replies (2)
|
 |
'DECLARE not needed if FUNCTION source is before the CALL
'here the CALL is in PBMAIN
'I call it bottom up because PBMAIN is last and flow goes up
'
'Pretty sure PUSHes and POPs not needed in FUNCTION
'They will be needed to use "inside" code in-line with BASIC
'
'Used PBCC v6 to test. I no longer have PBDOS available.
function Tage_im_Februar(byval iJahr as integer) as integer
local FebruarTage as integer
! push ax
! mov FebruarTage, 28& 'not a leap year, pre-set to 28
! mov ax, 1582%
! cmp ax, iJahr
! jge Julian
! mov ax, 3%
! and ax, iJahr 'conditionally equivalent MOD 4
! jz MOD100 '0 is possible leap year
! jmp Done
MOD100:
! push bx 'for divisor
! push dx 'for high part of dividend, remainder (MOD)
! xor dx, dx
! mov ax, iJahr
! mov bx, 100%
! div bx
! cmp dx, 0% 'does MOD 100 = 0 ?
! pop dx
! pop bx
! jz MOD400 '0 is possibly not a leap year
! jmp Is29Days 'non 0 is a leap year
MOD400:
! and ax, 3% 'EAX has Year\100, so conditionally equivalent MOD 400
! jnz Done
Julian:
! mov ax, 3%
! and ax, iJahr
! jnz Done
Is29Days:
! mov FebruarTage, 29%
Done:
! pop ax
function = FebruarTage
end function
function pbmain () as long 'put only to demonstrate Tage_im_Februar
local iJahr as integer
iJahr = 2000
print Tage_im_Februar(iJahr); " 2000, divisible by 400, is leap"
iJahr = 2100
print Tage_im_Februar(iJahr); " 2100, divisible by 100 not 400, not leap"
iJahr = 2104
print Tage_im_Februar(iJahr); " 2104, divisible by 4 not 100, is leap"
iJahr = 2103
print Tage_im_Februar(iJahr); " 2103, not divide 4, not leap
print "julian, did not check rule for prior to Gregorian myself"
iJahr = 1204
print Tage_im_Februar(iJahr); " 1204, divisible by 4, is leap
iJahr = 1201
print Tage_im_Februar(iJahr) " 1201, not divisible by 4, not leap
waitkey$
end function
|
|
|
The LeapYear |
Posted by: Andy Dee - 03-07-2025, 04:09 PM - Forum: Programming
- Replies (11)
|
 |
Here, Dale Yarker shows a fast Way to find a Leap Year.
This looks very nice - for 32-Bit Systems.
Programming in 16-Bit PB 3.5 for DOS, I can only make eyes… 
I use a much slower routine, calculating results for julian and gregorian calendar.
Code: Declare _
Function iFeb(ByVal iJahr As Integer) As Integer
Function iFeb(ByVal iJahr As Integer) Public As Integer
If iJahr < 1582% then
Function = 29% _
+ ( _
( _
iJahr Mod 4% _
) _
<> 0% _
)
Else
Function = 29% _
+ ( _
( _
iJahr/4 _
) _
<> _
( _
iJahr\4 _
) _
Or _
( _
iJahr/100 _
) _
= _
( _
iJahr\100 _
) _
And _
( _
iJahr/400 _
) _
<> _
( _
iJahr\400 _
) _
)
End If
End Function
Does someone has an idea, how this could look in 16-Bit-Inline-Asm?
|
|
|
Bug found: → |
Posted by: Andy Dee - 03-07-2025, 12:32 PM - Forum: PowerBASIC for DOS
- Replies (5)
|
 |
Hello everyone
In a text block commented out with $If 0 - $EndIF, the control character "→" appears at some point. This causes PB 3.5 to assume that the file ends here, which is acknowledged with error 436 during compilation.
There used to be this bug with the "ü", but it was fixed quite quickly.
Perhaps of interest and use to someone.
Andy
Edit:
Dieser Fehler tritt auch beim Auskommentieren mit "'" oder "Rem" auf.
Edit 2 (sorry for German language):
This error also occurs when commenting out with “'” or “Rem”.
|
|
|
Detect QEMU Virtual Machine |
Posted by: Anne Wilson - 01-29-2025, 09:39 PM - Forum: Source Code Library
- No Replies
|
 |
This program will detect if it is being run in a QEMU Virtual Machine VM.
Note that hackers will place your programs to run in a VM so that they can
pirate or hack your programs.
This is to detect whether the user is using a QEMU VM and to do the
necessary counter action.
Please let me know if you encounter issue with this program.
Code: ' Detect QEMU.bas
' This program uses multiple detection methods for QEMU VM to increase accuracy.
' However, no single method is foolproof, as virtualization environments
' can be customized or masked by hackers.
#COMPILE EXE
#DIM ALL
#INCLUDE "Win32Api.inc"
%KEY_QUERY_VALUE = &H0001
%ERROR_SUCCESS = 0
'============================
FUNCTION PBMAIN () AS LONG
IF IsQEMU() THEN
? "Running inside a QEMU virtual machine."
ELSE
? "Not running inside a QEMU virtual machine."
END IF
END FUNCTION
'===============================
' Detects QEMU VM using several methods
FUNCTION IsQEMU() AS LONG
LOCAL hqeKey AS DWORD
LOCAL dwType AS DWORD
LOCAL dwData AS DWORD
LOCAL cbData AS DWORD
LOCAL qresult AS LONG
' Indicator for various QEMU types
LOCAL tmpQe AS LONG
tmpQe = 0
' Check for QEMU-specific registry key (System Manufacturer)
' HARDWARE\DESCRIPTION\System\BIOS
qresult = RegOpenKeyEx(%HKEY_LOCAL_MACHINE, hwBios, 0, %KEY_QUERY_VALUE, hqeKey)
IF qresult = %ERROR_SUCCESS THEN
cbData = 256
' SystemManufacturer
qresult = RegQueryValueEx(hqeKey, SysManf , 0, dwType, BYVAL VARPTR(dwData), cbData)
IF qresult = %ERROR_SUCCESS THEN
'QEMU
IF INSTR(UCASE$(PEEK$(VARPTR(dwData), cbData)), StQE) > 0 THEN
tmpQe = 1
END IF
END IF
RegCloseKey hqeKey
END IF
IF tmpQe > 0 THEN
IsQEMU = 1
EXIT FUNCTION
END IF
' Check for QEMU-specific driver (qxl.sys or virtio drivers)
' such as QXL video adapter or VirtIO devices
' C:\Windows\System32\drivers\qxl.sys and
' C:\Windows\System32\drivers\vioinput.sys
IF ISFILE(qxlS ) OR ISFILE(vioinp) THEN
tmpQe = 2
END IF
IF tmpQe > 0 THEN
IsQEMU = 1
EXIT FUNCTION
END IF
' Check for QEMU-specific hardware (QXL video or VirtIO devices)
' C:\Windows\System32\drivers\qxl.dll and
' C:\Windows\System32\drivers\viostor.sys
IF ISFILE(stQxl) OR ISFILE(stVio) THEN
tmpQe = 3
END IF
IF tmpQe > 0 THEN
IsQEMU = 1
EXIT FUNCTION
END IF
' Not running inside QEMU
IsQEMU = 0
END FUNCTION
' ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
' C:\Windows\System32\drivers\vioinput.sys
FUNCTION vioinp() AS STRING
' Text is 40 bytes excluding the terminating zero
#REGISTER NONE
LOCAL src AS DWORD
LOCAL dst AS DWORD
LOCAL outpt$
src = CODEPTR(datalabel)
outpt$ = NUL$(40)
dst = STRPTR(outpt$)
' -------------------
' copy data to string
' -------------------
! mov esi, src
! mov edi, dst
! mov ecx, 40
! rep movsb
src = CODEPTR(paddlabel)
' -----------------------------
' xor string data to unique pad
' -----------------------------
! mov esi, dst
! mov ebx, 40
! mov edi, src
! add esi, ebx
! add edi, ebx
! neg ebx
lbl0:
! movzx eax, BYTE PTR [edi+ebx]
! xor [esi+ebx], al
! add ebx, 1
! jz lbl1
! movzx eax, BYTE PTR [edi+ebx]
! xor [esi+ebx], al
! add ebx, 1
! jz lbl1
! movzx eax, BYTE PTR [edi+ebx]
! xor [esi+ebx], al
! add ebx, 1
! jz lbl1
! movzx eax, BYTE PTR [edi+ebx]
! xor [esi+ebx], al
! add ebx, 1
! jnz lbl0
lbl1:
FUNCTION = outpt$
EXIT FUNCTION
#ALIGN 4
datalabel:
! db 137,244,134,19,90,252,4,157,27,48,199,3,14,247,228,3
! db 175,250,190,186,216,209,84,46,134,104,244,174,243,136,210,100
! db 103,146,120,43,36,182,157,78,0
#ALIGN 4
paddlabel:
! db 202,206,218,68,51,146,96,242,108,67,155,80,119,132,144,102
! db 194,201,140,230,188,163,61,88,227,26,135,242,133,225,189,13
! db 9,226,13,95,10,197,228,61,0
END FUNCTION
' ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
' ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
' C:\Windows\System32\drivers\qxl.sys
FUNCTION qxlS() AS STRING
' Text is 35 bytes excluding the terminating zero
#REGISTER NONE
LOCAL src AS DWORD
LOCAL dst AS DWORD
LOCAL outpt$
src = CODEPTR(datalabel)
outpt$ = NUL$(35)
dst = STRPTR(outpt$)
' -------------------
' copy data to string
' -------------------
! mov esi, src
! mov edi, dst
! mov ecx, 35
! rep movsb
src = CODEPTR(paddlabel)
' -----------------------------
' xor string data to unique pad
' -----------------------------
! mov esi, dst
! mov ebx, 35
! mov edi, src
! add esi, ebx
! add edi, ebx
! neg ebx
lbl0:
! movzx eax, BYTE PTR [edi+ebx]
! xor [esi+ebx], al
! add ebx, 1
! jz lbl1
! movzx eax, BYTE PTR [edi+ebx]
! xor [esi+ebx], al
! add ebx, 1
! jz lbl1
! movzx eax, BYTE PTR [edi+ebx]
! xor [esi+ebx], al
! add ebx, 1
! jz lbl1
! movzx eax, BYTE PTR [edi+ebx]
! xor [esi+ebx], al
! add ebx, 1
! jnz lbl0
lbl1:
FUNCTION = outpt$
EXIT FUNCTION
#ALIGN 4
datalabel:
! db 39,193,199,194,34,252,156,45,109,153,235,30,232,30,74,199
! db 100,250,27,119,124,175,212,177,7,207,147,66,236,149,73,81
! db 143,69,39,0
#ALIGN 4
paddlabel:
! db 100,251,155,149,75,146,248,66,26,234,183,77,145,109,62,162
! db 9,201,41,43,24,221,189,199,98,189,224,30,157,237,37,127
! db 252,60,84,0
END FUNCTION
' ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
' ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
'C:\Windows\System32\drivers\qxl.dll
FUNCTION stQxl() AS STRING
' Text is 35 bytes excluding the terminating zero
#REGISTER NONE
LOCAL src AS DWORD
LOCAL dst AS DWORD
LOCAL outpt$
src = CODEPTR(datalabel)
outpt$ = NUL$(35)
dst = STRPTR(outpt$)
' -------------------
' copy data to string
' -------------------
! mov esi, src
! mov edi, dst
! mov ecx, 35
! rep movsb
src = CODEPTR(paddlabel)
' -----------------------------
' xor string data to unique pad
' -----------------------------
! mov esi, dst
! mov ebx, 35
! mov edi, src
! add esi, ebx
! add edi, ebx
! neg ebx
lbl0:
! movzx eax, BYTE PTR [edi+ebx]
! xor [esi+ebx], al
! add ebx, 1
! jz lbl1
! movzx eax, BYTE PTR [edi+ebx]
! xor [esi+ebx], al
! add ebx, 1
! jz lbl1
! movzx eax, BYTE PTR [edi+ebx]
! xor [esi+ebx], al
! add ebx, 1
! jz lbl1
! movzx eax, BYTE PTR [edi+ebx]
! xor [esi+ebx], al
! add ebx, 1
! jnz lbl0
lbl1:
FUNCTION = outpt$
EXIT FUNCTION
#ALIGN 4
datalabel:
! db 107,242,156,222,105,186,235,71,251,111,207,178,223,54,223,160
! db 48,66,192,5,85,78,114,228,105,10,125,30,253,8,13,29
! db 29,250,74,0
#ALIGN 4
paddlabel:
! db 40,200,192,137,0,212,143,40,140,28,147,225,166,69,171,197
! db 93,113,242,89,49,60,27,146,12,120,14,66,140,112,97,51
! db 121,150,38,0
END FUNCTION
' ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
' ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
' C:\Windows\System32\drivers\viostor.sys
FUNCTION stVio() AS STRING
' Text is 39 bytes excluding the terminating zero
#REGISTER NONE
LOCAL src AS DWORD
LOCAL dst AS DWORD
LOCAL outpt$
src = CODEPTR(datalabel)
outpt$ = NUL$(39)
dst = STRPTR(outpt$)
' -------------------
' copy data to string
' -------------------
! mov esi, src
! mov edi, dst
! mov ecx, 39
! rep movsb
src = CODEPTR(paddlabel)
' -----------------------------
' xor string data to unique pad
' -----------------------------
! mov esi, dst
! mov ebx, 39
! mov edi, src
! add esi, ebx
! add edi, ebx
! neg ebx
lbl0:
! movzx eax, BYTE PTR [edi+ebx]
! xor [esi+ebx], al
! add ebx, 1
! jz lbl1
! movzx eax, BYTE PTR [edi+ebx]
! xor [esi+ebx], al
! add ebx, 1
! jz lbl1
! movzx eax, BYTE PTR [edi+ebx]
! xor [esi+ebx], al
! add ebx, 1
! jz lbl1
! movzx eax, BYTE PTR [edi+ebx]
! xor [esi+ebx], al
! add ebx, 1
! jnz lbl0
lbl1:
FUNCTION = outpt$
EXIT FUNCTION
#ALIGN 4
datalabel:
! db 249,253,198,251,223,113,140,156,245,139,234,192,79,79,251,90
! db 10,141,82,54,82,155,166,16,138,158,122,123,208,158,228,122
! db 211,170,16,201,173,76,240,0
#ALIGN 4
paddlabel:
! db 186,199,154,172,182,31,232,243,130,248,182,147,54,60,143,63
! db 103,190,96,106,54,233,207,102,239,236,9,39,166,247,139,9
! db 167,197,98,231,222,53,131,0
END FUNCTION
' ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
' ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
' QEMU
FUNCTION StQE() AS STRING
#REGISTER NONE
LOCAL pstr AS DWORD
LOCAL a$
a$ = NUL$(4)
pstr = STRPTR(a$)
! mov esi, pstr
! mov BYTE PTR [esi+0], 81
! mov BYTE PTR [esi+2], 77
! mov BYTE PTR [esi+1], 69
! mov BYTE PTR [esi+3], 85
FUNCTION = a$
END FUNCTION
' ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
' ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
' SystemManufacturer
FUNCTION SysManf() AS STRING
#REGISTER NONE
LOCAL pstr AS DWORD
LOCAL a$
a$ = NUL$(18)
pstr = STRPTR(a$)
! mov esi, pstr
! mov BYTE PTR [esi+14], 117
! mov BYTE PTR [esi+5], 109
! mov BYTE PTR [esi+9], 117
! mov BYTE PTR [esi+16], 101
! mov BYTE PTR [esi+15], 114
! mov BYTE PTR [esi+17], 114
! mov BYTE PTR [esi+11], 97
! mov BYTE PTR [esi+8], 110
! mov BYTE PTR [esi+13], 116
! mov BYTE PTR [esi+3], 116
! mov BYTE PTR [esi+4], 101
! mov BYTE PTR [esi+2], 115
! mov BYTE PTR [esi+0], 83
! mov BYTE PTR [esi+1], 121
! mov BYTE PTR [esi+7], 97
! mov BYTE PTR [esi+12], 99
! mov BYTE PTR [esi+6], 77
! mov BYTE PTR [esi+10], 102
FUNCTION = a$
END FUNCTION
' ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
' ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
' HARDWARE\DESCRIPTION\System\BIOS
FUNCTION hwBios() AS STRING
#REGISTER NONE
LOCAL pstr AS DWORD
LOCAL a$
a$ = NUL$(32)
pstr = STRPTR(a$)
! mov esi, pstr
! mov BYTE PTR [esi+28], 66
! mov BYTE PTR [esi+29], 73
! mov BYTE PTR [esi+27], 92
! mov BYTE PTR [esi+17], 73
! mov BYTE PTR [esi+4], 87
! mov BYTE PTR [esi+30], 79
! mov BYTE PTR [esi+20], 92
! mov BYTE PTR [esi+16], 84
! mov BYTE PTR [esi+21], 83
! mov BYTE PTR [esi+25], 101
! mov BYTE PTR [esi+31], 83
! mov BYTE PTR [esi+12], 67
! mov BYTE PTR [esi+15], 80
! mov BYTE PTR [esi+22], 121
! mov BYTE PTR [esi+9], 68
! mov BYTE PTR [esi+1], 65
! mov BYTE PTR [esi+3], 68
! mov BYTE PTR [esi+6], 82
! mov BYTE PTR [esi+0], 72
! mov BYTE PTR [esi+18], 79
! mov BYTE PTR [esi+23], 115
! mov BYTE PTR [esi+11], 83
! mov BYTE PTR [esi+7], 69
! mov BYTE PTR [esi+19], 78
! mov BYTE PTR [esi+26], 109
! mov BYTE PTR [esi+8], 92
! mov BYTE PTR [esi+2], 82
! mov BYTE PTR [esi+5], 65
! mov BYTE PTR [esi+10], 69
! mov BYTE PTR [esi+13], 82
! mov BYTE PTR [esi+14], 73
! mov BYTE PTR [esi+24], 116
FUNCTION = a$
END FUNCTION
' ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
|
|
|
|