Assembly and Cracking From the Ground Up |
An Introduction by Greythorne the Technomancer |
Some User Interactivity |
Our First Real Program For this next section we are going to put together a small program, First of all, note the semicolons marking the start of a comment Inline commentation is the technical term, but what it means is simple: You can therefore use that space to make your own comments in the program. This works in TASM and MASM and most other assembly compilers, but don't try it in Borland's C/C++ compiler when doing inline assembly, it just doesn't know what a semicolon is for inside the assembly sections. * * * Here is a sample that shows text string output like described in the last lesson. [ ------------------------- CUT HERE -------------------------- ] ;********************************************** ; ; .COM File Program Template (COM.ASM) ; ; Compile with: ; ; TASM COM.ASM ; TLINK /t COM.OBJ ; ; +gthorne'97 ; ;********************************************** .model small .code .386 org 100h start: jmp MAIN_PROGRAM ;---------------------- ; Your Data Here ;---------------------- CopyMsg db 'Copyright (c)1997 By Me!',0Dh,0Ah,'$' ;---------------------- MAIN_PROGRAM: ;--------------- ; Your Code Here ;--------------- mov dx, offset CopyMsg ; tell DOS where string is mov ah, 09h ; DOS command 9 = print string int 21h ; tell DOS to issue command ;--------------- mov al, 0h ; return code (0 = no error) EXIT_PROGRAM: mov ah,4ch ; quit to DOS int 21h end start [ ------------------------- CUT HERE -------------------------- ] Notice that I called the message CopyMsg, and used the name as a label by which I can reference my string at any time. Strings are referenced by their offsets in memory so as to differentiate them from a normal tasm label or some kind of variable. If you look at the usage of the phrase MAIN_PROGRAM, it is also a label - but it is not a string, so you don't use the offset directive to point at it. For now, think of DOS strings as offsets in memory that end in either $ or a zero. The 0Dh,0Ah is the code for the computer to hit the enter key at the end of the string. (0D is the hex code for a carriage return which means 'move all the way to the left', and 0A is the code for a linefeed which means 'drop down one line on the screen') Just for fun, another interesting code is 07h that is known as the BELL character, which used to be ctrl-G on older computer keyboards. When a 07h is printed to the screen, it issues a computer beep (the same one you hear when you reboot your machine or get some lame windows error) which is quite handy on occasion. * * * Now that we know how to print a string, here is a simple one: The DOS version is like this (the non-dos version is on my page in sample code, so you can experiment with that if you like. For this lesson you won't need it - but remember that people use all of these methods (and then some) to print text to a screen, so reverse engineering an application requires knowledge of all the possibilities. Here are two in a row that are very useful. This one expects the user tyo hit a key on the keyboard: mov ah,08h ; DOS function 08h, get a key from user This next command, shows what character was pressed on the screen. mov dl, al ; copy the user keypress from AL into DL Now we will use it, in the program we have already been using as an example: [ ------------------------- CUT HERE -------------------------- ] ;********************************************** ; ; KEYPRESS.ASM ; Our First Interactive Program ; ; Compile with: ; ; TASM KEYPRESS.ASM ; TLINK /t KEYPRESS.OBJ ; ; +gthorne'97 ; ;********************************************** .model small .code .386 org 100h start: jmp MAIN_PROGRAM ;---------------------- ; Your Data Here ;---------------------- CopyMsg db 'Copyright (c)1997 By Me!',0Dh,0Ah,'$' PressEnter db 0Dh,0Ah,'$' ;---------------------- MAIN_PROGRAM: ;--------------- ; Your Code Here ;--------------- ; DISPLAY OUR COPYRIGHT MESSAGE mov dx, offset CopyMsg ; tell DOS where string is mov ah, 09h ; DOS command 9 = print string int 21h ; tell DOS to issue command ; Press ENTER for the heck of it mov dx, offset PressEnter ; tell DOS where string is mov ah, 09h ; DOS command 9 = print string int 21h ; tell DOS to issue command ; GET A KEY FROM THE USER (DOES NOT ECHO) ; RESULT IS LEFT IN AL REGISTER mov ah,08h ; DOS function 08h, get a key from user int 21h ; tell DOS to do the command ; ECHO (SHOW) WHAT KEY THE USER PRESSED mov dl, al ; copy the user keypress from AL into DL mov ah,06h ; DOS function 06h, print character in DL to screen int 21h ; tell DOS to do the command ; JUST FOR FUN WE GO BEEP mov dl, 07h ; copy the BEEP code into DL mov ah,06h ; DOS function 06h, print one character to the screen int 21h ; tell DOS to do the command (which will make a BEEP) ;--------------- mov al, 0h ; return code (0 = no error) mov ah,4ch ; quit to DOS int 21h end start [ ------------------------- CUT HERE -------------------------- ] This last section is the most fun, because now we have most of what we need to make a real program that actually does something. Whenever you are sitting in front of a screen with a blinking cursor in some program waiting for a keypress, it isn't passive. It is actively running through a loop that checks constantly whether you are pressing a key. The computer itself is not required to do this, but programs are. In actuality, the INT 21 (interrupt 21) really means this: For this purpose, it is usually the norm to set up and endless loop that only gets broken out of in a special case (say for instance a special code is entered, or just a simple key is hit. In our case, we will expect that the key has to be a Y or N (we will accept lowercase as well) Our code will not be optimized, it is important to be clear in this case. Showing you how to make the program compile so that the executable is smaller will be for later. Right now we just want to make it work. Making an endless loop is simple.
; your code goes here JMP START_OF_LOOP ; jump back to the label GO_ON_WITH_PROGRAM: ; a label to mark after the loop
Remember how a key is entered by the user with this command:
mov ah,8 ; DOS function 08h, get a key from user
Since our key is stored in AL, a CMP would clobber it if we did not store it somewhere for safety, so we choose to store it in BL. (Why BL? because we havent used it yet. No other reason.) the way you use CMP is like this: CMP SOMETHING , SOMETHING in our case, we are comparing BL to a letter Y from the user so we type: CMP BL, 'Y' notice that the letter Y is in quotes. Text characters should be in quotes or the assembler gets confused. numbers in decimal are written normally: CMP BL, 89 numbers in base 16 (hexadecimal are written like this: CMP BL, 059h All 3 of these reveal the same result, as the ASCII code for the letter 'Y' is 89 in decimal, which is 59 in base 16. * * * then we have many nice commands that work based on the results of a compare. JZ is also called JE (jump if EQUAL) Basically it is also a simple concept. If the result of a compare is zero then your program jumps to somewhere you want it to, otherwise it does not make a jump to anywhere. and JNZ (jump if not zero) which is also known as JNE Here is a sample section of code that does what we have just been describing: * * * START_OF_LOOP: ; the label (notice the colon) ; GET A KEY FROM THE USER INTO AL (DOES NOT ECHO) mov ah,8 ; DOS function 08h, get a key from user int 21h ; tell DOS to do the command mov bl, al ; store key for later in BL register ; so we don't lose it ; because AL gets clobbered when a CMP is issued cmp bl, 'Y' ; see if user pressed a 'Y' je GO_ON_WITH_PROGRAM cmp bl, 'N' ; see if user pressed a 'N' je GO_ON_WITH_PROGRAM JMP START_OF_LOOP ; jump back to the label GO_ON_WITH_PROGRAM: ; a label to mark after the loop * * *
[ ------------------------- CUT HERE -------------------------- ] ;********************************************** ; ; KEYPRESS.ASM ; Our First Interactive Program ; ; Compile with: ; ; TASM KEYPRESS.ASM ; TLINK /t KEYPRESS.OBJ ; ; +gthorne'97 ; ;********************************************** .model small .code .386 org 100h start: jmp MAIN_PROGRAM ;---------------------- ; Your Data Here ;---------------------- CopyMsg db 'Copyright (c)1997 By Me!',0Dh,0Ah,'$' PressEnter db 0Dh,0Ah,'$' ;---------------------- MAIN_PROGRAM: ;--------------- ; Your Code Here ;--------------- ; DISPLAY OUR COPYRIGHT MESSAGE mov dx, offset CopyMsg ; tell DOS where string is mov ah, 09h ; DOS command 9 = print string int 21h ; tell DOS to issue command ; Press ENTER for the heck of it mov dx, offset PressEnter ; tell DOS where string is mov ah, 09h ; DOS command 9 = print string int 21h ; tell DOS to issue command START_OF_ENDLESS_LOOP: ; GET A KEY FROM THE USER INTO AL (DOES NOT ECHO) mov ah,8 ; DOS function 08h, get a key from user int 21h ; tell DOS to do the command mov bl, al ; store key for later in BL register ; so we don't lose it because AL ; gets clobbered when a CMP is issued cmp bl, 'Y' ; see if user pressed a 'Y' je GO_ON_WITH_PROGRAM cmp bl, 'N' ; see if user pressed a 'N' je GO_ON_WITH_PROGRAM cmp bl, 'y' ; see if user pressed a 'y' je GO_ON_WITH_PROGRAM cmp bl, 'n' ; see if user pressed a 'n' je GO_ON_WITH_PROGRAM ; WE GO BEEP IF ANY OTHER KEY WAS PRESSED mov dl, 07h ; copy the BEEP code into DL mov ah,6 ; DOS function 06h, print a character int 21h ; tell DOS to do the command (make a BEEP) JMP START_OF_ENDLESS_LOOP GO_ON_WITH_PROGRAM: ; ECHO (SHOW) WHAT KEY THE USER PRESSED mov dl, bl ; copy the user keypress from BL into DL mov ah,6 ; DOS function 06h, print a character int 21h ; tell DOS to do the command ;--------------- mov al, bl ; put keypress into AL to be the exit code ; from this program mov ah,4ch ; quit to DOS int 21h end start [ ------------------------- CUT HERE -------------------------- ] Now for experimentation, see if you can modify the above program so that it compares whether you typed 'N' or 'n' and tells you a text string saying 'you said no!' and on the other possibility it will say 'that was affirmative!' if you hit a 'y' or a 'Y' It would also be nice if you made a text message at the start of the program that tells the user to hit keys (Y/N). There is nothing more frustrating to a user than not knowing what the machine is supposed to be waiting for. Well take care and enjoy! also - if you get edgy to try something, the exit code of the program is known to batch files as the ERRORLEVEL There are many uses of the errorlevel being set at the end of the program, since another program can tell exactly what the results of your app were. |
+gthorne'97 |