• 标 题:SnagIt! v5.2.1. (一) (10千字)
  • 作 者:arbiter
  • 时 间:2001-6-24 3:28:24
  • 链 接:http://bbs.pediy.com

; -----------------------------------------------------------
; author:    arbiter
; target:    SnagIt! v5.2.1
; tools:    SoftIce v4.05 for win2k ( only )
; time:        2001-6-24 2:37    
; -----------------------------------------------------------

  not say more than is needed, we are go into particulars.
 
  firstly, fire up your SoftIce, and set the break point on GetWindowTextA,
go back into the SnagIt's register dialogbox,fill in some information at will,
then click the 'ok' button,SoftIce'll pop up as it hook at the api we set
just now. out of the api by pushing F10 about times. you can easyly find the
address ( offset: 47b01a ), here is the snippet of code over the offset: 47b01a

  Possible StringData Ref from Data Obj ->""                         
                                  |                               
  0047AFDE A168264F00              mov eax, dword ptr [004F2668]   
  0047AFE3 8944240C                mov dword ptr [esp+0C], eax     
  0047AFE7 C744241C00000000        mov [esp+1C], 00000000         
  0047AFEF 89442408                mov dword ptr [esp+08], eax     
  0047AFF3 8D44240C                lea eax, dword ptr [esp+0C]     
  0047AFF7 8BCE                    mov ecx, esi                   
  0047AFF9 50                      push eax                       
  0047AFFA 68ED270000              push 000027ED                   
  0047AFFF C644242401              mov [esp+24], 01               
  0047B004 E85F1C0200              call 0049CC68                   
  0047B009 8D4C2408                lea ecx, dword ptr [esp+08]     
  0047B00D 51                      push ecx                       
  0047B00E 68EE270000              push 000027EE                   
  0047B013 8BCE                    mov ecx, esi                   
  0047B015 E84E1C0200              call 0049CC68                   
  0047B01A 8B8E94000000            mov ecx, dword ptr [esi+00000094]
  0047B020 8D542408                lea edx, dword ptr [esp+08]     
  0047B024 8D44240C                lea eax, dword ptr [esp+0C]     
  0047B028 52                      push edx                       
  0047B029 50                      push eax                       
  0047B02A 56                      push esi                       
  0047B02B E800E5FFFF              call 00479530    <--- @ main routine here! @             
  0047B030 8BD8                    mov ebx, eax                   
  0047B032 8B868C000000            mov eax, dword ptr [esi+0000008C]
  0047B038 85C0                    test eax, eax                   
  0047B03A 0F85B7000000            jne 0047B0F7                   
  0047B040 8B8E94000000            mov ecx, dword ptr [esi+00000094]
  0047B046 53                      push ebx                       
  0047B047 E8D4E2FFFF              call 00479320                   
  0047B04C 85C0                    test eax, eax                   
  0047B04E 0F84A3000000            je 0047B0F7
  .
  .
  .
  before the call 47b02b, it pushed your 'userName', 'userCode', that you entered
for the inner checking routine. so we need go into the call. i ignore the slim length
check for the entered name. after that we are here: 47955c
 
  0047955C 8B7C2418                mov edi, dword ptr [esp+18]   
  00479560 8BCF                    mov ecx, edi                   
  00479562 E89CEB0100              call 00498103                 
  00479567 8B07                    mov eax, dword ptr [edi]       
  00479569 8B58F8                  mov ebx, dword ptr [eax-08]   
  0047956C 83FB0E                  cmp ebx, 0000000E             
  0047956F 0F8CB9000000            jl 0047962E                   
                                                                 
  Possible StringData Ref from Data Obj ->"0123456789ABCDEF-"   
                                  |                             
  00479575 6844204F00              push 004F2044                 
  0047957A 50                      push eax                       
  0047957B E840DD0000              call 004872C0                 
  00479580 83C408                  add esp, 00000008             
  00479583 3BC3                    cmp eax, ebx                   
  00479585 0F85A3000000            jne 0047962E                   
                                                                 
  Possible StringData Ref from Data Obj ->""                     
                                  |                             
  0047958B 6864664F00              push 004F6664                 
                                                                 
  Possible StringData Ref from Data Obj ->"-"                   
                                  |                             
  00479590 6840204F00              push 004F2040                 
  00479595 8BCF                    mov ecx, edi                   
  00479597 E853E40100              call 004979EF                 
  0047959C 8B07                    mov eax, dword ptr [edi]       
  0047959E 8B4D00                  mov ecx, dword ptr [ebp+00]   
  004795A1 8B16                    mov edx, dword ptr [esi]       
  004795A3 50                      push eax                       
  004795A4 51                      push ecx                       
  004795A5 8BCE                    mov ecx, esi                   
  004795A7 FF520C                  call [edx+0C]                 
  004795AA 8BD8                    mov ebx, eax                   
  004795AC 80FB01                  cmp bl, 01                     
  004795AF 7545                    jne 004795F6                   
 
  we'll be warned with the nag and kicked off from the code, if bl got
