免杀专题
29、动态Patch函数
1. 课程目标
学习运行时动态修改代码的技术,用于绕过静态检测。
2. 技术原理
编译时:
┌─────────────────────────────────┐
│ 加密/混淆的函数代码 │
└─────────────────────────────────┘
运行时:
┌─────────────────────────────────┐
│ 1. 修改内存权限为可写 │
│ 2. 解密/还原真实代码 │
│ 3. 修改权限为可执行 │
│ 4. 执行函数 │
│ 5. (可选)重新加密 │
└─────────────────────────────────┘
3. 实现代码
3.1 基础动态Patch
#include <windows.h>
#include <stdio.h>
// 被加密的函数体(编译时用工具加密)
unsigned char encryptedFunc[] = {
0x55, // push ebp
0x8B, 0xEC, // mov ebp, esp
// ... 加密后的指令
};
// 解密密钥
BYTE key = 0x41;
void DynamicPatchAndExecute() {
DWORD size = sizeof(encryptedFunc);
// 1. 分配可写内存
LPVOID pFunc = VirtualAlloc(NULL, size,
MEM_COMMIT | MEM_RESERVE,
PAGE_READWRITE);
memcpy(pFunc, encryptedFunc, size);
// 2. 解密
LPBYTE pCode = (LPBYTE)pFunc;
for (DWORD i = 0; i < size; i++) {
pCode[i] ^= key;
}
// 3. 修改为可执行
DWORD oldProtect;
VirtualProtect(pFunc, size, PAGE_EXECUTE_READ, &oldProtect);
// 4. 执行
typedef int(*FUNC_TYPE)();
FUNC_TYPE func = (FUNC_TYPE)pFunc;
int result = func();
// 5. 清理
VirtualFree(pFunc, 0, MEM_RELEASE);
}
3.2 原地Patch
#include <windows.h>
// 在.text段的函数(需要特殊编译设置)
__declspec(noinline) void EncryptedFunction() {
// 占位指令,运行时会被替换
__asm {
nop
nop
nop
nop
}
}
void PatchFunctionInPlace() {
// 获取函数地址
LPVOID pFunc = (LPVOID)EncryptedFunction;
// 修改权限
DWORD oldProtect;
VirtualProtect(pFunc, 100, PAGE_EXECUTE_READWRITE, &oldProtect);
// 写入真实代码
BYTE realCode[] = {
0xB8, 0x01, 0x00, 0x00, 0x00, // mov eax, 1
0xC3 // ret
};
memcpy(pFunc, realCode, sizeof(realCode));
// 刷新缓存
FlushInstructionCache(GetCurrentProcess(), pFunc, sizeof(realCode));
// 恢复权限
VirtualProtect(pFunc, 100, oldProtect, &oldProtect);
// 调用
EncryptedFunction();
}
3.3 延迟解密
#include <windows.h>
typedef struct _ENCRYPTED_FUNC {
LPBYTE pEncrypted;
DWORD dwSize;
BYTE key;
BOOL bDecrypted;
LPVOID pExecutable;
} ENCRYPTED_FUNC;
// 延迟解密执行
LPVOID LazyDecrypt(ENCRYPTED_FUNC* pEF) {
if (pEF->bDecrypted) {
return pEF->pExecutable;
}
// 首次调用时解密
pEF->pExecutable = VirtualAlloc(NULL, pEF->dwSize,
MEM_COMMIT | MEM_RESERVE,
PAGE_EXECUTE_READWRITE);
for (DWORD i = 0; i < pEF->dwSize; i++) {
((LPBYTE)pEF->pExecutable)[i] = pEF->pEncrypted[i] ^ pEF->key;
}
pEF->bDecrypted = TRUE;
return pEF->pExecutable;
}
4. 课后作业
4.1、作业1:基础Patch(必做)
- 实现函数动态解密执行
- 验证解密前后代码差异
4.2、作业2:原地Patch(进阶)
- 实现原地修改.text段代码
- 处理DEP保护
5. 下一课预告
下一课我们将学习代码混淆技术。