x86 64架构汇编语言

14、阶段合集

1、课程目标

  1. 回顾整个x86/x64汇编章节的核心知识
  2. 通过综合项目巩固学习内容
  3. 掌握汇编在安全研究中的应用
  4. 为后续章节打下坚实基础

2、知识回顾

第一部分:x86基础

课时 核心内容
课时01 寄存器体系:EAX/EBX/ECX/EDX/ESI/EDI/ESP/EBP
课时02 MASM框架、数据移动指令、段定义
课时03 数据类型、整数运算指令
课时04 位运算指令、XOR加密应用
课时05 寻址方式、有效地址计算
课时06 EFLAGS标志寄存器、条件判断
课时07 JCC条件跳转、循环实现

第二部分:进阶内容

课时 核心内容
课时08 函数调用、堆栈帧、调用约定
课时09 串指令、REP前缀、内存操作
课时10 结构体、宏定义、条件汇编
课时11 x64架构、新寄存器、调用约定
课时12 内联汇编、混合编程
课时13 Linux汇编、系统调用

3、综合实战项目

3.1、项目1:简单加密器

#include <stdio.h>
#include <string.h>

// XOR加密实现
void XorEncrypt(unsigned char* data, size_t len, unsigned char key) {
    __asm {
        mov esi, data
        mov ecx, len
        mov al, key
        
    encrypt_loop:
        test ecx, ecx
        jz done
        
        xor [esi], al
        inc esi
        dec ecx
        jmp encrypt_loop
        
    done:
    }
}

// ROL/ROR加密
void RotateEncrypt(unsigned char* data, size_t len, unsigned char shift) {
    __asm {
        mov esi, data
        mov ecx, len
        mov cl, shift
        
    rotate_loop:
        cmp ecx, 0
        je rotate_done
        
        mov al, [esi]
        rol al, cl          ; 循环左移
        mov [esi], al
        inc esi
        dec ecx
        jmp rotate_loop
        
    rotate_done:
    }
}

int main() {
    char plaintext[] = "Hello, Assembly!";
    unsigned char key = 0x5A;
    
    printf("Original: %s\n", plaintext);
    
    XorEncrypt((unsigned char*)plaintext, strlen(plaintext), key);
    printf("Encrypted: ");
    for (size_t i = 0; i < strlen(plaintext); i++) {
        printf("%02X ", (unsigned char)plaintext[i]);
    }
    printf("\n");
    
    XorEncrypt((unsigned char*)plaintext, strlen(plaintext), key);
    printf("Decrypted: %s\n", plaintext);
    
    return 0;
}

3.2、项目2:内存扫描器

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

// 在内存中搜索特征码
void* ScanMemory(void* start, size_t size, unsigned char* pattern, size_t patternLen) {
    void* result = NULL;
    
    __asm {
        mov edi, start          ; 搜索起始地址
        mov ecx, size           ; 搜索范围
        
    scan_loop:
        cmp ecx, patternLen
        jb not_found
        
        ; 比较特征码
        push ecx
        push edi
        
        mov esi, pattern
        mov ecx, patternLen
        repe cmpsb
        
        pop edi
        pop ecx
        
        je found
        
        inc edi
        dec ecx
        jmp scan_loop
        
    found:
        mov result, edi
        jmp done
        
    not_found:
        mov result, 0
        
    done:
    }
    
    return result;
}

int main() {
    char testData[] = "AAAA_TARGET_BBBB";
    unsigned char pattern[] = "TARGET";
    
    void* found = ScanMemory(testData, sizeof(testData), pattern, sizeof(pattern)-1);
    
    if (found) {
        printf("Found at offset: %d\n", (int)((char*)found - testData));
    } else {
        printf("Not found\n");
    }
    
    return 0;
}

3.3、项目3:API哈希计算

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

// 计算字符串哈希(常用于shellcode)
DWORD CalcHash(const char* str) {
    DWORD hash;
    
    __asm {
        mov esi, str
        xor eax, eax        ; hash = 0
        xor ecx, ecx        ; 字符清零
        
    hash_loop:
        mov cl, [esi]
        test cl, cl
        jz hash_done
        
        ror eax, 13         ; 循环右移13位
        add eax, ecx        ; 加上字符
        inc esi
        jmp hash_loop
        
    hash_done:
        mov hash, eax
    }
    
    return hash;
}

int main() {
    printf("Hash of 'kernel32.dll': 0x%08X\n", CalcHash("kernel32.dll"));
    printf("Hash of 'LoadLibraryA': 0x%08X\n", CalcHash("LoadLibraryA"));
    printf("Hash of 'GetProcAddress': 0x%08X\n", CalcHash("GetProcAddress"));
    printf("Hash of 'VirtualAlloc': 0x%08X\n", CalcHash("VirtualAlloc"));
    
    return 0;
}

3.4、项目4:简单Hook实现

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

// 原MessageBoxA地址
typedef int (WINAPI *pMessageBoxA)(HWND, LPCSTR, LPCSTR, UINT);
pMessageBoxA OriginalMessageBoxA = NULL;

// 保存原始字节
BYTE OriginalBytes[5] = {0};

