-
-
[原创]KCTF2023 第六题 至暗时刻
-
发表于: 2023-9-14 11:23 9659
-
代码中有很多syscall,win11调试进不去,需要布置win10虚拟机调试,才能看到函数名
创建的第一个线程,每次调用RtlFillMemory拷贝1字节,跟踪发现拷贝的就是 unk_140008050 中的数据,而且看着像jmp指令:
用IDA加载能识别为代码,但是有很多错误。需要x64dbg调试shellcode。
先内存断,再执行断。shellcode运行后会将所有17替换成00,重新拿到shellcode,IDA F5就能完美识别
然后就是反复调试,发现字符串分为3块:
3201382652D139C0E22132DF1BC2212EA0991650A229B36436823D0B13D51E6 //前缀,3位一个16进制数
input //必须是3的倍数,后续分析长度必须是180
677116575313142309154604431859253431473963507533496829080645035455771774602058076430276921790210013736267644383505517280 //后缀 2位一个10进制数
核心函数是2063B,要求input每3位,是一个十六进制
比如 input[0]="112",0x112=274,十位*9+个位=67,要跟后缀[0]相等
十位和个位就确定了。
同时十位和个位要作为下标,充当数独的坐标。百位就是数独的内容。
数独一共是9*9个格子,其中前缀是21个数,input是60个数。所以先转换已有的21个数,更新到棋盘
再求解出答案:
编程反算数独下标,
.text:
0000000140001324
FF
15
2E
4D
00
00
call cs:IsDebuggerPresent
.text:
000000014000132A
85
C0 test eax, eax
.text:
000000014000132C
74
05
jz short loc_140001333
.text:
0000000140001324
FF
15
2E
4D
00
00
call cs:IsDebuggerPresent
.text:
000000014000132A
85
C0 test eax, eax
.text:
000000014000132C
74
05
jz short loc_140001333
.text:
0000000140001324
FF
15
2E
4D
00
00
call cs:IsDebuggerPresent
.text:
000000014000132A
|
31C0
| xor eax,eax |
.text:
000000014000132C
| EB
05
| jmp blackclient_.
140001333
|
.text:
000000014000132E
| E8
65FFFFFF
| call blackclient_.
140001298
|
.text:
0000000140001324
FF
15
2E
4D
00
00
call cs:IsDebuggerPresent
.text:
000000014000132A
|
31C0
| xor eax,eax |
.text:
000000014000132C
| EB
05
| jmp blackclient_.
140001333
|
.text:
000000014000132E
| E8
65FFFFFF
| call blackclient_.
140001298
|
.text:
0000000140001484
FF
15
DE
4B
00
00
call cs:CheckRemoteDebuggerPresent
.text:
000000014000148A
83
7D
38
00
cmp
[rbp
+
pbDebuggerPresent],
0
.text:
000000014000148E
0F
84
95
00
00
00
jz loc_140001529
.text:
0000000140001494
B9
08
00
00
00
mov ecx,
8
; Size
.text:
0000000140001484
FF
15
DE
4B
00
00
call cs:CheckRemoteDebuggerPresent
.text:
000000014000148A
83
7D
38
00
cmp
[rbp
+
pbDebuggerPresent],
0
.text:
000000014000148E
0F
84
95
00
00
00
jz loc_140001529
.text:
0000000140001494
B9
08
00
00
00
mov ecx,
8
; Size
fun_scanf((__int64)
"%s"
, input_1, v64);
fun_decode(v15, v52, (__int64)
"*s>0?"
,
5
);
/
/
kctf
sub_1400026AC(&Src, v16, v52, v17, qword_140009A80);
/
/
kctf拼接到字符串前面
sub_140002BBA((__int64)v19, (__int64)&Source,
0i64
, (__int64)&v69, Size);
/
/
NtAllocateVirtualMemory
sub_140002DA9((__int64)v19);
/
/
NtWriteVirtualMemory
fun_decode(v20, v58, (__int64)
"!?>d*"
,
5
);
/
/
kernel32.dll
fun_decode(v22, v55, (__int64)
"?x)da"
, v21);
/
/
RtlFillMemory(地址,大小,值)
( (unsigned
int
)sub_140003529((__int64)&hThread) )
/
/
NtCreateThreadEx
strncpy((char
*
)&Str1, Source
+
67
,
3ui64
);
if
( !strcmp((const char
*
)&Str1,
"110"
) )
/
/
此时Str1
=
=
"110"
{
v43
=
&unk_140006590;
}
else
{
if
( strcmp((const char
*
)&Str1,
"120"
) )
/
/
不等于
120
,就退出
ExitProcess(
0
);
v43
=
&unk_140006598;
}
fun_decode(&Dest,
3
, (__int64)v43,
3
);
fun_printf((__int64)&unk_14000659C, &Dest);
/
/
这里肯定就是打印成功了
fun_scanf((__int64)
"%s"
, input_1, v64);
fun_decode(v15, v52, (__int64)
"*s>0?"
,
5
);
/
/
kctf
sub_1400026AC(&Src, v16, v52, v17, qword_140009A80);
/
/
kctf拼接到字符串前面
sub_140002BBA((__int64)v19, (__int64)&Source,
0i64
, (__int64)&v69, Size);
/
/
NtAllocateVirtualMemory
sub_140002DA9((__int64)v19);
/
/
NtWriteVirtualMemory
fun_decode(v20, v58, (__int64)
"!?>d*"
,
5
);
/
/
kernel32.dll
fun_decode(v22, v55, (__int64)
"?x)da"
, v21);
/
/
RtlFillMemory(地址,大小,值)
( (unsigned
int
)sub_140003529((__int64)&hThread) )
/
/
NtCreateThreadEx
strncpy((char
*
)&Str1, Source
+
67
,
3ui64
);
if
( !strcmp((const char
*
)&Str1,
"110"
) )
/
/
此时Str1
=
=
"110"
{
v43
=
&unk_140006590;
}
else
{
if
( strcmp((const char
*
)&Str1,
"120"
) )
/
/
不等于
120
,就退出
ExitProcess(
0
);
v43
=
&unk_140006598;
}
fun_decode(&Dest,
3
, (__int64)v43,
3
);
fun_printf((__int64)&unk_14000659C, &Dest);
/
/
这里肯定就是打印成功了
__int64 sub_20217()
{
__int64 (__fastcall
*
CreateToolhelp32Snapshot)(signed __int64, _QWORD);
/
/
rbx
__int64 (__fastcall
*
Process32First)(__int64,
int
*
);
/
/
r13
void (__fastcall
*
CloseHandle)(__int64);
/
/
r15
__int64 (
*
GetCurrentProcessId)(void);
/
/
r12
__int64 process;
/
/
rdi
bool
v5;
/
/
si
__int64 handle;
/
/
rax
__int64 v7;
/
/
r14
int
v9;
/
/
eax
__int64 (__fastcall
*
Process32Next_1)(__int64,
int
*
);
/
/
rbx
__int64 (__fastcall
*
OpenProcess_1)(signed __int64, _QWORD);
/
/
r13
__int64 address;
/
/
rbx
int
v13;
/
/
eax
int
*
v14;
/
/
rdx
_BYTE
*
v15;
/
/
rbx
int
*
lpBuffer;
/
/
[rsp
+
48h
] [rbp
-
2B0h
]
int
v17;
/
/
[rsp
+
58h
] [rbp
-
2A0h
]
__int64 v18;
/
/
[rsp
+
60h
] [rbp
-
298h
]
int
v19;
/
/
[rsp
+
68h
] [rbp
-
290h
]
int
v20;
/
/
[rsp
+
80h
] [rbp
-
278h
]
int
v21;
/
/
[rsp
+
88h
] [rbp
-
270h
]
__int64 Process32Next;
/
/
[rsp
+
300h
] [rbp
+
8h
]
__int64 OpenProcess;
/
/
[rsp
+
308h
] [rbp
+
10h
]
__int64 (__fastcall
*
VirtualQueryEx)(__int64, __int64,
int
*
*
, signed __int64);
/
/
[rsp
+
310h
] [rbp
+
18h
]
CreateToolhelp32Snapshot
=
(__int64 (__fastcall
*
)(signed __int64, _QWORD))sub_20563(
0xF88DDF46
);
OpenProcess
=
sub_20563(
0xFD0B55A7
);
VirtualQueryEx
=
(__int64 (__fastcall
*
)(__int64, __int64,
int
*
*
, signed __int64))sub_20563(
0x242E6FF
);
Process32First
=
(__int64 (__fastcall
*
)(__int64,
int
*
))sub_20563(
0x3F347695
);
Process32Next
=
sub_20563(
-
1813961927
);
CloseHandle
=
(void (__fastcall
*
)(__int64))sub_20563(
0x1CA655F1
);
GetCurrentProcessId
=
(__int64 (
*
)(void))sub_20563(
55981281
);
process
=
0i64
;
v20
=
0x238
;
v5
=
0
;
handle
=
CreateToolhelp32Snapshot(
2i64
,
0i64
);
v7
=
handle;
if
( handle
=
=
-
1
)
return
0xFFFFFFFFi64
;
v9
=
Process32First(handle, &v20);
Process32Next_1
=
(__int64 (__fastcall
*
)(__int64,
int
*
))Process32Next;
OpenProcess_1
=
(__int64 (__fastcall
*
)(signed __int64, _QWORD))OpenProcess;
while
( v9 )
{
if
( v21
=
=
(unsigned
int
)GetCurrentProcessId() )
{
process
=
OpenProcess_1(
0x2000000i64
,
0i64
);
if
( process )
{
address
=
0i64
;
while
(
1
)
{
do
{
if
( !VirtualQueryEx(process, address, &lpBuffer,
48i64
) )
{
Process32Next_1
=
(__int64 (__fastcall
*
)(__int64,
int
*
))Process32Next;
OpenProcess_1
=
(__int64 (__fastcall
*
)(signed __int64, _QWORD))OpenProcess;
goto LABEL_20;
}
address
=
(__int64)lpBuffer
+
v18;
}
while
( v19 !
=
4096
|| v17 !
=
64
);
v13
=
GetCurrentProcessId();
v14
=
lpBuffer;
if
( v21
=
=
v13 )
v5
=
sub_2062F(
*
lpBuffer);
if
( v5 )
break
;
*
(_BYTE
*
)v14
=
'm'
;
/
/
第一层判断,kctf头
*
((_BYTE
*
)v14
+
1
)
=
'j'
;
*
((_BYTE
*
)v14
+
2
)
=
')'
;
*
((_BYTE
*
)v14
+
3
)
=
0
;
*
((_BYTE
*
)v14
+
67
)
=
'1'
;
*
((_BYTE
*
)v14
+
68
)
=
'2'
;
*
((_BYTE
*
)v14
+
69
)
=
'0'
;
}
v15
=
v14
+
1
;
if
( sub_20AA3((__int64)(v14
+
1
)) )
/
/
所有判断,都在这里呗 传入kctf后面的字符串
{
*
(v15
-
4
)
=
'i'
;
/
/
正确答案!!!!!!
*
(v15
-
3
)
=
'o'
;
*
(v15
-
2
)
=
' '
;
*
(v15
-
1
)
=
0
;
v15[
63
]
=
'1'
;
v15[
64
]
=
'1'
;
}
else
{
*
(v15
-
4
)
=
'm'
;
*
(v15
-
3
)
=
'j'
;
*
(v15
-
2
)
=
')'
;
*
(v15
-
1
)
=
0
;
v15[
63
]
=
'1'
;
v15[
64
]
=
'2'
;
}
v15[
65
]
=
'0'
;
break
;
}
}
LABEL_20:
v9
=
Process32Next_1(v7, &v20);
}
CloseHandle(v7);
return
((__int64 (__fastcall
*
)(__int64))CloseHandle)(process);
}
__int64 sub_20217()
{
__int64 (__fastcall
*
CreateToolhelp32Snapshot)(signed __int64, _QWORD);
/
/
rbx
__int64 (__fastcall
*
Process32First)(__int64,
int
*
);
/
/
r13
void (__fastcall
*
CloseHandle)(__int64);
/
/
r15
__int64 (
*
GetCurrentProcessId)(void);
/
/
r12
__int64 process;
/
/
rdi
bool
v5;
/
/
si
__int64 handle;
/
/
rax
__int64 v7;
/
/
r14
int
v9;
/
/
eax
__int64 (__fastcall
*
Process32Next_1)(__int64,
int
*
);
/
/
rbx
__int64 (__fastcall
*
OpenProcess_1)(signed __int64, _QWORD);
/
/
r13
__int64 address;
/
/
rbx
int
v13;
/
/
eax
int
*
v14;
/
/
rdx
_BYTE
*
v15;
/
/
rbx
int
*
lpBuffer;
/
/
[rsp
+
48h
] [rbp
-
2B0h
]
int
v17;
/
/
[rsp
+
58h
] [rbp
-
2A0h
]
__int64 v18;
/
/
[rsp
+
60h
] [rbp
-
298h
]
int
v19;
/
/
[rsp
+
68h
] [rbp
-
290h
]
int
v20;
/
/
[rsp
+
80h
] [rbp
-
278h
]
int
v21;
/
/
[rsp
+
88h
] [rbp
-
270h
]
__int64 Process32Next;
/
/
[rsp
+
300h
] [rbp
+
8h
]
__int64 OpenProcess;
/
/
[rsp
+
308h
] [rbp
+
10h
]
__int64 (__fastcall
*
VirtualQueryEx)(__int64, __int64,
int
*
*
, signed __int64);
/
/
[rsp
+
310h
] [rbp
+
18h
]
CreateToolhelp32Snapshot
=
(__int64 (__fastcall
*
)(signed __int64, _QWORD))sub_20563(
0xF88DDF46
);
OpenProcess
=
sub_20563(
0xFD0B55A7
);
VirtualQueryEx
=
(__int64 (__fastcall
*
)(__int64, __int64,
int
*
*
, signed __int64))sub_20563(
0x242E6FF
);
Process32First
=
(__int64 (__fastcall
*
)(__int64,
int
*
))sub_20563(
0x3F347695
);
Process32Next
=
sub_20563(
-
1813961927
);
CloseHandle
=
(void (__fastcall
*
)(__int64))sub_20563(
0x1CA655F1
);
GetCurrentProcessId
=
(__int64 (
*
)(void))sub_20563(
55981281
);
process
=
0i64
;
v20
=
0x238
;
v5
=
0
;
handle
=
CreateToolhelp32Snapshot(
2i64
,
0i64
);
v7
=
handle;
if
( handle
=
=
-
1
)
return
0xFFFFFFFFi64
;
v9
=
Process32First(handle, &v20);
Process32Next_1
=
(__int64 (__fastcall
*
)(__int64,
int
*
))Process32Next;
OpenProcess_1
=
(__int64 (__fastcall
*
)(signed __int64, _QWORD))OpenProcess;
while
( v9 )
{
if
( v21
=
=
(unsigned
int
)GetCurrentProcessId() )
{
process
=
OpenProcess_1(
0x2000000i64
,
0i64
);
if
( process )
{
address
=
0i64
;
while
(
1
)
{
do
{
if
( !VirtualQueryEx(process, address, &lpBuffer,
48i64
) )
{
Process32Next_1
=
(__int64 (__fastcall
*
)(__int64,
int
*
))Process32Next;
OpenProcess_1
=
(__int64 (__fastcall
*
)(signed __int64, _QWORD))OpenProcess;
goto LABEL_20;
}
address
=
(__int64)lpBuffer
+
v18;
}
while
( v19 !
=
4096
|| v17 !
=
64
);
v13
=
GetCurrentProcessId();
v14
=
lpBuffer;
if
( v21
=
=
v13 )
v5
=
sub_2062F(
*
lpBuffer);
if
( v5 )
break
;
*
(_BYTE
*
)v14
=
'm'
;
/
/
第一层判断,kctf头
*
((_BYTE
*
)v14
+
1
)
=
'j'
;
*
((_BYTE
*
)v14
+
2
)
=
')'
;
*
((_BYTE
*
)v14
+
3
)
=
0
;
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)
赞赏
他的文章
- 2024KCTF_第九题 第一次接触-提交题目 1792
- [原创]KCTF2023 第十二题深入内核 3584
- [原创]KCTF2023 第八题AI核心地带 9877
- [原创]KCTF2023 第六题 至暗时刻 9660
- [原创]KCTF2023 第五题 争分夺秒 8586
看原图
赞赏
雪币:
留言: