FileSee V6.3 通用文件浏览器(重起验证) 破解分析
【文章标题】: FileSee V6.3 通用文件浏览器 破解分析【文章作者】: roking
【软件名称】: FileSee V6.3
【下载地址】: http://www.filesee.com/download.html
【加壳方式】: UPX
【保护方式】: 注册码、30天试用
【编写语言】: BC
【使用工具】: OD、PEid、Import REC、DeDe
【软件介绍】: FileSee is a powerful All-In-One file viewer
【作者声明】: 仅供技术交流,请勿用于非法用途
--------------------------------------------------------------------------------
【详细过程】
一、脱壳修复IAT
PEid查壳为:UPX 0.89.6 - 1.02 / 1.05 - 1.24 -> Markus & Laszlo
ESP定律脱壳,使用Import REC修复时需要注意,如果采用自动寻找到的IAT进行修复则不成功,应该手动指定RAV及大小为.UPX1区段的偏移和大小进行搜索,经过漫长的等待后出现结果,删掉所有无效指针再修复即可成功。
脱壳修复后,PEiD再查,为BC++ 1999写的,这样可以用DeDe来快速定位事件入口
二、注册流程分析
OD载入脱壳后的软件,F9跑起来提示试用信息,按“Enter Register Number”按钮出现注册码输入框,为了便于分析注册流程,采用如下试练码:
1Abcd-2Efgh-3Ijkl-4Mnop-5Qrst(用数字、大小写组合便于理解程序中的某些call的功能)
按OK按钮前,使用DeDe找到按钮事件入口0041E750,再OD中下好断点(不使用DeDe的话,此软件也可以通过查找字符串参考定位关键提示来找到事件入口),按“OK”注册按钮断在入口:
0041E750/.PUSH EBP ;ok按钮事件入口
0041E751|.MOV EBP,ESP
0041E753|.ADD ESP,-10C
。。。。。。。。省略若干。。。
0041E77D|.INC DWORD PTR SS:
0041E780|.MOV EAX,DWORD PTR SS:
0041E786|.MOV EAX,DWORD PTR DS:
0041E78C|.CALL filesee.006504A4 ;读注册码第5部分,记为s5
0041E791|.LEA EDX,DWORD PTR SS:
0041E794|.XOR ECX,ECX
0041E796|.PUSH EDX
0041E797|.MOV DWORD PTR SS:,ECX
0041E79A|.INC DWORD PTR SS:
0041E79D|.LEA EDX,DWORD PTR SS:
0041E7A0|.MOV EAX,DWORD PTR SS:
0041E7A6|.MOV EAX,DWORD PTR DS:
0041E7AC|.CALL filesee.006504A4 ;读s4
0041E7B1|.LEA EDX,DWORD PTR SS:
0041E7B4|.XOR ECX,ECX
0041E7B6|.PUSH EDX
0041E7B7|.MOV DWORD PTR SS:,ECX
0041E7BA|.INC DWORD PTR SS:
0041E7BD|.LEA EDX,DWORD PTR SS:
0041E7C0|.MOV EAX,DWORD PTR SS:
0041E7C6|.MOV EAX,DWORD PTR DS:
0041E7CC|.CALL filesee.006504A4 ;读s3
0041E7D1|.LEA EDX,DWORD PTR SS:
0041E7D4|.XOR ECX,ECX
0041E7D6|.PUSH EDX
0041E7D7|.MOV DWORD PTR SS:,ECX
0041E7DA|.INC DWORD PTR SS:
0041E7DD|.LEA EDX,DWORD PTR SS:
0041E7E0|.MOV EAX,DWORD PTR SS:
0041E7E6|.MOV EAX,DWORD PTR DS:
0041E7EC|.CALL filesee.006504A4 ; 读s2
0041E7F1|.LEA EDX,DWORD PTR SS:
0041E7F4|.XOR ECX,ECX
0041E7F6|.PUSH EDX
0041E7F7|.MOV DWORD PTR SS:,ECX
0041E7FA|.INC DWORD PTR SS:
0041E7FD|.LEA EDX,DWORD PTR SS:
0041E800|.MOV EAX,DWORD PTR SS:
0041E806|.MOV EAX,DWORD PTR DS:
0041E80C|.CALL filesee.006504A4 ;读s1
0041E811|.LEA EAX,DWORD PTR SS:
0041E814|.XOR EDX,EDX
。。。。。。。。省略若干。。。
0041E858|.INC DWORD PTR SS:
0041E85B|.POP EDX
0041E85C|.CALL filesee.006A5900 ;注册码sn= "1Abcd2Efgh3Ijkl4Mnop5Qrst"
0041E861|.DEC DWORD PTR SS:
。。。。。。。。省略若干。。。
0041E8E1|. >MOV WORD PTR SS:,8
0041E8EA|.CMP DWORD PTR SS:,0 ;注册码是否为空
0041E8EE|.JE SHORT filesee.0041E8F8
0041E8F0|.MOV EAX,DWORD PTR SS:
0041E8F3|.MOV ECX,DWORD PTR DS:
0041E8F6|.JMP SHORT filesee.0041E8FA
0041E8F8|>XOR ECX,ECX
0041E8FA|>CMP ECX,19 ;注册码长度是否为0x19(25位)
0041E8FD|.JE SHORT filesee.0041E951
0041E8FF|. >MOV WORD PTR SS:,20
0041E908|.MOV EDX,filesee.00711FDD ;ASCII "Wrong serial number!"
0041E90D|.LEA EAX,DWORD PTR SS:
0041E910|.CALL filesee.006A5698
0041E915|.INC DWORD PTR SS:
0041E918|.MOV EAX,DWORD PTR DS:
0041E91A|.CALL filesee.0064A870
0041E91F|.DEC DWORD PTR SS:
0041E922|.LEA EAX,DWORD PTR SS:
0041E925|.MOV EDX,2
0041E92A|.CALL filesee.006A58A8
0041E92F|.DEC DWORD PTR SS:
0041E932|.LEA EAX,DWORD PTR SS:
0041E935|.MOV EDX,2
0041E93A|.CALL filesee.006A58A8
0041E93F|.MOV ECX,DWORD PTR SS:
0041E945|. >MOV DWORD PTR FS:,ECX
0041E94C|.JMP filesee.0041ED4A
0041E951|> >MOV WORD PTR SS:,2C
0041E95A|.XOR EAX,EAX
0041E95C|.LEA EDX,DWORD PTR SS:
0041E95F|.MOV DWORD PTR SS:,EAX
0041E962|.LEA EAX,DWORD PTR SS:
0041E965|.INC DWORD PTR SS:
0041E968|.CALL filesee.006A5B68 ;注册码sn转大写字母。记为SN,
SN="1ABCD2EFGH3IJKL4MNOP5QRST"
0041E96D|.LEA EDX,DWORD PTR SS:
0041E970|.LEA EAX,DWORD PTR SS:
0041E973|.CALL filesee.006A58D8
0041E978|.DEC DWORD PTR SS:
0041E97B|.LEA EAX,DWORD PTR SS:
0041E97E|.MOV EDX,2
0041E983|.CALL filesee.006A58A8
0041E988|.CMP DWORD PTR SS:,0 ;再次判断注册码是否为空
0041E98C|.JE SHORT filesee.0041E993
0041E98E|.MOV EBX,DWORD PTR SS:
0041E991|.JMP SHORT filesee.0041E998
0041E993|>MOV EBX,filesee.00711FF2
0041E998|> >MOV WORD PTR SS:,8
0041E9A1|. >MOV WORD PTR SS:,38
0041E9AA|.MOV EDX,filesee.00711FF3
0041E9AF|.LEA EAX,DWORD PTR SS:
0041E9B2|.CALL filesee.006A5698
0041E9B7|.INC DWORD PTR SS:
0041E9BA|. >MOV WORD PTR SS:,8
0041E9C3|.MOV EAX,EBX
0041E9C5|.XOR EDI,EDI
0041E9C7|.MOV EBX,EAX
0041E9C9|.LEA ESI,DWORD PTR SS:
0041E9CF|>/MOV DL,BYTE PTR DS: ;算法循环开始:依次取SN第n位字母,n=1、5、9、13、17、21
0041E9D1|.|XOR EAX,EAX
0041E9D3|.|MOV BYTE PTR DS:,DL
0041E9D5|.|MOV ECX,3
0041E9DA|. >|MOV WORD PTR SS:,44
0041E9E3|.|MOV AL,BYTE PTR DS:
0041E9E5|.|CDQ
0041E9E6|.|IDIV ECX ;每位字符ASCII码除以3,余数记为m
0041E9E8|.|LEA EAX,DWORD PTR SS:
0041E9EB|.|MOV DL,BYTE PTR DS: ;从注册码SN中摘取位置n+m+1处的1个字母作为本次循环的输出
0041E9EF|.|CALL filesee.006A5818
0041E9F4|.|INC DWORD PTR SS:
0041E9F7|.|LEA EDX,DWORD PTR SS:
0041E9FA|.|LEA EAX,DWORD PTR SS:
0041E9FD|.|CALL filesee.006A58EC
0041EA02|.|DEC DWORD PTR SS:
0041EA05|.|LEA EAX,DWORD PTR SS:
0041EA08|.|MOV EDX,2
0041EA0D|.|CALL filesee.006A58A8
0041EA12|.|INC EDI
0041EA13|.|INC ESI
0041EA14|.|ADD EBX,4
0041EA17|.|CMP EDI,6
0041EA1A|.^ \JL SHORT filesee.0041E9CF ;循环完毕后,输出为:“BFI4PS”,记为out
0041EA1C|. >MOV WORD PTR SS:,50
0041EA25|.XOR ECX,ECX
0041EA27|.MOV DWORD PTR SS:,ECX
0041EA2A|.LEA ECX,DWORD PTR SS:
0041EA2D|.INC DWORD PTR SS:
0041EA30|.LEA EDX,DWORD PTR SS:
0041EA33|.MOV EAX,filesee.00711FF4 ; "z"
0041EA38|.CALL filesee.006A5E74
0041EA3D|.LEA EAX,DWORD PTR SS:
0041EA40|.PUSH EAX
0041EA41|.MOV EDX,filesee.00711FF6 ;"rh"
0041EA46|.LEA EAX,DWORD PTR SS:
0041EA49|.CALL filesee.006A5698
0041EA4E|.INC DWORD PTR SS:
0041EA51|.XOR ECX,ECX
0041EA53|.MOV DWORD PTR SS:,ECX
0041EA56|.LEA ECX,DWORD PTR SS:
0041EA59|.INC DWORD PTR SS:
0041EA5C|.LEA EDX,DWORD PTR SS:
0041EA5F|.POP EAX
0041EA60|.CALL filesee.006A5900 ;out="z"+ out + "rh" = "zBFI4PSrh"
。。。。。。。。省略若干。。。
0041EAAB|.CMP DWORD PTR SS:,0 ;out是否为空
0041EAAF|.JE SHORT filesee.0041EAB6
0041EAB1|.MOV EAX,DWORD PTR SS:
0041EAB4|.JMP SHORT filesee.0041EABB
0041EAB6|>MOV EAX,filesee.00711FF9
0041EABB|>PUSH EAX ; |Arg2
0041EABC|.LEA EDX,DWORD PTR SS:; |
0041EAC2|.PUSH EDX ; |Arg1
0041EAC3|.CALL filesee.004796A8 ; \filesee.004796A8
0041EAC8|. >MOV WORD PTR SS:,5C ; out不为空来到这里
0041EAD1|.LEA ECX,DWORD PTR SS:
0041EAD7|.ADD ESP,14
0041EADA|.XOR EDX,EDX
0041EADC|.MOV EAX,8
0041EAE1|.PUSH DWORD PTR DS: ; /Arg2
0041EAE4|.PUSH DWORD PTR DS: ; |Arg1
0041EAE6|.MOV DWORD PTR SS:,EDX ; |
0041EAE9|.LEA EDX,DWORD PTR SS: ; |
0041EAEC|.INC DWORD PTR SS: ; |
0041EAEF|.CALL filesee.005EAFFC
; \MD5(out)="DA47D926AAB7DCFEEBB032C787CDA6D7"前16位2字母一组逆序变形得到"FEDCB7AA26D947DA",记为MD5_1
0041EAF4|.LEA EDX,DWORD PTR SS:
0041EAF7|.LEA EAX,DWORD PTR SS:
0041EAFA|.CALL filesee.006A56D0
0041EAFF|.INC DWORD PTR SS:
0041EB02|.DEC DWORD PTR SS:
0041EB05|.LEA EAX,DWORD PTR SS:
0041EB08|.MOV EDX,2
0041EB0D|.CALL filesee.006A58A8
0041EB12|. >MOV WORD PTR SS:,8
0041EB1B|. >MOV WORD PTR SS:,68
0041EB24|.MOV EDX,filesee.00711FFA ;字符串常数“8225EE7D473CCFD7”,记为MD5_2
0041EB29|.LEA EAX,DWORD PTR SS:
0041EB2C|.CALL filesee.006A5698
0041EB31|.INC DWORD PTR SS:
0041EB34|.LEA EDX,DWORD PTR SS:
0041EB37|.LEA EAX,DWORD PTR SS:
0041EB3A|.CALL filesee.006A598C ;比较MD5_1与MD5_2
0041EB3F|.PUSH EAX ; /Arg1
0041EB40|.DEC DWORD PTR SS: ; |
0041EB43|.LEA EAX,DWORD PTR SS: ; |
0041EB46|.MOV EDX,2 ; |
0041EB4B|.CALL filesee.006A58A8 ; \filesee.006A58A8
0041EB50|.POP ECX
0041EB51|.TEST CL,CL
0041EB53|.JE filesee.0041ECDD ;MD5_1不等于MD5_2则跳走完蛋,关键跳,NOP掉进行测试
。。。。。。。。省略若干。。。
0041EC37|.INC DWORD PTR SS:
0041EC3A|.MOV EDX,DWORD PTR DS:
0041EC3C|.MOV EAX,EBX
0041EC3E|.POP ECX
0041EC3F|.MOV ESI,DWORD PTR DS:
0041EC41|.CALL DWORD PTR DS: ;把SN写入ini\config.ini的IniParas节的sn键中保存
0041EC44|.DEC DWORD PTR SS:
0041EC47|.LEA EAX,DWORD PTR SS:
0041EC4A|.MOV EDX,2
0041EC4F|.CALL filesee.006A58A8
0041EC54|.DEC DWORD PTR SS:
0041EC57|.LEA EAX,DWORD PTR SS:
0041EC5A|.MOV EDX,2
0041EC5F|.CALL filesee.006A58A8
0041EC64|.MOV ESI,EBX
0041EC66|.MOV DWORD PTR SS:,ESI
0041EC69|.TEST ESI,ESI
0041EC6B|.JE SHORT filesee.0041EC91
0041EC6D|.MOV EAX,DWORD PTR DS:
0041EC6F|.MOV DWORD PTR SS:,EAX
0041EC72|. >MOV WORD PTR SS:,98
0041EC7B|.MOV EDX,3
0041EC80|.MOV EAX,DWORD PTR SS:
0041EC83|.MOV ECX,DWORD PTR DS:
0041EC85|.CALL DWORD PTR DS:
0041EC88|. >MOV WORD PTR SS:,8C
0041EC91|> >MOV WORD PTR SS:,0A4
0041EC9A|.MOV EDX,filesee.00712026 ;ASCII "Congratulations! Register Success!"
0041EC9F|.LEA EAX,DWORD PTR SS:
0041ECA2|.CALL filesee.006A5698
0041ECA7|.INC DWORD PTR SS:
0041ECAA|.MOV EAX,DWORD PTR DS:
0041ECAC|.CALL filesee.0064A870
0041ECB1|.DEC DWORD PTR SS:
注意上面的循环算法,取得注册码中有用的关键字母序列,md5后经过处理与字符串常量“8225EE7D473CCFD7”比较,相同则保存到ini文件,并有重起验证。
通过nop掉这一句:
0041EB53|.JE filesee.0041ECDD
就可以保存注册码并提示注册成功,我们接着来处理重起验证部分。前面我们知道了注册信息保存到ini文件,那么就可以通过bp GetPrivateProfileStringA下API断点来拦截重起验证时对ini\config.ini文件中保存的注册码的读取。
OD重新载入程序,命令行“bp GetPrivateProfileStringA”下断,F9跑起来,多次断在GetPrivateProfileStringA入口处,注意观察堆栈中ini文件的名字是否是我们的目标文件以及读取的键值是否为sn,拦到目标后,ALT+F9返回程序领空,再经过1个RET,来到这里:
00410C05|. POP ECX
00410C06|. MOV EDI,DWORD PTR DS:
00410C08|. CALL DWORD PTR DS: ;读取ini文件中保存的注册码SN
00410C0A|. DEC DWORD PTR DS: ;GetPrivateProfileStringA拦下后返回到这里
00410C0D|. LEA EAX,DWORD PTR SS:
。。。。。。。。省略若干。。。
00411180|> CMP DWORD PTR SS:,0 ;注册码是否为空
00411184|. JE SHORT filesee.0041118E ;爆破点!!!这是读取注册码后的第一个成功与否的分支跳转
00411186|. MOV EDX,DWORD PTR SS:
00411189|. MOV EAX,DWORD PTR DS:
0041118C|. JMP SHORT filesee.00411190
0041118E|> XOR EAX,EAX
00411190|> CMP EAX,19 ;注册码长度是否为0x19(25位)
00411193|. JE filesee.00411258
。。。。。。。。省略若若若干。。。
004112E0|> /MOV EAX,DWORD PTR SS:;算法循环开始:依次取SN第n位字母,n=1、5、9、13、17、21
;算法与前面填写注册码时相同
004112E6|. |MOV EDX,DWORD PTR SS:
004112EC|. |MOV CL,BYTE PTR DS:
004112EF|. |XOR EAX,EAX
004112F1|. |MOV BYTE PTR DS:,CL
004112F3|. |MOV ECX,3
004112F8|.>|MOV WORD PTR DS:,11C
004112FE|. |MOV AL,BYTE PTR DS:
00411300|. |CDQ
00411301|. |IDIV ECX
00411303|. |MOV EAX,DWORD PTR SS:
00411309|. |MOV ECX,DWORD PTR SS:
0041130F|. |LEA EAX,DWORD PTR DS:
00411312|. |MOV DL,BYTE PTR DS:
00411316|. |LEA EAX,DWORD PTR SS:
0041131C|. |CALL filesee.006A5818
00411321|. |INC DWORD PTR DS:
00411324|. |LEA EDX,DWORD PTR SS:
0041132A|. |LEA EAX,DWORD PTR SS:
00411330|. |CALL filesee.006A58EC
00411335|. |DEC DWORD PTR DS:
00411338|. |LEA EAX,DWORD PTR SS:
0041133E|. |MOV EDX,2
00411343|. |CALL filesee.006A58A8
00411348|. |INC DWORD PTR SS:
0041134E|. |INC EDI
0041134F|.>|CMP DWORD PTR SS:,6
00411356|. \JL SHORT filesee.004112E0 ;循环完毕后,输出为:“BFI4PS”,记为out
*******************这里循环完后,根据试练码同输入注册码时的算法循环一样返回out=BFI4PS,但下面与输入注册码运算不同的是,out没有与"z"和"rh"做连接运算
。。。。。。。。省略若干。。。
004113B0|. CALL filesee.005EAFFC ; \MD5(out)="03EA4C11F75016D8421466CD2A94246E"前16位2字母一组逆序变形得到 "D81650F7114CEA03",记为restartMD5_1
。。。。。。。。省略若干。。。
004113E8|. MOV EDX,filesee.00707F2A ;取字符串常数 "B75FE3582D996545",记为restartMD5_2
004113ED|. LEA EAX,DWORD PTR SS:
004113F3|. CALL filesee.006A5698
004113F8|. INC DWORD PTR DS:
004113FB|. LEA EDX,DWORD PTR SS:
00411401|. LEA EAX,DWORD PTR SS:
00411407|. CALL filesee.006A598C ;比较restartMD5_1与restartMD5_2
0041140C|. PUSH EAX
0041140D|. DEC DWORD PTR DS:
00411410|. LEA EAX,DWORD PTR SS:
00411416|. MOV EDX,2
0041141B|. CALL filesee.006A58A8
00411420|. POP ECX
00411421|. TEST CL,CL
00411423|. JE SHORT filesee.00411458 ;关键跳!restartMD5_1不等于restartMD5_2则跳走完蛋
00411425|.>MOV BYTE PTR DS:,1 ;这里就是真正的重起验证的成功点入口
。。。。。。。。。。。。。。。。。。。。
通过上面的分析,我们如果要爆破的话,可以仅选择:
00411184|. JE SHORT filesee.0041118E ;爆破点!!!
为啥呢?因为这是读取注册码后的第一个成功与否的分支跳转,那如何改呢,我这里直接让他跳到这里:
00411425|.>MOV BYTE PTR DS:,1 ;这里就是真正的重起验证的成功点入口
亦即把00411184一处改为:jmp filesee.00411425即可完成爆破!保存修改验证,一切OK!!
三、做算法注册机的可行性分析
经前面分析,关键的算法核心在于逆向出两个变形MD5生成的字符串常量MD5_2及restartMD5_2对应的明文,知道了明文,就可以根据前面代码里的算法循环构造我们的注册码了。而MD5本身不可逆,用算法直接逆推明文不可行,因为从代码分析已经知道变形方式,我们只能构造一个相同的变形算法进行穷举。
由于在输入注册码时的算法循环(0041E9CF--0041EA1A处)的输出out(6位)与"z"及"rh"连接后是9位,也就是说字符串常量MD5_2对应的明文为9位字母,而重启验证时的算法循环(004112E0--00411356处)输出6位字母的out后,直接进行变形MD5运算后与restartMD_2比较,表明restartMD_2对应的明文是6位,则效率高的穷举是根据6位的所有字母数字组合来穷举匹配restartMD_2,要循环:
(10个数字字符 + 26个大写字母) ^ 6 = 21亿次(变形MD5调用+判断匹配)
要是为了穷举9位明文的MD5_2的话,则需要:
(10个数字字符 + 26个大写字母) ^ 9 = 100万亿次(变形MD5调用+判断匹配) ,天文数字啊!!
为啥只算大写字母?因为据上面分析进入算法前经过了大写转换的,呵呵!6个明文字母的穷举得时间复杂度上考虑还是可行的。有时间的话试看。
--------------------------------------------------------------------------------
【版权声明】: 本文原创于ChinaPYG技术论坛, 转载请注明作者并保持文章的完整, 谢谢!
2008年03月02日 5:42:56
[ 本帖最后由 roking 于 2008-3-17 18:10 编辑 ] 学习一下 谢谢了 高手啊,进步不小啊!! 不错啊,学习了。 好啊,顶/:010 学习一下 谢谢了 挺长,呵呵。不过很详细,留待品味 很详细啊。。。/:013 新手最爱 OK,学了作者的这遍文章基本上总结出自己的思路来了。 学习一下 谢谢
页:
[1]
2