shellcode开发技术

5、x64shellcode框架

1、课程目标

  1. 理解x64架构与x86的关键差异
  2. 掌握x64 ShellCode的开发技术
  3. 实现完整的x64 ShellCode框架
  4. 掌握x64调用约定和寄存器使用

2、名词解释

术语全称解释
x64AMD64/x86-6464位扩展架构
GSGS Segmentx64用于访问TEB的段寄存器
RCX/RDX/R8/R9-x64调用约定的前4个参数寄存器
Shadow Space影子空间函数调用时预留的32字节栈空间
Red Zone红区栈指针下方128字节的保留区域
REXRegister Extensionx64指令前缀,用于访问扩展寄存器

3、使用工具

工具用途备注
MASM (ml64)x64汇编VS自带
NASM跨平台汇编支持x64
x64dbg64位调试调试验证
Visual Studio开发环境x64不支持内联汇编

4、技术原理

1. x86与x64关键差异

特性x86x64
指针大小4字节8字节
通用寄存器EAX-EDI (8个)RAX-R15 (16个)
TEB访问FS:[0x30]GS:[0x60]
调用约定cdecl/stdcallMicrosoft x64
参数传递RCX,RDX,R8,R9+栈
返回值EAXRAX
影子空间32字节必需

2. x64调用约定

参数传递:
  整数/指针: RCX, RDX, R8, R9, 栈
  浮点数:    XMM0, XMM1, XMM2, XMM3, 栈

影子空间: 调用前必须预留32字节
  sub rsp, 0x28  ; 32(影子) + 8(对齐) = 40 = 0x28

非易失寄存器: RBX, RBP, RDI, RSI, RSP, R12-R15
易失寄存器:   RAX, RCX, RDX, R8-R11

3. PEB结构偏移对比

x86:                            x64:
TEB: FS:[0x00]                  TEB: GS:[0x00]
PEB: FS:[0x30]                  PEB: GS:[0x60]
Ldr: PEB+0x0C                   Ldr: PEB+0x18
InLoadOrder: Ldr+0x0C           InLoadOrder: Ldr+0x10
InMemoryOrder: Ldr+0x14         InMemoryOrder: Ldr+0x20
InInitOrder: Ldr+0x1C           InInitOrder: Ldr+0x30

4. LDR_DATA_TABLE_ENTRY偏移

x86:                            x64:
DllBase: +0x18                  DllBase: +0x30
EntryPoint: +0x1C               EntryPoint: +0x38
SizeOfImage: +0x20              SizeOfImage: +0x40
FullDllName: +0x24              FullDllName: +0x48
BaseDllName: +0x2C              BaseDllName: +0x58

5、代码实现

1. x64 ShellCode框架(MASM)

; x64_shellcode.asm
; x64 ShellCode完整框架 - MASM64格式
; 编译: ml64 /c x64_shellcode.asm
;       link /entry:ShellEntry /subsystem:console x64_shellcode.obj

.code

; 哈希常量
HASH_KERNEL32       EQU 06A4ABC5Bh
HASH_LOADLIBRARYA   EQU 0EC0E4E8Eh
HASH_GETPROCADDRESS EQU 07C0DFCAAh
HASH_EXITPROCESS    EQU 073E2D87Eh
HASH_MESSAGEBOXA    EQU 0BC4DA2A8h

; ====== ShellCode入口 ======
ShellEntry PROC
    ; 保存非易失寄存器
    push rbx
    push rbp
    push rdi
    push rsi
    push r12
    push r13
    push r14
    push r15
    
    ; 对齐栈(16字节对齐)
    sub rsp, 28h        ; 影子空间 + 对齐
    
    ; === 获取kernel32.dll基址 ===
    xor rcx, rcx
    mov rax, gs:[60h]       ; PEB
    mov rax, [rax + 18h]    ; Ldr
    mov rsi, [rax + 20h]    ; InMemoryOrderModuleList.Flink
    
