BOOL WriteFile(
[in] HANDLE hFile, //文件或设备的句柄
[in] LPCVOID lpBuffer, //指向包含要写入文件或设备的数据的缓冲区的指针。
[in] DWORD nNumberOfBytesToWrite,//要写入文件或设备的字节数。
[out, optional] LPDWORD lpNumberOfBytesWritten,
//指向变量的指针,该变量接收使用同步 hFile 参数时写入的字节数。写入文件集 在执行任何工作或错误检查之前,此值为零。为此使用 NULL 参数,如果这是异步操作,以避免潜在的错误结果
[in, out, optional] LPOVERLAPPED lpOverlapped
);
返回值
如果函数成功,则返回值为非零值 (TRUE)。
如果函数失败或异步完成,则返回值为零 (假)。
然后在OD中打开notepad.exe,在运行程序之前,在WriteFile()API处下断点
下断点
在堆栈中找到数据缓冲区的指针Buffer,然后在数据窗口中跟随
可以看到之前保存在记事本中的内容
接下来要做的就是钩取WriteFile()API,用指定字符串覆盖数据缓冲区的字符串。
#include "windows.h"
#include "stdio.h"
LPVOID g_pfWriteFile = NULL;// 获取WriteFile() API地址,
CREATE_PROCESS_DEBUG_INFO g_cpdi;
BYTE g_chINT3 = 0xCC, g_chOrgByte = 0;
BOOL OnCreateProcessDebugEvent(LPDEBUG_EVENT pde)
{
// 获取WriteFile() API地址,此时获取的是调试进程的内存地址,因为是系统dll
g_pfWriteFile = GetProcAddress(GetModuleHandleA("kernel32.dll"), "WriteFile");
// API Hook - WriteFile()
// 更改第一个字节为0xCC
// originalbyte是g_ch0rgByte备份
//(目标,源,长度)
memcpy(&g_cpdi, &pde->u.CreateProcessInfo, sizeof(CREATE_PROCESS_DEBUG_INFO));
//目标进程句柄,目标进程的基址,用于存储读取的数据的缓冲区,读取的字节数,指向读取的字节数的变量的指针,
ReadProcessMemory(g_cpdi.hProcess, g_pfWriteFile,
&g_chOrgByte, sizeof(BYTE), NULL);
WriteProcessMemory(g_cpdi.hProcess, g_pfWriteFile,
&g_chINT3, sizeof(BYTE), NULL);
return TRUE;
}
BOOL OnExceptionDebugEvent(LPDEBUG_EVENT pde)
{
CONTEXT ctx;
PBYTE lpBuffer = NULL;
DWORD dwNumOfBytesToWrite, dwAddrOfBuffer, i;
PEXCEPTION_RECORD per = &pde->u.Exception.ExceptionRecord;
// 是断点异常时
if (EXCEPTION_BREAKPOINT == per->ExceptionCode)
{
// 断点地址为WriteFile()API地址时
if (g_pfWriteFile == per->ExceptionAddress)
{
// #1. Unhook
// 将0xCC恢复为original byte
WriteProcessMemory(g_cpdi.hProcess, g_pfWriteFile,
&g_chOrgByte, sizeof(BYTE), NULL);
// #2. 获取线程上下文
ctx.ContextFlags = CONTEXT_CONTROL;
//g_cpdi.hThread是被调试者的主线程句柄
GetThreadContext(g_cpdi.hThread, &ctx);
// #3. 获取WriteFile()的param2、3值
// 分别是数据缓冲区的地址和数据缓冲区的大小
// 函数参数存在于进程的栈,通过线程上下文的context结构体中的ESP成员可以获取
// param 2 : ESP + 0x8
// param 3 : ESP + 0xC
ReadProcessMemory(g_cpdi.hProcess, (LPVOID)(ctx.Esp + 0x8),
&dwAddrOfBuffer, sizeof(DWORD), NULL);
// &dwAddrOfBuffer指的是被调试者虚拟内存空间中的地址
ReadProcessMemory(g_cpdi.hProcess, (LPVOID)(ctx.Esp + 0xC),
&dwNumOfBytesToWrite, sizeof(DWORD), NULL);
// #4.分配临时缓冲区
lpBuffer = (PBYTE)malloc(dwNumOfBytesToWrite + 1);
//将 lpBuffer所指向区域的前dwNumOfBytesToWrite+1个字节用0填充
memset(lpBuffer, 0, dwNumOfBytesToWrite + 1);
// #5.复制WriteFile()缓冲区到临时缓冲区
ReadProcessMemory(g_cpdi.hProcess, (LPVOID)dwAddrOfBuffer,
lpBuffer, dwNumOfBytesToWrite, NULL);
printf("\n原始\n%s\n", lpBuffer);
// #6. 将小写字母转换为大写字母
for (i = 0; i < dwNumOfBytesToWrite; i++)
{
if (0x61 <= lpBuffer[i] && lpBuffer[i] <= 0x7A)
lpBuffer[i] -= 0x20;
}
printf("\n###目前 ###\n%s\n", lpBuffer);
// #7. 将变换后的缓冲区复制到WriteFile()缓冲区
WriteProcessMemory(g_cpdi.hProcess, (LPVOID)dwAddrOfBuffer,
lpBuffer, dwNumOfBytesToWrite, NULL);
// #8. 释放临时缓冲区
free(lpBuffer);
// #9. 将线程上下文的EIP更改为WriteFile()首地址
// (当前为WriteFile+1位置,INT3命令之后)
ctx.Eip = (DWORD)g_pfWriteFile;
SetThreadContext(g_cpdi.hThread, &ctx);
// #10. 运行被调试进程
ContinueDebugEvent(pde->dwProcessId, pde->dwThreadId, DBG_CONTINUE);
Sleep(0);
// #11. API Hook
WriteProcessMemory(g_cpdi.hProcess, g_pfWriteFile,
&g_chINT3, sizeof(BYTE), NULL);
return TRUE;
}
}
return FALSE;
}
void DebugLoop()
{
DEBUG_EVENT de;//调试事件结构体
DWORD dwContinueStatus;
// 等待被调试者发生事件
while (WaitForDebugEvent(&de, INFINITE))
{
//发生调试事件后,WaitForDebugEvent()API 会将相关信息设置到DEBUG_EVENT结构体对象
dwContinueStatus = DBG_CONTINUE;
//若处理正常,则为DBG_CONTINUE
// 若无法处理,或希望在SEH中进行处理,DBG_EXCEPTION_NOT_HANDLED
//
//被调试者进程生成或者附加事件
if (CREATE_PROCESS_DEBUG_EVENT == de.dwDebugEventCode)
{
OnCreateProcessDebugEvent(&de);
}
// 异常事件
else if (EXCEPTION_DEBUG_EVENT == de.dwDebugEventCode)
{
if (OnExceptionDebugEvent(&de))
continue;
}
// 被调试进程终止事件
else if (EXIT_PROCESS_DEBUG_EVENT == de.dwDebugEventCode)
{
// 被调试者终止 -> 调试器终止
break;
}
// 再次运行被调试者
ContinueDebugEvent(de.dwProcessId, de.dwThreadId, dwContinueStatus);
}
}
int main(int argc, char* argv[])
{
DWORD dwPID;
//判断参数个数
if (argc != 2)
{
//告诉使用者该exe的正确用法
printf("\nUSAGE : hookdbg.exe \n");
return 1;
}
// Attach Process,字符串转化成int型数据
dwPID = atoi(argv[1]);
//使调试器能够附加活动进程并对其进行调试
if (!DebugActiveProcess(dwPID))
{
printf("DebugActiveProcess failed!!!\n");
return 1;
}
// 调试器循环
DebugLoop();
return 0;
}
win7中快捷键打开任务管理器:
win+r——taskmgr
右键下方任务栏
Ctrl +Alt+del