通过调试对WriteFile()API的钩取
通过调试对WriteFile()API的钩取
0x00 目标与思路
目标:钩取指定的notepad.exe进程writeFile()API函数,对notepad.exe进程的写入的字符保存时保存为大写形式
思路:
1)使用DebugActiveProcess函数使调试器附加到指定进程中。
2)使用WaitForDebugEvent函数取得目标进程的调试信息。
3)更改writeFile()函数api的第一个字节为0xcc,使其进入调试区
4)进入调试去后将writeFile()API的第一个字节恢复原状,因为后面还有用。
5)对notepad输入缓冲区的字符串进行大写转换,并保存到缓冲区。
6)恢复writeFile的EIP信息
7)继续运行调试程序
8)再次写入INT3钩子
0x01实现代码
// hookapi1.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
#include "pch.h"
#include <iostream>
#include<Windows.h>
#include<stdio.h>
LPVOID g_pfWriteFile = NULL;
CREATE_PROCESS_DEBUG_INFO g_cpdi;
BYTE g_chINT3 = 0xcc, g_chOrgByte = 0;
//被调试进程启动时函数发生作用
BOOL OnCreateProcessDebugEvent(LPDEBUG_EVENT pde)
{
//获取WriteFile()API地址
g_pfWriteFile = GetProcAddress(GetModuleHandleA("kernel32.dll"), "WriteFile");
//将WriteFile()的第一个字节换成INT3即0xcc
//并且添加WriteFile()第一字节的备份,为以后恢复做准备
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 dwNumofByteToWrite, dwAddrOfBuffer, i;
PEXCEPTION_RECORD per = &pde->u.Exception.ExceptionRecord;
//判断是否是INT3异常
if (EXCEPTION_BREAKPOINT == per->ExceptionCode)
{
//判断是够否是WriteFile()API的地址
if (g_pfWriteFile == per->ExceptionAddress)
{
//1.脱钩,即将writeFile()的首地址恢复,因为后面的用到该函数
WriteProcessMemory(g_cpdi.hProcess, g_pfWriteFile, &g_chOrgByte, sizeof(BYTE), NULL);
//2.获取进程上下文,其实就是获取各个寄存器的值
//获得进程上下文之后就可以获得进程中函数的各个参数值
ctx.ContextFlags = CONTEXT_CONTROL;
GetThreadContext(g_cpdi.hThread, &ctx);
//3.获取WriteFile()的param2以及param3的值
//param2是writeFile()的字符缓冲区地址
//param3是WriteFile()的字符缓冲区大小
ReadProcessMemory(g_cpdi.hProcess, (LPVOID)(ctx.Esp + 0x8), &dwAddrOfBuffer, sizeof(DWORD), NULL);
ReadProcessMemory(g_cpdi.hProcess, (LPVOID)(ctx.Esp + 0xC), &dwNumofByteToWrite, sizeof(DWORD), NULL);
//4.分配临时缓冲区给存放缓冲区的字符串
lpBuffer = (PBYTE)malloc(dwNumofByteToWrite + 1);
//将新分配的缓冲区的内容清零,以便存放内容
memset(lpBuffer, 0, dwNumofByteToWrite + 1);
//5.复制writeFile()的缓冲区的内容复制到临时缓冲区
ReadProcessMemory(g_cpdi.hProcess, (LPVOID)dwAddrOfBuffer, lpBuffer, dwNumofByteToWrite, NULL);
printf("\n### 初始字符串 ###\n%s\n", lpBuffer);
//6.将临时缓冲区的字符串转换成大写
for (i = 0; i < dwNumofByteToWrite; 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, dwNumofByteToWrite, NULL);
//8.释放临时缓冲区
free(lpBuffer);
//9.更改EIP指针恢复为WriteFile()的首地址
//由于前面更改WriteFile()的首地址为INT3了,后面执行了INT3指令之后EIP增加了1。所以执行完之后要改回去。
ctx.Eip = (DWORD)g_pfWriteFile;
SetThreadContext(g_cpdi.hThread, &ctx);
//10.继续运行被调试程序
ContinueDebugEvent(pde->dwProcessId, pde->dwThreadId, DBG_CONTINUE);
Sleep(0);
//11.再次写入API钩子
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))
{
dwContinueStatus = DBG_CONTINUE;
//被调试进程生成或者要附加事件
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)
{
printf("\nUSAGE : hookdbg.exe <pid>\n");
return 1;
}
// 将第二个参数转化为long型
dwPID = atoi(argv[1]);
if (!DebugActiveProcess(dwPID))
{
printf("DebugActiveProcess(%d) failed!!!\n"
"Error Code = %d\n", dwPID, GetLastError());
return 1;
}
// 循环等待事件发生
Debugloop();
return 0;
}
编译生成hookapi1.exe文件。将其放入D盘。
0x02 运行查看效果
打开notepad.exe,打开processExploer查看notepad.exe的PID,用管理员权限打开cmd,输入hookapi1.exe 16576,向notepad中输入小写的“war is over!”退出并保存为1.text文件。运行结果如下图:
通过调试对WriteFile()API的钩取的更多相关文章
- 通过注入DLL修改API代码实现钩取(一)
通过注入DLL修改API代码实现钩取(一) Ox00 大致思路 通过CreateRemoteThread函数开辟新线程,并将DLL注入进去 通过GetProcessAddress函数找到需钩取的API ...
- 调试钩取技术 - 记事本WriteFile() API钩取
@author: dlive 0x01 简介 本章将讲解前面介绍过的调试钩取技术,钩取记事本的kernel32!WriteFile() API 调试钩取技术能进行与用户更具有交互性(interacti ...
- x64 下记事本WriteFile() API钩取
<逆向工程核心原理>第30章 记事本WriteFile() API钩取 原文是在x86下,而在x64下函数调用方式为fastcall,前4个参数保存在寄存器中.在原代码基础上进行修改: 1 ...
- 高级全局API钩取 - IE连接控制
@author: dlive @date: 2017/02/14 0x01 调试IE进程 常见网络连接库:ws2_32.dll(套接字),wininet.dll,winhttp.dll 使用Proce ...
- c#使用easyhook库进行API钩取
目标:使calc程序输入的数自动加1 (当别人使用时,总会得不到正确的结果,哈哈) 编写注入程序 ————————————————————————————————— class Program中的方法 ...
- 通过注入DLL后使用热补丁钩取API
通过注入DLL后使用热补丁钩取API 0x00 对比修改API的前五个字节钩取API 对前一种方法钩取API的流程梳理如下: 注入相应的DLL 修改原始AI的函数的前五个字节跳往新函数(钩取API) ...
- 《逆向工程核心原理》——通过调试方式hook Api
1.附加目标进程, 2.CREATE_PROCESS_DEBUG_EVENT附加事件中将目标api处设置为0xcc(INT 3断点) 3.EXCEPTION_DEBUG_EVENT异常事件中,首先判断 ...
- 《逆向工程核心原理》Windows消息钩取
DLL注入--使用SetWindowsHookEx函数实现消息钩取 MSDN: SetWindowsHookEx Function The SetWindowsHookEx function inst ...
- Azure DevOps Server: 使用Rest Api获取拉取请求Pull Request中的变更文件清单
需求: Azure DevOps Server 的拉取请求模块,为开发团队提供了强大而且灵活的代码评审功能.拉取请求中变更文件清单,对质量管理人员,是一个宝贵的材料.质量保障人员可以从代码清单中分析不 ...
随机推荐
- python3 修改计算机名称GUI程序
from tkinter import *from tkinter import messageboximport tkinterimport winregimport osdef serch(): ...
- 最新 iOS 框架整体梳理(二)
在前面一篇中整理出来了一些了,下面的内容是接着上面一篇的接着整理.上篇具体的内容可以点击这里查看: 最新 iOS 框架整体梳理(一) Part - 2 34.CoreTeleph ...
- 小程序scroll-view实现回到顶部
一.wxml页面:catchtap阻止冒泡事件. <view class="gotop" hidden='{{!cangotop}}'catchtap="goTop ...
- 写了个全局变量的bug,被同事们打脸!!!
话说栈长前阵子写了一个功能,测试 0 bug 就上线了,上线后也运行好好的,好多天都没有人反馈bug,超爽.. 不出问题还好,出问题就是大问题.. 最近有个客户反馈某些数据混乱问题,看代码死活看不出什 ...
- JS基础知识笔记
2020-04-15 JS基础知识笔记 // new Boolean()传入的值与if判断一样 var test=new Boolean(); console.log(test); // false ...
- <Win10开发>UWP使用.Net Native编译时遇到的一些问题。
最近开始尝试把WP8.1 Runtime的项目升级成Win10 UWP,我用的方法没什么技巧性,就是直接复制文件和代码到新建的UWP项目.结果是后台代码未经修改,全部正常运行.但是UI控件的布局有些偏 ...
- android中getWidth()和getMeasuredWidth()之间的区别
先给出一个结论:getMeasuredWidth()获取的是view原始的大小,也就是这个view在XML文件中配置或者是代码中设置的大小.getWidth()获取的是这个view最终显示的大小,这个 ...
- 【JMeter_11】JMeter逻辑控制器__Switch控制器<Switch Controller>
Switch控制器<Switch Controller> 业务逻辑: 取得switch value的值,通过对节点下所有取样器.逻辑控制器的下标.名称匹配去执行,switch value的 ...
- MySQL的使用方法和视图、索引、以及存储过程的一些简单方法
一,基本概念 1, 常用的两种引擎: (1) InnoDB a,支持ACID,简单地说就是支持事务完整性.一致性: b,支持行锁,以及类似ORACLE的一 ...
- Java学习笔记7(IO)
IO(输入输出) IO流按照操作数据的不同,分为字节流和字符流,按照数据传输方向分为输入流和输出流. 字节流 计算机中,所有文件都是以二进制(字节)形式存在,IO流中针对字节的输入输出提供了一系列的流 ...