解剖SQLSERVER 第十五篇 SQLSERVER存储过程的源文本存放在哪里?(译)

解剖SQLSERVER 第十五篇  SQLSERVER存储过程的源文本存放在哪里?(译)

http://improve.dk/where-does-sql-server-store-the-source-for-stored-procedures/

目前我正在扩展OrcaMDF Studio的功能 不单只支持系统表,DMVs 和用户表 而且也要支持存储过程。那很容易,我们只需要查询sys.procedures --或者查询sys.sysschobjs,

因为当SQLSERVER没有在运行的时候我们是不能查询sys.procedures 的

然而,我不想只是列出存储过程名称,我也需要显示存储过程里面的源代码。这带来了新的任务--检索源代码。源代码存储在哪里?

我在Google上找不到任何有用的资料,所以我们只能依靠自己观察了!

我已经创建了一个新的空数据库 这个数据库有一个3MB的数据文件。在这个数据库里面,我已经创建了一个单独的存储过程就像这样:

SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
-- =============================================
-- Author:
-- Create date:
-- Description:
-- =============================================
CREATE PROCEDURE XYZ
    AS
BEGIN
    -- SET NOCOUNT ON added to prevent extra result sets from
    -- interfering with SELECT statements.
    SET NOCOUNT ON;

    -- Insert statements for procedure here
    SELECT ‘AABBCC‘ AS Output
END

现在,当我select * from sys.procedures的时候,我们可以看到存储过程的object ID 是2105058535

select * from sys.procedures

到目前为止一切顺利。然后我们可以检索存储过程的定义 使用查询sys.sql_modules 视图返回nvarchar(MAX)类型的定义文本

select * from sys.sql_modules where object_id = 2105058535

上面就是XYZ存储过程的源代码!等下,我可以从sys.sysschobjs表里获取存储过程的object ID,我不需要访问
sys.sql_modules ,sys.sql_modules 只是一个视图而不是系统表。我们看一下sys.sql_modules 视图是如何获取定义的:

select object_definition(object_id(‘sys.sql_modules‘))
SELECT
    object_id = o.id,
    definition = Object_definition(o.id),
    uses_ansi_nulls = Sysconv(bit, o.status & 0x40000), -- OBJMOD_ANSINULLS
    uses_quoted_identifier = sysconv(bit, o.status & 0x80000),   -- OBJMOD_QUOTEDIDENT
    is_schema_bound = sysconv(bit, o.status & 0x20000),    -- OBJMOD_SCHEMABOUND
    uses_database_collation = sysconv(bit, o.status & 0x100000),  -- OBJMOD_USESDBCOLL
    is_recompiled = sysconv(bit, o.status & 0x400000),     -- OBJMOD_NOCACHE
    null_on_null_input = sysconv(bit, o.status & 0x200000),   -- OBJMOD_NULLONNULL
    execute_as_principal_id = x.indepid
FROM
    sys.sysschobjs o
LEFT JOIN
    sys.syssingleobjrefs x ON x.depid = o.id AND x.class = 22 AND x.depsubid = 0 -- SRC_OBJEXECASOWNER
WHERE
    o.pclass <> 100 AND
    (
        (o.type = ‘TR‘ AND has_access(‘TR‘, o.id, o.pid, o.nsclass) = 1) OR
        (type IN (‘P‘,‘V‘,‘FN‘,‘IF‘,‘TF‘,‘RF‘,‘IS‘) AND has_access(‘CO‘, o.id) = 1) OR
        (type IN (‘R‘,‘D‘) AND o.pid = 0)
    )

大家如果使用sqlprompt的话也可以直接显示定义而不需要执行object_definition函数

可以看到sys.sql_modules 视图也是使用系统函数object_definition 来获取代码
不幸的是,下面的代码无法工作

select object_definition(object_id(‘object_definition‘))

我碰巧记得有一个废弃的视图可以代替sys.sql_modules,sys.syscomments 视图
我们看一下获取到的代码

select object_definition(object_id(‘sys.syscomments‘))
SELECT
    o.id AS id,
    convert(smallint, case when o.type in (‘P‘, ‘RF‘) then 1 else 0 end) AS number,
    s.colid,
    s.status,
    convert(varbinary(8000), s.text) AS ctext,
    convert(smallint, 2 + 4 * (s.status & 1)) AS texttype,
    convert(smallint, 0) AS language,
    sysconv(bit, s.status & 1) AS encrypted,
    sysconv(bit, 0) AS compressed,
    s.text
FROM
    sys.sysschobjs o
CROSS APPLY
    OpenRowset(TABLE SQLSRC, o.id, 0) s
WHERE
    o.nsclass = 0 AND
    o.pclass = 1 AND
    o.type IN (‘C‘,‘D‘,‘P‘,‘R‘,‘V‘,‘X‘,‘FN‘,‘IF‘,‘TF‘,‘RF‘,‘IS‘,‘TR‘) AND
    has_access(‘CO‘, o.id) = 1  

UNION ALL  

