-------- ROOTKIT 核心技術——系統服務調度表掛鉤調試(PART III) --------

来源:https://www.cnblogs.com/flying-shark/archive/2018/01/29/8379345.html
-Advertisement-
Play Games

———————————————————————————————————————————————————————————————————————————————————————— 本篇開始進行真槍實彈的調試,本文的最後會附上完整的源碼包,方便各位在自己的機器上演練。 如果安裝了 Windows Dri ...


————————————————————————————————————————————————————————————————————————————————————————

本篇開始進行真槍實彈的調試,本文的最後會附上完整的源碼包,方便各位在自己的機器上演練。

 

如果安裝了 Windows Driver Kits,在“開始”->“所有程式”中選擇類似“WDK 7600.16385.1”的項目。具體的數字取決於你

安裝的 WDK 開發環境版本而定。然後選擇“Build Environments”下麵的操作系統版本,

亦即你編譯出來的驅動要運行其上的 OS 版本,接著選擇硬體平臺體繫結構構建類型,比如“x86 Checked Build

Environment”是用於 32 位平臺,且附帶生成包含調試符號文件的構建環境。

調試符號文件有助於調試器顯示驅動二進位文件中的函數,變數,常量名稱等信息,生成人性化的輸出。

這樣會創建一個特殊的 cmd.exe 進程,它的環境變數預配置好了各種構建相關的參數,比如頭文件,庫文件的位置;編譯器,彙編

器,鏈接器程式所在路徑。。。等等。

我們在該 cmd 視窗中切換到源碼包的解壓目錄,然後執行如下命令:

build /D /g /b /B /e /F /S /s /$ /why /v /w /y

這些指定的參數讓你能查看詳細的構建過程,比如預處理器解析頭文件的嵌套包含過程,給出可能的警告或錯誤提示。

下麵是一個樣例輸出,對於排除過程中出現的問題很有用:

 

D:\kmdsource_use_mdl_mapping_ssdt>build  /D /g /b /B /e /F /S /s /$ /why /v /w /y
BUILD: Compile and Link for x86
BUILD: Loading d:\winddk\7600.16385.1\build.dat...
BUILD: Computing Include file dependencies:
    Scanning d:\winddk\7600.16385.1\inc\api
    Scanning d:\winddk\7600.16385.1\inc\ddk
BUILD: Start time: Mon Jan 29 14:08:34 2018
    Scanning d:\kmdsource_use_mdl_mapping_ssdt
    Scanning d:\winddk\7600.16385.1\inc\crt
BUILD: Examining d:\kmdsource_use_mdl_mapping_ssdt directory for files to compile.
    d:\kmdsource_use_mdl_mapping_ssdt
