【文章标题】: a4desk 标准版+模板破解
【文章作者】: 啊cr/FTSTT
【软件名称】: a4desk 标准版
【软件大小】: 9.99 MB (10,481,049 字节)
【下载地址】: 自己搜索下载
【加壳方式】: 无
【保护方式】: Demo
【编写语言】: Borland Delphi v6.0 - v7.0
【使用工具】: Sothink SWF Quicker+Flash Decompiler Trillix+C32asm
【操作平台】: WinAll
【软件介绍】: A4Desk是一个基于模板的所见即所得的FLASH菜单和FLASH网站创作工具,无需编码即可制作出吸引人的FLASH。
【作者声明】: 只是感兴趣,没有其他目的。失误之处敬请诸位大侠赐教!
--------------------------------------------------------------------------------
【详细过程】
软件部分:
A4Desk和A4DeskPro不同,因为后者网站提供的是可以注册的版本,而A4Desk提供的是Demo版。
Demo版本,爆破。
很简单,找一个demo提示就可以定位,修改如下(6.23 build:2009年3月25日, 17:28:02):
004C63AD C605 C9155700>MOV BYTE PTR DS:[5715C9],0
004C63AD C605 C9155702>MOV BYTE PTR DS:[5715C9],2
 
模板部分:
模板是swf 格式的,demo版提供的是不可注册的模板,所以要爆破^_^。
Swf可以采取直接修改的方法去除demo提示,但是重新编译有可能带来字体或者其他特性的变化,影响使用效果而且也不能批量操作,所以采取二进制修改的方式进行爆破。
 
和PE文件的搜索替换补丁类似,过程分为2部分:
一,寻找爆破点
二,找到可用特征码,并对多个文件(版本)进行测试
 
基础知识(仅供参考):  
字串在常量池(constant Pool):
constantPool 0:"i" 1:"temptemp" 2:"bu" 3:"" 4:"btn" 5:"_visible"
88 1E 00 06 00 69 00 74 65 6D 70 74 65 6D 70 00 62 75 00 00 62 74 6E 00 5F 76 69 73 69 62 6C 65 00
88 常量池标记
1E 00 长度(此例子06 00 69 …… 6C 65 00)
06 00 变量数
69 00………………………………………………0:"i
74 65 6D 70 74 65 6D 70 00………………………1:"temptemp"
62 75 00……………………………………………2:"bu"
00 …………………………………………………3:""
62 74 6E 00 ………………………………………4:"btn"
5F 76 69 73 69 62 6C 65 00 ………………………5:"_visible"
注:标号从0开始
 
跳转:
99 02 00 06 00 JMP
99是jmp ,02是 参数长度(06 00),06 00 是距离
9d 02 00 06 00 JE(if true goto)
9d是je ,02是 参数长度(06 00),06 00 是距离
注:距离是目标指令与跳转指令的下一条指令的地址之差(两条指令之间的字节数)
 
三种push
1,push 值
push 1
96 05 00 07 01 00 00 00
96 是 push,05是 参数长度(07 01 00 00 00),07 是压入值的标记,01 00 00 00 是压入的值
 
2,push 字串
push "_root"
96 07 00 00 5F 72 6F 6F 74 00
96 是 push,07是 参数长度(00 5F 72 6F 6F 74 00),5F 72 6F 6F 74 00 是压入的字串"_root"
 
3,push 字串常量
push "bu"(2) 注:使用前面的常量池
96 02 00 08 02
96 是 push,02是 参数长度(08 02),08 是压入常量的标记, 02 是压入的常量的标号
够用了。
 
第一步 寻找爆破点
 
首先需要知道模板的限制是怎样的,随手创建一个工程输入一下,可以看到限制有两处,一处是界面上有demo的标记,另一处是点击按钮有的会弹出注册提示。
使用编辑工具工具进行辅助分析,我选择的工具是Sothink SWF Quicker。
使用Sothink SWF Quicker导入\templates\swf site下的任意模板,我导入的是\templates\swf site\a4biz001\a4desk.swf一路确认。
Sothink SWF Quicker 界面的左下有影片【浏览器的面板】(如果没有请在窗口菜单中选中“浏览器的面板”)。回想一下,demo版有demo的提示不妨搜索一下“demo”字串。
在【浏览器的面板】搜索“demo”字串,在第一处看到如下代码: 
[元件192]
[帧100]
stop ();
if (eval("/:passcode") ne "")
{
_parent.gotoAndStop("unkey");
}
else
{
_parent.gotoAndStop("demo");
} // end else if
如果有passcode 则显示unkey ,没有则显示demo ,果真是demo版,任何 passcode都是不能注册成功的(passcode就是软件中输入的模板注册码)。
 
