UWP应用:Repacks & Hacks

今天遇到了需要修改 UWP 程序的情况,步骤比较繁杂,在此记录一下。

Repacks

获取程序文件

  1. appx 文件可以通过抓包的方式直接获取下载地址。我在搜索过程中发现了很多相关的教程,都比较老了,有些地方变动比较大。

首先 Microsoft Store 会产生一个到http://dl.delivery.mp.microsoft.com/filestreamingservice/files/{GUID}/piecehash的请求,确定程序版本、哈希、分段等信息。然后在http://tlu.dl.delivery.mp.microsoft.com/filestreamingservice/files/{GUID}?P1={}&P2={}&P3={}&P4={}分段下载文件。只要访问 URL ,就可以下载到完整的 appx 。

Microsoft Store 下载请求

  1. 直接打开应用的安装目录(在C:\Program Files\WindowsApps\下),把所有文件复制出来。如果不能直接打开这个文件夹,可能需要调整文件夹的高级安全设置,加入当前用户的访问权限。事实证明,对于我测试的一个程序来说,在打包之后它确实能够运行,所以这也可以算是一种可行方法吧。

解包

使用makeappx.exe unpack /p foo.appx /d unpacked /l对 appx 进行解包,得到的目录结构如下:

appx 解包后的目录结构

如果makeappx报错,很有可能抓包得到的是 App Bundle 。根据文件头可知其为一个 zip 文件,里面的内容有不同分辨率的资源文件和 x64 、 x86 两个架构的程序文件。Unbundle 命令为makeappx.exe unbundle /p rest.appxbundle /d unpacked

原安装包留下的不必要的结构有:AppxSignature.p7x文件和AppxBlockMap.xml文件(指出文件实际位置信息的xml)。直接把这些文件删除就可以。

重新打包

为了能正常安装 appx 程序包,我们必须准备一个用于签名的证书。在 Powershell 中,执行

# 制作自签名证书,记录输出的证书指纹
New-SelfSignedCertificate -Type Custom -Subject "CN=Contoso Software" -KeyUsage DigitalSignature -FriendlyName "Your friendly name goes here" -CertStoreLocation "Cert:\CurrentUser\My" -TextExtension @("2.5.29.37={text}1.3.6.1.5.5.7.3.3", "2.5.29.19={text}")
# 使用密码方式导出
$password = ConvertTo-SecureString -String <Your Password> -Force -AsPlainText 
Export-PfxCertificate -cert "Cert:\CurrentUser\My\<Certificate Thumbprint>" -FilePath <FilePath>.pfx -Password $password

打开AppxManifest.xml,将Identity节点中的Publisher属性改为刚刚制作的证书中的Subject值,如CN=Contoso Software。之后就可以打包、签名了。

makeappx.exe pack /d unpacked /p repacked.appx /l
signtool.exe sign /fd SHA256 /a /f mycert.pfx /p "mycertpassword" repacked.appx

signtool中指定使用 SHA256 的原因是makeappx默认使用SHA256。

Hacks

如何让一个正在试用中的应用认为它已经被购买?对于 dotnet 程序,微软在Windows.Services.Store中提供了StoreAppLicense类作为应用可以获取到的返回值类型。在官方示例中,说明了其用法:

StoreAppLicense license = await storeContext.GetAppLicenseAsync();
if (license.IsActive)
{
    if (license.IsTrial)
    {
        LicenseMode.Text = "Trial license";
    }
    else
    {
        LicenseMode.Text = "Full license";
    }
}
else
{
    LicenseMode.Text = "Inactive license";
}

StoreAppLicense.IsActiveStoreAppLicense.IsTrial 都是只读的属性,所以修改它们需要用到反射。但很幸运的是,我要修改的程序中自己封装了一个用来获取许可的类,也提供了相同名称的两个只读属性。在 C# 中,属性的getset都是函数,所以可以直接修改它们的IL代码强制其返回指定的布尔值,达到欺骗程序的目的。

处理 UWP 程序相对来说比较困难。它不允许直接启动,事实上 Visual Studio 在调试 UWP 程序时,会先将其安装到系统中,目前我还没有找到很好的动态调试的方法。其次 XAML 交互部分的代码中可能存在大量匿名函数,对程序的修改工作制造了一定的阻碍。

参考

  1. Create a certificate for package signing
  2. App packager (MakeAppx.exe)
  3. Unpack, edit, repack, and re-sign Windows Phone apps
  4. Repackaging Windows Store Applications
  5. Get license info for apps and add-ons