find_kernel32:
    mov rdi, [rsi + 50h]    ; BaseDllName.Buffer
    test rdi, rdi
    jz next_module
    
    ; 检查是否为kernel32
    movzx rax, word ptr [rdi]
    or rax, 20h             ; 转小写
    cmp al, 'k'
    jne next_module
    
    movzx rax, word ptr [rdi + 0Eh]
    cmp al, '3'
    jne next_module
    
    ; 找到kernel32
    mov rbx, [rsi + 20h]    ; DllBase
    jmp got_kernel32
    
next_module:
    mov rsi, [rsi]          ; Flink
    jmp find_kernel32
    
got_kernel32:
    ; rbx = kernel32.dll基址
    
    ; === 获取GetProcAddress ===
    mov rcx, rbx
    mov rdx, HASH_GETPROCADDRESS
    call GetFunctionByHash
    mov r12, rax            ; r12 = GetProcAddress
    
    ; === 获取LoadLibraryA ===
    mov rcx, rbx
    mov rdx, HASH_LOADLIBRARYA
    call GetFunctionByHash
    mov r13, rax            ; r13 = LoadLibraryA
    
    ; === 获取ExitProcess ===
    mov rcx, rbx
    mov rdx, HASH_EXITPROCESS
    call GetFunctionByHash
    mov r14, rax            ; r14 = ExitProcess
    
    ; === 加载user32.dll ===
    ; 构造字符串 "user32.dll"
    sub rsp, 20h            ; 为字符串分配空间
    mov rax, 'resu'         ; "user" (little endian)
    mov [rsp], rax
    mov rax, 'd.23'         ; "32.d" 
    mov [rsp+4], rax
    mov word ptr [rsp+8], 'll'
    mov byte ptr [rsp+10], 0
    
    lea rcx, [rsp]          ; lpLibFileName
    call r13                ; LoadLibraryA
    mov r15, rax            ; r15 = user32.dll
    add rsp, 20h
    
    ; === 获取MessageBoxA ===
    mov rcx, r15
    mov rdx, HASH_MESSAGEBOXA
    call GetFunctionByHash
    mov rbp, rax            ; rbp = MessageBoxA
    
    ; === 调用MessageBoxA ===
    sub rsp, 20h            ; 字符串空间
    mov dword ptr [rsp], 'lleH'
    mov dword ptr [rsp+4], '!o'
    mov byte ptr [rsp+6], 0
    
    xor rcx, rcx            ; hWnd = NULL
    lea rdx, [rsp]          ; lpText
    xor r8, r8              ; lpCaption = NULL
    xor r9, r9              ; uType = MB_OK
    sub rsp, 20h            ; 影子空间
    call rbp
    add rsp, 40h
    
    ; === 退出 ===
    xor rcx, rcx            ; 退出码 = 0
    call r14                ; ExitProcess(0)
    
    ; 清理并返回
    add rsp, 28h
    pop r15
    pop r14
    pop r13
    pop r12
    pop rsi
    pop rdi
    pop rbp
    pop rbx
    ret
ShellEntry ENDP

; ====== GetFunctionByHash ======
; 参数: RCX = 模块基址, RDX = 哈希值
; 返回: RAX = 函数地址
GetFunctionByHash PROC
    push rbp
    mov rbp, rsp
    push rbx
    push rsi
    push rdi
    push r8
    push r9
    push r10
    push r11
    sub rsp, 20h
    
    mov rbx, rcx            ; rbx = 模块基址
    mov r8, rdx             ; r8 = 目标哈希
    
    ; 获取导出表
    mov eax, [rbx + 3Ch]    ; e_lfanew
    mov eax, [rbx + rax + 88h]  ; 导出表RVA (x64偏移)
    test eax, eax
    jz not_found_func
    
    add rax, rbx            ; 导出表VA
    mov rdi, rax            ; rdi = 导出表
    
    mov esi, [rdi + 20h]    ; AddressOfNames RVA
    add rsi, rbx            ; rsi = 名称表
    
    xor r9, r9              ; 索引 = 0
    
