win32调试工具原理OutputDebugString以及如何获取输出信息
在应用程序和调试器之间传递数据是通过一个 4KB 大小的共享内存块完成的,并有一个互斥量和两个事件对象用来保护对他的访问。下面就是相关的四个内核对象:
对象名称 对象类型 DBWinMutex Mutex DBWIN_BUFFER Section (共享内存) DBWIN_BUFFER_READY Event DBWIN_DATA_READY Event
互斥量通常一直保留在系统中,其他三个对象仅当调试器要接收信息才出现。事实上 - 如果一个调试器发现后三个对象已经存在,它会拒绝运行。
当 DBWIN_BUFFER 出现时,会被组织成以下结构。进程 ID 显示信息的来源,字符串数据填充这 4K 的剩余部分。按照约定,信息的末尾总是包括一个 NULL 字节。
struct dbwin_buffer {
DWORD dwProcessId;
char data[4096-sizeof(DWORD)];
};
当 OutputDebugString() 被应用调用时,它执行以下步骤。注意在任意位置的错误都将放弃整个事情,调试请求被认为是什么也不做(不会发送字符串)。
- 打开 DBWinMutex 并且等待,直到我们取得了独占访问。
- 映射 DBWIN_BUFFER 段到内存中:如果没有发现,则没有调试器在运行,将忽略整个请求。
- 打开 DBWIN_BUFFER_READY 和 DBWIN_DATA_READY 事件对象。就像共享内存段一样,缺少对象意味着没有可用的调试器。
- 等待 DBWIN_BUFFER_READY 事件对象为有信号状态:表示内存缓冲区不再被占用。大部分时候,这一事件对象一被检查就处于有信号状态,但等待缓冲区就绪不会超过 10 秒(超时将放弃请求)。
- 复制数据直到内存缓冲区中接近 4KB,再保存当前进程 ID。总是放置一个 NULL 字节到字符串结尾。
- 通过设置 DBWIN_DATA_READY 事件对象告诉调试器缓冲区就绪。调试器从那儿取走它。
- 释放互斥量。
- 关闭事件对象和段对象,但保留互斥量的句柄以备后用。
在调试器端会简单一点。互斥量根本不需要,如果事件对象和/或共享内存对象已经存在,则假定其他调试器已经在运行。系统中任意时刻只能存在一个调试器。
- 创建共享内存段以及两个事件对象。如果失败,退出。
- 设置 DBWIN_BUFFER_READY 事件对象,由此应用程序得知缓冲区可用。
- 等待 DBWIN_DATA_READY 事件对象变为有信号状态。
- 从内存缓冲区中提取进程 ID 和 NULL 结尾的字符串。
- 转到步骤 2。
这使我们认为这决不是一种低消耗的发送信息的方法,应用程序的运行速度会受到调试器的左右。
#define WIN32_LEAN_AND_MEAN #include <Windows.h>
#include <stdio.h> #define IfFalseRet(c) do{if(!(c)){return dwLastError = ::GetLastError();}}while(false) class CHandle
{
public:
CHandle(HANDLE h = NULL): m_h(h)
{
}
~CHandle()
{
Release();
}
void Release()
{
if(*this)
{
::CloseHandle(m_h);
}
m_h = NULL;
}
operator bool() const
{
return m_h != INVALID_HANDLE_VALUE && m_h != NULL;
}
operator HANDLE() const
{
return m_h;
}
CHandle& operator= (const HANDLE& h)
{
Release();
m_h = h;
return *this;
}
CHandle& operator= (CHandle& h)
{
if(this != &h)
{
HANDLE hSwap = m_h;
m_h = h.m_h;
h.m_h = hSwap;
h.Release();
}
return *this;
}
private:
HANDLE m_h;
}; LPCTSTR DBWIN_BUFFER = TEXT("DBWIN_BUFFER");
LPCTSTR DBWIN_BUFFER_READY = TEXT("DBWIN_BUFFER_READY");
LPCTSTR DBWIN_DATA_READY = TEXT("DBWIN_DATA_READY");
LPCTSTR DBWIN_MUTEX = TEXT("DBWinMutex"); #pragma pack(push, 1)
struct CDBWinBuffer
{
DWORD dwProcessId;
BYTE abData[4096 - sizeof(DWORD)];
};
#pragma pack(pop) bool g_fContinue = true; BOOL CtrlHandler(DWORD fdwCtrlType)
{
switch(fdwCtrlType)
{
case CTRL_C_EVENT:
case CTRL_CLOSE_EVENT:
case CTRL_LOGOFF_EVENT:
case CTRL_SHUTDOWN_EVENT:
g_fContinue = false;
return TRUE;
}
return FALSE;
} int __cdecl main()
{
DWORD dwLastError = ERROR_SUCCESS; IfFalseRet(SetConsoleCtrlHandler((PHANDLER_ROUTINE)(CtrlHandler), TRUE) == TRUE); CHandle hMutex = OpenMutex(MUTEX_ALL_ACCESS, FALSE, DBWIN_MUTEX);
if(!hMutex)
{
IfFalseRet(GetLastError() == ERROR_FILE_NOT_FOUND);
IfFalseRet(hMutex = CreateMutex(NULL, FALSE, DBWIN_MUTEX));
}
CHandle hEventBufferReady = OpenEvent(EVENT_MODIFY_STATE, FALSE, DBWIN_BUFFER_READY);
if(!hEventBufferReady)
{
IfFalseRet(GetLastError() == ERROR_FILE_NOT_FOUND);
IfFalseRet(hEventBufferReady = CreateEvent(NULL, FALSE, TRUE, DBWIN_BUFFER_READY));
}
CHandle hEventDataReady = OpenEvent(EVENT_MODIFY_STATE, FALSE, DBWIN_DATA_READY);
if(!hEventDataReady)
{
IfFalseRet(GetLastError() == ERROR_FILE_NOT_FOUND);
IfFalseRet(hEventDataReady = CreateEvent(NULL, FALSE, FALSE, DBWIN_DATA_READY));
} CHandle hFileMappingBuffer = OpenFileMapping(FILE_MAP_READ, FALSE, DBWIN_BUFFER);
if(!hFileMappingBuffer)
{
IfFalseRet(GetLastError() == ERROR_FILE_NOT_FOUND);
IfFalseRet(hFileMappingBuffer = CreateFileMapping(
INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE,
0, sizeof(CDBWinBuffer), DBWIN_BUFFER));
} CDBWinBuffer* pDbgBuffer = (CDBWinBuffer*)(MapViewOfFile(
hFileMappingBuffer, SECTION_MAP_READ, 0, 0, 0));
IfFalseRet(pDbgBuffer); while(g_fContinue)
{
if(WaitForSingleObject(hEventDataReady, 100) == WAIT_OBJECT_0)
{
printf("%s", pDbgBuffer->abData);
SetEvent(hEventBufferReady);
}
} UnmapViewOfFile(pDbgBuffer); return dwLastError;
}
win32调试工具原理OutputDebugString以及如何获取输出信息的更多相关文章
- Java实践-远程调用Shell脚本并获取输出信息
1.添加依赖 <dependency> <groupId>ch.ethz.ganymed</groupId> <artifactId>ganymed-s ...
- vc++调用exe获取输出信息
目的 调用命令行程序,返回结果. 思路 把命令行结果输入到管道中,exe的输出信息都存在了strOutput这个变量里. 实现代码 CString strCmd = L"yara64.exe ...
- win32程序调试OutputDebugString 类似printf格式化输出
有没有win32编程因为打印变量调试程序而头疼呢.方法二的函数完全类似printf.非常完美.方法一:不带参数输出如printf("hello world"); OutputDeb ...
- .net 代码调用cmd执行.exe程序,获取控制台输出信息
使用.net core 对老项目升级, .net core 使用TripleDES.Create() 加密众iv字节限制 与 framework中的不同, 新项目还需要兼容老项目版本,还不想通过web ...
- C#使用cmd运行命令并返回控制台输出信息
public static string RunCmd(string cmd){ cmd = cmd.Trim().TrimEnd('&') + "&exit";/ ...
- C语言使用cmd命令并获取输出方法
转自http://blog.csdn.net/hxh129/article/details/8000205 C语言使用cmd命令并获取输出方法 在实践中,我们有时候需要用C语言来调用cmd的命令,并得 ...
- 老李推荐:第5章5节《MonkeyRunner源码剖析》Monkey原理分析-启动运行: 获取系统服务引用
老李推荐:第5章5节<MonkeyRunner源码剖析>Monkey原理分析-启动运行: 获取系统服务引用 上一节我们描述了monkey的命令处理入口函数run是如何调用optionP ...
- 从BIRT报表文件中获取页面设置信息(页边距、纸张大小、输出方向)的方法
从BIRT报表文件中获取页面设置信息(页边距.纸张大小.输出方向)的方法 报表打印时,尤其是套打的报表,页面设置信息非常重要,比如页边距,纸张大小,输出方向等,而且每个报表的相关参数有可能不同 ...
- java执行cmd命令并获取输出结果
1.java执行cmd命令并获取输出结果 import java.io.BufferedReader; import java.io.InputStreamReader; import org.apa ...
随机推荐
- Flowplayer-一款免费的WEB视频播放器(转)
Flowplayer 是一个开源(GPL 3的)WEB视频播放器.您可以将该播放器嵌入您的网页中,如果您是开发人员,您还可以自由定制和配置播放器相关参数以达到您要的播放效果.本文主要介绍Flowpla ...
- 使用JavaScript 和 CSS 实现图像缩放和剪裁(转)
英文原文:Scale and Crop an Image using Javascript and CSS 在页面上需要裁减和缩放一张图片是一个常见问题.缩放图片比较简单的方法是使用image的hig ...
- JavaScript处理JSON
一.什么是JSON? JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式.易于人阅读和编写.同时也易于机器解析和生成.它基于JavaScript(Standa ...
- 【BZOJ】1653: [Usaco2006 Feb]Backward Digit Sums(暴力)
http://www.lydsy.com/JudgeOnline/problem.php?id=1653 看了题解才会的..T_T 我们直接枚举每一种情况(这里用next_permutation,全排 ...
- js post
在进行html5页面的设计时,希望用户加载完成页面后,进行交互时只改变其中的某些元素的内容,这样更像本地APP的呈现效果,但是HTML中的post.get如果使用submit进行提交的话会直接使用返回 ...
- VC++ 创建自己的头文件包含GUID
Guidgen 是比较好用的工具之一,可以使用它来创建ActiveX控件的UUID,同时可以创建独特的剪贴板格式名称和唯一的标识符的内核对象, 如信号量.互斥和事件. 但我需要为另一个目的创建一个唯 ...
- 状态栏,ActionBar,工具栏高度调整
1.在属性中可以这样设置更改ActionBar的高度android:layout_marginTop="?android:attr/actionBarSize" Rect fram ...
- IOS7开发~新UI学起(一)
本文转载至:http://blog.csdn.net/lizhongfu2013/article/details/9124893 IOS7在UI方面发生了很大改变,所以感觉有必要重新审视的学习一下(新 ...
- fopen与读写的标识r,r+,rb+,rt+,w+.....
FILE * fopen(const char * path,const char * mode); 参数mode字符串则代表着流形态. mode有下列几种形态字符串: r 打开只读文件,该文件必须存 ...
- c#基础 第二讲
判断一个人的体重是否为标准体重 计算公式:男生:体重(kg)-身高+100=±3(在此范围内为标准体重) 女生:体重(kg)-身高+110=±3 using System; using System. ...