home *** CD-ROM | disk | FTP | other *** search
/ Cracking 2 / Cracking II..iso / Texty / crackme / ARASHA.TXT < prev    next >
Encoding:
Text File  |  1998-01-09  |  16.3 KB  |  449 lines

  1. HOW TO CRACK RBSTRIAL.COM
  2.  
  3. A word of caution before we begin: this method is likely not the most
  4. efficient as it's the first program I ever cracked.  The good thing is
  5. that it works though.
  6.  
  7. Alright, pick up a copy of RBSTRIAL.COM from Lord Caligo's site and
  8. let's start.  Run the program a couple of time to see the sequence of
  9. actions.  Since the file is very small (308 bytes), you might as well
  10. print the entire disassembled code and have a look.  Here's a
  11. disassembly:
  12.  
  13. 241E:0100 6B4F5547      IMUL    CX,[BX+55],+47
  14. 241E:0104 45            INC     BP
  15. 241E:0105 52            PUSH    DX
  16. 241E:0106 21D2          AND     DX,DX
  17. 241E:0108 4D            DEC     BP
  18. 241E:0109 5A            POP     DX
  19. 241E:010A E98A00        JMP     0197
  20. ....
  21. 241E:0190 F6D8          NEG     AL
  22. 241E:0192 FEC3          INC     BL
  23. 241E:0194 EB3F          JMP     01D5
  24. 241E:0196 90            NOP
  25. 241E:0197 B409          MOV     AH,09
  26. 241E:0199 BA0D01        MOV     DX,010D
  27. 241E:019C CD21          INT     21
  28. 241E:019E BA8001        MOV     DX,0180
  29. 241E:01A1 B40A          MOV     AH,0A
  30. 241E:01A3 CD21          INT     21
  31. 241E:01A5 42            INC     DX
  32. 241E:01A6 8BF2          MOV     SI,DX
  33. 241E:01A8 AC            LODSB
  34. 241E:01A9 1C0A          SBB     AL,0A
  35. 241E:01AB 754D          JNZ     01FA
  36. 241E:01AD 90            NOP
  37. 241E:01AE 90            NOP
  38. 241E:01AF 2BC0          SUB     AX,AX
  39. 241E:01B1 33D2          XOR     DX,DX
  40. 241E:01B3 46            INC     SI
  41. 241E:01B4 BFE101        MOV     DI,01E1
  42. 241E:01B7 BBA59D        MOV     BX,9DA5
  43. 241E:01BA B90B00        MOV     CX,000B
  44. 241E:01BD 51            PUSH    CX
  45. 241E:01BE F8            CLC
  46. 241E:01BF AC            LODSB
  47. 241E:01C0 750F          JNZ     01D1
  48. 241E:01C2 90            NOP
  49. ....
  50. 241E:01D1 02C3          ADD     AL,BL
  51. 241E:01D3 72BB          JB      0190
  52. 241E:01D5 0FAFCB        IMUL    CX,BX
  53. 241E:01D8 02CD          ADD     CL,CH
  54. 241E:01DA 2AC1          SUB     AL,CL
  55. 241E:01DC AA            STOSB
  56. 241E:01DD 750D          JNZ     01EC
  57. ....
  58. 241E:01EC 86DF          XCHG    BL,BH
  59. 241E:01EE 59            POP     CX
  60. 241E:01EF E2CC          LOOP    01BD
  61. 241E:01F1 FD            STD
  62. 241E:01F2 BECF01        MOV     SI,01CF
  63. 241E:01F5 B90D00        MOV     CX,000D
  64. 241E:01F8 F3            REPZ
  65. 241E:01F9 A6            CMPSB
  66. 241E:01FA B409          MOV     AH,09
  67. 241E:01FC BA0802        MOV     DX,0208
  68. 241E:01FF 7425          JZ      0226
  69. 241E:0201 90            NOP
  70. 241E:0202 90            NOP
  71. 241E:0203 CD21          INT     21
  72. 241E:0205 EB18          JMP     021F
  73. ....
  74. 241E:021F B8004C        MOV     AX,4C00
  75. 241E:0222 CD21          INT     21
  76. ....
  77. 241E:0226 BA6B01        MOV     DX,016B
  78. 241E:0229 EBD8          JMP     0203
  79.  
  80. (The code segment will likely be different on your machine.)  Now,
  81. examine the code and trace through it with a debugger.  Consider the
  82. following section of the code:
  83.  
  84. 241E:0197 B409          MOV     AH,09
  85. 241E:0199 BA0D01        MOV     DX,010D
  86. 241E:019C CD21          INT     21
  87. 241E:019E BA8001        MOV     DX,0180
  88. 241E:01A1 B40A          MOV     AH,0A
  89. 241E:01A3 CD21          INT     21
  90.  
  91. If we look at the contends of address 010Dh, we see it contains the
  92. introductory text.  The first INT 21 call prints this text to the
  93. screen.  The second INT 21 call gets the user input and saves it at
  94. 0180h.  If you dump the contents of memory starting at 0180h, you will
  95. see your input.  Now look at the next few lines:
  96.  
  97. 241E:01A5 42            INC     DX
  98. 241E:01A6 8BF2          MOV     SI,DX
  99. 241E:01A8 AC            LODSB
  100. 241E:01A9 1C0A          SBB     AL,0A
  101. 241E:01AB 754D          JNZ     01FA
  102.  
  103. INC DX will set DX equal to 0180h+1h = 0181h.  The contents of 0181h
  104. will be the length of the user's input (when interrupt 21 saves the user
  105. input, it precedes the data with the length of the user input).  Thus,
  106. the next three lines check whether the user entered 0ah or 10 characters
  107. for the password.  If the user did not, the computer will jump to 01fah
  108. which, upon examination, prints out "Incorrect Password" and terminates
  109. the program.  We just learned our first clue: the correct password is 10
  110. characters long.
  111.  
  112. Look at the next few lines:
  113.  
  114. 241E:01AD 90            NOP
  115. 241E:01AE 90            NOP
  116. 241E:01AF 2BC0          SUB     AX,AX
  117. 241E:01B1 33D2          XOR     DX,DX
  118. 241E:01B3 46            INC     SI
  119. 241E:01B4 BFE101        MOV     DI,01E1
  120. 241E:01B7 BBA59D        MOV     BX,9DA5
  121. 241E:01BA B90B00        MOV     CX,000B
  122. 241E:01BD 51            PUSH    CX
  123. 241E:01BE F8            CLC
  124. 241E:01BF AC            LODSB
  125. 241E:01C0 750F          JNZ     01D1
  126.  
  127. After clearing the AX and DX registers, SI is incremented.  SI should
  128. now be pointing to the SECOND character of our input (remember this fact
  129. for later).  This is because the preceding LODSB command already
  130. increased SI from 181h to 182h.  SI is now 183h, which is where our
  131. second input charater is.  The next few lines initialize some
  132. registers.
  133. Note that DI is initialized to 01E1h.  The LODSB will load AL with our
  134. second input character.  If that character is not equal to zero (which
  135. it shouldn't unless you used escape codes in your input), we will jump
  136. to 01D1h.  Now comes the interesting part.  Examine the next piece of
  137. code:
  138.  
  139. 241E:01D1 02C3          ADD     AL,BL
  140. 241E:01D3 72BB          JB      0190
  141. 241E:01D5 0FAFCB        IMUL    CX,BX
  142. 241E:01D8 02CD          ADD     CL,CH
  143. 241E:01DA 2AC1          SUB     AL,CL
  144. 241E:01DC AA            STOSB
  145. 241E:01DD 750D          JNZ     01EC
  146. ....
  147. 241E:01EC 86DF          XCHG    BL,BH
  148. 241E:01EE 59            POP     CX
  149. 241E:01EF E2CC          LOOP    01BD
  150. 241E:01F1 FD            STD
  151. 241E:01F2 BECF01        MOV     SI,01CF
  152. 241E:01F5 B90D00        MOV     CX,000D
  153. 241E:01F8 F3            REPZ
  154. 241E:01F9 A6            CMPSB
  155.  
  156. Here's the code for the JB instruction at 01D3:
  157.  
  158. 241E:0190 F6D8          NEG     AL
  159. 241E:0192 FEC3          INC     BL
  160. 241E:0194 EB3F          JMP     01D5
  161.  
  162. Hmmm.  This looks like an encryption procedure.  It's modifying each of
  163. our input characters according to some algorithm and storing it
  164. beginning at 01E1h (recall that DI was initialized to 01E1h).  After the
  165. encryption (i.e. starting at address cs:01F1h), you will see that the
  166. program compares our encrypted password to the something (REPZ CMPSB).
  167. Here is where the program checks to see whether we entered the correct
  168. password.  Now, let's figure out where the correct password is stored.
  169. Since the direction flag is set (STD instruction at cs:01F1h), we know
  170. that the REPZ CMPSB will compare bytes BACKWARDS from memory.  Thus, we
  171. know that the last character of the correct password is at ds:01CFh,
  172. which is what the SI register is initialized to at cs:01F2h.  The CX
  173. register is initialized to Dh right before the comparison.  This means
  174. that the REPZ CMPSB instructions will compare a maximum of Dh
  175. characters.  Therefore, the beginning of the correct password is at
  176. ds:01CFh - Dh + 1h = 01C3.  Well, let's see what's there by dumping the
  177. contents of memory beginning at ds:01C3:
  178.  
  179. 241E:01C3  90 0A 56 7B D9 21 56 8A-CF F5 1F 61 86 34 02 C3
  180.  
  181. There's only one problem.  That data isn't exactly the correct
  182. password.
  183. It's the ENCRYPTED correct password.  Remember that the program first
  184. encrypts our input and then compares our ENCRYPTED input with the above
  185. data.  Now, you might think, "that's simple, let's just decrypt the
  186. data".  You're on the right track but, unfortunately, decrypting the
  187. password is much more complicated that you probably think.
  188.  
  189. By now, you must be thinking, if we just change CS:01FF from JZ 0226 to
  190. JMP 0226, the program will say "Correct Password" for anything we type
  191. in.  Sure, we could do that, but kOUGER!'s challenge was for us to to
  192. find out what the real password is.
  193.  
  194. To figure out what the password is, we must COMPLETELY understand what
  195. the encryption algorithm is.  So, sit back and examine the code
  196. carefully.  Examine it until you FULLY understand what's going on.
  197. First, one character of our input is loaded into AL.  Next, BL is added
  198. to it.  Then, if the addition caused an unsigned overflow (i.e. if AL +
  199. BL > 255 causing the carry flag to be set), AL is negated and BL is
  200. incremented by one.  Next, the sum of the high and low bytes of CX*BX is
  201. subtracted from AL to complete the encryption.  After storing our
  202. encrypted character, the high and low bytes of BX are exchanged and the
  203. next character goes through the same process.  Let's formalize this
  204. algorithm mathematically.  First, define a function f(x) which returns
  205. the sum of the high and low bytes of its argument, x.  For example,
  206. f(2FB4h) = 2Fh + B4h = E3h.  Here's how the encryption alorithm looks:
  207.  
  208. If AL + BL <= 255:                      If AL + BL > 255:
  209. output = input + BL - f(BX*CX)  output = -(input+BL) - f[(BX+1)*CX]
  210.  
  211. Let's re-arrange the equations to solve for the input (i.e. this is the
  212. decryption algorithm):
  213.  
  214. If AL + BL <= 255:                      If AL + BL > 255:
  215. input = output - BL + f(BX*CX)  input = -(output - f[(BX+1)*CX])-BL
  216.  
  217. No problem, you say. Just substitute the values for the correct
  218. encrypted password for "output" and solve for "input".  While this seems
  219. simple, it has two problems.  Here's the first problem: given BX and CX,
  220. there are up to two possible inputs which would yield the same output.
  221. One for when AL + BL <= 255 and the jump at CS:01D3h is not taken, and
  222. one for when AL + BL > 255 and jump at CS:01D3h is taken.  For example,
  223. if we want to find the correct input for 0Ah (i.e. the second character
  224. of the correct encrypted password), we get either 42h or 39h which
  225. corresponds to "B" and "9" respectively.  We could choose either one and
  226. proceed to decode the next character.  The problem with this is that if
  227. we chose the wrong one, we may find that the later characters we decode
  228. fall outside the typeable range of ASCII characters.  If we are VERY
  229. lucky and chose the correct path through the decryption, we will get the
  230. correct password.  However, for 10 characters, there are 2^10 = 1024
  231. different paths.  That makes this option a little unattractive.  The
  232. second problem however renders this option even less attractive.
  233.  
  234. The astute readers will notice that the correct password is 10
  235. characters in length whereas the encryption and compare routines encrypt
  236. and compare 12 characters.  Thus, the encryption procedure also encrypts
  237. the two bytes following our 10 character input beginning at address
  238. DS:0182h.  Upon examination, we see that the program fixes these two
  239. bytes to 0Dh and 00.  When these two bytes are encrypted, they will be
  240. compared to 1Fh and 61h (check the dump of the correct encrypted
  241. password to see where these numbers come from).  To fully understand
  242. what this means, you have to realize that how each character is
  243. encrypted depends on how the previous characters were encrypted.  This
  244. is because the BX register is changed according to whether the jump at
  245. CS:01D3h is taken.  Thus, the correct password is one which follows a
  246. path which causes BX to equal a value which will correctly encode the
  247. 11th and 12th bytes to 1Fh and 61h, respectively.
  248.  
  249. Now, not only do we have to worry about taking a path which yields an
  250. ASCII typeable password, but we must also make sure that it sets BX to a
  251. value which correctly encodes the next two bytes.  Solution: we will
  252. write a program which will go through all the possible paths and see
  253. whether one password gives us the same encryption as the correct
  254. encrypted password.  Before going any further, recall the encryption
  255. procedure begins with the SECOND input character, not the first.  Thus,
  256. the first character of our input is never encrypted at all.  Although
  257. the password compare procedure actually compares the address where our
  258. first input character would have been stored had it been encrypted, we
  259. note that that address is fixed at 90h.  Fortunately, 90h is exactly
  260. what it is compared to in the password compare procedure. This gives us
  261. the second clue to the password: it doesn't matter what you type for the
  262. first character.
  263.  
  264. Alright, here's the pascal program which goes through all the possible
  265. 2^9 = 512 (remember, the first character is irrelevant) paths.  It will
  266. print out only those passwords which meet both of the following
  267. criteria:
  268. (1) All characters fall within the typeable ASCII range
  269. (2) Characters 11 and 12 (i.e. those "hard-wired" to 0Dh and 00) are
  270. correctly encoded to 1Fh and 61h, respectively.
  271. Note also that this program prints only characters 2 to 10 of the
  272. correct password(s) as the first character is irrelevant.
  273.  
  274. Program RbsTrialDecode (Input,Output);
  275.  
  276. Function LowByte(Value : word) : word;
  277. Begin
  278.   LowByte := Value - (Value div 256)*256;
  279. End;
  280.  
  281. Function HighByte(Value : word) : word;
  282. Begin
  283.   HighByte := Value div 256;
  284. End;
  285.  
  286. Function Encode(Var InBX : word;
  287.                 InCX : word;
  288.                 CorrectInput : byte) : byte;
  289. Var
  290.   BX,
  291.   CX            : word;
  292.   CorrectOutput,
  293.   BH,
  294.   BL,
  295.   CH,
  296.   CL,
  297.   TempByte      : byte;
  298.  
  299. Begin
  300.   BX := InBX;
  301.   CX := InCX;
  302.   BH := HighByte(InBX);
  303.   BL := LowByte(InBX);
  304.   CorrectOutPut := CorrectInput + BL;
  305.   If (CorrectOutput < CorrectInput) Then
  306.   Begin
  307.     CorrectOutput := (CorrectOutput XOR 255) + 1;
  308.     BL := BL + 1;
  309.   End;
  310.   BX := 256*BH + BL;
  311.   CX := CX*BX;
  312.   CL := LowByte(CX);
  313.   CH := HighByte(CX);
  314.   CorrectOutput := CorrectOutput - CH - CL;
  315.   BH := HighByte(BX);
  316.   BL := LowByte(BX);
  317.   BX := 256*BL + BH;
  318.   InBX := BX;
  319.   Encode := CorrectOutput;
  320. End;
  321.  
  322. Function Decode(Var InBX      : word;
  323.                 InCX          : word;
  324.                 CorrectOutput : byte;
  325.                 NoJump        : boolean) : Byte;
  326.  
  327. Var
  328.  
  329.   BX,
  330.   CX  : word;
  331.   CorrectInput     : byte;
  332.   BH,
  333.   BL,
  334.   CH,
  335.   CL,
  336.   TempByte   : byte;
  337.  
  338. Begin
  339.   If NoJump Then
  340.   Begin
  341.     CX := InCX;
  342.     BX := InBX;
  343.     BL := LowByte(InBX);
  344.     BH := HighByte(InBX);
  345.     CX := CX * BX;
  346.     CL := LowByte(CX);
  347.     CH := HighByte(CX);
  348.     TempByte := CL + CH;
  349.     CorrectInput := CorrectOutput + TempByte - BL;
  350.     BX := BH + 256*BL;
  351.     TempByte := CorrectInput + BL;
  352.     If TempByte >= CorrectInput Then
  353.     Begin
  354.       Decode := CorrectInput;
  355.       InBX := BX;
  356.     End
  357.     Else
  358.       Decode := 0;
  359.   End
  360.   Else
  361.   Begin
  362.     CX := InCX;
  363.     BX := InBX;
  364.     BL := LowByte(BX);
  365.     BH := HighByte(BX);
  366.     BL := BL + 1;
  367.     BX := BL + BH*256;
  368.     CX := BX * CX;
  369.     CL := LowByte(CX);
  370.     CH := HighByte(CX);
  371.     TempByte := CL+CH;
  372.     CorrectInput := ((CorrectOutput + TempByte) XOR 255) + 1 -
  373. LowByte(InBX);
  374.     BX := BH + 256*BL;
  375.     TempByte := CorrectInput + LowByte(InBX);
  376.     If TempByte < CorrectInput Then
  377.     Begin
  378.       Decode := CorrectInput;
  379.       InBX := BX;
  380.     End
  381.     Else
  382.       Decode := 0;
  383.   End;
  384. End;
  385.  
  386.  
  387. Const
  388.   EncodedPassword : array[2..11] of byte =
  389. (31,245,207,138,86,33,217,123,86,10);
  390.  
  391. Var
  392.   InBX,
  393.   InCX,
  394.   Counter1,
  395.   Counter2,
  396.   Mask,
  397.   Temp           : word;
  398.   CorrectInput,
  399.   a,b            : byte;
  400.   GoodPassword,
  401.   NoJump         : boolean;
  402.   PasswordString : String;
  403.  
  404. Begin
  405.   Writeln;
  406.   For Counter1 := 0 to 511 do
  407.   Begin
  408.     Mask := 1;
  409.     InBX := 40357;
  410.     GoodPassword := True;
  411.     PasswordString := '';
  412.     For Counter2 := 1 to 9 do
  413.     Begin
  414.       Temp := Counter1 and Mask;
  415.       NoJump := Temp <> 0;
  416.       InCX := 12 - Counter2;
  417.       CorrectInput := Decode(InBX,InCX,EncodedPassword[InCX],NoJump);
  418.       If (CorrectInput <= 126) and (CorrectInput >= 32) Then
  419.         PasswordString := PasswordString + Chr(CorrectInput)
  420.       Else
  421.       Begin
  422.         PasswordString := PasswordString + Chr(CorrectInput);
  423.         GoodPassword := False;
  424.       End;
  425.       Mask := Mask * 2;
  426.     End {for};
  427.     a := Encode(InBX,2,13);
  428.     b := Encode(InBX,1,0);
  429.     If GoodPassword and (a = 31) and (b = 97) Then
  430.       Writeln(PasswordString);
  431.   End {for};
  432. End.
  433.  
  434.  
  435. When we run the program, we see that there are two possible passwords:
  436.  
  437. BS-Party!
  438. i]5XTrty!
  439.  
  440. Remember that these are the 2nd to 10th characters and we can enter
  441. anything for the first character.  It is likely that kOUGER!'s intended
  442. password was "RBS-Party!".  Running the program and typing these
  443. passwords, we see that we have correctly "cracked" the program.  Looking
  444. back now that I know the password, I think that it may be possible for
  445. someone to figure out the password by hand (i.e. without writing a
  446. program as I did) if he could see the pattern leading to the word
  447. "Party!".
  448.  
  449.