继续搜索, 
 
[元件193]
[帧1]demo = "BIZ001";
向后查看,下一帧的动作:
[帧2]if (_root.passcode ne "")
{
gotoAndStop(3); 注:[帧3]Unauthorized Key
}
else
{
gotoAndStop(4); 注:[帧4]Created By A4Desk
} // end else if
找到了,这是第一处限制!
修改[帧1]的代码为stop (); ,预览一下,第一处的demo不见了。
 
寻找第二处限制的位置。
既然是点击才出现的提示不妨搜索字串“click”。
第一处没发现特别的。
第二处: 
 
[元件104]
[btn8]
on (release)
{
_root.text.gotoAndPlay("page8");
if (eval("/:reg") != 1)
{
clickcount = clickcount + 1;
chkclick(clickcount);
bar.play();
} // end if
}
看到 /:reg 眼前一亮啊,改为搜索 “reg”,找到若干处 btn的动作,代码类似。将与/:reg相关的if语句删除,预览,点击按钮数次没有注册提示了,OK。此时保存这个模板就可以用了。
 
 
 
第二步 寻找特征码
上百的模板逐个手工修改既麻烦也可能带来未知的问题,所以要批量,批量就要找共同点特征码。
找把刀子出来Flash Decompiler Trillix。
使用Flash Decompiler Trillix 打开刚才的\templates\swf site\a4biz001\a4desk.swf,打开右侧的“Scripts”节点,找到刚才记录的两个位置。
第一处[元件193]对应的名字是“Sprite 193”
双击“Sprite 193”并切换到Pi-Codes and hex视图 
 
//Sprite 193
// Frame 0
// Action tag #0
 
push "demo" "BIZ001"
96 0E 00 00 64 65 6D 6F 00 00 42 49 5A 30 30 31 00
setVariable 
1D
……
需要修改的是这里:
 
push "demo" "BIZ001"
96 0E 00 00 64 65 6D 6F 00 00 42 49 5A 30 30 31 00
setVariable 
1D
打开\templates\swf site\a4biz002\a4desk.swf找到这段代码  
push "demo" "BIZ002"
96 0E 00 00 64 65 6D 6F 00 00 42 49 5A 30 30 32 00
setVariable 
1D
打开\templates\swf site\a4biz003\a4desk.swf找到这段代码  
push "demo" "BIZ003"
96 0E 00 00 64 65 6D 6F 00 00 42 49 5A 30 30 33 00
setVariable 
1D
打开\templates\swf site\a4dp120\a4desk.swf找到这段代码  
push "demo" 120
96 0B 00 00 64 65 6D 6F 00 07 78 00 00 00
setVariable 
1D
比较一下,寻找特征。  
64 65 6D 6F = demo 42 49 5A 30 30 33 = 模板名/序号 
模板名/序号是不同的所以后面这部分不能用。 
尝试取特征码  
96 0? 00 00 64 65 6D 6F 00 …… 1D
用任意十六进制编辑器打开刚才的模板(注:此swf未压缩),十六进制搜索 96 0E 00 00 64 65 6D 6F 00只找到一处,换一个模板,还是只有一处。好,暂时确定此特征码为有效特征码。
找到了搜索码,替换成什么呢?回忆一下 刚才将指令修改为stop ();成功解决了第一处限制,那么将这些代码替换成stop (); 对应的hex代码就可以了。正好第一次搜索“demo”的时候[元件192][帧100]处正好有一个stop ();指令,查看一下[元件192][帧100]对应的名称“Sprite 192”切换到Pi-Codes and hex视图:([元件193]Frame 2中也有这个命令。)  
……
stop 
07
……
stop (); = 07h
将找到的 96 0? 00 00 64 65 6D 6F 00 …… 1D 使用 07h 填充,保存,打开测试一下,第一处demo消失了,成功。
 
 
第二处 [元件104][btn8]对应的名字是“Button 104”  
//Button 104
// On release
 
on (release)
{
_root.text.gotoAndPlay("page8");
if (eval("/:reg") != 1) 
{
clickcount = clickcount + 1;
chkclick(clickcount);
bar.play();
}
}
Pi-Codes and hex:  
//Button 104
// On release
 
