Cracking for dummies - by reverser+
Lesson 2: "The difficult years" - Target: Netmed
(08 December 1997 - version 0.01, will change)

Cracking and reverse engineering for those that have NEVER done something like this before

"Reverser's lessons demonstrate that cracking can be great fun!"

"For people that would like doing useful cracking in a matter of hours"

"Reverser+'s 'Cracking for dummies' is the perfect choice for those who want to use their programs in order to do what they want, not what the programmers wanted they to do with them"

Expert +cracker and +ORC's student reverser+ builds on the success of his cracking essays, updating his discussions in a humorous fashion. His style helps to overcome the technical and non-intuitive barriers presented by cracking. The lessons show readers everything from how to 'dead list' a target to more advanced cracking tasks like 'feeling' concealed and encrypted protection schemes.

Nothing, nada, nichts... it's here and free for everyone, of course :-)

OK, enough kidding... I have decided to write an easy and GUIDED tutorial to software reverse engineering, aimed at all those among my readers that are interested yet AFRAID of the many 'technicalities' that are given for acquired inside the 'real' essays on the student pages (those essays of the +HCU Academy that are dedicated to a 'more mature' cracking audience). In fact I believe that our duty is not only to explain our science to those already able to follow it, but also to allow anybody who cares to join us.

These essays does not have ANY value for average or advanced crackers and are aimed EXCLUSIVELY at those among our readers that have NOT YET BEGONNEN any cracking or reverse engineering at all.
This said, you'll not be able to understand this lesson if you do not 'work' a little. Some of the explanations and of the concepts that you have to learn may NOT be easy to assimilate, no matter how 'basically' explained.
If this happens, just read on, once you have got some more 'perspective' many of the 'barriers' that you encounter will suddenly disappear.
Don't forget to read and assimilate lesson 1 before starting this.

You are about to begin a REVERSE ENGINEERING SESSION. You need to PRINT this text, you need a PC-computer with windows95 installed, you need a 'target' and you need some tools in order to follow my lessons (tools are forever, like diamonds).

For this second lesson you'll need, specifically, all tools described in lesson 1 (the "tekfact" lesson: wdasm, psedit and pkunzip) and two new programs

1) Base Calculator: an integer calculator with not only the usual operations such as addition and subtraction, but also the most common logical operations. In addition, Base Calculator can display 8 bit, 16 bit and 32 bit numbers, both signed and unsigned in decimal, hexadecimal, binary or octal.
You can fetch it right off my site, here: (148.156 bytes).
This program by John Zaitseff has been programmed in pascal (Delphi2) and is one of the best tools you'll use when you reverse engineer. It offers bin, hex, dec and octal calculations with XORing, ANDing, NOTing and whatever capabilities you need... you'll see and understand... For now just download it, unzip it and keep it ready for use.