0 from above call. and that call is most important call for calculate
the real RegCode and use it to compare with our fake key. so you should
know how to do with your brute forcing way. whereas out purpose was to
find out the scheme that the SnagIt use to generate the real RegCode and
got one of certified informations by ourself. so go on. we're more and
more closer with our final goal from now on.
  go into the most important call at address 4795a7 that mentioned above.
and you'll get a little confusion about the code below, and do not be
worry about that. i'll nevigate you throughout it.

  0045A9B3 B824194C00              mov eax, 004C1924                 
  0045A9B8 E8CFA60200              call 0048508C                     
  0045A9BD 83EC58                  sub esp, 00000058                   
  0045A9C0 53                      push ebx                         
  0045A9C1 56                      push esi                         
  0045A9C2 57                      push edi                         
  0045A9C3 894DE4                  mov dword ptr [ebp-1C], ecx       
  0045A9C6 FF750C                  push [ebp+0C]                     
  0045A9C9 33DB                    xor ebx, ebx                     
  0045A9CB 8D4D0C                  lea ecx, dword ptr [ebp+0C]       
  0045A9CE 895DEC                  mov dword ptr [ebp-14], ebx       
  0045A9D1 C745E001000000          mov [ebp-20], 00000001           
  0045A9D8 885DF2                  mov byte ptr [ebp-0E], bl         
  0045A9DB C645F301                mov [ebp-0D], 01                 
  0045A9DF E898530400              call 0049FD7C                     
  0045A9E4 8B450C                  mov eax, dword ptr [ebp+0C]       
  0045A9E7 895DFC                  mov dword ptr [ebp-04], ebx       
  0045A9EA 8B40F8                  mov eax, dword ptr [eax-08]       
  0045A9ED 83F80E                  cmp eax, 0000000E                 
  0045A9F0 0F8C65010000            jl 0045AB5B
 
  all of above code do some initializations and the call nearby are checking
if the entered key is illegal by counting the number of the every chars of the
key except for the non-hexadecimal number( legal char is between 0~F ). and
compare the result with 0Eh, game over if they are not equal. so do remember
the legal RegCode is composed with the hexadecimal number.
                         
  0045A9F6 6A02                    push 00000002                     
  0045A9F8 8D45E8                  lea eax, dword ptr [ebp-18]       
  0045A9FB 6A0C                    push 0000000C                     
  0045A9FD 50                      push eax                         
  0045A9FE 8D4D0C                  lea ecx, dword ptr [ebp+0C]       
 
  0045AA01 E86FD10300              call 00497B75  <--- get last two num.                   
 
  0045AA06 8B00                    mov eax, dword ptr [eax]
 
  call at 497b75 fetched the last two numbers of the fake key and store it
for later use.    exp: char num[2];
           
  0045AA08 6A10                    push 00000010                     
  0045AA0A 53                      push ebx                         
  0045AA0B 50                      push eax                         
  0045AA0C E803B80200              call 00486214  <---                   
 
  this call converted the number from ASCII to hexadecima.
                exp:    dword h_num = atoi( num );
     
 
  0045AA11 83C40C                  add esp, 0000000C                 
  0045AA14 8D4DE8                  lea ecx, dword ptr [ebp-18]       
  0045AA17 8BF8                    mov edi, eax                     
  0045AA19 E8F0520400              call 0049FD0E                     
 
  here move the h_num to di and compare it with 041h, if it shy, then
