From 97a35ab0e2aa207d1820c783b68fc83a0ece66b1 Mon Sep 17 00:00:00 2001 From: github-actions <41898282+github-actions[bot]@users.noreply.github.com> Date: Sun, 25 Feb 2024 05:50:52 +0000 Subject: [PATCH] [U] Generate json --- content/generated/metas.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/generated/metas.json b/content/generated/metas.json index 32e2a54..b9a208d 100644 --- a/content/generated/metas.json +++ b/content/generated/metas.json @@ -3,7 +3,7 @@ "categories": [["置顶", 1], ["技术", 1], ["日记", 2], ["梦", 1], ["想想想", 1], ["影评", 1]], "pins": [11], "posts": [ - {"id": 11, "title": "部落格索引", "subtitle": "按分类、标签检索", "category": "置顶", "pinned": 1, "file": "content/posts/Index.md", "tags": [], "date": "2023-11-30T08:03:51.417049", "url_name": "Index", "content": "按分类检索:\n\n\n\n按主题检索:\n\n"}, + {"id": 11, "title": "部落格索引", "subtitle": "按分类、标签检索", "category": "置顶", "pinned": 1, "file": "content/posts/Index.md", "tags": [], "date": "2024-02-25T05:50:46.528141", "url_name": "Index", "content": "按分类检索:\n\n\n\n按主题检索:\n\n"}, {"id": 10, "title": "Maimai 街机音游逆向!", "subtitle": "从拆包到脱壳到魔改遇到的各种坑", "tags": ["ctf"], "file": "content/posts/2023-11-30 Maimai Reversing.md", "date": "2023-11-30T00:00:00", "url_name": "2023-11-30-Maimai-Reversing", "content": "不久之前某位朋友拿到了最新最热的 maimai DX 某版本的 .app 镜像,然后和ta一起折腾了几天拆包脱壳之后终于成功启动了!在这里简单写一下解包过程和学到的事情,作为记录也作为一个教程吧,希望之后尝试解包的人不需要踩同样的坑了。\n\n## 0x1 解压 .app 包\n\n首先,朋友拿到的文件是一个 .app,通常在官方渠道中通过 U 盘或者网络下发给官方的街机框体,这也是所有 Sega 游戏都在用的传统格式。解压起来也已经有工具和教程。首先 .app 是使用 AES128 加密的,是一个对称密钥加密算法,然而已经有人帮忙把真正街机上的密钥复制出来了,接下来就是按教程解密啦,工具和教程都在[这个仓库](https://gitdab.com/SEGA/sega/src/branch/master/tools/Filesystem)里面。\n\n解密之后是一个两层的 VHD 文件。第一层似乎文件元信息是坏的,大部分硬盘工具分区工具解压工具都打不开,不过试了各种方案发现在 Linux 上用 qemu-nbd 可以挂载,虽然会报错。挂载用了下面那一串指令,之后把 /mnt 里面的第二层 VHD 拷出来就可以直接用 7zip 解压了。\n\n```sh\nsudo modprobe nbd\nsudo qemu-nbd -c /dev/nbd0 \"outer.vhd\"\nsudo mount /dev/nbd0 /mnt\n# /mnt 里面应该有 internal_{N}.vhd\n```\n\n下面分别是两层 VHD 的文件头和 file 信息,`conectix` 开头的是第二层,`eb5290 NTFS` 开头的是第一层(以下用旧版中二节奏举例):\n\n\n\nqemu-nbd 加载了第一层之后连 fdisk 都是懵的,即使是这样乱来也能挂载上也真是好神奇:\n\n\n\n## 0x2 Crackproof 脱壳\n\n解开 .app 包之后脱壳反而是最难的步骤,因为没有找到任何针对 SEGA 街机的脱壳教程(所以我才在写这篇教程!)解压好文件之后发现直接运行会闪退,为什么呢?用文件识别工具 [DIE (detect it easy)](https://github.com/horsicq/Detect-It-Easy) 检测一下发现主程序 Sinmai.exe 被一个叫 HyperTech Crackproof 的工具加密过 (aka. “Htpac”)。\n\n\n\n啊但是 Sinmai.exe 明明就只是一个 Unity 启动器,Unity 的话所有游戏的启动器都是一样的,让每个游戏不同的是 {Game}\\_Data 里面的 dll 文件,所以我直接去下了一个[开源 GTA 圣安地列斯](https://github.com/GTA-ASM/SanAndreasUnity)然后把启动器拷出来改名成 Sinmai.exe 就可以了!\n\n\n\n...然后还是没法启动,怎么回事呢?用 `diec` 扫描一下目录里面的所有 exe 和 dll 发现还有四个文件是加密过的:\n\n* amdaemon.exe\n* Sinmai\\_Data/Managed/Assembly-CSharp.dll\n* Sinmai\\_Data/Plugins/Cake.dll\n* Sinmai\\_Data/Plugins/amdaemon_api.dll\n\n查了一下,首先我看到 SEGA 工具库里面有一个叫 [DecryptCrackproof](https://gitdab.com/SEGA/sega/src/branch/master/tools/Crackproof/DecryptCrackproofExe64) 的工具,感觉这个尝试起来是最简单的,所以就先用它试了一下。这个工具确实自动解出来了 amdaemon.exe,但是剩下三个 DLL 都失败了,报错说 CRC32 算法的长度 out of range of valid values。\n\n\n\n看着这个报错,第一眼觉得应该是这个算法实现的问题,毕竟从 stack trace 可以看出传给 CalcChecksum 的参数是 UInt32,而 CRC32 函数接收的参数是 Int32... 会不会是长度超了 Int32 的最高值呢?所以就用 DotPeek 反编译、导出项目重新编译再 Debug 饶了一大圈,然后发现并不是长度超过 Int32 最高值,而是超过了整个文件的长度... 而请求长度又是一串非常不标准的计算算出来的,看来应该是 HyperTech 他们换了加密算法,并不是改一两行就能修好的。\n\n\n\n接下来有点没有头绪,到处查查也没有查到有用信息,有一个 [iatrepair](https://github.com/rakisaionji/iatrepair) 仓库的脱壳思路是开一个 QEMU 有 2GB 内存的 VM 里面跑游戏,等游戏加载完之后把整个系统的内存 dump 出来再解包分析... 感觉这个方法好灵车,而且这个加密也会检测系统是不是 VM。\n\n接下来去群里问了问,群友给我了一份街机系统上会有的 odd.sys 驱动,用 OSRLoader 加载进系统就可以启动游戏了,虽然是黑屏而且不能正常启动 amdaemon。原本以为解密代码在驱动里面,所以先用 IDA Pro 打开驱动看看能不能提取出来,但是发现似乎只有一些 hashing 的 PID 验证和字符串处理,返回一个处理过的字符串,这样看来这个驱动应该是让用户进程上传识别信息来生成真正解密密钥的工具。\n\n\n\n但是感觉要反汇编找到真正解密的代码再重新实现出来有点太复杂了... 还是试试直接从内存里面找吧。\n\n下载一个 CheatEngine 用来查看内存,然后启动游戏。刚开始发现 CheatEngine 的调试器挂到 Sinmai 进程上会报错,上网查了一下说可以试试在设置的调试器选项里开 DBVM 内核驱动模式,再把 Extras 里面的用内核模式浏览内存选上,然后果然就可以挂了!\n\n\n\n接下来打开内存视图,先看了一遍 Memory Regions 里面标注的 DLL 名,但是似乎没有我想要找的 DLL 的样子。那怎么办呢?看看有没有只属于这个 DLL 的可识别信息吧,用 hexed.it 打开上一代别人解包好的 Assembly-CSharp.dll 发现文件末尾有一串元信息,写着 \"InternalName Assembly-CSharp.dll\",每个字符中间间隔着一个 NULL \\\\0 字符。\n\n\n\n所以我在 CE 内存视图里面搜这段文字然后就找到了!正好只有一个匹配结果。然后记录一下最左边的地址,打开内存区域视图找到这个地址所属的区域,右键把整个区域存下来,然后用 hexed.it 打开把 CE 的文件头去掉(截到 DLL 文件头那里)再把文件尾补到整 32 位,保存改名成 DLL 就可以了!\n\n\n\n之后就只差 Cake.dll 和 amdaemon_api.dll 了,可惜这两个我用同样的方法没有解出来。amdaemon_api 在游戏里并没有加载,而 Cake 是一个包含了依赖的 dll,被拆成了很多不同的内存区域导致让它完整结合回去比较麻烦,但是这两个文件在不同版本中几乎没有改动,所以就直接拿上一个版本别人脱好壳的用了(一般会放在 segatools 文件夹里一起发出来)\n\n## 0x3 魔改\n\n可惜脱完 dll 壳并不是直接就能玩,还要去掉一些街机验证。因为 maimai 是一个 Unity 游戏,是用 C# 写的,而众所周知 .NET 运行时的结构和 Java 差不多都是反编译出来几乎直接是源码的,所以魔改思路就是把 Assembly-CSharp 反编译成源码,改好所有的代码报错,改掉验证然后再编译回去啦。\n\n\n\n...结果还在修报错的时候发现朋友已经魔改完了,所以就先用别人的啦,具体需要做哪些魔改等下次拿到最新最热数据再研究好了 qwq\n\n## 0xF 总结\n\n总之这是我第一次做 Windows 二进制程序脱壳,感觉有别人写好的文档和群友帮忙也没有想象的那么难(以前打 CTF 从来都不敢碰 binary 题的呜呜呜)虽然是朋友先解出来魔改完了有点扫兴,但是学到了很多脱壳技巧还是很开心的!现在就差给 [AquaDX](https://github.com/hykilpikonna/AquaDX) 加服务器支持了...(下次再写 qwq"}, {"id": 9, "title": "CyberSci 2023 CTF 网安比赛 Writeup", "subtitle": "你是来打网安还是修 Bug 的?🌚", "tags": ["ctf"], "file": "content/posts/2023-11-18 CyberSci Canada Writeup.md", "date": "2023-11-18T00:00:00", "url_name": "2023-11-18-CyberSci-Canada-Writeup", "content": "我解的五道题都是 Defense 分类的,Defense 规则是修好一个服务器端让攻击方的 PoC 脚本失效就能拿分(这不是我维护服务器日常做的事情吗 ;-;\n\n前三道题「CFP」是一套 PhP + Nginx 写的用来上传作业文档的服务器,后两道题「Swag Shop」是一套 Go GIN 写的购物服务器,全都跑在 docker compose 容器里(然而这两个语言我都没用过呜呜呜)\n\n知道问题的时候修一个 bug 很容易,但是 PoC 机并不会告诉你 bug 在哪里,所以解题的第一步是去查 HTTP log 找到被攻击的方法。\n\n## 前三道题 - Call for Presentations\n\n### Attack 1\n\n前三道题的部署结构我真的太熟悉了,因为我自己的所有服务器都是 Nginx + Docker,直接 `tail -f /var/log/nginx/access.log` 读出所有的请求,整理出一个攻击从开始到结束的所有请求,再 `cat /tmp/nginx-req-body/{n}/` 来读出每个请求内容。看一下请求过程如下:\n\n1. 注册一个帐号\n2. 登录这个帐号\n3. 换一个不同的密码登录这个帐号还登进去了??\n\n啊所以难道给我的这套代码登录甚至没有验证密码的吗 (╯’ – ‘)╯︵ ┻━┻\n\n
欣赏一下屎山代码
\n\n看看源代码 lib.php 确实数据库密码验证逻辑写得乱七八糟,数据库直接 string concat,密码甚至没 hash... 好直接让 GPT4 重写了一遍登录和注册这两个函数,然后 PoC 就失效了,拿分拿分 🌚\n\n
GPT4 帮我修好了!
\n\n(不过我至今没弄懂 PhP 要怎样把 log 打到能看到的地方... 打比赛的时候试了几个不同的方法都看不到 log 就算了算了直接把 curl hydev.org/say 写进去了,发到 /say 的东西会转发到我的 Telegram 上hhhh\n\n### Attack 2\n\n第一个好简单。第二个攻击的请求乍一看好像没什么问题,但是仔细看看就会发现 PoC 机注册的帐号的名字和请求提交的 JWT Token 名字不一样然后还莫名过签证验证了... 为什么呢?\n\n
第二个攻击的 Log
\n\n看一眼代码确实,签名居然不是密码学签名,而是直接把请求 JWT 里面的东西 hash 了一遍,验证签名和 hash 相等???🫠 这种客户端能生成的东西还算签名吗?算了交给 GPT4 去改,果然改完就过了。\n\n### Attack 3\n\n第三个攻击感觉是最简单的,看日志内容发现用户上传了五个不同的文件,但是看请求内容那一步就马上发现不对劲了——五个文件中有一个是 PhP 文件,里面是攻击代码,居然直接以 .php 结尾被传进代码旁边的子目录了。泰经典辣,甚至没有用 GPT4,直接给 portal.php 上传文件的代码加一个文件结尾检查就过了(虽然如果是现实中真的遇到这种情况的话肯定要检测文件内容的)\n\n## 后二道题 - Swag Shop\n\n上一道题因为是 PhP,改完代码直接 `compose up --build -d` 重新跑容器也只要几秒。但是这两道题是用 Go 写的,而 Go 是需要编译的语言,所以发现的第一件事情是 `docker build` 居然要两分钟 (╯’ – ‘)╯︵ ┻━┻\n\n磨刀不误砍柴工,先把本地 Go 环境和依赖装上,把 SSL cert 挪到该放的地方,带缓存的编译重跑就只需要不到一秒了。\n\n\n\n### Attack 1\n\n第一道题非常非常简单,跑起来之后看 HTTP 访问日志马上就看到了一条野生 SQL 语句 👀 原来要修的是 SQL 注入。看看代码,main 里面定义了这个 `/shop/items/:item` 节点的函数是 DescribeItem(),把整个函数拷给 GPT4 重写拿分()\n\n
GPT4 不知道今天帮了我多少忙
\n\n### Attack 2\n\n第二道题我觉得是这五道题里面最难的,因为攻击方法并不明显。整个日志看起来都非常正常,我为了让日志看起来更整洁还隐藏了签名验证的部分,日志里实现的操作都是用户正常使用会用到的,管理员创建了几个商品,删了两个商品,用户读了一次商品列表,然后买了一件,感觉没有哪里不对。\n\n
非常正常的日志
\n\n看了超级超级久还没发现问题,但是把签名打出来发现了不同请求的签名长度不一样,所以猜猜可能是签名验证的问题就去检查了一下签名验证的代码,然后发现了这堆鬼东西:\n\n
他们自己实现了一个 ASN 验证,后面是五百行的我都看不懂的纯正密码学
\n\n不懂就不要随便自己实现加密算法啊啊啊 (╯’ – ‘)╯︵ ┻━┻\n\n密码学真的有太多我看不懂的理论数学,所以我也看不出他们的实现有没有 Bug,但是总之先试试让 GPT4 用标准库重写一遍 VerifyASN 吧... 重写完重跑一遍居然就真的就过了 🌚\n\n## 总结\n\n总之五道 Defense 题全都解出来啦,然后看时间不够快赶不上 One Among Us 的手工活动就赶快走了。感觉很开心!这是我参加的第一个有 Defense 题型的 CTF,感觉是和 Web 题完全反过来的题型。Defense 少见可能是因为这种题比较难封沙盒吧,不过第一次知道原来像我这样的平凡全栈技能也能在 CTF 上起到作用。\n\n原本登记了这次比赛只是因为 UofTCTF 他们组缺人,去之前还觉得自己一年没打过 CTF 了说不定一道题都做不出来呢,结果发现并没有全都忘掉也很开心。居然比同组的那些 UofTCTF 活跃队员分还高一些(不过也是因为 Defense 题更简单啦)总之虽然已经退坑了但是偶尔打打 CTF 还是很好玩的!"}, {"id": 8, "title": "开源打击琴!第二天", "subtitle": "绝赞设计中 ⭐️", "tags": ["open-keyprec"], "file": "content/posts/2023-03-15 OKP Day 2.md", "date": "2023-03-15T00:00:00", "url_name": "2023-03-15-OKP-Day-2", "content": "#open-keyprec 开源打击琴的第二天\n\n今天在设计琴键布局呢,决定了做五个八度的马林巴琴布局,从 C2 到 C7 一共 61 个琴键。为了不用手动复制 60 遍写了脚本自动生成琴键!FreeCAD 可以用 py 写脚本真是省了不知道多少时间哇(虽然学 API 可能用了更久hhh)。原本是按照 78-194mm 等比例分布琴键长度,但是觉得看起来太规整了,改成用三点的方式找到了一个抛物曲线计算长度,效果好棒!\n\n
生成的 61 个琴键模型,高度是条抛物线
\n\n然后算下来打印时间大概要 91.5h,如果 24h 无间断打印的话要 3.8 天... 今天发现 Cura 的一个实验性功能可以让多个模型在同一个平台上顺序打印,很灵车但是好想试试,如果可以的话睡觉的时候也能让打印机工作了(打印机加油!\n\n真正打印的时候才发现这个打印机有好多问题,果然不应该相信半价全新... 首先是自动调平不工作,而且因为这款 \"Smart\" 打印机的受众是富家小孩,设计师去掉了需要耐心的手动调平旋钮。研究了一下发现是固件逻辑每次回零都会把调平 Mesh 关掉,也就是说自动调平完全没有用到。解决方案就是在 GCode 开始段回零之后加一句 `M420 S1` 重新启用调平... 创想啊你完全不测试你的代码么 (╯’ – ‘)╯︵ ┻━┻\n\n
自动调平 Mesh 可视化(好歪!)
\n\n然后看到印床底下有一颗孤零零的螺丝 ;-;;; 估计要拆下整个 y 轴才能取出来,好麻烦啊,不过有一点点小风险也没关系?\n\n
卡在床下面的螺丝
\n\n今天下午和聊聊去拼装模型爱好者的店买了喷漆罐,打算喷成 V7530BCF 那样的金属黑色。给 PLA 喷漆也很讲究呢,需要先喷 Primer,喷漆,再喷保护层,还要一个通风柜... 原本想在厕所开上换气喷,但是看到成分里含有机溶剂,只能等天暖在外面喷了呜呜。\n\n晚上复用器芯片到了,因为 D1 ESP32 控制板只有六个模拟输入,用来接 61 个琴键肯定不够,所以就改成了用四个 16 输入的复用器去读四个输入啦。去焊了四片芯片上的 96 个引脚。开始焊之前觉得 96 个引脚好多好可怕,但是熟练之后发现其实可以很快的,焊最后一个芯片的 24 根引脚只花了两分钟,离成为一个合格的工程师更近了!零件还缺 60 个 1MΩ 电阻和 60 个二极管和一些转接头就收集齐了!"},