Avi恢复向导--追注册码(1)

 软件:Avi恢复向导

壳:ASPack 2.12 -> Alexey Solodovnikov脱壳:Microsoft Visual C++ 6.0

追注册码:

       OD载入脱壳后程序,Ctrl+N查看函数,看到程序有lstrcmplstrcmpi两个函数,在lstrcmp函数上回车查看函数信息,并在全部使用lstrcmp函数上下断(右键在每条命令上设置断点),lstrcmpi同样。F9运行程序,输入假的注册信息:

用户名:Alex

注册码:0123456789

点击注册,程序停在字符串比较函数00491F0E处:

00491ED1  /$  55            PUSH EBP

00491ED2  |.  8BEC          MOV EBP,ESP

00491ED4  |.  81EC 00010000 SUB ESP,100

00491EDA  |.  56            PUSH ESI

00491EDB  |.  FF75 0C       PUSH DWORD PTR SS:[EBP+C]                ; /String

00491EDE  |.  FF15 60A14E00 CALL DWORD PTR DS:[<&kernel32.lstrlen>]  ; /lstrlenA

00491EE4  |.  8BF0          MOV ESI,EAX

00491EE6  |.  B8 00010000   MOV EAX,100

00491EEB  |.  3BF0          CMP ESI,EAX

00491EED  |.  77 29         JA SHORT unpack.00491F18

00491EEF  |.  50            PUSH EAX                                 ; /Count => 100 (256.)

00491EF0  |.  8D85 00FFFFFF LEA EAX,DWORD PTR SS:[EBP-100]           ; |

00491EF6  |.  50            PUSH EAX                                 ; |Buffer

00491EF7  |.  FF75 08       PUSH DWORD PTR SS:[EBP+8]                ; |hWnd

00491EFA  |.  FF15 2CA54E00 CALL DWORD PTR DS:[<&user32.GetWindowTex>; /GetWindowTextA

00491F00  |.  3BC6          CMP EAX,ESI

00491F02  |.  75 14         JNZ SHORT unpack.00491F18

00491F04  |.  FF75 0C       PUSH DWORD PTR SS:[EBP+C]                ; /String2

00491F07  |.  8D85 00FFFFFF LEA EAX,DWORD PTR SS:[EBP-100]           ; |

00491F0D  |.  50            PUSH EAX                                 ; |String1

00491F0E  |.  FF15 4CA14E00 CALL DWORD PTR DS:[<&kernel32.lstrcmp>]  ; /lstrcmpA

00491F14  |.  85C0          TEST EAX,EAX

00491F16  |.  74 0C         JE SHORT unpack.00491F24

00491F18  |>  FF75 0C       PUSH DWORD PTR SS:[EBP+C]                ; /Text

00491F1B  |.  FF75 08       PUSH DWORD PTR SS:[EBP+8]                ; |hWnd

00491F1E  |.  FF15 7CA44E00 CALL DWORD PTR DS:[<&user32.SetWindowTex>; /SetWindowTextA

00491F24  |>  5E            POP ESI

00491F25  |.  C9            LEAVE

00491F26  /.  C2 0800       RETN 8

       我们向上可以看到程序调用了GetWidnowTextA来取我们的假信息。堆栈窗口可以看到取了机器码:

0012DC50   0012DC5C  |String1 = "7a22983c58866dcd"

0012DC54   017A5528  /String2 = "7a22983c58866dcd"

       00491ED1处下断,这样方便我们以后重载程序直接飞到这来。

       向下F8走,就会来到0041C19D,可以知道我们跟出的这个CALL就是用来取用户输入信息的,并且下面还有两个相同CALL用来取信息,第一CALL取机器码,二CALL用户名,三CALL注册码。

0041C191   .  50            PUSH EAX                                 ; /Arg3

0041C192   .  68 04040000   PUSH 404                                 ; |Arg2 = 00000404

0041C197   .  57            PUSH EDI                                 ; |Arg1

0041C198   .  E8 E7860700   CALL unpack.00494884                     ; /unpack.00494884

0041C19D   .  8D8E 0C030000 LEA ECX,DWORD PTR DS:[ESI+30C]

0041C1A3   .  51            PUSH ECX                                 ; /Arg3

0041C1A4   .  68 06040000   PUSH 406                                 ; |Arg2 = 00000406

0041C1A9   .  57            PUSH EDI                                 ; |Arg1

0041C1AA   .  E8 D5860700   CALL unpack.00494884                     ; /unpack.00494884

0041C1AF   .  81C6 10030000 ADD ESI,310

0041C1B5   .  56            PUSH ESI                                 ; /Arg3

0041C1B6   .  68 05040000   PUSH 405                                 ; |Arg2 = 00000405

0041C1BB   .  57            PUSH EDI                                 ; |Arg1

0041C1BC   .  E8 C3860700   CALL unpack.00494884                     ; /unpack.00494884

       接着向下F8走,跟出0041C57A处可以看到有跳转,是比较注册码长度是否为32个字符长度,不够32个字符则跳走。因为们输入0123456789不够32个字符,F8跟到0041C586跳转处,直接双击寄存器中的ZF位,让其由01使其成功跳转。

0041C578   .  8BCE          MOV ECX,ESI

0041C57A   .  E8 CBB30600   CALL 11.0048794A                         ;  这里面进行了取注册码

0041C57F   .  8B45 00       MOV EAX,DWORD PTR SS:[EBP]

0041C582   .  8378 F8 20    CMP DWORD PTR DS:[EAX-8],20              ;  注册码必须为32字符

0041C586      0F84 95000000 JE 11.0041C621

       跳转来到0041C621,往下看可以看到很我跳转,并且下面出现了打开注册表等函数,所以我们可以怀疑此处就有可能会是真正注册码出现的地方。事实证明注册码就出现在0041C638处的CALL中,当然在0041C638中还有很多CALL要分析。先跟入这CALL

0041C621   > /8B15 84D44D00 MOV EDX,DWORD PTR DS:[4DD484]            ;  11.004DD498

0041C627   .  895424 0C     MOV DWORD PTR SS:[ESP+C],EDX

0041C62B   .  8BCE          MOV ECX,ESI

0041C62D   .  C78424 BC0200>MOV DWORD PTR SS:[ESP+2BC],5

0041C638   .  E8 FC4CFEFF   CALL 11.00401339                   ;  在这里面出现真正的注册码

0041C63D   .  85C0          TEST EAX,EAX

0041C63F      0F85 EF000000 JNZ 11.0041C734

 

看到的打开注册表等函数:此处我们可以看到程序把我们的注册码放到注册表的哪个位置了。

注册信息在注册表中位置:HKEY_LOCAL_MACHINE/SOFTWARE/HYDATA/Avi Recovery/20006

0041C73A   .  8D4C24 1C     LEA ECX,DWORD PTR SS:[ESP+1C]

0041C73E   .  68 90B44D00   PUSH 11.004DB490                         ;  ASCII "Software/Hydata/"

0041C743   .  51            PUSH ECX

0041C744   .  E8 C8CE0600   CALL 11.00489611

0041C749   .  8B00          MOV EAX,DWORD PTR DS:[EAX]

0041C74B   .  8D5424 14     LEA EDX,DWORD PTR SS:[ESP+14]

0041C74F   .  52            PUSH EDX                                 ; /pHandle

0041C750   .  50            PUSH EAX                                 ; |Subkey

0041C751   .  68 02000080   PUSH 80000002         ; |hKey = HKEY_LOCAL_MACHINE

0041C756   .  FF15 309D4E00 CALL DWORD PTR DS:[<&ADVAPI32.RegOpenKey>; /RegOpenKeyA

0041C75C   .  85C0          TEST EAX,EAX

 

       跟入0041C638CALL后可以在下面见到大量的CALL,先进入第一个0041CB80 CALL看看情况,情况不妙,又见好多CALL,这里暂且不分析了,第一个CALL实际是会根据两个常量字符串与机器码得到三个长度为32的字符串。

 

0041CB78   .  50            PUSH EAX

0041CB79   .  889C24 A00000>MOV BYTE PTR SS:[ESP+A0],BL

0041CB80   .  E8 D34BFEFF   CALL 11.00401758                       ;进入出现332位字符串

0041CB85   .  50            PUSH EAX          ; "c8a6ddea90ef46a3f1fab79ffd6f9eef"地址压入      

      

跟入0041CB79处的CALL后可见到下面常量串。

常量一:

gU3eITbF9PiJUIBPTryY2kB6XthrCXwEVJVKoxXlPHv6RzbKC55JHpfoFWz2wxyVJQ5VeQg3ebnj6suD7CcRrmU0Qolf95NeybAMN6EmvBVP9Eat8FxeHgOL7jyEYnYgge5HJor4vNZ0N78qlgZjWayqKqwcUhZfpvRNIIqnHORCs7vQwS1hUFfpsscX1gaujNLhpp4GzIKAtyCjexQ4N1EFZYxWelvj

常量二:

6VwzF4bO1Y6vkZhmmyHMHp1TQxqBvlMBtliKBvzTwVm4Hv9l6Oa1ulGzHmzuiOoSurjABk524a0HKAzGEDC9pkTaeS4sx1E4ehH1IUNUFCJ      

根据以上常量得到三个字符串:

"c8a6ddea90ef46a3f1fab79ffd6f9eef"  

"d8a6d8e2f0f346a3f0fab49df47a9ae3"        下面的很多CALL是对上面这两个字符串做文章的。

"de167882f4f31e3c108fb47d847a8a83"

 

       接着回到上面的0041CB85处,一直向下跟,CALL就不进去分析了。当来到0041CDB2处的CALL的时候堆栈里已经出现很多长度为32的字符串,这实际上是我们跳过的那些CALL的杰作。0041CDB2处的CALL有所不同,因为它的下面有一句跳转语句,所以此CALL我们跟入。

0041CDB0   .  8BCE          MOV ECX,ESI

0041CDB2   .  E8 1E45FEFF   CALL 11.004012D5                     ;  这里面出现真正的注册码

0041CDB7   .  85C0          TEST EAX,EAX

0041CDB9   .  0F85 3C0A0000 JNZ 11.0041D7FB

 

堆栈窗口中的数据:

0012DD48   017A5888  ASCII "m8j3k3j1h8o823i2j5ofg95ej17b9ff7"

0012DD4C   017A56F8  ASCII "e3h4l6e2k3n372j9l4fac89hg35j9je5"

0012DD50   017A56A8  ASCII "d1f7l8i9l2n332b1o3mic92fn57j9dg3"

0012DD54   017A54C8  ASCII "j4j5h9j1o9l827i2j1kab33mm43c8jf1"

0012DD58   017A5748  ASCII "l5b7m2g7h4i341e9n7njd79lk55g9ai1"

0012DD5C   017A5608  ASCII "d8a6d8e2f0f346a3f0fab49df47a9ae3"

0012DD60   017A5798  ASCII "g7j8e3m7o7j967b7m3fjd26eg62d4jg9"

0012DD64   017A5888  ASCII "m8j3k3j1h8o823i2j5ofg95ej17b9ff7"

0012DD68   017A5838  ASCII "f2j9i6m3l1k557g1m0mci29kk21i4ik6"

0012DD6C   017A57E8  ASCII "h9f2m4l6g2k375a4k5ohb49jl21e1bn2"

 

       跟入0041CDB2处的CALL后我们接着向下走来到CALL,在来到这个0041EB62处的CALL之前我们能看到前面的一些CALL又算出了一个新串m2ji8ch9lbm3aj8j237j3f59144j1ok,实际我们真正的注册码是这个字符串算出来的,而前的那些个串的作用为了算此串,算法繁杂 - -#

0041EB55   .  C68424 240200>MOV BYTE PTR SS:[ESP+224],2

0041EB5D   .  51            PUSH ECX                   ;  m2ji8ch9lbm3aj8j237j3f59144j1ok

0041EB5E   .  8D4C24 38     LEA ECX,DWORD PTR SS:[ESP+38]

0041EB62   .  E8 872CFEFF   CALL 11.004017EE                         ;  这里面出现真正注册码

0041EB67   .  8D4C24 34     LEA ECX,DWORD PTR SS:[ESP+34]

 

       接着跟入0041EB62处的CALL后可以看到非常短的代码,第一个CALL填充了MD5的四个常量(- - #竟然用MD5算法,而且竟然还是修改过的,郁闷)

0042F860   > /56            PUSH ESI                               

0042F861   .  8BF1          MOV ESI,ECX

0042F863   .  E8 6F18FDFF   CALL 11.004010D7                           ; 里面填充了MD5的四个常量

0042F868   .  84C0          TEST AL,AL

0042F86A   .  75 09         JNZ SHORT 11.0042F875

0042F86C   .  6A 01         PUSH 1

0042F86E   .  8BCE          MOV ECX,ESI

0042F870   .  E8 171DFDFF   CALL 11.0040158C

0042F875   >  8B4424 08     MOV EAX,DWORD PTR SS:[ESP+8]       

0042F879   .  8BCE          MOV ECX,ESI

0042F87B   .  50            PUSH EAX                                ;压入m2ji8ch9lbm3aj8j237j3f59144j1ok

0042F87C   .  E8 9817FDFF   CALL 11.00401019                         ;里面出现注册码

0042F881   .  5E            POP ESI

0042F882   .  C2 0400       RETN 4

      

填充完MD5常量后就压入我们前的字符串m2ji8ch9lbm3aj8j237j3f59144j1ok,可见真正算注册码的地方要出现了,直接进0042F87CCALL,再走不远就看到:

 

00430A14   .  C740 3C 00000>MOV DWORD PTR DS:[EAX+3C],0

00430A1B   .  E8 000EFDFF   CALL 11.00401820                   ;里面是修改过的MD5算法

00430A20   .  8BCB          MOV ECX,EBX

00430A22   .  E8 EF08FDFF   CALL 11.00401316                 ; 进了这里后出现真正的注册码

 

       上面00430A1B处的CALL里面是真正的MD5变异算法,会得到消息摘要,用于我们下面这个CALL计算注册码。所以我现在跟入0042F87C处的CALL即可,进入此CALL后代码也非常短。

 

我们的注册码前身也是由它算出来的,之所以说注册码前身是因为00430A1BCALL算出来的还不是真正的注册码,但已经很接近了。下面0042F87C处的CALL又把32位的注册码前身位置相互换了一下便得到真正注册码了。

 

00430B10   > /83EC 10       SUB ESP,10

00430B13   .  53            PUSH EBX

00430B14   .  55            PUSH EBP

00430B15   .  8D81 C2010000 LEA EAX,DWORD PTR DS:[ECX+1C2]

00430B1B   .  56            PUSH ESI

00430B1C   .  57            PUSH EDI

00430B1D   .  894424 10     MOV DWORD PTR SS:[ESP+10],EAX

00430B21   .  8D59 6C       LEA EBX,DWORD PTR DS:[ECX+6C]

00430B24   .  BD 04000000   MOV EBP,4

00430B29   >  8B0B          MOV ECX,DWORD PTR DS:[EBX]

00430B2B   .  8BC1          MOV EAX,ECX

00430B2D   .  8BD1          MOV EDX,ECX

00430B2F   .  25 0000FF00   AND EAX,0FF0000

00430B34   .  C1EA 10       SHR EDX,10

00430B37   .  0BC2          OR EAX,EDX

00430B39   .  8BD1          MOV EDX,ECX

00430B3B   .  C1E2 10       SHL EDX,10

00430B3E   .  81E1 00FF0000 AND ECX,0FF00

00430B44   .  0BD1          OR EDX,ECX

00430B46   .  C1E8 08       SHR EAX,8

00430B49   .  C1E2 08       SHL EDX,8

00430B4C   .  0BC2          OR EAX,EDX

00430B4E   .  8903          MOV DWORD PTR DS:[EBX],EAX

00430B50   .  50            PUSH EAX

00430B51   .  8D4424 18     LEA EAX,DWORD PTR SS:[ESP+18]           

00430B55   .  68 4CC24D00   PUSH 11.004DC24C                         ;  ASCII "%08x"

00430B5A   .  50            PUSH EAX

00430B5B   .  E8 D5570200   CALL 11.00456335                       这里算出一段8字符字串

00430B60   .  8D7C24 20     LEA EDI,DWORD PTR SS:[ESP+20]

00430B64   .  83C9 FF       OR ECX,FFFFFFFF

00430B67   .  33C0          XOR EAX,EAX

00430B69   .  83C4 0C       ADD ESP,0C

00430B6C   .  F2:AE         REPNE SCAS BYTE PTR ES:[EDI]

00430B6E   .  F7D1          NOT ECX

00430B70   .  2BF9          SUB EDI,ECX

00430B72   .  83C3 04       ADD EBX,4

00430B75   .  8BF7          MOV ESI,EDI

00430B77   .  8B7C24 10     MOV EDI,DWORD PTR SS:[ESP+10]

00430B7B   .  8BD1          MOV EDX,ECX

00430B7D   .  83C9 FF       OR ECX,FFFFFFFF

00430B80   .  F2:AE         REPNE SCAS BYTE PTR ES:[EDI]

00430B82   .  8BCA          MOV ECX,EDX

00430B84   .  4F            DEC EDI

00430B85   .  C1E9 02       SHR ECX,2

00430B88   .  F3:A5         REP MOVS DWORD PTR ES:[EDI],DWORD PTR DS>

00430B8A   .  8BCA          MOV ECX,EDX

00430B8C   .  83E1 03       AND ECX,3

00430B8F   .  4D            DEC EBP

00430B90   .  F3:A4         REP MOVS BYTE PTR ES:[EDI],BYTE PTR DS:[>

00430B92   .^ 75 95         JNZ SHORT 11.00430B29

00430B94   .  5F            POP EDI                                      ;  到这里的时候显示出注册码

00430B95   .  5E            POP ESI

00430B96   .  5D            POP EBP

00430B97   .  5B            POP EBX

00430B98   .  83C4 10       ADD ESP,10

00430B9B   .  C3            RETN

       上面这段代码是一个循环,共循环4次,每次得到一个8个字符串的数据,所以循环4次也就得到了长度为32的注册码。8个字符由00430B5B处的CALL来取得,而00430B5B处的CALL里面还有CALL,这里不分析下去了。当我们来到00430B94处的时候,即4次循环完成之后,在堆栈就可以看到我们的注册码了。

 

堆栈窗口中的数据:

0012DAD0   0012DB40

0012DAD4   0012DD02  ASCII "9de760e139360774875a24feb713591c"    ;注册码

0012DAD8   33313762

       经过我们的分析可以知道,我们输入的用户名什么作用都没起,不用用户名一样可以注册,信息保存在注册表中的HKEY_LOCAL_MACHINE/SOFTWARE/HYDATA/Avi Recovery/20006

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值