[VS2015] 用 VS2015 來對 JScript/VBScript 檔案單步執行除錯

[VS2015] 用 VS2015 來對 JScript/VBScript 檔案單步執行除錯

最近拿到一個用 JScript 寫的病毒檔案,想來研究一下看看它是怎麼寫的,

但看了一下,發現裡面用了許多將程式模糊化 (obfuscation) 的技巧,

要單單憑肉眼就看出這個 JScript 在做什麼是很困難的,

最好還是用一個 script debugger 來單步執行,比較能正確的解譯~

當然另一種方法是在檔案裡加一堆 WScript.Echo 顯示變數的值,

但變數太多時,這個方法會很累…

 

在網路上搜尋了一下,看到大部分提到的是一個很舊的 Microsoft Script Debugger 的東西,

但這個東西已經很久沒更新了,在網路上找到的版本也都無法執行…

後來才發現,原來我剛剛裝好的 Visual Studio 2015 就可以拿來 debug JScript/VBScript 了~

 

假設 JScript 的檔名是 test.js 的話,可以用下列的方式,

使用 cscript 的參數 //x,把 Visual Studio 2015 叫起來對它除錯:

cscript //x test.js

 

執行後,就會彈出一個對話框讓我們選擇 debugger,

可以選 New instance of VS2015 開一個新的 VS2015 視窗,

或是用現有的 VS2015 的視窗都行:

20160711_180620

 

接著就進到熟悉的除錯畫面,按 F10/F11 可以分別 Step Over/Step Into,

也可以開著 Locals 視窗,方便檢查變數值:

20160711_180648

 

來提一下模糊化 (obfuscation) 吧~

以今天分析的這隻樣本為例,它裡面寫了一堆其實根本沒用到的程式碼,

像是它定義了 Point 這個類別,也寫了不少相關的函式,

乍看下好像這程式是在處理一個點 (Point) 的相關動作,但這個類別其實完全沒被使用到:

function Point(x, y)
{
this.x = x || 0;
this.y = y || 0;
}
Point.create = function(o, y)
{
if (isArray(o)) return new Point(o[0], o[1]);
if (isObject(o)) return new Point(o.x, o.y);
return new Point(o, y);
};
Point.add = function(p1, p2)
{
return new Point(p1.x + p2.x, p1.y + p2.y);
};

 

另一種常見的模糊化手法,是用很複雜的編碼解碼動作,

讓我們沒辦法直接看出來變數值會是多少~

像是下面定義了一個叫 miami4() 的函式,

當字串 archivesarchivesJVarchivesRFTVarchivesAl 被丟進去時,

得到的結果是 %TEMP%:

String.prototype.miami4 = function()
{
var c1, c2, c3, c4;
var i, len, out;
var str = this.replace(/archives/g, '')
len = str.length;
i = 0;
out = "";
while (i < len)
{
do {
c1 = libel[str.charCodeAt(i++) & 0xff]
} while (i < len && c1 == -1);
if (c1 == -1)
break;
var dodo = false;
do {
c2 = libel[str.charCodeAt(i++) & 0xff];
dodo = i < len && c2 == -1;
} while (dodo);
if (c2 == -1)
break;
out += String.fromCharCode((c1 << 2) | ((c2 & 0x30) >> 4));
do {
c3 = str.charCodeAt(i++) & 0xff;
if (c3 == 61)
return out;
c3 = libel[c3]
} while (i < len && c3 == -1);
if (c3 == -1)
break;
out += String.fromCharCode(((c2 & 0XF) << 4) | ((c3 & 0x3C) >> 2));
do {
c4 = str.charCodeAt(i++) & 0xff;
if (c4 == 61)
return out;
c4 = libel[c4]
} while (i < len && c4 == -1);
if (c4 == -1)
break;
out += String.fromCharCode(((c3 & 0x03) << 6) | c4)
}
return out
}
var ranger = "archivesarchivesJVarchivesRFTVarchivesAl".miami4();

 

上面這種複雜的運算當然是不用自己去手算了,用 VS2015 的 Locals 視窗就可以看到變數的值~

