[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 的視窗都行:
接著就進到熟悉的除錯畫面,按 F10/F11 可以分別 Step Over/Step Into,
也可以開著 Locals 視窗,方便檢查變數值:
來提一下模糊化 (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:
上面的叙述最後是 false,因為它想要連的網址已經被禁止訪問了 (403 forbidden),
這會導致我們無法繼續單步執行下去,
但 VS2015 的好處是我們可以直接修改執行中變數的值,
像本例中將 advocacy 從 false 改成 true,就可以繼續執行病毒的工作,
它在發現 HTTP 請求成功 (HTTP 200) 之後,就會將下載下來的東西儲存下來:
用單步執行的方法來追踪病毒,其實還是蠻辛苦的,
今天這個樣本並不大,但要理清它做的事情也很花時間和腦力~
(取一堆怪變數名稱真的很殺腦筋啊… 這正告訴我們取好變數名稱很重要,
但這也是病毒作者可以反向利用的一點,讓分析者頭昏腦脹)
但是沒有 VS2015 的單步執行的話,就更別談如何分析了~
總之今天學到了用 VS2015 來除錯 JScript/VBScript,覺得很開心呢^^