/* This file shows examples of the additions made to zeus-ish in v2.20..v2.22 If you want more sustantial files they're available at www.desdes.com Timestamps ---------- Version 2.20 adds a predefine string variable "timestr" or "TIMESTR" which contains the time/date at which assembly takes place (according to the local clock) in a human-readible form. This can be used to add a timestamp to the code as follows: db TIMESTR This is not as useful as it might be - my development tools implant the modification date in source files so that TIMESTR is only updated when the files are edited. Assembling the same files repeatedly doesn't alter the time implanted; it's hard to see how this functionallity could be duplicated for zeusish - I can't use the dos filestamps because the files may be saved before every assembly cycle and I can't assume my editor is being used... New numeric functions --------------------- Version 2.20 adds LOW, HIGH, WORD, ZEUSRAND LOW returns the least significant byte, HIGH returns the next most significant byte. They're useful for loading a 16-bit value into 8-bit registers. WORD returns the least significant word (16-bits). It's useful for loading a 16-bit value from a 32-bit value; perhaps when writing code for a paged-memory design. Fred equ $12345678 ld c,low Fred ; c := $78 ld b,high Fred ; b := $56 ld hl,word Fred ; hl := $5678 ZEUSRAND returns a 32-bit signed random number. (From version v2.22 this uses the Mersenne Twister generator) Note that using random numbers can introduce tricky problems - consider what happens during multiple passes; does a single zeusrand statement always return the same value on each pass? If it does not and this difference causes some labels to be moved, then zeus may consider that the pass needs to be repeated and so on ad infinitum, or at least until zeus gives up - a fatal assembly error. However, I've thought about that and unless you go to some trouble the answer is yes, any given zeusprint statement will return the same number on each pass of a single assembly cycle - obviously each assembly cycle (each time you click assemble) may produce a different value (it wouldn't be particularly random otherwise). By way of example consider the following repulsive idea - suppose we want to randomly move code about between different versions of an application, say for the purposes of obsfucation. You might decide to plant a random number of bytes somewhere so that everything gets moved about a bit during each development cycle. Something like this, perhaps: ; Plant a random amount of random data... mRandomSpace macro(malign_size) loop abs(ZEUSRAND) mod (malign_size+1) db ZEUSRAND lend mend So the idea is that invoking this macro plants a random number of random bytes. mRandomSpace(16) <- 0 .. 16 random bytes mRandomSpace(256) <- 0 .. 256 random bytes And so on. Well, does this work? Yes, it does... Have fun ;) If you want more deterministic randomness you can apply a fixed seed to zeusrand as follows: zeusrand seedvalue ... where seedvalue is a 32-bit integer expression. This will cause subsequent calls to zeusrand to return a fixed series of pseudo-random values. Encrypted data -------------- Version 2.20 adds a simple way to hide data from casual inspection; text strings for example. Note that this is not intended for anything serious, it's just for the purposes of obsfucation. The two new statements are DBX (Define-Byte XOR'd) and DBXO (DBX Offset) and they are used as follows: To plant obscured data use dbx instead of db. The syntax is: dbx xor-value, data [,data] Where xor-value is a byte that is to xor'd with the data. Eg: dbx $FF,"Hello!" This puts 6 bytes in memory, where the bytes are the characters of the string "Hello!" each xor'd with $FF. Since xoring with a fixed value doesn't add much obscurity zeus allows you to have the xor value change after every time it is used (after every byte) and zeus does this by adding a fixed value to the xor value every time it is used. Normally this value is zero, so that the xor is constant, but you can choose to set something other than zero by using the dbxo statement. Eg: dbxo 1 dbx $42,"Hello!" This puts 6 bytes in memory, where the bytes are the characters of the string "Hello!" with the first byte xor'd with $42, the second byte xor'd with $43 and so on. I'd suggest using a dbxo value that is prime and in the range 17 .. 61, and deriving a different starting XOR value from the data's address - that will be available to whatever is decoding it. Speaking of obsfucation, this macro can be useful. It acts like align but fills with random bytes, so things aren't so obvious... mAlignRandomFill macro(Alignment) while ( * mod Alignment) <> 0 db zeusrand wend mend See the example code at the end of this file for ideas... New memory checksum functions ----------------------------- Version 2.20 adds SUM_MEM and XOR_MEM SUM_MEM and XOR_MEM are functions that will run through the Z80 code planted by zeus and calculate a byte sum of a range of bytes, or the xor sum of a range of bytes. These can be used to calculate the correct checksum for a block of memory so that the code running can check for changes/errors. Obviously these must be used with care - if the calculated result is planted as data that lives in the range of memory being calculated it will alter the results of any dynamic calculation made later. The obvious way to use these calculations is to include the calculated bytes at the end of the range modified so that they, for example, make checks over this larger range return zero. eg: CS_Start equ * db "Put whatever you like here" dd " code or data" ; Add a byte which makes the block XOR to zero db XOR_MEM(CS_Start,* - CS_Start) CS_Length equ * - CS_Start Now, if the application calculates the XOR of memory starting at CS_Start for CS_Length bytes the result will be zero - the byte zeus calculated will cancel the rest out. With a bit of thought it is possible to use these two functions to add three bytes to any block of data so that both an XOR and a SUM of the total return zero; I leave this as an exercise for the alert reader. Scoping operator ---------------- Version 2.20 adds a new scoping operator "::" - prefixing a label with this causes zeus to use the global symbol table for that symbol access regardless of the references location. This has been added so that global symbols can be manipulated from inside procedures or macros. Consider the following code: Total = 0 ; Init the total Count macro() ; Total = Total+1 ; This doesn't work! mend ; That looks like a simple macro which just adds one to the value Total every time it is invoked - but it does not work. The problem is that the "Total=expression" does not write a new value to the global variable "Total", what it does is declare a new local variable "Total" inside the scope of the macro. This is probably not what the user intended... Total = 0 ; Init the total Count macro() ; ::Total = ::Total+1 ; This does work! mend ; With the scoping operator :: prepended this now does what the user intended. Note: Since zeus will look in the global symbol table for any symbols it doesn't find in the local symbol table, the second scope override isn't strictly required. The following will also work "::Total = Total+1" as long as there aren't any local labels called "Total" declared in the macro. Increased code memory --------------------- Version 2.20 of zeus increases the code memory supported by zeus to $40000 (256K) This may ease software development for systems which have paged memory. Then again, it may not - unfortunately I haven't yet extended the szx output to support more than 64K; I don't have the file format documentation to hand. Zeus can now use segments and/or displacements either from ORG statements or DISP statements to place code in a larger space than 64K. Note that you can save fragments of this large space in multiple file using multiple output statements. */ ; Example ZX Spectrum (48K) source to demonstrate DBX/DBXO/ZEUSRAND/ADD_MEM/XOR_MEM ; ; This shows how to use XOR_SUM and ADD_SUM so that changes to the ; code (loading errors or hacking, etc) can be detected. ; ; This just skims the surface of anti-piracy and anti-hacking concepts. ; zeusemulate "48K" ; Let's be a Spectrum 48K ; Change this to suit your system - I note that Vista doesn't like changes to the root. output_szx "dbx.szx",0,Start ; Generate code to test ; First turn the flow warning off so zeus doesn't care we appear to execute data zoWarnFlow = false ; We don't want to be bothered with 'em ; Set the encryption XOR step value XOR_Inc equ 37 ; A reasonable value dbxo XOR_Inc ; Tell Zeus ; Print control codes cDel equ $08 ; cCret equ $0D ; cCls equ $0C ; cClr equ $1B ; cHome equ $0E ; ; Print colour select characters cBlack equ $00 ; cBlue equ $01 ; cRed equ $02 ; cMagenta equ $03 ; cGreen equ $04 ; cCyan equ $05 ; cYellow equ $06 ; cWhite equ $07 ; org $8000 ; Somewhere safe Start di ; Make sure we're not interrupted ld sp,0 ; Set the stack to the top of memory ld a,cCls ; Clear the screen call Print ; ; Show some encrypted messages embedded in the code call PrintEncStrFollow ; Print the encrypted string following this call dbx *,cCyan,"Hello! This was assembled at ",0 call PrintEncStrFollow ; Print the encrypted string following this call dbx *,cCret,TIMESTR,0 call PrintEncStrFollow ; Print the encrypted string following this call dbx *,cCret,cCret,cYellow,"If you look at the code you won't see",0 call PrintEncStrFollow ; Print the encrypted string following this call dbx *,cCret,cYellow,"any of this text...",0 ; Now, print some encrypted data that lives elsewhere ld hl,szMsg1 ; Point at an encrypted string call PrintEncStr ; And show it... ld hl,szMsg2 ; Point at an encrypted string call PrintEncStr ; And show it... ld hl,szMsg3 ; Point at an encrypted string call PrintEncStr ; And show it... ; Show the code length (changes randomly) ld hl,szLEN ; "LENGTH = " call PrintEncStr ; ld hl,CS_Length ; Show the code length call PrintHex_HL ; ; Show the checksum results ld hl,szXOR_CS ; "XOR CS = " call PrintEncStr ; ld hl,Start ; XOR all the bytes together ld bc,CS_Length ; call Calc_XOR_CS ; call PrintHex_A ; Show the result ld hl,szADD_CS ; "ADD CS = " call PrintEncStr ; ld hl,Start ; XOR all the bytes together ld bc,CS_Length ; call Calc_ADD_CS ; call PrintHex_A ; Show the result ; We're done... halt ; Stop all the excitement ; Add all the bytes of a block of memory Calc_ADD_CS xor a ; Clear the count CAC_Lp ld e,(hl) ; add a,e ; cpi ; INC HL, DEC BC jp v CAC_Lp ; Loop ret ; Done ; XOR all the bytes of a block of memory Calc_XOR_CS xor a ; Clear the count CXC_Lp ld e,(hl) ; xor e ; cpi ; INC HL, DEC BC jp v CXC_Lp ; Loop ret ; Done ; Data - the aligns are just here to make this obvious when you look at the Zeus Code tab ; so you can see how well obsfucated it is align 256 szMsg1 dbx *,cCret,cCret,cWhite,"If you look at the code you won't see",0 szMsg2 dbx *,cCret,cWhite,"this either.",0 szMsg3 dbx *,cCret,cCret,cGreen,"Exciting, isn't it? No? Oh well. Suit yourself...",0 szLEN dbx *,cCret,cCret,cCyan,"Code length is ",0 szXOR_CS dbx *,cCret,cCret,cCyan,"Memory XOR's to ",0 szADD_CS dbx *,cCret,cCret,cCyan,"Memory ADD's to ",0 align 256 /* Now, notice that you can't easily do stuff like the following: call PrintEncStrFollow ; Print the encrypted string following this call dbx *,cCyan,"Hello there!" dbx *,cCret,cYellow,"If you look at the code you won't see" dbx *,cCret,cYellow,"any of this text...",0 Why not? Well, because ALL the data has to be encoded by the SAME dbx statement if the decryption process is going to work - each dbx statement above restarts with a new XOR value. The print routine won't know this and so can't decode them correctly. */ ; Print the zero-terminated encrypted string pointed to by HL PrintEncStr proc ; push hl,bc,af ; ld b,l ; Get the low-byte of the address as the start XOR value Loop ld a,(hl) ; inc hl ; xor b ; Apply the encryption jr z,Exit ; If zero, we're done call Print ; ld a,b ; Now we update the running XOR value add a,XOR_Inc ; ld b,a ; jr Loop ; Exit pop af,bc,hl ; retp ; (RET) ; Print an encrypted string at (HL) PrintEncStrFollow proc ; ex (sp),hl ; push af,bc ; ld b,l ; Get the low-byte of the address as the start XOR value Loop ld a,(hl) ; inc hl ; xor b ; Apply the encryption jr z,Exit ; If zero, we're done call Print ; ld a,b ; Now we update the running XOR value add a,XOR_Inc ; ld b,a ; jr Loop ; Exit pop bc,af ; ex (sp),hl ; retp ; (RET) ; Print the contents of HL in hex PrintHex_HL ld a,h ; call PrintHex_A ; ld a,l ; ; Print the contents of A in hex PrintHex_A call PH2 ; PH2 rrca ; rrca ; rrca ; rrca ; push af ; and $0F ; add a,"0" ; cp "9"+1 ; jr c,PH3 ; add a,"A"-("9"+1) ; PH3 call Print ; pop af ; ret ; ; Print a space Print_Sp push af ; Save ld a,' ' ; Print a space call Print ; pop af ; Done ret ; ; A print character routine. Proportionally spaced characters Print push ix,hl,de,bc,af ; Save them cp cWhite+1 ; jr c,PrintColour ; cp cCls ; jr z,PrintCls ; cp cCret ; jr z,PrintCret ; cp cHome ; jr z,PrintHome ; ld h,PrintWidths/256 ; ld l,a ; ld a,(pCurX) ; add a,(hl) ; call c,PrintCret ; call PrintOutChar ; ld a,(pCurX) ; add a,(hl) ; ld (pCurX),a ; PrintExit pop af,bc,de,hl,ix ; ret ; ; Set a colour PrintColour cp 4 ; Above green don't make them bright jr nc,PrintCol1 ; or $40 ; Bright PrintCol1 ld (CurCol),a ; jr PrintExit ; ; Carriage return PrintCret call PrintDoCret ; jr PrintExit ; ; Clear screen - this clears it slowly with a fade effect PrintCls ld e,$00 ; ld hl,$5800 ; ld bc,$02FF ; pC1 ld a,(hl) ; and $07 ; jr z,pC2 ; set 0,e ; dec (hl) ; pC2 cpi ; jp pe,pC1 ; call Delay ; bit 0,e ; jr nz,PrintCls ; ld hl,$4000 ; ld de,$4001 ; ld bc,$1800 ; xor a ; ld (hl),a ; ldir ; ld a,(CurCol) ; ld (hl),a ; ld bc,$02FF ; ldir ; xor a ; out ($FE),a ; PrintHome xor a ; ld (pCurX),a ; ld (ppCurY),a ; ld a,cWhite ; ld (CurCol),a ; ld hl,$4000 ; ld (pCurY),hl ; jr PrintExit ; ; A suitable delay for the fade Delay push bc ; ld bc,1000 ; Del1 cpi ; dec hl ; jp pe,Del1 ; pop bc ; ret ; ; Do the carriage return PrintDoCret ld a,(ppCurY) ; inc a ; PrintSetUpY ld (ppCurY),a ; and $1F ; push hl ; ld l,a ; ld h,$00 ; add hl,hl ; ld de,YTable ; add hl,de ; ld a,(hl) ; inc hl ; ld h,(hl) ; ld l,a ; ld (pCurY),hl ; xor a ; ld (pCurX),a ; pop hl ; ret ; ; Output the character PrintOutChar bit 7,l ; characters $00..$7F only ret nz ; push hl ; ld h,0 ; add hl,hl ; add hl,hl ; add hl,hl ; ld de,PrintChars-256 ; add hl,de ; push hl ; pop ix ; ld a,(pCurX) ; rrca ; rrca ; rrca ; and $1F ; ld de,(pCurY) ; or e ; ld e,a ; push de ; ld a,d ; rrca ; rrca ; rrca ; and $03 ; or $58 ; ld d,a ; ld a,(CurCol) ; ld (de),a ; inc de ; ld (de),a ; pop de ; ld a,(pCurX) ; and $07 ; ld c,a ; ld b,$08 ; OutCharL ld h,(ix) ; ld l,$00 ; ld a,c ; or a ; jr z,OCL1 ; OCL2 srl h ; rr l ; dec a ; jr nz,OCL2 ; OCL1 ld a,(de) ; xor h ; ld (de),a ; inc e ; ld a,(de) ; xor l ; ld (de),a ; dec e ; inc ix ; inc d ; djnz OutCharL ; pop hl ; ret ; ; Screen addresses for the character rows YTable defw $4000,$4020,$4040,$4060 ; defw $4080,$40A0,$40C0,$40E0 ; defw $4800,$4820,$4840,$4860 ; defw $4880,$48A0,$48C0,$48E0 ; defw $5000,$5020,$5040,$5060 ; defw $5080,$50A0,$50C0,$50E0 ; defw 0,0,0,0,0,0,0,0 ; So running off the end isn't fatal ; Character set graphics mAlignRandomFill(256) ; Put these on page boundaries ; These are left aligned bitmaps. The character widths follow afterwards. PrintChars dg -------- dg -------- dg -------- dg -------- dg -------- dg -------- dg -------- dg -------- dg #------- dg #------- dg #------- dg #------- dg #------- dg -------- dg #------- dg -------- dg #-#----- dg #-#----- dg #-#----- dg -------- dg -------- dg -------- dg -------- dg -------- dg -#-#---- dg -#-#---- dg #####--- dg -#-#---- dg #####--- dg -#-#---- dg -#-#---- dg -------- dg --#----- dg -####--- dg #-#----- dg -###---- dg --#-#--- dg ####---- dg --#----- dg -------- dg ##------ dg ##--#--- dg ---#---- dg --#----- dg -#------ dg #--##--- dg ---##--- dg -------- dg -#------ dg #-#----- dg #-#----- dg -#------ dg #-#-#--- dg #--#---- dg -##-#--- dg -------- dg #------- dg #------- dg #------- dg -------- dg -------- dg -------- dg -------- dg -------- dg --#----- dg -#------ dg #------- dg #------- dg #------- dg -#------ dg --#----- dg -------- dg #------- dg -#------ dg --#----- dg --#----- dg --#----- dg -#------ dg #------- dg -------- dg --#----- dg #-#-#--- dg -###---- dg --#----- dg -###---- dg #-#-#--- dg --#----- dg -------- dg -------- dg --#----- dg --#----- dg #####--- dg --#----- dg --#----- dg -------- dg -------- dg -------- dg -------- dg -------- dg -------- dg -#------ dg -#------ dg #------- dg -------- dg -------- dg -------- dg -------- dg #####--- dg -------- dg -------- dg -------- dg -------- dg -------- dg -------- dg -------- dg -------- dg -------- dg -------- dg #------- dg -------- dg -------- dg ----#--- dg ---#---- dg --#----- dg -#------ dg #------- dg -------- dg -------- dg -###---- dg #---#--- dg #--##--- dg #-#-#--- dg ##--#--- dg #---#--- dg -###---- dg -------- dg --#----- dg -##----- dg --#----- dg --#----- dg --#----- dg --#----- dg -###---- dg -------- dg -###---- dg #---#--- dg ----#--- dg --##---- dg -#------ dg #------- dg #####--- dg -------- dg #####--- dg ----#--- dg ---#---- dg --##---- dg ----#--- dg #---#--- dg -###---- dg -------- dg ---#---- dg --##---- dg -#-#---- dg #--#---- dg #####--- dg ---#---- dg ---#---- dg -------- dg #####--- dg #------- dg ####---- dg ----#--- dg ----#--- dg #---#--- dg -###---- dg -------- dg --###--- dg -#------ dg #------- dg ####---- dg #---#--- dg #---#--- dg -###---- dg -------- dg #####--- dg ----#--- dg ---#---- dg --#----- dg -#------ dg -#------ dg -#------ dg -------- dg -###---- dg #---#--- dg #---#--- dg -###---- dg #---#--- dg #---#--- dg -###---- dg -------- dg -###---- dg #---#--- dg #---#--- dg -####--- dg ----#--- dg ---#---- dg ###----- dg -------- dg -------- dg -------- dg #------- dg -------- dg #------- dg -------- dg -------- dg -------- dg -------- dg -------- dg -#------ dg -------- dg -#------ dg -#------ dg #------- dg -------- dg ---#---- dg --#----- dg -#------ dg #------- dg -#------ dg --#----- dg ---#---- dg -------- dg -------- dg -------- dg #####--- dg -------- dg #####--- dg -------- dg -------- dg -------- dg #------- dg -#------ dg --#----- dg ---#---- dg --#----- dg -#------ dg #------- dg -------- dg -###---- dg #---#--- dg ---#---- dg --#----- dg --#----- dg -------- dg --#----- dg -------- dg -###---- dg #---#--- dg #-#-#--- dg #-###--- dg #-##---- dg #------- dg -####--- dg -------- dg --#----- dg -#-#---- dg #---#--- dg #---#--- dg #####--- dg #---#--- dg #---#--- dg -------- dg ####---- dg #---#--- dg #---#--- dg ####---- dg #---#--- dg #---#--- dg ####---- dg -------- dg -###---- dg #---#--- dg #------- dg #------- dg #------- dg #---#--- dg -###---- dg -------- dg ####---- dg #---#--- dg #---#--- dg #---#--- dg #---#--- dg #---#--- dg ####---- dg -------- dg #####--- dg #------- dg #------- dg ####---- dg #------- dg #------- dg #####--- dg -------- dg #####--- dg #------- dg #------- dg ####---- dg #------- dg #------- dg #------- dg -------- dg -####--- dg #------- dg #------- dg #------- dg #--##--- dg #---#--- dg -####--- dg -------- dg #---#--- dg #---#--- dg #---#--- dg #####--- dg #---#--- dg #---#--- dg #---#--- dg -------- dg ###----- dg -#------ dg -#------ dg -#------ dg -#------ dg -#------ dg ###----- dg -------- dg ----#--- dg ----#--- dg ----#--- dg ----#--- dg ----#--- dg #---#--- dg -###---- dg -------- dg #---#--- dg #--#---- dg #-#----- dg ##------ dg #-#----- dg #--#---- dg #---#--- dg -------- dg #------- dg #------- dg #------- dg #------- dg #------- dg #------- dg #####--- dg -------- dg #---#--- dg ##-##--- dg #-#-#--- dg #-#-#--- dg #---#--- dg #---#--- dg #---#--- dg -------- dg #---#--- dg #---#--- dg ##--#--- dg #-#-#--- dg #--##--- dg #---#--- dg #---#--- dg -------- dg -###---- dg #---#--- dg #---#--- dg #---#--- dg #---#--- dg #---#--- dg -###---- dg -------- dg ####---- dg #---#--- dg #---#--- dg ####---- dg #------- dg #------- dg #------- dg -------- dg -###---- dg #---#--- dg #---#--- dg #---#--- dg #-#-#--- dg #--#---- dg -##-#--- dg -------- dg ####---- dg #---#--- dg #---#--- dg ####---- dg #-#----- dg #--#---- dg #---#--- dg -------- dg -###---- dg #---#--- dg #------- dg -###---- dg ----#--- dg #---#--- dg -###---- dg -------- dg #####--- dg --#----- dg --#----- dg --#----- dg --#----- dg --#----- dg --#----- dg -------- dg #---#--- dg #---#--- dg #---#--- dg #---#--- dg #---#--- dg #---#--- dg -###---- dg -------- dg #---#--- dg #---#--- dg #---#--- dg #---#--- dg #---#--- dg -#-#---- dg --#----- dg -------- dg #---#--- dg #---#--- dg #---#--- dg #-#-#--- dg #-#-#--- dg ##-##--- dg #---#--- dg -------- dg #---#--- dg #---#--- dg -#-#---- dg --#----- dg -#-#---- dg #---#--- dg #---#--- dg -------- dg #---#--- dg #---#--- dg -#-#---- dg --#----- dg --#----- dg --#----- dg --#----- dg -------- dg #####--- dg ----#--- dg ---#---- dg --#----- dg -#------ dg #------- dg #####--- dg -------- dg #####--- dg ##------ dg ##------ dg ##------ dg ##------ dg ##------ dg #####--- dg -------- dg -------- dg #------- dg -#------ dg --#----- dg ---#---- dg ----#--- dg -------- dg -------- dg #####--- dg ---##--- dg ---##--- dg ---##--- dg ---##--- dg ---##--- dg #####--- dg -------- dg --#----- dg -###---- dg #-#-#--- dg --#----- dg --#----- dg --#----- dg -------- dg -------- dg -------- dg -------- dg -------- dg -------- dg -------- dg -------- dg #####--- dg -------- dg -------- dg -------- dg -------- dg -------- dg -------- dg -------- dg -------- dg -------- dg -------- dg -------- dg -##-#--- dg #--##--- dg #---#--- dg #--##--- dg -##-#--- dg -------- dg #------- dg #------- dg #-##---- dg ##--#--- dg #---#--- dg ##--#--- dg #-##---- dg -------- dg -------- dg -------- dg -####--- dg #------- dg #------- dg #------- dg -####--- dg -------- dg ----#--- dg ----#--- dg -##-#--- dg #--##--- dg #---#--- dg #--##--- dg -##-#--- dg -------- dg -------- dg -------- dg -###---- dg #---#--- dg #####--- dg #------- dg -###---- dg -------- dg --#----- dg -#------ dg -#------ dg ###----- dg -#------ dg -#------ dg -#------ dg -------- dg -------- dg -------- dg -####--- dg #---#--- dg #--##--- dg -##-#--- dg ----#--- dg -###---- dg #------- dg #------- dg ####---- dg #---#--- dg #---#--- dg #---#--- dg #---#--- dg -------- dg #------- dg -------- dg #------- dg #------- dg #------- dg #------- dg #------- dg -------- dg -------- dg --#----- dg -------- dg --#----- dg --#----- dg --#----- dg --#----- dg ##------ dg #------- dg #------- dg #--#---- dg #-#----- dg ###----- dg #--#---- dg #---#--- dg -------- dg ##------ dg -#------ dg -#------ dg -#------ dg -#------ dg -#------ dg ###----- dg -------- dg -------- dg -------- dg ##-#---- dg #-#-#--- dg #-#-#--- dg #-#-#--- dg #-#-#--- dg -------- dg -------- dg -------- dg ####---- dg #---#--- dg #---#--- dg #---#--- dg #---#--- dg -------- dg -------- dg -------- dg -###---- dg #---#--- dg #---#--- dg #---#--- dg -###---- dg -------- dg -------- dg -------- dg ####---- dg #---#--- dg #---#--- dg ####---- dg #------- dg #------- dg -------- dg -------- dg -####--- dg #---#--- dg #---#--- dg -####--- dg ----#--- dg ----#--- dg -------- dg -------- dg #-##---- dg ##------ dg #------- dg #------- dg #------- dg -------- dg -------- dg -------- dg -####--- dg #------- dg -###---- dg ----#--- dg ####---- dg -------- dg -------- dg --#----- dg #####--- dg --#----- dg --#----- dg --#----- dg ---##--- dg -------- dg -------- dg -------- dg #---#--- dg #---#--- dg #---#--- dg #---#--- dg -####--- dg -------- dg -------- dg -------- dg #---#--- dg #---#--- dg -#-#---- dg -#-#---- dg --#----- dg -------- dg -------- dg -------- dg #---#--- dg #---#--- dg #---#--- dg #-#-#--- dg -#-#---- dg -------- dg -------- dg -------- dg #---#--- dg -#-#---- dg --#----- dg -#-#---- dg #---#--- dg -------- dg -------- dg -------- dg #--#---- dg #--#---- dg #--#---- dg ####---- dg ---#---- dg ###----- dg -------- dg -------- dg #####--- dg ---#---- dg --#----- dg -#------ dg #####--- dg -------- dg --##---- dg -#------ dg -#------ dg #------- dg -#------ dg -#------ dg --##---- dg -------- dg -------- dg #------- dg #------- dg -------- dg -------- dg #------- dg #------- dg -------- dg ##------ dg --#----- dg --#----- dg ---#---- dg --#----- dg --#----- dg ##------ dg -------- dg -#-#---- dg -------- dg -###---- dg #---#--- dg #####--- dg #------- dg -###---- dg -------- dg -------- dg -------- dg ----#--- dg -###---- dg #------- dg -------- dg -------- dg -------- ; Character widths PrintWidths db $07,$09,$09,$09,$09,$09,$09,$03 db $05,$05,$05,$05,$03,$05,$05,$05 db $05,$03,$05,$05,$05,$05,$09,$09 db $07,$09,$07,$02,$05,$09,$07,$09 db $06,$02,$04,$06,$06,$06,$06,$02 db $04,$04,$06,$06,$03,$06,$02,$06 db $06,$06,$06,$06,$06,$06,$06,$06 db $06,$06,$02,$03,$05,$06,$05,$06 db $06,$06,$06,$06,$06,$06,$06,$06 db $06,$04,$06,$06,$06,$06,$06,$06 db $06,$06,$06,$06,$06,$06,$06,$06 db $06,$06,$06,$06,$06,$06,$06,$06 db $06,$06,$06,$06,$06,$06,$04,$06 db $06,$02,$04,$06,$04,$06,$06,$06 db $06,$06,$05,$06,$06,$06,$06,$06 db $06,$05,$06,$05,$02,$05,$06,$06 db $03,$06,$0C,$12,$18,$1E,$24,$2A ; Wide spaces $80..? db $30,$36,$3C,$42,$48,$06,$06,$06 db $01,$02,$03,$04,$05,$06,$06,$06 db $06,$06,$06,$06,$06,$06,$06,$06 db $06,$06,$06,$06,$06,$06,$06,$06 db $06,$06,$06,$06,$06,$06,$06,$06 db $06,$06,$06,$06,$06,$06,$06,$06 db $06,$06,$06,$06,$06,$06,$06,$06 db $06,$06,$06,$06,$06,$06,$06,$06 db $06,$06,$06,$06,$06,$06,$06,$06 db $06,$06,$06,$06,$06,$06,$06,$06 db $06,$06,$06,$06,$06,$06,$06,$06 db $06,$06,$06,$06,$06,$06,$06,$06 db $06,$06,$06,$06,$06,$06,$06,$06 db $06,$06,$06,$06,$06,$06,$06,$06 db $06,$06,$06,$06,$06,$06,$06,$06 ; For fun, include some random bytes... align $400 ; So it shows up clearly on the Zeus Code tab db "Random block starts " mRandomSpace(256) ; Plant a random number of random bytes db "Random block ends" ; Now, we're going to add three bytes so that the XOR_SUM and ADD_SUMs are zero ; First, we plant a byte which makes the XOR CS (including it) zero ; To do that we just work out the XOR of every byte to here and plant that value db XOR_MEM(Start,* - Start) ; It may not be obvious but the SUM_MEM of any block with an XOR_SUM of zero must ; be even - since the LSB of the XOR CS is zero. ; This means we can do the following without having to divide an odd-number ; We now calculate the byte value we need to add to this block to make the SUM ; (including it) be zero. SUM_Val = 0 - SUM_MEM(Start,* - Start) ; We now plant that value as two equal bytes to make the ADD CS of all this zero ; We plant this as two halves so they cancel out when XOR'd and don't ruin the XOR CS db SUM_Val/2,SUM_Val/2 ; Now if we XOR or ADD sum all the bytes between Start and here both should be zero. CS_Length equ * - Start ; The number of bytes in the checked block ; Variables pCurX db 0 ; A logical X position ppCurY db 0 ; A logical Y position pCurY dw 0 ; The actual address CurCol db 0 ; The cursor colour ; A handy macro - acts like align but fills with random bytes mAlignRandomFill macro(Alignment) ; We're given the alignment required while ( * mod Alignment) ; Loop while we're not aligned db zeusrand ; Plant a random byte wend ; mend ; Plant a random amount of random data... mRandomSpace macro(malign_size) loop abs(ZEUSRAND) mod (malign_size+1) db ZEUSRAND lend mend