本帖最后由 zjh16529 于 2019-6-6 18:40 编辑
题注:这是我前几年写的一篇笔记,部分内容尚算有新意,就尝试分享一下吧。
【文章标题】: ACDSEE PRO 2.5.363简体中文版许可证代码分析
【作者主页】: 保密
【作者IM 】: 保密
【软件名称】: ACDSEE PRO 2.5.363简体中文版
【下载地址】: http://www.acdsee.com/
【加壳方式】: 无壳
【保护方式】: 许可证代码
【使用工具】: Windows Installer SDK,Orca,Hiew,WindowsInstaller XML Toolset 3.0,EditPlus,IDA,OllyDbg,UltraCompare
【操作平台】: Windows 7
【软件介绍】: 很好的图像浏览、编辑工具
【作者声明】: 纯属自娱自乐 |
我一直有坚持使用Acdsee软件的习惯——虽然很多人指责它体积庞大臃肿、启动速度慢,但是它的功能还是足够全面和方便的。那天安装一台电脑的时候,偶尔兴起想装一套中文版本Acdsee Pro,发现居然找不到的注册码或者注册机,网上流传的都是破解版本或者方法。趁着偶有闲暇,忍不住好奇地打量起这个有趣的家伙起来。首先,用鼠标右键打开WinRAR菜单,看WinRAR能否识别软件安装包:
看来WinRAR并不认识它。不过不要紧,那就运行一下它吧!
启动安装软件后,到系统的临时目录下找一下,哈哈,原来真正的安装程序都在临时目录“{F6CBB502-B3E4-42AA-B916-2DCF80C05727}”里面呢:
提示:临时目录在哪里?检查一下系统的环境变量就知道了。
通过“ACDSee Pro 2.5.msi”这个文件,可以判断这是一个“Windows Installer”制作的安装包。随便输入一个许可证代码,然后选择“下一步”:
安装程序跳出错误提示:
由此可以判断安装包带有许可证代码判断程序。按经验,一般情况下,这很可能是一个由acdsystems公司提供的DLL动态链接库。不过,那如何分析、拆解“.MSI”安装包呢? 先去微软网站下一个“Windows Installer 4.5 SDK”(也是一个“.MSI”安装包),安装好以后,在安装目录下有一个“orca.msi”安装包(如果嫌麻烦的话,也可以直接到网上找“orca.msi”软件包),再运行它,就可以安装Orca软件。安装了Orca软件,用鼠标右键打开“.MSI”文件,在弹出菜单中就多了“Edit with Orca”这个选项。点击“Edit with Orca”,启动Orca,就可以对“.MSI”文件进行分析了;详细可参
考相关文档,在此不再细说。
直接到“Binary”一栏中找到“LMinstaller.dll”,这个看起来应该非常象我们要找的东西了。用鼠标左键双击“LMinstaller.dll”右侧的“Binary Data”栏位,然后选择“Write binary to file”,文件名输入“LMinstaller.dll”,再用“Browse…”选择目录,就可以得到了一个“.DLL”动态链接库文件。
为了确认这个文件是否真的是我们想要的东西,用Hiew打开这个文件,然后检查“Export段”部分内容,在看见“ValidateLicenseData”这些熟悉的字眼以后,基本上可以断定已经成功找到我们需要的东西了。
接下来就是祭出“Ida”大法的时候了(记得选择“Load resources”选项,可以便于查看定义在资源段内的数据,特别是字符串):
Acdsystems是相当的客气啊,“LMinstaller.dll”居然还带有Pdb调试信息呢。不过,面对这一大堆输出函数,问题又来了:安装程序又是怎么样调用和判断处理的呢? 各类的安装专门软件都是有可编程脚本文件的,WindowsInstaller也不例外。同样从微软网站找来“WindowsInstaller XML Toolset 3.0”软件,安装了以后,在安装目录下找到“dark.exe”程序,这个就是“.MSI”安装包的脚本文件反编译程序了。
执行“dark /?”可以查阅命令行参数:
[Shell] 纯文本查看 复制代码 Microsoft (R) Windows Installer Xml Decompiler version 3.0.5419.0
Copyright (C) Microsoft Corporation. All rights reserved.
usage: dark.exe [-?] [-nologo] database.msi [source.wxs] [@responseFile]
-ext <extension> extension assembly or "class, assembly"
-nologo skip printing dark logo information
-notidy do not delete temporary files (useful for debugging)
-o[ut] specify output file (default: write .wxs to current directory)
-sct suppress decompiling custom tables
-sdet suppress dropping empty tables (adds EnsureTable as appropriate)
-sras suppress relative action sequencing
(use explicit sequence numbers)
-sui suppress decompiling UI-related tables
-sw[N] suppress all warnings or a specific message ID
(example: -sw1059 -sw1067)
-swall suppress all warnings (deprecated)
-v verbose output
-wx[N] treat all warnings or a specific message ID as an error
(example: -wx1059 -wx1067)
-wxall treat all warnings as errors (deprecated)
-x <path> export binaries from cabinets and embedded binaries to <path>
-xo output wixout instead of WiX source code
(mandatory for transforms and patches)
-? | -help this help information
Environment variables:
WIX_TEMP overrides the temporary directory used for cab extraction, binary extraction, ...
For more information see: [url=http://wix.sourceforge.net]http://wix.sourceforge.net[/url]
执行“dark -nologo "ACDSee Pro 2.5.msi" -oAcdsee.wxs -v”命令,就可以得到完整的脚本文件(此文件为XML格式):
[XML] 纯文本查看 复制代码 <?xml version="1.0" encoding="utf-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Product Id="{2D95950E-6D76-43E7-94A5-D9DBA2FD29E4}" Codepage="936" Language="2052" Manufacturer="ACD Systems" Name="ACDSee Pro 2.5" UpgradeCode="{5F8662C3-4DE5-4405-94FB-3D18CCCF30AA}" Version="2.5.363">
<Package Comments=" ACDSee /" Description="ACDSee Pro 2.5" InstallerVersion="200" Keywords="Installer; MSI; Database" Languages="2052" Manufacturer="ACD Systems" SummaryCodepage="936" />
<AppId Advertise="yes" Id="{8F751B8F-72A8-4AAA-95E6-523FC4177709}" />
<Binary Id="SxsUninstallCA" SourceFile="FILE NOT EXPORTED, USE THE dark.exe -x OPTION TO EXPORT BINARIES" />
…………
关于此文件的详细描述可以参考“WindowsInstaller XML Toolset 3.0”软件的帮助说明。我们直接在“BinaryId”一节中找到我们所关心的“LMInstaller.dll”(注:通过dark.exe程序也可以提取“LMInstaller.dll”):
[XML] 纯文本查看 复制代码 <Binary Id="LMInstaller.dll" SourceFile="FILE NOT EXPORTED, USE THE dark.exe -x OPTION TO EXPORT BINARIES" />
接下来继续在文件中搜索“LMInstaller”,可以找到一下一些内容:
[XML] 纯文本查看 复制代码 <CustomAction Id="LMValidateLicenseData" BinaryKey="LMInstaller.dll" DllEntry="ValidateLicenseData" Return="ignore" />
<CustomAction Id="LMCleanupLicenseDataDeferred" BinaryKey="LMInstaller.dll" DllEntry="CleanupLicenseDataDeferred" Return="ignore" Execute="deferred" Impersonate="no" />
<CustomAction Id="LMPrepareLicenseData" BinaryKey="LMInstaller.dll" DllEntry="PrepareLicenseData" Return="ignore" />
<CustomAction Id="LMStoreLicenseDataDeferred" BinaryKey="LMInstaller.dll" DllEntry="StoreLicenseDataDeferred" Return="ignore" Execute="deferred" Impersonate="no" />
<CustomAction Id="LMShowUninstallMessage" BinaryKey="LMInstaller.dll" DllEntry="ShowUninstallMessage" Return="ignore" />
<CustomAction Id="LMIsFloatingLicense" BinaryKey="LMInstaller.dll" DllEntry="IsFloatingLicense" Return="ignore" />
比对Hiew的结果,显然以上都是“LMInstaller.dll”的输出函数。接着搜索“LMValidateLicenseData”,就会看到这么一段:[XML] 纯文本查看 复制代码 </Control>
<Control Id="Next" Type="PushButton" X="230" Y="243" Width="66" Height="17" Text="下一步(&N) >" TabSkip="no" Default="yes">
<Publish Event="DoAction" Value="LMValidateLicenseData">1</Publish>
<Publish Event="DoAction" Value="LMIsFloatingLicense">ISReleaseFlags >< "FLC"</Publish>
<Publish Event="Remove" Value="BuyNowACDSeeTrial">LICENSE_MODEL="Full"</Publish>
<Publish Event="NewDialog" Value="SetupType">ValidationCode = "1" and ((ISReleaseFlags >< "FLC" and IsFloatingLicense=1) or Not (ISReleaseFlags >< "FLC"))</Publish>
<Publish Event="SpawnDialog" Value="SetupErrorPrivilegesInsufficient">ValidationCode = "-1"</Publish>
<Publish Event="SpawnDialog" Value="SetupErrorLicenseInvalid">ValidationCode = "-2" or (ISReleaseFlags >< "FLC" and IsFloatingLicense=0 and LICENSE_MODEL="Full")</Publish>
<Publish Event="SpawnDialog" Value="SetupErrorNoLicenseEntered">LICENSE_MODEL="Full" And PIDKEY=""</Publish>
<Publish Event="EndDialog" Value="Exit">(ValidationCode <> "1") And (ValidationCode <> "-1") And (ValidationCode <> "-2")</Publish>
</Control>
这段话大意就是:显示按钮“下一步”,如果按下此按钮,将顺序执行执行“LMValidateLicenseData”和“LMIsFloatingLicense”两个“CustomAction”(用户定义的功能),然后检查返回结果。
[Plain Text] 纯文本查看 复制代码 Ø如果“LICENSE_MODEL="Full"”(选择完全安装)那么删除“BuyNowACDSeeTrial”选项;
>> 如果“ValidationCode = "1"”并且((ISReleaseFlags<>"FLC"以及IsFloatingLicense=1)或者(ISReleaseFlags等于"FLC")),打开"SetupType"对话框继续完成安装;
>> 如果ValidationCode = "-1"打开子对话框"SetupErrorPrivilegesInsufficient"("用户权限不足,无法继续安装。请与计算机管理员联系。");
>> 如果ValidationCode = "-2"或者(ISReleaseFlags<>"FLC"以及IsFloatingLicense=0以及LICENSE_MODEL="Full"),则打开子对话框"SetupErrorLicenseInvalid"("输入的许可证代码无效。在继续安装之前,请检查许可证代码并重试。");
>> 如果LICENSE_MODEL="Full" And PIDKEY="",则打开子对话框"SetupErrorNoLicenseEntered"("请输入许可证代码;如果没有许可证代码,请选择“试用版”选项。")。
通过上述检查可以发现:
[Plain Text] 纯文本查看 复制代码 Ø变量PIDKEY就是许可证代码;
>> “LMValidateLicenseData”和“LMIsFloatingLicense”是许可证代码的检验函数;
>> ValidationCode、ISReleaseFlags 和IsFloatingLicense是许可证代码的检验结果;
>> 正确的许可证代码的检验结果是“ValidationCode = "1"”并且((ISReleaseFlags<>"FLC"以及IsFloatingLicense=1)或者(ISReleaseFlags等于"FLC"))。
[Shell] 纯文本查看 复制代码 提示:动态链接库内的函数和MSIEXEC程序之间是通过msi.145:MsiSetPropertyW和msi.74:MsiGetPropertyW两个函数来传递数据和信息的。这两个函数的原型分别是:
UINT __stdcall MsiSetPropertyW(MSIHANDLE hInstall, LPCWSTR szName, LPCWSTR szValue)
UINT __stdcall MsiGetPropertyW(MSIHANDLE hInstall, LPCWSTR szName, LPWSTR szValueBuf, LPDWORD pcchValueBuf)
例如:
pcchValueBuf = 32;
v1 = MsiGetPropertyW(hInstall, L"UILevel", &szValueBuf, &pcchValueBuf);
以及:
if ( v15 == 9 )
v10 = L"1";
else
v10 = L"0";
v9 = MsiSetPropertyW(v2, L"IsFloatingLicense", v10); 有了这些了解,我们就可以在IDA当中好好研究那么汇编代码了。不过问题又来了:那些汇编代码让人晕头转向的,特别是大量的嵌套函数调用以及堆栈变量传递,光靠看又怎么能彻底了解其中的内容和处理呢?!那能不能调不跟踪呢?“.MSI”文件是依赖于“Msiexec.exe”来解释执行的,直接用调试软件跟踪似乎不太可行。翻查“WindowsInstaller XML Toolset 3.0”软件所带的“MSI SDK Documentation”,找到下面一段帮助说明:[Plain Text] 纯文本查看 复制代码 Debugging Custom Actions
You can debug custom actions that are based on dynamic-link libraries by using Debugging Tools for Windows. It is not possible to use dynamic debugging with custom actions based on executable files or scripts.
The techniques described in this section can help you debug Windows Installer custom actions. See the Driver Development Tools section of the Windows Driver Kit for information about Debugging Tools for Windows.
Windows Installer uses the MsiBreak environment variable to determine which custom action is to be debugged. If you have access to the custom action's source code, you may be able to use debugging without MsiBreak. To start debugging without MsiBreak, put a temporary message box at the beginning of the action's code. When the message box appears during the installation, attach the debugger to the process owning the message box. You can then set any necessary breakpoints and dismiss the message box to resume execution. It is not possible to debug the earlier portions of the custom action by this method.
To use the MsiBreak environment variable to debug the custom action, set MsiBreak to the custom action's name in the CustomAction table. MsiBreak can be either a system or a user environment variable. If the variable is set as a system variable, a restart of the system may be needed when the value is changed to detect the new value.
To use the MsiBreak environment variable to debug an embedded user interface, set the value of MsiBreak to MsiEmbeddedUI.
Windows Installer only checks the MsiBreak environment variable if the user is an Administrator. The installer ignores the value of MsiBreak if the user is not an Administrator, even if this is a managed application.
If you are debugging a custom action that runs with elevated (system) privileges in the execution sequence, attach the debugger to the Windows Installer service. When debugging a custom action that runs with impersonated privileges in the execution sequence, the system prompts with a dialog box that indicates which process should be debugged. The user is prompted with a dialog box indicating which process to debug. For more information about elevated custom actions, see Custom Action Security.
Once the debugger has been attached to the correct process, the installer triggers a debugger breakpoint immediately before calling the entry point of the DLL. At the breakpoint, your DLL is already loaded into the process and the entry point address determined. If your custom action DLL could not be loaded or the custom action entry point did not exist, no breakpoint is triggered. Because the breakpoint is triggered before calling the DLL function, once the breakpoint has been triggered you should use your debugger to step forward until your custom action entry point is called. Alternately, you can set a breakpoint anywhere in your custom action and resume normal execution. 后面还有一段:[Plain Text] 纯文本查看 复制代码 The Windows Installer executes DLLs not stored in the Binary table directly from the DLL location. The installer does not know the original name of a DLL stored in the Binary table and runs the DLL custom action under a temporary file name. The form of the temporary file name is MSI?????.TMP. On Windows 2000 or Windows XP this temporary file is stored in a secure location, commonly <WindowFolder>\Installer.
Note that many DLLs created for debugging contain the name and path of the corresponding PDB file as part of the DLL itself. When debugging this type of DLL on a system where the PDB can be found at the location stored in the DLL, symbols may be loaded automatically by the debugger tool. In situations where the PDB cannot be found at the stored location, where the debugger does not support loading symbols from the stored location, or where the DLL was not built with debugging information, you may need to place your symbol files in the folder with the temporary DLL file.
The installer adds debugging information for custom action scripts to the installation log file. 仔细看过说明,就亲自动手一试吧!首先启动命令行窗口,并设置MsiBreak为“LMValidateLicenseData”,然后启动安装程序:
随便输入一个许可证代码,然后按“下一步”,安装软件自动弹出Process ID(这里案例是0x0C28)提示:
接着启动OLLYDBG,选择“File”菜单的“Attach”功能:
找到并选定软件提示的Process ID(这里案例是0x0C28)然后执行“Attach”功能:
待OLLYDBG成功Attach指定进程以后,按“F9”继续运行;然后再点击Windows Installer提示窗口的“确定”键。
点击Windows Installer提示窗口的“确定”键之后,OLLYDBG将取得进程的所有权:
按“F7”单步执行,返回到关键的调用点:
留意“7016B679 FF55 08 CALL DWORD PTR SS:[EBP+8]”此句,这里就是调用“CustomAction”(案例为“LMInstaller.dll”“LMValidateLicenseData”函数)的地方了。用F7单步进入所调用的功能函数!
好了,各种手段以及工具都已经充分准备好了,剩下的就是去分析许可证代码的算法的“苦力活”啦!余下细节就不谈了,大家有兴趣的话,就自己去慢慢分析一下吧。大家可能很感兴趣:Acdsee不同语言版本的许可证代码有什么不同?我用UltraCompare比较过,其实Acdsee Pro不同语言安装包内里的“LMinstaller.dll”都是完全一样的,不一样的是脚本文件内的这一段定义:简体中文版:[XML] 纯文本查看 复制代码 <Property Id="LanguageCode" Value="ZA" /> 英文版:[XML] 纯文本查看 复制代码 <Property Id="LanguageCode" Value="EN" /> 而“LMinstaller.dll”内里有这么一个语言数据表:[Asm] 纯文本查看 复制代码 .rdata:10028DD8 Table_LanguageCode dd 0FFFFFFFFh ; LanguageCodeIndex
.rdata:10028DD8 ; DATA XREF: _GetLanguageCodeToIndex+153r
.rdata:10028DD8 ; _GetLanguageCodeToIndex+8Eo ...
.rdata:10028DD8 unicode 0, <aa>,0 ; LanguageCode
.rdata:10028DD8 dw 0 ; anonymous_0
.rdata:10028DD8 dd 0FFFFFFFFh ; LanguageCodeIndex
.rdata:10028DD8 unicode 0, <ab>,0 ; LanguageCode
.rdata:10028DD8 dw 0 ; anonymous_0
.rdata:10028DD8 dd 0FFFFFFFFh ; LanguageCodeIndex
…………
.rdata:10028DD8 dd 0 ; LanguageCodeIndex
.rdata:10028DD8 unicode 0, <en>,0 ; LanguageCode
.rdata:10028DD8 dw 0 ; anonymous_0
…………
.rdata:10028DD8 dd 0Dh ; LanguageCodeIndex
.rdata:10028DD8 unicode 0, <za>,0 ; LanguageCode
.rdata:10028DD8 dw 0 ; anonymous_0
.rdata:10028DD8 dd 0Eh ; LanguageCodeIndex
.rdata:10028DD8 unicode 0, <zh>,0 ; LanguageCode
.rdata:10028DD8 dw 0 ; anonymous_0
.rdata:10028DD8 dd 0FFFFFFFFh ; LanguageCodeIndex
.rdata:10028DD8 unicode 0, <zu>,0 ; LanguageCode
.rdata:10028DD8 dw 0 ; anonymous_0
.rdata:10028DD8 dd 0FFFFFFFFh ; LanguageCodeIndex
.rdata:10028DD8 dw 0 ; anonymous_0 不同语言版本的许可证代码的差异就在“LanguageCode”所对应的索引代码上。Acdsee系列软件有两个两个特殊的软件版本号标志:“ParentProductID”和“Packages”,不同版本的Acdsee系列软件,其许可证代码的校验方法都是一致的,区别只是这两个标志的不同。例如对于ACDSEEPRO 2.5.363简体中文版,其内容分别为:[XML] 纯文本查看 复制代码 <Property Id="Packages" Value="737" />
<Property Id="ParentProductID" Value="1401" /> 按我理解,“ParentProductID”中的“14”即为主版本号,“01”为次版本号。因此,只要获得“ParentProductID”、“Packages”和“LanguageCode”,就可以制作各个不同版本的Acdsee系列软件的注册机。 |