Invalidating OACR warning log for 'root:x86chk'
0x00000001-0x00000001/0x00000001 usemdlmappingssdt.c  ntddk.h                d:\winddk\7600.16385.1\inc\ddk
0x00000002-0x00000001/0x00000001 usemdlmappingssdt.c    wdm.h                d:\winddk\7600.16385.1\inc\ddk
0x00000003-0x00000001/0x00000001 usemdlmappingssdt.c      excpt.h            d:\winddk\7600.16385.1\inc\crt
0x00000004-0x00000001/0x00000001 usemdlmappingssdt.c        crtdefs.h        d:\winddk\7600.16385.1\inc\crt
0x00000005-0x00000001/0x00000001 usemdlmappingssdt.c          specstrings.h     d:\winddk\7600.16385.1\inc\api
0x00000006-0x00000001/0x00000001 usemdlmappingssdt.c            sal_supp.h   d:\winddk\7600.16385.1\inc\api
0x00000006-0x00000001/0x00000001 usemdlmappingssdt.c            specstrings_supp.h   d:\winddk\7600.16385.1\inc\api
0x00000007-0x00000001/0x00000001 usemdlmappingssdt.c              sal_supp.h d:\winddk\7600.16385.1\inc\api
0x00000006-0x00000001/0x00000001 usemdlmappingssdt.c            sal.h        d:\winddk\7600.16385.1\inc\api
0x00000006-0x00000001/0x00000001 usemdlmappingssdt.c            specstrings_strict.h   d:\winddk\7600.16385.1\inc\api
0x00000007-0x00000001/0x00000001 usemdlmappingssdt.c              specstrings_undef.h d:\winddk\7600.16385.1\inc\api
0x00000006-0x00000001/0x00000001 usemdlmappingssdt.c            driverspecs.h   d:\winddk\7600.16385.1\inc\api
0x00000007-0x00000001/0x00000001 usemdlmappingssdt.c              specstrings.h d:\winddk\7600.16385.1\inc\api
0x00000006-0x00000001/0x00000001 usemdlmappingssdt.c            sal_supp.h   d:\winddk\7600.16385.1\inc\api
0x00000006-0x00000001/0x00000001 usemdlmappingssdt.c            specstrings_supp.h   d:\winddk\7600.16385.1\inc\api
0x00000006-0x00000001/0x00000001 usemdlmappingssdt.c            sal.h        d:\winddk\7600.16385.1\inc\api
0x00000006-0x00000001/0x00000001 usemdlmappingssdt.c            specstrings_strict.h   d:\winddk\7600.16385.1\inc\api
0x00000006-0x00000001/0x00000001 usemdlmappingssdt.c            sdv_driverspecs.h   d:\winddk\7600.16385.1\inc\api
0x00000003-0x00000001/0x00000001 usemdlmappingssdt.c      ntdef.h            d:\winddk\7600.16385.1\inc\api
0x00000004-0x00000001/0x00000001 usemdlmappingssdt.c        ctype.h          d:\winddk\7600.16385.1\inc\crt
0x00000005-0x00000001/0x00000001 usemdlmappingssdt.c          crtdefs.h      d:\winddk\7600.16385.1\inc\crt
0x00000004-0x00000001/0x00000001 usemdlmappingssdt.c        specstrings.h       d:\winddk\7600.16385.1\inc\api
0x00000004-0x00000001/0x00000001 usemdlmappingssdt.c        kernelspecs.h       d:\winddk\7600.16385.1\inc\api
0x00000005-0x00000001/0x00000001 usemdlmappingssdt.c          driverspecs.h     d:\winddk\7600.16385.1\inc\api
0x00000004-0x00000001/0x00000001 usemdlmappingssdt.c        basetsd.h        d:\winddk\7600.16385.1\inc\api
0x00000004-0x00000001/0x00000001 usemdlmappingssdt.c        guiddef.h        d:\winddk\7600.16385.1\inc\api
0x00000005-0x00000001/0x00000001 usemdlmappingssdt.c          string.h       d:\winddk\7600.16385.1\inc\crt
0x00000006-0x00000001/0x00000001 usemdlmappingssdt.c            crtdefs.h    d:\winddk\7600.16385.1\inc\crt
0x00000004-0x00000001/0x00000001 usemdlmappingssdt.c        excpt.h          d:\winddk\7600.16385.1\inc\crt
0x00000004-0x00000001/0x00000001 usemdlmappingssdt.c        sdkddkver.h       d:\winddk\7600.16385.1\inc\api
0x00000003-0x00000001/0x00000001 usemdlmappingssdt.c      ntstatus.h         d:\winddk\7600.16385.1\inc\api
0x00000003-0x00000001/0x00000001 usemdlmappingssdt.c      bugcodes.h         d:\winddk\7600.16385.1\inc\api
0x00000003-0x00000001/0x00000001 usemdlmappingssdt.c      ntiologc.h         d:\winddk\7600.16385.1\inc\api
0x00000003-0x00000001/0x00000001 usemdlmappingssdt.c      mce.h              d:\winddk\7600.16385.1\inc\ddk
0x00000003-0x00000001/0x00000001 usemdlmappingssdt.c      pshpack4.h         d:\winddk\7600.16385.1\inc\api
0x00000003-0x00000001/0x00000001 usemdlmappingssdt.c      poppack.h          d:\winddk\7600.16385.1\inc\api
0x00000003-0x00000001/0x00000001 usemdlmappingssdt.c      guiddef.h          d:\winddk\7600.16385.1\inc\api
0x00000003-0x00000001/0x00000001 usemdlmappingssdt.c      pshpack1.h         d:\winddk\7600.16385.1\inc\api
0x00000003-0x00000001/0x00000001 usemdlmappingssdt.c      string.h           d:\winddk\7600.16385.1\inc\crt
0x00000003-0x00000001/0x00000001 usemdlmappingssdt.c      dpfilter.h         d:\winddk\7600.16385.1\inc\api
0x00000003-0x00000001/0x00000001 usemdlmappingssdt.c      ktmtypes.h         d:\winddk\7600.16385.1\inc\api
0x00000003-0x00000001/0x00000001 usemdlmappingssdt.c      dsfhrmports.h         d:\winddk\7600.16385.1\inc\ddk
Compiling - d:\kmdsource_use_mdl_mapping_ssdt\usemdlmappingssdt.c
0x00000003-0x00000001/0x00000001 usemdlmappingssdt.c      evntrace.h         d:\winddk\7600.16385.1\inc\api
Linking Executable - d:\kmdsource_use_mdl_mapping_ssdt\objchk_win7_x86\i386\UseMdlMappingSSDT.sys
0x00000003-0x00000001/0x00000001 usemdlmappingssdt.c      stdarg.h           d:\winddk\7600.16385.1\inc\crt
 0% done.    0 TLPS  Time Left: 0:00:00  Files: 0  Total LLines: 0
