在本文中,将探讨如何利用基础的汇编语言知识来获取MySQL服务器软件在运行时的有趣信息。不久前,一个朋友参与了一个使用PHP和MySQL的网站开发项目,他遇到了一些问题。可以从这里开始。
首先,需要下载并安装MySQL的任何版本。请确保MySQLD服务正在成功运行(换句话说,确保MySQL能够正常工作)。
从微软网站下载最新版本的Windbg for Windows。启动Windbg。
按下F6键,附加到mysqld.exe进程。
通过使用File->Symbols File Path设置Windbg符号路径:
srv*c:\windows*http://msdl.microsoft.com/download/symbols
在Windbg命令行上执行.reload
命令。
按下F5键运行进程(当附加到进程时,它会冻结)。使用F5或G命令,进程将运行。
MYSQLD.exe进程(或服务)负责执行来自PHP页面或不同MySQL客户端的SQL查询。Navicat是一个很棒的MySQL客户端,它允许以图形模式查看MYSQL服务器,就像Microsoft Management Studio与SQL Server一样。
出于教育目的,让开始使用Navicat工具(如果愿意),或者使用自己的PHP或其他任何MySQL客户端。
在Windbg中,通过CTRL+Break停止当前MYSQLD执行,并输入以下命令来设置断点:
bm *mysqld*!*execute*
(BM=在库*mysqld*和函数*execute*上设置断点)。
按下F5键并使用PHP页面或Navicat或其他任何MYSQL客户端执行任何客户端操作。
将看到页面或Navicat冻结:为什么?因为MYSQLD被停止了。让看看Windbg。
使用KB命令查看堆栈跟踪。
在Args to Child部分,可以直接观察到MYSQL_EXECUTE_COMMAND的输入参数。那里的每个十六进制值通常代表指向任何特定数据结构的指针。Args to Child指针中有任何字符串吗?让检查一下。
点击View->Memory。在Address中,输入指针(从Args to child捕获)尝试使用01eb2630和其他args to child:
没有在MYSQL_EXECUTE_COMMAND的所有args to child参数中看到任何有趣的东西,但是之前的函数mysql_parse呢?如果在那里打印值会怎样?让执行:
.printf “%ma”.03b62a68
是的,这绝对是从MYSQLD进程捕获的SQL查询。现在有了想要的函数,使用命令BC *
删除所有断点,并使用bp mysqld!mysql_parse
继续执行,使用F5或G windbg命令行。
现在windbg停在mysqld!mysql_parse上。一个百万问题:每次任何MYSQL查询执行时,它会冻结应用程序直到按下F5吗?答案是不,如果使用更智能的断点。知道函数mysql_parse,但它存储在哪个内存地址?这是一个调用栈理论:
让解释一下,当进程开始一个函数时,它会将函数参数推入栈中。那么ESP处理器寄存器会发生什么?例如:
VOID SUM(INT X,INT *Y)
ESP代表栈的顶部,EBP是栈的基地址。假设ESP=1000。进程将Y值的指针推入,ESP的值减少,减少了栈的顶部?听起来很混乱,是的,这是真的,在Windows操作系统中,栈的顶部位于内存的较低部分,比EBP(栈的基指针)低。
完整的断点命令:
bp mysqld!mysql_parse ".printf \"\\n%ma\",poi(esp+8);gc"