2019 KCTF 晉級賽Q1 | 第三題點評及解題思路
影分身之術是火影忍者中-鳴人的招牌忍術,火影迷們想必並不陌生了。與簡單的分身術相比,這個由二代火影千手扉間開創的忍術,其分出來的分身不再是幻影,而是實打實的實體。
你能成功識破哪個是真身,哪個是幻影嗎?接下來,讓我們一起來看看這道《影分身之術》,是如何被大家破解的吧!
第三題 影分身之術
此題共有 35 支戰隊破解,圍觀人數達 3443 人。
出題團隊
戰神伽羅
戰隊成員看雪ID:simpower
個人主頁:https://bbs.pediy.com/user-177594.htm
簡介:
野生程式猿,臨床醫學專業轉行,現為北京某網路安全公司研發,從事惡意軟體動態行為分析產品的開發,對黑科技以及產品架構有很大興趣,設計出了超穩定的大規模掛鉤引擎,kctf中的戰神伽羅系列題目某種程度上反應了本猿平時的工作特徵,本系列賽題將會和你一起不斷進化,成長,歡迎繼續關注,感謝看雪!感謝有你參與!
看雪CTF 評委 crownless 點評
《影分身之術》這道題採用了javascript加密,並考察了簡單的彙編。然而,不同的戰隊採用了不同的解題手法和工具,讓人大開眼界,值得學習和借鑑。
題目設計思路
1. 首先將一部分密碼封裝在javascript中,透過javascript將自身進行加密。
2. 透過簡單的彙編程式碼變形演算法 (加減固定數值) ,將一部分密碼程式碼編譯到可執行區域,透過指令跳轉和對硬編碼的變形對這部分密碼進行恢復比對。
3. 將恢復的程式碼注入到IE核心當中,並顯示出來。
破解思路
1. 搜尋記憶體可以搜到javascript程式碼,並將程式碼中的一部分密碼獲取出來。
2. 解密後程式碼, 密碼為:simpower91
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!"); }
3. 剩下4位很容易就可以跟蹤到比對程式碼的那個call處,有4個很怪異的指令被跳過,將 每個位元組-7F就是剩餘的ascii碼 。
其中E0-7F='a'
B0-7F='1'
B1-7F='2'
B2-7F='3'
介面如下所示(註冊成功後):
題目破解思路
本題破解思路由 oooAooo 提供
一、初探
初看程式是由dephi寫的,從出題團隊來看,可能是去年的加強版。用DEDE反編譯一下看看,雖然註冊了幾個按鈕事件,但並不是核心校驗函式。可能是dephi+script形式。開啟IDA可以發現類似如下字串:
CODE:00493628 db 'function sptWBCallback(spt_wb_id,spt_wb_name,optionstr){url=',27h; Text CODE:00493628 db '#sptWBCallback:id=',27h,';url=url+spt_wb_id+',27h,';eventName=',27h; Text CODE:00493628 db '+spt_wb_name;if(optionstr) url=url+',27h,';params=optionstr',27h,';'; Text CODE:00493628 db 'location=url;}',0 ; Text CODE:00493868 db '<center><br><br><br><input value="" id="pswd" size=39></input><br'; Text CODE:00493868 db '><br><br><input type=button value="checkMyFlag" onclick="ckpswd()'; Text CODE:00493868 db ';"></center>',0 ; Text CODE:004938FF align 10h
從字串上看,存在一個html,裡面有個onclick的處理函式 ckpswd函式,首先需要找到ckpswd函式體。不想一步一步分析,啟動程式,用ce在記憶體總搜尋,很快可以發現如下指令碼函式:
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"; } }
可以看出要求輸入的sn開頭部分必須是 "simpower91",否則會提示 'worng!',測試一下確實如此,如果輸入simpower91111,沒有任何提示,看起來仍然有進一步的判斷。從上面的指令碼可知為sptWBCallback函式,看起來像個回撥函式。先找到sptWBCallback函式體。從前面的字串中可以看到其影子,在記憶體中搜尋下,發現如下:
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; }
上面程式碼應該是WebBrowser JS回撥delphi的方法。因此真正的檢測應該仍然在dephi主程式中。需要找到註冊時間的回撥函式。分析IDA反彙編程式碼發下如下:
CODE:00491DCC sub_491DCC proc near ; CODE XREF: _Tfrmcrackme_FormCreate+81↓p CODE:00491DCC push ebx CODE:00491DCD mov ebx, eax CODE:00491DCF mov eax, ebx CODE:00491DD1 call sub_491B78 ; call function CODE:00491DD6 mov eax, [ebx+40h] CODE:00491DD9 mov [eax+2A4h], ebx CODE:00491DDF mov dword ptr [eax+2A0h], offset sub_492088 CODE:00491DE9 pop ebx CODE:00491DEA retn CODE:00491DEA sub_491DCC endp
其中sub_492088函式比較可疑。設定個斷點,輸入 “ simpower91111 ”果然斷了下了。
二、回撥 sub_492088
int __userpurge sub_492088@<eax>(int a1@<eax>, int a2@<edx>, int a3@<ecx>, int a4@<ebx>, int a5@<esi>, int edi0@<edi>, _WORD *a6, int a7, int a8, int a9, int a10, int a11) { int v12; // ebx int v13; // esi int v14; // eax int v15; // eax Classes::TStrings *v16; // esi int v17; // ST14_4 int v18; // ST10_4 unsigned int v20; // [esp-14h] [ebp-34h] void *v21; // [esp-10h] [ebp-30h] int *v22; // [esp-Ch] [ebp-2Ch] int v23; // [esp-8h] [ebp-28h] int v24; // [esp-4h] [ebp-24h] int v25; // [esp+0h] [ebp-20h] int v26; // [esp+4h] [ebp-1Ch] int v27; // [esp+8h] [ebp-18h] char v28[4]; // [esp+Ch] [ebp-14h] int v29; // [esp+10h] [ebp-10h] int System::AnsiString; // [esp+14h] [ebp-Ch] int v31; // [esp+18h] [ebp-8h] int v32; // [esp+1Ch] [ebp-4h] int savedregs; // [esp+20h] [ebp+0h] System::AnsiString = 0; v29 = 0; *(_DWORD *)v28 = 0; v27 = 0; v26 = 0; v25 = 0; v24 = a4; v23 = a5; v31 = a3; v32 = a2; v12 = a1; v22 = &savedregs; v21 = &loc_4921D1; v20 = __readfsdword(0); __writefsdword(0, (unsigned int)&v20); Variants::__linkproc__ VarToLStr(&v29, a11); v13 = sub_465C88((int)&str__sptWBCallback_[1], v29); if ( v13 > 0 ) { *a6 = -1; Variants::__linkproc__ VarToLStr(&System::AnsiString, a11); v14 = GetJSLen(System::AnsiString); v15 = System::__linkproc__ LStrCopy(System::AnsiString, v13 + 15, v14 - v13 - 14, (int)&System::AnsiString); LOBYTE(v15) = 1; unknown_libname_161(System::AnsiString, (int)&str___41[1], (int)&str____19[1], v12, edi0, v13, (int)v28, v15); System::__linkproc__ LStrLAsg(&System::AnsiString, *(signed __int32 *)v28); v16 = (Classes::TStrings *)TStreamCreate((int)cls_Classes_TStringList, 1); (*(void (__fastcall **)(Classes::TStrings *, int))(*(_DWORD *)v16 + 44))(v16, System::AnsiString); if ( *(_WORD *)(v12 + 50) ) { Classes::TStrings::GetValue(v16, (const int)&str_params[1], (int)&v27); v17 = v27; Classes::TStrings::GetValue(v16, (const int)&str_eventName[1], (int)&v26); v18 = v26; Classes::TStrings::GetValue(v16, (const int)&str_id[1], (int)&v25); (*(void (__fastcall **)(_DWORD, int, int, int))(v12 + 48))(*(_DWORD *)(v12 + 52), v25, v18, v17); } } if ( *(_WORD *)(v12 + 58) ) (*(void (__fastcall **)(_DWORD, int, int, int, int, int, int, int, _WORD *))(v12 + 0x38))( *(_DWORD *)(v12 + 60), v32, v31, a11, a10, a9, a8, a7, a6); __writefsdword(0, v20); v22 = (int *)&loc_4921D8; return System::__linkproc__ LStrArrayClr(&v25, 6); }
核心處理函式為 V12+0X38,地址為;493F70
三、493F70函式
loc_493F70: ; DATA XREF: _Tfrmcrackme_FormCreate+87↑o CODE:00493F70 push ebp CODE:00493F71 mov ebp, esp CODE:00493F73 CODE:00493F73 loc_493F73: ; CODE XREF: CODE:00493FC5↓j CODE:00493F73 add esp, 0FFFFFBD8h CODE:00493F79 push ebx CODE:00493F7A push esi CODE:00493F7B xor ebx, ebx CODE:00493F7D mov [ebp-428h], ebx CODE:00493F83 mov [ebp-424h], ebx CODE:00493F89 mov [ebp-420h], ebx CODE:00493F8F mov [ebp-14h], edx CODE:00493F92 mov ebx, eax CODE:00493F94 mov eax, [ebp-14h] CODE:00493F97 call @System@@LStrAddRef$qqrpv ; System::__linkproc__ LStrAddRef(void *) CODE:00493F9C mov eax, [ebp+8] CODE:00493F9F call @System@@LStrAddRef$qqrpv ; System::__linkproc__ LStrAddRef(void *) CODE:00493FA4 xor eax, eax CODE:00493FA6 push ebp CODE:00493FA7 push offset loc_4941BA CODE:00493FAC push dword ptr fs:[eax] CODE:00493FAF mov fs:[eax], esp CODE:00493FB2 mov eax, [ebp-14h] CODE:00493FB5 call GetJSLen ; BDS 2005-2007 and Delphi6-7 Visual Component Library CODE:00493FBA cmp eax, 4 CODE:00493FBD jnz loc_494181 CODE:00493FC3 jmp short loc_493FE6 CODE:00493FC5 ; --------------------------------------------------------------------------- CODE:00493FC5 loopne near ptr loc_493F73+4 CODE:00493FC7 mov cl, 0B2h CODE:00493FC9 mov edx, offset byte_494045 CODE:00493FCE mov [ebp-4], edx CODE:00493FD1 mov edx, offset loc_4940D0 CODE:00493FD6 mov [ebp-8], edx CODE:00493FD9 mov edx, offset dword_494168 CODE:00493FDE mov [ebp-0Ch], edx CODE:00493FE1 jmp loc_4940DA CODE:00493FE6 ; --------------------------------------------------------------------------- CODE:00493FE6 CODE:00493FE6 loc_493FE6: ; CODE XREF: CODE:00493FC3↑j CODE:00493FE6 mov eax, offset _str_data_txt_1.Text CODE:00493FEB call @Sysutils@FileExists$qqrx17System@AnsiString ; Sysutils::FileExists(System::AnsiString) CODE:00493FF0 test al, al CODE:00493FF2 jz short loc_494010 CODE:00493FF4 mov dl, 1 CODE:00493FF6 mov eax, off_416648 CODE:00493FFB call TStreamCreate ; BDS 2005-2007 and Delphi6-7 Visual Component Library CODE:00494000 mov esi, eax CODE:00494002 mov edx, offset _str_data_txt_1.Text CODE:00494007 mov eax, esi CODE:00494009 call @Ibsql@TIBXSQLVAR@LoadFromFile$qqrx17System@AnsiString ; Ibsql::TIBXSQLVAR::LoadFromFile(System::AnsiString) CODE:0049400E jmp short loc_494025 CODE:00494010 ; --------------------------------------------------------------------------- CODE:00494010 CODE:00494010 loc_494010: ; CODE XREF: CODE:00493FF2↑j CODE:00494010 or ecx, 0FFFFFFFFh CODE:00494013 mov edx, offset _str_data_txt_1.Text CODE:00494018 mov eax, [ebx+330h] CODE:0049401E call GetVmpCode CODE:00494023 mov esi, eax CODE:00494025 CODE:00494025 loc_494025: ; CODE XREF: CODE:0049400E↑j CODE:00494025 mov edx, offset byte_494045 CODE:0049402A mov [ebp-4], edx CODE:0049402D mov eax, [ebp-4] CODE:00494030 push eax CODE:00494031 mov eax, [esi+4] CODE:00494034 push eax CODE:00494035 mov eax, ds:dword_498F3C CODE:0049403A push eax CODE:0049403B call sub_473A04 CODE:0049403B ; --------------------------------------------------------------------------- CODE:00494040 dd 0 CODE:00494044 db 0 CODE:00494045 byte_494045 db 0 ; DATA XREF: CODE:00493FC9↑o CODE:00494045 ; CODE:loc_494025↑o CODE:00494046 dd 0 CODE:0049404A align 4 CODE:0049404C dd 1Ah dup(0) CODE:004940B4 db 2 dup(0) CODE:004940B6 dd 0 CODE:004940BA align 4 CODE:004940BC dd 5 dup(0)
這個函式與去年的類似,程式對地址 494045程式碼進行解密,裡面存在一個反彙編引擎,對程式碼進行重定位,並一條一條執行,同時存在一個簡單的VMP。
73 69 6D 76 6D 01 00 05 00 .......simvm.... 00 F0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00 00 00 00 00 00 00 00 00 00 00 C5 3F 49 00 05 .............I.. 01 00 07 00 00 F0 00 00 00 00 00 00 00 00 01 00 ................ 00 00 01 05 00 00 F0 00 00 00 00 00 00 00 00 00 ................ 00 00 00 02 01 01 02 00 00 F0 00 00 00 00 F3 FF ................ FF FF 00 00 00 00 00 07 00 00 F0 00 00 00 00 00 ................ 00 00 00 00 00 00 00 03 01 00 07 00 00 F0 00 00 ................ 00 00 00 00 00 00 01 00 00 00 01 05 00 00 F0 00 ................ 00 00 00 01 00 00 00 00 00 00 00 03 01 01 02 00 ................ 00 F0 00 00 00 00 F2 FF FF FF 00 00 00 00 00 07 ................ 00 00 F0 00 00 00 00 00 00 00 00 00 00 00 00 03 ................ 01 00 07 00 00 F0 00 00 00 00 00 00 00 00 01 00 ................ 00 00 01 05 00 00 F0 00 00 00 00 02 00 00 00 00 ................ 00 00 00 03 01 01 02 00 00 F0 00 00 00 00 F1 FF ................ FF FF 00 00 00 00 00 07 00 00 F0 00 00 00 00 00 ................ 00 00 00 00 00 00 00 03 01 00 07 00 00 F0 00 00 ................ 00 00 00 00 00 00 01 00 00 00 01 05 00 00 F0 00 ................ 00 00 00 03 00 00 00 00 00 00 00 03 01 01 02 00 ................ 00 F0 00 00 00 00 F0 FF FF FF 00 00 00 00 00 07 ................ 00 00 F0 00 00 00 00 00 00 00 00 00 00 00 00 03 ................ 01 00 07 00 00 F0 00 00 00 00 00 00 00 00 00 00 ................ 00 00 04 02 00 00 F0 00 00 00 00 EC FF FF FF 00 ................ 00 00 00 03 01 00 07 00 00 F0 00 00 00 00 00 00 ................ 00 00 00 00 00 00 01 07 00 00 F0 00 00 00 00 00 ................ 00 00 00 00 00 00 00 03 6F 72 69 67 6E 83 C0 7F ........orign兝 . 33 D2 73 69 6D 76 6D 01 00 05 00 00 F0 00 00 00 3襰 imvm......... 00 00 00 00 00 01 00 00 00 01 02 00 00 F0 00 00 ................ 00 00 F3 FF FF FF 00 00 00 00 03 6F 72 69 67 6E ...........orign 3B C2 75 52 73 69 6D 76 6D 01 00 07 00 00 F0 00 ;聈 Rsimvm....... 00 00 00 00 00 00 00 00 00 00 00 04 02 00 00 F0 ................ 00 00 00 00 EC FF FF FF 00 00 00 00 03 01 00 07 ................ 00 00 F0 00 00 00 00 00 00 00 00 00 00 00 00 01 ................ 07 00 00 F0 00 00 00 00 01 00 00 00 00 00 00 00 ................ 04 6F 72 69 67 6E 83 C0 7F 33 D2 73 69 6D 76 6D .orign兝 .3襰 imvm 01 00 05 00 00 F0 00 00 00 00 00 00 00 00 01 00 ................ 00 00 01 02 00 00 F0 00 00 00 00 F2 FF FF FF 00 ................ 00 00 00 03 6F 72 69 67 6E 3B C2 75 3F 73 69 6D ....orign;聈 ?sim 76 6D 01 00 07 00 00 F0 00 00 00 00 00 00 00 00 vm.............. 00 00 00 00 04 02 00 00 F0 00 00 00 00 EC FF FF ................ FF 00 00 00 00 03 01 00 07 00 00 F0 00 00 00 00 ................ 00 00 00 00 00 00 00 00 01 07 00 00 F0 00 00 00 ................ 00 02 00 00 00 00 00 00 00 04 6F 72 69 67 6E 83 ..........orign. C0 7F 33 D2 73 69 6D 76 6D 01 00 05 00 00 F0 00 ..3襰 imvm....... 00 00 00 00 00 00 00 01 00 00 00 01 02 00 00 F0 ................ 00 00 00 00 F1 FF FF FF 00 00 00 00 03 6F 72 69 .............ori 67 6E 3B C2 75 2C 73 69 6D 76 6D 01 00 07 00 00 gn;聈 ,simvm..... F0 00 00 00 00 00 00 00 00 00 00 00 00 04 02 00 ................ 00 F0 00 00 00 00 EC FF FF FF 00 00 00 00 03 01 ................ 00 07 00 00 F0 00 00 00 00 00 00 00 00 00 00 00 ................ 00 01 07 00 00 F0 00 00 00 00 03 00 00 00 00 00 ................ 00 00 04 6F 72 69 67 6E 83 C0 7F 33 D2 73 69 6D ...orign兝 .3襰 im 76 6D 01 00 05 00 00 F0 00 00 00 00 00 00 00 00 vm.............. 01 00 00 00 01 02 00 00 F0 00 00 00 00 F0 FF FF ................ FF 00 00 00 00 03 6F 72 69 67 6E 3B C2 75 19 8D ......orign;聈 .. 85 E0 FB FF FF 50 33 C9 73 69 6D 76 6D 01 00 05 呧 ...P3蓅 imvm... 00 00 F0 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00 00 00 00 00 00 00 00 00 00 00 00 E8 41 49 00 ............鐰 I. 05 01 00 07 00 00 F0 00 00 00 00 00 00 00 00 00 ................ 00 00 00 04 04 00 00 F0 00 00 00 00 34 03 00 00 ............4... 00 00 00 00 06 6F 72 69 67 6E E8 27 DD FF FF EB .....orign...... 09 73 69 6D 76 6D 65 6E 64 00 .simvmend
上面是指令碼,其中帶有 simvm 標識的為VMP程式碼,帶有orgin的為原始程式碼,對於simvm的程式碼走虛擬機器執行引擎,對於orgin標識透過反編譯引擎,並重定位執行。
493F70 會呼叫473A04 上面的邏輯主要在本函式執行。
CODE:00473A04 sub_473A04 proc near ; CODE XREF: CODE:0049403B↓p CODE:00473A04 CODE:00473A04 var_2C = dword ptr -2Ch CODE:00473A04 var_8 = dword ptr -8 CODE:00473A04 var_4 = dword ptr -4 CODE:00473A04 var_s0 = dword ptr 0 CODE:00473A04 arg_4 = dword ptr 0Ch CODE:00473A04 arg_8 = dword ptr 10h CODE:00473A04 CODE:00473A04 push ebp CODE:00473A05 mov ebp, esp CODE:00473A07 leave CODE:00473A08 push dword ptr [esp+0] CODE:00473A0B push [esp+var_s0] CODE:00473A0E push [esp+4+var_4] CODE:00473A11 pusha CODE:00473A12 pushf CODE:00473A13 call sub_4723EC CODE:00473A18 mov ebx, eax CODE:00473A1A xor eax, eax CODE:00473A1C mov [ebx+1050h], eax CODE:00473A22 mov eax, 0FFFFFFFFh CODE:00473A27 mov [ebx+1054h], eax CODE:00473A2D mov [esp+2Ch+var_8], ebx CODE:00473A31 mov eax, [esp+2Ch+arg_8] ; eax = encryptCodeAddr CODE:00473A35 mov [esp+2Ch+var_4], eax CODE:00473A39 mov eax, [esp+2Ch+arg_4] CODE:00473A3D mov [esp+2Ch+var_s0], eax CODE:00473A41 mov eax, [ebx+1090h] CODE:00473A47 cmp eax, 0 CODE:00473A4A jnz short loc_473A57 CODE:00473A4C mov eax, offset codeCrypt CODE:00473A51 mov [ebx+1090h], eax CODE:00473A57 CODE:00473A57 loc_473A57: ; CODE XREF: sub_473A04+46↑j CODE:00473A57 popf CODE:00473A58 popa CODE:00473A59 call HandleCode CODE:00473A5E pushf CODE:00473A5F pushf CODE:00473A60 pushf CODE:00473A61 pusha CODE:00473A62 pushf CODE:00473A63 jmp short loc_473A89 CODE:00473A65 ; --------------------------------------------------------------------------- CODE:00473A65 CODE:00473A65 loc_473A65: ; CODE XREF: sub_473A04+98↓j CODE:00473A65 mov eax, [ebx+1058h] CODE:00473A6B mov [esp+2Ch+var_s0], eax CODE:00473A6F mov eax, [ebx+1050h] CODE:00473A75 mov [esp+2Ch+var_4], eax CODE:00473A79 mov [esp+2Ch+var_8], ebx CODE:00473A7D popf CODE:00473A7E popa CODE:00473A7F call HandleCode CODE:00473A84 pushf CODE:00473A85 pushf CODE:00473A86 pushf CODE:00473A87 pusha CODE:00473A88 pushf CODE:00473A89 CODE:00473A89 loc_473A89: ; CODE XREF: sub_473A04+5F↑j CODE:00473A89 call sub_4723EC CODE:00473A8E mov ebx, eax CODE:00473A90 mov eax, [ebx+1050h] CODE:00473A96 cmp eax, [ebx+1054h] CODE:00473A9C jb short loc_473A65 CODE:00473A9E mov eax, [ebx+1050h] CODE:00473AA4 mov [esp+30h], eax CODE:00473AA8 mov eax, [esp+2Ch+var_2C] CODE:00473AAB mov [esp+2Ch+var_s0], eax CODE:00473AAF popf CODE:00473AB0 popa CODE:00473AB1 add esp, 8 CODE:00473AB4 popf CODE:00473AB5 retn 0Ch CODE:00473AB5 sub_473A04 endp CODE:00473AB5
而其核心函式為HandleCode(472EAC)
int __usercall HandleCode@<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; DecryptData(a13, a14, a12, (char *)a15, &v21, (int *)&v20, &v19); vars0 = v18; __writeeflags(v18); __writeeflags(v18); return v16(&vars0); }
其中 "16(&vars0);"語句為執行重定位後的程式碼。而虛擬機器以及原始程式碼重定位在DecryptData函式(472EAC)如下:
DWORD *__stdcall DecryptData(int a1, int orgAddr, int a3, char *dataOfFile, _DWORD *a5, int *a6, _DWORD *a7) { _DWORD *global; // ebx int v8; // esi int v9; // edi int v10; // eax int v11; // ecx int v12; // esi int v13; // esi int v14; // eax int v15; // ST18_4 unsigned int v17; // [esp+1Ch] [ebp-77Ch] void *v18; // [esp+20h] [ebp-778h] int *v19; // [esp+24h] [ebp-774h] int v20; // [esp+34h] [ebp-764h] int v21; // [esp+38h] [ebp-760h] char data[1024]; // [esp+3Fh] [ebp-759h] int v23; // [esp+440h] [ebp-358h] char v24; // [esp+444h] [ebp-354h] char v25; // [esp+544h] [ebp-254h] unsigned __int8 orgCodeLen; // [esp+77Ah] [ebp-1Eh] char v27; // [esp+77Bh] [ebp-1Dh] char *nextData; // [esp+77Ch] [ebp-1Ch] char *data1; // [esp+780h] [ebp-18h] _BYTE *v30; // [esp+784h] [ebp-14h] int outDataLen; // [esp+788h] [ebp-10h] int v32; // [esp+78Ch] [ebp-Ch] int opCodeLen; // [esp+790h] [ebp-8h] _DWORD *v34; // [esp+794h] [ebp-4h] int vars0; // [esp+798h] [ebp+0h] v21 = 0; v20 = 0; v30 = 0; v19 = &vars0; v18 = &loc_4732B2; v17 = __readfsdword(0); __writefsdword(0, (unsigned int)&v17); global = sub_4723EC(); v34 = (_DWORD *)(vars0 + 8); data1 = data; v8 = *(_DWORD *)off_497644; *(_DWORD *)(*(_DWORD *)off_497644 + 52) = 0; v27 = 0; while ( 1 ) { callCodeDecrypt((int)global, dataOfFile, data, &outDataLen); while ( 1 ) { while ( *(_DWORD *)(v8 + 52) == 1 ) { orgCodeLen = 0; nextData = callVmpHandle(v8, (_BYTE *)orgAddr, data, (int)&orgCodeLen); opCodeLen = nextData - data; GetNextValueByLen(&dataOfFile, nextData - data); GetNextValueByLen(&orgAddr, orgCodeLen); callCodeDecrypt((int)global, dataOfFile, data, &outDataLen); } if ( ifCode_simvm_orign(v8, &data1) != 1 )// 不是 simvm break; data1 = data; v27 = 1; simvm_Handle(global, v34); } data1 = data; if ( !v27 ) break; v27 = 0; orgin_Handle(global, v34); } outDataLen = off_498CA0(data, outDataLen, 0x400000, &v23, 4, v17);// 執行原始code *a5 = outDataLen; v9 = unknown_libname_29(32 - outDataLen - 6); data1 = (char *)global + v9 + 4144; sub_464FA4(data1, data, outDataLen); *((_BYTE *)global + v9 + outDataLen + 4144) = 104; GetCharFormTstring((int)&v30, &v25); if ( (unsigned __int8)sub_472520(v30, global[1047]) ) { GetCharFormTstring((int)&v30, &v24); opCodeLen = sub_465C88((int)&str___29[1], (int)v30); v10 = GetJSLen(v30); System::__linkproc__ LStrCopy((int)v30, opCodeLen + 1, v10 - opCodeLen, (int)&v30); opCodeLen = sub_465CEC(v30); if ( outDataLen - 1 >= 0 ) { v11 = outDataLen; v32 = 0; do { *((_BYTE *)global + v9 + v32++ + 4144) = -112; --v11; } while ( v11 ); } opCodeLen += outDataLen; v12 = sub_471F04(v8, data, opCodeLen); } else if ( sub_465C88((int)&str_CALL_0[1], (int)v30) == 1 ) { GetCharFormTstring((int)&v30, &v24); if ( sub_465C88((int)&str_FF_0[1], (int)v30) != 1 ) { opCodeLen = sub_465C88((int)&str___29[1], (int)v30); v32 = opCodeLen - 1; v13 = (opCodeLen - 1) / 2; data1 = (char *)global + v9 + v13 + 4144; v14 = GetJSLen(v30); System::__linkproc__ LStrCopy((int)v30, opCodeLen + 1, v14 - opCodeLen, (int)&v30); opCodeLen = sub_465CEC(v30); v32 = opCodeLen + orgAddr - ((_DWORD)global + v9 + 4144); sub_464FA4(data1, &v32, outDataLen - v13); } opCodeLen = outDataLen; v12 = outDataLen; } else { opCodeLen = outDataLen; v12 = outDataLen; } *a7 = opCodeLen; opCodeLen = a3; data1 = (char *)global + v9 + outDataLen + 4145; sub_464FA4(data1, &opCodeLen, 4u); *((_BYTE *)global + v9 + outDataLen + 4149) = 0xC3u; *a6 = (int)global + v9 + 0x1030; global[1044] = orgAddr + *a7; global[1046] = &dataOfFile[v12]; GetCharFormTstring((int)&v21, &v25); v15 = v21; GetCharFormTstring((int)&v20, &v24); sub_4736D4((int)global, *a6, orgAddr, v15, v20, outDataLen); __writefsdword(0, v17); v19 = (int *)&loc_4732B9; System::__linkproc__ LStrArrayClr(&v20, 2); return System::__linkproc__ LStrClr(&v30); }
其中如下程式碼為執行VMP程式碼:
while ( 1 ) { callCodeDecrypt((int)global, dataOfFile, data, &outDataLen); while ( 1 ) { while ( *(_DWORD *)(v8 + 52) == 1 ) { orgCodeLen = 0; nextData = callVmpHandle(v8, (_BYTE *)orgAddr, data, (int)&orgCodeLen); opCodeLen = nextData - data; GetNextValueByLen(&dataOfFile, nextData - data); GetNextValueByLen(&orgAddr, orgCodeLen); callCodeDecrypt((int)global, dataOfFile, data, &outDataLen); } if ( ifCode_simvm_orign(v8, &data1) != 1 )// 不是 simvm break; data1 = data; v27 = 1; simvm_Handle(global, v34); } data1 = data; if ( !v27 ) break; v27 = 0; orgin_Handle(global, v34); }
後半部分為執行原始程式碼,進行反編譯從定位。
下面是虛擬程式相關函式:
char *__fastcall callVmpHandle(int unknowGlogal, _BYTE *orgAddr, _BYTE *data, int global) { int unknowGlogal_1; // ebx char *data_2; // [esp+4h] [ebp-8h] char *data_1; // [esp+8h] [ebp-4h] data_1 = data; unknowGlogal_1 = unknowGlogal; data_2 = data; if ( *(_DWORD *)(unknowGlogal + 52) == 1 ) { if ( ifCode_simvm_orign(unknowGlogal, &data_1) == 2 ) { data_2 = data_1; // orgin } else { data_2 = data_1; if ( *data_1 == byte_497214 ) data_2 = vmpHandle(unknowGlogal_1, data_1, (char *)global); else *(_DWORD *)(unknowGlogal_1 + 52) = 2; } } return data_2; } char *__fastcall vmpHandle(int unknowGlogal, char *data, char *a3) { char *v3; // ST1C_4 int unknowGlogal_1; // edi char num0Data; // bl int num6Data; // ebp char *dataEnd; // [esp+4h] [ebp-38h] char num5Data; // [esp+8h] [ebp-34h] int num7Data; // [esp+Ch] [ebp-30h] int num8Data; // [esp+10h] [ebp-2Ch] int num9Data; // [esp+14h] [ebp-28h] int num1Data; // [esp+18h] [ebp-24h] int num2Data; // [esp+1Ch] [ebp-20h] int num3Data; // [esp+20h] [ebp-1Ch] int num4Data; // [esp+24h] [ebp-18h] char *data_1; // [esp+28h] [ebp-14h] v3 = a3; unknowGlogal_1 = unknowGlogal; dataEnd = data + 0x24; data_1 = data; GetNextValueByLen(&data_1, 1); num0Data = *data_1; GetNextValueByLen(&data_1, 1); num1Data = *(_DWORD *)data_1; GetNextValueByLen(&data_1, 4); num2Data = *(_DWORD *)data_1; GetNextValueByLen(&data_1, 4); num3Data = *(_DWORD *)data_1; GetNextValueByLen(&data_1, 4); num4Data = *(_DWORD *)data_1; GetNextValueByLen(&data_1, 4); num5Data = *data_1; GetNextValueByLen(&data_1, 1); num6Data = *(_DWORD *)data_1; GetNextValueByLen(&data_1, 4); num7Data = *(_DWORD *)data_1; GetNextValueByLen(&data_1, 4); num8Data = *(_DWORD *)data_1; GetNextValueByLen(&data_1, 4); num9Data = *(_DWORD *)data_1; GetNextValueByLen(&data_1, 4); *v3 = *data_1; if ( num0Data || num5Data ) { if ( num0Data && num5Data ) { sub_471CDC(num0Data, num9Data, num8Data, num7Data, num6Data, num4Data, num3Data); } else if ( !num0Data || num5Data ) { if ( !num0Data && num5Data ) call_vmp_add_reg_value( unknowGlogal_1, num1Data, num2Data, num3Data, num4Data, num6Data, num7Data, num8Data, num9Data, num5Data); } else { call_vmp_memcpy_regAndReg_num( unknowGlogal_1, num1Data, num2Data, num3Data, num4Data, num6Data, num7Data, num8Data, num9Data, num0Data); } } else { sub_471C08(unknowGlogal_1, num1Data, num2Data, num3Data, num4Data, num6Data, num7Data, num8Data, num9Data, 0); } return dataEnd; }
int __fastcall call_vmp_add_reg_value(int unknowGlogal, int num1Data, int num2Data, int num3Data, int num4Data, int num6Data, int num7Data, int num8Data, int num9Data, char num5Data) { if ( num1Data && num6Data ) return vmp_add_reg_value(unknowGlogal, num1Data, num3Data, num6Data, num8Data, num5Data); if ( num1Data && num7Data ) return vmp_add_reg_value(unknowGlogal, num1Data, num3Data, num7Data, num8Data, num5Data); if ( num1Data && num9Data ) return vmp_add_reg_value(unknowGlogal, num1Data, num3Data, num9Data, 0, 0); if ( num2Data && num6Data ) return vmp_add_reg_value(unknowGlogal, num2Data, num3Data, num6Data, num8Data, num5Data); if ( num2Data && num7Data ) return vmp_add_reg_value(unknowGlogal, num2Data, num3Data, num7Data, num8Data, num5Data); if ( num2Data ) { if ( num9Data ) unknowGlogal = vmp_add_reg_value(unknowGlogal, num2Data, num3Data, num9Data, 0, 0); } return unknowGlogal; }
就是一些簡單的暫存器讀取以及加減乘除運算。
下面的函式是針對程式碼解密的,就是異或0xFF.
DWORD *__fastcall codeCrypt(int a1, int dataOfFile, char *outData, _DWORD *a4) { int v4; // ecx char v5; // zf _DWORD *v6; // eax unsigned int v8; // [esp+8h] [ebp-20h] void *v9; // [esp+Ch] [ebp-1Ch] int *v10; // [esp+10h] [ebp-18h] int v11; // [esp+20h] [ebp-8h] char *outData1; // [esp+24h] [ebp-4h] int savedregs; // [esp+28h] [ebp+0h] v11 = 0; v10 = &savedregs; v9 = &loc_473839; v8 = __readfsdword(0); __writefsdword(0, (unsigned int)&v8); *a4 = 0x400; outData1 = outData; v4 = 0; do { outData1[v4] = ~*(_BYTE *)(dataOfFile + v4); ++v4; } while ( v4 != 0x400 ); GetCharFormTstring((int)&v11, outData1 + 2); System::__linkproc__ LStrCmp(v11, &str_simvmend[1]._top); if ( v5 ) // 判斷程式碼是否結束 { v6 = sub_4723EC(); v6[0x415] = v6[0x414]; } __writefsdword(0, v8); v10 = (int *)&loc_473840; return System::__linkproc__ LStrClr(&v11); }
三、sn
如下vm指令的主要功能就是解密最後的字串"a123"
73 69 6D 76 6D 01 00 05 00 .......simvm.... 00 F0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00 00 00 00 00 00 00 00 00 00 00 C5 3F 49 00 05 .............I.. 01 00 07 00 00 F0 00 00 00 00 00 00 00 00 01 00 ................ 00 00 01 05 00 00 F0 00 00 00 00 00 00 00 00 00 ................ 00 00 00 02 01 01 02 00 00 F0 00 00 00 00 F3 FF ................ FF FF 00 00 00 00 00 07 00 00 F0 00 00 00 00 00 ................ 00 00 00 00 00 00 00 03 01 00 07 00 00 F0 00 00 ................ 00 00 00 00 00 00 01 00 00 00 01 05 00 00 F0 00 ................ 00 00 00 01 00 00 00 00 00 00 00 03 01 01 02 00 ................ 00 F0 00 00 00 00 F2 FF FF FF 00 00 00 00 00 07 ................ 00 00 F0 00 00 00 00 00 00 00 00 00 00 00 00 03 ................ 01 00 07 00 00 F0 00 00 00 00 00 00 00 00 01 00 ................ 00 00 01 05 00 00 F0 00 00 00 00 02 00 00 00 00 ................ 00 00 00 03 01 01 02 00 00 F0 00 00 00 00 F1 FF ................ FF FF 00 00 00 00 00 07 00 00 F0 00 00 00 00 00 ................ 00 00 00 00 00 00 00 03 01 00 07 00 00 F0 00 00 ................ 00 00 00 00 00 00 01 00 00 00 01 05 00 00 F0 00 ................ 00 00 00 03 00 00 00 00 00 00 00 03 01 01 02 00 ................ 00 F0 00 00 00 00 F0 FF FF FF 00 00 00 00 00 07 ................ 00 00 F0 00 00 00 00 00 00 00 00 00 00 00 00 03 ................ 01 00 07 00 00 F0 00 00 00 00 00 00 00 00 00 00 ................ 00 00 04 02 00 00 F0 00 00 00 00 EC FF FF FF 00 ................ 00 00 00 03 01 00 07 00 00 F0 00 00 00 00 00 00 ................ 00 00 00 00 00 00 01 07 00 00 F0 00 00 00 00 00 ................ 00 00 00 00 00 00 00 03 6F 72 69 67 6E 83 C0 7F ........orign兝 . 33 D2 73 69 6D 76 6D 01 00 05 00 00 F0 00 00 00 3襰 imvm......... 00 00 00 00 00 01 00 00 00 01 02 00 00 F0 00 00 ................ 00 00 F3 FF FF FF 00 00 00 00 03 6F 72 69 67 6E ...........orign 3B C2 75 52 73 69 6D 76 6D 01 00 07 00 00 F0 00 ;聈 Rsimvm....... 00 00 00 00 00 00 00 00 00 00 00 04 02 00 00 F0 ................ 00 00 00 00 EC FF FF FF 00 00 00 00 03 01 00 07 ................ 00 00 F0 00 00 00 00 00 00 00 00 00 00 00 00 01 ................ 07 00 00 F0 00 00 00 00 01 00 00 00 00 00 00 00 ................ 04 6F 72 69 67 6E 83 C0 7F 33 D2 73 69 6D 76 6D .orign兝 .3襰 imvm 01 00 05 00 00 F0 00 00 00 00 00 00 00 00 01 00 ................ 00 00 01 02 00 00 F0 00 00 00 00 F2 FF FF FF 00 ................ 00 00 00 03 6F 72 69 67 6E 3B C2 75 3F 73 69 6D ....orign;聈 ?sim 76 6D 01 00 07 00 00 F0 00 00 00 00 00 00 00 00 vm.............. 00 00 00 00 04 02 00 00 F0 00 00 00 00 EC FF FF ................ FF 00 00 00 00 03 01 00 07 00 00 F0 00 00 00 00 ................ 00 00 00 00 00 00 00 00 01 07 00 00 F0 00 00 00 ................ 00 02 00 00 00 00 00 00 00 04 6F 72 69 67 6E 83 ..........orign. C0 7F 33 D2 73 69 6D 76 6D 01 00 05 00 00 F0 00 ..3襰 imvm....... 00 00 00 00 00 00 00 01 00 00 00 01 02 00 00 F0 ................ 00 00 00 00 F1 FF FF FF 00 00 00 00 03 6F 72 69 .............ori 67 6E 3B C2 75 2C 73 69 6D 76 6D 01 00 07 00 00 gn;聈 ,simvm..... F0 00 00 00 00 00 00 00 00 00 00 00 00 04 02 00 ................ 00 F0 00 00 00 00 EC FF FF FF 00 00 00 00 03 01 ................ 00 07 00 00 F0 00 00 00 00 00 00 00 00 00 00 00 ................ 00 01 07 00 00 F0 00 00 00 00 03 00 00 00 00 00 ................ 00 00 04 6F 72 69 67 6E 83 C0 7F 33 D2 73 69 6D ...orign兝 .3襰 im 76 6D 01 00 05 00 00 F0 00 00 00 00 00 00 00 00 vm.............. 01 00 00 00 01 02 00 00 F0 00 00 00 00 F0 FF FF ................ FF 00 00 00 00 03 6F 72 69 67 6E 3B C2 75 19 8D ......orign;聈 .. 85 E0 FB FF FF 50 33 C9 73 69 6D 76 6D 01 00 05 呧 ...P3蓅 imvm... 00 00 F0 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00 00 00 00 00 00 00 00 00 00 00 00 E8 41 49 00 ............鐰 I. 05 01 00 07 00 00 F0 00 00 00 00 00 00 00 00 00 ................ 00 00 00 04 04 00 00 F0 00 00 00 00 34 03 00 00 ............4... 00 00 00 00 06 6F 72 69 67 6E E8 27 DD FF FF EB .....orign...... 09 73 69 6D 76 6D 65 6E 64 00 .simvmend
sn為 :simpower91a123
文章來源:2019 KCTF 晉級賽Q1 | 第三題點評及解題思路
相關文章
- 2019KCTF 晉級賽Q1 | 第九題點評及解題思路2019-04-04
- 2019KCTF 晉級賽Q1 | 第十題點評及解題思路2019-04-08
- 2020 KCTF秋季賽 | 第一題點評及解題思路2020-11-20
- 2020 KCTF秋季賽 | 第四題點評及解題思路2020-11-24
- 看雪.紐盾 KCTF 2019 Q2 | 第三題點評及解題思路2019-07-01
- 看雪.紐盾 KCTF 2019 Q3 | 第一題點評及解題思路2019-09-25
- 看雪.紐盾 KCTF 2019 Q3 | 第四題點評及解題思路2019-09-29
- 看雪.紐盾 KCTF 2019 Q3 | 第七題點評及解題思路2019-09-30
- 看雪.紐盾 KCTF 2019 Q3 | 第六題點評及解題思路2019-10-08
- 看雪.紐盾 KCTF 2019 Q3 | 第八題點評及解題思路2019-10-08
- 看雪.紐盾 KCTF 2019 Q3 | 第九題點評及解題思路2019-10-08
- 看雪.紐盾 KCTF 2019 Q3 | 第十題點評及解題思路2019-10-08
- 看雪.紐盾 KCTF 2019 Q2 | 第九題點評及解題思路2019-07-04
- 看雪.紐盾 KCTF 2019 Q2 | 第十題點評及解題思路2019-07-05
- 看雪.紐盾 KCTF 2019 Q2 | 第一題點評及解題思路2019-07-01
- 看雪.紐盾 KCTF 2019 Q2 | 第二題點評及解題思路2019-07-01
- 看雪.紐盾 KCTF 2019 Q2 | 第五題點評及解題思路2019-07-01
- 看雪.紐盾 KCTF 2019 Q2 | 第七題點評及解題思路2019-07-02
- 看雪.紐盾 KCTF 2019 Q2 | 第八題點評及解題思路2019-07-03
- 看雪.紐盾 KCTF 2019 Q2 | 第六題點評及解題思路2019-07-01
- 看雪.紐盾 KCTF 2019 Q3 | 第十一題點評及解題思路2019-10-08
- 看雪.紐盾 KCTF 2019 Q3 | 第十二題點評及解題思路2019-10-08
- 看雪.紐盾 KCTF 2019 Q3 | 第十三題點評及解題思路2019-10-08
- 2020 KCTF秋季賽 | 第二題設計及解題思路2020-11-23
- 2020 KCTF秋季賽 | 第五題設計及解題思路2020-11-30
- 看雪·深信服 2021 KCTF 春季賽 | 第三題設計思路及解析2021-05-14
- 看雪·眾安 2021 KCTF 秋季賽 | 第三題設計思路及解析2021-11-22
- 看雪.騰訊TSRC 2017 CTF 秋季賽 第三題點評及解析思路2017-10-30
- 看雪.WiFi萬能鑰匙 CTF 2017第三題 點評及解題思路2017-06-29WiFi
- 看雪·深信服 2021 KCTF 春季賽 | 第七題設計思路及解析2021-05-25
- 看雪·深信服 2021 KCTF 春季賽 | 第八題設計思路及解析2021-05-25
- 看雪·深信服 2021 KCTF 春季賽 | 第九題設計思路及解析2021-05-28
- 看雪·深信服 2021 KCTF 春季賽 | 第四題設計思路及解析2021-05-17
- 看雪·深信服 2021 KCTF 春季賽 | 第五題設計思路及解析2021-05-17
- 看雪·深信服 2021 KCTF 春季賽 | 第六題設計思路及解析2021-05-21
- 看雪·深信服 2021 KCTF 春季賽 | 第二題設計思路及解析2021-05-12
- 看雪·深信服 2021 KCTF 春季賽 | 第十題設計思路及解析2021-05-31
- 看雪·眾安 2021 KCTF 秋季賽 | 第十題設計思路及解析2021-12-16