SELECT
    c.object_id AS id,
    convert(smallint, c.column_id) AS number,
    s.colid,
    s.status,
    convert(varbinary(8000), s.text) AS ctext,
    convert(smallint, 2 + 4 * (s.status & 1)) AS texttype,
    convert(smallint, 0) AS language,
    sysconv(bit, s.status & 1) AS encrypted,
    sysconv(bit, 0) AS compressed,
    s.text
FROM
    sys.computed_columns c
CROSS APPLY
    OpenRowset(TABLE SQLSRC, c.object_id, c.column_id) s  

UNION ALL  

SELECT
    p.object_id AS id,
    convert(smallint, p.procedure_number) AS number,
    s.colid,
    s.status,
    convert(varbinary(8000), s.text) AS ctext,
    convert(smallint, 2 + 4 * (s.status & 1)) AS texttype,
    convert(smallint, 0) AS language,
    sysconv(bit, s.status & 1) AS encrypted,
    sysconv(bit, 0) AS compressed,
    s.text
FROM
    sys.numbered_procedures p
CROSS APPLY
    OpenRowset(TABLE SQLSRC, p.object_id, p.procedure_number) s  

UNION ALL  

SELECT
    o.id AS id,
    convert(smallint, case when o.type in (‘P‘, ‘RF‘) then 1 else 0 end) AS number,
    s.colid,
    s.status,
    convert(varbinary(8000), s.text) AS ctext,
    convert(smallint, 2) AS texttype,
    convert(smallint, 0) AS language,
    sysconv(bit, 0) AS encrypted,
    sysconv(bit, 0) AS compressed,
    s.text
FROM
    sys.sysobjrdb o
CROSS APPLY
    OpenRowset(TABLE SQLSRC, o.id, 0) s
WHERE
    db_id() = 1 AND
    o.type IN (‘P‘,‘V‘,‘X‘,‘FN‘,‘IF‘,‘TF‘)

很令人失望,他不使用object_definition, 而是使用另一个内部函数格式是OpenRowset(TABLE SQLSRC, o.id, 0)。我不会轻易放弃 --我对 OpenRowset(TABLE RSCPROP)函数进行逆向

让我们使用不同的方法去解决这个问题。在SQLSERVER里面任何东西的存储都使用8KB页面的固定格式。当存储过程不是加密的,他们一定以明文存储在数据库的某个地方--只是我们不知道在哪个地方。

我们分离数据库并使用hex编辑器进行破解(我推荐使用HxD这个hex编辑器)

HxD hex编辑器下载:

http://files.cnblogs.com/lyhabc/HxDhex%E7%BC%96%E8%BE%91%E5%99%A8.rar

我们为了要找到存储过程的位置,我在存储过程里故意使用“SELECT ‘AABBCC’ 这个字符串
以便于我们能够容易的找到存储过程的所在位置:

我们找到了:

好了,我们现在代码是存储在数据库里面。数据存储在偏移位置为0x00101AF0 的数据文件里。十进制值是01055472。我们知道数据页面是8KB,我们可以计算代码所在的页面编号

01055472 / 8192 = 128

现在我们知道代码存储在页面号128页上 --我们重新附加数据库,使用DBCC PAGE看一下页面内容:

--只显示数据页面头
DBCC TRACEON (3604)
GO
DBCC PAGE(Test2, 1, 128, 0)
GO

注意,对于DBCC PAGE 命令我使用了页面样式0作为执行。在这里我只想查看数据页面头--那里会有一些有趣的东西

正如所料,这是一个正常的数据页面,m_type 字段显示的值为1(type id为1表示这是数据库内部的数据页面)
更有趣的是,我们可以看到页面属于object ID 60!我们看一下object ID 60是什么对象:

select * from sys.sysobjects where id = 60

让我们看看sys.sysobjvalues的内容。注意,当你查询sys.sysobjvalues视图的时候,需要使用DAC连接,可以看到他实际上是一个内部的系统表:

select * from sys.sysobjvalues

这里显示的很多内容我们都不需要关心,不过我们需要尝试过滤出我们的存储过程object ID为2105058535的信息:

select * from sys.sysobjvalues where objid = 2105058535

我想知道imageval 列包含了什么内容,如果我没有记错 0x2D2D 在ASCII里面应该是“-”
这提醒了我 XYZ这个存储过程刚开始的时候 ,我们尝试将这列的值转换为我们可读的形式

select convert(varchar(max), imageval) from sys.sysobjvalues where objid = 2105058535

亲爱的读者,这就是XYZ存储过程的源代码,他存储在sys.sysobjvalues系统表中。
作为最后一个例子,下面是不依靠object_definition()函数和sys.sql_modules视图从而检索出用户存储过程的源代码列表

select
    p.name,
    cast(v.imageval as varchar(MAX))
from
    sys.procedures p
inner join
    sys.sysobjvalues v on p.object_id = v.objid

第十五篇完

时间: 2024-10-26 18:26:43

解剖SQLSERVER 第十五篇 SQLSERVER存储过程的源文本存放在哪里?(译)的相关文章

Django 【第二十五篇】Django admin源码解析