只不過通常它們還會搭配使用非常難記、或是沒什麼意義的變數名稱,

像上例中用 ranger 這個變數,來儲存 %TEMP% 這個之後要儲存檔案的目錄…

 

這樣本裡用的另一種模糊化手法,是利用逗號運算子 (,) 求值只會取最右邊的值的特性~

舉例來說,(“loathsome”, “felong”, …, “exe”) 求值的結果是 “exe”,

但 “exe” 前面的參數隨便亂換成其他的東西,也不影響最後求值的結果。

這樣的話,病毒作者就可以隨意的變換整個敘述,但最終的結果是一樣的~

如果不是用單步執行的話,是很難知道 unrestrained 會變成一個如下的陣列的:

[0] “ActiveXObject”
[1] “ExpandEnvironmentStrings”
[2] “%TEMP%”
[3] “.exe”
[4] “Run”
[5] “MSXML2.XMLHTTP>WScript.Shell”:

var unrestrained = [ungodly, workroom, ranger, "" + "." + ("loathsome", "felony", "painting", "budgets", "recluse", "otter", "hills", "northeast", "exe"), "UnarchivesVuarchives".miami4(), miami("M" + "SX" + "ML" + ("iniquitous", "saturn", "weird", "caroline", "softball", "template", "preventing", "2.") + "381M" + "LH" + "TT" + ("abortion", "ladies", "october", "retrospect", "julian", "preside", "kenneth", "twisted", "P>") + "WU" + ("baghdad", "tutorial", "technological", "tassel", "invariable", "concur", "whipping", "cr") + ("flawless", "charles", "juvenile", "encountered", "pollux", "conserve", "adjacent", "householder", "ip") + "t:" + ("linguist", "participate", "dedicate", "media", "offal", "shades", "interrogatory", "peterson", "Sh") + "ell")];

 

在單步執行的過程中,有時因為整個敘述可能會將函式結果串接起來,

導致我們沒辦法知道各別小步驟的值是什麼,這時用 Watch 就能很方便的求值~

舉例來說,下面一個落落長的敘述,它裡面用到了上面的複雜函式 miami4(),

因此看不出來到底在做什麼,如果直接單步執行過去又會忽略掉一些細節:

var advocacy = ("casque" + WScript == "casque" + "V2luZGarchives93cyBTY3JpcHQgarchivesSG9zdA=archives=".miami4()) && selecting["c3archivesRhdHarchivesVz".miami4()] + "" == "MjarchivesAw".miami4() && typeof(GzEAPd) === "undefined";

 

利用 Watch 視窗,可以看到 “c3archivesRhdHarchivesVz”.miami4() 傳回的是 “status”,

以及 “MjarchivesAw”.miami4() 傳回的是 “200”,

搭配之前單步執行時觀察到 selecting 代表的是一個 MSXML2.XMLHTTP 物件,

就可以明瞭它其實是在檢查一個 HTTP 請求的回傳狀態是不是 200 OK:

20160711_181500

 

上面的叙述最後是 false,因為它想要連的網址已經被禁止訪問了 (403 forbidden),

這會導致我們無法繼續單步執行下去,

但 VS2015 的好處是我們可以直接修改執行中變數的值,

像本例中將 advocacy 從 false 改成 true,就可以繼續執行病毒的工作,

它在發現 HTTP 請求成功 (HTTP 200) 之後,就會將下載下來的東西儲存下來:

20160711_181526  

 

用單步執行的方法來追踪病毒,其實還是蠻辛苦的,

今天這個樣本並不大,但要理清它做的事情也很花時間和腦力~

(取一堆怪變數名稱真的很殺腦筋啊… 這正告訴我們取好變數名稱很重要,

但這也是病毒作者可以反向利用的一點,讓分析者頭昏腦脹)

但是沒有 VS2015 的單步執行的話,就更別談如何分析了~

總之今天學到了用 VS2015 來除錯 JScript/VBScript,覺得很開心呢^^

 

(本頁面已被瀏覽過 1,263 次)

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *

這個網站採用 Akismet 服務減少垃圾留言。進一步了解 Akismet 如何處理網站訪客的留言資料