-
-
[原创]看雪CTF 2019Q3 第二题 血肉佣兵
-
发表于: 2019-9-21 15:15 4059
-
这是作者第三次改版的题目,上一次是个微型的vm,但这一次没看出来是什么
将simpower91
放在输入的开头,并不能触发sptWBCallback
回调函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | function ckpswd() { key = "simpower91" ; a = document. all .pswd.value; if (a.indexOf(key) = = 0 ) { l = a.length; i = key.length; sptWBCallback(a.substring(i, l)); } else { alert( "wrong!<" + a + "> is not my GUID ;-)" ); return "1234" ; } } function ok() { alert( "congratulations!" ); } |
1 2 3 4 5 6 7 8 9 10 | CODE: 00498D1B push ebx CODE: 00498D1C push offset sub_499388 ; 替换 simpower91 首字母为大写 CODE: 00498D21 mov eax, [ebx + 33Ch ] ; this CODE: 00498D27 call @Idsyslogmessage@TIdSysLogMessage@SetTimeStamp$qqrx16System@TDateTime / / 定时事件函数替换代码 sub_499388: CODE: 004993B5 mov eax, [ebp + System::AnsiString] ; System::AnsiString CODE: 004993B8 mov ecx, offset _str_d_return_Si.Text ; int CODE: 004993BD mov edx, offset _str_d_return_si.Text ; System::AnsiString CODE: 004993C2 call SysUtils_StringReplace |
1 2 3 4 5 6 7 8 9 | function ckpswd() { key = "Simpower91" ; a = document. all .pswd.value; if (a.indexOf(key) = = 0 ) { l = a.length; i = key.length; sptWBCallback(a.substring(i, l)); } ...... |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | CODE: 00474E98 f_call_fun_474E98 proc near ; CODE XREF: sub_474EAC + 49 ↓p CODE: 00474E98 CODE: 00474E98 arg_0 = dword ptr 8 CODE: 00474E98 arg_4 = dword ptr 0Ch CODE: 00474E98 arg_8 = dword ptr 10h CODE: 00474E98 CODE: 00474E98 push ebp ; SimInstructions.sub_00474E98 CODE: 00474E99 mov ebp, esp CODE: 00474E9B mov eax, [ebp + arg_0] CODE: 00474E9E push eax CODE: 00474E9F mov eax, [ebp + arg_8] CODE: 00474EA2 call [ebp + arg_4] CODE: 00474EA5 pop ebp CODE: 00474EA6 retn 0Ch CODE: 00474EA6 f_call_fun_474E98 endp |
1 2 3 4 | str [ 0 ] + 7F = = E0 str [ 1 ] + 7F = = B2 str [ 2 ] + 7F = = B1 str [ 3 ] + 7F = = B0 |
1 2 3 4 5 | E0 - 7F = 61 B2 - 7F = 33 B1 - 7F = 32 B0 - 7F = 31 / / a123 |
1 2 | Simpower91a321 / / 这个答案。。。上次是a123,这次是a321,这说不定那个大佬猜都猜对了 |
这是作者第三次改版的题目,上一次是个微型的vm,但这一次没看出来是什么
将
simpower91
放在输入的开头,并不能触发sptWBCallback
回调函数
- 原因是在
_Tfrmcrackme_FormCreate
事件函数中又注册了一个定时事件,修改了内存中加载的js代码12345678910CODE:
00498D1B
push ebx
CODE:
00498D1C
push offset sub_499388 ; 替换 simpower91 首字母为大写
CODE:
00498D21
mov eax, [ebx
+
33Ch
] ; this
CODE:
00498D27
call @Idsyslogmessage@TIdSysLogMessage@SetTimeStamp$qqrx16System@TDateTime
/
/
定时事件函数替换代码
sub_499388:
CODE:
004993B5
mov eax, [ebp
+
System::AnsiString] ; System::AnsiString
CODE:
004993B8
mov ecx, offset _str_d_return_Si.Text ;
int
CODE:
004993BD
mov edx, offset _str_d_return_si.Text ; System::AnsiString
CODE:
004993C2
call SysUtils_StringReplace
- 所以实际内存中加载的js验证代码如下123456789
function ckpswd() {
key
=
"Simpower91"
;
a
=
document.
all
.pswd.value;
if
(a.indexOf(key)
=
=
0
) {
l
=
a.length;
i
=
key.length;
sptWBCallback(a.substring(i, l));
}
......
- 可以看出这个函数
00474EA2
的位置会调用参数中传进来的函数,最后跑飞的位置也在这里,疑似某种事件函数 - 输入
Simpower910123
在这里下断点持续观察,会发现输入的字符串地址会在其中一次命中断点时出现在寄存器窗口 - 这里调用的函数是
sub_471720
,调试后会发现此时将传进来的字符串的第一个字符作为DWORD
数据保存在了函数第4个参数指向的地址中 - 因为后面还有很多函数调用,不确定哪个函数是关键,于是在保存后的
DWORD
数据那里下硬件访问断点,再确认是否为验证操作 - 经过两次断点触发,来到这里
00470A21
,发现给第一个字符加上了7F
,最后保存在了原位置 - 再经过几次断点触发,来到这里
00470B36
(注意在这里下个断点),发现将加上7F
的数据再次减E0
,将结果保存在edx
中 - 然后
F7
单步,一直到这里,发现有个比较edx
值是不是0
的操作,于是怀疑这里就是判断,手动将edx
的值改为0
- 然后删除之前给数据下的硬件断点,
F9
运行观察一下,经过几次断点触发,又来到这这个熟悉的地方,不一样的是,开始操作第二个字符了 - 于是重复刚才的操作会发现1234
str
[
0
]
+
7F
=
=
E0
str
[
1
]
+
7F
=
=
B2
str
[
2
]
+
7F
=
=
B1
str
[
3
]
+
7F
=
=
B0
- 算出输入的值:12345
E0
-
7F
=
61
B2
-
7F
=
33
B1
-
7F
=
32
B0
-
7F
=
31
/
/
a123
答案
12Simpower91a321
/
/
这个答案。。。上次是a123,这次是a321,这说不定那个大佬猜都猜对了
- 在
00498C00 _Tfrmcrackme_FormCreate
事件函数的00498C72 call sub_4969C0
函数中注册sptWBCallback
回调函数,回调函数地址:00496C7C
- 加载
HTML
作为界面,JavaScript
获取输入,触发sptWBCallback
事件123456789101112131415function ckpswd() {
key
=
"simpower91"
;
a
=
document.
all
.pswd.value;
if
(a.indexOf(key)
=
=
0
) {
l
=
a.length;
i
=
key.length;
sptWBCallback(a.substring(i, l));
}
else
{
alert(
"wrong!<"
+
a
+
"> is not my GUID ;-)"
);
return
"1234"
;
}
}
function ok() {
alert(
"congratulations!"
);
}
-
00496E08 call dword ptr [ebx+40h]
该位置调用反调试函数 - 之后的
call
指令在F8
单步的时候,程序会重新跑起来,于是依次F8 F7
确认后来到了如下位置... 004772CE -> 00476C3E -> 00475C64 -> 00474EF5 -> 00474EA2 -> 00474E98
123456789101112131415CODE:
00474E98
f_call_fun_474E98 proc near ; CODE XREF: sub_474EAC
+
49
↓p
CODE:
00474E98
CODE:
00474E98
arg_0
=
dword ptr
8
CODE:
00474E98
arg_4
=
dword ptr
0Ch
CODE:
00474E98
arg_8
=
dword ptr
10h
CODE:
00474E98
CODE:
00474E98
push ebp ; SimInstructions.sub_00474E98
CODE:
00474E99
mov ebp, esp
CODE:
00474E9B
mov eax, [ebp
+
arg_0]
CODE:
00474E9E
push eax
CODE:
00474E9F
mov eax, [ebp
+
arg_8]
CODE:
00474EA2
call [ebp
+
arg_4]
CODE:
00474EA5
pop ebp
CODE:
00474EA6
retn
0Ch
CODE:
00474EA6
f_call_fun_474E98 endp
00498C00 _Tfrmcrackme_FormCreate
事件函数的00498C72 call sub_4969C0
函数中注册sptWBCallback
回调函数,回调函数地址:00496C7C
[招生]科锐逆向工程师培训(2025年3月11日实地,远程教学同时开班, 第52期)!
赞赏
他的文章
- [分享]教你签到获得更多的雪币 10301
- [原创]看雪CTF 2019总决赛 第六题 三道八佛 6198
- [原创]看雪CTF 2019总决赛 第二题 南充茶坊 6839
谁下载
无
赞赏
雪币:
留言: