微信小程序.wxapkg文件分析

前一段时间“跳一跳”很火,朋友圈老刷不上名次,于是了解小程序大致的实现原理,写了wxapkg的反编译工具,目前可以基本还原小程序源码。

那么哪里可以找到小程序的安装包?

1、 https://servicewechat.com/weapp/release/appid/{appid}/{version_num}.wxapkg

2、在android手机中/data/data/com.tencent.mm/MicroMsg/${userid}/appband/pkg

找到安装包后,源码就在里面,那么要怎么来解析?

我整理了wxapkg文件格式,写了一款解压工具SS.UnWxapkg,核心代码如下

    {
        public static void UnWxapkg(string filePath)
        {

            var bytes = File.ReadAllBytes(filePath);

            ByteBuffer byteBuffer = ByteBuffer.Allocate(bytes);

            var firstMark = byteBuffer.ReadByte();
            Console.WriteLine($"first header mark = {firstMark}");

            var info1 = byteBuffer.ReadInt();
            Console.WriteLine($"info1 = {info1}");

            var indexInfoLength = byteBuffer.ReadInt();
            Console.WriteLine($"indexInfoLength = {indexInfoLength}");

            var bodyInfoLength = byteBuffer.ReadInt();
            Console.WriteLine($"bodyInfoLength = {bodyInfoLength}");

            var lastMark = byteBuffer.ReadByte();
            Console.WriteLine($"last header mark = {lastMark}");

            if (firstMark != 0xBE || lastMark != 0xED)
            {
                Console.WriteLine("its not a wxapkg file!");
            }

            var fileCount = byteBuffer.ReadInt();
            Console.WriteLine($"fileCount = {fileCount}");

            var fileList = new List<WxapkgFile>();

            for (int i = 0; i < fileCount; i++)
            {
                var nameLen = byteBuffer.ReadInt();
                byte[] nameByte = new byte[nameLen];
                byteBuffer.ReadBytes(nameByte, 0, nameLen);
                var name = Encoding.UTF8.GetString(nameByte);
                var offset = byteBuffer.ReadInt();
                var size = byteBuffer.ReadInt();
                var wxapkgFile = new WxapkgFile() { Name = name, NameLen = nameLen, Offset = offset, Size = size };
                fileList.Add(wxapkgFile);
                Console.WriteLine($"readFile = {name} at Offset = {offset}");
            }
            var rootPath = System.Environment.CurrentDirectory;
            var fileNameWithoutExtension = Path.GetFileNameWithoutExtension(filePath);
            Console.WriteLine($"rootPath = {rootPath}");
            Console.WriteLine($"fileNameWithoutExtension = {fileNameWithoutExtension}");

            var unzipPath = Path.Combine(rootPath, fileNameWithoutExtension);
            Console.WriteLine($"unzipPath = {unzipPath}");
            if (!Directory.Exists(unzipPath))
            {
                Directory.CreateDirectory(unzipPath);
            }

            foreach (var wxapkgFile in fileList)
            {
                var wxapkgFileName = unzipPath + wxapkgFile.Name.Replace('/', Path.DirectorySeparatorChar);
                Console.WriteLine($"wxapkgFileName = {wxapkgFileName}");
                var directoryName = Path.GetDirectoryName(wxapkgFileName);
                Console.WriteLine($"directoryName = {directoryName}");
                if (!Directory.Exists(directoryName))
                {
                    Directory.CreateDirectory(directoryName);
                }
                byteBuffer.SetReaderIndex(wxapkgFile.Offset);
                var fileBytes = new byte[wxapkgFile.Size];
                byteBuffer.ReadBytes(fileBytes, 0, fileBytes.Length);
                File.WriteAllBytes(wxapkgFileName, fileBytes);
            }

        }
    }

代码大意是

1、根据firstMark和lastMark来判断是否是小程序的wxapkg文件格式

2、获取索引段长度、数据段长度、以及文件数量

3、根据文件数量,顺序读取文件数据区,读取每个文件

解压出来的格式基本上如下

│ app-config.json

│ app-service.js

│ page-frame.html

├─images

│ hello.png

│ world.png

├─pages

│ gameover.html

│ index.html

│ play.html

│ web.html

根据解压出来的文件进行分析可以得出下列信息

按照上面信息对应解析基本上就能得到源码了。

我的博客即将搬运同步至腾讯云+社区,邀请大家一同入驻:https://cloud.tencent.com/developer/support-plan