之前比赛有出现的类似题目,但是这次虚拟执行的部分强化了很多,我并没有分析出虚拟执行的部分,有点遗憾。
用OD从内存中dump出完整的html。内存搜索 unicode "CTF 2019"就能找到了。
为了方便调试,可以把script标签里面的代码另存为一个js文件。
得到解密后的js代码,这里为了方便看,就把两个function放到一起了。
function sptWBCallback(spt_wb_id, spt_wb_name, optionstr) { url = '#sptWBCallback:id='; url = url + spt_wb_id + ';eventName=' + spt_wb_name; if (optionstr) url = url + ';params=optionstr'; location = url; } 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!"); }
得到flag前面的部分为"Simpower91"。
然后我们需要找到回调函数,先用IDR分析CM,导出MAP,给IDA使用(需要插件)。
int __fastcall Unit1_Tfrmcrackme_FormCreate(int a1) { int v1; // ebx int v2; // edx int v3; // eax int v4; // eax double v5; // ST00_8 int v6; // edx int v7; // ecx int v8; // edx int v9; // eax int v10; // edx int v11; // edx Teengine::TTeeFunction *v12; // eax double v13; // ST00_8 int v14; // edx int result; // eax unsigned int v16; // [esp-Ch] [ebp-14h] void *v17; // [esp-8h] [ebp-10h] int *v18; // [esp-4h] [ebp-Ch] int savedregs; // [esp+8h] [ebp+0h] v1 = a1; v18 = &savedregs; v17 = &loc_498D75; v16 = __readfsdword(0); __writefsdword(0, (unsigned int)&v16); SHDocVw_TWebBrowser_Navigate(*(Shdocvw::TWebBrowser **)(a1 + 760)); LOBYTE(v2) = 1; dword_49DF50 = Unit87_TVirtualMachine_Create("\x0FTVirtualMachine", v2); v3 = dword_49DF50; *(_DWORD *)(dword_49DF50 + 4372) = dword_49DF50; *(_DWORD *)(v3 + 4368) = sub_477514; v4 = ScripertJava_TScripertJava_Create((Classes::TComponent *)&cls_ScripertJava_TScripertJava); *(_DWORD *)(v1 + 824) = v4; *(_DWORD *)(v4 + 72) = *(_DWORD *)(v1 + 760); sub_4969C0(v4); HIDWORD(v5) = v1; LODWORD(v5) = &sub_49945C; // 回调函数 ScripertJava_TScripertJava_SetOnSptWBCallBack(*(Teengine::TTeeFunction **)(v1 + 824), v5);// 设置回调函数 ScripertJava_TScripertJava_SetOnBeforeSptWBCallBack(*(_DWORD *)(v1 + 824), v6, v7, v1, (int)sub_499428); LOBYTE(v8) = 1; v9 = Unit91_TIHookAgent_Create(dword_4957E8, v8); *(_DWORD *)(v1 + 832) = v9; Iddnsserver::TIdDNTreeNode::SaveToFile(v9, 0); sub_494694(*(_DWORD *)(*(_DWORD *)(v1 + 832) + 24), antiDebug_kernel32_IsDebuggerPresent, &str_idp[1]); sub_494694(*(_DWORD *)(*(_DWORD *)(v1 + 832) + 24), MessageBoxW, &str_mb[1]); LOBYTE(v10) = 1; *(_DWORD *)(v1 + 820) = system_TObject_Create(dword_46F088, v10); LOBYTE(v11) = 1; v12 = (Teengine::TTeeFunction *)antiDebug_TAntiDebug_Create(&cls_antiDebug_TAntiDebug, v11, 0); *(_DWORD *)(v1 + 828) = v12; HIDWORD(v13) = v1; LODWORD(v13) = sub_49978C; antiDebug_TAntiDebug_SetOnCheckTrue(v12, v13); antiDebug_TAntiDebug_SetOnAllCheckFalse(*(Idsyslogmessage::TIdSysLogMessage **)(v1 + 828), v14); dword_49DF54 = sub_494898(*(_DWORD *)(*(_DWORD *)(v1 + 832) + 24), 0); dword_49DF58 = sub_494898(*(_DWORD *)(*(_DWORD *)(v1 + 832) + 24), 1); *(_BYTE *)(v1 + 836) = 0; result = 0; __writefsdword(0, v16); return result; }
在Unit1_Tfrmcrackme_FormCreate事件里面能看到设置的回调函数sub_49978C。因为不能使用F5,后面还是用OD动态调试,同样可以把map导入到OD。
OD载入CM,0049978C 下断,输入 "Simpower911",点击按钮。
用处理异常的方法来跳转,单步过去。
单步出retn。
跟进call。
单步过第一个call没有问题,过第二个call时跑飞了,在单步过第一个call时,查看堆栈上面,发现一个可疑的调用。
00404734 strlen,在运行到004777E2处时对其下断。
运行到00476B8C,用OD的跟踪步过看看发生了什么。
在00476C3E处跑飞,可以在这里下断,测试一下几次后跑飞,然后在跑飞之前用跟踪步入,等OD断在strlen处。
在这条retn指令下断,继续运行。
eax出现 Simpower91后面的字符串的长度,继续单步,发现走出了回调函数。
有可能是字符串的长度不符合,然后就直接返回了,增加字符串的字数,继续测试几次,输入 “Simpower911111”的时候,寄存器的值发生明显变化了。
eax与edx较可疑,把输入后面改成2222发现eax是字符的ascii值加0x7F,那edx应该就是flag的ascii加0x7F了。
根据edx修改输入,edx的值分别为0xE0, 0xB2, 0xB1, 0xB0,最终得到flag后四位为a321。
故flag为:
Simpower91a321
[培训]《安卓高级研修班》彻底搞定函数抽取型壳!现在报名得源码和安卓8.1脱壳机!10月20日深圳专场不见不散!
最后于 1天前 被梦游枪手编辑 ,原因: