home *** CD-ROM | disk | FTP | other *** search
/ Reverse Code Engineering RCE CD +sandman 2000 / ReverseCodeEngineeringRceCdsandman2000.iso / RCE / +Sandman / kgtut1.txt < prev    next >
Text File  |  2000-05-25  |  19KB  |  397 lines

  1.                 Keygen Tutorial 1
  2.                    Yes123 '99
  3. ---[ WARNING ]--------------------------------------------------------------------------------
  4.  
  5. This Tutorial is for education purpose only. I wrote it to allow you to understand how are
  6. coded some protections schemes in software. I didn't make it to allow you to use the target
  7. program without paying the author. If you plan to use these programs regularly, please remeber
  8. to send your $ to the authors, don't be a outlaw, and over all, don't be a LAMER !!!
  9.  
  10. ---[ INTRO ]----------------------------------------------------------------------------------
  11.  
  12. target: A Day in the Life v1.0
  13. where : http://www.cartoonlogic.com
  14.  
  15. Tools : SoftIce for Win9x v3.24
  16.     W32Dasm v8.9
  17.         Programming Language (C, Pascal, asm, anyone you want, I'll use our old C)
  18.  
  19. This is my first tutorial in english. I hope my bad spelling won't make this text 
  20. too much hard to understand for you. :)
  21.  
  22. I'll try to teach you how to make a key generator for a program . Our target will be an 
  23. easy one, as the protection scheme is really easy to understand and follow.
  24. I'll assume you know the following:
  25.  
  26. - basic use of SoftIce
  27. - asm instructions (at least the ones used for cracking)
  28. ---[ TUTORIAL ]-------------------------------------------------------------------------------
  29.  
  30. At first, launch SoftIce (assuming you know the basics, and how to setup this Numega's
  31. nice tool). Then launch our target, ADITL1.0.exe! Go to the help menu and select the register.
  32.  
  33. Well, we'll try to find how this protection is running. Let's enter anything as a name
  34. and random digits as a serial. Don't click the OK button yet, but hit CTRL & D to bring up 
  35. SoftICe. We'll define a breakpoint, using the classical BPX hmemcpy(it works for most program.) 
  36. Hit CTRL-D again to go back to the program. Click OK and... SoftICe pop up.
  37.  
  38. Keep pressing F12 until you get back to the traget program code. Trace a few lines down you will
  39. be in:
  40.  
  41.  
  42. :004848A7 E8D4B1F9FF              call 0041FA80            ;start here
  43. :004848AC 8B45F8                  mov eax, dword ptr [ebp-08]    ;eax=pointer to name
  44. :004848AF E8C4F3F7FF              call 00403C78            ;return eax=lenght of name
  45. :004848B4 8BF0                    mov esi, eax            ;esi=lenght of name
  46. :004848B6 85F6                    test esi, esi            ;test lenght
  47. :004848B8 7E28                    jle 004848E2            ;if no name enterthen jump
  48. :004848BA B901000000              mov ecx, 00000001        ;counter=1;ebx=1 firstly
  49.  
  50. * Referenced by a (U)nconditional or (C)onditional Jump at Address:
  51. |:004848E0(C)
  52.  
  53. *first important loop*
  54. ======================
  55. :004848BF 8B45F8                  mov eax, dword ptr [ebp-08]    ;move name to eax
  56. :004848C2 0FB67C08FF              movzx edi, byte ptr [eax+ecx-01];edi=name[ecx]
  57. :004848C7 0FAFFB                  imul edi, ebx            ;edi=edi*ebx
  58. :004848CA 83FF12                  cmp edi, 00000012        ;compare edi with 0x12
  59. :004848CD 7C0F                    jl 004848DE            ;jump if less than
  60. :004848CF 8B45F8                  mov eax, dword ptr [ebp-08]    ;move name to eax
  61. :004848D2 8BC7                    mov eax, edi            ;eax=edi
  62. :004848D4 BB11000000              mov ebx, 00000011        ;ebx=11
  63. :004848D9 99                      cdq                ;expand eax
  64. :004848DA F7FB                    idiv ebx            ;eax=eax/11
  65. :004848DC 8BD8                    mov ebx, eax            ;ebx=eax
  66.  
  67. * Referenced by a (U)nconditional or (C)onditional Jump at Address:
  68. |:004848CD(C)
  69. |
  70. :004848DE 41                      inc ecx
  71. :004848DF 4E                      dec esi
  72. :004848E0 75DD                    jne 004848BF            ;if unfinish loop back
  73.  
  74. The above code is the first important loop of the key-genereating loop.It is basicaaly a very
  75. simple coding and can be summurized as follow:
  76. code=name[ecx]*code/17
  77. Ecx act as a counter, it count the current byte of name in increasing order, and the ebx is 
  78. the code we want.
  79.  
  80. * Referenced by a (U)nconditional or (C)onditional Jump at Address:
  81. |:004848B8(C)
  82. |
  83. :004848E2 8B45F8                  mov eax, dword ptr [ebp-08]    ;move name to eax
  84. :004848E5 E88EF3F7FF              call 00403C78            ;calculate lenght of eax
  85. :004848EA 8BC8                    mov ecx, eax
  86. :004848EC 83F901                  cmp ecx, 00000001
  87. :004848EF 7C30                    jl 00484921            ;jump if no name enter 
  88.  
  89. * Referenced by a (U)nconditional or (C)onditional Jump at Address:
  90. |:0048491F(C)
  91.  
  92. *second important loop*
  93. =======================
  94. :004848F1 8B45F8                  mov eax, dword ptr [ebp-08]    ;move name to eax
  95. :004848F4 0FB67408FF              movzx esi, byte ptr [eax+ecx-01];move name[ecx] to esi
  96. :004848F9 8BC1                    mov eax, ecx            ;ecx is in decresing order
  97. :004848FB 99                      cdq                ;clear edx
  98. :004848FC F7FE                    idiv esi            ;eax = count / name[ecx]
  99. :004848FE 85D2                    test edx, edx            ;test if any number remain
  100. :00484900 740D                    je 0048490F            ;if no then jump
  101. :00484902 8B45F8                  mov eax, dword ptr [ebp-08]    ;eax=name
  102. :00484905 83EE0B                  sub esi, 0000000B        ;name[ecx]=name[ecx]-0B
  103. :00484908 0FAFF3                  imul esi, ebx            ;code=esi*code
  104. :0048490B 8BDE                    mov ebx, esi            ;ebx=code
  105. :0048490D EB0D                    jmp 0048491C            ;unconditional jump
  106.  
  107. * Referenced by a (U)nconditional or (C)onditional Jump at Address:
  108. |:00484900(C)
  109. |
  110. :0048490F 8B45F8                  mov eax, dword ptr [ebp-08]    ;eax=name
  111. :00484912 83C611                  add esi, 00000011        ;name[0]=name[0]+0x11
  112. :00484915 8BC3                    mov eax, ebx            ;eax=code
  113. :00484917 99                      cdq                ;clear edx
  114. :00484918 F7FE                    idiv esi            ;eax=eax/esi
  115. :0048491A 8BD8                    mov ebx, eax            ;ebx=code
  116.  
  117. * Referenced by a (U)nconditional or (C)onditional Jump at Address:
  118. |:0048490D(U)
  119. |
  120. :0048491C 49                      dec ecx
  121. :0048491D 85C9                    test ecx, ecx
  122. :0048491F 75D0                    jne 004848F1            ;loop if unfinish
  123.  
  124. The second important loop is also quite simple, we can neglect line 48490F to 48491A because 
  125. it will never reach when is came to last byte, it will pass throught 48491F and never have 
  126. change to loop back. So the testing algorithem from 4848FB to 484900 actually is rubbish code.
  127. This might be a bug or something that make to confuse us.
  128. The above coding can be summerized as:
  129. code=code*(name[ecx]-0x0b)    ;code in this case is our serial calculated
  130. Ecx is a counter in decreasing order, it start it the last byte of our name. Ebx is the code we
  131. want.
  132.  
  133. * Referenced by a (U)nconditional or (C)onditional Jump at Address:
  134. |:004848EF(C)
  135. |
  136. :00484921 8B45F8                  mov eax, dword ptr [ebp-08]    
  137. :00484924 E84FF3F7FF              call 00403C78
  138. :00484929 50                      push eax
  139. :0048492A 8BC3                    mov eax, ebx
  140. :0048492C 5A                      pop edx            ;edx=lenght of name
  141. :0048492D 2BC2                    sub eax, edx            ;code=code-lenght
  142. :0048492F B907000000              mov ecx, 00000007        ;ecx=0x07
  143. :00484934 99                      cdq
  144. :00484935 F7F9                    idiv ecx            ;code=code/7
  145. :00484937 05920F0000              add eax, 00000F92        ;code=code+0x0f92
  146. :0048493C 8BD8                    mov ebx, eax            ;ebx=code
  147.  
  148. Until here our code=((code-lenght of our name)/7)+0F92
  149.  
  150. :0048493E 8D55F4                  lea edx, dword ptr [ebp-0C]    ;edx=location [final reg key]
  151. :00484941 8BC3                    mov eax, ebx            ;eax=code
  152. :00484943 E8042BF8FF              call 0040744C            ;This call convert the int format
  153. :00484948 8D45F0                  lea eax, dword ptr [ebp-10]    ;of the code into character,
  154. :0048494B 8B55F8                  mov edx, dword ptr [ebp-08]    ;including it's sign also
  155. :0048494E 8A12                    mov dl, byte ptr [edx]
  156.  
  157. The call at 484943 actually convert our code into string form including sign also.
  158.  
  159. :00484950 E84BF2F7FF              call 00403BA0
  160.  
  161. This call search for the char need to be insert in first byte of our serial, it return the
  162. in [ebp-10]. In this case is search for the first byte of our name as result.
  163.  
  164. :00484955 8B45F0                  mov eax, dword ptr [ebp-10]    ;eax=target of insertion
  165. :00484958 8D55F4                  lea edx, dword ptr [ebp-0C]    ;edx=target for insertion
  166. :0048495B B901000000              mov ecx, 00000001        ;ecx=location
  167. :00484960 E89FF5F7FF              call 00403F04            ;This call insert first char 
  168. :00484965 8B55F8                  mov edx, dword ptr [ebp-08]    ;of name into first location
  169. :00484968 B8744A4800              mov eax, 00484A74        ;of code
  170.  
  171. The call 00403F04 actually is a call to insert certain character into the string. It need
  172. EAX for what we want to insert, in above case it need to insert the first char of name.
  173. EDX is the address for the target to insert, in above case edx=address of our serial.
  174. ECX is the location for insertion, in above case it is insert at first byte.
  175.  
  176. :0048496D E8EEF5F7FF              call 00403F60            ;This call for any space in our
  177. :00484972 8B55F8                  mov edx, dword ptr [ebp-08]    ;name
  178. :00484975 8A1402                  mov dl, byte ptr [edx+eax]
  179. :00484978 8D45F0                  lea eax, dword ptr [ebp-10]
  180. :0048497B E820F2F7FF              call 00403BA0            ;This call return eax=the char 
  181. :00484980 8B45F0                  mov eax, dword ptr [ebp-10]    ;should placed in last byte of
  182. :00484983 50                      push eax            ;code
  183. :00484984 8B45F4                  mov eax, dword ptr [ebp-0C]
  184. :00484987 E8ECF2F7FF              call 00403C78            ;Calculate last byte location
  185. :0048498C 8BC8                    mov ecx, eax
  186. :0048498E 41                      inc ecx
  187. :0048498F 8D55F4                  lea edx, dword ptr [ebp-0C]
  188. :00484992 58                      pop eax
  189. :00484993 E86CF5F7FF              call 00403F04            ;This call insert eax from call
  190. :00484998 8B45F4                  mov eax, dword ptr [ebp-0C]    ;00403BA0 into last byte of code
  191.  
  192. The above code search for any space(20) in our name, if it does then the take the next byte
  193. after the FIRST space and put it into last byte of our code. If it doesn't found any space, then
  194. it will put first byte of our name into last byte of our code.
  195. Eg: Name=abc
  196.     code=a15335672a
  197.     Name=abc def
  198.     code=a87672812d
  199.     Name=abc 123 456
  200.     code=a-15942455d
  201.  
  202. :0048499B E8D8F2F7FF              call 00403C78
  203. :004849A0 8BC8                    mov ecx, eax
  204. :004849A2 D1F9                    sar ecx, 1            ;ecx=lenght(name)>>1
  205. :004849A4 7903                    jns 004849A9            ;jump if ecx>0
  206. :004849A6 83D100                  adc ecx, 00000000
  207.  
  208. The above code calculate the lenght of our name, ecx = our lenght of name shift right by one.
  209.  
  210.  
  211. * Referenced by a (U)nconditional or (C)onditional Jump at Address:
  212. |:004849A4(C)
  213. |
  214. :004849A9 8D55F4                  lea edx, dword ptr [ebp-0C]
  215.  
  216. * Possible StringData Ref from Code Obj ->"ClaDiTL"
  217.                                   |
  218. :004849AC B8804A4800              mov eax, 00484A80
  219. :004849B1 E84EF5F7FF              call 00403F04            ;This call insert "ClaDiTL" into
  220. :004849B6 8D55EC                  lea edx, dword ptr [ebp-14]    ;ecx location of code
  221. :004849B9 8B45FC                  mov eax, dword ptr [ebp-04]
  222. :004849BC 8B80EC010000            mov eax, dword ptr [eax+000001EC]
  223. :004849C2 E8B9B0F9FF              call 0041FA80
  224.  
  225. The above code inserts words'ClaDiTL" into our code, it insert in the location ecx, and ecx
  226. is our name lenght right shift by one.
  227. Eg:With name=yes123
  228.    before insertion, code=y-85638181y
  229.    after insertion,  code=y-85ClaDiTL638181y
  230.  
  231. :004849C7 8B55EC                  mov edx, dword ptr [ebp-14]    ;edx=our false key
  232. :004849CA 8B45F4                  mov eax, dword ptr [ebp-0C]    ;eax=real key
  233. :004849CD E8B6F3F7FF              call 00403D88            ;test for both key
  234. :004849D2 7530                    jne 00484A04            ;jump if not equal
  235.  
  236. The this part, it compare our fake key with the real key generated.
  237. So we can type 'd eax' after line 4849CA to sea for the real key.
  238.  
  239.  
  240. :004849D4 8D55EC                  lea edx, dword ptr [ebp-14]
  241. :004849D7 8B45FC                  mov eax, dword ptr [ebp-04]
  242. :004849DA 8B80EC010000            mov eax, dword ptr [eax+000001EC]
  243. :004849E0 E89BB0F9FF              call 0041FA80
  244. :004849E5 8B55EC                  mov edx, dword ptr [ebp-14]
  245.  
  246. * Possible StringData Ref from Code Obj ->"ClaDiTL"
  247.                                   |
  248. :004849E8 B8804A4800              mov eax, 00484A80
  249. :004849ED E86EF5F7FF              call 00403F60
  250. :004849F2 85C0                    test eax, eax
  251. :004849F4 7E0E                    jle 00484A04
  252. :004849F6 A114F74800              mov eax, dword ptr [0048F714]
  253. :004849FB 8B00                    mov eax, dword ptr [eax]
  254. :004849FD E8BA7B0000              call 0048C5BC
  255. :00484A02 EB37                    jmp 00484A3B
  256.  
  257. The above code store our registered data into registry.
  258.  
  259. * Referenced by a (U)nconditional or (C)onditional Jump at Addresses:
  260. |:004849D2(C), :004849F4(C)
  261. |
  262. :00484A04 6A00                    push 00000000
  263. :00484A06 668B0D884A4800          mov cx, word ptr [00484A88]
  264. :00484A0D B201                    mov dl, 01
  265.  
  266. * Possible StringData Ref from Code Obj ->"Invalid registration code!"
  267.                                   |
  268. :00484A0F B8944A4800              mov eax, 00484A94        ;Change this code to 8B45F49090
  269.  
  270. When we trace to here, there is also a fun place to make change, we can change the :
  271.     00484A0F B8944A4800              mov eax, 00484A94
  272.     into:
  273.     00484A0F 8B45F4                  mov eax, dword ptr [ebp-0C]
  274.     00484A12 90                      nop
  275.     00484A13 90                      nop
  276. So that instead of display out the "Invalid registration code!", it will display out our real
  277. key if we enter wrong key. This is beacuse from line 4849CA, we know the real key is store at
  278. [ebp-0C]. You can try and make a patch for for it. This technique is so call 'Magic Window'.
  279.  
  280. :00484A14 E8DB7CFBFF              call 0043C6F4    
  281. :00484A19 8B45FC                  mov eax, dword ptr [ebp-04]    
  282. :00484A1C 8B80E0010000            mov eax, dword ptr [eax+000001E0]
  283. :00484A22 8B10                    mov edx, dword ptr [eax]    
  284. :00484A24 FF9294000000            call dword ptr [edx+00000094]    
  285. :00484A2A 8B45FC                  mov eax, dword ptr [ebp-04]
  286. :00484A2D 8B80EC010000            mov eax, dword ptr [eax+000001EC]
  287. :00484A33 8B10                    mov edx, dword ptr [eax]
  288. :00484A35 FF9294000000            call dword ptr [edx+00000094]
  289.  
  290. * Referenced by a (U)nconditional or (C)onditional Jump at Address:
  291. |:00484A02(U)
  292. |
  293. :00484A3B 33C0                    xor eax, eax
  294. :00484A3D 5A                      pop edx
  295. :00484A3E 59                      pop ecx
  296. :00484A3F 59                      pop ecx
  297. :00484A40 648910                  mov dword ptr fs:[eax], edx
  298.  
  299. * Possible StringData Ref from Code Obj ->"_^["
  300.                                   |
  301. :00484A43 68654A4800              push 00484A65
  302.  
  303. * Referenced by a (U)nconditional or (C)onditional Jump at Address:
  304. |:00484A63(U)
  305. |
  306. :00484A48 8D45EC                  lea eax, dword ptr [ebp-14]
  307. :00484A4B E8ACEFF7FF              call 004039FC
  308. :00484A50 8D45F0                  lea eax, dword ptr [ebp-10]
  309. :00484A53 BA03000000              mov edx, 00000003
  310. :00484A58 E8C3EFF7FF              call 00403A20
  311. :00484A5D C3                      ret
  312.  
  313. ---[ OVERALL CONCLUSION OF KEY GENERATING PROCESS ]--------------------------------------------
  314. 1.code=(code*name[count1])/0x11;    //count1=counter from 0 to lenght of name
  315. 2.code=code*(name[count2]-0x0b);    //count2=counter from lenght of name to 0
  316. 3.code=((code-count1)/7)+0xf92;        //count1=lenght of name
  317. 4.convert code into string form.
  318. 5.insert suitable character into the head and tail of the code.
  319. 6.insert 'ClaDiTL' into suitable place of the code
  320.  
  321. ---[ C-LANGUAGE CODE ]-------------------------------------------------------------------------
  322. #include <stdio.h>
  323. #include<conio.h>
  324. #include <stdlib.h>
  325.  
  326. int main(void)
  327.   {
  328.    long code=1;
  329.    int count1,count2,count3;
  330.    char name[25],reg[15];
  331.    clrscr();
  332.    textcolor(14);
  333.    cprintf("    __,__\r\n");
  334.    cprintf("   /     \\\r\n" );
  335.    cprintf("   vvvvvvv  /|__/|\r\n");
  336.    cprintf("      I   /O,O   |\r\n");
  337.    cprintf("      I /_____   |      /|/|\r\n");
  338.    cprintf("     J|/^ ^ ^ \\  |    /00  |    _//|\r\n");
  339.    cprintf("      |^ ^ ^ ^ |W|   |/^^\\ |   /oo |\r\n");
  340.    cprintf("       \\m___m__|_|    \\m_m_|   \\mm_|\r\n");
  341.    textcolor(10);
  342.    cprintf("=======================================");
  343.    textcolor(11);
  344.    cprintf("\r\nKeyGenerator for A Day in the Life v1.0");
  345.    textcolor(10);
  346.    cprintf("\r\n=======================================");
  347.    printf("\nCracked by ");
  348.    textcolor(14);
  349.    cprintf("%c%c%c",0x10,0x10,0x10);
  350.    textcolor(12);
  351.    cprintf("Yes123");
  352.    textcolor(14);
  353.    cprintf("%c%c%c",0x11,0x11,0x11);
  354.    printf(" - February 1999");
  355.    printf("\n\nEnter register name = ");
  356.    scanf("%[^\n]",name);
  357.    for(count1=0;name[count1]>0;count1++)    //first loop
  358.      code=(code*name[count1])/0x11;
  359.    for(count2=count1-1;count2>=0;count2--)    //second loop
  360.      code=code*(name[count2]-0x0b);
  361.    code=((code-count1)/7)+0xf92;
  362.    ltoa(code,reg,10);                //convert long to string
  363.    printf("Your registration key = %c",name[0]);
  364.    for(count2=0;reg[count2]>0;count2++);
  365.    count2=(count2+2)>>1;
  366.    for(count1=0;count1<(count2-2);count1++)
  367.      printf("%c",reg[count1]);
  368.    printf("ClaDiTL");
  369.    for(;reg[count1]>0;count1++)
  370.      printf("%c",reg[count1]);
  371.    for(count1=0;name[count1]>0;count1++){
  372.      if ((name[count1]==0x20)&&(name[count1+1]>0)){
  373.        printf("%c",name[count1+1]);
  374.        return;
  375.        }
  376.      }
  377.    printf("%c",name[0]);
  378.    return ;
  379. }
  380.  
  381. ---[ LAST ]------------------------------------------------------------------------------------
  382.  
  383. I know my english expressing ability is weak, so in many place i know what's happening but i can
  384. express well and explain to you clearly. I hope you can really try it out then you can
  385. understand more out of it. This is my first keygen tutorial and i hope you'll like it.
  386.  
  387. You can also try to trace into the call of how they insert words into string, call of how
  388. they calculate the strings number, call of how they compare two strings, call of how they search 
  389. for specific char in a string... Try to understand their coding, it is quite interesting and 
  390. useful also if we met similar call.
  391.  
  392. Thanks for reading my first keygen tutorial.
  393.  
  394. ---[ THAT'S ALL FOLKS ]-----------------------------------------------------------------------
  395.  
  396. Yes123 '99
  397. ==========