Cronos
Task 4
Sat Jan 2 09:48:44 1999


Rushed it this morning, excuse any mistakes,

Solution to Task4
=================

I have already previously outlined some of my investigations into what happens when the username is entered, and mentioned that it is read on the fly as it is entered into the Name box on the Registration form. I also, in the solution to Task 3, tried to show the structures which are still present within the executable file due to the nature of the Delphi RAD design (although I don't think this worked very well partly due to the formatting of entries on the forum). All programs will contain the resource entries from which some information can be gleaned, but RAD (Rapid Application Development) involving the use of components leaves a lot more in the way of clues, at the same time as providing layers of obfuscation to the code at an assembly level. Basically, with Delphi and development programs like C++ Builder, you would start out with a blank 'Form' and add components to the forms to develop your program. The components will be standard items, or could be newly developed classes (but this is getting too deep). So Edit Boxes and Static Text Boxes and Buttons can be added to a Form (=Dialog Box/Window) and the RAD system generates a lot of the entries you would need (like id numbers for components, resource statements, etc). Now at this point the programmer can step into the code for these forms at any point and add some code of their own. Each Form will have Methods, which do something or can be called on some event, and properties, which can be read or changed. Now, I'd already found the following information, left directly in amongst the program code (in fact it is almost impossible for the compiler to remove this information since it forms part of the propertys of the class and could be queried by the program itself):

(note, I have cut a lot of extraneous information here)
1000:0043f93d c0f94300 dd offset clickcancel
1000:0043f941 0c427574746f6e3243.. ds "Button2Click"

1000:0043f950 c8f94300 dd offset regbuttonclick
1000:0043f954 0c427574746f6e3143.. ds "Button1Click"

1000:0043f963 88fa4300 dd offset editnamechange
1000:0043f967 0b4564697431436861.. ds "Edit1Change"

1000:0043f975 e4044400 dd offset editserialchange
1000:0043f979 0b4564697432436861.. ds "Edit2Change"

Anyway, these are the four main routines/methods for the Registration box. We know that the editnamechange routine at 43fa88 is the one which processes the entry of the name in some way, because after it is entered there and the Registration button is pressed there is no request to read the name (as found with SoftIce).

Strictly speaking the 43fa88 routine is the routine which processes a change in the EditBox of the Dialog, it isn't the calculation routine which we're looking for, so we need to go further down the code. Looking down the code at 43fa88 we see the following :-

1. Calls to a number of string routines like strcpy,etc. Although these calls are very tied in to the Delphi class type code and obfuscated.

2. The following instructions :
1000:0043fb42 83c0e0 add eax, -20h
1000:0043fb45 83f83a cmp eax, 3ah
These two instructions are significant in our quest. Firstly 20h is ASCII space, and secondly 5ah = 'z'. These are also just at the start of a loop, which will be the loop through each character of the Name string. It is this loop which is the calculation routine that we are seeking.

It is directly followed by:
1000:0043fb4e ff248555fb4300 jmp dword ptr charactertable[eax*4]

So each character of the Name string is used as an index into a jump table, provided it is within the table limits (if not, it is skipped). So each character of the name is treated individually, and has it's own piece of code. Most of these are practically the same. We find that only letters, numbers and the space character are treated in any way, and anything else is skipped.

First, take a look at how a character is treated:
map_9: ;this is actually for the 'a' character.
1000:0043fc41 8d55f4 lea edx, [ebp-0ch]
1000:0043fc44 8b83f8010000 mov eax, [ebx+1f8h]
1000:0043fc4a e865d4fdff call poss_strcpy
1000:0043fc4f 8d45f4 lea eax, [ebp-0ch]
1000:0043fc52 ba3c034400 mov edx, offset char_9
1000:0043fc57 e8a03efcff call strfunc1
1000:0043fc5c 8b55f4 mov edx, [ebp-0ch]
1000:0043fc5f 8b83f8010000 mov eax, [ebx+1f8h]
1000:0043fc65 e87ad4fdff call strfunc2
1000:0043fc6a e98a060000 jmp skiptonext

There are three string routines, just to add a character (or two) to the end of the serial string. So each character is mapped, as in a substitution cipher, into a character, or two characters of the serial number. It only remains to work out the mapping of each character, and these are held in a table in the executable file (look at 440334 onwards). Each entry in the table consists of three dwords - one which contains the string to be mapped to, one which is the length, and a third flag (possibly an end marker ?).

Finally, it remains to take a look at the treatment of the space character and here we see that the space is treated as a backspace for the serial number.

The final result of this, and the treatment of the space character means that we don't quite have a substitution cipher, and some strings will map to the same registration string (for example Pirate Copy and PiratCopy give the same string).

Cronos.