逆向: Patch 两款基于ActionScript的软件
两款基于Adobe ActionScript的软件,一款用来制作音乐视频,一款用来制作海报,上手都非常简单,功能也不差。
官网:https://sways.io/
Patch: https://pan.baidu.com/s/1pZTRFOk-xzuNqChGcpIQ5A
为了保护软件作者的权利,降低被搜索引擎查到的概率,故不在标题和文章中包含软件名,敬请谅解。
以下正文开始。
一、环境
- JDK 1.8.161
- JPEXS Free Flash Decompiler
- Pumpernickel 😀
二、Patch 制作海报软件
我们在windows平台下Patch,故只关注有关windows的内容。
在入口点发现,程序会根据软件运行的平台,调用相应授权验证模块初始化函数,根据pushstring入不同的特征值来区分平台。
通过跟踪软件注册界面发现,程序会先对于邮箱和注册码的格式进行简单验证,然后在调用真正的验证处理函数进行激活过程。
验证的位于util.stringutil。
可见邮箱的格式为合法的邮箱格式,如:test@test.com
注册码的格式为:XXXXXXXX-XXXXXXXX-XXXXXXXX-XXXXXXXX
真正的注册验证函数位于util.LicenseKeyValidationUtil。
程序会根据一个条件,来判断是执行联网验证还是执行本地验证。
我们要 Patch,只想让其执行本地验证,故直接删除联网验证,使得程序运行到这里的时候只能执行本地验证。
然后查看本地验证函数 utils.LicenseKeyBalidationUtil.validatePlatform。
以下为其算法。
trait method Qname(PrivateNamespace("sways.utils:LicenseKeyValidationUtil"),"validatePlatform") dispid 0 method name "validatePlatform" flag HAS_PARAM_NAMES param Qname(PackageNamespace(""),"String") param Qname(PackageNamespace(""),"Function") paramname "licenseKey" paramname "onSucces" returns Qname(PackageNamespace(""),"void") body maxstack 4 localcount 7 initscopedepth 0 maxscopedepth 1 code getlocal_0 pushscope pushnull setlocal 6 pushnull setlocal 4 pushnull setlocal 5 pushnull setlocal_3 getlocal_1 getlex Qname(PackageNamespace(""),"RegExp") pushstring "-" pushstring "g" construct 2 pushstring "" callproperty Qname(Namespace("http://adobe.com/AS3/2006/builtin"),"replace") 2 coerce_s setlocal_1 getlocal_1 pushbyte 0 pushbyte 8 callproperty Qname(Namespace("http://adobe.com/AS3/2006/builtin"),"substr") 2 coerce_s setlocal 6 getlocal_1 pushbyte 8 pushbyte 8 callproperty Qname(Namespace("http://adobe.com/AS3/2006/builtin"),"substr") 2 coerce_s setlocal 4 getlocal_1 pushbyte 16 pushbyte 8 callproperty Qname(Namespace("http://adobe.com/AS3/2006/builtin"),"substr") 2 coerce_s setlocal 5 getlocal_1 pushbyte 24 pushbyte 8 callproperty Qname(Namespace("http://adobe.com/AS3/2006/builtin"),"substr") 2 coerce_s setlocal_3 getlocal 5 getlex Qname(PackageNamespace("by.blooddy.crypto"),"MD5") getlocal 6 getlocal 4 add callproperty Qname(PackageNamespace(""),"hash") 1 pushbyte 0 pushbyte 8 callproperty Qname(Namespace("http://adobe.com/AS3/2006/builtin"),"substr") 2 callproperty Qname(Namespace("http://adobe.com/AS3/2006/builtin"),"toUpperCase") 0 equals dup iffalse ofs008b pop getlocal_3 getlex Qname(PackageNamespace("by.blooddy.crypto"),"MD5") getlocal 4 getlocal 5 add callproperty Qname(PackageNamespace(""),"hash") 1 pushbyte 0 pushbyte 8 callproperty Qname(Namespace("http://adobe.com/AS3/2006/builtin"),"substr") 2 callproperty Qname(Namespace("http://adobe.com/AS3/2006/builtin"),"toUpperCase") 0 equals ofs008b:iffalse ofs009b findpropstrict Qname(PackageNamespace("sways.animation"),"DelayedCall") constructprop Qname(PackageNamespace("sways.animation"),"DelayedCall") 0 pushbyte 7 getlocal_2 callpropvoid Qname(PackageNamespace(""),"call") 2 returnvoid ofs009b:findpropstrict Qname(PackageNamespace("sways.animation"),"DelayedCall") constructprop Qname(PackageNamespace("sways.animation"),"DelayedCall") 0 pushbyte 7 getlex Qname(PrivateNamespace("sways.utils:LicenseKeyValidationUtil"),"onEtcError") callpropvoid Qname(PackageNamespace(""),"call") 2 returnvoid end ; code end ; body end ; method end ; trait
可见:邮箱名不参加运算。
注册码的第一,第二组任意,第三组为第一组+第二组的md5的前8位,第四组为第二组+第三组的md5的前8位。
下面给出一个满足的注册码:11111111-11111111-FA1D3EB0-8397BA56
将文件替换为去除联网验证的程序文件,输入邮箱名:test@test.com和以上注册码即可注册成功!
三、Patch 音乐视频编辑软件
由于为同一家的软件,前面过程大体相当,这里只介绍区别。
- 真正的验证函数位于core.LicenseKeyBalidationUtil
- 似乎去除了本地验证,只可能通过联网激活。不能离线激活??(难道是39.95美刀的缘故???)
由于是只能联网激活,为了保险起见,先将其联网激活api修改为:http://www.baidu.com ....... :) 来防止与其激活服务器进行沟通(发送异常数据给它。。。)
发现关键函数。
此函数会根据_urlRequest是否成功,来决定是执行onComplete函数还是onError函数。(注释:_urlRequest中包含Adobe AIR runtime的内部对象,不方便修改)
由于修改了api,程序运行此函数时只可能回调onError,所以只要将onError函数修改的和onComplete函数中注册成功的部分相同即可。
如需进一步精简可以将oncomplete函数中的返回激活失败的代码通通删除,只保留激活成功代码。
这样 Patch 就成功了,由于没有本地验证算法,任意满足:XXXXXXXX-XXXXXXXX-XXXXXXXX-XXXXXXXX的注册码都行。
11111111-11111111-11111111-11111111可以,11111111-11111111-FA1D3EB0-8397BA56也可以。