其他
阿里云CTF2024-暴力ENOTYOURWORLD题解
CTF authors, please don't put PhD level math in reverse engineering challenges. thank you.(好吧其实不是PhD level math)
一
脚本文件分析
import lzma
O = b"..."
with open("object", "wb") as f:
f.write(lzma.decompress(base64.a85decode(O)))
二
释放文件分析
tar -xf toolchain-loongarch64-linux-gnu-cross-830-rc1.0-2022-04-22.tar.xz
pushd toolchain-loongarch64-linux-gnu-cross-830-rc1.0-2022-04-22
export TC_HOME=`pwd`
pushd bin
export PATH=$PATH:`pwd`
popd
popd
.rela.text.
这一部分内容过长,不符合常规。不难将这一部分导出为CSV表格文件。三
重定位表分析
mem_delta = 0x01FFFBB5
。此外另从ELF结构读取文件偏移reloca_foff = 0x0000045B
和大小reloca_size = 0x00245940
。source = []
mem_delta = 0x01FFFBB5
reloca_foff = 0x0000045B
reloca_size = 0x00245940
reloca_start = mem_delta + reloca_foff
reloca_end = reloca_start + reloca_size
value_addrs = []
addend_writable_addrs = []
for i in range(reloca_start, reloca_end, 24):
value_addrs.append(i + 16)
addend_writable_addrs.append(i + 16)
addend_writable_addrs.append(i + 20)
with open("reloc.csv") as f:
c = csv.reader(f)
c = list(c)
assert len(c) == len(value_addrs)
modified_value_addrs = []
SP = 0
for (OFFSET, TYPE, VALUE), VALUE_ADDR in zip(c, value_addrs):
if TYPE in ["R_LARCH_SOP_PUSH_PCREL", "R_LARCH_SOP_PUSH_PLT_PCREL"]:
SP += 1
elif TYPE == "R_LARCH_SOP_PUSH_ABSOLUTE":
if VALUE.startswith("*ABS*"):
t1 = VALUE_ADDR
t2 = VALUE_ADDR + 4
lpart = t1 in modified_value_addrs
rpart = t2 in modified_value_addrs
if lpart or rpart:
assert lpart and rpart
source.append(
f"STK_U64_{SP} = ((uint64_t)LOC_U32_{t2:08X} << 32) | LOC_U32_{t1:08X};"
)
SP += 1
else:
if VALUE == "*ABS*":
source.append(f"STK_U64_{SP} = 0;")
SP += 1
else:
source.append(f"STK_U64_{SP} = {VALUE[5:]};")
SP += 1
elif VALUE in ["v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7"]:
source.append(f"STK_U64_{SP} = flag_{VALUE};")
SP += 1
else:
assert False, f"Unknown VALUE {VALUE}"
elif TYPE == "R_LARCH_SOP_SR":
SP -= 1
opr2 = f"STK_U64_{SP}"
SP -= 1
opr1 = f"STK_U64_{SP}"
source.append(f"STK_U64_{SP} = {opr1} >> {opr2};")
SP += 1
elif TYPE == "R_LARCH_SOP_SL":
SP -= 1
opr2 = f"STK_U64_{SP}"
SP -= 1
opr1 = f"STK_U64_{SP}"
source.append(f"STK_U64_{SP} = {opr1} << {opr2};")
SP += 1
elif TYPE == "R_LARCH_SOP_SUB":
SP -= 1
opr2 = f"STK_U64_{SP}"
SP -= 1
opr1 = f"STK_U64_{SP}"
source.append(f"STK_U64_{SP} = {opr1} - {opr2};")
SP += 1
elif TYPE == "R_LARCH_SOP_PUSH_DUP":
SP -= 1
opr1 = f"STK_U64_{SP}"
source.append(f"STK_U64_{SP} = {opr1};")
SP += 1
source.append(f"STK_U64_{SP} = {opr1};")
SP += 1
elif TYPE == "R_LARCH_SOP_AND":
SP -= 1
opr2 = f"STK_U64_{SP}"
SP -= 1
opr1 = f"STK_U64_{SP}"
source.append(f"STK_U64_{SP} = {opr1} & {opr2};")
SP += 1
elif TYPE == "R_LARCH_SOP_ADD":
SP -= 1
opr2 = f"STK_U64_{SP}"
SP -= 1
opr1 = f"STK_U64_{SP}"
source.append(f"STK_U64_{SP} = {opr1} + {opr2};")
SP += 1
elif TYPE == "R_LARCH_SOP_IF_ELSE":
SP -= 1
opr3 = f"STK_U64_{SP}"
SP -= 1
opr2 = f"STK_U64_{SP}"
SP -= 1
opr1 = f"STK_U64_{SP}"
source.append(f"STK_U64_{SP} = {opr1} ? {opr2} : {opr3};")
SP += 1
elif TYPE == "R_LARCH_SOP_NOT":
SP -= 1
v = f"STK_U64_{SP}"
source.append(f"STK_U64_{SP} = !{v};")
SP += 1
elif TYPE == "R_LARCH_SOP_ASSERT":
SP -= 1
v = f"STK_U64_{SP}"
source.append(f"assert({v});")
elif TYPE in [
"R_LARCH_SOP_POP_32_S_5_20",
"R_LARCH_SOP_POP_32_S_10_12",
"R_LARCH_SOP_POP_32_S_0_10_10_16_S2",
]:
SP -= 1
elif TYPE == "R_LARCH_SOP_POP_32_U":
t = int(OFFSET, 16)
if reloca_start <= t < reloca_end:
assert t in addend_writable_addrs
modified_value_addrs.append(t)
SP -= 1
v = f"STK_U64_{SP}"
source.append(f"LOC_U32_{t:08X} = {v} & 0xffffffff;")
else:
SP -= 1
elif TYPE == "R_LARCH_ADD32":
pass
else:
assert False, f"Unknown TYPE {TYPE}"
for i in range(4):
print(f"uint64_t STK_U64_{i} = 0;")
print()
for i in modified_value_addrs:
print(f"uint32_t LOC_U32_{i:08X};")
print()
for i in source:
print(i)
#include <stdint.h>
#include <stdio.h>
uint64_t v0;
uint64_t v1;
uint64_t v2;
uint64_t v3;
uint64_t v4;
uint64_t v5;
uint64_t v6;
uint64_t v7;
char buf[80];
void func()
{
#include "reloc.h"
}
int main(int argc, const char *argv[])
{
scanf("%s", buf);
v0 = ((uint64_t *)buf)[0];
v1 = ((uint64_t *)buf)[1];
v2 = ((uint64_t *)buf)[2];
v3 = ((uint64_t *)buf)[3];
v4 = ((uint64_t *)buf)[4];
v5 = ((uint64_t *)buf)[5];
v6 = ((uint64_t *)buf)[6];
v7 = ((uint64_t *)buf)[7];
func();
return 0;
}
四
还原代码分析
+ (chk_1 != 0x21723CFAFE557F5BLL)
+ (chk_2 != 0x17F625C5B017ED4ALL)
+ (chk_3 != 0xACC2F6A815E0ABBELL)
+ (chk_4 != 0x6FE42391AD85770FLL)
+ (chk_5 != 0x4AFDC5B82BC36032LL)
+ (chk_6 != 0xF513E6C7E2C54367LL)
+ (chk_7 != 0x8B90A1353119C9FBLL)
+ (chk_8 != 0x141196587DA3CFD3LL)
+ (chk_9 != 0x6D4A289D687EE32LL)
+ (chk_10 != 0xAD6D362D3965DCA8LL)
+ (chk_11 != 0x4FF07F315026EA3FLL)
+ (chk_12 != 0x1BE1E40658C8F166LL)
+ (chk_13 != 0xE761EC01EF80841FLL)
+ (chk_14 != 0x5FAF914221BB1C6CLL)
+ (chk_15 != 0xEE40D4E4B790E50BLL)
+ (chk_16 != 0x7C7BA53DDE44DA46LL)
+ (chk_17 != 0x4861E5170730111BLL)
+ (chk_18 != 0x8E1396D18B199C64LL)
+ (chk_19 != 0x2B65B265EE427F7CLL) == 0
((unsigned __int64)flag_v2 >> 32) + (flag_v3 << 32)
((unsigned __int64)flag_v4 >> 32) + (flag_v5 << 32)
((unsigned __int64)flag_v6 >> 32) + (flag_v7 << 32)
v1 = BYTE4(flag_v6) & 1;
v2 = 2 * v0;
v3 = 0LL;
if ( flag_v6 & 0x100000000LL )
v3 = ((unsigned __int64)flag_v6 >> 32) + (flag_v7 << 32);
v138 = v0 >> 63;
if ( (v0 & 0x8000000000000000LL) != 0LL )
v2 = v2 - 6851306870693981165LL - 2 * (v2 & 0xA0EB44B36D179413LL);
/* ... */
if ( v138 )
v3 = v3 + v73 - 2 * (v73 & v3);
v74 = 2 * v3;
if ( flag_v6 & 0x100000000LL )
v1 = v3;
if ( v3 < 0 )
v74 = v74 - 6851306870693981165LL - 2 * (v74 & 0xA0EB44B36D179413LL);
/* ... */
if ( v138 )
v1 = v1 + v136 - 2 * (v136 & v1);
五
数学?暴力!
flag_v0
到flag_v7
(8字节,64位)。flag_v?
(8字节,64位)拥有2个杂凑算法结果(8字节,64位)。flag_v?
的后半部分和后一个flag_v(?+1)
的前半部分拼接(8字节,64位)拥有1个数域运算结果(8字节,64位)。flag_v?
的一半部分(4字节,32位),再暴力枚举剩余一半部分(4字节,32位)。看雪ID:UserXCh
https://bbs.kanxue.com/user-home-726188.htm
# 往期推荐
2、.NET 恶意软件 101:分析 .NET 可执行文件结构
3、CVE-2024-0015复现 (DubheCTF DayDream)
球分享
球点赞
球在看
点击阅读原文查看更多