2) Netmedic. (Version 1.2). This is our target for this lesson: You'll be able to fetch it easily performing a ftp search.
Search for the strings 'nm.exe', 'netmedic' and 'vitalsign' in this order.
The self-extracting trial shareware version 1.2 that we will use here as target has a length of 1.019.455 bytes
Alternatively you may fetch this target from vitalsign's own site at They will release a new version very soon, of course, so harry up.
Netmedic is a PHANTASTIC tool for stalking activities, self-defense on the Web and net surfing, as you will soon discover. To navigate the deep sees of the web with this tool can be great fun, like being in the gauge and machine room of a huge ship every time you approach a site.
Its protection scheme, altough extremely easy to defeat, does indeed present some very interesting pecuilarities.
I checked (just in case) and found that this target has already been cracked by (at least) three different cracker groups.
You could easily fetch all over the web a ready made de-protection, for instance its Phrozen Crew's patch...
But you will not do it, because you will never need any more these ready-made "patches for lamers".
You are already a cracker (in nuce) and therefore you are going to feel the code of your target, understand it and crack it all by yourself (and in the mean time you will learn a lot, and you'll know what you have done and why :-)
OK, let's start: fetch netmedic and install it on your harddisk. Believe me: you'll love this target for the sheer MIGHT that it gives (offensive and defensive) to all internauts lost among the sees (and the currents) of the Web.
In fact you'll like netmedic so much that you'll probably want to register its next new version (which should deserve in my opinion a much more complicated protection scheme :-)
STARTING THE SESSION: string fishing
We could have tackled this protection scheme inside the code of our target in many other ways, like searching for the relative protection functions; pinpointing the protection scheme through a debugger (the easiest if most boring approach); getting the pixel dimensions of the protection window elements with a screen ruler, individuating the protection through a resource editor or even using a software 'stepwatch' (great fun for graphical demos deprotection :-)
But we will for this lesson -once more- use the SIMPLEST way: the approach you already began to learn with lesson one: string fishing.

Disassemble netmedic.exe
Run wdasm32 (by now you should have found on the web, or bought, version 8.9 of wdasm (see my first lesson). If you are still using the demo version, what follows applies nevertheless, yet you'll work on your target's code "on screen", using wdasm's own search capabilities, and not inside your texteditor, since the demo version of wdasm does not allow the editing and saving of the disassembled text file. Yet by the end of this lesson you should be enough 'semi-advanced' in our reversing art to be able to work on the essays inside +HCU's project 0, where you'll find detailed instructions about transforming the demo version of wdasm in a full working version adding or modifying all disabled functions inside it. But wait, don't go there right now: you better finish this lesson first :-)
The disassembly of a windows95 program can easily result in a huge text file.
netmed.exe is a 1.016.832 bytes file, and wdasm89 -which I'm using as disassembler instead of the more powerful (but newbyes scaring) IDA 3.7. for these lessons- will give you a 11.927.177 bytes *.alf file: a dead listing that of 12 millions bytes, quite a monster. Of course you wont be able to handle well such a file inside Micro$oft Word, which is a very sloppy wordprocessor by whatever standards you might choose to use. I may suggest my personal choice working under Windoze: Ultraedit32.
You'll have the possibility to customize its toolbar with your own 'reversing' macros and it will be a lot quicker than Word. Moreover it will not crash and you'll be able to cut and paste code without 'loosing' your mouse grip on the window (a very peculiar and annoying characteristic of Micro$oft's abomination :-(

Choose a quiet evening and perform your string search, (using for instance "license" "evaluation" "expir"), see if something "bites" and once you think you have found enough, pull your nets out of the code and look at the many little poor zapping fishes you have caught:
:00406A1B 6817E20000 push 0000E217 ID=57879: "Your advanced feature trial license expires in 1 day." 
:00406A3A 6818E20000 push 0000E218 ID=57880: "Your advanced feature trial license expires in %d days."                                 |
:00406A87 6819E20000 push 0000E219 ID=57881: "Your advanced feature trial license has expired."                                         
:0043E901 6812E20000 push 0000E212 ID=57874: "Your evaluation period for Net.Medic has ended. 
:0043F21F 6835E20000 push 0000E235 ID=57909: "Your advanced feature trial license expires in %d day(s)
:0043F234 6840094A00 push 004A0940 Data Obj ->"Your license expires in %d days."
Whoa! Even if something did slip through we have pulled a full net of strings out of our target's code! We will not hunger this evening!
Notice that we already know WHERE are located the protection code snippets: in fact we'll have a protection snippet around 06A and another one from 3E9 to 3F2!
Let's prepare and sip our cocktail and continue:
Let's pull out the guts of the first one
:00406A1B 6817E20000 push 0000E217 ID=57879: "Your advanced feature...expires in 1 day."
Before passing the protection code that dwells around this location under our serene 'reversing' blick (we will do it in a minute), we better understand first of all what's the meaning of the code that precedes those 6 strings above. Let's look at the instruction at location :00406A1B: 6817E20000
68 is push and 17E20000 is 0000E217 (which corresponds, hexadecimally to the decimal value ID=57879).

Why the pushing around?
First: all the strings you see are being PUSHED on the stack because a subsequent call to a display function will need to know what to display on the screen. All the parameters for any subroutine function must be pushed (the call must be prepared) before executing the call, and the only (minor) question when you reverse is the ORDER of this pushing. In C language it is rightmost parameter first, in Pascal language the other way round.
Here we have a target written in C... well, sort of, they have used overbloated Micro$oft's "Visual" C++... would the authors have programmed with "real" C, this target would have been a lot smaller, yet some sort of degenerated C it is anyway, and therefore the LAST parameter is pushed first on the stack... how do I know that our target has been written and compiled with Micro$oft's VisualC++? Well, the code is typical, and that would be more than enough, but if you want to check on your own, just have a look at the list of IMPORTED FUNCTIONS (at the beginning of your dead listing) and you'll find the following: Import Module 009: MSVCRT40.dll... that's the (bad) Micro$oft's run-time library dll, as you'll see in a moment... back to our pushing parameters around:
The following code snippet (from our very target) shows you for instance the typical and very simple parameter passing for the ubiquitous messagebox function:
:00457586 6A00                    push 00000000             ;0, the rightmost parameter
:00457588 68541E4A00              push 004A1E54             ;Data Obj ->"Error"
:0045758D 68481E4A00              push 004A1E48             ;Data Obj ->"Print Error"
:00457592 6A00                    push 00000000             ;NULL, the leftmost parameter
:00457594 FF15A4864A00            Call dword ptr [004A86A4] ;USER32.MessageBoxA, Ord:0188h
Since the function MessageBox has 4 parameters, int MessageBox(hwndParent, lpszText, lpszTitle, fuStyle) you can see inside the target's code four pushes just before the call, so easy and simple is that.

The above code means therefore: MessageBoxA(NULL, Print Error, Error, 0)... in other words: "please draw a DialogBox without parent window (hwndParent=NULL) with the word "Error" as title and the words "Print Error" as message text and with a nice little OK button!
See, fuStyle is 0, and this correspond to MB_OK, and therefore this message box will contain only one push button with the tag OK written onto it... In fact you could modify this last parameter determining the "button", through your hexeditor, and for instance substitute 0x20 to the zero for the rightmost parameter. If you then re-run the program (and then cause a print error), the modified line :00457586 6A20 would give you MB_ICONQUESTION instead of MB_OK, and a silly question-mark icon would in this case appear in the message box. Pretty cheap reversing thrills, in this specific case, yet I'm sure you are getting the point: substituting parameters inside alien code it's very easy and may be great fun!

Yet the 'MessageBox' explanation above is fully valid only for ONE of the above fishes: the last string at 3F234, which is directly located inside our target's data:
:0043F234 6840094A00 push 004A0940 Data Obj ->"Your license expires in %d days."
So it pushes a string located inside the target, at A0940! Now -for this string- we will use psedit (or another hexeditor, see lesson1, the "tekfact" lesson) and search it "physically" inside the BYTES of our target, (I repeat: put now aside our disassembled wdasmed dead listing, and look at the bytes of netmed.exe).
Once we search for this string we find it at 9ED40:
9ED40	596F7572206C6963656E736520657870 Your license exp
9ED50   6972657320696E20256420646179732E ires in %d days.
O mann_o_mann! Hey! It is not at A0940!ou use your brand new base calculator, that you should have downloaded and installed on your harddisk and notice a staggering difference of 1C00 bytes! What's going on? Where does this difference come from?
Man! I thought you just pushed the stupid data location for the call, getting thattaway the string you pushed for, automagically, appear! Hey reverser+, what's going on?
Quiet! I have the pleasure to introduce to you the subdivisions of all windozes' programs (in fact of ALL programs but the most tight ones): have a look at the TOP of your netmed's dead listing! The very first table you'll find there is the following one:
Number of Objects = 0007 (dec), Imagebase = 00400000h

   Object01: .text    RVA: 00001000 Offset: 00000400 Size: 00087400 Flags: 60000020
   Object02: .rdata   RVA: 00089000 Offset: 00087800 Size: 00014C00 Flags: 40000040
   Object03: .data    RVA: 0009E000 Offset: 0009C400 Size: 00006200 Flags: C0000040
   Object04: .idata   RVA: 000A7000 Offset: 000A2600 Size: 00002E00 Flags: C0000040
   Object05: .tls     RVA: 000AA000 Offset: 000A5400 Size: 00000200 Flags: C0000040
   Object06: .rsrc    RVA: 000AB000 Offset: 000A5600 Size: 00046A00 Flags: 40000040
   Object07: .reloc   RVA: 000F2000 Offset: 000EC000 Size: 0000C400 Flags: 42000040
So, netmed.exe has 7 objects. Don't worry about their names and exact meanings for yet, just remember that .text and .data are the two important (and standard) ones. .text is CODE and .data is DATA.
Now look: the Imagebase is at 400000 and the DATA (Object03), is at RVA 9E000 with offset 9C400.
And as you can easily check (using for instance your brand new basecalculator tool) once you take away the dummy 400000 of the Imagebase, the simple subtraction 0x9E000-0x9C400 gives us a difference of 1C00... Bingo! This little mistery is cleared.
Yet where are the other little zapping strings we have fished out?
ALL the other protection strings inside our target's code (our zapping fishes) are in unicode (all the ascii characters have an interpolated null) and dwell at locations that (apparently) have nothing to do with the direct data locations pushed above... for instance, 0xE217 (which is ID=57879) does NOT directly correspond to a code location... hey bud, what's that? Keep cool, just read on
:00406A1B 6817E20000    push 0000E217      ;Your advanced... license expires in 1 day."
What's "E217"? Some sort of european food component?
No. it's a stringtable pointer... see: 0xE217 is decimal 57879. Yet if we have look at the hexes of our target with an hexeditor... our string begins at 0xE8DFC... what's going on here?
E8DFA		                350059006F00           5.Y.o.
E8E00		7500720020006100640076006100  u.r. .a.d.v.a.n.
E8E10		6E00630065006400200066006500  c.e.d. .f.e.a.t.
Well: this is a pointer to the STRINGTABLE! I'l show you a part of the stringtable of our target, which you could easily inspect using a resource monitor tool like BRW from Borland... you will learn how to use this very important reversing tool later studying the +HCU's essays, for the moment just have a look at this STRINGTABLE snippet):
 57872, "Delay"
 57873, "Traffic"
 57874, "Your evaluation period for Net.Medic has ended. You can continue using 
 57875, ""
 57876, ""
 57877, ""
 57878, ""
 57879, "Your advanced feature trial license expires in 1 day."
 57880, "Your advanced feature trial license expires in %d days."
 57881, "Your advanced feature trial license has expired."
 57882, "The feature you have requested is available only in the retail 
 57883, "Net.Medic from VitalSigns Software uses analysis techniques which 
 57884, "Some of the information above has been provided by Net.Medic from\r\nVitalSigns 
 57885, "Date and Time of Occurrence: "
 57886, "Date and Time of First Occurrence: "
 57887, "Date and Time of Last Occurrence: "
If we look at the data part of the target code we find above our string running from E8DFC (That's the "Y" of Your) to E8E66 (that's the full point after "day."). Look once more at the data dump above... at E8DFA, immediately before the "Y", we have a "3500": this is 0x0035, and represents the number of characters (it's decimal 53) of our string
 Your advanced feature trial license expires in 1 day.
So the real "block" is E8dfA-E8e65. And somewhere inside the code a TABLE translates the string number 57879 (0xE217) into a pointer to our location E8defA... where? Well as you'll see, the MFC40 function "NoName" 185 is an equivalent of a LoadString function, and it works like this:
:00406A1B 6817E20000    push 0000E217      ;Your advanced... license expires in 1 day."
:00406A20 8D4DA8        lea ecx, dword ptr [ebp-58] ;prepare call
:00406A23 E8BC0C0800    Call 004876E4      ;MFC40:NoName0185, Ord:0E48h; call_this
This means: call MFC40:NoName0185 with a pre-determined cx and the stringtable ID pushed. OK, we have seen enough, if you want to see what the cuckoo MFC40/185 does you know already what you have to do: just disassemble MFC40.DLL and look at the dead listing!
A string table consists of one or more separate resources, each containing exactly 16 strings. The maximum length of each string is 255 bytes. One or more strings in a block can be null or empty. The first byte in the string specifies the number of characters in the string. (For null or empty strings, the first byte contains the value zero.)
Windows uses a 16-bit identifier to locate a string in a string-table resource.
Bits 4 through 15 specify the block in which the string appears;
bits 0 through 3 specify the location of that string relative to the beginning of the block.
Time to get back to our little fishes and crack them, before they get stale.
Sniffing the code
Let's have a look at the code where our first string "Your advanced... license expires in 1 day" is pushed for the call: as we have already noticed, part of the protection scheme MUST dwell around 00406Axx; here you have the relative code snippet, that I have commented for you. Don't worry too much right now, get this snippet on your screen (or on paper) as well and just try to follow:
* Referenced by a Jump at Address:069BF(C)
:069EC E8CF7D0100    call 0041E7C0      ;get PROT parameter good/bad guy  !!!!!!
:069F1 83C404        add esp, 4         ;correct stack after call
:069F4 898542FFFFFF  mov dword ptr [ebp+FFFFFF42], eax  ;save PROT parameter
:069FA 83F801        cmp eax, 1         ;is it one?
:069FD 757F          jne 00406A7E       ;go check if PROT is three, or what else
:069FF E83C800100    call 0041EA40      ;else PROT = one, call this function
:06A04 8BF8          mov edi, eax       ;and save in edi how many days this guys has left
:06A06 8D4DA8        lea ecx, dword ptr [ebp-58] ;and do whatever the following call
:06A09 E8CA0C0800    Call 004876D8      ;MFC40:NoName0183, Ord:01E6h, ;MFC40/183 does
:06A0E C645FC03      mov [ebp-04], 03   ;and flag with three [ebp-04]
:06A12 85F6          test esi, esi      ;and check esi
:06A14 7455          je 00406A6B        ;go flag [ebp-04] with 2, else
:06A16 83FF01        cmp edi, 1         ;does he have only one day left, the poor chap?
:06A19 751F          jne 00406A3A       ;no, then go calculate how many days left, else
:06A1B 6817E20000    push 0000E217      ;Your... license expires in 1 day"
:06A20 8D4DA8        lea ecx, dword ptr [ebp-58] ;prepare call
:06A23 E8BC0C0800    Call 004876E4      ;MFC40:NoName0185, Ord:0E48h; call MFC40/185
:06A28 85C0          test eax, eax      ;did it work?
:06A2A 7430          je 00406A5C        ;no:continue without ax/cx and without call213
:06A2C 8D45A8        lea eax, dword ptr [ebp-58]  ;yes get ax
:06A2F 8D4DF0        lea ecx, dword ptr [ebp-10]  ;yes get cx
:06A32 50            push eax           ;and use ax for the following call213
:06A33 E8480D0800    Call 00487780      ;MFC40:NoName0213, Ord:02F8h ;call MFC40/
:06A38 EB22          jmp 00406A5C       ;then continue

:let's tell you how many days you have left (from 6A19)
:00406A3A 6818E20000    push 0000E218      ;Your... license expires in %d days"
:00406A3F 8D4DA8        lea ecx, dword ptr [ebp-58]
:00406A42 E89D0C0800    Call 004876E4  ;MFC40.MFC40:NoName0185, Ord:0E48h
:check if parameter PROT is three (from 69FD):
:00406A7E 83BD42FFFFFF03    cmp dword ptr [ebp+FFFFFF42], 3  ;guy's parameter it's three
:00406A85 751C              jne 00406AA3                     ;if not three check what else it is
:00406A87 6819E20000        push 0000E219     ;and push "Your advanced license has expired"
:00406A8C 8D4DF0            lea ecx, dword ptr [ebp-10]      ;beggar off bad guy

Well, an impressive code snippet with not only one but THREE zapping strings!
We can already understand some easy elements of this protection. The scheme checks right at the beginning a protection PARAMETER, calling function 1E7C0 (that we will examine in a minute). ON return we save the return value in [ebp+FFFFFF42] (which is [ebp-BE] probably). And chooses different strings depending from these values.
We know now that:
call 1E7C0 and get "kinda_guy" return value"
  if kinda _guy=1 then 
                    call 1EA40 and save in edi how many days this guy has left
                    call MFC40/143 and check esi return value 
                                                  and flag [EBP-4] with 2 or 3 accordingly
                             if the guy has 1 day tell him
                             else tell him how many days he has left
  if kinda_guy=3 then
                    tell the guy that his license his expired.
I would say that our work is already (almost) finished. Let's examine the code at the call that triggers the whole "kinda_guy" value, we will surely learn more.
Where we will crack:
The following code snippet is the routine that rturns the "kinda_guy" parameter.
We already know that a value of 1 means a "time limited trial" and that a value of 3 means that "your allowed time limit has expired". Well, an immediate legitime quastion for any researcher mind would be: "What about parameters "0", "2" and "4", "5", etcetera?
In the code below of our kinda_guy routine, you'll see many calls to OTHER routines (of course) some of them are calls to MSVCRT40.DLL, like the following sscanf:
:0041E8A6 8B3D44854A00       mov edi, dword ptr [004A8544];MSVCRT40.sscanf, Ord:0442h
:0041E8AC C645C000           mov [ebp-40], 00             ;zeroing memory location [ebp-40]
:0041E8B0 51                 push ecx                     ;pass parameter cx for sscanf
:0041E8B1 68A4F54900         push 0049F5A4   ;->"%x"      ;pass parameter
:0041E8B6 52                 push edx                     ;pass parameter dx for sscanf
:0041E8B7 FFD7               call edi                     ;sscanf(dx,%x,cx)
Clearly you may legitimately ask what the cuckoo is going on here. Well, I told you that this target has been written with Microsoft Visual C++, and therefore read (and head) the following:
MSVCRT40 is "Microsoft C Runtime Library Version 4.10.6038" 
for  "Microsoft Visual C++", as you can see through any hexeditor inside the very code of 
this *.DLL.

What the cuckoo is a "runtime library"?
A run time library is a set of hundreds of predifined 
functions and macros, designed for use in C programs.

Run time libraries make programming (and cracking) easier, 
providing tne following:

- an interface to operating system functions (such as opening 
  and closing files)

- fast functions to perform common programming task (such as
  string manipulation, "sparing the programmer the time and 
  effort needed to write such functions".

Run time libraries are specially important in high level programming 
because all "high level" programmers rely on libraries for basic functions not 
provided by their languages: input and output, storage allocation, process 

These C functions try to maintain a maximum system compatibility
between DOS, Xenix and Unix, and have mostly the same names in 
the C runtime libraries for Unix operating systems.

OK, let's have a look "inside" our MSVCRT40.DLL (you'll find a couple 
of them, at least, inside your own harddisk, disassemble one of them 
with wdasm (or IDA) and look, for instance, at the very simple 
_toupper function:

in c you would have:
int toupeer(c);		converts c to uppercase if appropriate
int _toupper(c);	converts c to uppercase

and therefore you would for instance use this kind of programming code:

if (islover(ch))
	printf("_toupper =%#04x", _toupper(ch));

Well, let's look at its implementation INSIDE our disassembled MSVCRT40.DLL:

Exported fn(): _toupper - Ord:036Fh
:10215450 8B442404                mov eax, dword ptr [esp+04]
:10215454 83E820                  sub eax, 00000020
:10215457 C3                      ret

This means: get passed parameter inside eax
            subtract 20h
            return home with subtracted parameter... 
and since reverser is (ASCII)     f  r  a  v  i  a
                               66 72 61 76 69 61
if I call _toupper six times, one for each letter, this will return me
                               46 52 41 56 49 41
which, as you have guessed is:
                                F  R  A  V  I  A
So easy is that (in assembly :-)
In fact it is so easy that one wonders why you should use twelwe bytes
to perform the same uppercasing (with a lot more CPU-cycles and a call 
to a DLL outside your main exe code):

 53                      push ebx                   ;throw lowercase char_value
 FF15C8854A00            Call dword ptr [004A85C8]  ;MSVCRT40.toupper, Ord:0461h
 83C404                  add esp, 00000004          ;correct stack
 8BD8                    mov ebx, eax               ;save uppercased returned char

instead of just using directly inside your program the three bytes: 
 83E820                  sub eax, 00000020          ;uppercase char in ax
...misteryes of high level languages, I presume. Multiply this for MUCH more 
complexes routines and MANY more bytes and you will quickly understand WHY the 
programs that you are using nowadays
-	are slow
-	crash
-	are huge
-	need powerful CPUs and a lot of memory
-	compel you to upgrade PC every two years

Let's look at our target's code now, it's time to CRACK!: Let's have a look at the routine returning the "kinda_guy" parameter:
this code snippet is CALLED from three different points (:004069EC, :0041ED0D, and :0043F1F1) it has also to do with a Menu whose ident is [ID=807Fh], as you will easily see just perusing the routine, which starts at 41E7C0. Here follows ONLY the most interesting part of it for us, but if you examine ALL its code, you'll see that we have already had another important C++ functions: a strncpy and a sscanf(dx,%x,cx) and that now we come to the second sscanf function: sscanf(ax,%x,cx).
....(started at 1E7C0)
:0041E8BC 8D4DEC             lea ecx, dword ptr [ebp-14]  ;prepare cx for call
:0041E8BF 8D45B8             lea eax, dword ptr [ebp-48]  ;prepare ax for call
:0041E8C2 51                 push ecx		          ;pass parameter cx for sscanf
:0041E8C3 68A4F54900         push 0049F5A4   ;->"%x"      ;pass parameter
:0041E8C8 50                 push eax		          ;pass parameter
:0041E8C9 FFD7               call edi		          ;sscanf(ax,%x,cx)
:0041E8CB 83C40C             add esp, 0000000C            ;correct stack
:0041E8CE 8B45F0             mov eax, dword ptr [ebp-10]  ;get value
:0041E8D1 3501101000         xor eax, 00101001            ;xor it with 0010 1001
:0041E8D6 3B45EC             cmp eax, dword ptr [ebp-14]  ;is it like cx, once xored?
:0041E8D9 7521               jne 0041E8FC 		  ;No? Beggar off: EVIL JUMP
:0041E8DB C745FCFFFFFFFF     mov [ebp-04], FFFFFFFF	  ;dummy parameter
:0041E8E2 E831010000         call 0041EA18                ;dummy end call
:0041E8E7 B804000000         mov eax, 4                   ;GOOD "registered" FLAG ax=4

* MAIN EXIT: Jump at Addresses	:0041E916(U), :0041E936(U), :0041E968(U), 
				:0041E974(U), :0041E98A(U), :0041EA09(U)
:0041E8EC 8B4DF4                  mov ecx, dword ptr [ebp-0C]   ;poppall and exit
:0041E8EF 5F                      pop edi
:0041E8F0 64890D00000000          mov dword ptr fs:[00000000], ecx
:0041E8F7 5E                      pop esi
:0041E8F8 8BE5                    mov esp, ebp
:0041E8FA 5D                      pop ebp
:0041E8FB C3                      ret  				;RETURN after check

* Referenced by a Jump at Address:0041E8D9(C) EVIL JUMP 
:0041E8FC 833DA0F5490000          cmp dword ptr [0049F5A0], 0   ;d'we have a zero there?
:0041E903 7413                    je 0041E918			;if so go ahead and xor other things
:0041E905 C745FCFFFFFFFF          mov [ebp-04], FFFFFFFF 	;else  dummy parameter
:0041E90C E807010000              call 0041EA18			;      dummy end call
:0041E911 B801000000              mov eax, 00000001  		;trial FLAG ax=1
:0041E916 EBD4                    jmp 0041E8EC  		;RET WITH trial FLAG 1

* Referenced by a Jump at Address:0041E903(C) EVIL JUMP
:0041E918 8B45F0               mov eax, dword ptr [ebp-10]   ;clean and ready for xor once more
:0041E91B 3510101100           xor eax, 00111010             ;this time xor with 0011 1010
:0041E920 3B45EC               cmp eax, dword ptr [ebp-14]   ;is it, xored, like cx?
:0041E923 7513                 jne 0041E938                  ;No? Go ahead and xor 1101 1101
:0041E925 C745FCFFFFFFFF       mov [ebp-04], FFFFFFFF        ;else   dummy parameter
:0041E92C E8E7000000           call 0041EA18                 ;       dummy end call
:0041E931 B805000000           mov eax, 00000005             ;Not yet advanced funct flag 5
:0041E936 EBB4                 jmp 0041E8EC                  ;ret with bad flag ax=5

* Referenced by a Jump at Address:0041E923(C) EVIL JUMP
:0041E938 8B45F0               mov eax, dword ptr [ebp-10]   ;ready for xor once more
:0041E93B 3501110111           xor eax, 11011101             ;this time xor with 1101 1101
:0041E940 3B45EC               cmp eax, dword ptr [ebp-14]   ;is it, xored, like cx?
:0041E943 7534                 jne 0041E979                  ;if yes check time else ret with 
:0041E945 6A00                 push 00000000                 ;trial ax=1 and time unchecked
:0041E947 FF1548864A00         Call dword ptr [004A8648]     ;MSVCRT40.time, Ord:045Dh
:0041E94D 83C404               add esp, 00000004
:0041E950 2B45F0               sub eax, dword ptr [ebp-10]   ;number of second elapsed, subtracted
:0041E953 C745FCFFFFFFFF       mov [ebp-04], FFFFFFFF        ;       dummy parameter
:0041E95A 3BC6                 cmp eax, esi                  ;check if user has time or not
:0041E95C 760C                 jbe 0041E96A	             ;below, return with trial flag one
:0041E95E E8B5000000           call 0041EA18                 ;       dummy call
:0041E963 B803000000           mov eax, 3                    ;else return with flag ax=3:
:0041E968 EB82                 jmp 0041E8EC                  ;flag ax=3= no more time!

* Referenced by a Jump at Address:0041E95C(C)
:0041E96A E8A9000000              call 0041EA18    ;     dummy call
:0041E96F B801000000              mov eax, 1       ;trial FLAG 1: time not to be...
:0041E974 E973FFFFFF              jmp 0041E8EC     ;...checked or something: return 1 

* Referenced by a Jump at Address:0041E943(C)
:0041E979 C745FCFFFFFFFF          mov [ebp-04], FFFFFFFF    ;dummy parameter
:0041E980 E893000000              call 0041EA18             ;dummy call
:0041E985 B801000000              mov eax, 1                ;trial flag 1
:0041E98A E95DFFFFFF              jmp 0041E8EC              ;return with trial flag 1
OK, we can now experiment a little... since the return flag of this function is important, you may want to see what happens when you return: 0, 2, 4 (just try it :-) and 5. (parameter fiddling).

The big question is of course: what is the sscanf above? The sscanf function reads data from buffer into the locations given by each argument. Every argument must be a pointer to a variable with a type that corresponds to a type specifier in format.

The sscanf function returns the NUMBER of fields that were successfully converted and assigned. The return value does not include the fields that were read but not assigned.

The return value is EOF for an attempt to read at end of string A return value of ZERO means that no fields were assigned
among other things sscanf calls _isctype and isspace!
isspace is a test for white space chars (0x9, 0xD, 0x20)
_isctype is a test for integer values in an ASCII environment (alphanumeric, letters or ASCII)

So we have here the part of the target code that checks if the name and the serial number you have entered are or, are not, valid.
Actually, to be simple, sscanf goes into a string and interprets it according to the format specifications... let's seay you want for instance to convert a STRING OF DIGITS INTO AN INTEGER (typical of password protections :-)
In that case you would write in C:
sscanf (char_array_digitz, "%d",&intstorez);
this statement will convert the string of digits held inside the array of type char into type int, and store it into the variable intstorez
Well, if you want to learn more you'll find many resources about C language (and sscanf) online... just read on!

You'll notice that we have THREE xoring operations inside the code above: it work like this:
          8B45F0             mov eax, dword ptr [ebp-10]  ;get value
:0041E8D1 3501101000         xor eax, 00101001            ;1) here xor it with 0x00101001
:0041E91B 3510101100         xor eax, 00111010            ;2) here xor it with 0x00111010
:0041E93B 3501110111         xor eax, 11011101            ;3) here xor it with 0x11011101
          3B45EC             cmp eax, dword ptr [ebp-14]  ;[ebp-14] like xored [ebp-10]?
