home *** CD-ROM | disk | FTP | other *** search
- HOW TO CRACK, by +ORC, A TUTORIAL
-
- ---------------------------------------------------------------------------
-
- LESSON C (2) - How to crack, Cracking as an art
-
- ---------------------------------------------------------------------------
-
- [INSTANT ACCESS]
-
- --------------------------------------
-
- cracking Instant Access (2) - strainer for the +HCU
-
- [SEE LESSON C.1 for the first part of this cracking session]
- Here follow the relevant protection routines for the first
- (The "Registration") number_code of Instant Access, with my
- comments: you have to investigate a little the following code.
- Later, when you'll crack on your own, try to recognize the
- many routines that fiddle with input BEFORE the relevant (real
- protection) one. In this case, for instance, a routine checks the
- correctness of the numbers of your input:
-
- This_loop_checks_that_numbers_are_numbers:
- 1B0F:2B00 C45E06 LES BX,[BP+06] ; set/reset pointer
- 1B0F:2B03 03DF ADD BX,DI
- 1B0F:2B05 268A07 MOV AL,ES:[BX] ; get number
- 1B0F:2B08 8846FD MOV [BP-03],AL ; store
- 1B0F:2B0B 807EFD30 CMP BYTE PTR [BP-03],30
- 1B0F:2B0F 7C06 JL 2B17 ; less than zero?
- 1B0F:2B11 807EFD39 CMP BYTE PTR [BP-03],39
- 1B0F:2B15 7E05 JLE 2B1C ; between 0 & 9?
- 1B0F:2B17 B80100 MOV AX,0001 ; no, set flag=1
- 1B0F:2B1A EB02 JMP 2B1E ; keep flag
- 1B0F:2B1C 33C0 XOR AX,AX ; flag=0
- 1B0F:2B1E 0BC0 OR AX,AX ; is it zero?
- 1B0F:2B20 7507 JNZ 2B29 ; flag NO jumps away
- 1B0F:2B22 8A46FD MOV AL,[BP-03] ; Ok, get number
- 1B0F:2B25 8842CC MOV [BP+SI-34],AL ; Ok, store number
- 1B0F:2B28 46 INC SI ; inc storespace
- 1B0F:2B29 47 INC DI ; inc counter
- 1B0F:2B2A C45E06 LES BX,[BP+06] ; reset pointer
- 1B0F:2B2D 03DF ADD BX,DI ; point next number
- 1B0F:2B2F 26803F00 CMP BYTE PTR ES:[BX],00 ; input end?
- 1B0F:2B33 75CB JNZ 2B00 ; no:loop next num
-
- You now obviously understand that the "real" string is
- stored inside memory location [BP+SI-34]... set a memory
- breakpoint on this area to get the next block of code that
- fiddles with the transformed input. Notice how this routine
- "normalizes" the input, strips the "-" off and puts the 10
- numbers together:
- user input: 1 2 1 2 1 2 1 2 1 2 End
- 1E7F:92E2 31 32 31 32 31 32 31 32 31 32 00 45 AF 1F 70 9B
- Stack ptr: 0 1 2 3 4 5 6 7 8 9 A B C D E F
- Let's now look at the "real" protection routine: the one
- that checks these numbers and throw you out if they are not
- "sound". Please pay attention to the following block of code:
-
- check_if_sum_other_9_numbers_=_remainder_of_the_third_number:
- :4B79 8CD0 MOV AX,SS ; we'll work inside the stack...
- :4B7B 90 NOP
- :4B7C 45 INC BP
- :4B7D 55 PUSH BP ; save real BP
- :4B7E 8BEC MOV BP,SP ; BP = stackpointer
- :4B80 1E PUSH DS ; save real Datasegment
- :4B81 8ED8 MOV DS,AX ; Datasegment = stacksegment
- :4B83 83EC04 SUB SP,+04
- :4B86 C45E06 LES BX,[BP+06] ; BX points input_start
- :4B89 268A07 MOV AL,ES:[BX] ; load first number
- :4B8C 98 CBW ; care only for low
- :4B8D C45E06 LES BX,[BP+06] ; reset pointer
- :4B90 50 PUSH AX ; save 1st number
- :4B91 268A4701 MOV AL,ES:[BX+01] ; load 2nd number
- :4B95 98 CBW ; only low
- :4B96 8BD0 MOV DX,AX ; 2nd number in DX
- :4B98 58 POP AX ; get 1st number
- :4B99 03C2 ADD AX,DX ; sum with second
- :4B9B C45E06 LES BX,[BP+06] ; reset pointer
- :4B9E 50 PUSH AX ; save sum
- :4B9F 268A4707 MOV AL,ES:[BX+07] ; load 8th number
- :4BA3 98 CBW ; only low
- :4BA4 8BD0 MOV DX,AX ; 8th number in DX
- :4BA6 58 POP AX ; old sum is back
- :4BA7 03C2 ADD AX,DX ; sum 1+2+8
- :4BA9 C45E06 LES BX,[BP+06] ; reset pointer
- :4BAC 50 PUSH AX ; save sum
- :4BAD 268A4703 MOV AL,ES:[BX+03] ; load 4rd number
- :4BB1 98 CBW ; only low
- :4BB2 8BD0 MOV DX,AX ; #4 in DX
- :4BB4 58 POP AX ; sum is back
- :4BB5 03C2 ADD AX,DX ; sum 1+2+8+4
- :4BB7 C45E06 LES BX,[BP+06] ; reset pointer
- :4BBA 50 PUSH AX ; save sum
- :4BBB 268A4704 MOV AL,ES:[BX+04] ; load 5th number
- :4BBF 98 CBW ; only low
- :4BC0 8BD0 MOV DX,AX ; #5 in DX
- :4BC2 58 POP AX ; sum is back
- :4BC3 03C2 ADD AX,DX ; 1+2+8+4+5
- :4BC5 C45E06 LES BX,[BP+06] ; reset pointer
- :4BC8 50 PUSH AX ; save sum
- :4BC9 268A4705 MOV AL,ES:[BX+05] ; load 6th number
- :4BCD 98 CBW ; only low
- :4BCE 8BD0 MOV DX,AX ; #6 in DX
- :4BD0 58 POP AX ; sum is back
- :4BD1 03C2 ADD AX,DX ; 1+2+8+4+5+6
- :4BD3 C45E06 LES BX,[BP+06] ; reset pointer
- :4BD6 50 PUSH AX ; save sum
- :4BD7 268A4706 MOV AL,ES:[BX+06] ; load 7th number
- :4BDB 98 CBW ; only low
- :4BDC 8BD0 MOV DX,AX ; #7 in DX
- :4BDE 58 POP AX ; sum is back
- :4BDF 03C2 ADD AX,DX ; 1+2+8+4+5+6+7
- :4BE1 C45E06 LES BX,[BP+06] ; reset pointer
- :4BE4 50 PUSH AX ; save sum
- :4BE5 268A4708 MOV AL,ES:[BX+08] ; load 9th number
- :4BE9 98 CBW ; only low
- :4BEA 8BD0 MOV DX,AX ; #9 in DX
- :4BEC 58 POP AX ; sum is back
- :4BED 03C2 ADD AX,DX ; 1+2+8+4+5+6+7+9
- :4BEF C45E06 LES BX,[BP+06] ; reset pointer
- :4BF2 50 PUSH AX ; save sum
- :4BF3 268A4709 MOV AL,ES:[BX+09] ; load 10th #
- :4BF7 98 CBW ; only low
- :4BF8 8BD0 MOV DX,AX ; #10 in DX
- :4BFA 58 POP AX ; sum is back
- :4BFB 03C2 ADD AX,DX ; 1+2+8+4+5+6+7+9+10
- :4BFD 0550FE ADD AX,FE50 ; clean sum to 0-51
- :4C00 BB0A00 MOV BX,000A ; BX holds 10
- :4C03 99 CWD ; only AL
- :4C04 F7FB IDIV BX ; remainder in DX
- :4C06 C45E06 LES BX,[BP+06] ; reset pointer
- :4C09 268A4702 MOV AL,ES:[BX+02] ; load now # 3
- :4C0D 98 CBW ; only low
- :4C0E 05D0FF ADD AX,FFD0 ; clean # 3 to 0-9
- :4C11 3BD0 CMP DX,AX ; remainder = pampered #3?
- :4C13 7407 JZ 4C1C ; yes, go on good guy
- :4C15 33D2 XOR DX,DX ; no! beggar off! Zero DX
- :4C17 33C0 XOR AX,AX ; and FLAG_AX = FALSE
- :4C19 E91701 JMP 4D33 ; go to EXIT
- let's_go_on_if_first_check_passed:
- :4C1C C45E06 LES BX,[BP+06] ; reset pointer
- :4C1F 268A4701 MOV AL,ES:[BX+01] ; now load #2 anew
- :4C23 98 CBW ; only low
- :4C24 05D7FF ADD AX,FFD7 ; pamper adding +3
- :4C27 A38D5E MOV [5E8D],AX ; save SEC_+3
- :4C2A 3D0900 CMP AX,0009 ; was it < 9? (no A-F)
- :4C2D 7E05 JLE 4C34 ; ok, no 0xletter
- :4C2F 832E8D5E0A SUB WORD PTR [5E8D],+0A ; 0-5 if A-F
- :4C34 C45E06 LES BX,[BP+06] ; reset pointer
- :4C37 268A07 MOV AL,ES:[BX] ; load 1st input number
- :4C3A 98 CBW ; only low
- :4C3B 05C9FF ADD AX,FFC9 ; pamper adding +7
- :4C3E A38F5E MOV [5E8F],AX ; save it in FIR_+7
- :4C41 0BC0 OR AX,AX ; if #1 > 7
- :4C43 7D05 JGE 4C4A ; no need to add 0xA
- :4C45 83068F5E0A ADD WORD PTR [5E8F],+0A ; FIR_+7 + 0xA
- now_we_have_the_sliders_let's_prepare_for_loop:
- :4C4A C45E0E LES BX,[BP+0E] ; Set pointer to E
- :4C4D 26C747020000 MOV WORD PTR ES:[BX+02],0000 ; 0 flag
- :4C53 26C7070000 MOV WORD PTR ES:[BX],0000 ; 0 flag
- :4C58 C706975E0900 MOV WORD PTR [5E97],0009 ; counter=9
- :4C5E E99500 JMP 4CF6 ; Jmp check_counter
- loop_8_times:
- :4C61 C45E06 LES BX,[BP+06] ; reset pointer
- :4C64 031E975E ADD BX,[5E97] ; add running counter
- :4C68 268A07 MOV AL,ES:[BX] ; load # counter+1
- :4C6B 98 CBW ; only low
- :4C6C 50 PUSH AX ; save 10th number
- :4C6D A18D5E MOV AX,[5E8D] ; ld SEC_+3 down_slider
- :4C70 BA0A00 MOV DX,000A ; BX holds 0xA
- :4C73 F7EA IMUL DX ; SEC_+3 * 0xA
- :4C75 03068F5E ADD AX,[5E8F] ; plus FIR_+7 up_slider
- :4C79 BAA71E MOV DX,1EA7 ; fixed segment
- :4C7C 8BD8 MOV BX,AX ; BX = Lkup_val=(SEC_+3*10+FIR_+7)
- :4C7E 8EC2 MOV ES,DX ; ES = 1EA7
- :4C80 268A870000 MOV AL,ES:[BX+0000] ; ld 1EA7:[Lkup_val]
- :4C85 98 CBW ; only low: KEY_PAR
- :4C86 8BD0 MOV DX,AX ; save KEY_PAR in DX
- :4C88 58 POP AX ; repops 10th number
- :4C89 03C2 ADD AX,DX ; RE_SULT=KEY_PAR+#10
- :4C8B 05D0FF ADD AX,FFD0 ; polish RE_SULT
- :4C8E 99 CWD ; only low: RE_SULT
- :4C8F 8956FC MOV [BP-04],DX ; save here KEY_PAR [9548]
- :4C92 8946FA MOV [BP-06],AX ; save here RE_SULT [9546]
- :4C95 0BD2 OR DX,DX ; KEY_PAR < 0?
- :4C97 7C0F JL 4CA8 ; yes: KEY_PAR < 0
- :4C99 7F05 JG 4CA0 ; no: KEY_PAR > 0
- :4C9B 3D0900 CMP AX,0009 ; KEY_PAR = 0
- :4C9E 7608 JBE 4CA8 ; no pampering if RE_SULT < 9
- :4CA0 836EFA0A SUB WORD PTR [BP-06],+0A ; else pamper
- :4CA4 835EFC00 SBB WORD PTR [BP-04],+00 ; and SBB [9548]
- :4CA8 C45E0E LES BX,[BP+0E] ; reset pointer to E
- :4CAB 268B4F02 MOV CX,ES:[BX+02] ; charge CX [958C]
- :4CAF 268B1F MOV BX,ES:[BX] ; charge BX slider [958A]
- :4CB2 33D2 XOR DX,DX ; clear DX to zero
- :4CB4 B80A00 MOV AX,000A ; 10 in AX
- :4CB7 9A930D2720 CALL 2027:0D93 ; call following RO_routine
-
- This is the only routine called from our protection, inside the
- loop (therefore 8 times), disassembly from WCB. Examining this
- code please remember that we entered here with following
- configuration: DX=0, AX=0xA, CX=[958C] and BX=[958A]...
- 1.0D93 56 push si ; save si
- 1.0D94 96 xchg ax, si ; ax=si, si=0xA
- 1.0D95 92 xchg ax, dx ; dx=0xA ax=dx
- 1.0D96 85C0 test ax, ax ; TEST this zero
- 1.0D98 7402 je 0D9C ; zero only 1st time
- 1.0D9A F7E3 mul bx ; BX slider! 0/9/5E/3B2...
- 1.0D9C >E305 jcxz 0DA3 ; cx=0? don't multiply!
- 1.0D9E 91 xchg ax, cx ; cx !=0? cx = ax & ax = cx
- 1.0D9F F7E6 mul si ; ax*0xA in ax
- 1.0DA1 03C1 add ax, cx ; ax= ax*0xA+cx = M_ULT
- 1.0DA3 >96 xchg ax, si ; ax=0xA; si evtl. holds M_ULT
- 1.0DA4 F7E3 mul bx ; ax= bx*0xA
- 1.0DA6 03D6 add dx, si ; dx= dx_add
- 1.0DA8 5E pop si ; restore si
- 1.0DA9 CB retf ; back to caller with two
- parameters: DX and AX
- Back_to_main_protection_loop_from_RO_routine:
- :4CBC C45E0E LES BX,[BP+0E] ; reset pointer
- :4CBF 26895702 MOV ES:[BX+02],DX ; save R_DX par [958C]
- :4CC3 268907 MOV ES:[BX],AX ; save R_AX par [958A]
- :4CC6 0346FA ADD AX,[BP-06] ; add to AX RE_SULT [9546]
- :4CC9 1356FC ADC DX,[BP-04] ; add to DX KEY_PAR [9548]
- :4CCC C45E0E LES BX,[BP+0E] ; reset pointer
- :4CCF 26895702 MOV ES:[BX+02],DX ; save R_DX+KEY_PAR [958C]
- :4CD3 268907 MOV ES:[BX],AX ; save R_AX+RE_SULT [958A]
- :4CD6 FF0E8D5E DEC WORD PTR [5E8D] ; down_slide SEC_+3
- :4CDA 7D05 JGE 4CE1 ; no need to add
- :4CDC 83068D5E0A ADD WORD PTR [5E8D],+0A ; pamper adding 10
- :4CE1 FF068F5E INC WORD PTR [5E8F] ; up_slide FIR_+7
- :4CE5 A18F5E MOV AX,[5E8F] ; save upslided FIR_+7 in AX
- :4CE8 3D0900 CMP AX,0009 ; is it over 9?
- :4CEB 7E05 JLE 4CF2 ; no, go on
- :4CED 832E8F5E0A SUB WORD PTR [5E8F],+0A ; yes, pamper -10
- :4CF2 FF0E975E DEC WORD PTR [5E97] ; decrease loop counter
- check_loop_counter:
- :4CF6 833E975E03 CMP WORD PTR [5E97],+03 ; counter = 3?
- :4CFB 7C03 JL 4D00 ; finish if counter under 3
- :4CFD E961FF JMP 4C61 ; not yet, loop_next_count
- loop_is_ended:
- :4D00 C45E06 LES BX,[BP+06] ; reset pointer to input
- :4D03 268A4701 MOV AL,ES:[BX+01] ; load 2nd number (2)
- :4D07 98 CBW ; only low
- :4D08 05D0FF ADD AX,FFD0 ; clean it
- :4D0B BA0A00 MOV DX,000A ; DX = 10
- :4D0E F7EA IMUL DX ; AX = SEC_*10 = 14
- :4D10 C45E06 LES BX,[BP+06] ; reset pointer
- :4D13 50 PUSH AX ; save SEC_*10
- :4D14 268A07 MOV AL,ES:[BX] ; load 1st number (1)
- :4D17 98 CBW ; only low
- :4D18 8BD0 MOV DX,AX ; save in DX
- :4D1A 58 POP AX ; get SEC_*10
- :4D1B 03C2 ADD AX,DX ; sum SEC_*10+1st number
- :4D1D 05D0FF ADD AX,FFD0 ; clean it
- :4D20 99 CWD ; only low
- :4D21 C45E0A LES BX,[BP+0A] ; get pointer to [9582]
- :4D24 26895702 MOV ES:[BX+02],DX ; save 1st (1) in [9584]
- :4D28 268907 MOV ES:[BX],AX ; save FINAL_SUM (15) [9582]
- :4D2B 33D2 XOR DX,DX ; DX = 0
- :4D2D B80100 MOV AX,0001 ; FLAG TRUE !
- :4D30 E9E6FE JMP 4C19 ; OK, you_are_a_nice_guy
- EXIT:
- :4D33 59 POP CX ; pop everything and
- :4D34 59 POP CX ; return with flag
- :4D35 1F POP DS ; AX=TRUE if RegNum OK
- :4D36 5D POP BP ; with 1st # in [9584]
- :4D37 4D DEC BP ; with FINAL_SUM in [9582]
- :4D38 CB RETF
-
- Let's translate the preceding code: first of all the pointers:
- At line :4B86 we have the first of a long list of stack ptrs:
- LES BX,[BP+06]
- This stack pointer points to the beginning of the input string,
- which, once polished from the "-", has now a length of 10 bytes,
- concluded by a 00 fence. At the beginning, before the main loop,
- 9 out of our 10 numbers are added, all but the third one.
- Notice that protection has jumped # 3 (and added # 8 out of the
- line). The rest is straightforward. Now, at line :4BFD we have
- our first "cleaning" instruction. You see: the numbers are
- hexadecimal represented by the codes 0x30 to 0x39. If you add
- FE50 to the minimum sum you can get adding 9 numbers (0x30*9 =
- 0x160) You get 0. The maximum you could have adding 9 numbers,
- on the contrary is (0x39*9=0x201), which, added to FE50 gives
- 0x51. So we'll have a "magic" number between 0x0 and 0x51 instead
- of a number between 0x160 and 0x201. Protection pampers this
- result, and retains only the last ciffer: 0-9. Then protection
- divides this number through 0xA, and what happens? DX get's the
- REMAINDER of it.
- If we sum the hexcodes of our (1212-1212-12) we get 0x1BE (we
- sum only 9 out of then numbers: the third "1" -i.e. "31"- does
- not comes into our count); 0x1BE, cleaned and pampered gives E.
- Therefore (0xE/0xA = 1) We get 1 with a remainder of 4.
- You may observe that of all possible answers, only sums
- finishing with A, B, C, D, E or F give 1 (and rem=0,1,2,3,4 or
- 5). Sums finishing 0 1 2 3 4 5 6 7 8 or 9 give 0 as result and
- themselves as reminder. The chance of getting a 0,1,2,3 or 4 are
- therefore bigger as the chance of getting a 5, 6, 7, 8 or 9. We
- are just observing... we do not know yet if this should play a
- role or not.
- Now this remainder is compared at :4C11 with the third number
- polished from 0x30-0x39 to 0-9. This is the only protection check
- for the registration number input: If your third number does not
- match with the remainder of the sum of all the 9 others numbers
- of your input you are immediately thrown out with FLAG AX=FALSE
- (i.e. zero).
- To crack the protection you now have to MODIFY your input string
- accordingly. Our new input string will from now on be "1242-1212-
- 12": we have changed our third number (originally a "2") to a "4"
- to get through this first strainer in the correct way. Only now
- protection starts its mathematical part (We do not know yet why
- it does it... in order to seed the random product number? To
- provide a check for the registration number you'll input at the
- end? We'll see).
- - Protection saves the second number of your input (cleaned
- with FFD7) in SEC_+3 [5E8D], pampering it if it is bigger
- than 9 (i.e. if it is 0xA-0xF). Here you'll have therefore
- following correspondence: 0=7 1=8 2=9 3=0 4=1 5=2 6=3 7=4
- 8=5 9=6. The second number of your input has got added +3.
- This is value SEC_+3. In (lengthy) C it would look like
- this:
- If (RegString(2)is lower than 7) RegString(2) = RegString(2)+3
- Else Regstring(2) = ((RegString(2)-10)+3)
- - Protection saves your first number in FIR_+7 [5E8F] with a
- different cleaning parameter (FFC9). The next pampering
- adds 0xA if it was not 7/8/9 therefore you have here
- following correspondence 7=0 8=1 9=2 0=3 1=4 2=5 3=6 4=7
- 5=8 6=9). This is value FIR_+7. In (lengthy) C it would
- look like this:
- If (RegString(1) is lower than 3) RegString(1) = RegString(1)+7
- Else Regstring(1) = ((RegString(1)-10)+7)
- So protection has "transformed" and stored in [5E8D] and [5E8F]
- the two numbers 1 and 2. In our RegString: 1242-1212-12 the first
- two numbers "12" are now stored as "94". These will be used as
- "slider" parameters inside the main loop, as you will see.
- Only now does protection begin its main loop, starting from the
- LAST number, because the counter has been set to 9 (i.e. the
- tenth number of RegString). The loop, as you'll see, handles only
- the numbers from 10 to 3: it's an 8-times loop that ends without
- handling the first and second number. What happens in this
- loop?... Well, quite a lot: Protection begins the loop loading
- the number (counter+1) from the RegString. Protection then loads
- the SEC_+3 down_slider parameter (which began its life as second
- number "transformed"), multiplies it with 0xA and then adds the
- up_slider parameter FIR_+7 (at the beginning it was the first
- number transformed).
- This sum is used as "lookup pointer" to find a parameter
- inside a table of parameters in memory, which are all numbers
- between 0 and 9. Let's call this value Lkup_val.
- Protection looks for data in 1EA7:[Lkup_val]. In our case (we
- entered 1242-1212-12, therefore the first SEC_+3 value is 9 and
- the first FIR_+7 value is 4): [Lkup_val] = 9*0xA+4; 0x5A+4 =
- 0x5E. At line :4C80 therefore AL would load the byte at 1EA7:005E
- (let's call it KEY_PAR), which now would be ADDED to the #
- counter+1 of this loop. In our case KEY_PAR at 1EA7:005E it's a
- "7" and is added to the pampered 0x32=2, giving 9.
- Let's establish first of all which KEY_PAR can possibly get
- fetched: the maximum is 0x63 and the minimum is 0x0. The possible
- KEY_PARs do therefore dwell in memory between 1EA7: and
- 1EA7:0063. Let's have a look at the relative table in memory,
- where these KEY_PARs are stored ("our" first 0x5Eth byte is
- underlined):
- 1EA7:0000 01 03 03 01 09 02 03 00-09 00 04 03 08 07 04 04
- 1EA7:0010 05 02 09 00 02 04 01 05-06 06 03 02 00 08 05 06
- 1EA7:0020 08 09 05 00 04 06 07 07-02 00 08 00 06 02 04 07
- 1EA7:0030 04 04 09 05 09 06 00 06-08 07 00 03 05 09 00 08
- 1EA7:0040 03 07 07 06 08 09 01 05-07 04 06 01 04 02 07 01
- 1EA7:0050 03 01 08 01 05 03 03 01-02 08 02 01 06 05 07 02
- 1EA7:0060 05 09 09 08 02 09 03 00-00 04 05 01 01 03 08 06
- 1EA7:0070 01 01 09 00 02 05 05 05-01 07 01 05 08 07 01 09
- 1EA7:0080 08 07 07 04 04 08 03 00-06 01 09 08 08 04 09 09
- 1EA7:0090 00 07 05 02 03 01 03 08-06 05 07 06 03 07 06 07
- 1EA7:00A0 04 02 02 05 02 04 06 02-06 09 09 01 05 02 03 04
- 1EA7:00B0 04 00 03 05 00 03 08 07-06 04 08 08 02 00 03 06
- 1EA7:00C0 09 00 00 06 09 04 07 02-00 01 01 01 01 00 01 FF
- 1EA7:00D0 00 FF FF FF FF 00 FF 01-00 00 00 00 00 00 00 00
-
- An interesting table, where all the correspondences are
- between 0 and 9... are we getting some "secret" number here? But,
- hey, look there... funny, isn't it? Instead of only 0-0x63 bytes
- we have roughly the DOUBLE here: 0-0xC8 bytes (the 01 sequence
- starting at CA "feels" like a fence). We'll see later how
- important this is. At the moment you should only "perceive" that
- something must be going on with a table that's two time what she
- should be.
- As I said the result of KEY_PAR + input number is polished
- (with a FFDO) and pampered (subtracting, if necessary, 0xA).
- Therefore the result will be the (counter+1) input number +
- KEY_PAR (let's call it RE_SULT], in our case, (at the beginning
- of the loop) a 9. Now (DX=0 because of the CWD instruction) DX
- will be saved in [9548] and RE_SULT in [9546].
- Now Protection prepares for the RO_routine: resets its pointer
- and charges CX and BX from [958C] and from [958A] respectively,
- charges AX with 0xA and sets DX to zero.
- The routine performs various operations on AX and DX and saves
- the results in the above mentioned locations [958A] and [958C].
- Now KEY_PAR and RE_SULT are added respectively to the DX and AX
- value we got back from the RO_routine call, and saved once more
- in the last two locations: AX+RE_SULT in [958A] and DX+KEY_PAR
- in [958C]
- Now the value in SEC_+3 is diminished by 1 (if it was 9 it's now
- 8, if it was zero it will be pampered to 9). It's a "slider"
- parameter (in this case a down_slider), typically used in
- relatively complicated protections to give a "random" impression
- to the casual observer. The value in FIR_+7, on the contrary, is
- augmented by one, from 4 to 5... up_sliding also.
- Protection now handles the next number of your input for the
- loop. In our case this loop uses following protection
- configuration with our "sliding" parameters:
- Input # pamp_2nd pamp_1st Lookup value KEY_PAR # RE_SULT
- # 10 = 2, SEC_+3= 9, FIR_+7= 4, Lkup_val = 0x5E, KEY=7 +2 = 9
- # 9 = 1, SEC_+3= 8, FIR_+7= 5, Lkup_val = 0x55, KEY=3 +1 = 4
- # 8 = 2, SEC_+3= 7, FIR_+7= 6, Lkup_val = 0x4C, KEY=4 +2 = 6
- # 7 = 1, SEC_+3= 6, FIR_+7= 7, Lkup_val = 0x43, KEY=7 +1 = 7
- # 6 = 2, SEC_+3= 5, FIR_+7= 8, Lkup_val = 0x3A, KEY=0 +2 = 2
- # 5 = 1, SEC_+3= 4, FIR_+7= 9, Lkup_val = 0x31, KEY=4 +1 = 5
- # 4 = 2, SEC_+3= 3, FIR_+7= 0, Lkup_val = 0x1E, KEY=5 +2 = 7
- # 3 = 4, SEC_+3= 2, FIR_+7= 1, Lkup_val = 0x15, KEY=2 +4 = 5
- Notice how our "regular" input 21212124 has given an "irregular"
- 94672575.
- You may legitimately ask yourself what should all this mean:
- what are these RE_SULTs used for? Well they are used to slide
- another parameter: this one inside the called routine... this is
- what happens to AX and DX inside the routine, and the lines after
- the called routine:
- :4CBF 26895702 MOV ES:[BX+02],DX ; save R_DX par [958C]
- :4CC3 268907 MOV ES:[BX],AX ; save R_AX par [958A]
- :4CC6 0346FA ADD AX,[BP-06] ; add to AX RE_SULT [9546]
- :4CC9 1356FC ADC DX,[BP-04] ; add to DX KEY_PAR [9548]
- :4CCC C45E0E LES BX,[BP+0E] ; reset pointer to E
- :4CCF 26895702 MOV ES:[BX+02],DX ; save R_DX+KEY_PAR [958C]
- :4CD3 268907 MOV ES:[BX],AX ; save R_AX+RE_SULT [958A]
-
- :4CC6 :4CC9 :4CCF Odd_DX :4CD3 slider_sum
- RE_SULT [958A] [958C] [958C] [958A]
- 0 0 0 0 0
- 9 5A 0 0 9
- 4 3AC 0 0 5E
- 6 24F4 0 0 3B2
- 7 71CE 1 1 24FB
- 2 7220 4 E 71D0
- 5 7572 4 90 7225
- 7579
-
- Now the loops ends, having handled the input numbers from tenth
- to third. Protection loads the second number and multiplies it
- by 10 (let's call this result SEC_*10), in our case 2*0xA=14.
- Protection loads the first number and adds it to the
- multiplication, in our case 1+0x14=0x15 (FINAL_SUM].
- Now everything will be added to FFDO to "clean" it.
- Pointer will now be set to the end of the input number.
- DX, zeroed by CDW, will be saved as parameter in [9584] and the
- cleaned and pampered sum will be saved in [9582].
- FLAG is set to true and this routine is finished! No parameter
- are passed and the only interesting thing is what actually
- happens in the locations [9582], [9584], [958A] and [958C], i.e.:
- FINAL_SUM, 0, slider_sum, odd_dx.
- In the next lesson we'll crack everything, but I'll give you
- already some hints here, in case you would like to go ahead on
- your own: we'll see how the scheme used for the third (the
- registration) number show analogies and differences with the
- scheme we have studied (and cracked) here for the first number.
- Our 3434-3434-3434-3434-34 input string for the registration
- number will be transformed in the magic string
- 141593384841547431, but this will not work because the "magic"
- 12th number: "1" will not correspond to the remainder calculated
- inside this check through the previous locations of the other
- checks.
- Here the things are more complicated because every little
- change in your input string transforms COMPLETELY the "magic"
- string... therefore in order to pass the strainer you'll have to
- change 3434-3434-3434-3434-34 in (for instance) 7434-3434-3434-
- 3434-96. The "magic" string 219702960974498056 that this
- registration input gives will go through the protection strainer.
- Only then we'll be able to step over and finally crack the whole
- protection... it's a pretty complicated one as I said. Now crack
- it pupils... you have three months time. From this crack depends
- your admission to the Uni, there will be no other admission text
- till summer 1997 (it's a hell of work to prepare this crap)...
- work well.
-
- Well, that's it for this lesson, reader. Not all lessons of my
- tutorial are on the Web.
- You 'll obtain the missing lessons IF AND ONLY IF you mail
- me back (via anon.penet.fi) some tricks of the trade I may not
- know but YOU've discovered. I'll probably know most of them
- already, but if they are really new you'll be given full credit,
- and even if they are not, should I judge that you "rediscovered"
- them with your work, or that you actually did good work on them,
- I'll send you the remaining lessons nevertheless. Your
- suggestions and critics on the whole crap I wrote are also
- welcomed.
-
- E-mail +ORC
-
- +ORC an526164@anon.penet.fi
-