### 如何不在编码时直接导入相关 API 的前提下进行攻击

从攻击者的角度来看，**不在编码时直接导入相关 API** 是一个核心的规避手段。这种技术通常被称为**动态 API 调用**或**运行时 API 解析**，其主要目的是：

1. **绕过签名检测：** 传统的杀毒软件和安全工具会扫描可执行文件中的**导入表**。如果导入表里有 `CreateRemoteThread`、`WriteProcessMemory`、`LoadLibrary` 等高危函数，文件就会被标记为可疑。动态调用 API 可以让导入表看起来非常“干净”，从而躲过静态扫描
2. **增加逆向分析难度：** 逆向工程师通常会从导入表入手，快速了解程序的功能。如果导入表是空的或只导入了少数几个基础函数，逆向分析师就必须花费大量时间去跟踪程序的运行时行为，才能发现其真正意图
3. **支持多操作系统版本和架构：** 有些 API 的地址在不同版本的 Windows 上可能会有细微差异。动态获取 API 地址可以确保代码在不同系统上都能正确运行，提高攻击的通用性
4. **按需加载：** 只有在需要执行特定恶意行为时才去获取和调用相应的 API，这可以减少不必要的代码和数据，使恶意程序更小、更精简

下面是几种具体的技术实现，从初级到高级：

**1. 使用 `LoadLibrary` 和 `GetProcAddress`**

这是最基础、最常见的方法。攻击者只需要在代码中静态导入 `LoadLibraryA/W` 和 `GetProcAddress` 这两个函数，然后用它们来动态获取所有其他需要的 API

**实现步骤：**

1. **加载 DLL：** 调用 `LoadLibraryA`，传入需要加载的 DLL 名称（例如 "kernel32.dll"）。这个函数会返回该 DLL 在内存中的基址
2. **获取函数地址：** 调用 `GetProcAddress`，传入 DLL 的基址和需要获取的函数名称（例如 "CreateRemoteThread"）。这个函数会返回该 API 的内存地址
3. **函数指针调用：** 将获取到的地址赋值给一个函数指针，然后通过这个指针像调用普通函数一样来调用它

```c
// 伪代码
#include <windows.h>
#include <stdio.h>

int main() {
    HMODULE hKernel32 = LoadLibraryA("kernel32.dll");
    if (hKernel32 == NULL) {
        // 处理错误
        return 1;
    }

    // 定义一个函数指针类型
    typedef HANDLE (WINAPI* CreateRemoteThread_t)(HANDLE, LPSECURITY_ATTRIBUTES, SIZE_T, LPTHREAD_START_ROUTINE, LPVOID, DWORD, LPDWORD);

    // 获取 CreateRemoteThread 的地址
    CreateRemoteThread_t pCreateRemoteThread = (CreateRemoteThread_t)GetProcAddress(hKernel32, "CreateRemoteThread");
    if (pCreateRemoteThread == NULL) {
        // 处理错误
        return 1;
    }

    // 现在可以使用 pCreateRemoteThread 来调用 CreateRemoteThread 函数了
    // pCreateRemoteThread(..., ..., ...);

    return 0;
}
```

这种方法虽然简单，但 `LoadLibrary` 和 `GetProcAddress` 依然会出现在程序的导入表中，因此安全软件仍然可以进行识别

**2. 手动解析 PEB**

这是更高级、更隐蔽的方法。其核心是**完全不依赖任何静态导入**，通过**手动遍历内存中的数据结构**来找到所需的 API 地址

**实现步骤：**

1. **获取 PEB 地址：** 在 32 位系统上，PEB 的地址可以通过 `FS:[0x30]` 寄存器来获取；在 64 位系统上，可以通过 `GS:[0x60]` 来获取
2. **遍历 PEB LDR 数据结构：** PEB 结构体中包含一个指向已加载模块列表的指针（`LDR_DATA`）。攻击者可以遍历这个列表，找到 `ntdll.dll`、`kernel32.dll` 等已加载的 DLL 模块
3. **解析 DLL 的导出表（EAT）：** 找到目标 DLL 的基址后，手动解析其**导出地址表 (EAT)**。EAT 是一个包含所有导出函数名称和地址的结构
4. **哈希值匹配：** 为了避免在代码中硬编码函数名称字符串（字符串会暴露恶意意图），攻击者通常会为每个函数名称计算一个哈希值。遍历 EAT 中的函数名称，计算哈希值，然后与预设的目标哈希值进行匹配。如果匹配成功，就找到了所需 API 的地址
5. **函数指针调用：** 获取到地址后，同样通过函数指针进行调用