XOR is a "logical" operation, like and, not and all the other that you'll learn if you continue on your cracking path.
You take the bits of your two operands and check, each bit of the resultant dword is set to 1 ONLY if the corrisponding bits of the two operands contain opposite values.
So, first of all the three right operands of our three XORs are HEXADECIMAL values, in a "binary-similar" format: 0x00101001, 0x00111010, 0x11011101. (Watch it when you will search for these instructions inside the listing, there are two occurrences inside our target, and the second one is the correct one, as you'll notice if you acquire the GOOD practice of ALWAYS checking the code "around" your search strings)!
At your base calculator! Use hexadecimaml values and xore them, and see how they see out in binary (and how the xoring affects the bits!)
In my case we have always Ox34829AB7 inside [ebp-10]
which, xored with 0x01101000 unfortunately does not give
0x25838bb6 (the value that I always had inside [ebp-14]... therefore we are unfortunately NOT REGISTERED!

This Ox34829AB7 that we have inside [ebp-10]
xored with 0x10101100 (at the second check) does not give either
0x25838bb6 any more (it would have done it at the beginning, by the first run of our target) therefore we don't get flag 5 and that means that we have CHOSEN THE SPECIAL advanced features option!

Finally, our Ox34829AB7, that we have inside [ebp-10]
xored with the third xoring choice: 0x01110111 does indeed
give us 0x25838bb6 therefore we have snapped the advanced features and we are running the trial time flag.

What do we learn from this, besides using our base calculator?
1) That the only thing that matter is to get flag 4, therefore we just need to xor with 0x01110111 at the FIRST occurrence to have it every time!
2) That even xoring with 0x01110111 at the SECOND OCCURRENCE would be good, since we would have 'just started' flag 5 every time.
3) That the only thing we really don't need is xoring 0x01110111 at the third xoring occurrence, since that's the "normal" trial period checking.
4) That this protection is incredibly lame and that the programmer should NEVER have included a 'registering' flag inside the target.

In order to crack the above target you may of course now choose HUNDRED different solutions, and you may apply the crack wherever you want inside the get the flag subroutine.

Now that you have seen the protection scheme naked, try to work a little on this using the DEBUGGER that you have downloaded for the previous "tekfact" lesson (iwindebug).
Set some location breakpoints just before the xores above, and follow in the register window (and in the memory windows) what's going on. You'll have a taste of the 'live' approach to cracking, that we will use in the next lessons. Dead listing and live approach together can reverse ANY code you will encounter on your way, even if it has been written on Mars (or at Micro$oft :-)

I showed you enough, I'm not going to give you ANY ready made solution to crack this target, you don't need it any more. In fact I will never give ready made cracks again, you are (gonna be) real crackers: you don't need people chewing code for you and spitting out ready made solutions any more! Reread this lesson, experiment a little and crack this target on your own, it's very easy (now).

Well, I reckon that's enough for this second lesson.

(c) reverser+ December 1997. All rights reserved.


You are deep inside reverser's page of reverse engineering, choose your way out:

redhomepage redlinks redanonymity +ORC redstudents' essays redacademy database
redtools redcocktails redantismut CGI-scripts redsearch_forms redmail_fravia
redIs reverse engineering legal?