x64 下记事本WriteFile() API钩取

《逆向工程核心原理》第30章 记事本WriteFile() API钩取 

原文是在x86下,而在x64下函数调用方式为fastcall,前4个参数保存在寄存器中。在原代码基础上进行修改:

  1 // myhookdbg.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
  2 //
  3 
  4 #include "pch.h"
  5 #include <iostream>
  6 #include <windows.h>
  7 #include <tchar.h>
  8 #include <tlhelp32.h>
  9 #include <stdio.h>
 10 #include <shlobj.h>
 11 
 12 
 13 LPVOID g_pfWriteFile = NULL;
 14 CREATE_PROCESS_DEBUG_INFO g_cpdi;
 15 BYTE g_chINT3 = 0xCC, g_chOrgByte = 0;
 16 BOOL OnCreateProcessDebugEvent(LPDEBUG_EVENT pde)
 17 {
 18     // 查找API地址
 19     HMODULE dll = GetModuleHandleA("kernel32.dll");
 20     g_pfWriteFile = GetProcAddress(dll, "WriteFile");
 21     //g_pfWriteFile =(LPVOID)0x7ffca76b2500;
 22     printf("kernel32.dll基址:%I64x\n", dll);
 23     printf("WriteFile地址:%I64x\n", (DWORD64 )g_pfWriteFile);
 24     // API Hook - WriteFile()
 25     //   将byte更改为0xCC (INT 3)
 26     //  orginal byte是备份
 27     memcpy(&g_cpdi, &pde->u.CreateProcessInfo, sizeof(CREATE_PROCESS_DEBUG_INFO));
 28     ReadProcessMemory(g_cpdi.hProcess, g_pfWriteFile,
 29         &g_chOrgByte, sizeof(BYTE), NULL);
 30     printf("原api调用处字节:%x\n", g_chOrgByte);
 31     WriteProcessMemory(g_cpdi.hProcess, g_pfWriteFile,
 32         &g_chINT3, sizeof(BYTE), NULL);
 33     BYTE arr[10];
 34     ReadProcessMemory(g_cpdi.hProcess, g_pfWriteFile,
 35         arr, sizeof(BYTE)*10, NULL);
 36     printf("修改后:\n");
 37     for (int i = 0; i < 10; i++)
 38         printf("%02x ", arr[i]);
 39     printf("\n");
 40     return TRUE;
 41 }
 42 
 43 BOOL OnExceptionDebugEvent(LPDEBUG_EVENT pde)
 44 {
 45     CONTEXT ctx;
 46     PBYTE lpBuffer = NULL;
 47     DWORD i;
 48     ULONG_PTR dwNumOfBytesToWrite, dwAddrOfBuffer;
 49     PEXCEPTION_RECORD64 per =(PEXCEPTION_RECORD64)&pde->u.Exception.ExceptionRecord;
 50 
 51     // BreakPoint exception (INT 3) 的情况
 52     if (EXCEPTION_BREAKPOINT == per->ExceptionCode)
 53     {
 54         // 如果BP地址是WriteFile,
 55         if ((DWORD64)g_pfWriteFile == per->ExceptionAddress)
 56         {
 57             printf("发现writefile调用,地址:%I64X\n", g_pfWriteFile);
 58             // #1. Unhook
 59             //   如果BP地址是WriteFile(用0xCC覆盖的部分返回original byte)
 60             WriteProcessMemory(g_cpdi.hProcess, g_pfWriteFile,
 61                 &g_chOrgByte, sizeof(BYTE), NULL);
 62             BYTE arr[10];
 63             ReadProcessMemory(g_cpdi.hProcess, g_pfWriteFile,
 64                 arr, sizeof(BYTE)*10, NULL);
 65             printf("恢复后:");
 66             for (int i = 0; i < 10; i++)
 67                 printf("%02x ", arr[i]);
 68             printf("\n");
 69             // #2. 寻求Thread Context
 70             //ctx.ContextFlags = CONTEXT_CONTROL;SegSs栈段, Rsp, SegCs代码段, Rip, and EFlags
 71             ctx.ContextFlags = CONTEXT_FULL;//要获得全部寄存器
 72             GetThreadContext(g_cpdi.hThread, &ctx);
 73             LPOVERLAPPED arg5_lpOverlapped = NULL;
 74             ReadProcessMemory(g_cpdi.hProcess, (LPVOID)(ctx.Rsp + 0x28), &arg5_lpOverlapped, sizeof(DWORD), NULL);
 75             printf("寄存器数据:\n");
 76             //printf("rax:%I64x\n", ctx.Rax);
 77             //printf("rbx:%I64x\n", ctx.Rbx);
 78             printf("rcx:%I64x\n", ctx.Rcx);
 79             printf("rdx:%I64x\n", ctx.Rdx);
 80             printf("r8:%I64x\n", ctx.R8);
 81             printf("r9:%I64x\n", ctx.R9);
 82             printf("arg5:%I64x\n",arg5_lpOverlapped);
 83             
 84             
 85             // #3.获取param 2和3的值
 86             //   x86函数参数存在于此进程的栈中;x64 fastcall 前4个参数存在寄存器中
 87             //   LPCVOID lpBuffer,//数据缓存区指针 rdx 
 88             //    DWORD   nNumberOfBytesToWrite,//你要写的字节数 r8
 89             //   param 2 : rdx
 90             //   param 3 : r8
 91 
 92             //ReadProcessMemory(g_cpdi.hProcess, (LPVOID)(ctx.esp + 0x8),&dwAddrOfBuffer, sizeof(DWORD), NULL);
 93             //ReadProcessMemory(g_cpdi.hProcess, (LPVOID)(ctx.esp + 0xC),&dwNumOfBytesToWrite, sizeof(DWORD), NULL);
 94             dwAddrOfBuffer = ctx.Rdx;
 95             dwNumOfBytesToWrite = ctx.R8;
 96             //printf("%s\n", dwAddrOfBuffer);
 97             // #4. 临时缓冲配额
 98             lpBuffer = (PBYTE)malloc(dwNumOfBytesToWrite + 1);
 99             memset(lpBuffer, 0, dwNumOfBytesToWrite + 1);
100 
101             // #5. 将WriteFile的缓冲复制到临时缓冲
102             ReadProcessMemory(g_cpdi.hProcess, (LPVOID)dwAddrOfBuffer,
103                 lpBuffer, dwNumOfBytesToWrite, NULL);
104             printf("\n### original string ###\n%s\n", lpBuffer);
105 
106             // #6.小写->大写转换
107             for (i = 0; i < dwNumOfBytesToWrite; i++)
108             {
109                 if (0x61 <= lpBuffer[i] && lpBuffer[i] <= 0x7A)
110                     lpBuffer[i] -= 0x20;
111             }
112 
113             printf("\n### converted string ###\n%s\n", lpBuffer);
114 
115             // #7. 将转换后的缓冲复制到WriteFile的缓冲
116             WriteProcessMemory(g_cpdi.hProcess, (LPVOID)dwAddrOfBuffer,
117                 lpBuffer, dwNumOfBytesToWrite, NULL);
118             //ctx.Rdx=
119             // #8. 取消临时缓冲
120             free(lpBuffer);
121 
122             // #9.将Thread Context的EIP更改为WriteFile()
123             //   (现在已经过WriteFile() + 1)
124     
125             //BOOL WriteFile(
126             //    HANDLE  hFile,//文件句柄  rcx
127             //    LPCVOID lpBuffer,//数据缓存区指针 rdx 
128             //    DWORD   nNumberOfBytesToWrite,//你要写的字节数 r8
129             //    LPDWORD lpNumberOfBytesWritten,//用于保存实际写入字节数的存储区域的指针 r9
130             //    LPOVERLAPPED lpOverlapped//OVERLAPPED结构体指针 rsp+0x20    [call 前rsp 0 8 10 18 20 28]
131             //);
132             /*ctx.Rdx += 1;
133             ctx.R8 -= 1;*/
134             ctx.Rip =(DWORD64)g_pfWriteFile;
135             //ctx.Eip = (DWORD)g_pfWriteFile;
136             SetThreadContext(g_cpdi.hThread, &ctx);
137 
138             // #10. Debuggee 运行被调试进程
139             ContinueDebugEvent(pde->dwProcessId, pde->dwThreadId, DBG_CONTINUE);
140             Sleep(0);
141             printf("continue\n");
142             // #11. API Hook
143             WriteProcessMemory(g_cpdi.hProcess, g_pfWriteFile,&g_chINT3, sizeof(BYTE), NULL);
144 
145             return TRUE;
146         }
147     }
148 
149     return FALSE;
150 }
151 
152 void DebugLoop()
153 {
154     DEBUG_EVENT de;
155     DWORD dwContinueStatus;
156 
157     // 从Debuggee等待event的到来。
158     while (WaitForDebugEvent(&de, INFINITE))
159     {
160         dwContinueStatus = DBG_CONTINUE;
161 
162         // 创建Debuggee进程或attach事件
163         if (CREATE_PROCESS_DEBUG_EVENT == de.dwDebugEventCode)
164         {
165             OnCreateProcessDebugEvent(&de);
166             printf("finish creat debuggee\n");
167         }
168         // 异常活动
169         else if (EXCEPTION_DEBUG_EVENT == de.dwDebugEventCode)
170         {
171             if (OnExceptionDebugEvent(&de))
172                 continue;
173         }
174         // Debuggee进程退出事件
175         else if (EXIT_PROCESS_DEBUG_EVENT == de.dwDebugEventCode)
176         {
177             // debuggee结束-> debugger结束
178             break;
179         }
180 
181         // Debuggee的恢复执行。
182         ContinueDebugEvent(de.dwProcessId, de.dwThreadId, dwContinueStatus);
183     }
184 }
185 
186 int main()
187 {
188     //system("tasklist");
189     system("tasklist | findstr notepad");
190     char pid[10];
191     printf("输入要注入的进程pid:\n");
192     scanf_s("%s", pid, 10);
193 
194     DWORD dwPID;
195     dwPID = atoi(pid);
196     if (!DebugActiveProcess(dwPID))
197     {
198         printf("DebugActiveProcess(%d) failed!!!\n"
199             "Error Code = %d\n", dwPID, GetLastError());
200         return 1;
201     }
202 
203     // 调试器循环
204     DebugLoop();
205     system("pause");
206     return 0;
207     /*std::cout << "Hello World!\n"; */
208 }
209 
210 // 运行程序: Ctrl + F5 或调试 >“开始执行(不调试)”菜单
211 // 调试程序: F5 或调试 >“开始调试”菜单
212 
213 // 入门提示: 
214 //   1. 使用解决方案资源管理器窗口添加/管理文件
215 //   2. 使用团队资源管理器窗口连接到源代码管理
216 //   3. 使用输出窗口查看生成输出和其他消息
217 //   4. 使用错误列表窗口查看错误
218 //   5. 转到“项目”>“添加新项”以创建新的代码文件,或转到“项目”>“添加现有项”以将现有代码文件添加到项目
219 //   6. 将来,若要再次打开此项目,请转到“文件”>“打开”>“项目”并选择 .sln 文件

vs2017 

 

 

 

 

 

 

 

 

 

 

 

 

 

上一篇:vc++进程注入钩子DLL通用模块开源


下一篇:逆向对抗技术之ring3解除文件句柄,删除文件