52破解 2022 新春试题
52破解 2022 新春试题

52破解 2022 新春试题

  • 题二—-解题领红包之二 {Windows 初级题}

题目zip

思路

  • 简单题,所以先拖入ida
Frida_Hook   sub_402b70
var base_addr = Module.getBaseAddress("【2021春节】解题领红包之二.exe")
var target_addr = base_addr.add('0x2B70')
//载入后输入23位测试文本->     11111111111111111111111
Interceptor.attach(ptr(target_addr), {
    onEnter: function (args) {
        console.log("Enter sub_402B70() flag_addr:" + args[2])
        console.log("长度:  " + (args[1].toInt32() - args[0].toInt32()) + "    flag:  " + Memory.readUtf8String(args[2]))
    }
});
得到flag文本为    
题二答案得出!无难度
  • 题三—-解题领红包之三 {Windows 中级题}

题目zip

思路

  • 中级题,PE查壳
UPX壳,使用ESP定律脱壳,不细讲,上教程

脱后文件拖入ida

得知sub_401520为比较函数,sub_401100和sub_401080和sub_401110为uid参数处理函数
运行程序,确定两个变量uid和key,在三个入口函数下断调试+ida分析,发现输入字串经过处理后在sub_401520比较flag输出success

遂打算直接还原代码
进入uid处理的三个关键方法(sub_401100,sub_401080,sub_401110)
这三个方法,生成两个参数,并传入sub_401520(1,2,3,4,uid_1,uid_2)进行判断,遂对三个方法进行步入跟踪
sub_401100,sub_401080方法简单,实现过程如下
def sub_401100(uid):
    return uid % 25

def sub_401080(uid):
    return list(range(1, 26, 2))[uid % 12]
sub_401110过于繁琐,我还是太菜了,无法还原,无奈放弃还原思路,直接od动调hook算好的uid_1,uid_2

便更换思路,从sub_401520判断函数下手
在其领空内存发现疑似flag文本   ->    flag{Happy_New_Year_52Pojie_2022}
遂记录下字符串Happy_New_Year_52Pojie_2022
输入测试数据(Happy_New_Year_52Pojie_2022),得出下标
uidkey
123456Bujjs_Hyq_Syul_52Jidcy_2022
123Utkkp_Gbl_Pbto_52Kvyjb_2022
测试数据,收集flag
发现该函数会处理输入字符,并和flag作比较返回int结果
抄起py,输出发现文本处理并无明显规律,重新查看代码
str1 = 'Happy_New_Year_52Pojie_2022'
# str2 = "Utkkp_Gbl_Pbto_52Kvyjb_2022"
str2 = "Bujjs_Hyq_Syul_52Jidcy_2022"
for i in range(27):
    if str1[i] == str2[i]:
        continue
    print("{:3d}-> {} <> {:3d} -> {}    ===  {}".format(ord(str1[i]), str1[i], ord(str2[i]), str2[i],  ord(str2[i]) - ord(str1[i])))
跟入sub_401520,发现内容颇长,动调查看有用部分,前面一大段对flag的处理忽略,后面的释放空间也忽略,得到关键函数sub_4011B0和sub_403ED0,祭出ida,想起刚刚的uid_1和uid_2,得出sub_4011B0为关键函数
sub_4011B0  在ida中分析得知  大小写分类型进行运算   chr(15 * (ord(i) - 20 - num) % 26 + num)  num=大写:65 小写:97
便使用逆推算法,推出本人uid正确的flag
def u1s1(pr):
    for i in string.ascii_letters:
        num = 97 if i.islower() else 65
        if chr(15 * (ord(i) - 20 - num) % 26 + num) == pr:
            return i

str1 = 'Happy_New_Year_52Pojie_2022'
str2 = []
for i in str1:
    print(u1s1(i) if i.isalpha() else i, end="")
代入算出结果发现答案错误,简直怀疑人生了................
后抱着试一试的心态,测试
str1=flag{Happy_New_Year_52Pojie_2022}
结果答案正确,大写的无语..............
算了半个晚上用的都是  Happy_New_Year_52Pojie_2022  属实心态有点蹦了
至此题三结束
  • 题四—-解题领红包之四 {Android 中级题}

题目zip

思路

  • 中级题,安卓题,APK Messenger查壳
跟踪代码,找到入口
发现为native函数,上方为导入so,ida拉入 lib52pojie.so
都是混淆,ida py解混淆的大佬文章读不懂,遂放弃解题
  • 题五—-解题领红包之番外篇 {Web 中级题}

题目zip

