作者论坛账号:pandamon
解题领红包之二 {Windows 初级题} 查壳,无壳
运行程序看一下
拖进od,搜字符串,找到please input password,以及附近的tip: flag长度为23
双击please input password,在该处硬件断点,运行
堆栈窗口看到字符串,长度也为23,可能就是flag
试输入,正确,得到flag为2022HappyNewYear52PoJie
解题领红包之三 {Windows 中级题} 查壳,可能是有修改的upx,要先脱壳
先用52虚拟机脱壳,拖进od,走一步,ESP定律,在ESP寄存器上右键,数据窗口中跟随
然后右键,断点-硬件访问-byte
然后运行程序,停在4240C6,上面是popad,下面不远处一个大jmp,推测接近OEP
运行到4240D3该jmp处,然后单步一次,到40B37B的push处,应为OEP
Ollydump脱壳
脱壳结果ExeinfoPE看不出,用PEID看应该是脱了
运行程序看一下
拖回实机上的IDA,看流程,首先是Input your UID:,然后到Input your Key:,最后根据某种判断条件跳到Success或Error。
在Success处F5得到伪代码,显然地,sub_401520内有判定flag是否正确的条件
双击点进sub_401520,它的返回值以v8变量为判断条件决定返回值为0或1
if ( v8 )
{
//省略其他代码
return 0;
}
else
{
//省略其他代码
return 1;
}
上面代码省略处为与分析返回值逻辑关系不大的代码,太长截不了图用文字表示
根据以上条件可知需要sub_401520返回1,就需要v8=sub_403ED0的返回值为0
双击点进sub_403ED0,看到以下和返回值有关的代码
因为需要返回值为0,根据该逻辑就需要memcmp返回0,且v5==v3
接下来在IDA中进行动态调试,先在伪代码17、18、20行下断点,输入我的UID,在key处我随便输了个114514,停在17行。鼠标放在v4变量上能看到疑似flag:flag{Happy_New_Year_52Pojie_2022}
停止调试重新运行程序,但测试发现flag不对
继续看IDA,在第17行的第一个参数处拆分内存访问
得到新的伪代码如下图所示
在新伪代码的22行下断点,在IDA中运行,输入UID和key:flag{Happy_New_Year_52Pojie_2022},停在伪代码22行后查看变量v7为ikpr{Apuux_Czf_Xzpm_52Ulsjz_2022},v4仍为flag{Happy_New_Year_52Pojie_2022}
推测v7的值是对输入的flag{Happy_New_Year_52Pojie_2022}的字母部分做了某种变换,遂输入与flag等长的连续33个a,得到v7为连续33个p,故推测该变换与其为何种字母有关,与其在字符串中的位置无关。
为了获得该变换的规则,输入abcdefghijklnmopqrstuvwxyzABCDEFGHIJKLNMOPQRSTUVWXYZ,得到v7为pyhqzirajsbkctludmvenwfoxgPYHQZIRAJSBKCTLUDMVENWFOXG
从而得到了变换规则,将之前找到的flag{Happy_New_Year_52Pojie_2022}进行逆变换,得到wohz{Chaab_Utv_Bthg_52Axift_2022},测试显示success,为正确flag
解题领红包之番外篇 {Web 中级题}
用fiddler打开52tube.saz,把文件保存出来
/api/drm/包含疑似密钥为32byte,但m3u8里是AES-128加密,应是16byte的密钥,此处不对,先看js,查找“/api/drm/”字符串,相关代码如下所示
let e = "/api/ping/", i = "/api/drm/";
function n(t)
{
return [...new Uint8Array(t)].map((t => t.toString(16).padStart(2, "0"))).join("")
}
function s(t, e)
{
let r = new Uint8Array(t.length);
for (let i = 0; i < t.length; i++) {
r[i] = t[i]^e[i];
}
return r
}
class a extends t.DefaultConfig.loader
{
constructor(t)
{
super (t);
var r = this.load.bind(this);
this.load = function (t, a, o)
{
if (t && t.url.startsWith("key://"))
{
let r = t.url.substr(6);
t.url = e;
var l = o.onSuccess;
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)
}))
}
}
r(t, a, o)
}
}
}
显然,s(t,e)是一个按位异或,return s(s(u, e), c);可能为解密密钥
let u = new Uint8Array(l.slice(0, 16)), c = new Uint8Array(l.slice(16, 32)); 处可看出32byte密钥的前半部分为u,后半部分为c
var r = new URLSearchParams; r.append("h", n(e.buffer)), r.append("id", t); 处可看出e为URL参数h,在fiddler的/api/drm/处可找到
u=08a5e6c2c261a8acb4d79c49af160a3a
c=da4e5ceae16fed46eb6f498c9b63d53b
e=7b10311e6e310f0df068d9ede10475a8
解密密钥为u异或e异或c= a9fb8b364d3f4ae7afd00c28d571aaa9
然后找了个现成的ts解密工具(ts助手)解密得到mp4,播放mp4视频得到flag{like_sub_52tube}
我太菜,安卓题没做出来,今后需要继续学习
活动已结束,题目打包放到爱盘供大家下载学习:
https://down.52pojie.cn/Challenge/Happy_New_Year_2022_Challenge.rar
欢迎发帖讨论分享分析过程和结果。
--官方论坛
www.52pojie.cn
--推荐给朋友
公众微信号:吾爱破解论坛
或搜微信号:pojie_52