2019 KCTF 晉級賽Q1 | 第三題點評及解題思路

Editor發表於2019-03-28

2019 KCTF 晉級賽Q1 | 第三題點評及解題思路


影分身之術是火影忍者中-鳴人的招牌忍術,火影迷們想必並不陌生了。與簡單的分身術相比,這個由二代火影千手扉間開創的忍術,其分出來的分身不再是幻影,而是實打實的實體。

你能成功識破哪個是真身,哪個是幻影嗎?接下來,讓我們一起來看看這道《影分身之術》,是如何被大家破解的吧!



第三題 影分身之術 


2019 KCTF 晉級賽Q1 | 第三題點評及解題思路


此題共有 35 支戰隊破解,圍觀人數達 3443 人。



出題團隊

戰神伽羅

2019 KCTF 晉級賽Q1 | 第三題點評及解題思路

戰隊成員看雪ID:simpower

個人主頁:https://bbs.pediy.com/user-177594.htm


簡介:

野生程式猿,臨床醫學專業轉行,現為北京某網路安全公司研發,從事惡意軟體動態行為分析產品的開發,對黑科技以及產品架構有很大興趣,設計出了超穩定的大規模掛鉤引擎,kctf中的戰神伽羅系列題目某種程度上反應了本猿平時的工作特徵,本系列賽題將會和你一起不斷進化,成長,歡迎繼續關注,感謝看雪!感謝有你參與!




看雪CTF 評委 crownless 點評 


《影分身之術》這道題採用了javascript加密,並考察了簡單的彙編。然而,不同的戰隊採用了不同的解題手法和工具,讓人大開眼界,值得學習和借鑑。



題目設計思路

1. 首先將一部分密碼封裝在javascript中,透過javascript將自身進行加密。


2. 透過簡單的彙編程式碼變形演算法 (加減固定數值) ,將一部分密碼程式碼編譯到可執行區域,透過指令跳轉和對硬編碼的變形對這部分密碼進行恢復比對。


3. 將恢復的程式碼注入到IE核心當中,並顯示出來。


破解思路


1. 搜尋記憶體可以搜到javascript程式碼,並將程式碼中的一部分密碼獲取出來。 


2019 KCTF 晉級賽Q1 | 第三題點評及解題思路


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碼 。


2019 KCTF 晉級賽Q1 | 第三題點評及解題思路


其中E0-7F='a'

B0-7F='1'

B1-7F='2'

B2-7F='3'


介面如下所示(註冊成功後):


2019 KCTF 晉級賽Q1 | 第三題點評及解題思路



題目破解思路 


本題破解思路由 oooAooo 提供


2019 KCTF 晉級賽Q1 | 第三題點評及解題思路



一、初探


初看程式是由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 | 第三題點評及解題思路



相關文章