一.admin的源码流程 首先可以确定的是:路由关系一定对应一个视图函数 a.当点击运行的时候,会先找到每一个app中的admin.py文件,并执行 b.执行urls.py admin.site是什么? admin.site,urls    返回的是一个元组,里面的第一个元素是一个列表 django-admin的源码流程 我们自己生成的动态的访问url ====================================初级版========================= from dj

解剖SQLSERVER 第十四篇 Vardecimals 存储格式揭秘(译)

原文:解剖SQLSERVER 第十四篇 Vardecimals 存储格式揭秘(译) 解剖SQLSERVER 第十四篇    Vardecimals 存储格式揭秘(译) http://improve.dk/how-are-vardecimals-stored/ 在这篇文章,我将深入研究vardecimals 是怎麽存储在磁盘上的. 作为一般的介绍vardecimals 是怎样的,什么时候应该使用,怎样使用,参考这篇文章 vardecimal 存储格式启用了吗? 首先,我们需要看一下vardecim

解剖SQLSERVER 第十六篇 OrcaMDF RawDatabase --MDF文件的瑞士军刀(译)

解剖SQLSERVER 第十六篇 OrcaMDF RawDatabase --MDF文件的瑞士军刀(译) http://improve.dk/orcamdf-rawdatabase-a-swiss-army-knife-for-mdf-files/ 当我最初开始开发OrcaMDF的时候我只有一个目标,比市面上大部分的书要获取MDF文件内部的更深层次的知识 随着时间的推移,OrcaMDF确实做到了.在我当初没有计划的时候,OrcaMDF 已经可以解析系统表,元数据,甚至DMVs.我还做了一个简单U

解剖SQLSERVER 第十二篇 OrcaMDF 行压缩支持(译)

解剖SQLSERVER 第十二篇   OrcaMDF 行压缩支持(译) http://improve.dk/orcamdf-row-compression-support/ 在这两个月的断断续续的开发工作中,我终于将OrcaMDF 压缩功能分支合并到主分支这意味着OrcaMDF 现在正式支持数据行压缩功能 支持的数据类型实现行压缩需要我修改几乎所有已实现的数据类型以将他们作为压缩存储.integer类型被压缩了,decimal类型变成可变长度,而可变长度类型基本上都被截断了进而用0来填补.所有先

秒杀多线程第十五篇 关键段,事件,互斥量,信号量的“遗弃”问题

版权声明:本文为博主原创文章,未经博主允许不得转载. 目录(?)[+] 秒杀多线程第十五篇 关键段,事件,互斥量,信号量的“遗弃”问题 在<秒杀多线程第九篇 经典线程同步总结 关键段 事件 互斥量 信号量>中对经典多线程同步互斥问题进行了回顾和总结,这篇文章对Windows系统下常用的线程同步互斥机制——关键段.事件.互斥量.信号量进行了总结.有网友问到互斥量能处理“遗弃”问题,事件和信号量是否也能处理“遗弃”问题.因此本文将对事件和信号量作个试验,看看事件和信号量能否处理“遗弃”问题. 一.

Python之路【第十五篇】:Web框架

Python之路[第十五篇]:Web框架 Web框架本质 众所周知,对于所有的Web应用,本质上其实就是一个socket服务端,用户的浏览器其实就是一个socket客户端. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 #!/usr/bin/env python #coding:utf-8   import socket   def handle_request(client):     buf = client.recv(10

第十五篇 Integration Services:SSIS参数

本篇文章是Integration Services系列的第十五篇,详细内容请参考原文. 简介在前一篇,我们使用SSDT-BI将第一个SSIS项目My_First_SSIS_Project升级/转换到SSIS 2012.在这一篇,我们将探讨SSIS变量的姊妹:SSIS参数.我们将展示参数配置,通过包参数管理动态属性值,以及在SSIS包执行期间参数是如何配置和使用的.首先在SSDT-BI打开转换过的My_First_SSIS_Project,如图15.1所示:图15.1My_First_SSIS_P

第十五篇 和谐

第十五篇  和谐 "和谐"对于整个宇宙来讲至关重要,无论是宇宙自身空间的环境还是万物之间都需要和谐.如果在任何方面或任何领域出现不和谐的因素,就会对宇宙本身及宇宙中的万物带来很大的影响.这种影响大可以使宇宙规律出现混乱,小也会造成宇宙空间中的万物出现变异. 以上讲的这些是针对整个大宇宙背景所作出的描述.从这些真相当中我们可以知道人类世界同样也需要和谐.因为不和谐,我们就无法向上发展.如今人类世界就有很多的空间出现不和谐的因素,这些不和谐的因素一直障碍着整个人类世界的发展.这样的状况,只

NHibernate 过滤器(第十五篇)

NHibernate 过滤器(第十五篇) NHibernate过滤器相当于定义一个非常类似于类和集合上使用的where子句.ISession 中默认是不启用过滤器的,必须通过ISession.EnableFilter()方法显式的启用. 该方法返回被启用的IFilter的实例.这也支持链式操作. 过滤器主要的配置都在映射文件内完成.来看示例: <?xml version="1.0" encoding="utf-8" ?> <hibernate-ma