-
-
[原创]KCTF2022春季赛第三题 解题过程
-
发表于: 2022-5-16 00:33 7636
-
题目流程比较简洁,初步判断该exe定义了一个大的结构体进行操作,简单根据偏移量进行了结构体判断。
重新对main进行解析,比较友好了。
存在较多的反调试。
流程较为清晰:
1、keys = MD5(Enj0y_1t_4_fuuuN)
2、AES(keys , 16bytes , plain , cipher , 32bytes) == byte_40B200[0:20]
直接进行解密计算发现是乱码,判断算法进行了改变。
直接使用题目中的MD5(Enj0y_1t_4_fuuuN),反正不会改变,看了别人的帖子才注意到这里修改了MD5的常数值。
整个AES算法结构比较标准,在正常的128bit密钥流程中增加了对16字节输入输出的转置操作。
需要找一份类似的代码实现。
密钥扩展函数正常。
字节替换函数中,查表方式没变,但是查看交叉引用时,发现sub_402330函数对其进行了修改。
原S盒中的:SBox[0x71] = 0xa3、SBox[0xa3]=0x0a,
这里修改为了:SBox[0x71] = 0x0a、SBox[0xa3]=0xa3
因此解密inv_sub_bytes的时候,RBox也应该进行相应的修改:
原本RBox[0xA3] = 0x71、RBox[0x0A] = 0xA3
修改为:RBox[0xA3] = 0xA3、RBox[0x0A] = 0x71
反编译时提示401bef无法转换,直接nop掉反调试的指令。
该题目对行变换函数进行了修改。直接分析16字节输入,魔改的变换如下:
0 1 2 3 -> 0 1 2 3
4 5 6 7 -> 7 4 5 6
8 9 10 11 -> 10 11 8 9
12 13 14 15 -> 13 14 15 12
在进行inv_shift_rows直接对如上变换方式进行逆变换即可。
列混淆函数中,计算时取的是state矩阵的转置,在编写Inv_MixColumn时也在取计算结果时,取state矩阵的转置。
加轮密钥中,也对要异或的16字节密钥进行了转置操作ExtendKey[i][j] = u32Extendkey[j] >> (8 * (3 - i))。解密时直接调用该函数即可。
根据对AES加密函数相应的修改,编写对应的解密函数。直接对byte_40B200开始的32字节进行解密,发现不对,直接获取内存值发现有修改,查看交叉引用,发现sub_4023D0对校验值进行修改。求解得到flag。
struct context{
int
iterator1;
/
/
0
int
unknow1;
/
/
1
unsigned
int
md5[
5
];
/
/
2
-
6
int
unknow7;
/
/
7
int
unknow8;
/
/
8
byte keys[
16
];
/
/
9
-
12
int
unknow13;
/
/
13
int
unknow14;
/
/
14
int
unknow15;
/
/
15
int
iterator2;
/
/
16
int
unknow17;
/
/
17
unsigned
int
cipher[
10
];
/
/
18
-
27
int
unknow28;
/
/
28
int
unknow29;
/
/
29
char sn[
4000
];
int
a3;
int
a4;
};
struct context{
int
iterator1;
/
/
0
int
unknow1;
/
/
1
unsigned
int
md5[
5
];
/
/
2
-
6
int
unknow7;
/
/
7
int
unknow8;
/
/
8
byte keys[
16
];
/
/
9
-
12
int
unknow13;
/
/
13
int
unknow14;
/
/
14
int
unknow15;
/
/
15
int
iterator2;
/
/
16
int
unknow17;
/
/
17
unsigned
int
cipher[
10
];
/
/
18
-
27
int
unknow28;
/
/
28
int
unknow29;
/
/
29
char sn[
4000
];
int
a3;
int
a4;
};
int
__cdecl main_0(
int
argc, const char
*
*
argv, const char
*
*
envp)
{
void
*
v3;
/
/
esp
int
result;
/
/
eax
char v7;
/
/
[esp
-
10h
] [ebp
-
1048h
]
context ctx;
/
/
[esp
+
0h
] [ebp
-
1038h
] BYREF
CPPEH_RECORD ms_exc;
/
/
[esp
+
1020h
] [ebp
-
18h
]
v3
=
alloca(
4128
);
memset(&ctx,
0xCCu
, sizeof(ctx));
ms_exc.registration.ScopeTable
=
(ms_exc.registration.ScopeTable ^ __security_cookie);
memset(ctx.sn,
0
, sizeof(ctx.sn));
ctx.cipher[
0
]
=
0
;
ctx.cipher[
1
]
=
0
;
ctx.cipher[
2
]
=
0
;
ctx.cipher[
3
]
=
0
;
ctx.cipher[
4
]
=
0
;
ctx.cipher[
5
]
=
0
;
ctx.cipher[
6
]
=
0
;
ctx.cipher[
7
]
=
0
;
ctx.cipher[
8
]
=
0
;
ctx.cipher[
9
]
=
0
;
gets_s(ctx.sn,
4000u
);
if
( strlen(ctx.sn)
=
=
32
)
{
for
( ctx.iterator2
=
0
; ctx.iterator2 <
512
;
+
+
ctx.iterator2 )
{
ctx.unknow15
=
0
;
MEMORY[
0
]
=
ctx.iterator2;
ms_exc.registration.TryLevel
=
0xFFFFFFFE
;
}
strcpy(ctx.keys,
"Enj0y_1t_4_fuuuN"
);
/
/
16bytes
_DX
=
0x5F00
;
*
(&ctx.unknow13
+
1
)
=
0
;
HIBYTE(ctx.unknow13)
=
0
;
ctx.md5[
0
]
=
0
;
ctx.md5[
1
]
=
0
;
ctx.md5[
2
]
=
0
;
ctx.md5[
3
]
=
0
;
ctx.md5[
4
]
=
0
;
for
( ctx.iterator1
=
0
; ctx.iterator1 <
512
;
+
+
ctx.iterator1 )
{
__asm { insb }
ms_exc.registration.TryLevel
=
-
2
;
_DX
=
LOWORD(ctx.iterator1)
+
1
;
}
j_MD5_402DB0(ctx.keys,
0x10u
, ctx.md5);
j_aes_402070(ctx.md5,
0x10u
, ctx.sn, ctx.cipher,
32
);
if
( !memcmp(ctx.cipher, byte_40B200,
0x20u
) )
printf_401037(
"OK\n"
, v7);
else
printf_401037(
"NO\n"
, v7);
result
=
0
;
}
else
{
printf_401037(
"NO\n"
, v7);
result
=
0
;
}
return
result;
}
int
__cdecl main_0(
int
argc, const char
*
*
argv, const char
*
*
envp)
{
void
*
v3;
/
/
esp
int
result;
/
/
eax
char v7;
/
/
[esp
-
10h
] [ebp
-
1048h
]
context ctx;
/
/
[esp
+
0h
] [ebp
-
1038h
] BYREF
CPPEH_RECORD ms_exc;
/
/
[esp
+
1020h
] [ebp
-
18h
]
v3
=
alloca(
4128
);
memset(&ctx,
0xCCu
, sizeof(ctx));
ms_exc.registration.ScopeTable
=
(ms_exc.registration.ScopeTable ^ __security_cookie);
memset(ctx.sn,
0
, sizeof(ctx.sn));
ctx.cipher[
0
]
=
0
;
ctx.cipher[
1
]
=
0
;
ctx.cipher[
2
]
=
0
;
ctx.cipher[
3
]
=
0
;
ctx.cipher[
4
]
=
0
;
ctx.cipher[
5
]
=
0
;
ctx.cipher[
6
]
=
0
;
ctx.cipher[
7
]
=
0
;
ctx.cipher[
8
]
=
0
;
ctx.cipher[
9
]
=
0
;
gets_s(ctx.sn,
4000u
);
if
( strlen(ctx.sn)
=
=
32
)
{
for
( ctx.iterator2
=
0
; ctx.iterator2 <
512
;
+
+
ctx.iterator2 )
{
ctx.unknow15
=
0
;
MEMORY[
0
]
=
ctx.iterator2;
ms_exc.registration.TryLevel
=
0xFFFFFFFE
;
}
strcpy(ctx.keys,
"Enj0y_1t_4_fuuuN"
);
/
/
16bytes
_DX
=
0x5F00
;
*
(&ctx.unknow13
+
1
)
=
0
;
HIBYTE(ctx.unknow13)
=
0
;
ctx.md5[
0
]
=
0
;
ctx.md5[
1
]
=
0
;
ctx.md5[
2
]
=
0
;
ctx.md5[
3
]
=
0
;
ctx.md5[
4
]
=
0
;
for
( ctx.iterator1
=
0
; ctx.iterator1 <
512
;
+
+
ctx.iterator1 )
{
__asm { insb }
ms_exc.registration.TryLevel
=
-
2
;
_DX
=
LOWORD(ctx.iterator1)
+
1
;
}
j_MD5_402DB0(ctx.keys,
0x10u
, ctx.md5);
j_aes_402070(ctx.md5,
0x10u
, ctx.sn, ctx.cipher,
32
);
if
( !memcmp(ctx.cipher, byte_40B200,
0x20u
) )
printf_401037(
"OK\n"
, v7);
else
printf_401037(
"NO\n"
, v7);
result
=
0
;
}
else
{
printf_401037(
"NO\n"
, v7);
result
=
0
;
}
return
result;
}
int
sub_402C60()
{
MD5_Constants_40B298[
42
]
=
0xD4AF3085
;
return
1
;
}
int
sub_402C60()
{
MD5_Constants_40B298[
42
]
=
0xD4AF3085
;
return
1
;
}
int
__cdecl aes_402070(void
*
Src, size_t KeySize, unsigned __int8
input
[], unsigned __int8 uccipher[],
int
iLen)
{
int
j;
/
/
[esp
+
4h
] [ebp
-
1C8h
]
unsigned
int
i;
/
/
[esp
+
8h
] [ebp
-
1C4h
]
int
state[
6
];
/
/
[esp
+
10h
] [ebp
-
1BCh
] BYREF
int
key[
11
];
/
/
[esp
+
28h
] [ebp
-
1A4h
] BYREF
unsigned
int
*
iKeyOffset;
/
/
[esp
+
54h
] [ebp
-
178h
]
unsigned __int8
*
__attribute__((__org_arrdim(
0
,
0
))) output;
/
/
[esp
+
58h
] [ebp
-
174h
]
unsigned
int
KeyExtend[
90
];
/
/
[esp
+
60h
] [ebp
-
16Ch
] BYREF
output
=
uccipher;
iKeyOffset
=
KeyExtend;
key[
6
]
=
0
;
key[
7
]
=
0
;
key[
8
]
=
0
;
key[
9
]
=
0
;
key[
0
]
=
0
;
key[
1
]
=
0
;
key[
2
]
=
0
;
key[
3
]
=
0
;
state[
0
]
=
0
;
state[
1
]
=
0
;
state[
2
]
=
0
;
state[
3
]
=
0
;
if
( !Src || !
input
|| !uccipher )
return
-
1
;
if
( KeySize >
0x10
)
return
-
1
;
if
( iLen
%
0x10u
)
return
-
1
;
memcpy(key, Src, KeySize);
KeyExtend_4010BE(key,
16
, KeyExtend);
for
( i
=
0
; i < iLen; i
+
=
16
)
{
input_transpose_401145(state,
input
);
AddRoundKey_401186(state, iKeyOffset);
for
( j
=
1
; j <
10
;
+
+
j )
{
iKeyOffset
+
=
4
;
ByteSub_401172(state);
ShiftRow_40122B(state);
MixColumn_40100F(state);
AddRoundKey_401186(state, iKeyOffset);
}
ByteSub_401172(state);
ShiftRow_40122B(state);
AddRoundKey_401186(state, iKeyOffset
+
4
);
output_transpose_40125D(state, output);
output
+
=
16
;
input
+
=
16
;
iKeyOffset
=
KeyExtend;
}
return
0
;
}
int
__cdecl aes_402070(void
*
Src, size_t KeySize, unsigned __int8
input
[], unsigned __int8 uccipher[],
int
iLen)
{
int
j;
/
/
[esp
+
4h
] [ebp
-
1C8h
]
unsigned
int
i;
/
/
[esp
+
8h
] [ebp
-
1C4h
]
int
state[
6
];
/
/
[esp
+
10h
] [ebp
-
1BCh
] BYREF
int
key[
11
];
/
/
[esp
+
28h
] [ebp
-
1A4h
] BYREF
unsigned
int
*
iKeyOffset;
/
/
[esp
+
54h
] [ebp
-
178h
]
unsigned __int8
*
__attribute__((__org_arrdim(
0
,
0
))) output;
/
/
[esp
+
58h
] [ebp
-
174h
]
unsigned
int
KeyExtend[
90
];
/
/
[esp
+
60h
] [ebp
-
16Ch
] BYREF
output
=
uccipher;
iKeyOffset
=
KeyExtend;
key[
6
]
=
0
;
key[
7
]
=
0
;
key[
8
]
=
0
;
key[
9
]
=
0
;
key[
0
]
=
0
;
key[
1
]
=
0
;
key[
2
]
=
0
;
key[
3
]
=
0
;
state[
0
]
=
0
;
state[
1
]
=
0
;
state[
2
]
=
0
;
state[
3
]
=
0
;
if
( !Src || !
input
|| !uccipher )
return
-
1
;
if
( KeySize >
0x10
)
return
-
1
;
if
( iLen
%
0x10u
)
return
-
1
;
memcpy(key, Src, KeySize);
KeyExtend_4010BE(key,
16
, KeyExtend);
for
( i
=
0
; i < iLen; i
+
=
16
)
{
input_transpose_401145(state,
input
);
AddRoundKey_401186(state, iKeyOffset);
for
( j
=
1
; j <
10
;
+
+
j )
{
iKeyOffset
+
=
4
;
ByteSub_401172(state);
ShiftRow_40122B(state);
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)
赞赏
- [原创]第七题解题 4398
- [原创]KCTF2022春季赛第三题 解题过程 7637
- [原创]KCTF2022春季赛第三题:解题过程 7338
- [原创]KCTF2022春季赛第二题 解题过程 7430