home *** CD-ROM | disk | FTP | other *** search
/ Reverse Code Engineering RCE CD +sandman 2000 / ReverseCodeEngineeringRceCdsandman2000.iso / RCE / Library / +ORC / Orc pac C / HOWTOC2.TXT < prev    next >
Encoding:
Text File  |  2000-05-25  |  24.7 KB  |  483 lines

  1.  
  2.                        HOW TO CRACK, BY +ORC, A TUTORIAL
  3.                                        
  4.    
  5.      _________________________________________________________________
  6.    
  7.    
  8.    
  9.    LESSON C (2) - How to crack, Cracking as an art
  10.      _________________________________________________________________
  11.    
  12.    
  13.    
  14.    [INSTANT ACCESS]
  15.      _________________________________________________________________
  16.    
  17.    
  18.    
  19.  
  20.       cracking Instant Access (2) - strainer for the +HCU
  21.  
  22. [SEE LESSON C.1 for the first part of this cracking session]
  23.      Here follow the relevant protection routines for the first
  24. (The "Registration") number_code of Instant Access, with my
  25. comments: you have to investigate a little the following code.
  26.      Later, when you'll crack on your own, try to recognize the
  27. many routines that fiddle with input BEFORE the relevant (real
  28. protection) one. In this case, for instance, a routine checks the
  29. correctness of the numbers of your input:
  30.  
  31. This_loop_checks_that_numbers_are_numbers:
  32. 1B0F:2B00 C45E06    LES    BX,[BP+06]  ; set/reset pointer
  33. 1B0F:2B03 03DF      ADD    BX,DI
  34. 1B0F:2B05 268A07    MOV    AL,ES:[BX]  ; get number
  35. 1B0F:2B08 8846FD    MOV    [BP-03],AL  ; store
  36. 1B0F:2B0B 807EFD30  CMP    BYTE PTR [BP-03],30
  37. 1B0F:2B0F 7C06      JL     2B17        ; less than zero?
  38. 1B0F:2B11 807EFD39  CMP    BYTE PTR [BP-03],39
  39. 1B0F:2B15 7E05      JLE    2B1C        ; between 0 & 9?
  40. 1B0F:2B17 B80100    MOV    AX,0001     ; no, set flag=1
  41. 1B0F:2B1A EB02      JMP    2B1E        ; keep flag
  42. 1B0F:2B1C 33C0      XOR    AX,AX       ; flag=0
  43. 1B0F:2B1E 0BC0      OR     AX,AX       ; is it zero?
  44. 1B0F:2B20 7507      JNZ    2B29        ; flag NO jumps away
  45. 1B0F:2B22 8A46FD    MOV    AL,[BP-03]  ; Ok, get number
  46. 1B0F:2B25 8842CC    MOV    [BP+SI-34],AL ; Ok, store number
  47. 1B0F:2B28 46        INC    SI          ; inc storespace
  48. 1B0F:2B29 47        INC    DI          ; inc counter
  49. 1B0F:2B2A C45E06    LES    BX,[BP+06]  ; reset pointer
  50. 1B0F:2B2D 03DF      ADD    BX,DI       ; point next number
  51. 1B0F:2B2F 26803F00  CMP    BYTE PTR ES:[BX],00 ; input end?
  52. 1B0F:2B33 75CB      JNZ    2B00        ; no:loop next num
  53.  
  54.      You now obviously understand that the "real" string is
  55. stored inside memory location [BP+SI-34]... set a memory
  56. breakpoint on this area to get the next block of code that
  57. fiddles with the transformed input. Notice how this routine
  58. "normalizes" the input, strips the "-" off and puts the 10
  59. numbers together:
  60. user input:  1  2  1  2  1  2  1  2  1  2 End
  61.   1E7F:92E2 31 32 31 32 31 32 31 32 31 32 00 45 AF 1F 70 9B
  62.  Stack ptr:  0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F
  63.      Let's now look at the "real" protection routine: the one
  64. that checks these numbers and throw you out if they are not
  65. "sound". Please pay attention to the following block of code:
  66.  
  67. check_if_sum_other_9_numbers_=_remainder_of_the_third_number:
  68. :4B79 8CD0       MOV    AX,SS ; we'll work inside the stack...
  69. :4B7B 90         NOP
  70. :4B7C 45         INC    BP
  71. :4B7D 55         PUSH   BP    ; save real BP
  72. :4B7E 8BEC       MOV    BP,SP ; BP = stackpointer
  73. :4B80 1E         PUSH   DS    ; save real Datasegment
  74. :4B81 8ED8       MOV    DS,AX ; Datasegment = stacksegment
  75. :4B83 83EC04     SUB    SP,+04
  76. :4B86 C45E06     LES    BX,[BP+06] ; BX points input_start
  77. :4B89 268A07     MOV    AL,ES:[BX] ; load first number
  78. :4B8C 98         CBW               ; care only for low
  79. :4B8D C45E06     LES    BX,[BP+06] ; reset pointer
  80. :4B90 50         PUSH   AX         ; save 1st number
  81. :4B91 268A4701   MOV    AL,ES:[BX+01] ; load 2nd number
  82. :4B95 98         CBW               ; only low
  83. :4B96 8BD0       MOV    DX,AX      ; 2nd number in DX
  84. :4B98 58         POP    AX         ; get 1st number
  85. :4B99 03C2       ADD    AX,DX      ; sum with second
  86. :4B9B C45E06     LES    BX,[BP+06] ; reset pointer
  87. :4B9E 50         PUSH   AX         ; save sum
  88. :4B9F 268A4707   MOV    AL,ES:[BX+07] ; load 8th number
  89. :4BA3 98         CBW               ; only low
  90. :4BA4 8BD0       MOV    DX,AX      ; 8th number in DX
  91. :4BA6 58         POP    AX         ; old sum is back
  92. :4BA7 03C2       ADD    AX,DX      ; sum 1+2+8
  93. :4BA9 C45E06     LES    BX,[BP+06] ; reset pointer
  94. :4BAC 50         PUSH   AX         ; save sum
  95. :4BAD 268A4703   MOV    AL,ES:[BX+03] ; load 4rd number
  96. :4BB1 98         CBW               ; only low
  97. :4BB2 8BD0       MOV    DX,AX      ; #4 in DX
  98. :4BB4 58         POP    AX         ; sum is back
  99. :4BB5 03C2       ADD    AX,DX      ; sum 1+2+8+4
  100. :4BB7 C45E06     LES    BX,[BP+06] ; reset pointer
  101. :4BBA 50         PUSH   AX         ; save sum
  102. :4BBB 268A4704   MOV    AL,ES:[BX+04] ; load 5th number
  103. :4BBF 98         CBW               ; only low
  104. :4BC0 8BD0       MOV    DX,AX      ; #5 in DX
  105. :4BC2 58         POP    AX         ; sum is back
  106. :4BC3 03C2       ADD    AX,DX      ; 1+2+8+4+5
  107. :4BC5 C45E06     LES    BX,[BP+06] ; reset pointer
  108. :4BC8 50         PUSH   AX         ; save sum
  109. :4BC9 268A4705   MOV    AL,ES:[BX+05] ; load 6th number
  110. :4BCD 98         CBW               ; only low
  111. :4BCE 8BD0       MOV    DX,AX      ; #6 in DX
  112. :4BD0 58         POP    AX         ; sum is back
  113. :4BD1 03C2       ADD    AX,DX      ; 1+2+8+4+5+6
  114. :4BD3 C45E06     LES    BX,[BP+06] ; reset pointer
  115. :4BD6 50         PUSH   AX         ; save sum
  116. :4BD7 268A4706   MOV    AL,ES:[BX+06] ; load 7th number
  117. :4BDB 98         CBW               ; only low
  118. :4BDC 8BD0       MOV    DX,AX      ; #7 in DX
  119. :4BDE 58         POP    AX         ; sum is back
  120. :4BDF 03C2       ADD    AX,DX      ; 1+2+8+4+5+6+7
  121. :4BE1 C45E06     LES    BX,[BP+06] ; reset pointer
  122. :4BE4 50         PUSH   AX         ; save sum
  123. :4BE5 268A4708   MOV    AL,ES:[BX+08] ; load 9th number
  124. :4BE9 98         CBW               ; only low
  125.  
  126. :4BEA 8BD0       MOV    DX,AX      ; #9 in DX
  127. :4BEC 58         POP    AX         ; sum is back
  128. :4BED 03C2       ADD    AX,DX      ; 1+2+8+4+5+6+7+9
  129. :4BEF C45E06     LES    BX,[BP+06] ; reset pointer
  130. :4BF2 50         PUSH   AX         ; save sum
  131. :4BF3 268A4709   MOV    AL,ES:[BX+09] ; load 10th #
  132. :4BF7 98         CBW               ; only low
  133. :4BF8 8BD0       MOV    DX,AX      ; #10 in DX
  134. :4BFA 58         POP    AX         ; sum is back
  135. :4BFB 03C2       ADD    AX,DX      ; 1+2+8+4+5+6+7+9+10
  136. :4BFD 0550FE     ADD    AX,FE50    ; clean sum to 0-51
  137. :4C00 BB0A00     MOV    BX,000A    ; BX holds 10
  138. :4C03 99         CWD               ; only AL
  139. :4C04 F7FB       IDIV   BX         ; remainder in DX
  140. :4C06 C45E06     LES    BX,[BP+06] ; reset pointer
  141. :4C09 268A4702   MOV    AL,ES:[BX+02] ; load now # 3
  142. :4C0D 98         CBW               ; only low
  143. :4C0E 05D0FF     ADD    AX,FFD0    ; clean # 3 to 0-9
  144. :4C11 3BD0       CMP    DX,AX  ; remainder = pampered #3?
  145. :4C13 7407       JZ     4C1C       ; yes, go on good guy
  146. :4C15 33D2       XOR    DX,DX  ; no! beggar off! Zero DX
  147. :4C17 33C0       XOR    AX,AX  ;     and FLAG_AX = FALSE
  148. :4C19 E91701     JMP    4D33       ; go to EXIT
  149. let's_go_on_if_first_check_passed:
  150. :4C1C C45E06     LES    BX,[BP+06] ; reset pointer
  151. :4C1F 268A4701   MOV    AL,ES:[BX+01] ; now load #2 anew
  152. :4C23 98         CBW               ; only low
  153.  
  154. :4C24 05D7FF     ADD    AX,FFD7    ; pamper adding +3
  155. :4C27 A38D5E     MOV    [5E8D],AX  ; save SEC_+3
  156. :4C2A 3D0900     CMP    AX,0009    ; was it  7
  157. :4C43 7D05       JGE    4C4A       ; no need to add 0xA
  158. :4C45 83068F5E0A ADD    WORD PTR [5E8F],+0A ; FIR_+7 + 0xA
  159. now_we_have_the_sliders_let's_prepare_for_loop:
  160. :4C4A C45E0E     LES    BX,[BP+0E] ; Set pointer to E
  161. :4C4D 26C747020000 MOV  WORD PTR ES:[BX+02],0000 ; 0 flag
  162. :4C53 26C7070000   MOV  WORD PTR ES:[BX],0000    ; 0 flag
  163. :4C58 C706975E0900 MOV  WORD PTR [5E97],0009     ; counter=9
  164. :4C5E E99500     JMP    4CF6       ; Jmp check_counter
  165. loop_8_times:
  166.  
  167. :4C61 C45E06     LES    BX,[BP+06] ; reset pointer
  168. :4C64 031E975E   ADD    BX,[5E97]  ; add running counter
  169. :4C68 268A07     MOV    AL,ES:[BX] ; load # counter+1
  170. :4C6B 98         CBW               ; only low
  171. :4C6C 50         PUSH   AX         ; save 10th number
  172. :4C6D A18D5E     MOV    AX,[5E8D]  ; ld SEC_+3 down_slider
  173. :4C70 BA0A00     MOV    DX,000A    ; BX holds 0xA
  174. :4C73 F7EA       IMUL   DX         ; SEC_+3 * 0xA
  175. :4C75 03068F5E   ADD    AX,[5E8F]  ; plus FIR_+7 up_slider
  176. :4C79 BAA71E     MOV    DX,1EA7    ; fixed segment
  177. :4C7C 8BD8       MOV    BX,AX ; BX = Lkup_val=(SEC_+3*10+FIR_+7)
  178. :4C7E 8EC2       MOV    ES,DX      ; ES = 1EA7
  179. :4C80 268A870000 MOV    AL,ES:[BX+0000] ; ld 1EA7:[Lkup_val]
  180. :4C85 98         CBW               ; only low: KEY_PAR
  181. :4C86 8BD0       MOV    DX,AX      ; save KEY_PAR in DX
  182. :4C88 58         POP    AX         ; repops 10th number
  183. :4C89 03C2       ADD    AX,DX      ; RE_SULT=KEY_PAR+#10
  184. :4C8B 05D0FF     ADD    AX,FFD0    ; polish RE_SULT
  185. :4C8E 99         CWD               ; only low: RE_SULT
  186. :4C8F 8956FC     MOV    [BP-04],DX ; save here KEY_PAR [9548]
  187. :4C92 8946FA     MOV    [BP-06],AX ; save here RE_SULT [9546]
  188. :4C95 0BD2       OR     DX,DX      ; KEY_PAR  0
  189. :4C9B 3D0900     CMP    AX,0009    ; KEY_PAR = 0
  190. :4C9E 7608       JBE    4CA8 ; no pampering if RE_SULT E305    jcxz   0DA3   ;
  191. cx=0? don't multiply!
  192.  1.0D9E  91      xchg   ax, cx ; cx !=0? cx = ax & ax = cx
  193.  1.0D9F  F7E6    mul    si     ;     ax*0xA in ax
  194.  1.0DA1  03C1    add    ax, cx ; ax=  ax*0xA+cx = M_ULT
  195.  1.0DA3 >96      xchg   ax, si ; ax=0xA; si evtl. holds M_ULT
  196.  1.0DA4  F7E3    mul    bx     ; ax= bx*0xA
  197.  1.0DA6  03D6    add    dx, si ; dx= dx_add
  198.  1.0DA8  5E      pop    si     ; restore si
  199.  1.0DA9  CB      retf          ; back to caller with two
  200.                                         parameters: DX and AX
  201. Back_to_main_protection_loop_from_RO_routine:
  202. :4CBC C45E0E     LES    BX,[BP+0E] ; reset pointer
  203. :4CBF 26895702   MOV    ES:[BX+02],DX ; save R_DX par  [958C]
  204. :4CC3 268907     MOV    ES:[BX],AX ; save R_AX par     [958A]
  205. :4CC6 0346FA     ADD    AX,[BP-06] ; add to AX RE_SULT [9546]
  206. :4CC9 1356FC     ADC    DX,[BP-04] ; add to DX KEY_PAR [9548]
  207. :4CCC C45E0E     LES    BX,[BP+0E] ; reset pointer
  208. :4CCF 26895702   MOV    ES:[BX+02],DX ; save R_DX+KEY_PAR [958C]
  209. :4CD3 268907     MOV    ES:[BX],AX ; save R_AX+RE_SULT    [958A]
  210. :4CD6 FF0E8D5E   DEC    WORD PTR [5E8D] ; down_slide SEC_+3
  211. :4CDA 7D05       JGE    4CE1       ; no need to add
  212. :4CDC 83068D5E0A ADD    WORD PTR [5E8D],+0A  ; pamper adding 10
  213. :4CE1 FF068F5E   INC    WORD PTR [5E8F] ; up_slide FIR_+7
  214. :4CE5 A18F5E     MOV    AX,[5E8F]  ; save upslided FIR_+7 in AX
  215. :4CE8 3D0900     CMP    AX,0009    ; is it over 9?
  216. :4CEB 7E05       JLE    4CF2       ; no, go on
  217. :4CED 832E8F5E0A SUB    WORD PTR [5E8F],+0A ; yes, pamper -10
  218. :4CF2 FF0E975E   DEC    WORD PTR [5E97]  ; decrease loop counter
  219. check_loop_counter:
  220. :4CF6 833E975E03 CMP    WORD PTR [5E97],+03  ; counter = 3?
  221. :4CFB 7C03       JL     4D00       ; finish if counter under 3
  222. :4CFD E961FF     JMP    4C61       ; not yet, loop_next_count
  223. loop_is_ended:
  224. :4D00 C45E06     LES    BX,[BP+06] ; reset pointer to input
  225. :4D03 268A4701   MOV    AL,ES:[BX+01] ; load 2nd number (2)
  226. :4D07 98         CBW               ; only low
  227. :4D08 05D0FF     ADD    AX,FFD0    ; clean it
  228. :4D0B BA0A00     MOV    DX,000A    ; DX = 10
  229. :4D0E F7EA       IMUL   DX         ; AX = SEC_*10 = 14
  230. :4D10 C45E06     LES    BX,[BP+06] ; reset pointer
  231. :4D13 50         PUSH   AX         ; save SEC_*10
  232. :4D14 268A07     MOV    AL,ES:[BX] ; load 1st number (1)
  233. :4D17 98         CBW               ; only low
  234. :4D18 8BD0       MOV    DX,AX      ; save in DX
  235. :4D1A 58         POP    AX         ; get SEC_*10
  236. :4D1B 03C2       ADD    AX,DX      ; sum SEC_*10+1st number
  237. :4D1D 05D0FF     ADD    AX,FFD0    ; clean it
  238. :4D20 99         CWD               ; only low
  239. :4D21 C45E0A     LES    BX,[BP+0A] ; get pointer    to   [9582]
  240. :4D24 26895702   MOV    ES:[BX+02],DX ; save 1st (1) in  [9584]
  241. :4D28 268907     MOV    ES:[BX],AX ; save FINAL_SUM (15) [9582]
  242. :4D2B 33D2       XOR    DX,DX      ; DX = 0
  243. :4D2D B80100     MOV    AX,0001    ; FLAG TRUE !
  244. :4D30 E9E6FE     JMP    4C19       ; OK, you_are_a_nice_guy
  245. EXIT:
  246. :4D33 59         POP    CX         ; pop everything and
  247. :4D34 59         POP    CX         ;  return with flag
  248. :4D35 1F         POP    DS         ;  AX=TRUE if RegNum OK
  249. :4D36 5D         POP    BP         ;  with 1st # in     [9584]
  250. :4D37 4D         DEC    BP         ;  with FINAL_SUM in [9582]
  251. :4D38 CB         RETF
  252.  
  253.   Let's translate the preceding code: first of all the pointers:
  254. At line :4B86 we have the first of a long list of stack ptrs:
  255.                         LES BX,[BP+06]
  256.  This stack pointer points to the beginning of the input string,
  257. which, once polished from the "-", has now a length of 10 bytes,
  258. concluded by a 00 fence. At the beginning, before the main loop,
  259. 9 out of our 10 numbers are added, all but the third one.
  260.   Notice that protection has jumped # 3 (and added # 8 out of the
  261. line). The rest is straightforward. Now, at line :4BFD we have
  262. our first "cleaning" instruction. You see: the numbers are
  263. hexadecimal represented by the codes 0x30 to 0x39. If you add
  264. FE50 to the minimum sum you can get adding 9 numbers (0x30*9 =
  265. 0x160) You get 0. The maximum you could have adding 9 numbers,
  266. on the contrary is (0x39*9=0x201), which, added to FE50 gives
  267. 0x51. So we'll have a "magic" number between 0x0 and 0x51 instead
  268. of a number between 0x160 and 0x201. Protection pampers this
  269. result, and retains only the last ciffer: 0-9.  Then protection
  270. divides this number through 0xA, and what happens? DX get's the
  271. REMAINDER of it.
  272.   If we sum the hexcodes of our (1212-1212-12) we get 0x1BE (we
  273. sum only 9 out of then numbers: the third "1" -i.e. "31"- does
  274. not comes into our count); 0x1BE, cleaned and pampered gives E.
  275. Therefore (0xE/0xA = 1) We get 1 with a remainder of 4.
  276.   You may observe that of all possible answers, only sums
  277. finishing with A, B, C, D, E or F give 1 (and rem=0,1,2,3,4 or
  278. 5). Sums finishing 0 1 2 3 4 5 6 7 8 or 9 give 0 as result and
  279. themselves as reminder. The chance of getting a 0,1,2,3 or 4 are
  280. therefore bigger as the chance of getting a 5, 6, 7, 8 or 9. We
  281. are just observing... we do not know yet if this should play a
  282. role or not.
  283.   Now this remainder is compared at :4C11 with the third number
  284. polished from 0x30-0x39 to 0-9. This is the only protection check
  285. for the registration number input: If your third number does not
  286. match with the remainder of the sum of all the 9 others numbers
  287. of your input you are immediately thrown out with FLAG AX=FALSE
  288. (i.e. zero).
  289.  To crack the protection you now have to MODIFY your input string
  290. accordingly. Our new input string will from now on be "1242-1212-
  291. 12": we have changed our third number (originally a "2") to a "4"
  292. to get through this first strainer in the correct way. Only now
  293. protection starts its mathematical part (We do not know yet why
  294. it does it... in order to seed the random product number? To
  295. provide a check for the registration number you'll input at the
  296. end? We'll see).
  297. -    Protection saves the second number of your input (cleaned
  298.      with FFD7) in SEC_+3 [5E8D], pampering it if it is bigger
  299.      than 9 (i.e. if it is 0xA-0xF). Here you'll have therefore
  300.      following correspondence: 0=7 1=8 2=9 3=0 4=1 5=2 6=3 7=4
  301.      8=5 9=6. The second number of your input has got added +3.
  302.      This is value SEC_+3. In (lengthy) C it would look like
  303.      this:
  304.        If (RegString(2)is lower than  7) RegString(2) = RegString(2)+3
  305.        Else Regstring(2) = ((RegString(2)-10)+3)
  306. -    Protection saves your first number in FIR_+7 [5E8F] with a
  307.      different cleaning parameter (FFC9). The next pampering
  308.      adds 0xA if it was not 7/8/9 therefore you have here
  309.      following correspondence 7=0 8=1 9=2 0=3 1=4 2=5 3=6 4=7
  310.      5=8 6=9). This is value FIR_+7. In (lengthy) C it would
  311.      look like this:
  312.        If (RegString(1) is lower than 3) RegString(1) = RegString(1)+7
  313.        Else Regstring(1) = ((RegString(1)-10)+7)
  314.   So protection has "transformed" and stored in [5E8D] and [5E8F]
  315. the two numbers 1 and 2. In our RegString: 1242-1212-12 the first
  316. two numbers "12" are now stored as "94". These will be used as
  317. "slider" parameters inside the main loop, as you will see.
  318.  Only now does protection begin its main loop, starting from the
  319. LAST number, because the counter has been set to 9 (i.e. the
  320. tenth number of RegString). The loop, as you'll see, handles only
  321. the numbers from 10 to 3: it's an 8-times loop that ends without
  322. handling the first and second number. What happens in this
  323. loop?... Well, quite a lot: Protection begins the loop loading
  324. the number (counter+1) from the RegString. Protection then loads
  325. the SEC_+3 down_slider parameter (which began its life as second
  326. number "transformed"), multiplies it with 0xA and then adds the
  327. up_slider parameter FIR_+7 (at the beginning it was the first
  328.  
  329. number transformed).
  330.      This sum is used as "lookup pointer" to find a parameter
  331. inside a table of parameters in memory, which are all numbers
  332. between 0 and 9. Let's call this value Lkup_val.
  333. Protection looks for data in 1EA7:[Lkup_val]. In our case (we
  334. entered 1242-1212-12, therefore the first SEC_+3 value is 9 and
  335. the first FIR_+7 value is 4): [Lkup_val] = 9*0xA+4; 0x5A+4 =
  336. 0x5E. At line :4C80 therefore AL would load the byte at 1EA7:005E
  337. (let's call it KEY_PAR), which now would be ADDED to the #
  338. counter+1 of this loop. In our case KEY_PAR at 1EA7:005E it's a
  339. "7" and is added to the pampered 0x32=2, giving 9.
  340.      Let's establish first of all which KEY_PAR can possibly get
  341. fetched: the maximum is 0x63 and the minimum is 0x0. The possible
  342. KEY_PARs do therefore dwell in memory between 1EA7: and
  343. 1EA7:0063. Let's have a look at the relative table in memory,
  344. where these KEY_PARs are stored ("our" first 0x5Eth byte is
  345. underlined):
  346. 1EA7:0000 01 03 03 01 09 02 03 00-09 00 04 03 08 07 04 04
  347. 1EA7:0010 05 02 09 00 02 04 01 05-06 06 03 02 00 08 05 06
  348. 1EA7:0020 08 09 05 00 04 06 07 07-02 00 08 00 06 02 04 07
  349. 1EA7:0030 04 04 09 05 09 06 00 06-08 07 00 03 05 09 00 08
  350. 1EA7:0040 03 07 07 06 08 09 01 05-07 04 06 01 04 02 07 01
  351. 1EA7:0050 03 01 08 01 05 03 03 01-02 08 02 01 06 05 07 02
  352. 1EA7:0060 05 09 09 08 02 09 03 00-00 04 05 01 01 03 08 06
  353. 1EA7:0070 01 01 09 00 02 05 05 05-01 07 01 05 08 07 01 09
  354. 1EA7:0080 08 07 07 04 04 08 03 00-06 01 09 08 08 04 09 09
  355. 1EA7:0090 00 07 05 02 03 01 03 08-06 05 07 06 03 07 06 07
  356. 1EA7:00A0 04 02 02 05 02 04 06 02-06 09 09 01 05 02 03 04
  357. 1EA7:00B0 04 00 03 05 00 03 08 07-06 04 08 08 02 00 03 06
  358. 1EA7:00C0 09 00 00 06 09 04 07 02-00 01 01 01 01 00 01 FF
  359. 1EA7:00D0 00 FF FF FF FF 00 FF 01-00 00 00 00 00 00 00 00
  360.  
  361.      An interesting table, where all the correspondences are
  362. between 0 and 9... are we getting some "secret" number here? But,
  363. hey, look there... funny, isn't it? Instead of only 0-0x63 bytes
  364. we have roughly the DOUBLE here: 0-0xC8 bytes (the 01 sequence
  365. starting at CA "feels" like a fence). We'll see later how
  366. important this is. At the moment you should only "perceive" that
  367. something must be going on with a table that's two time what she
  368. should be.
  369.      As I said the result of KEY_PAR + input number is polished
  370. (with a FFDO) and pampered (subtracting, if necessary, 0xA).
  371. Therefore the result will be the (counter+1) input number +
  372. KEY_PAR (let's call it RE_SULT], in our case, (at the beginning
  373. of the loop) a 9. Now (DX=0 because of the CWD instruction) DX
  374. will be saved in [9548] and RE_SULT in [9546].
  375.  Now Protection prepares for the RO_routine: resets its pointer
  376. and charges CX and BX from [958C] and from [958A] respectively,
  377. charges AX with 0xA and sets DX to zero.
  378.  The routine performs various operations on AX and DX and saves
  379. the results in the above mentioned locations [958A] and [958C].
  380.  Now KEY_PAR and RE_SULT are added respectively to the DX and AX
  381. value we got back from the RO_routine call, and saved once more
  382. in the last two locations: AX+RE_SULT in [958A] and DX+KEY_PAR
  383. in [958C]
  384.  Now the value in SEC_+3 is diminished by 1 (if it was 9 it's now
  385. 8, if it was zero it will be pampered to 9). It's a "slider"
  386. parameter (in this case a down_slider), typically used in
  387. relatively complicated protections to give a "random" impression
  388. to the casual observer. The value in FIR_+7, on the contrary, is
  389. augmented by one, from 4 to 5... up_sliding also.
  390.      Protection now handles the next number of your input for the
  391. loop. In our case this loop uses following protection
  392. configuration with our "sliding" parameters:
  393.  Input #  pamp_2nd   pamp_1st   Lookup value  KEY_PAR  # RE_SULT
  394. # 10 = 2, SEC_+3= 9, FIR_+7= 4, Lkup_val = 0x5E, KEY=7 +2 = 9
  395. # 9  = 1, SEC_+3= 8, FIR_+7= 5, Lkup_val = 0x55, KEY=3 +1 = 4
  396. # 8  = 2, SEC_+3= 7, FIR_+7= 6, Lkup_val = 0x4C, KEY=4 +2 = 6
  397. # 7  = 1, SEC_+3= 6, FIR_+7= 7, Lkup_val = 0x43, KEY=7 +1 = 7
  398. # 6  = 2, SEC_+3= 5, FIR_+7= 8, Lkup_val = 0x3A, KEY=0 +2 = 2
  399. # 5  = 1, SEC_+3= 4, FIR_+7= 9, Lkup_val = 0x31, KEY=4 +1 = 5
  400. # 4  = 2, SEC_+3= 3, FIR_+7= 0, Lkup_val = 0x1E, KEY=5 +2 = 7
  401. # 3  = 4, SEC_+3= 2, FIR_+7= 1, Lkup_val = 0x15, KEY=2 +4 = 5
  402. Notice how our "regular" input 21212124 has given an "irregular"
  403. 94672575.
  404.      You may legitimately ask yourself what should all this mean:
  405. what are these RE_SULTs used for? Well they are used to slide
  406. another parameter: this one inside the called routine... this is
  407. what happens to AX and DX inside the routine, and the lines after
  408. the called routine:
  409. :4CBF 26895702   MOV    ES:[BX+02],DX ; save R_DX par  [958C]
  410. :4CC3 268907     MOV    ES:[BX],AX ; save R_AX par     [958A]
  411. :4CC6 0346FA     ADD    AX,[BP-06] ; add to AX RE_SULT [9546]
  412. :4CC9 1356FC     ADC    DX,[BP-04] ; add to DX KEY_PAR [9548]
  413. :4CCC C45E0E     LES    BX,[BP+0E] ; reset pointer to E
  414. :4CCF 26895702   MOV    ES:[BX+02],DX ; save R_DX+KEY_PAR [958C]
  415. :4CD3 268907     MOV    ES:[BX],AX ; save R_AX+RE_SULT    [958A]
  416.  
  417.             :4CC6     :4CC9  :4CCF Odd_DX  :4CD3 slider_sum
  418.   RE_SULT   [958A]    [958C]   [958C]        [958A]
  419.      0         0        0        0            0
  420.      9         5A       0        0            9
  421.      4         3AC      0        0            5E
  422.      6         24F4     0        0            3B2
  423.      7         71CE     1        1            24FB
  424.      2         7220     4        E            71D0
  425.      5         7572     4        90           7225
  426.                                               7579
  427.  
  428. Now the loops ends, having handled the input numbers from tenth
  429. to third. Protection loads the second number and multiplies it
  430. by 10 (let's call this result SEC_*10), in our case 2*0xA=14.
  431. Protection loads the first number and adds it to the
  432. multiplication, in our case 1+0x14=0x15 (FINAL_SUM].
  433. Now everything will be added to FFDO to "clean" it.
  434. Pointer will now be set to the end of the input number.
  435. DX, zeroed by CDW, will be saved as parameter in [9584] and the
  436. cleaned and pampered sum will be saved in [9582].
  437. FLAG is set to true and this routine is finished! No parameter
  438. are passed and the only interesting thing is what actually
  439. happens in the locations [9582], [9584], [958A] and [958C], i.e.:
  440. FINAL_SUM, 0, slider_sum, odd_dx.
  441.      In the next lesson we'll crack everything, but I'll give you
  442. already some hints here, in case you would like to go ahead on
  443. your own: we'll see how the scheme used for the third (the
  444. registration) number show analogies and differences with the
  445. scheme we have studied (and cracked) here for the first number.
  446. Our 3434-3434-3434-3434-34 input string for the registration
  447. number will be transformed in the magic string
  448. 141593384841547431, but this will not work because the "magic"
  449. 12th number: "1" will not correspond to the remainder calculated
  450. inside this check through the previous locations of the other
  451. checks.
  452.      Here the things are more complicated because every little
  453. change in your input string transforms COMPLETELY the "magic"
  454. string... therefore in order to pass the strainer you'll have to
  455. change 3434-3434-3434-3434-34 in (for instance) 7434-3434-3434-
  456. 3434-96. The "magic" string 219702960974498056 that this
  457. registration input gives will go through the protection strainer.
  458. Only then we'll be able to step over and finally crack the whole
  459. protection... it's a pretty complicated one as I said. Now crack
  460. it pupils... you have three months time. From this crack depends
  461. your admission to the Uni, there will be no other admission text
  462. till summer 1997 (it's a hell of work to prepare this crap)...
  463. work well.
  464.  
  465. Well, that's it for this lesson, reader. Not all lessons of my
  466. tutorial are on the Web.
  467.      You 'll obtain the missing lessons IF AND ONLY IF you mail
  468. me back (via anon.penet.fi) some tricks of the trade I may not
  469. know but YOU've discovered. I'll probably know most of them
  470. already, but if they are really new you'll be given full credit,
  471. and even if they are not, should I judge that you "rediscovered"
  472. them with your work, or that you actually did good work on them,
  473. I'll send you the remaining lessons nevertheless. Your
  474. suggestions and critics on the whole crap I wrote are also
  475. welcomed.
  476.  
  477.  
  478. E-mail +ORC
  479.  
  480.  
  481.  
  482. +ORC an526164@anon.penet.fi
  483.