解压,文件为52tube.saz和52tube.wacz,saz为Fiddler文件,导入查看
发现为ts视频,查找key和iv
在所有链接中/api/drm较为符合
32位字串
08A5E6C2C261A8ACB4D79C49AF160A3ADA4E5CEAE16FED46EB6F498C9B63D53B
但m3u8中为AES-128-CBC无iv加密,遂排除,虚拟机模拟环境直接搭建
搭建完毕,打开页面,发现29秒视频,但加载失败
参考官网示例
MEDIA_ERR_ABORTED - 取回过程被用户中止
无法找到原因

遂下断点查看

//Uint8Array转字符串
const Uint8ArrayToString=function(fileData) {
	var dataString = "";
	for (var i = 0; i < fileData.length; i++) {
		dataString += String.fromCharCode(fileData[i]);
	}
	return dataString
}

//字符串转Uint8Array
const stringToUint8Array=function(str) {
	var arr = [];
	for (var i = 0, j = str.length; i < j; ++i) {
		arr.push(str.charCodeAt(i));
	}
	var tmpUint8Array = new Uint8Array(arr);
	return tmpUint8Array
}

//Uint8Array转Hex
const U8A2Hex=function(uint8Array) {
	return Array.prototype.map.call(uint8Array, (x) => ('00' + x.toString(16)).slice(-2)).join('');
}

//Hex转Uint8Array
const Hex2Uint8Array=function(hex){
	var typedArray = new Uint8Array(hex.match(/[\da-f]{2}/gi).map(function (h) {
		return parseInt(h, 16)
	}))
	return typedArray
}

//ArrayBuffer转Hex
const B2hex=function(buffer) {
	//return Array.prototype.map.call(new Uint8Array(buffer), x => ('00' + x.toString(16)).slice(-2)).join('');
	return Array.prototype.map.call(new Uint8Array(buffer), x => (x.toString(16)).slice(-2)).join('');
}

//Hex转ArrayBuffer
const Hex2ArrayBuffer=function(hex){
	var typedArray = new Uint8Array(hex.match(/[\da-f]{2}/gi).map(function (h) {
		return parseInt(h, 16)
	}))
	return typedArray.buffer
}
iv    : 000000000000000[0-7]
key : ef8d9c7c7b31b626ab204804ae5852d3
发现key值飘忽不定,否决前面的观点
再次查看drm,发现为post方法,遂逐一检查method
除了该接口,其他都为get,此处的不小心下次一定改
详查可知,ping通后继续访问drm,在此期间生成h和id
o.onSuccess = function(t, e, a) {
	(async function(t) {
		let e = await async function() {
			let t = new Uint8Array(16);
			crypto.getRandomValues(t);
			let e = n(t.buffer) + Date.now() + Math.random();
			return new Uint8Array((await async function(t) {
				const e = (new TextEncoder).encode(t);
				return await crypto.subtle.digest("SHA-256", e)
			}(e)).slice(0, 16))
		}();
		var r = new URLSearchParams;
		r.append("h", n(e.buffer)),
			r.append("id", t);
		var a = {
			method: "POST",
			headers: {
				"Content-Type": "application/x-www-form-urlencoded"
			},
			body: r
		};
		let o = await fetch(i, a),
			l = await o.arrayBuffer();
		if (32 !== l.byteLength)
			throw new Error("Invalid response");
		let u = new Uint8Array(l.slice(0, 16)),
			c = new Uint8Array(l.slice(16, 32));
		return s(s(u, e), c)
	})(r).then((t => {
		l({
			data: t.buffer
		}, e, a)
	}))
}
由代码可知h由e算出,e是根据随机数和时间戳而定的
即 逆向出e的值即可赋值hook
//t=e.buffer
function n(t) {
	return [...new Uint8Array(t)].map((t => t.toString(16).padStart(2, "0"))).join("")
}
由函数n(t)可知,此过程为buffer转hex,所以目标h=7b10311e6e310f0df068d9ede10475a8的对应t->即e为
e=Hex2Uint8Array("7b10311e6e310f0df068d9ede10475a8")
crypto.getRandomValues(t);
let e = new Uint8Array("7b10311e6e310f0df068d9ede10475a8".match(/[\da-f]{2}/gi).map(function (h) {
	return parseInt(h, 16)
}))
修改js,F5,结果如下

得到正确视频,注意s小写

视频提取工具感谢github作者 Momo707577045

https://github.com/Momo707577045/media-source-extract

总结

世上无难事,只怕有心人,不要因为难就放弃,要肯学

ps:题四继续研究