find_function_loop:
    mov r10d, [rdi + 18h]   ; NumberOfNames
    cmp r9d, r10d
    jge not_found_func
    
    mov eax, [rsi + r9*4]   ; 名称RVA
    add rax, rbx            ; 名称VA
    
    ; 计算哈希
    xor r10, r10            ; hash = 0
    
hash_loop:
    movzx r11, byte ptr [rax]
    test r11b, r11b
    jz hash_done
    
    ror r10d, 13
    add r10d, r11d
    inc rax
    jmp hash_loop
    
hash_done:
    cmp r10d, r8d           ; 比较哈希
    je found_function
    
    inc r9
    jmp find_function_loop
    
found_function:
    ; 获取序号
    mov eax, [rdi + 24h]    ; AddressOfNameOrdinals RVA
    add rax, rbx
    movzx eax, word ptr [rax + r9*2]
    
    ; 获取函数地址
    mov r10d, [rdi + 1Ch]   ; AddressOfFunctions RVA
    add r10, rbx
    mov eax, [r10 + rax*4]  ; 函数RVA
    add rax, rbx            ; 函数VA
    jmp done_func
    
not_found_func:
    xor rax, rax
    
done_func:
    add rsp, 20h
    pop r11
    pop r10
    pop r9
    pop r8
    pop rdi
    pop rsi
    pop rbx
    pop rbp
    ret
GetFunctionByHash ENDP

END

2. NASM格式的x64 ShellCode

; x64_shellcode_nasm.asm
; NASM格式 - x64 ShellCode
; 编译: nasm -f win64 x64_shellcode_nasm.asm -o shellcode.obj
;       或: nasm -f bin x64_shellcode_nasm.asm -o shellcode.bin

BITS 64

; 哈希常量
%define HASH_KERNEL32       0x6A4ABC5B
%define HASH_LOADLIBRARYA   0xEC0E4E8E
%define HASH_GETPROCADDRESS 0x7C0DFCAA
%define HASH_EXITPROCESS    0x73E2D87E
%define HASH_MESSAGEBOXA    0xBC4DA2A8

section .text
global _start

_start:
    ; 保存寄存器
    push rbx
    push rbp
    push rdi
    push rsi
    push r12
    push r13
    push r14
    push r15
    
    ; === 获取kernel32基址 ===
    xor rcx, rcx
    mov rax, [gs:0x60]      ; PEB
    mov rax, [rax + 0x18]   ; Ldr
    mov rsi, [rax + 0x20]   ; InMemoryOrderModuleList.Flink
    
.find_kernel32:
    mov rdi, [rsi + 0x50]   ; BaseDllName.Buffer
    test rdi, rdi
    jz .next_module
    
    movzx rax, word [rdi]
    or rax, 0x20
    cmp al, 'k'
    jne .next_module
    
    movzx rax, word [rdi + 14]
    cmp al, '3'
    jne .next_module
    
    mov rbx, [rsi + 0x20]   ; DllBase
    jmp .got_kernel32
    
.next_module:
    mov rsi, [rsi]
    jmp .find_kernel32
    
