Deception 发表于 2018-12-1 18:06

XX SEE PRO 2.5.363简体中文版许可证代码分析

本帖最后由 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 /?”可以查阅命令行参数:
Microsoft (R) Windows Installer Xml Decompiler version 3.0.5419.0
Copyright (C) Microsoft Corporation. All rights reserved.

usage: dark.exe [-?] [-nologo] database.msi [@responseFile]

   -ext <extension>extension assembly or "class, assembly"
   -nologo    skip printing dark logo information
   -notidy    do not delete temporary files (useful for debugging)
   -o   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   suppress all warnings or a specific message ID
            (example: -sw1059 -sw1067)
   -swall   suppress all warnings (deprecated)
   -v         verbose output
   -wx   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: http://wix.sourceforge.net
执行“dark -nologo "ACDSee Pro 2.5.msi" -oAcdsee.wxs -v”命令,就可以得到完整的脚本文件(此文件为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”):
      <Binary Id="LMInstaller.dll" SourceFile="FILE NOT EXPORTED, USE THE dark.exe -x OPTION TO EXPORT BINARIES" />
接下来继续在文件中搜索“LMInstaller”,可以找到一下一些内容:
      <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”,就会看到这么一段:                </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”(用户定义的功能),然后检查返回结果。
Ø如果“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"("请输入许可证代码;如果没有许可证代码,请选择“试用版”选项。")。
通过上述检查可以发现:
Ø变量PIDKEY就是许可证代码;
>> “LMValidateLicenseData”和“LMIsFloatingLicense”是许可证代码的检验函数;
>> ValidationCode、ISReleaseFlags 和IsFloatingLicense是许可证代码的检验结果;
>> 正确的许可证代码的检验结果是“ValidationCode = "1"”并且((ISReleaseFlags<>"FLC"以及IsFloatingLicense=1)或者(ISReleaseFlags等于"FLC"))。
提示:动态链接库内的函数和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”,找到下面一段帮助说明: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.后面还有一段: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:”此句,这里就是调用“CustomAction”(案例为“LMInstaller.dll”“LMValidateLicenseData”函数)的地方了。用F7单步进入所调用的功能函数!





好了,各种手段以及工具都已经充分准备好了,剩下的就是去分析许可证代码的算法的“苦力活”啦!余下细节就不谈了,大家有兴趣的话,就自己去慢慢分析一下吧。大家可能很感兴趣:Acdsee不同语言版本的许可证代码有什么不同?我用UltraCompare比较过,其实Acdsee Pro不同语言安装包内里的“LMinstaller.dll”都是完全一样的,不一样的是脚本文件内的这一段定义:简体中文版:      <Property Id="LanguageCode" Value="ZA" />英文版:      <Property Id="LanguageCode" Value="EN" />而“LMinstaller.dll”内里有这么一个语言数据表:.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简体中文版,其内容分别为:      <Property Id="Packages" Value="737" />
      <Property Id="ParentProductID" Value="1401" />按我理解,“ParentProductID”中的“14”即为主版本号,“01”为次版本号。因此,只要获得“ParentProductID”、“Packages”和“LanguageCode”,就可以制作各个不同版本的Acdsee系列软件的注册机。

老伙计 发表于 2018-12-14 13:34

本帖最后由 老伙计 于 2018-12-14 13:36 编辑

       楼主技术很强,在下只能膜拜,有关 MSI 安装包的逆向分析这还是头一回见到,真是大开眼界,受益匪浅,楼主能否把你用于分析的 ACDSee 的安装包和 Windows Installer XML ToolSet 3.0 的工具也分享一下?

       网上能找到的 ACDSee Pro 2.5.363 简体中文版都不是原版,安装不需要序列号,Windows Installer XML ToolSet 3.0 搬家去了 github 我这里根本无法访问和下载。

Deception 发表于 2018-12-13 22:10

haoren6205 发表于 2018-12-3 11:04
太高水平了!!!只是能不能求一个可用的注册机,谢谢楼主了

很老的版本了,以下是两个中文版本的KEY,可以试一下可用否。
2.5:D2QTVH-3348T-38DCF2-3ZVRJQ7
4.0:HPYTVH-334YC-3WB3GY-388Y7TC

Deception 发表于 2020-7-3 22:38

dafs 发表于 2020-3-10 16:17
感觉
1应该不是中文,中文应该是



该软件用的就是“ZA”。最新版本在“计算机\HKEY_LOCAL_MACHINE\SOFTWARE\ACD Systems\ACDSee Ultimate\130”下的“Language”条目可以直接看到。

hua111 发表于 2020-3-10 19:57

这么厉害的

dafs 发表于 2020-3-10 16:17

感觉
1<Property Id="LanguageCode" Value="ZA" />应该不是中文,中文应该是

1<Property Id="LanguageCode" Value="ZH"/>

不过我也没有楼主的水平,只是刚觉而已

yepulu9 发表于 2019-7-30 09:56

太厉害了,给楼主点赞。

JACKFANS 发表于 2019-7-24 23:06

感谢分享好东西 赞赞

轻花落迟 发表于 2019-7-22 15:02

感谢分享好东西~

ok318 发表于 2019-4-27 10:07

谢谢分享。

tgy238 发表于 2019-3-30 14:43

感谢分享!

Elliot蜗牛 发表于 2019-3-30 10:48

谢谢分享
页: [1] 2 3 4 5 6 7 8 9
查看完整版本: XX SEE PRO 2.5.363简体中文版许可证代码分析