sql存储过程的解决方法

php中文网
发布: 2016-06-07 17:48:18
原创
1248人浏览过

1、并没有删除原存储重建,仅仅在控制台做了一个输出,拷贝出来很不方便。
2、对于长度大点的加密数据会解密失败。
带着这两个问题来改造此存储过程。

先做准备工作,首先需要知道DAC这么个东西, 指的是专用管理员连接,为管理员提供的一种特殊的诊断连接。
知道了后得先打开它,以SQL2008为例:
右击“对象浏览器”,找到“Facets”,点击,如图:
 
找到“Sruface Area Configuration”,选择“RemoteDacEnabled”,设为True:


然后进行DAC登录,CMD模式下敲如下命令,不清楚原理的可以自行研究:
sqlcmd -A -S 192.168.1.101 -U sa -P 123456 
命令提示行下打开需处理的数据库:
>USE TEST
>GO

准备就绪,复制搜索得到的存储过程(这里有些语法问题,做些小调整即可),生成解密存储程,然后我们准备两个加密后的存储过程,其中一个长度较大(可自行循环创建一个500行的存储程,本文不再提供),验证得出结论,短小的存储过程很快即解密成功,并输出,但长度较大的却解密失败。
接下来看看其如何解密的:
先看这句
@maxColID = max(subobjid),@intEncrypted = imageval FROM sys.sysobjvalues WHERE objid = object_id(@procedure)
指的是加密后的数据存放在“sys.sysobjvalues”表中,其内容存放于“imageval”字段。

知道了加密后的数据,就得进行解密,它定义了4个关键字段:
DECLARE @real_01 nvarchar(max)
DECLARE @fake_01 nvarchar(max)
DECLARE @fake_encrypt_01 nvarchar(max)
DECLARE @real_decrypt_01 nvarchar(max)
分别指的原始加密数据内容、原始加密存储过程的CREATE语句、自己构造的假的存储过程加密后的数据、最终解密后的存储过程。
其方法是按位将@real_01、@fake_encrypt_01、@real_decrypt_01进行异或运算,此处为何如此处理,原理不明!!!
WHILE @intProcSpace BEGIN
--xor real & fake & fake encrypted
SET @real_decrypt_01 = stuff(@real_decrypt_01, @intProcSpace, 1, NCHAR(UNICODE(substring(@real_01, @intProcSpace, 1)) ^ (UNICODE(substring(@fake_01, @intProcSpace, 1)) ^UNICODE(substring(@fake_encrypt_01, @intProcSpace, 1)))))
SET @intProcSpace=@intProcSpace+1
END
实际上到此为止,加密后的存储过程已解密出来了。

其下面还有一大段语句没有仔细研究,但基本上是利用sp_helptext将内容输出,方法比较繁索,而且没有达到我们要的效果,我们将换一种方法进行输出。
基本上就这么简单,除了原理不清楚外,基本上已达到要求,接下来要解决开始提出的两个问题。
首先是长度问题,为什么长度一大就解密失败,来看看@real_decrypt_01的定义并进行初始化@real_decrypt_01的语句:
DECLARE @real_decrypt_01 nvarchar(max)
SET @real_decrypt_01 = replicate(N'A', (datalength(@real_01) /2 ))
乍一看没什么问题,但我们使用LEN(@real_decrypt_01)输出看看,最大输出长度为4000,可能问题就出现NVARCHAR的长度上了,理论上NVARCHAR(MAX)支持2G的大小。为什么会出现这种情况没有研究过,但有人给出了解决方法,进行显示转换:
SET @real_decrypt_01 = replicate(CONVERT(NVARCHAR(MAX), N'A'), (datalength(@real_01) /2 ))
其它的几还有几处也是该原因,改正后进行重新运行,问题解决,长度较大的存储过程也解密成功。

第一个问题解决了,如何能方便的输出呢,试验了删除重建,但未成功,那么就用最简单的方法吧,利用xp_cmdshell将内容输出到文本。
先建立一个物理表,用于存储解密后的数据:

<p>create table [dbo].[sql_decode](<br />    [id] [int] identity(1,1) not null,<br />    [sqltext] [nvarchar](max) not null,<br /> constraint [id] primary key clustered <br />(<br />    [id] asc<br />)<br />) on [primary]<br /><br />go</p>
登录后复制


然后建立一个存储过程,遍历所有加密过的存储过程,调用解密存储过程进行解密,解密后输出:

<p>CREATE PROCEDURE [dbo].[DECODE_DATABASE]<br />AS<br />SET NOCOUNT ON<br />BEGIN<br /><br />    DECLARE @PROC_NAME VARCHAR(256)<br />    SET @PROC_NAME = ''<br />    DECLARE @ROWS INT<br />    DECLARE @TEMP TABLE(<br />        NAME VARCHAR(256)<br />    )<br />    INSERT INTO @TEMP SELECT NAME FROM sysobjects WHERE TYPE = 'P' <br />    AND NAME NOT IN (<br />        'DECODE_DATABASE', 'DECODE_PROC'<br />    )<br />    SET @ROWS = @@ROWCOUNT<br />    WHILE @ROWS > 0<br />    BEGIN<br />        SELECT @PROC_NAME = NAME FROM (<br />            SELECT ROW_NUMBER() OVER (ORDER by NAME) AS ROW, NAME FROM @TEMP <br />        ) T <br />        WHERE ROW = @ROWS<br />        EXEC [DECODE_PROC] @PROC_NAME<br />        PRINT @PROC_NAME<br />        SET @ROWS = @ROWS - 1<br />    END<br />    <br />    RETURN<br />    <br />    EXEC master..xp_cmdshell 'bcp "SELECT [SQLTEXT] FROM TEST.dbo.[SQL_DECODE]" queryout C:decode.txt -c -T -S PC2011043012JUJ'<br />END<br /><br /><br />GO</p>
登录后复制