.got_kernel32:
    ; rbx = kernel32
    
    ; === 解析导出表获取函数 ===
    ; 获取GetProcAddress
    mov rcx, rbx
    mov edx, HASH_GETPROCADDRESS
    call .get_func_by_hash
    mov r12, rax            ; r12 = GetProcAddress
    
    ; 获取LoadLibraryA
    mov rcx, rbx
    mov edx, HASH_LOADLIBRARYA
    call .get_func_by_hash
    mov r13, rax            ; r13 = LoadLibraryA
    
    ; 获取ExitProcess
    mov rcx, rbx
    mov edx, HASH_EXITPROCESS
    call .get_func_by_hash
    mov r14, rax            ; r14 = ExitProcess
    
    ; === 加载user32.dll ===
    sub rsp, 0x20
    mov dword [rsp], 'user'
    mov dword [rsp+4], '32.d'
    mov word [rsp+8], 'll'
    mov byte [rsp+10], 0
    
    mov rcx, rsp
    sub rsp, 0x20           ; 影子空间
    call r13                ; LoadLibraryA
    add rsp, 0x40
    mov r15, rax            ; r15 = user32
    
    ; === 获取MessageBoxA ===
    mov rcx, r15
    mov edx, HASH_MESSAGEBOXA
    call .get_func_by_hash
    mov rbp, rax
    
    ; === 调用MessageBoxA ===
    sub rsp, 0x10
    mov dword [rsp], 'Hell'
    mov dword [rsp+4], 'o!'
    mov byte [rsp+6], 0
    
    xor rcx, rcx            ; hWnd
    lea rdx, [rsp]          ; lpText
    xor r8, r8              ; lpCaption
    xor r9, r9              ; uType
    sub rsp, 0x20           ; 影子空间
    call rbp
    add rsp, 0x30
    
    ; === 退出 ===
    xor rcx, rcx
    sub rsp, 0x20
    call r14
    add rsp, 0x20
    
    ; 恢复并返回
    pop r15
    pop r14
    pop r13
    pop r12
    pop rsi
    pop rdi
    pop rbp
    pop rbx
    ret

; ====== 内部函数:通过哈希获取函数地址 ======
; rcx = 模块基址, edx = 哈希
; 返回: rax = 函数地址
.get_func_by_hash:
    push rbx
    push rsi
    push rdi
    push r8
    push r9
    push r10
    
    mov rbx, rcx            ; 模块基址
    mov r8d, edx            ; 目标哈希
    
    ; 导出表
    mov eax, [rbx + 0x3C]   ; e_lfanew
    mov eax, [rbx + rax + 0x88]  ; x64导出表RVA
    test eax, eax
    jz .func_not_found
    add rax, rbx
    mov rdi, rax            ; 导出表
    
    mov esi, [rdi + 0x20]   ; AddressOfNames RVA
    add rsi, rbx
    
    xor r9, r9              ; 索引
    
.func_find_loop:
    cmp r9d, [rdi + 0x18]   ; NumberOfNames
    jge .func_not_found
    
    mov eax, [rsi + r9*4]
    add rax, rbx            ; 函数名VA
    
    ; 计算ROR13哈希
    xor r10, r10
.hash_calc:
    movzx ecx, byte [rax]
    test cl, cl
    jz .hash_compare
    ror r10d, 13
    add r10d, ecx
    inc rax
    jmp .hash_calc
    
.hash_compare:
    cmp r10d, r8d
    je .func_found
    inc r9
    jmp .func_find_loop
    
.func_found:
    mov eax, [rdi + 0x24]   ; AddressOfNameOrdinals
    add rax, rbx
    movzx eax, word [rax + r9*2]
    
    mov r10d, [rdi + 0x1C]  ; AddressOfFunctions
    add r10, rbx
    mov eax, [r10 + rax*4]
    add rax, rbx
    jmp .func_done
    
.func_not_found:
    xor rax, rax
    
.func_done:
    pop r10
    pop r9
    pop r8
    pop rdi
    pop rsi
    pop rbx
    ret

3. C语言版本(使用独立asm文件)

// x64_shellcode_c.c
// x64 ShellCode框架 - C语言实现
// 需要配合独立的.asm文件或使用intrinsic

#include <windows.h>
#include <stdio.h>
#include <intrin.h>

// 哈希常量
#define HASH_KERNEL32       0x6A4ABC5B
#define HASH_LOADLIBRARYA   0xEC0E4E8E
#define HASH_GETPROCADDRESS 0x7C0DFCAA
#define HASH_EXITPROCESS    0x73E2D87E
#define HASH_MESSAGEBOXA    0xBC4DA2A8
#define HASH_USER32         0x63C84283