0x00000004-0x00000001/0x00000001 usemdlmappingssdt.c        vadefs.h         d:\winddk\7600.16385.1\inc\crt

0x00000003-0x00000001/0x00000001 usemdlmappingssdt.c      evntprov.h         d:\winddk\7600.16385.1\inc\api
0x00000003-0x00000001/0x00000001 usemdlmappingssdt.c      devpropdef.h         d:\winddk\7600.16385.1\inc\api
0x00000003-0x00000001/0x00000001 usemdlmappingssdt.c      clfslsn.h          d:\winddk\7600.16385.1\inc\ddk
0x00000002-0x00000001/0x00000001 usemdlmappingssdt.c    excpt.h              d:\winddk\7600.16385.1\inc\crt
0x00000002-0x00000001/0x00000001 usemdlmappingssdt.c    ntdef.h              d:\winddk\7600.16385.1\inc\api
0x00000002-0x00000001/0x00000001 usemdlmappingssdt.c    ntstatus.h           d:\winddk\7600.16385.1\inc\api
0x00000002-0x00000001/0x00000001 usemdlmappingssdt.c    bugcodes.h           d:\winddk\7600.16385.1\inc\api
0x00000002-0x00000001/0x00000001 usemdlmappingssdt.c    ntiologc.h           d:\winddk\7600.16385.1\inc\api
0x00000002-0x00000001/0x00000001 usemdlmappingssdt.c    mce.h                d:\winddk\7600.16385.1\inc\ddk
0x00000002-0x00000001/0x00000001 usemdlmappingssdt.c    pshpack4.h           d:\winddk\7600.16385.1\inc\api
0x00000002-0x00000001/0x00000001 usemdlmappingssdt.c    poppack.h            d:\winddk\7600.16385.1\inc\api
0x00000002-0x00000001/0x00000001 usemdlmappingssdt.c    guiddef.h            d:\winddk\7600.16385.1\inc\api
0x00000002-0x00000001/0x00000001 usemdlmappingssdt.c    pshpack1.h           d:\winddk\7600.16385.1\inc\api
0x00000001-0x00000001/0x00000001 usemdlmappingssdt.c  datatype.h             d:\kmdsource_use_mdl_mapping_ssdt
0x00000001-0x00000001/0x00000001 usemdlmappingssdt.c  dbgmsg.h               d:\kmdsource_use_mdl_mapping_ssdt
0x00000001-0x00000001/0x00000001 usemdlmappingssdt.c  ctrlcode.h             d:\kmdsource_use_mdl_mapping_ssdt
0x00000001-0x00000001/0x00000001 usemdlmappingssdt.c  device.h               d:\kmdsource_use_mdl_mapping_ssdt
0x00000002-0x00000001/0x00000001 usemdlmappingssdt.c    ntddk.h              d:\winddk\7600.16385.1\inc\ddk