game over. add it with 0ffbf and check the al with 050h, that use to
switch the program from two flows. if the addition result less than 050h
it will involve the userName procedure, else it's simply to cope with.
i forgot commenting some code above, heihei, but it just the simple MD5
HASH digest for the userName. the whole routine mainly use the MD5 HASH
function two times to produce an 128 bit value, finaly picking up bytes
from the result and using it to look up the hex-table to yield the real
RegCode.i assume its name string3. the string1 is yielded by firstly MD5
HASH with the userName. string2 is made up with the string1 and last 6
number of the fake key, use the string2 to do the second MD5 HASH function
to yield the string3. later on i'll explain it in details.

  • 标 题:SnagIt! v5.2.1. (二) (8千字)
  • 作 者:arbiter
  • 时 间:2001-6-24 3:29:32

0045AA1E 6683FF41                cmp di, 0041                     
  0045AA22 0F8233010000            jb 0045AB5B                       
  0045AA28 81C7BFFF0000            add edi, 0000FFBF                 
  0045AA2E 6683FF50                cmp di, 0050                     
  0045AA32 7260                    jb 0045AA94                       
  0045AA34 8B450C                  mov eax, dword ptr [ebp+0C]       
  0045AA37 8378F812                cmp dword ptr [eax-08], 00000012 
  0045AA3B 7C79                    jl 0045AAB6                       
  0045AA3D 8D4508                  lea eax, dword ptr [ebp+08]       
  0045AA40 6A04                    push 00000004                     
  0045AA42 50                      push eax                         
  0045AA43 8D4D0C                  lea ecx, dword ptr [ebp+0C]       
  0045AA46 E8C0D10300              call 00497C0B                     
  0045AA4B 8B00                    mov eax, dword ptr [eax]         
  0045AA4D 6A10                    push 00000010                     
  0045AA4F 53                      push ebx                         
  0045AA50 50                      push eax                         
  0045AA51 E8BEB70200              call 00486214                     
  0045AA56 83C40C                  add esp, 0000000C                 
  0045AA59 8D4D08                  lea ecx, dword ptr [ebp+08]       
  0045AA5C 8945EC                  mov dword ptr [ebp-14], eax       
  0045AA5F E8AA520400              call 0049FD0E                     
  0045AA64 8B450C                  mov eax, dword ptr [ebp+0C]       
  0045AA67 8D4D0C                  lea ecx, dword ptr [ebp+0C]       
  0045AA6A 8B40F8                  mov eax, dword ptr [eax-08]       
  0045AA6D 83C0FC                  add eax, FFFFFFFC                 
  0045AA70 50                      push eax                         
  0045AA71 8D4508                  lea eax, dword ptr [ebp+08]       
  0045AA74 50                      push eax                         
  0045AA75 E80DD20300              call 00497C87                     
  0045AA7A 50                      push eax                         
  0045AA7B 8D4D0C                  lea ecx, dword ptr [ebp+0C]       
  0045AA7E C645FC01                mov [ebp-04], 01                 
  0045AA82 E874530400              call 0049FDFB                     
  0045AA87 8D4D08                  lea ecx, dword ptr [ebp+08]       
  0045AA8A 885DFC                  mov byte ptr [ebp-04], bl         
  0045AA8D E87C520400              call 0049FD0E                     
  0045AA92 EB22                    jmp 0045AAB6                     
                                                                     
  Referenced by a (U)nconditional or (C)onditional Jump at Address: 
  :0045AA32(C)                                                       
                                                                     
  0045AA94 FF7508                  push [ebp+08]                     
  0045AA97 E8E8D40200              call 00487F84                     
  0045AA9C 8BF0                    mov esi, eax                     
  0045AA9E 59                      pop ecx                           
  0045AA9F 3BF3                    cmp esi, ebx                     
  0045AAA1 7413                    je 0045AAB6                       
  0045AAA3 8B4DE4                  mov ecx, dword ptr [ebp-1C]       
  0045AAA6 56                      push esi                         
  0045AAA7 E814E20100              call 00478CC0 
 
  above call is calculating the MD5 HASH digest of the uppercase of the