// 函数指针类型
typedef HMODULE (WINAPI* PFN_LOADLIBRARYA)(LPCSTR);
typedef FARPROC (WINAPI* PFN_GETPROCADDRESS)(HMODULE, LPCSTR);
typedef void    (WINAPI* PFN_EXITPROCESS)(UINT);
typedef int     (WINAPI* PFN_MESSAGEBOXA)(HWND, LPCSTR, LPCSTR, UINT);

// ROR13哈希
__forceinline DWORD Ror13Hash(const char* str) {
    DWORD hash = 0;
    while (*str) {
        hash = _rotr(hash, 13) + *str;
        str++;
    }
    return hash;
}

// 通过PEB获取模块基址
__forceinline HMODULE GetModuleByHash(DWORD hash) {
    PPEB pPeb = (PPEB)__readgsqword(0x60);
    PPEB_LDR_DATA pLdr = (PPEB_LDR_DATA)pPeb->Ldr;
    PLIST_ENTRY pHead = &pLdr->InLoadOrderModuleList;
    PLIST_ENTRY pEntry = pHead->Flink;
    
    while (pEntry != pHead) {
        PLDR_DATA_TABLE_ENTRY pModule = CONTAINING_RECORD(
            pEntry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks
        );
        
        if (pModule->BaseDllName.Buffer) {
            // 计算模块名哈希(小写化)
            DWORD moduleHash = 0;
            WCHAR* name = pModule->BaseDllName.Buffer;
            while (*name) {
                WCHAR c = *name;
                if (c >= 'A' && c <= 'Z') c += 0x20;
                moduleHash = _rotr(moduleHash, 13) + (BYTE)c;
                name++;
            }
            
            if (moduleHash == hash) {
                return (HMODULE)pModule->DllBase;
            }
        }
        pEntry = pEntry->Flink;
    }
    return NULL;
}

// 通过哈希从模块获取函数
__forceinline FARPROC GetFuncByHash(HMODULE hModule, DWORD hash) {
    PIMAGE_DOS_HEADER pDos = (PIMAGE_DOS_HEADER)hModule;
    PIMAGE_NT_HEADERS64 pNt = (PIMAGE_NT_HEADERS64)((LPBYTE)hModule + pDos->e_lfanew);
    
    DWORD exportRva = pNt->OptionalHeader.DataDirectory[0].VirtualAddress;
    if (!exportRva) return NULL;
    
    PIMAGE_EXPORT_DIRECTORY pExport = (PIMAGE_EXPORT_DIRECTORY)((LPBYTE)hModule + exportRva);
    
    PDWORD pFunctions = (PDWORD)((LPBYTE)hModule + pExport->AddressOfFunctions);
    PDWORD pNames = (PDWORD)((LPBYTE)hModule + pExport->AddressOfNames);
    PWORD pOrdinals = (PWORD)((LPBYTE)hModule + pExport->AddressOfNameOrdinals);
    
    for (DWORD i = 0; i < pExport->NumberOfNames; i++) {
        char* name = (char*)((LPBYTE)hModule + pNames[i]);
        if (Ror13Hash(name) == hash) {
            return (FARPROC)((LPBYTE)hModule + pFunctions[pOrdinals[i]]);
        }
    }
    return NULL;
}