最后是改造后的存储过程:

<p>CREATE PROCEDURE [dbo].[DECODE_PROC](<br />    @PROC_NAME SYSNAME = NULL<br />)<br />AS<br />SET NOCOUNT ON<br /><br />DECLARE @PROC_NAME_LEN INT    --存储过程名长度<br />DECLARE @MAX_COL_ID SMALLINT    --最大列ID<br />SELECT @MAX_COL_ID = MAX(subobjid) FROM sys.sysobjvalues WHERE objid = OBJECT_ID(@PROC_NAME) GROUP BY imageval<br /><br />SELECT @PROC_NAME_LEN = DATALENGTH(@PROC_NAME) + 29<br />DECLARE @REAL_01 NVARCHAR(MAX)    --真实加密存储过程数据<br />DECLARE @FACK_01 NVARCHAR(MAX)    --修改为假的存储过程,长度(40003 - 存在过程名长度),原理不明?<br />DECLARE @FACK_ENCRYPT_01 NVARCHAR(MAX)    --伪加密存储过街程数据<br />DECLARE @REAL_DECRYPT_01 NVARCHAR(MAX)    --最终解密后的数据,初始化为原始加密长度的一半的&ldquo;A&rdquo;,原理不明?<br /><br />SET @REAL_01 = (<br />    SELECT imageval FROM sys.sysobjvalues WHERE objid = object_id(@PROC_NAME) AND valclass = 1 AND subobjid = 1<br />)<br /><br />DECLARE @REAL_DATA_LEN BIGINT<br />SET @REAL_DATA_LEN = DATALENGTH(@REAL_01)<br />--PRINT @REAL_DATA_LEN<br /><br />DECLARE @FACK_LEN BIGINT<br />SET @FACK_LEN = @REAL_DATA_LEN * 10    --改造:假的长度在原真实数据长度上放大10倍<br /><br />--此处需将NVARCHAR显示转换成NVARCHAR(MAX),不然将只能产生4K长度<br />SET @FACK_01 = 'ALTER PROCEDURE ' + @PROC_NAME + ' WITH ENCRYPTION AS ' + REPLICATE(CONVERT(NVARCHAR(MAX), '-'), @FACK_LEN - @PROC_NAME_LEN)<br />--PRINT '@FACK_01 = ' + STR(LEN(@FACK_01))<br />EXECUTE (@FACK_01)<br />SET @FACK_ENCRYPT_01 = (<br />    SELECT imageval FROM sys.sysobjvalues WHERE objid = object_id(@PROC_NAME) AND valclass = 1 AND subobjid = 1<br />)<br /><br />SET @FACK_01 = 'CREATE PROCEDURE ' + @PROC_NAME + ' WITH ENCRYPTION AS ' + REPLICATE(CONVERT(VARCHAR(MAX), '-'), @FACK_LEN - @PROC_NAME_LEN)<br />SET @REAL_DECRYPT_01 = REPLICATE(CONVERT(NVARCHAR(MAX), N'A'), (DATALENGTH(@REAL_01) /2))<br />--PRINT 'LEN(@REAL_DECRYPT_01) = ' + STR(LEN(@REAL_DECRYPT_01))<br /><br /><br />--按位对 @REAL_01、 @FACK_01、 @REAL_DECRYPT_01 进行异或操作。<br />DECLARE @INT_PROC_SPACE BIGINT<br />SET @INT_PROC_SPACE = 1<br />WHILE @INT_PROC_SPACE <= (DATALENGTH(@REAL_01) /2 )<br />BEGIN<br />    SET @REAL_DECRYPT_01 = STUFF(<br />        @REAL_DECRYPT_01, <br />        @INT_PROC_SPACE, <br />        1, <br />        NCHAR(UNICODE(SUBSTRING(@REAL_01, @INT_PROC_SPACE, 1)) ^ (UNICODE(SUBSTRING(@FACK_01, @INT_PROC_SPACE, 1)) ^ UNICODE(SUBSTRING(@FACK_ENCRYPT_01, @INT_PROC_SPACE, 1))))<br />    )<br />    SET @INT_PROC_SPACE = @INT_PROC_SPACE + 1<br />END<br /><br />--移除WITH ENCRYPTION<br />SET @REAL_DECRYPT_01 = REPLACE(@REAL_DECRYPT_01, 'WITH ENCRYPTION', '')<br />INSERT INTO [SQL_DECODE] VALUES (@REAL_DECRYPT_01)<br /><br />--PRINT '@REAL_DECRYPT_01 = ' + @REAL_DECRYPT_01<br />--PRINT 'LEN(@REAL_DECRYPT_01) = ' + STR(LEN(@REAL_DECRYPT_01))<br /><br />--删除原存储过程<br />SET @FACK_01 = 'DROP PROCEDURE ' + @PROC_NAME<br />EXEC(@FACK_01)<br /><br />GO</p>
登录后复制


至此,解密全过程大功告成,命令行模式下运行:
>EXEC [DECODE_DATABASE]
>GO
在C盘根目录下,解密后的存储过程文本生成成功。
运行前别忘记打开xp_cmdshell使用权限,同打开DAC一样:


或者命令行模式下敲如下命令:
>sp_configure 'show advanced options',1
>reconfigure
>go
>sp_configure 'xp_cmdshell',1
>reconfigure
>go

最佳 Windows 性能的顶级免费优化软件
最佳 Windows 性能的顶级免费优化软件

每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。

下载
来源:php中文网
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
最新问题
开源免费商场系统广告
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板
关于我们 免责申明 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送
PHP中文网APP
随时随地碎片化学习
PHP中文网抖音号
发现有趣的

Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号