constantPool 0:"page8" 1:"_root" 2:"text" 3:"gotoAndPlay" 4:"/:reg" 5:"clickcount" 6:"chkclick" 7:"bar" 8:"play"
88 42 00 09 00 70 61 67 65 38 00 5F 72 6F 6F 74 00 74 65 78 74 00 67 6F 74 6F 41 6E 64 50 6C 61 79 00 2F 3A 72 65 67 00 63 6C 69 63 6B 63 6F 75 6E 74 00 63 68 6B 63 6C 69 63 6B 00 62 61 72 00 70 6C 61 79 00
push "page8"(0) 1 "_root"(1)
96 09 00 08 00 07 01 00 00 00 08 01
getVariable 
1C
push "text"(2)
96 02 00 08 02
getMember 
4E
push "gotoAndPlay"(3)
96 02 00 08 03
callMethod 
52
pop 
17
push "/:reg"(4)
96 02 00 08 04
getVariable 
1C
push 1
96 05 00 07 01 00 00 00
equals2 
49
not 
12
not 
12
if true goto #30
9D 02 00 3A 00
push "clickcount"(5) "clickcount"(5)
96 04 00 08 05 08 05
……
#30: 
很明显 if true goto #30 改为jmp #30 ( 9D -> 99)就等于删除了中间的这些代码。
 
 
随机打开另一个模板,找到类似代码,进行比较。  
//Button 66
// On release
 
on (release)
{
gotoAndPlay(60);
if (eval("/:reg") != 1) 
{
clickcount = clickcount + 1;
chkclick(clickcount);
}
}
Pi-Codes and hex:  
//Button 66
// On release
 
constantPool 0:"/:reg" 1:"clickcount" 2:"chkclick"
88 1C 00 03 00 2F 3A 72 65 67 00 63 6C 69 63 6B 63 6F 75 6E 74 00 63 68 6B 63 6C 69 63 6B 00
gotoFrame 59
81 02 00 3B 00
play 
06
push "/:reg"(0)
96 02 00 08 00
getVariable 
1C
push 1
96 05 00 07 01 00 00 00
equals2 
49
not 
12
not 
12
if true goto #20
9D 02 00 24 00
push "clickcount"(1) "clickcount"(1)
96 04 00 08 01 08 01
getVariable 
1C
push 1
96 05 00 07 01 00 00 00
add2 
47
setVariable 
1D
push "clickcount"(1)
96 02 00 08 01
getVariable 
1C
push 1 "chkclick"(2)
96 07 00 07 01 00 00 00 08 02
callFunction 
3D
pop 
17
#20: 
比较结果:  
push 1
96 05 00 07 01 00 00 00
equals2 
49
not 
12
not 
12
if true goto #20
9D 02 00 24 00
跳转长度不确定 不能用,得到一组特征码: 
 
1C 96 05 00 07 01 00 00 00 49 12 12 9D 02 00
替换成即可完成破解  
1C 96 05 00 07 01 00 00 00 49 12 12 99 02 00
这是一组可用的特征码,不过代码不是很有特点容易与类似的判断重复造成错误的判断,改用另外一种方法。
"/:reg"字串是很有特色的正好增加这段作为特征码,注意,字串的标号可能不同所以要加以判断
if true goto #20
9D 02 00 24 00
 
96 02 00 08 ?? 1C 96 05 00 07 01 00 00 00 49 12 12 9D 02 00
搜索时红色部分用??替换,找到之后保存这个值并向前搜索"/:reg",并获取"/:reg"在常量池中的标号,然后与之前保存的值进行比较,相等就修改,不等就继续搜索特征码(要忽略第一次的匹配,为什么呢?)。(实际写补丁的时候采取了先确定标号再搜索的方法)
 
 
经过上面步骤,\templates\swf site下面的模板都可以处理掉了。
\templates\swf menu下还有8个menu模板,和swf site的稍有不同需要另外处理。
仍然搜索demo,找到关键位置,不过这回字串是在常量池里。  
push "idcode"(9) "A4DM008"(19)
96 04 00 08 09 08 13
setVariable 
1D
push "demo"(20) "m8"(21)
96 04 00 08 14 08 15
getVariable 
1C
setVariable 
1D
提取特征码:
96 04 00 08 ?? 08 ?? 1D 96 04 00 08 ?? 08 ?? 1C 1D
搜索"demo",判断是否在常量池中如果不在继续搜索"demo",并获取"demo"在常量池中的标号,然后替换红色的值开始搜索。
找到后
用07h 填充。
 