input userName and get first two bytes of the digest and store it to a
memory locations for the later processing. this generate the string1.
the first two bytes.
                     
  0045AAAC 56                      push esi                         
  0045AAAD 8945EC                  mov dword ptr [ebp-14], eax       
  0045AAB0 E840C10200              call 00486BF5                     
  0045AAB5 59                      pop ecx                           
                                                                     
  Referenced by a (U)nconditional or (C)onditional Jump at Addresses:
  :0045AA3B(C), :0045AA92(U), :0045AAA1(C)                           
                                                                     
  0045AAB6 6A0F                    push 0000000F                     
  0045AAB8 8D45D0                  lea eax, dword ptr [ebp-30]       
  0045AABB 53                      push ebx                         
  0045AABC 50                      push eax                         
  0045AABD E84EA90200              call 00485410                     
  0045AAC2 83C40C                  add esp, 0000000C                 
  0045AAC5 8D4D0C                  lea ecx, dword ptr [ebp+0C]       
  0045AAC8 6A0E                    push 0000000E                     
  0045AACA 6A0E                    push 0000000E                     
  0045AACC E821560400              call 004A00F2                     
  0045AAD1 50                      push eax                         
  0045AAD2 8D45D0                  lea eax, dword ptr [ebp-30]       
  0045AAD5 50                      push eax                         
  0045AAD6 E895A90200              call 00485470                     
  0045AADB 83C40C                  add esp, 0000000C                 
  0045AADE 8D4D0C                  lea ecx, dword ptr [ebp+0C]       
                                                                     
  Possible Reference to Dialog: DialogID_0098, CONTROL_ID:00FF, "" 
                                  |                                 
  0045AAE1 6AFF                    push FFFFFFFF                     
  0045AAE3 E859560400              call 004A0141                     
  0045AAE8 8D459C                  lea eax, dword ptr [ebp-64]       
  0045AAEB 50                      push eax                         
  0045AAEC E8EFF10100              call 00479CE0                     
  0045AAF1 85C0                    test eax, eax                     
  0045AAF3 59                      pop ecx                           
  0045AAF4 7505                    jne 0045AAFB                     
                                                                     
  Referenced by a (U)nconditional or (C)onditional Jump at Addresses:
  :0045AB0F(C), :0045AB25(C)                                         
                                                                     
  0045AAF6 885DF3                  mov byte ptr [ebp-0D], bl         
  0045AAF9 EB67                    jmp 0045AB62                     
                                                                     
  Referenced by a (U)nconditional or (C)onditional Jump at Address: 
  :0045AAF4(C)                                                       
                                                                     
  0045AAFB 8D45E0                  lea eax, dword ptr [ebp-20]       
  0045AAFE 6A02                    push 00000002                     
  0045AB00 50                      push eax                         
  0045AB01 8D459C                  lea eax, dword ptr [ebp-64]       
  0045AB04 50                      push eax                         
  0045AB05 E8E6F10100              call 00479CF0                     
  0045AB0A 83C40C                  add esp, 0000000C                 
  0045AB0D 85C0                    test eax, eax                     
  0045AB0F 74E5                    je 0045AAF6                       
  0045AB11 8D45EC                  lea eax, dword ptr [ebp-14]       
  0045AB14 6A02                    push 00000002                     
  0045AB16 50                      push eax                         
  0045AB17 8D459C                  lea eax, dword ptr [ebp-64]       
  0045AB1A 50                      push eax                         
 
  0045AB1B E8D0F10100              call 00479CF0 <--- commented below.
 
  through out a long way we come here. the call above is the first step to
construct the string2. by default, the string2 is initialized with '01 00'
as the first two bytes. this call fetch another two bytes in the memory loc
which store the string1 or dword zero before by the checking of h_num. cat
it to string2 follow the '01 00', now it is look like '01 00 xx xx' which
xx xx is denoted string1.

  • 标 题:SnagIt! v5.2.1. (三) (9千字)
  • 作 者:arbiter
  • 时 间:2001-6-24 3:30:24

