《逆向工程核心原理》第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

最新文章

  1. 使用Masonry搭建特殊布局时与xib的对比
  2. construction of tuples containing 0 or 1 items
  3. lucene 建立索引的不同方式
  4. 51 nod 机器人走方格
  5. [转]浅谈https\ssl\数字证书
  6. 如何恢复 Linux 上删除的文件,第 1 部分
  7. HDOJ2011多项式求和
  8. hive建表没使用LZO存储格式,可是数据是LZO格式时遇到的问题
  9. javascript获取整数随机数
  10. vue+node+webpack搭建环境
  11. django restful 1-在线Python编辑器
  12. Python 线程复习
  13. Sting、StringBuffer、StringBuilder
  14. 论文阅读笔记二十:LinkNet: Exploiting Encoder Representations for Efficient Semantic Segmentation(CVPR2017)
  15. Java语法基础学习DayTwelve(泛型)
  16. 关于 IdentityServer 部署到生产环境相关问题踩坑记录
  17. 机器学习 支持向量机(SVM) 从理论到放弃,从代码到理解
  18. CentOS7.2 安装Docker
  19. java 内部类 工厂方法
  20. IIS7.5标识介绍

热门文章

  1. Chrome Canary crashed bug
  2. algorithm &amp; bitwise operation &amp; the best leetcode solutions
  3. taro 进阶指南
  4. svg &amp; regex
  5. TypeScript &amp; Examples
  6. BGV再度爆发,流通市值破500万美金!
  7. javascript中的内置对象和数据结构
  8. SpringBoot2.x中的AOP机制总结(附带demo)
  9. 求幂&amp;&amp;快速幂&amp;&amp;位运算
  10. 500GJava/Hadoop/Spark/机器学习...视频教程免费分享 百度云持续更新