// ShellCode主逻辑 - 可以转换为纯汇编
void ShellcodeMain() {
    // 获取kernel32
    HMODULE hKernel32 = GetModuleByHash(HASH_KERNEL32);
    
    // 获取关键API
    PFN_LOADLIBRARYA pLoadLibraryA = 
        (PFN_LOADLIBRARYA)GetFuncByHash(hKernel32, HASH_LOADLIBRARYA);
    PFN_GETPROCADDRESS pGetProcAddress = 
        (PFN_GETPROCADDRESS)GetFuncByHash(hKernel32, HASH_GETPROCADDRESS);
    PFN_EXITPROCESS pExitProcess = 
        (PFN_EXITPROCESS)GetFuncByHash(hKernel32, HASH_EXITPROCESS);
    
    // 加载user32.dll
    char szUser32[] = {'u','s','e','r','3','2','.','d','l','l',0};
    HMODULE hUser32 = pLoadLibraryA(szUser32);
    
    // 获取MessageBoxA
    char szMsgBox[] = {'M','e','s','s','a','g','e','B','o','x','A',0};
    PFN_MESSAGEBOXA pMessageBoxA = 
        (PFN_MESSAGEBOXA)pGetProcAddress(hUser32, szMsgBox);
    
    // 显示消息
    char szTitle[] = {'x','6','4',' ','S','h','e','l','l',0};
    char szText[] = {'H','e','l','l','o',' ','x','6','4','!',0};
    pMessageBoxA(NULL, szText, szTitle, 0);
    
    // 退出
    pExitProcess(0);
}

// x64汇编辅助(需要在.asm文件中实现)
extern void ShellcodeEntry_ASM();

int main() {
    printf("========================================\n");
    printf("      x64 ShellCode Framework          \n");
    printf("========================================\n\n");
    
    // 测试C版本
    printf("[*] Testing C version...\n");
    printf("[*] Press Enter to execute MessageBox\n");
    getchar();
    
    ShellcodeMain();
    
    return 0;
}

4. 独立的x64汇编文件(供C调用)

; x64_shell_asm.asm
; 供C程序调用的x64 ShellCode入口
; 编译: ml64 /c x64_shell_asm.asm

.data
    szUser32 db 'user32.dll', 0
    szMsgBox db 'MessageBoxA', 0
    szTitle  db 'x64 Shell', 0
    szText   db 'Hello from ASM!', 0

.code

; 导出函数
PUBLIC ShellcodeEntry_ASM

; 哈希常量
HASH_KERNEL32       EQU 06A4ABC5Bh
HASH_LOADLIBRARYA   EQU 0EC0E4E8Eh
HASH_GETPROCADDRESS EQU 07C0DFCAAh
HASH_EXITPROCESS    EQU 073E2D87Eh

ShellcodeEntry_ASM PROC
    ; 标准函数序言
    push rbp
    mov rbp, rsp
    sub rsp, 60h            ; 本地变量 + 影子空间
    
    ; 保存非易失寄存器
    mov [rbp-8], rbx
    mov [rbp-10h], rdi
    mov [rbp-18h], rsi
    mov [rbp-20h], r12
    mov [rbp-28h], r13
    mov [rbp-30h], r14
    mov [rbp-38h], r15
    
    ; === 获取kernel32 ===
    mov rax, gs:[60h]           ; PEB
    mov rax, [rax + 18h]        ; Ldr
    mov rsi, [rax + 20h]        ; InMemoryOrderModuleList.Flink
    
@@find_k32:
    mov rdi, [rsi + 50h]        ; BaseDllName.Buffer
    test rdi, rdi
    jz @@next_mod
    
    movzx rax, word ptr [rdi]
    or rax, 20h
    cmp al, 'k'
    jne @@next_mod
    
    movzx rax, word ptr [rdi + 0Eh]
    cmp al, '3'
    jne @@next_mod
    
    mov rbx, [rsi + 20h]        ; DllBase
    jmp @@got_k32
    
@@next_mod:
    mov rsi, [rsi]
    jmp @@find_k32
    
