"use strict"; const common_vendor = require("../../common/vendor.js"); const utils_api = require("../../utils/api.js"); const utils_subscribeMessage = require("../../utils/subscribeMessage.js"); const common_assets = require("../../common/assets.js"); const app = getApp(); const mpHtml = () => "../../components/mp-html/mp-html.js"; const _sfc_main = { components: { mpHtml }, data() { return { // 全屏加载 coverBulr: true, no_list_data: false, // 文章ID posdCenterID: "", // 页面路径 posUrl: "", // 基本配置 wxSet: [], launchScene: 0, //微信小程序场景值 // 评论 XuMessageList: [], // 文章详情 detailData: [], isGuide: false, //前往小程序使用完整服务 // 页码 page: 1, // 当前时间戳和 postDaySum: 0, postAdKey: [], // 文本框解析 tag_style: {}, // 容器样式 container_style: "font-size:16px;overflow-x: hidden;line-height:1.8;letter-spacing:1px;", copyLink: true, // 相关文章 posTagsList: [], // 密码访问 protected: true, isError: "suss", getPass: "", public_step: false, // 广告次数控制 adViewCount: 0, requiredAdViews: 1, adNumber: 0, isAdPopup: false, isIntegral: false, // 消息订阅 templateId: "", openID: "", statusMessage: "", isSubscribed: false, read_records: [], //积分记录 noPoints: false, //积分不足 // 分割快手流量主id jiliAd: [], xingxiAd: [] }; }, // 分享好友配置 onShareAppMessage(res) { if (res.from === "button") ; return { title: this.detailData.title.rendered, imageUrl: this.detailData.thumbnailurl, path: "/pages/data/data?id=" + this.posdCenterID }; }, // 文章分享盆友圈 目前支持安卓 onShareTimeline(res) { return { title: this.detailData.title.rendered, imageUrl: this.detailData.thumbnailurl, path: "/pages/data/data?id=" + this.posdCenterID }; }, // 监听触底----上啦刷新 onReachBottom() { this.page = this.page + 1; }, onLoad(posID) { this.posdCenterID = posID.id; if (posID.scene) { this.posdCenterID = posID.scene; } this.posUrl = "pages/data/data?id=" + posID.id; this.tag_style = app.globalData.tag_style; const now = /* @__PURE__ */ new Date(); const year = now.getFullYear(); const month = now.getMonth() + 1; const day = now.getDate(); const postDaySum = year + month + day; this.postDaySum = postDaySum; const subscriptionMsg = common_vendor.index.getStorageSync("subscriptionMsg"); if (subscriptionMsg && subscriptionMsg == this.postDaySum) { this.isSubscribed = true; } else { this.isSubscribed = false; } if (app.globalData.wxSet == "") { app.on("wxSet", this.changeToken.bind(this)); } else { this.wxSet = app.globalData.wxSet; this.launchScene = app.globalData.launchScene; this.jiliAd = this.wxSet.wx_jili_video.split(","); this.xingxiAd = this.wxSet.wx_video.split(","); this.posdData(); this.getOpenid(); } common_vendor.wx$1.showShareMenu({ withShareTicket: true, menus: ["shareAppMessage", "shareTimeline"] }); }, methods: { // 【新增】链接点击处理函数 linkTapHandle(e) { const href = e.detail.href; // 外部网址 点击复制 uni.setClipboardData({ data: href, success() { common_vendor.index.showToast({ title: "链接已复制!" }); } }); }, //(解决异步) changeToken() { this.wxSet = app.globalData.wxSet; this.launchScene = app.globalData.launchScene; this.jiliAd = this.wxSet.wx_jili_video.split(","); this.xingxiAd = this.wxSet.wx_video.split(","); this.posdData(); this.getOpenid(); this.searchRecords(); }, // 获取用户openid getOpenid() { if (this.wxSet.fr_points == 0) { return; } const openid = common_vendor.index.getStorageSync("openid"); if (openid) { this.openID = openid; } else { common_vendor.index.login({ provider: "weixin", success: (loginRes) => { utils_api.postOpenid({ code: loginRes.code }).then((res) => { if (res.statusCode === 200 && res.data.openid) { common_vendor.index.setStorageSync("openid", res.data.openid); this.openID = res.data.openid; } else { common_vendor.index.showToast({ title: "获取OpenID失败", icon: "none" }); } }); } }); } }, // 文章数据 posdData() { utils_api.getInfo([this.posdCenterID]).then((res) => { this.detailData = res.data; this.posTag = res.data.tags[0]; this.protected = res.data.content.protected; this.coverBulr = false; if (this.wxSet.public_step != "") { this.public_step = true; } if (this.protected == false) { this.infoAdJudge(); } this.infoPassJudge(); if (res.data.tags == "" || res.data.tags[0] == void 0) { this.no_list_data = true; } else { this.tagList(res.data.tags[0]); } }); }, // 密码访问 emitPass(pass) { utils_api.getInfoPass(this.posdCenterID, pass).then((res) => { if (res.statusCode != 200) { this.isError = "err"; } else { this.setPass(pass); this.detailData = res.data; this.posTag = res.data.tags[0]; this.protected = false; if (res.data.tags == "" || res.data.tags[0] == void 0) { this.no_list_data = true; } else { this.tagList(res.data.tags[0]); } this.infoAdJudge(); } }); }, // 广告缓存公告判断 infoAdJudge() { const postAdKey = common_vendor.index.getStorageSync("post_adkey"); if (this.wxSet.ad_time == "1") { if (postAdKey) { const foundItem = postAdKey.find((item) => item.id === this.posdCenterID); if (foundItem) { if (foundItem.time != this.postDaySum) { this.starpAd(); } else { if (this.detailData.pos_notice != "") { common_vendor.index.showModal({ title: "公告", content: this.detailData.pos_notice }); } } } else { this.starpAd(); } } else { this.starpAd(); } } else { this.starpAd(); } }, // 密码缓存判断 infoPassJudge() { const passKey = common_vendor.index.getStorageSync("pass_adkey"); if (passKey) { const foundItem = passKey.find((item) => item.id === this.posdCenterID); if (foundItem) { if (foundItem.time == this.postDaySum) { this.getPass = foundItem.pass; } } } }, // 初始化广告 starpAd() { if (this.launchScene == 1154) { this.isGuide = true; return; } if (this.wxSet.if_subscribe == 1) { utils_api.getSubscribeTemplate().then((res) => { this.templateId = res.data.template_id; if (this.wxSet.if_subscribe_popup == 1) { setTimeout(() => { this.showSubscribeMessage(); }, 1500); } }); } if (this.detailData.fr_videp_integral != "" && this.detailData.fr_videp_integral != "0" && this.wxSet.fr_points != 0) { this.isIntegral = true; this.CreateAd(); this.videoAD(); } else if (this.wxSet.wx_jili_video != "" && this.detailData.fr_videp_if == "1") { this.requiredAdViews = this.detailData.ad_number && this.detailData.ad_number > 0 ? this.detailData.ad_number : 1; this.adViewCount = 0; this.adNumber = this.requiredAdViews; this.isIntegral = false; this.CreateAd(); this.videoAD(); } }, // 热门文章 tagList(posTag) { utils_api.getTagsList([posTag]).then((res) => { this.posTagsList = res.data; }); }, // 资源点击 downloadTap() { if (this.detailData.red_pay == "1") { common_vendor.index.navigateTo({ url: "../download-pay/download-pay?id=" + this.posdCenterID, fail(err) { common_vendor.index.showToast({ title: "打开失败,请检查是否有该文件" }); } }); return; } common_vendor.index.navigateTo({ url: "../download/download?id=" + this.posdCenterID }); }, // 点击跳转 posTap(e) { switch (e.pos_read) { case "": common_vendor.index.navigateTo({ url: "../data/data?id=" + e.id }); break; case "0": common_vendor.index.navigateTo({ url: "../data/data?id=" + e.id }); break; case "1": common_vendor.index.navigateTo({ url: "../weblist/weblist?aurl=" + e.account_url }); break; case "2": common_vendor.index.navigateTo({ url: "../download/download?id=" + e.id }); break; case "3": common_vendor.index.openChannelsActivity({ finderUserName: e.wxvideo_id, feedId: e.wxvideo_feedid, success: (res) => { }, fail: (err) => { common_vendor.index.__f__("log", "at pages/data/data/data.js:600", err); } }); break; case "4": const aid = e.bz_video_av; const timestamp = (/* @__PURE__ */ new Date()).getTime(); const path = `pages/video/video?__preload_=${timestamp * 10 + 3}&__key_=${timestamp * 10 + 4}&avid=${aid}`; common_vendor.wx$1.navigateToMiniProgram({ appId: "wx7564fd5313d24844", path, success: (res) => { common_vendor.index.__f__("log", "at pages/data/data/data.js:613", "跳转成功"); } }); break; } }, //初始化激励视频广告组件 CreateAd() { if (this.wxSet.wx_jili_video != "") { if (common_vendor.wx$1.createRewardedVideoAd) { this.videoAd = common_vendor.wx$1.createRewardedVideoAd({ adUnitId: this.wxSet.wx_jili_video }); this.videoAd.onLoad(() => { }); this.videoAd.onError((err) => { common_vendor.index.__f__("log", "at pages/data/data/data.js:631", err); common_vendor.wx$1.showToast({ icon: "none", title: "错误码:" + err.errCode }); if (this.noPoints == false) { this.isAdPopup = false; } if (this.wxSet.if_subscribe_popup == 1 && this.wxSet.if_subscribe == 1) { setTimeout(() => { this.showSubscribeMessage(); }, 1500); } }); this.videoAd.onClose((res) => { if (res && res.isEnded) { this.adViewCount++; if (this.adViewCount >= this.requiredAdViews) { common_vendor.index.showToast({ icon: "none", title: "感谢您的支持" }); if (this.noPoints == false) { this.isAdPopup = false; if (this.wxSet.ad_time == "1") { this.setRead(); } } if (this.wxSet.if_subscribe_popup == 1 && this.wxSet.if_subscribe == 1) { setTimeout(() => { this.showSubscribeMessage(); }, 1500); } this.addPoints(); } else { this.adNumber = this.requiredAdViews - this.adViewCount; } } else { common_vendor.index.showToast({ icon: "none", title: "中途关闭广告" }); this.tarBlack(); } }); } } }, // 流量主视频弹窗 videoAD() { this.isAdPopup = true; }, // 激励视频 getVideoAd() { if (this.videoAd) { this.videoAd.show().catch(() => { this.videoAd.load().then(() => this.videoAd.show()).catch((err) => { common_vendor.index.__f__("log", "at pages/data/data/data.js:789", "激励视频", err); }); }); } }, // 设置广告缓存 setRead() { var postAdKey = common_vendor.index.getStorageSync("post_adkey"); if (postAdKey == "") { var postAdKey = []; } var isItem = postAdKey.find((item) => item.id === this.posdCenterID); if (isItem) { const updateData = (id, newData) => { postAdKey = postAdKey.map((item) => { if (item.id === id) { return { ...item, ...newData }; } return item; }); }; updateData(this.posdCenterID, { time: this.postDaySum }); } else { postAdKey.unshift({ id: this.posdCenterID, time: this.postDaySum }); } common_vendor.index.setStorageSync("post_adkey", postAdKey); }, // 设置密码缓存 setPass(e) { var passKey = common_vendor.index.getStorageSync("pass_adkey"); if (passKey == "") { var passKey = []; } var isItem = passKey.find((item) => item.id === this.posdCenterID); if (isItem) { const updateData = (id, newData) => { passKey = passKey.map((item) => { if (item.id === id) { return { ...item, }; } return item; }); }; updateData(this.posdCenterID, { time: this.postDaySum, pass: e }); } else { passKey.unshift({ id: this.posdCenterID, time: this.postDaySum, pass: e }); } common_vendor.index.setStorageSync("pass_adkey", passKey); }, // 左上角返回按钮 tarBlack: function() { var selPage = getCurrentPages(); if (selPage.length == 1) { common_vendor.index.switchTab({ url: "../index/index" }); } else { common_vendor.index.navigateBack({ delta: 1 }); } }, // 弹窗订阅 showSubscribeMessage() { const subscriptionMsg = common_vendor.index.getStorageSync("subscriptionMsg"); if (subscriptionMsg && subscriptionMsg == this.postDaySum) { common_vendor.index.showToast({ title: "今日已订阅", icon: "none" }); return; } utils_subscribeMessage.SubscribeMessage.showSubscribeMessage(this.templateId, () => { this.statusMessage = "订阅成功!"; this.isSubscribed = true; common_vendor.index.setStorageSync("subscriptionMsg", this.postDaySum); }); }, // 调用积分操作接口 addPoints() { if (this.wxSet.fr_points == 0) { return; } utils_api.postPoints({ openid: this.openID, operation: "increase", points: this.wxSet.fr_ad_points }).then((res) => { if (res.statusCode === 200) { common_vendor.index.showToast({ title: "+" + this.wxSet.fr_ad_points + ",当前积分:" + res.data.current_points, duration: 2e3 }); } else { common_vendor.index.showToast({ title: "积分领取失败", icon: "none" }); } }); }, // 积分购买 getIntegral() { utils_api.postIntegralBuy({ openid: this.openID, article_id: this.posdCenterID, points: this.detailData.fr_videp_integral, type: "read" }).then((res) => { common_vendor.index.showToast({ title: res.data.message, duration: 2e3, icon: "none" }); if (res.data.message == "积分兑换成功") { this.read_records = res.data.read_records; this.isAdPopup = false; common_vendor.index.setStorageSync("read_records", this.read_records); } else if (res.data.message == "积分不足") { this.noPoints = true; common_vendor.index.__f__("log", "at pages/data/data/data.js:968", this.noPoints, "积分不足"); } }); }, // 积分恢复 restoreTap() { utils_api.postIntegralBuy({ openid: this.openID, article_id: this.posdCenterID, points: this.detailData.fr_videp_integral, type: "query" }).then((res) => { this.read_records = res.data.read_records; common_vendor.index.setStorageSync("read_records", this.read_records); const record = this.read_records.find((item) => item.article_id == this.posdCenterID); if (record) { common_vendor.index.showToast({ title: "恢复成功", icon: "success" }); this.isAdPopup = false; } else { common_vendor.index.showToast({ title: "未兑换此内容", icon: "error" }); } }); }, searchRecords() { const read_records = common_vendor.index.getStorageSync("read_records"); if (read_records) { this.read_records = read_records; const record = read_records.find((item) => item.article_id == this.posdCenterID); if (record && this.wxSet.fr_points != 0) { this.isAdPopup = false; } } } } }; if (!Array) { const _easycom_cover_bulr_bg2 = common_vendor.resolveComponent("cover-bulr-bg"); const _easycom_common_pass2 = common_vendor.resolveComponent("common-pass"); const _easycom_mp_html2 = common_vendor.resolveComponent("mp-html"); const _easycom_showPrivacyAd2 = common_vendor.resolveComponent("showPrivacyAd"); const _easycom_cover_guide2 = common_vendor.resolveComponent("cover-guide"); (_easycom_cover_bulr_bg2 + _easycom_common_pass2 + _easycom_mp_html2 + _easycom_showPrivacyAd2 + _easycom_cover_guide2)(); } const _easycom_cover_bulr_bg = () => "../../components/cover-bulr-bg/cover-bulr-bg.js"; const _easycom_common_pass = () => "../../components/common-pass/common-pass.js"; const _easycom_mp_html = () => "../../components/mp-html/mp-html.js"; const _easycom_showPrivacyAd = () => "../../components/showPrivacyAd/showPrivacyAd.js"; const _easycom_cover_guide = () => "../../components/cover-guide/cover-guide.js"; if (!Math) { (_easycom_cover_bulr_bg + _easycom_common_pass + _easycom_mp_html + _easycom_showPrivacyAd + _easycom_cover_guide)(); } function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) { return common_vendor.e({ a: $data.coverBulr }, $data.coverBulr ? {} : {}, { b: $data.protected }, $data.protected ? { c: common_vendor.o($options.emitPass, "aa"), d: common_vendor.p({ isError: $data.isError, getPass: $data.getPass, public_name: $data.wxSet.public_name, public_key: $data.detailData.public_key, public_step: $data.public_step }) } : common_vendor.e({ e: common_vendor.t($data.detailData.title.rendered), f: common_vendor.t($data.detailData.en_md_date), // ==========重点改动:增加 @linktap 事件绑定========== g: common_vendor.p({ ["tag-style"]: $data.tag_style, content: $data.detailData.content.rendered, ["container-style"]: $data.container_style, ["copy-link"]: $data.copyLink, selectable: true, ["scroll-table"]: true }), h: common_vendor.o($options.linkTapHandle), i: $data.detailData.fr_hide != "" }, $data.detailData.fr_hide != "" ? { j: common_assets._imports_0$1, k: common_vendor.p({ ["tag-style"]: $data.tag_style, content: $data.detailData.fr_hide, ["container-style"]: $data.container_style, ["copy-link"]: $data.copyLink, selectable: "true" }) } : {}, { l: $data.wxSet.wx_video != "" }, $data.wxSet.wx_video != "" ? { m: $data.wxSet.wx_video } : {}, { n: $data.posTagsList != "" }, $data.posTagsList != "" ? { o: common_assets._imports_1, p: common_vendor.f($data.posTagsList, (item, index, i0) => { return { a: item.thumbnailurl, b: common_vendor.t(item.title.rendered), c: index, d: 1 + index * 0.1 + "s", e: common_vendor.o(($event) => $options.posTap(item), index) }; }) } : {}, { q: $data.no_list_data }, $data.no_list_data ? {} : {}, { r: $data.wxSet.if_subscribe == 1 }, $data.wxSet.if_subscribe == 1 ? { s: common_vendor.t($data.isSubscribed ? "今日已订阅" : "订阅最新内容"), t: common_vendor.o(($event) => $options.showSubscribeMessage(), "01") } : {}, { u: $data.wxSet.if_subscribe != 1 }, $data.wxSet.if_subscribe != 1 ? { v: common_vendor.o(($event) => $options.tarBlack(), "bd") } : {}, { w: common_assets._imports_3, x: $data.detailData.title.rendered, y: $data.posUrl, z: $data.detailData.fr_down_url != "" || $data.detailData.fr_down_file != "" }, $data.detailData.fr_down_url != "" || $data.detailData.fr_down_file != "" ? { A: common_assets._imports_3$1, B: common_vendor.o(($event) => $options.downloadTap(), "ef") } : {}, { C: common_assets._imports_4 }), { D: $data.isAdPopup }, $data.isAdPopup ? { E: common_vendor.o($options.getVideoAd, "76"), F: common_vendor.o($options.getIntegral, "c6"), G: common_vendor.o($options.restoreTap, "56"), H: common_vendor.o($options.tarBlack, "ef"), I: common_vendor.p({ adNumber: $data.adNumber, isIntegral: $data.isIntegral, noPoints: $data.noPoints, fr_ad_points: $data.wxSet.fr_ad_points, fr_videp_integral: $data.detailData.fr_videp_integral }) } : {}, { J: $data.isGuide }, $data.isGuide ? {} : {}); } const MiniProgramPage = /* @__PURE__ */ common_vendor._export_sfc(_sfc_main, [["render", _sfc_render], ["__scopeId", "data-v-98b81aa6"]]); _sfc_main.__runtimeHooks = 6; wx.createPage(MiniProgramPage); //# sourceMappingURL=../../../.sourcemap/mp-weixin/pages/data/data.js.map 【手游解锁】【技术教程】一次关于unity–lua逆向的分析文章 – 弱鸡娱乐网

【手游解锁】【技术教程】一次关于unity–lua逆向的分析文章

【手游解锁】【技术教程】一次关于unity–lua逆向的分析文章

作者:

导语:样本xlua,简单涉及到解密、hook等部分基础逆向。补足个人学习路上该路线的教程贴

【手游解锁】【技术教程】一次关于unity–lua逆向的分析文章

本次样本算是一个比较标准的基础xlua样本,没有涉及到复杂的op还原,以及对dat等关键untiy文件的保护逆向。

简单介绍lua与untiy结合的背景,方便代码进行热更新从服务端拉取下发,unity做好相关承接即可也就是热更新

大部分逻辑将在lua中写明,unity基本为一个空壳

国内常见的是,我的老乡小腾腾公司的xlua,近年版本多为5.3的lua版本

简单执行支持流程dump出dll文件,拉进分析。不出意外没啥有用的东西,毕竟我们逆向方向不在这里

此类游戏,前面提到unityandlua,那么unity肯定有存在相关的注册函数来与lua建立联系就如同jni一样(java的native交互),这类函数一般都是固定的loadbuffer,可能根据不同框架函数名字略有区别比如本次的xlua他在ida中具体的实现为int32_t XLua_LuaDLL_Lua__xluaL_loadbuffer(intptr_t L, System_Byte_array *buff, int32_t size, System_String_o *name, const MethodInfo *method),最重要的参数是字节流buff,和脚本名字name。

关键函数拿下,直接手搓Frida的jshook脚本,核心代码逻辑为,hook该函数读写出buff的参数值,根据name作为文件名写入文件存储到我们的路径上

xlua存储后,我们发现常规的lua反编译使用unluac进行反编译失败,字节码验证不对。

在无进行op重写,以及魔改lua的情况下。我们针对lua框架只需进行字节码的一定修复,原为1B 4C 75 61 53 01 19 93

0D 0A 1A 0A 04 04,需将其改为1B 4C 75 61 53 00 19 93

0D 0A 1A 0A 04 04 04,然后再拖入jar进行反编译即可完成。

结合以上思路,编写Python、js两个Frida脚本将整个流程自动化,js复制hook字节流发送给Python端,Python端完成字节码验证、字节码修复、文件写入、拉起jar修复的完整流程即可获得下面的lua文件

获取完成后仅就只需进行正常的逆向改代码,以及hook替换字节流(配合c方向)

本次教程结束,逆向小白啥也不懂。部分名词有误的地方还请见谅。欢迎更多对uniy+lua、游戏引擎、游戏安全方面的有识之士加入初夏团队 到技术军团中找我交流

#本篇文章,全篇只交代核心逻辑思路,不提供其他脚本代码。希望还未了解此方向的朋友带来一点微不足道的光芒