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

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

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

vs2017

x64 下记事本WriteFile() API钩取的更多相关文章

  1. 调试钩取技术 - 记事本WriteFile() API钩取

    @author: dlive 0x01 简介 本章将讲解前面介绍过的调试钩取技术,钩取记事本的kernel32!WriteFile() API 调试钩取技术能进行与用户更具有交互性(interacti ...

  2. 高级全局API钩取 - IE连接控制

    @author: dlive @date: 2017/02/14 0x01 调试IE进程 常见网络连接库:ws2_32.dll(套接字),wininet.dll,winhttp.dll 使用Proce ...

  3. c#使用easyhook库进行API钩取

    目标:使calc程序输入的数自动加1 (当别人使用时,总会得不到正确的结果,哈哈) 编写注入程序 ————————————————————————————————— class Program中的方法 ...

  4. 通过注入DLL修改API代码实现钩取(一)

    通过注入DLL修改API代码实现钩取(一) Ox00 大致思路 通过CreateRemoteThread函数开辟新线程,并将DLL注入进去 通过GetProcessAddress函数找到需钩取的API ...

  5. 通过调试对WriteFile()API的钩取

    通过调试对WriteFile()API的钩取 0x00 目标与思路 目标:钩取指定的notepad.exe进程writeFile()API函数,对notepad.exe进程的写入的字符保存时保存为大写 ...

  6. 通过注入DLL后使用热补丁钩取API

    通过注入DLL后使用热补丁钩取API 0x00 对比修改API的前五个字节钩取API 对前一种方法钩取API的流程梳理如下: 注入相应的DLL 修改原始AI的函数的前五个字节跳往新函数(钩取API) ...

  7. 《逆向工程核心原理》Windows消息钩取

    DLL注入--使用SetWindowsHookEx函数实现消息钩取 MSDN: SetWindowsHookEx Function The SetWindowsHookEx function inst ...

  8. 汇编Ring 3下实现 HOOK API

    [文章标题]汇编ring3下实现HOOK API [文章作者]nohacks(非安全,hacker0058) [作者主页]hacker0058.ys168.com [文章出处]看雪论坛(bbs.ped ...

  9. Window下通过charles代理抓取iphone/android手机Https请求乱码问题处理

    Window下通过charles代理抓取iphone手机Https请求乱码问题 如果保持默认设置,https的reqeust和response都是乱码,设置完之后https就可以抓包了 手机端操作: ...

随机推荐

  1. shiro<1.2.4反序列化分析

    0x01.环境搭建 下载地址:https://codeload.github.com/apache/shiro/zip/shiro-root-1.2.4 环境:Tomcat 8.5.27 + idea ...

  2. 2021 从零开始打造一个自己的 UI 组件库

    2021 从零开始打造一个自己的 UI 组件库 refs GUI https://github.com/xgqfrms/gui/ https://www.npmjs.com/package/@xgqf ...

  3. PM2 in depth

    PM2 in depth ecosystem.config.js module.exports = { apps : [{ name: "app", script: ". ...

  4. Flutter WillPopScope 拦截路由返回

    WillPopScope addScopedWillPopCallback 启用此路由以使用户否决尝试以将其关闭. 典型应用是如果用户尝试退出表单,则警告用户有关未保存的表单数据.连按两次返回键退出A ...

  5. NGK创造的BGV金融世界观是什么?

    目前DeFi已经形成初级的金融体系.笔者将DeFi市场对比传统金融世界观,不过市场结构有显着差异.我们可以这样想:如果在去中心化金融世界中借钱,那么可以把MakerDAO比作为中央银行(+回购). 去 ...

  6. [转]#include< > 和 #include” ” 的区别

    原文网址:https://www.cnblogs.com/LeoFeng/p/5346530.html 一.#include< > #include< > 引用的是编译器的类库 ...

  7. epoll 原理

    本文转载自epoll 原理 导语 以前经常被人问道 select.poll.epoll 的区别,基本都是靠死记硬背的,最近正好复习 linux 相关的内容,就把这一块做个笔记吧,以后也能方便查阅. e ...

  8. Nifi组件脚本开发—ExecuteScript 使用指南(三)

    上一篇:Nifi组件脚本开发-ExecuteScript 使用指南(二) Part 3 - 高级特征 本系列的前两篇文章涵盖了 flow file 的基本操作, 如读写属性和内容, 以及使用" ...

  9. Oracle数据库配置监听程序

    最近在学习Oracle数据库,从安装到配置监听程序基本靠百度... 不得不说百度真的很nice!!! 下面是我的Oracle服务端(PL/SQL Developer)出现的监听程序的问题及我解决的方法 ...

  10. 2021-2-27:Linux 下如何优化 Java MMAP 写入

    主要是调整 pdflush 相关参数. 在linux操作系统中,写操作是异步的,即写操作返回的时候数据并没有真正写到磁盘上,而是先写到了系统cache里,随后由pdflush内核线程将系统中的脏页写到 ...