Compiling usemdlmappingssdt.c because .. (0x00000006)
BUILD: Saving d:\winddk\7600.16385.1\build.dat...
BUILD: Compiling and Linking d:\kmdsource_use_mdl_mapping_ssdt directory
Configuring OACR for 'root:x86chk' - <OACR on>
1>warnings in directory d:\kmdsource_use_mdl_mapping_ssdt
alSystemServicePtr' differs in levels of indirection from 'DWORD'1>d:\kmdsource_use_mdl_mapping_ssdt\usemdlmappingssdt.c(157) : warning
BUILD: Finish time: Mon Jan 29 14:08:35 2018
BUILD: Done

    3 files compiled - 2 Warnings
    1 executable built

D:\kmdsource_use_mdl_mapping_ssdt>

 

我在前一篇文章中說過,可以忽略源碼中 157 行造成的警告——rootkit 的實際效果不受該警告影響。

把編譯出來的 UseMdlMappingSSDT.sys 拷貝到虛擬機或另一臺真實機器上(交叉編譯的目標平臺假設是 widnows 7

或  Windows Server 2008),使用 sc.exe 載入該驅動進入內核空間,如果一切正常,宿主機上應該會觸發首個斷點,位

於 MapMdl() 中,如下圖,註意,DbgPrint() 與 DBG_TRACE 巨集的輸出信息除了可以在目標機器上用 DbgView.exe 查看外,也

直接輸出到宿主機上調試器的控制台。我們只關心獲取到的 KiServiceTable 地址: 83CABF7C ;

分配出來的一個 nt!_MDL 結構地址:86A838A8 ;

由於之前選擇了“Checked Build”構建環境,現在調試器能夠根據“UseMdlMappingSSDT.pdb”符號文件顯示諸如 MapMdl()

之類函數名稱:

 

 

結合源碼可知,首個斷點位於 IoAllocateMdl() 調用後不遠處,我們的意圖是檢查該調用後的一個 nt!_MDL 對象內容,前面通

過 mdl_pointer 保存的地址派上用場:

 

 

如你所見,IoAllocateMdl() 分配出來的一個 MDL 總大小(頭部加上其後的 PFN 數組)為 36 位元組;當前的標誌取值 10 進位

的 8,參見前一篇博文可知,它只對應 MDL_ALLOCATED_FIXED_SIZE;還記得嗎,我在前一篇博文指出:

僅當 _MDL 的 MdlFlags 欄位內設置了 MDL_MAPPED_TO_SYSTEM_VA 或 MDL_SOURCE_IS_NONPAGED_POOL 比特位,

MappedSystemVa 欄位才是有效的,因此上圖中的 MappedSystemVa 欄位值 0x8059d950 沒有意義。

你還看到, StartVa 欄位值為 0x83cab000,這就是 KiServiceTable(從 0x83CABF7C 開始)所在的虛擬頁起始地址,註意這個

地址是對齊在 4 KB 邊界上的,因為虛擬頁和物理頁大小正情況下均為 4 KB

ByteOffset 欄位值為 0xf7c,亦即 KiServiceTable 的頁內偏移量—— 0x83CABF7C - 0x83cab000 = 0xf7c

