A how to tutorial Friday, 09-Apr-99 19:55:47 Greetings fellow newbies, After some hesitation and a greet deal of procrastination, I am finally ready to share with you some of what I learned from the current project
Initial screen an messages displayed by the program Once the program is ran it opens a DOS window and displays the following: CronosSystems (C) Cronos Authorised Access Only Usernam: After a username is entered it displays another line : Access Code: After the Username and Access Code are entered one of two messages is displayed: Access Denied if the combination was wrong or , Access Granted if the combination was correct. Hidden text and messages in the program Hoping to locate the text for the messages mention above, I examined the hex dump of the program but there was not recognizable text shown. That is interesting. Where did these messages come from then? There are no other files associated with this program that might contain the text messages. The mystery deepens, but the answer is not that hard to find. Some sort of encoding must have been used to hide the plain text. A few steps through the program with the debugger revealed the hidden mystery shows its face. Fetch a byte from memory multiply it by 1FH and take the left byte of the result or the remainder of dividing by 256. The byte fetched from memory is stored in bx register and ax register contains the value 1FH a mul dx instruction multiplies these two registers and stores the result in ax. After the multiplication only the byte in al is stored back in memory. The encoding was done by multiplying the ASCII number of each character by DFH and the remainder of divide by 256 was take. So code = asc(char) * DFH MOD 2^8. It looks like I am getting ahead of my self so let us go back to the program and do some analysis. General description and division of the program The small size of the program offers an excellent opportunity to study almost every byte in it, thus let me divide the program to its main components. The program is only 915 bytes long and it may be divided into three sections: Code: the code section is about 323 bytes. Even those are not completely code since there are about 28 pairs of data bytes scattered thorough the code. I will come to this later Text data: There are about 87 bytes of data in the program starting at 296h and at 405h. Other data: The rest of the program, which is more than one half is mainly jump tables except for a few bytes used for other purposes. How dos the program work? This program is different from the usual programs most of us are familiar with: It has no calls and no return so one is always working on the highest level of the program. It uses a short segment of code starting at 110h as the main part and from it jumps to various routines that do very small tasks. All routines end by a jmp 110 instruction: Here is that main section:
Important routines in the program: Interrupts: There are four interrupt calls, here they are:
Math routines: There is an add routine, a subtract routine, and a multiply routine. These do operation on two registers namely ax and dx, here they are: Add routine
There are other add and sub routines but they add 2 or subtract 2 from a given register therefore I did mot consider them with the above. Memory manipulation routines. There are two of those of special interest for us: Fetch one byte from memory and put a byte in memory.
Compare an jump routines: Since these operations occupy a special place in the heart of every newbie reverser, I thought I will include them here. There are three of them. The first one makes, at least, three different things: 1- Checks if the character entered by the user is a back space, 2- check if the username and the access code are of equal length, and finally it dose the comparisons between the calculated code and a hard coded value. So don't attempt to the jump in this one. The second one checks for the length of the username and the access code making sure that none will exceed 256 bytes. An the third one checks if the character entered was a carriage return 0Dh. Here are the three routines:
A reversing method To revers the target one needs to find out what happens to the username and the access code after they have been entered and one needs a good place to stop the program at to follow this process. As listed above, there is an interrupt routine which gets a character from the keyboard thus providing a good place to stop the program. This routine starts at address 1F3:
It is a good idea to place the break at the end rather than the beginning of the routine so one will be able to step through the code without going into the interrupt routine itself. With a bpx place at 1FA the program will stop there after the user enters the first character of the username. Once the program stops start single stepping through the code and immediately you will land at 110. Once there notice how the registers is, bx, and dx are used to determine the next routine to be executed. Keep stepping through and eventually you will get to the multiplication routine starting at 1CB.
Put an other bpx the top of this routine, you will need it later. Here the character from the username will be multiplied by 2Bh. Your journey through the program will lead you to location 18C where your encoded character will be stored in memory in location starting at 494h.
Son after that you will be entering the second character of the username. From now on just run the program which will keep breaking at the locations where bpxs were place. Don't disable them. After you have entered enough characters, 5 or 6, hit the carriage return to start entering the access code. It a good idea to follow the journey of the first character of the access code in the same manner as done with the first one of the username. One difference will be the memory location where the encoded characters of the access code are stored. In this case the location starts at 594. The real fun starts after you the last character of the access code is entered and the carriage return is hit. After you hit the carriage return for the second and last time the program will break after returning from the interrupt call. From her on you have one of two choices, either single step and watch what is happening are run. In either case you will come to the multiplication routine where you have place the second bpx. From there on single step until you com to the addition routine at 1B7
Place another bpx at the top of this routine also. You could continue single stepping through the code, but to save some time run the program and it will break at the addition routine for a second time where it will add the number from the username to whatever has been calculated so far which will be 93h at this point. From here on single step again until you reach the top of the subtraction routine at 1C1
Here the number fetched from the access code will be subtracted from the accumulated number. From here on just run the program by hitting F5, X , or whatever. The program, however will continue to break at the top of each of the multiplication, addition, and subtraction routines. It is wise to just single step the few instructions in each routine to in order to watch what is happening. After all the characters in the username and the access code, which should be of an equal length, are processed you will end with a 16bit number which for convenience we will name as X. If you continue watching the multiplication and addition routines, soon you will notice that a hard coded number = 5BFh will be multiplied by X. The result of the multiplication will soon be added to another hard coded number = 79DFh. The result of this addition eventually will be compared with a third hard coded number = 7777h. If both numbers are equal you will get the "Access Granted" message, but if not you will get the "Access Denied" message. This last comparison takes place here:
The number needed for a solution and how it is generated: In order to succeed in getting the "Access Granted" message the number calculated from the username-access code combination must be 5868h. To generale this number, the program uses a complicated algorithm which may be summarized by the following equation: X = X*3 + 93H + NameCode(n) - AuthCode(n) With X = 0 at the start and the calculation repeated n times an being the length of each of the username and the access code. Here is a more detailed description of the above equation and a programmatic way of how it works: Definitions: Length = the number of bytes in each of the username and authorization number. n = 1 to length. NameCode(n) = the code for the respective byte in the name.=Ascii*2Bh AuthCode(n ) = the code of the respective byte in the authorization number = Ascii*2Bh X = result of calculation as shown next = 0 at the start For n = 1 to lengthThere is no easy way to calculate the needed number, but a determined reverser will find many was to do it. Patching the program Although the jump instruction following the compare je can't be changed since that routine is used to compare other values, there is an easy albeit not very obvious way to patch the target and get the "Access Granted" every time. After comparing the lengths of the username and access code, the program either continues with the rest of calculation if the two are equal, or goes on no display the "Access Denied" message if they are not equal. But for some reason, lucky for us, it compares the 7777 with 0000 in order to jump to the bad location. This is a good loop hole to exploit. By changing the 7777 to 0000 and enter a username different in length from the access code the "Access Granted" message will be displayed every time we enter a username longer or shorter than the access code. Try it. Use any hex editor such as HexWorkShop and change the 7777 to 0000. You will find 7777 at location 382 when using a hex editor and at location 482 when you are using a debugged such as SoftIce. Enjoy, Joseph Joseph |
Joseph's Thread (Question to Cronos) (30-Mar-99 23:45:59) |