-
-
[原创]第三题 write up by 青蛙Mage
-
发表于: 2019-3-24 16:14 6676
-
使用工具:IDA pro 7.0,JS反混淆,delphi反编译工具(IDR)
大体框架,用iefarme画出UI......
运行起来内存里有一段比较可疑的东西
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <script> 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; } eval(function(p, a, c, k, e, d) { e = function(c) { return (c < a ? '' : e(parseInt(c / a))) + ((c = c % a) > 35 ? StringfromCharCode(c + 29) : c.toString(36)) }; if (!''.replace(/^/, String)) { while (c--) d[e(c)] = k[c] || e(c); k = [function(e) { return d[e]}]; e = function() { return '\\w+' }; c = 1 }; while (c--) if (k[c]) p = p.replace(new RegExp('\\b' + e(c) + '\\b', 'g'), k[c]); document.write(p) return p }('a 6() { f="n";3 = 8.5.l.q; c (3.d(f) ==0) { g=3.h; b=f.h;o(3.p(b,g)); } 9 { 4("r!<" + 3 + "> e j i 2 ;-)");m "1"; }}a k(){ 4("7!");}', 62, 28, '|1234|GUID|a|alert|all|ckpswd|congratulations|document|else|function|i|if|indexOf|is|key|l|length|my|not|ok|pswd|return|simpower91|sptWBCallback|substring|value|wrong'.split('|'), 0, {})) </script> //解混淆以后 意思就是 比较输入的内容 如果有 simpower91 再将后面的几位 作为参数输入sptWBCallback,否则就会用vba画个框高速你错误。
做到这里就断了,完全断了,你无论后面输入什么都不给提示
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <script> 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; } eval(function(p, a, c, k, e, d) { e = function(c) { return (c < a ? '' : e(parseInt(c / a))) + ((c = c % a) > 35 ? StringfromCharCode(c + 29) : c.toString(36)) }; if (!''.replace(/^/, String)) { while (c--) d[e(c)] = k[c] || e(c); k = [function(e) { return d[e]}]; e = function() { return '\\w+' }; c = 1 }; while (c--) if (k[c]) p = p.replace(new RegExp('\\b' + e(c) + '\\b', 'g'), k[c]); document.write(p) return p }('a 6() { f="n";3 = 8.5.l.q; c (3.d(f) ==0) { g=3.h; b=f.h;o(3.p(b,g)); } 9 { 4("r!<" + 3 + "> e j i 2 ;-)");m "1"; }}a k(){ 4("7!");}', 62, 28, '|1234|GUID|a|alert|all|ckpswd|congratulations|document|else|function|i|if|indexOf|is|key|l|length|my|not|ok|pswd|return|simpower91|sptWBCallback|substring|value|wrong'.split('|'), 0, {})) </script> //解混淆以后 意思就是 比较输入的内容 如果有 simpower91 再将后面的几位 作为参数输入sptWBCallback,否则就会用vba画个框高速你错误。
做到这里就断了,完全断了,你无论后面输入什么都不给提示
柳暗花明又一村,既然脚本语言是动态执行,那么至少要捕获我输的什么内容吧,GO
摸鱼下断,在所有带strlen之类意思的函数下断,终于找到你了
int __userpurge sub_492088@<eax>(int a1@<eax>, int a2@<edx>, int a3@<ecx>, int a4@<ebx>, int a5@<esi>, _WORD *a6, int a7, int a8, int a9, int a10, int a11) { int v11; // ebx int v12; // eax int v13; // edx Classes::TStrings *v14; // esi int v15; // ST14_4 int v16; // ST10_4 unsigned int v18; // [esp-14h] [ebp-34h] void *v19; // [esp-10h] [ebp-30h] int *v20; // [esp-Ch] [ebp-2Ch] int v21; // [esp-8h] [ebp-28h] int v22; // [esp-4h] [ebp-24h] int v23; // [esp+0h] [ebp-20h] int v24; // [esp+4h] [ebp-1Ch] int v25; // [esp+8h] [ebp-18h] char v26[4]; // [esp+Ch] [ebp-14h] int v27; // [esp+10h] [ebp-10h] int System::AnsiString; // [esp+14h] [ebp-Ch] int v29; // [esp+18h] [ebp-8h] int v30; // [esp+1Ch] [ebp-4h] int savedregs; // [esp+20h] [ebp+0h] System::AnsiString = 0; v27 = 0; *(_DWORD *)v26 = 0; v25 = 0; v24 = 0; v23 = 0; v22 = a4; v21 = a5; v29 = a3; v30 = a2; v11 = a1; v20 = &savedregs; v19 = &loc_4921D1; v18 = __readfsdword(0); __writefsdword(0, (unsigned int)&v18); Variants::__linkproc__ VarToLStr(&v27, a11); if ( sub_465C88(&str__sptWBCallback_[1], v27) > 0 ) { *a6 = -1; Variants::__linkproc__ VarToLStr(&System::AnsiString, a11); unknown_libname_60(System::AnsiString); v12 = System::__linkproc__ LStrCopy(&System::AnsiString); LOBYTE(v12) = 1; unknown_libname_161(System::AnsiString, (int)&str___41[1], (int)&str____19[1], v12, (unsigned int)v26); System::__linkproc__ LStrLAsg(&System::AnsiString, *(_DWORD *)v26); LOBYTE(v13) = 1; v14 = (Classes::TStrings *)unknown_libname_33(cls_Classes_TStringList, v13); (*(void (__fastcall **)(Classes::TStrings *, int))(*(_DWORD *)v14 + 44))(v14, System::AnsiString); if ( *(_WORD *)(v11 + 50) ) { Classes::TStrings::GetValue(v14, (const int)&str_params[1], (int)&v25); v15 = v25; Classes::TStrings::GetValue(v14, (const int)&str_eventName[1], (int)&v24); v16 = v24; Classes::TStrings::GetValue(v14, (const int)&str_id[1], (int)&v23); (*(void (__fastcall **)(_DWORD, int, int, int))(v11 + 48))(*(_DWORD *)(v11 + 52), v23, v16, v15); } } if ( *(_WORD *)(v11 + 58) ) (*(void (__fastcall **)(_DWORD, int, int, int, int, int, int, int, _WORD *))(v11 + 56))( *(_DWORD *)(v11 + 60), v30, v29, a11, a10, a9, a8, a7, a6); __writefsdword(0, v18); v20 = (int *)&loc_4921D8; return System::__linkproc__ LStrArrayClr(&v23, 6); }
重要的流程,通过about:blank#sptcallback+str 作为后续输入,跟着一路会检测你是否是输入四位然后到另一个关键函数
int __userpurge sub_492088@<eax>(int a1@<eax>, int a2@<edx>, int a3@<ecx>, int a4@<ebx>, int a5@<esi>, _WORD *a6, int a7, int a8, int a9, int a10, int a11) { int v11; // ebx int v12; // eax int v13; // edx Classes::TStrings *v14; // esi int v15; // ST14_4 int v16; // ST10_4 unsigned int v18; // [esp-14h] [ebp-34h] void *v19; // [esp-10h] [ebp-30h] int *v20; // [esp-Ch] [ebp-2Ch] int v21; // [esp-8h] [ebp-28h] int v22; // [esp-4h] [ebp-24h] int v23; // [esp+0h] [ebp-20h] int v24; // [esp+4h] [ebp-1Ch] int v25; // [esp+8h] [ebp-18h] char v26[4]; // [esp+Ch] [ebp-14h] int v27; // [esp+10h] [ebp-10h] int System::AnsiString; // [esp+14h] [ebp-Ch] int v29; // [esp+18h] [ebp-8h] int v30; // [esp+1Ch] [ebp-4h] int savedregs; // [esp+20h] [ebp+0h] System::AnsiString = 0; v27 = 0; *(_DWORD *)v26 = 0; v25 = 0; v24 = 0; v23 = 0; v22 = a4; v21 = a5; v29 = a3; v30 = a2; v11 = a1; v20 = &savedregs; v19 = &loc_4921D1; v18 = __readfsdword(0); __writefsdword(0, (unsigned int)&v18); Variants::__linkproc__ VarToLStr(&v27, a11); if ( sub_465C88(&str__sptWBCallback_[1], v27) > 0 ) { *a6 = -1; Variants::__linkproc__ VarToLStr(&System::AnsiString, a11); unknown_libname_60(System::AnsiString); v12 = System::__linkproc__ LStrCopy(&System::AnsiString); LOBYTE(v12) = 1; unknown_libname_161(System::AnsiString, (int)&str___41[1], (int)&str____19[1], v12, (unsigned int)v26); System::__linkproc__ LStrLAsg(&System::AnsiString, *(_DWORD *)v26); LOBYTE(v13) = 1; v14 = (Classes::TStrings *)unknown_libname_33(cls_Classes_TStringList, v13); (*(void (__fastcall **)(Classes::TStrings *, int))(*(_DWORD *)v14 + 44))(v14, System::AnsiString); if ( *(_WORD *)(v11 + 50) ) { Classes::TStrings::GetValue(v14, (const int)&str_params[1], (int)&v25); v15 = v25; Classes::TStrings::GetValue(v14, (const int)&str_eventName[1], (int)&v24); v16 = v24; Classes::TStrings::GetValue(v14, (const int)&str_id[1], (int)&v23); (*(void (__fastcall **)(_DWORD, int, int, int))(v11 + 48))(*(_DWORD *)(v11 + 52), v23, v16, v15); } } if ( *(_WORD *)(v11 + 58) ) (*(void (__fastcall **)(_DWORD, int, int, int, int, int, int, int, _WORD *))(v11 + 56))( *(_DWORD *)(v11 + 60), v30, v29, a11, a10, a9, a8, a7, a6); __writefsdword(0, v18); v20 = (int *)&loc_4921D8; return System::__linkproc__ LStrArrayClr(&v23, 6); }
重要的流程,通过about:blank#sptcallback+str 作为后续输入,跟着一路会检测你是否是输入四位然后到另一个关键函数
int __usercall sub_4734B0@<eax>(int a1@<ebx>, int a2@<edi>, int a3@<esi>, int a4, int a5, int a6, int a7, int a8, int a9, int a10, int a11, int a12, int a13, int a14, int a15) { unsigned int v15; // et0 int (__fastcall *v16)(unsigned int *); // ST10_4 unsigned int v18; // [esp+10h] [ebp-30h] int v19; // [esp+30h] [ebp-10h] void **v20; // [esp+34h] [ebp-Ch] int *v21; // [esp+38h] [ebp-8h] int v22; // [esp+3Ch] [ebp-4h] unsigned int vars0; // [esp+40h] [ebp+0h] void *retaddr; // [esp+44h] [ebp+4h] //这个函数终极恐怖,整个就是一个虚拟机 vars0 = a3; v22 = a2; v21 = (int *)&vars0; v20 = &retaddr; v19 = a1; v15 = __readeflags(); *(_DWORD *)(a13 + 4188) = retaddr; sub_472EAC(a13, a14, a12, a15, &v21, &v20, &v19); //读取指令,并且翻译 vars0 = v18; __writeeflags(v18); __writeeflags(v18); return v16(&vars0); // 执行指令想,想不到吧 }
上面整个函数终极恐怖,他会把指令读出来然后进行翻译再执行
记录一下指令
00095032 add eax,0x7F eax 34 ->b1 ADD EAX, +7FH push 0x473A5E retn 00095034 xor edx,edx edx -> 00000 XOR EDX, EDX. push 0x473A84 retn 00095035 cmp eax,edx eax = B1 EDX = E0 c1 p1 a0 z0 s1 t0 d0 o0 CMP EAX, EDX 对比eax + 7h 比较 E0 eax = ‘a’ 如果这里真确则retrun 到第一条指令 对比eax + 7h 比较 B0 eax = ‘1’ 如果这里真确则retrun 到第一条指令 push 0x473A84 对比eax + 7h 比较 B1 eax = ‘2’ 如果这里真确则retrun 到第一条指令 retn 对比eax + 7h 比较 B2 eax = ‘3’ 如果这里真确则retrun到第一条指令 00095035 nop nop push 0x473A84 JNZ +XX 是否回到第一条 retn 00095046 nop JMP +09H nop push 0x473A84 retn LEA EAX, [EBP+FFFFFBE0H] PUSH EAX XOR ECX ECX CALL -000022D9H call 00491DEC
整理一下意思就是
int __usercall sub_4734B0@<eax>(int a1@<ebx>, int a2@<edi>, int a3@<esi>, int a4, int a5, int a6, int a7, int a8, int a9, int a10, int a11, int a12, int a13, int a14, int a15) { unsigned int v15; // et0 int (__fastcall *v16)(unsigned int *); // ST10_4 unsigned int v18; // [esp+10h] [ebp-30h] int v19; // [esp+30h] [ebp-10h] void **v20; // [esp+34h] [ebp-Ch] int *v21; // [esp+38h] [ebp-8h] int v22; // [esp+3Ch] [ebp-4h] unsigned int vars0; // [esp+40h] [ebp+0h] void *retaddr; // [esp+44h] [ebp+4h] //这个函数终极恐怖,整个就是一个虚拟机 vars0 = a3; v22 = a2; v21 = (int *)&vars0; v20 = &retaddr; v19 = a1; v15 = __readeflags(); *(_DWORD *)(a13 + 4188) = retaddr; sub_472EAC(a13, a14, a12, a15, &v21, &v20, &v19); //读取指令,并且翻译 vars0 = v18; __writeeflags(v18); __writeeflags(v18); return v16(&vars0); // 执行指令想,想不到吧 }
上面整个函数终极恐怖,他会把指令读出来然后进行翻译再执行
记录一下指令
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)
赞赏
他的文章
- 【原创】第六题 WP 5705
- [原创]第三题 write up by 青蛙Mage 6677
- [原创]第十题 write up by 青蛙mage 2187
- [原创]第一题write up 2458
看原图
赞赏
雪币:
留言: