IrfanView算法浅析
【软件简介】:IrfanView是非常优秀的看图工具,支持几十种格式(需插件)。它还能对不同文件格式进行转换,批量重命名等。甚至还支持mpg、mp3、mid等多媒体格式的播放。丝毫不逊色于ACDSEE。
【声 明】:刚学汇编不久,下面分析中难免有错误之处,敬请诸位大侠赐教!
【程 序 名】:i_view32.ExE
【版 本】:3.85
【大 小】:492KB
【语 言】:Visual C++
【运行平台】:W9x/NT/W2K/WXP
【保护方式】:telock0.98加壳+注册码
【分析方式】:追注册码+注册机
【难 度】:容易(明码比较)
【工 具】:PE-SCAN v3.31/WKTtElockDumper v1.2/W32dasm8.93+/TRW2000 v1.23
【程序下载】:http://www.irfanview.com
【作 者】:xbb_NCG
【分 析】:
1、获取信息:安装后运行程序,我们可以在程序的帮助里看到注册选项,单击后知道仅需要用户名和注册码两条信息。
2、脱壳:用PE-SCAN v3.31检测出该程序用telock0.98加壳。OK,我们用WKTtElockDumper v1.2(风飘雪的网站上有下载)脱掉它。
3、静态分析:用W32Dasm8.93+反汇编脱壳后的程序。查看字符串,找不到有用的。
4、动态跟踪:运行TRW2000 v1.23,选择脱壳后的程序,点击Load。按G,让程序先运行。然后我们点 帮助>注册 ,在弹出的注册框中填入用户名和注册码。我填的是xbb_NCG和123456789,先不在按确定。按CTRL+N呼出TRW,键入bpx hmemcpy,回车,键入G,回到程序,现在我们按确定,程序会被TRW中断,输入pmodule回到程序的领空,按2次f12,再输入pmodule我们会在下面的代码入停住。
* Reference To: USER32.DialogBoxParamA, Ord:0093h
|
:00455115 FF15F4844C00 Call dword ptr [004C84F4]
:0045511B 85C0 test eax, eax <-我们停在这里,检测用户名和注册码是否为空。
:0045511D 0F84AD000000 je 004551D0 <-为零则跳
:00455123 8DBC245C050000 lea edi, dword ptr [esp+0000055C] <-将用户名读入EDI
:0045512A 83C9FF or ecx, FFFFFFFF
:0045512D 33C0 xor eax, eax <-EAX清零
:0045512F F2 repnz
:00455130 AE scasb <-扫描用户名位数
:00455131 F7D1 not ecx <-ECX取反
:00455133 49 dec ecx <-ECX减1
:00455134 83F902 cmp ecx, 00000002 <-ECX的值和2比较
:00455137 0F825C010000 jb 00455299 <-用户名小于2位则跳
:0045513D 8DBC245C050000 lea edi, dword ptr [esp+0000055C]
:00455144 83C9FF or ecx, FFFFFFFF
:00455147 F2 repnz
:00455148 AE scasb
:00455149 F7D1 not ecx
:0045514B 49 dec ecx
:0045514C 83F955 cmp ecx, 00000055 <-ECX的值和55比较
:0045514F 0F8744010000 ja 00455299 <-用户名大于55位则跳
:00455155 8DBC245C060000 lea edi, dword ptr [esp+0000065C]
:0045515C 83C9FF or ecx, FFFFFFFF
:0045515F 33D2 xor edx, edx <-EDX置0
:00455161 F2 repnz
:00455162 AE scasb
:00455163 F7D1 not ecx
:00455165 49 dec ecx
:00455166 85C9 test ecx, ecx <-检测ECX是否为0.
:00455168 7E75 jle 004551DF <-不小于0则跳到计算注册码Call
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00455192(C)
|
:0045516A 8A84145C060000 mov al, byte ptr [esp+edx+0000065C]----- <-取注册码的第一位
:00455171 3C30 cmp al, 30 <-是否小于0
:00455173 7C04 jl 00455179
:00455175 3C39 cmp al, 39 <-是否大于9
:00455177 7E05 jle 0045517E
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00455173(C) |
| |
|
* Possible Ref to Menu: IRFANVIEW, Item: "黣r(M)" |
| |
:00455179 BB01000000 mov ebx, 00000001 <-EBX置1 |--这一段是将我们输入的
|假注册码转换为16进制
* Referenced by a (U)nconditional or (C)onditional Jump at Address: |
|:00455177(C) |
| |
:0045517E 8DBC245C060000 lea edi, dword ptr [esp+0000065C] |
:00455185 83C9FF or ecx, FFFFFFFF |
:00455188 33C0 xor eax, eax /
:0045518A 42 inc edx <-循环记数器,EDX加1 /
:0045518B F2 repnz /
:0045518C AE scasb /
:0045518D F7D1 not ecx /
:0045518F 49 dec ecx <-假注册码位数,ECX减1 /
:00455190 3BD1 cmp edx, ecx <-比较EDX和ECX的值 /
:00455192 7CD6 jl 0045516A __________________________/ <-循环记数小于注册码位数则跳
:00455194 85DB test ebx, ebx <-EBX是否为0?
:00455196 7447 je 004551DF <-为0就跳到注册码计算处。
:00455198 8B0D4C394F00 mov ecx, dword ptr [004F394C]
:0045519E 6804010000 push 00000104
:004551A3 6860C84F00 push 004FC860
....................
***********************************
我们由上面代码中的455192处跳来此处:
* Referenced by a (U)nconditional or (C)onditional Jump at Addresses:
|:00455168(C), :00455196(C)
|
:004551DF 8D84245C060000 lea eax, dword ptr [esp+0000065C] <-用户名入EAX
:004551E6 8D8C245C050000 lea ecx, dword ptr [esp+0000055C] <-注册码入ECX
:004551ED 50 push eax <-EAX入堆栈
:004551EE 51 push ecx <-ECX入堆栈
:004551EF E8CC16FEFF call 004368C0 <-关键Call,计算注册码处,后面分析。
:004551F4 83C408 add esp, 00000008 <-在这里D EAX可以见到真的注册码
:004551F7 85C0 test eax, eax
:004551F9 7533 jne 0045522E <-不=0则跳,到注册成功处。
:004551FB 8B154C394F00 mov edx, dword ptr [004F394C]
:00455201 6804010000 push 00000104
:00455206 6860C84F00 push 004FC860
....................
:00455211 FF15A0834C00 Call dword ptr [004C83A0]
:00455217 A188CB4F00 mov eax, dword ptr [004FCB88]
:0045521C 6830200000 push 00002030
:00455221 6800DF4F00 push 004FDF00
:00455226 6860C84F00 push 004FC860
:0045522B 50 push eax
:0045522C EB9C jmp 004551CA <-这里跳到出错提示
***********************************
4551EF处关键Call,我们进入。
* Referenced by a CALL at Addresses:
|:00436D8E , :004550A4 , :004551EF
|
:004368C0 8B442408 mov eax, dword ptr [esp+08]
:004368C4 83EC14 sub esp, 00000014
:004368C7 53 push ebx---
:004368C8 55 push ebp
:004368C9 56 push esi |--各寄存入栈
:004368CA 57 push edi /
:004368CB 50 push eax___/
:004368CC 33DB xor ebx, ebx <-EBX清零
:004368CE E82AFF0700 call 004B67FD <-此Call将我们输入的注册码即123456789转为16进制为75BCD15
EDX=4ED99A 这个数在后的要用到。
:004368D3 8B74242C mov esi, dword ptr [esp+2C]
:004368D7 8BE8 mov ebp, eax
:004368D9 8BFE mov edi, esi
:004368DB 83C9FF or ecx, FFFFFFFF
:004368DE 33C0 xor eax, eax
:004368E0 83C404 add esp, 00000004
:004368E3 33D2 xor edx, edx
:004368E5 F2 repnz
:004368E6 AE scasb
:004368E7 F7D1 not ecx
:004368E9 49 dec ecx
:004368EA 85C9 test ecx, ecx
:004368EC 7E17 jle 00436905
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00436903(C)
|
:004368EE 0FBE0C32 movsx ecx, byte ptr [edx+esi]-
:004368F2 03D9 add ebx, ecx
:004368F4 8BFE mov edi, esi
:004368F6 83C9FF or ecx, FFFFFFFF
:004368F9 33C0 xor eax, eax |将用户名的ASCII码逐位相加,和放入EBX
:004368FB 42 inc edx |
:004368FC F2 repnz /
:004368FD AE scasb /
:004368FE F7D1 not ecx /
:00436900 49 dec ecx /
:00436901 3BD1 cmp edx, ecx /<-比较EDX和ECX的值
:00436903 7CE9 jl 004368EE _______________/ <-小于则跳
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:004368EC(C)
|
:00436905 B804010000 mov eax, 00000104 <-104放入EAX
* Possible Reference to Dialog: DialogID_0402, CONTROL_ID:000A, ""
|
:0043690A 6A0A push 0000000A <-A入栈
:0043690C 2BC3 sub eax, ebx
:0043690E 99 cdq <-扩展EAX
:0043690F 33C2 xor eax, edx
:00436911 2BC2 sub eax, edx
:00436913 054C010000 add eax, 0000014C
:00436918 8D14C500000000 lea edx, dword ptr [8*eax+00000000]
:0043691F 2BD0 sub edx, eax
:00436921 8D0C90 lea ecx, dword ptr [eax+4*edx]
:00436924 8D542414 lea edx, dword ptr [esp+14]
:00436928 52 push edx
:00436929 8D3448 lea esi, dword ptr [eax+2*ecx] <-ESI=A119
:0043692C C1E603 shl esi, 03 <-A119做逻辑左移
:0043692F 56 push esi
:00436930 E851B00800 call 004C1986 <-令ESP+10=关键数,此关
键数根据用户名的不同而不同。
:00436935 83C40C add esp, 0000000C
:00436938 81FE3F420F00 cmp esi, 000F423F <-ESI与999999比较
:0043693E 0F87EF000000 ja 00436A33 <-大于则跳走
:00436944 8A4C2414 mov cl, byte ptr [esp+14] <-cl=2----------------ESP+10是注册码第1位
:00436948 8A442415 mov al, byte ptr [esp+15] <-al=8----------------- 这几行是对上面
:0043694C 8A542413 mov dl, byte ptr [esp+13] <-dl=9------------------关键数进行移位计
:00436950 884C2416 mov byte ptr [esp+16], cl <-注册码第七位为ESP+16=2-算的,六位数移
:00436954 8A4C2411 mov cl, byte ptr [esp+11] <-cl=2--------------------位后成为九位数
:00436958 88442418 mov byte ptr [esp+18], al <-注册码第九位为ESP+18=8--- 即注册码的位
:0043695C 8A442412 mov al, byte ptr [esp+12] <-al=9----------------------|数。但这不是
:00436960 88542415 mov byte ptr [esp+15], dl <-注册码第六位为ESP+15=9----|真的注册码,
:00436964 884C2412 mov byte ptr [esp+12], cl <-注册码第三位为ESP+12=2----|真注册码的第
:00436968 8B4C2414 mov ecx, dword ptr [esp+14] <-取注册码的第五位 /二、五、八位
:0043696C 81E1FF000000 and ecx, 000000FF <-ECX=32 /要通过这个九位
:00436972 88442413 mov byte ptr [esp+13], al <-注册码第四位为ESP+13=9-/数来计算得出。
:00436976 8BC1 mov eax, ecx
:00436978 C1E005 shl eax, 05
:0043697B 2BC1 sub eax, ecx
:0043697D 8B4C2418 mov ecx, dword ptr [esp+18] <-取注册码第9位数
:00436981 81E1FF000000 and ecx, 000000FF
:00436987 8D1440 lea edx, dword ptr [eax+2*eax]
:0043698A 8D0489 lea eax, dword ptr [ecx+4*ecx]
:0043698D C1E003 shl eax, 03
:00436990 2BC1 sub eax, ecx
:00436992 2BC2 sub eax, edx
:00436994 99 cdq
:00436995 8BC8 mov ecx, eax
:00436997 33CA xor ecx, edx
:00436999 2BCA sub ecx, edx
:0043699B 8D0489 lea eax, dword ptr [ecx+4*ecx]
:0043699E C1E003 shl eax, 03 <-EAX的值左移3次
:004369A1 2BC1 sub eax, ecx
* Possible Ref to Menu: IRFANVIEW, Item: "?u JPM(J)"
|
* Possible Reference to Dialog: DialogID_0402, CONTROL_ID:0009, ""
|
:004369A3 B909000000 mov ecx, 00000009 <-ECX置9
:004369A8 99 cdq
:004369A9 F7F9 idiv ecx <-EAX/9 商为29BE,余数为0
:004369AB 8B442413 mov eax, dword ptr [esp+13] <-取注册码的第四位
:004369AF 25FF000000 and eax, 000000FF <-EAX=39
:004369B4 80C230 add dl, 30
:004369B7 88542417 mov byte ptr [esp+17], dl <-注册码第8位为ESP+17=0
:004369BB 8D1440 lea edx, dword ptr [eax+2*eax]
:004369BE C1E204 shl edx, 04
:004369C1 2BD0 sub edx, eax
:004369C3 8B442415 mov eax, dword ptr [esp+15] <-取注册码的第六位
:004369C7 25FF000000 and eax, 000000FF
:004369CC 8D0CC0 lea ecx, dword ptr [eax+8*eax]
:004369CF 8D0488 lea eax, dword ptr [eax+4*ecx]
:004369D2 8D0442 lea eax, dword ptr [edx+2*eax]
:004369D5 99 cdq
:004369D6 33C2 xor eax, edx
:004369D8 2BC2 sub eax, edx
:004369DA 8D0CC0 lea ecx, dword ptr [eax+8*eax]
:004369DD 8D0488 lea eax, dword ptr [eax+4*ecx]
* Possible Ref to Menu: IRFANVIEW, Item: "?u JPM(J)"
|
* Possible Reference to Dialog: DialogID_0402, CONTROL_ID:0009, ""
|
:004369E0 B909000000 mov ecx, 00000009
:004369E5 D1E0 shl eax, 1
:004369E7 99 cdq
:004369E8 F7F9 idiv ecx <-EAX/9 商为DD84 余数6
:004369EA 8B4C2410 mov ecx, dword ptr [esp+10] <-取注册码的第一位
:004369EE 81E1FF000000 and ecx, 000000FF
:004369F4 8D0449 lea eax, dword ptr [ecx+2*ecx]
:004369F7 8D04C0 lea eax, dword ptr [eax+8*eax]
:004369FA D1E0 shl eax, 1
:004369FC 2BC1 sub eax, ecx
:004369FE 80C230 add dl, 30
:00436A01 88542414 mov byte ptr [esp+14], dl <-注册码第五位为ESP+14=6
:00436A05 8B4C2411 mov ecx, dword ptr [esp+11] <-取注册码的第二位
:00436A09 81E1FF000000 and ecx, 000000FF
:00436A0F 8D14CD00000000 lea edx, dword ptr [8*ecx+00000000]
:00436A16 2BD1 sub edx, ecx
:00436A18 8D1492 lea edx, dword ptr [edx+4*edx]
:00436A1B 2BC2 sub eax, edx
:00436A1D 99 cdq
:00436A1E 8BC8 mov ecx, eax
:00436A20 33CA xor ecx, edx
:00436A22 2BCA sub ecx, edx
:00436A24 8D0449 lea eax, dword ptr [ecx+2*ecx]
:00436A27 8D04C0 lea eax, dword ptr [eax+8*eax]
:00436A2A D1E0 shl eax, 1
:00436A2C 2BC1 sub eax, ecx
:00436A2E E9F5000000 jmp 00436B28
..................中间省略
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00436A2E(U)
|
:00436B28 99 cdq
* Possible Ref to Menu: IRFANVIEW, Item: "?u JPM(J)"
|
* Possible Reference to Dialog: DialogID_0402, CONTROL_ID:0009, ""
|
:00436B29 B909000000 mov ecx, 00000009
:00436B2E C644241900 mov [esp+19], 00
:00436B33 F7F9 idiv ecx <-商为15EC,余数为EDX=1
:00436B35 80C230 add dl, 30 <-dl=dl+30=31
:00436B38 88542411 mov byte ptr [esp+11], dl <-注册码第2位为1
:00436B3C 8D542410 lea edx, dword ptr [esp+10] <-真注册码入EDX
:00436B40 52 push edx <-EDX入栈
:00436B41 E8B7FC0700 call 004B67FD <-将真注册码转换为16进制,EBP为假注册码
:00436B46 83C404 add esp, 00000004
:00436B49 33C9 xor ecx, ecx <-ECX清零
:00436B4B 3BE8 cmp ebp, eax <-真假注册码比较
:00436B4D 5F pop edi
:00436B4E 5E pop esi
:00436B4F 0F94C1 sete cl <-设置cl
:00436B52 5D pop ebp
:00436B53 8BC1 mov eax, ecx <-EAX清零
:00436B55 5B pop ebx
:00436B56 83C414 add esp, 00000014
:00436B59 C3 ret <-返回EAX值
***********************************
程序的注册信息保存在程序的安装目录里的i_view32.ini文件中。
取消注册只要把此文件中的[Registration]段下的name和code两行删除即可。
***********************************
注册算法总结:软件根据用户名算出一个六位关键数,再将其进行移位,形成一个九位数。然后用用这个九位数算出注册码。最后将真注册码转换为16进制数与假注册码的16进制数进行比较。
关键数与九位数关系如下:
关键数的第六位---------九位数的第九位
关键数的第五位---------九位数的第五、七位
关键数的第四位---------九位数的第六位
关键数的第三位---------九位数的第四位
关键数的第二位---------九位数的第二、三位
关键数的第一位---------九位数的第一位
九位数的第八位为空
九位数中除第二、五、八位需要由其它数计算得出外,第一、三、四、六、七、九位就是真注册码的相应位。
注册码的第二位由九位数中的第一、二位计算得出;
注册码的第五位由九位数中的第四、六位计算得出;
注册码的第八位由九位数中的第五、九位计算得出。
***********************************
..............................................
. __ ___ ____ __ .
. / | | | | | | | | | | .
. / | | | | | | | __ | .
. / |~~| |~~| | | | | | | | .
. / |__| |__| |__ | | |___| |____| __| .
..............................................
2003.11.28 傍晚