// 我们的Hook函数
int WINAPI HookedMessageBoxA(HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType) {
    printf("[HOOK] MessageBoxA called!\n");
    printf("  Text: %s\n", lpText);
    printf("  Caption: %s\n", lpCaption);
    
    // 恢复原始字节
    DWORD oldProtect;
    VirtualProtect(OriginalMessageBoxA, 5, PAGE_EXECUTE_READWRITE, &oldProtect);
    memcpy(OriginalMessageBoxA, OriginalBytes, 5);
    VirtualProtect(OriginalMessageBoxA, 5, oldProtect, &oldProtect);
    
    // 调用原函数
    int result = OriginalMessageBoxA(hWnd, "[Hooked Message]", lpCaption, uType);
    
    return result;
}

void InstallHook() {
    // 获取原函数地址
    HMODULE hUser32 = GetModuleHandleA("user32.dll");
    OriginalMessageBoxA = (pMessageBoxA)GetProcAddress(hUser32, "MessageBoxA");
    
    // 保存原始字节
    memcpy(OriginalBytes, OriginalMessageBoxA, 5);
    
    // 计算跳转偏移
    DWORD hookOffset = (DWORD)HookedMessageBoxA - (DWORD)OriginalMessageBoxA - 5;
    
    // 写入JMP指令
    DWORD oldProtect;
    VirtualProtect(OriginalMessageBoxA, 5, PAGE_EXECUTE_READWRITE, &oldProtect);
    
    __asm {
        mov edi, OriginalMessageBoxA
        mov byte ptr [edi], 0xE9     ; JMP opcode
        mov eax, hookOffset
        mov [edi+1], eax              ; 偏移量
    }
    
    VirtualProtect(OriginalMessageBoxA, 5, oldProtect, &oldProtect);
}

int main() {
    printf("Installing hook...\n");
    InstallHook();
    
    printf("Calling MessageBoxA...\n");
    MessageBoxA(NULL, "Original Message", "Test", MB_OK);
    
    return 0;
}

3.5、项目5:x64寄存器读取器

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

void PrintRegisters() {
    CONTEXT ctx = {0};
    ctx.ContextFlags = CONTEXT_FULL;
    
    // 获取当前线程上下文
    HANDLE hThread = GetCurrentThread();
    
    // 使用RtlCaptureContext
    RtlCaptureContext(&ctx);
    
#ifdef _WIN64
    printf("=== x64 Registers ===\n");
    printf("RAX: 0x%016llX\n", ctx.Rax);
    printf("RBX: 0x%016llX\n", ctx.Rbx);
    printf("RCX: 0x%016llX\n", ctx.Rcx);
    printf("RDX: 0x%016llX\n", ctx.Rdx);
    printf("RSI: 0x%016llX\n", ctx.Rsi);
    printf("RDI: 0x%016llX\n", ctx.Rdi);
    printf("RBP: 0x%016llX\n", ctx.Rbp);
    printf("RSP: 0x%016llX\n", ctx.Rsp);
    printf("R8:  0x%016llX\n", ctx.R8);
    printf("R9:  0x%016llX\n", ctx.R9);
    printf("R10: 0x%016llX\n", ctx.R10);
    printf("R11: 0x%016llX\n", ctx.R11);
    printf("R12: 0x%016llX\n", ctx.R12);
    printf("R13: 0x%016llX\n", ctx.R13);
    printf("R14: 0x%016llX\n", ctx.R14);
    printf("R15: 0x%016llX\n", ctx.R15);
    printf("RIP: 0x%016llX\n", ctx.Rip);
#else
    printf("=== x86 Registers ===\n");
    printf("EAX: 0x%08lX\n", ctx.Eax);
    printf("EBX: 0x%08lX\n", ctx.Ebx);
    printf("ECX: 0x%08lX\n", ctx.Ecx);
    printf("EDX: 0x%08lX\n", ctx.Edx);
    printf("ESI: 0x%08lX\n", ctx.Esi);
    printf("EDI: 0x%08lX\n", ctx.Edi);
    printf("EBP: 0x%08lX\n", ctx.Ebp);
    printf("ESP: 0x%08lX\n", ctx.Esp);
    printf("EIP: 0x%08lX\n", ctx.Eip);
#endif
    
    printf("\n=== Flags ===\n");
    printf("EFlags: 0x%08lX\n", ctx.EFlags);
    printf("  CF=%d ZF=%d SF=%d OF=%d\n",
           (ctx.EFlags >> 0) & 1,
           (ctx.EFlags >> 6) & 1,
           (ctx.EFlags >> 7) & 1,
           (ctx.EFlags >> 11) & 1);
}

int main() {
    PrintRegisters();
    return 0;
}

4、汇编指令速查表

4.1、数据移动

指令 说明
MOV 数据传送
LEA 加载有效地址
PUSH/POP 栈操作
XCHG 交换数据

4.2、算术运算

指令 说明
ADD/SUB 加/减
MUL/IMUL 无符号/有符号乘
DIV/IDIV 无符号/有符号除
INC/DEC 加一/减一

4.3、位运算

指令 说明
AND/OR/XOR 与/或/异或
NOT/NEG 取反/取负
SHL/SHR 逻辑左移/右移
SAL/SAR 算术左移/右移
ROL/ROR 循环左移/右移

4.4、控制流

指令 说明
JMP 无条件跳转
JE/JZ 相等跳转
JNE/JNZ 不相等跳转
JG/JL 有符号大于/小于
JA/JB 无符号大于/小于
CALL/RET 调用/返回

5、课后作业

  1. 综合项目:结合所学内容,实现一个完整的内存修改器
  2. 深入研究:分析一个简单程序的汇编代码,理解编译器优化
  3. 实战应用:尝试编写一段位置无关的shellcode
  4. 跨平台:将Windows汇编程序移植到Linux