ByteCount 欄位值為 0x644,亦即整張 KiServiceTable 調用表(一片緩衝區)的大小—— 1064 位元組。

在猶如醍醐灌頂的狀態下,按“g”繼續執行目標系統至第二個軟體斷點處,再次轉儲這個 nt!_MDL 對象內容:

 

 

 

MdlFlags 欄位值變成了 138(0x8A),對照相關的巨集定義可知,這是 MDL_WRITE_OPERATION(0x80)加

上 MDL_PAGES_LOCKED(0x02)加上 MDL_ALLOCATED_FIXED_SIZE(0x08)的組合,表明 MmProbeAndLockPages() 常式

把該 MDL 鎖在物理記憶體中,且具有了寫訪問許可權。

繼續按“g”執行目標系統至第三個軟體斷點處,再次轉儲這個 nt!_MDL 對象內容,謹記在心,此刻代表

MmGetSystemAddressForMdlSafe() 常式執行後的狀態:

 

 

首先,MdlFlags 欄位值變成了 139(0x8B),這表明追加了一個 MDL_MAPPED_TO_SYSTEM_VA 標誌,從而使得

MappedSystemVa 欄位值:0x805fbf7c 為有效,它代表把 KiServiceTable 映射到的新內核緩衝區起始地址,這與 eax 寄存器

(普遍用來存放函數調用的返回值,在此場景中由 MmGetSystemAddressForMdlSafe() 返回 )的值相符!

細心的你可能已經發現了,“舊”緩衝與新緩衝地址的後 12 位都是“f7c”,這當然不是巧合,事實上,虛擬地址的後 12 位(頁

內偏移)在地址轉譯階段被原封不動地與高 20 位的物理頁框號結合產生物理地址!這暗示它們都映射到相同的物理地址。

那麼通過它們應該訪問到同一個 KiServiceTable,如下所示,記住,當前斷點是尚未 hook KiServiceTable,因此 0x39 號系統

務還是原來的那一個—— nt!NtCompleteConnectPort() :

 

前面我說過,新映射到的內核地址通常位於驅動被載入的內核空間中,下圖否決了這一點(盡信博文不如無博文!)

 

 

你可以看到,我們的 rootkit“UseMdlMappingSSDT”被載入到 9ff55000——9ff5c000 這片內核空間,占用 28 KB 左右的

核記憶體!

而 KiServiceTable 被映射到的 805fbf7c 內核地址顯然不在其內。

事實上,KiServiceTable 被映射到的 805fbf7c 內核地址屬於“SystemPte 型(即系統頁表條目)”內核空間,此類內核空間有多

種用途,包括提供給 MDL 來把 SSDT/KiServiceTable 映射到此處。

 

系統頁表條目(PTEs)內核空間,用於動態地映射系統頁面,例如 I/O 空間,內核棧,以及映射記憶體描述符列表(MDLs)。

系統 PTE 的分配者除了各種執行體/內核組件外,多數是一些載入到內核空間的設備驅動程式,其中有系統自帶的,也有第三方軟

硬體供應商開發的;

它們請求在系統 PTE 區域中分配記憶體的目的都是與映射視圖,MDLs(記憶體描述符列表),適配器記憶體映射,驅動程式映像,內核

棧, I/O 映射等相關的,如下圖所示:

 

 

內核空間中有多處被劃分為 SystemPte 類型,我們把 KiServiceTable 映射到第一個 SystemPte 型內核空間,該區域大小為 4

MB。

按下“g”繼續執行,這會導致 MapMdl() 返回新映射的地址到 DriverEntry(),後者掛鉤 nt!NtCompleteConnectPort(),另一方

面,我們還可以通過計算出來的 nt!_MDL 頭部大小訪問到其後的 PFN 數組,檢查其內保存的物理頁框號是否就是虛擬地址

0x83CABF7C 和 0x805fbf7c 兩者執行地址轉譯後所在的物理頁框號,它們都被轉譯到物理地址 0x3cabf7c,頁框號為

