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

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. webpack remove console.log

    webpack remove console.log https://stackoverflow.com/questions/41040266/remove-console-logs-with-web ...

  2. Vue 3.x & v-model

    Vue 3.x & v-model https://v3.vuejs.org/guide/migration/v-model.html#overview BREAKING: When used ...

  3. auto scroll bottom in js

    auto scroll bottom in js autoScrollToBottom() { let box = document.querySelector(`[data-dom="ch ...

  4. 大胆预计SPC算力空投收益,月收益22.8%

    此前,NGK官方公告表示,NGK算力持有者获得SPC的数量是根据200万枚SPC除以全网算力总量决定的. 举个例子,假设全网算力总量为500万,那么每个算力持有者如果持有一个算力,则可获得200万÷5 ...

  5. Mybatis-05 注解开发

    Mybatis-05 注解开发 注解开发 注解的核心是反射机制 面向接口编程的根本原因:解耦,可拓展,提高复用,分层开发中.上层不用管具体的实现,大家都遵守共同的标准,使得开发变得容易,规范性好. 1 ...

  6. 基于股票大数据分析的Python入门实战(视频教学版)的精彩插图汇总

    在我写的这本书,<基于股票大数据分析的Python入门实战(视频教学版)>里,用能吸引人的股票案例,带领大家入门Python的语法,数据分析和机器学习. 京东链接是这个:https://i ...

  7. sql注入和union all关联查询的学习总结

    1.后台从页面取值进行sql查询时最好不要直接拼,如下代码: String sql = "SELECT wo.* " + " from push_command pu & ...

  8. Manjaro安装后简单配置

    一个相见恨晚的 Linux 操作系统 Manjaro 到底有多受欢迎? DistroWatch是一个包含了各种Linux发行版及其他自由/开放源代码的类Unix操作系统. (如OpenSolaris. ...

  9. 关于C++中构造函数的常见疑问

    基本概念 我们已经知道在定义一个对象时,该对象会根据你传入的参数来调用类中对应的构造函数.同时,在释放这个对象时,会调用类中的析构函数.其中,构造函数有三种,分别是默认构造函数,有参构造函数和拷贝构造 ...

  10. 基于jQuery1.4.2轻量级的弹出窗口jQuery插件wBox 1.0

    Box特点 背景透明度可以根据实际情况进行调节 可以根据需要添加wBox标题 支持callback函数 支持html内容自定义 支持在wBox显示#ID的内容 支持Ajax页面内容 支持iFrame ...