HGAME2023 WP
Week1
Web
Classic Childhood Game
纯前端实现 -> 代码审计
发现Events.js里有mota()加密函数,输入控制台得Flaghgame{fUnnyJavascript&FunnyM0taG4me}
。
Guess Who I Am
手撸。
Reverse
test your IDA
签到题。
easyasm
汇编白学,我估计后面的Week会有hardasm之类的题目。
题面:
1 | ; void __cdecl enc(char *p) |
exp:
1 | enc = [0x5b,0x54,0x52,0x5e,0x56,0x48,0x44,0x56,0x5f,0x50,0x3,0x5e,0x56,0x6c,0x47,0x3,0x6c,0x41,0x56,0x6c,0x44,0x5c,0x41,0x2,0x57,0x12,0x4e] |
easyenc
exp:
1 | a = [0x04,0xFF,0xFD,0x9,0x01,0xF3,0xb0,0x0,0x0,0x05,0xf0,0xad,0x07,0x06,0x17,0x5,0xeb,0x17,0xfd,0x17,0xea,0x01,0xee,0x1,0xea,0xb1,0x05,0xfa,0x08,0x01,0x17,0xac,0xec,0x01,0xea,0xfd,0xf0,0x05,0x07,0x6] |
encode
exp:
1 | enc = [8,6,7,6,1,6,13,6,5,6,11,7,5,6,14,6,3,6,15,6,4,6,5,6,15,5,9,6,3,7,15,5,5,6,1,6,3,7,9,7,15,5,6,6,15,6,2,7,15,5,1,6,15,5,2,7,5,6,6,7,5,6,2,7,3,7,5,6,15,5,5,6,14,6,7,6,9,6,14,6,5,6,5,6,2,7,13,7] |
a_cup_of_tea
TEA算法的逆向。
exp:
1 | from ctypes import * |
还是搞不清大小端序。
Misc
e99p1ant_want_girlfriend
改长宽。
神秘的海报
LSB+音频隐写。
谷歌云盘文件的下载可以参考这篇文章。
音频隐写考点是弱密码123456(我一开始尝试114514的)。
Week2
Reverse
before_main
变表base64,有啥东西在main函数前面?
在init里面注册了一个地址数组,点进去发现了sub_1228这个函数。
可以确定是变表了。
exp:
1 | import base64 |
不仔细看/不动调的话会以为是原base64加密用的那个表(也是变表),主动防御了属于是。
stream
题面:兔兔假期前学习了编程,你能看出来他学的是什么语言吗
一眼Python。
使用pyinstxtractor工具解包,再反编译.pyc文件即可。
反编译后的.py代码如下:
1 | import base64 |
exp:
1 | import base64 |
math
五阶矩阵乘法逆运算,回忆起了被线性代数支配的恐惧。
还好我有Python。
exp:
1 | import numpy as np |
VidarCamera
安卓逆向,jadx打开,CameraActivity里发现伪Tea加密。
出题人保留Tea的大部分特征,但是也去除了一部分。
“是故意的还是不小心”
“是故意的”
exp:
1 | from ctypes import * |
Crypto
Rabin
Rabin加密,参考这里。
原理是中国剩余定理,可能有多解,选出适合的解即可。
exp:
1 | import gmpy2 |
Misc
Tetris Master
手打俄罗斯方块。
crazy_qrcode
手算二维码(手挖比特币还会远吗)
题目给了一个压缩包和一个扫不了的二维码,尝试修改其纠错码和掩码,发现纠错码为H,掩码为4时可以扫描,得压缩包密码QDjkXkpM0BHNXujs
。进压缩包一看好家伙,一个二维码被等分成25份,每一份随机进行0/90/180/270度旋转。按二维码特征(参照我写的这篇文章)可以恢复成下图。
然后根据“二维码数据从右下角开始向上填充”的原则勉勉强强一点点凑出下图。
可以用qrazybox扫出来了。Flag为hgame{Cr42y_qrc0de}
。
纯真说,可以用Python的Pillow库拼一下然后几张图放屏幕上一扫就出来了,大概我的能力还难以望纯真项背吧。
Week3
Reverse
坐牢局,一题10小时。Week4都没这么坐牢。
是我菜了。
kunmusic
题目给了kmusic.exe,kmusic.dll和kmusic.runtimeconfig.json。
exeinfope一下,知道了是.net框架的。
感谢纯真的提点,知道了.net框架的题目适合用dnSpy。
在kmusic-kmusic.ddl-kmusic-Program-Main()里发现疑似加密代码,动调后观察文件头发现是PE程序,内存窗口里dump出来再次拖入dnSpy得到真正的加密程序。
为了显示方便采用了VB语言,大体思路是用z3解方程然后再逆向解密。需要注意的是方程可能有多解,需要语义分析来增加约束条件。
exp1(z3):
1 | from z3 import * |
把上面的解再代入下面的加密代码即可。
exp2(decrypt):
1 | num = [236,72,213,106,189,86,62,53,120,199,15,93,133] |
patch
问题应该出在gets函数的栈溢出漏洞,需要换成更安全的fgets。patch不出来啊问题是,ChatGPT也没用,只能找判断函数动调了。
按照出题人给的hint:
1 | //检测是否patch成功的部分代码: |
然后一路狂飙去找长相差不多的汇编代码,报错直接跳,关键点在'%'
、'n'
这几个地方,然后改标志位进正确分支就可以了。
需要注意的是在init函数里注册了一个反动调的函数,原理是检测TracerId是否为0,不为0就给你掐了。在exit(0)
的分支前面断一下改一下标志位就好了。
改标志位的位置在下面两个地方:
最后的Flag:
Week4
Reverse
shellcode
go写的玩意,看不懂但能做。如果动调的话需要在文件夹下创建一个inputdir文件夹并写入文件,出来的结果在outputdir文件夹里。逆向的目的就是根据outputdir里已有的flag.enc去找flag。
一个base64,解码完是视觉意义上的乱码。
喂给ChatGPT,它说是x86汇编,再多的它不会了。
喂给艾达女神,发现是TEA加密。
三分逆向七分猜,试了几次出了Flag。
1 | from ctypes import * |
vm
很清楚的虚拟机逆向。
Flag40字节,用judge函数去模拟虚拟机运行。
然后根据code里面的数据去模拟汇编指令,以case 0为例:
进入不同的分支则进行不同的操作,如0 2 0 3
是将寄存器3的值mov到寄存器0中,而0 3 0 3
则是将立即数3mov到寄存器0中。
由此,我们可以模拟出mov
、push
、pop
、add
、sub
、xor
、shl
、shr
、cmp
、jmp
、jz/je
等指令,也可以模拟读取等操作。
重要的是搞清楚a1所模拟的寄存器类型:e0、e1、e2、e3、e4、e5、ip、sp、zf,每32位取低位作为16位寄存器。这点可以从模拟shl的代码看出:
1 | *(_DWORD *)(a1 + 4i64 * code[*(_DWORD *)(a1 + 24) + 2]) <<= *(_DWORD *)(a1 + 4i64 * code[*(_DWORD *)(a1 + 24) + 3]);// vm_shl |
在模拟push
和pop
的分支里我们可以找到模拟栈stack
。
另外注意每条指令执行完ip的增量(即指令长度),然后我们就可以把code里的vm机器码翻译成vm汇编并解读了。
1 | 0, 3, 2, 0, mov e2,0 |
根据条件爆破Flag。
exp:
1 | a1 = [155,168,2,188,172,156,206,250,2,185,255,58,116,72,25,105,232,3,203,201,255,252,128,214,141,215,114,0,167,29,61,153,136,153,191,232,150,46,93,87] |
写在最后
学到的东西越多,越发觉得自己学的东西还不够。
希望新的一年也能和Merak的各位共同努力。