测试结果,\templates\swf site\a4dp004\a4desk.swf demo字串使用了常量,破解失败,若干文件破解后文件错误,原因site第一个特征码过短,误判断造成错误。
 
对比看看找一段特征辅助定位:000000756E6B657900(unkey),找到后向前查找第一段特征码具体见代码。
这样只有a4dp004模板没有破解了。手工解决,收工。  
 
mov edi,0;edi计数 增加到filesize 就结束
mov esi,fileDateBegin
 
.if word ptr[esi+1] != 'SW';文件第2、3字节是否是WS,不是flash文件退出程序
jmp Exit
.endif
 
 
;000000756E6B657900(unkey)
.while (dword ptr[esi] != 75000000h) || (dword ptr[esi+4] != 79656B6Eh) || (byte ptr[esi+8] != 00h) 
.if edi > fileSize
jmp @menu;没找到site模板的特征码,前往menu处理部分
.endif
inc esi
inc edi
.endw
 
;site 特征码1
;搜索96 ?? 00 00 64 65 6D 6F 00 …… 1D
;替换07 07 07 07 07 07 07 07 07 …………
;仅一次
 
.while (byte ptr[esi] != 96h) || (dword ptr[esi+4] != 6F6D6564h) || (byte ptr[esi+8] != 00h) 
.if edi == 0
jmp @menu;没找到site模板的特征码,前往menu处理部分
.endif
dec esi
dec edi
.endw
 
.while byte ptr[esi] != 1Dh
mov byte ptr[esi],07h
inc esi
.endw
mov byte ptr[esi],07h
 
 
;site 特征码2
;搜索 /:reg
;96 02 00 08 ?? 1C 96 05 00 07 01 00 00 00 49 12 12 9D 02 00
;96 02 00 08 CL 1C 96 05 00 07 01 00 00 00 49 12 12 99 02 00
mov edi,0;edi计数 增加到filesize 就结束
mov esi,fileDateBegin
 
.while edi < fileSize 
 
.if (dword ptr[esi] == 'ger:') && (byte ptr[esi-1] == '/')
mov cl,0;假设常量少于200 呵呵
.while byte ptr[esi] != 88h
.if edi == 0
jmp Exit
.endif
.if byte ptr [esi]== 0
inc cl
.endif
dec esi
dec edi
.endw
 
sub ecx,2
 
.while (dword ptr[esi] != 08000296h) || (byte ptr[esi+4] != cl) || (dword ptr[esi+4+1] != 0005961Ch) || (dword ptr[esi+4+1+4] != 00000107h) || (dword ptr[esi+4+1+4+4] != 12124900h) 
.if edi > fileSize
jmp Exit
.endif
inc esi
inc edi 
.endw
 
mov byte ptr[esi+4+1+4+4+4],99h 
.endif 
 
 
inc esi
inc edi
.endw
jmp @save
 
@menu: 
 
 
;menu 特征码
;搜索 demo
mov edi,0;edi计数 增加到filesize 就结束
mov esi,fileDateBegin
@@: .while dword ptr[esi] != "omed"
.if edi > fileSize
jmp Exit
.endif
inc edi
inc esi
.endw
.if word ptr [esi-2] == 0;(没在常量表中或者前面的变量是空串)
jmp @B
.endif
 
mov cl,0;假设常量少于200 呵呵
.while byte ptr[esi] != 88h
.if edi == 0
jmp Exit
.endif
.if byte ptr [esi]== 0
inc cl
.endif
dec esi
dec edi
.endw
 
sub ecx,2
;96 04 00 08 ?? 08 ?? 1D 96 04 00 08 CL 08 ?? 1C 1D
;用07h 填充
 
.while (dword ptr[esi] != 08000496h) || (byte ptr[esi+4+1] != 08h) || (dword ptr[esi+4+3] != 0004961Dh) || (byte ptr[esi+4+3+4] != 08h) || (byte ptr[esi+4+3+4+1] != cl) 
.if edi > fileSize
jmp Exit
.endif
inc esi
inc edi 
.endw
 
.while byte ptr[esi] != 1Dh
mov byte ptr[esi],07h
inc esi
.endw
mov byte ptr[esi],07h
--------------------------------------------------------------------------------
【经验总结】
反复测试很重要。
 
--------------------------------------------------------------------------------
【版权声明】: 转载请注明作者并保持文章的完整, 谢谢!
 
2009年04月28日 3:31:08