0045AB20 83C40C                  add esp, 0000000C                 
  0045AB23 85C0                    test eax, eax                     
  0045AB25 74CF                    je 0045AAF6                       
  0045AB27 8D45D0                  lea eax, dword ptr [ebp-30]       
  0045AB2A 50                      push eax                         
  0045AB2B 8D459C                  lea eax, dword ptr [ebp-64]       
  0045AB2E 50                      push eax                         
 
  0045AB2F E89CF20100              call 00479DD0
 
  we must pay more attention on this callee, it work for finishing the
construction of the string2 and accomplish full key generation and key
check! just go into it! 
 
  00479DF3 8BD0                    mov edx, eax                     
  00479DF5 81E2FFFF0000            and edx, 0000FFFF               
  00479DFB 40                      inc eax                         
  00479DFC 884C1404                mov byte ptr [esp+edx+04], cl   
  00479E00 41                      inc ecx                         
  00479E01 6683F946                cmp cx, 0046                   
  00479E05 76EC                    jbe 00479DF3 
 
  messy code to puzzle you!
                   
  00479E07 53                      push ebx                       
  00479E08 8B9C2488000000          mov ebx, dword ptr [esp+00000088]
  00479E0F 56                      push esi                       
  00479E10 89442408                mov dword ptr [esp+08], eax     
  00479E14 57                      push edi                       
  00479E15 8D430C                  lea eax, dword ptr [ebx+0C]     
  00479E18 6A02                    push 00000002                   
  00479E1A 50                      push eax                       
  00479E1B E820FFFFFF              call 00479D40                   
  00479E20 8BB42494000000          mov esi, dword ptr [esp+00000094]
  00479E27 8D4C2414                lea ecx, dword ptr [esp+14]     
 
  00479E2B 6A02                    push 00000002                   
  00479E2D 51                      push ecx                       
  00479E2E 56                      push esi                       
  00479E2F 89442420                mov dword ptr [esp+20], eax     
  00479E33 E8B8FEFFFF              call 00479CF0       
 
  this piece of code take the last two chars and convert them to hexadecimal
format, and combine them to a byte. afterward,storing the result as a word into
the string2 series. now the string2 is look like '01 00 xx xx xl 00' which
xl denote to the hex-format of the last two bytes of the fake key. 
               
  00479E38 8D5308                  lea edx, dword ptr [ebx+08]     
  00479E3B 6A04                    push 00000004                   
  00479E3D 52                      push edx                       
  00479E3E E8FDFEFFFF              call 00479D40                   
  00479E43 89442428                mov dword ptr [esp+28], eax     
  00479E47 8D442428                lea eax, dword ptr [esp+28]     
  00479E4B 6A02                    push 00000002                   
  00479E4D 50                      push eax                       
  00479E4E 56                      push esi                       
  00479E4F E89CFEFFFF              call 00479CF0
   
  the fronter functions of the above two calls is use to do the same work
'convert' and 'combine' with the reciprocal 3~6 chars. and the second call
stores the result two bytes into the string2. and here finish constructing
the string2.  now it looks like this:
 
  char *string = "01 00 xx xx xl 00 ab cd"; which ab and cd denote to the
  result yield by the above two calls.
 
  00479E54 8D4C2458                lea ecx, dword ptr [esp+58]                         
  00479E58 51                      push ecx                       
  00479E59 E882000000              call 00479EE0   
 
  the call at 479ee0 initialize the four chaining variables of MD5 HASH according
with the standard MD5.
               
  00479E5E 33D2                    xor edx, edx                   
  00479E60 8D7E02                  lea edi, dword ptr [esi+02]   
  00479E63 668B16                  mov dx, word ptr [esi]         
  00479E66 8D44245C                lea eax, dword ptr [esp+5C]   
  00479E6A 52                      push edx                       
  00479E6B 57                      push edi                       
  00479E6C 50                      push eax                       
  00479E6D E89E000000              call 00479F10
 
  the above call intent to hide the string2 by convey it from the origin