0x03cab,虛擬地址的後 12 位偏移量(0xf7c)直接拷貝到物理地址的後 12 位偏移量;

頁框號可以通過對 pfn_array_follow_mdl 執行指針運算並解引地址處的內容得出,也是 0x03cab;

兩者的區別在於,描述虛擬地址 0x83CABF7C 的 PTE 內容設置了只讀標記;而描述虛擬地址 0x805fbf7c 的 PTE 內容設置了可讀

標記,因此通過虛擬地址 0x83CABF7C 向實際的物理頁寫入就會藍屏;而通過虛擬地址 0x805fbf7c 則可以安全寫入!

 

 

 訪問 KiServiceTable 中的 0x39 號系統服務,已經被替換為我們的鉤子常式:

 

 

我提供了一個 UnMapMdl() 常式,把它註冊為該 rootkit 的卸載回調,大致邏輯是,在驅動卸載時,取消映射新的內核虛擬地址,

並釋放 MDL 指針 ,如此一來,卸載 UseMdlMappingSSDT.sys 後,既不能通過新映射的地址訪問 KiServiceTable,也不能通過

指針訪問 nt!_MDL 結構(但該結構確實尚未釋):

 

 

 

最後,讓我們填充前一篇博文中那張 MDL 架構圖中的占位符,以便讓各位能夠洞察整個來龍去脈。祝願你沒有被那些紅紅綠綠的

箭頭搞暈!

 

附上源碼包的下載地址,歡迎反饋。

https://files.cnblogs.com/files/flying-shark/kmdsource_use_mdl_mapping_ssdt.rar

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 圖形用戶界面( G raphical U ser I nterface,GUI)編程 Python2.0級以下的版本叫做Tkinter,Python3.0改名為tkinter tkinter 模塊:添加 Tk 到應用中 那麼為了讓 tkinter 成為應用的一部分,你需要做些什麼呢?首先,已經存在的 ...
  • 一、int轉換成string Ⅰ、to_string函數 c++11標準增加了全局函數std::to_string: string to_string (int val); string to_string (long val); string to_string (long long val); ...
  • 空間配置器(allocator)這個概念在閱讀源碼之前我根本沒有聽過,原以為記憶體分配都是使用new和delete運算符(註意和operator new、placement new、operator delete以及placement delete不同)。在實際使用STL編程時也很少會遇到自己去實現一 ...
  • 如何用腳本判斷用戶輸入的的字元串是下麵的時間格式2004-11-21 必須要保證用戶的輸入是此格式,並且是時間,比如說月份不大於12等等,另外我需要用戶輸入兩個,並且後一個要比前一個晚,只允許用JAVASCRIPT,請詳細幫助作答, 提示:可用正則表達式提前判斷一下格式,然後提取各時間欄位內容 寫出 ...
  • 1、dict() 字典 字典是python里唯一的映射類型 2、字典由key和value組成的項組成 如何創建一個字典: 3、字典的內置函數 keys values items copy clear get fromkeys update pop popitems setdefault 4、設計一個 ...
  • ``` import re import urllib import urllib.request headers = {'User-Agent':'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:23.0) Gecko/20100101 Firefox/23.0'} ... ...
  • 1。藍圖 要用藍圖管理項目,需要導入的包是:from flask import Buleprint 具體大致分為三步: 1.先在子模塊中導入藍圖包,然後再創建藍圖對象。 2.然後將子模塊中的視圖函數存儲在藍圖對象中。 3.最後在主模塊的文件夾里註冊藍圖。 下麵分別展示以上三步在項目中的具體操作: 第 ...
  • 1 載入matplotli的繪圖模塊,並重命名為pltimport matplotlib.pyplot as plt2 折線圖import matplotlib.pyplot as pltimport numpy as npx = np.arange(9)y = np.sin(x)z = np.co... ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...