@@got_k32:
    ; rbx = kernel32
    
    ; === 获取LoadLibraryA ===
    mov rcx, rbx
    mov edx, HASH_LOADLIBRARYA
    call GetFuncByHashInternal
    mov r12, rax                ; r12 = LoadLibraryA
    
    ; === 获取GetProcAddress ===
    mov rcx, rbx
    mov edx, HASH_GETPROCADDRESS
    call GetFuncByHashInternal
    mov r13, rax                ; r13 = GetProcAddress
    
    ; === 获取ExitProcess ===
    mov rcx, rbx
    mov edx, HASH_EXITPROCESS
    call GetFuncByHashInternal
    mov r14, rax                ; r14 = ExitProcess
    
    ; === 加载user32.dll ===
    lea rcx, szUser32
    call r12                    ; LoadLibraryA
    mov r15, rax                ; r15 = user32
    
    ; === 获取MessageBoxA ===
    mov rcx, r15
    lea rdx, szMsgBox
    call r13                    ; GetProcAddress
    mov rbp, rax                ; rbp = MessageBoxA (临时使用)
    
    ; === 调用MessageBoxA ===
    xor rcx, rcx                ; hWnd = NULL
    lea rdx, szText             ; lpText
    lea r8, szTitle             ; lpCaption  
    xor r9, r9                  ; uType = MB_OK
    call rbp
    
    ; === 退出 ===
    xor rcx, rcx
    call r14                    ; ExitProcess(0)
    
    ; 恢复寄存器
    mov rbx, [rbp-8]
    mov rdi, [rbp-10h]
    mov rsi, [rbp-18h]
    mov r12, [rbp-20h]
    mov r13, [rbp-28h]
    mov r14, [rbp-30h]
    mov r15, [rbp-38h]
    
    add rsp, 60h
    pop rbp
    ret
ShellcodeEntry_ASM ENDP

; 内部函数:通过哈希获取函数
GetFuncByHashInternal PROC
    push r10
    push r11
    
    mov r10, rcx                ; 模块基址
    mov r11d, edx               ; 目标哈希
    
    mov eax, [r10 + 3Ch]        ; e_lfanew
    mov eax, [r10 + rax + 88h]  ; 导出表RVA
    test eax, eax
    jz @@not_found
    add rax, r10                ; 导出表VA
    
    push rax                    ; 保存导出表
    
    mov ecx, [rax + 20h]        ; AddressOfNames RVA
    add rcx, r10                ; AddressOfNames VA
    
    xor edx, edx                ; 索引
    
@@loop:
    pop rax
    push rax
    cmp edx, [rax + 18h]
    jge @@not_found_pop
    
    mov eax, [rcx + rdx*4]
    add rax, r10                ; 名称VA
    
    ; 计算哈希
    push rcx
    push rdx
    xor ecx, ecx                ; hash
@@hash:
    movzx edx, byte ptr [rax]
    test dl, dl
    jz @@hash_done
    ror ecx, 13
    add ecx, edx
    inc rax
    jmp @@hash
    
@@hash_done:
    cmp ecx, r11d
    pop rdx
    pop rcx
    je @@found
    
    inc edx
    jmp @@loop
    
@@found:
    pop rax                     ; 导出表
    push rax
    mov ecx, [rax + 24h]        ; AddressOfNameOrdinals
    add rcx, r10
    movzx ecx, word ptr [rcx + rdx*2]
    
    mov eax, [rax + 1Ch]        ; AddressOfFunctions
    add rax, r10
    mov eax, [rax + rcx*4]
    add rax, r10
    pop rcx                     ; 清理栈
    jmp @@done
    
@@not_found_pop:
    pop rax
@@not_found:
    xor eax, eax
    
@@done:
    pop r11
    pop r10
    ret
GetFuncByHashInternal ENDP

END

5、课后作业

5.1、作业1:添加更多功能

扩展x64 ShellCode,添加以下功能:

  • 下载并执行文件
  • 反向Shell连接

5.2、作业2:消除空字节

检查并消除x64 ShellCode中的所有空字节。

5.3、作业3:实现x64 Loader

编写一个x64 ShellCode加载器,支持从文件加载并执行。