local memeory to another place. but i catch it! :)
                   
  00479E72 8D4C2468                lea ecx, dword ptr [esp+68]   
  00479E76 8D542458                lea edx, dword ptr [esp+58]   
  00479E7A 51                      push ecx                       
  00479E7B 52                      push edx                       
  00479E7C E84F010000              call 00479FD0                 
 
  standard MD5 HASH digest! to processing the string2. the edx pointed to
the result address.  here the string3 was yielded.
 
  00479E81 B90C000000              mov ecx, 0000000C             
  00479E86 33C0                    xor eax, eax                   
  00479E88 F3                      repz                           
  00479E89 AB                      stosd                         
  00479E8A 66AB                    stosw                         
  00479E8C 83C440                  add esp, 00000040             
  00479E8F 33FF                    xor edi, edi                   
                                                                 
  Referenced by a (U)nconditional or (C)onditional Jump at Address:
  :00479EC5(C)                                                   
                                                                 
  00479E91 8BF7                    mov esi, edi                   
  00479E93 81E6FFFF0000            and esi, 0000FFFF             
  00479E99 8BC6                    mov eax, esi                   
  00479E9B D1E8                    shr eax, 1                     
  00479E9D 8A0C18                  mov cl, byte ptr [eax+ebx]     
  00479EA0 51                      push ecx                       
  00479EA1 E80AFFFFFF              call 00479DB0                 
  00479EA6 8A543424                mov dl, byte ptr [esp+esi+24] 
  00479EAA 25FF000000              and eax, 000000FF             
  00479EAF 83E20F                  and edx, 0000000F             
  00479EB2 83C404                  add esp, 00000004             
  00479EB5 0FBE4C1410              movsx ecx, byte ptr [esp+edx+10]
  00479EBA 3BC8                    cmp ecx, eax                   
  00479EBC 7515                    jne 00479ED3                   
  00479EBE 83C702                  add edi, 00000002             
  00479EC1 6683FF10                cmp di, 0010                   
  00479EC5 72CA                    jb 00479E91
 
  this paragraph is the core checking code, cl contained the first 8 fake
key that we entered before. and it picked out bytes from the string3 by each
iteration step 2,that's mean it selected the odd number chars of string3. 1,
3, 5, 7, 9 till 15. and move the byte just picked to the dl. and dl with 0fh,
looking up the hex table to yield the real RegCode. finally compary every yielded
RegCode with cl about 8 times, if any of check was not match then game over.
so here we can get the first 8 bytes of the real RegCode. and combine it with
the last 6 byte of the fake key which wo base on to calculate the first part of
the RegCode,we conclude our Regcode now!
 
  below snippet is the outer range of the main routine related to the upper
code before the core checking routine... why i mention this? the SnagIt! has
a version check by checking the value of the last byte of the reg code, as the
above slim operations.
 
              xor    di, di
              mov    di, last_byte
              add    di, 0ffbfh
              cmp    di, 050h
              ja    @good
              add    di, 0ch
              ja    @good
              call    MessageBoxA, ...offset " your register key are \
                      out of time".
  so do remeber that , never let the last number yielded from the convert and combine
operation with the entered last two chars less than 85d. 
  .
  .
  .
                                               
  0045AB43 6683FF50                cmp di, 0050                     
  0045AB47 7319                    jnb 0045AB62                     
  0045AB49 83C70C                  add edi, 0000000C                 
  0045AB4C 6683FF50                cmp di, 0050                     
  0045AB50 7310                    jnb 0045AB62                     
  0045AB52 885DF3                  mov byte ptr [ebp-0D], bl         
  0045AB55 C645F20B                mov [ebp-0E], 0B                 
  0045AB59 EB07                    jmp 0045AB62                     
  .
  .
  .
 
  here you are one of worked key set.
 
  userName:    arbiter
  userCode:    963B851E7D508F
 
  that all over the work. cause of my poor english, i just can do this essay
like this. i've try my best. so i beg your pardon for any errors and uncompat -
ibilities among this essay.
  at the same time, despite some of the errors and shortages, i hope you would
learn somethings from it!                                           


  my greeting fly to all of the guys of the kanxue forum. and all the crackers
in china!
                           
                                                                arbiter.