SQL Server存储过程文本加密与解密过程详解 2019版可用

SQL Server存储过程加密与解密过程详解

加密概述

SQL Server的存储过程支持对其创建脚本的加密,即即便是数据库管理员也无法查看其脚本内容。本文即介绍一种方法对存储过程的加密和解密。

加密实例

加密存储过程

创建示例加密存储过程见下(即加了WITH ENCRYPTION选项,脚本内容不可见):

Create PROCEDURE usp_inlight
WITH ENCRYPTION
AS
BEGIN
	print 'Can not see me! 1 '
	print 'Can not see me! 2 '
	print 'Can not see me! 3 '
	print 'Can not see me! 4'
	print 'Can not see me! 5'
	print 'Can not see me! 6'
END   

验证加密

此时我们通过SQL Server Management Studio(SSMS)SQL Server图形化管理工具查看该存储过程时无法查看脚本内容,无法点击“修改”按钮。

1)修改按钮灰色

2)查看存储过程脚本

解密

解密需要SQL在专用管理员连接(Dedicated Admin Connection)DAC下运行,首先我们需要打开远程连接。

指定远程连接DAC

指定连接允许远程连接 DAC的模式,其中0是本地、1是可以远程。

SP_CONFIGURE  'remote admin connections';
SP_CONFIGURE 'remote admin connections', 1;
GO
RECONFIGURE WITH OVERRIDE;
GO

SSMS连接DAC

不奏效方法:

SSMS连接DAC时不能直接通过对象连接器直接进入该模式,详见如下演示步骤:

正确方法:

SSMS里正确连接DAC的方法,是先通过普通方式连接进去数据库,新建立个查询,然后在空白处右键“更改连接”,输入DAC模式的连接地址和用户登录信息。

验证DAC连接

在SSMS里执行如下查询,查看DAC连接会话信息。

select 
@@SPID spid,
CASE
WHEN es.session_id= @@SPID THEN 'you '
ELSE es.host_name
END AS DAC_runner,
es.original_login_name,
es.session_id,
es.login_time,
es.status
from sys.endpoints as ep
join sys.dm_exec_sessions es on
ep.endpoint_id=es.endpoint_id
where ep.name='Dedicated Admin Connection'

 

创建解密存储过程 

USE [ShenLiang2025]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER OFF
GO

CREATE PROCEDURE [dbo].[usp_decrypt] 
(@procedure  varchar(100)) 
AS 
SET NOCOUNT ON 
DECLARE @intProcSpace bigint, @t bigint, @maxColID smallint,@procNameLength int 
select @maxColID = max(subobjid) FROM 
sys.sysobjvalues WHERE objid = object_id(@procedure) 
--select @maxColID as 'Rows in sys.sysobjvalues' 
select @procNameLength = datalength(@procedure) + 29 
DECLARE @real_01 nvarchar(max) 
DECLARE @fake_01 nvarchar(max) 
DECLARE @fake_encrypt_01 nvarchar(max) 
DECLARE @real_decrypt_01 nvarchar(max),@real_decrypt_01a nvarchar(max) 
declare @objtype varchar(2),@parentname nvarchar(max) 
select @real_decrypt_01a = '' 
--提取对象的类型如是存储过程还是函数,如果是触发器,还要得到其父对象的名称 
select @objtype=type,@parentname=object_name(parent_object_id) 
from sys.objects where [object_id]=object_id(@procedure) 
-- 从sys.sysobjvalues里提出加密的imageval记录 
SET @real_01=(SELECT top 1 imageval FROM sys.sysobjvalues WHERE objid = 
object_id(@procedure) and valclass = 1 order by subobjid) 
--创建一个临时表 
create table #output ( [ident] [int] IDENTITY (1, 1) NOT NULL , 
[real_decrypt] NVARCHAR(MAX) ) 
--开始一个事务,稍后回滚 
BEGIN TRAN 
--更改原始的存储过程,用短横线替换 
if @objtype='P' 
  SET @fake_01='ALTER PROCEDURE '+ @procedure +' WITH ENCRYPTION AS 
  '+REPLICATE(cast('-'as nvarchar(max)), datalength(@real_01) /2 - @procNameLength) 
else if @objtype='FN' 
  SET @fake_01='ALTER FUNCTION '+ @procedure +'() RETURNS INT WITH ENCRYPTION AS BEGIN RETURN 1 
  /*'+REPLICATE(cast('*'as nvarchar(max)), datalength(@real_01) /2 - @procNameLength)+'*/ END' 
else if @objtype='V' 
  SET @fake_01='ALTER view '+ @procedure +' WITH ENCRYPTION AS select 1 as col 
  /*'+REPLICATE(cast('*'as nvarchar(max)), datalength(@real_01) /2 - @procNameLength)+'*/' 
else if @objtype='TR' 
  SET @fake_01='ALTER trigger '+ @procedure +' ON '+@parentname+'WITHENCRYPTION AFTER INSERT AS RAISERROR (''N'',16,10) 
  /*'+REPLICATE(cast('*'as nvarchar(max)), datalength(@real_01) /2 - @procNameLength)+'*/' 
EXECUTE (@fake_01) 
--从sys.sysobjvalues里提出加密的假的 
SET @fake_encrypt_01=(SELECT top 1 imageval FROM sys.sysobjvalues WHERE objid = 
object_id(@procedure) and valclass = 1 order by subobjid ) 
if @objtype='P' 
  SET @fake_01='Create PROCEDURE '+ @procedure +' WITH ENCRYPTION AS 
  '+REPLICATE(cast('-'as nvarchar(max)), datalength(@real_01) /2 - @procNameLength) 
else if @objtype='FN' 
  SET @fake_01='CREATE FUNCTION '+ @procedure +'() RETURNS INT WITH ENCRYPTION AS BEGIN RETURN 1 
  /*'+REPLICATE(cast('*'as nvarchar(max)), datalength(@real_01) /2 - @procNameLength)+'*/ END' 
else if @objtype='V' 
  SET @fake_01='Create view '+ @procedure +' WITH ENCRYPTION AS select 1 as col 
  /*'+REPLICATE(cast('*'as nvarchar(max)), datalength(@real_01) /2 - @procNameLength)+'*/' 
else if @objtype='TR' 
  SET @fake_01='Create trigger '+ @procedure +' ON '+@parentname+'WITHENCRYPTION AFTER INSERT AS RAISERROR (''N'',16,10) 
  /*'+REPLICATE(cast('*'as nvarchar(max)), datalength(@real_01) /2 - @procNameLength)+'*/' 
--开始计数 
SET @intProcSpace=1 
--使用字符填充临时变量 
SET @real_decrypt_01 = replicate(cast('A'as nvarchar(max)), (datalength(@real_01) /2 )) 
--循环设置每一个变量,创建真正的变量 
--每次一个字节 
SET @intProcSpace=1 
--如有必要,遍历每个@real_xx变量并解密 
WHILE @intProcSpace <=(datalength(@real_01)/2) 
BEGIN 
--真的和假的和加密的假的进行异或处理 
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逻辑向表#output里插入变量 
insert #output (real_decrypt) select @real_decrypt_01 
-- select real_decrypt AS '#output chek' from #output --测试 
-- ------------------------------------- 
--开始从sp_helptext提取 
-- ------------------------------------- 
declare @dbname sysname 
,@BlankSpaceAdded int 
,@BasePos int 
,@CurrentPos int 
,@TextLength int 
,@LineId int 
,@AddOnLen int 
,@LFCR int --回车换行的长度 
,@DefinedLength int 
,@SyscomText nvarchar(max) 
,@Line nvarchar(4000) 
Select @DefinedLength = 4000 
SELECT @BlankSpaceAdded = 0 --跟踪行结束的空格。注意Len函数忽略了多余的空格 
CREATE TABLE #CommentText 
(LineId int 
,Text nvarchar(4000) collate database_default) 
--使用#output代替sys.sysobjvalues 
DECLARE ms_crs_syscom CURSOR LOCAL 
FOR SELECT real_decrypt from #output 
ORDER BY ident 
FOR READ ONLY 
--获取文本 
SELECT @LFCR = 2 
SELECT @LineId = 1 
OPEN ms_crs_syscom 
FETCH NEXT FROM ms_crs_syscom into @SyscomText 
WHILE @@fetch_status >= 0 
BEGIN 
SELECT @BasePos = 1 
SELECT @CurrentPos = 1 
SELECT @TextLength = LEN(@SyscomText) 
WHILE @CurrentPos != 0 
BEGIN 
--通过回车查找行的结束 
SELECT @CurrentPos = CHARINDEX(char(13)+char(10), @SyscomText, 
@BasePos) 
--如果找到回车 
IF @CurrentPos != 0 
BEGIN 
--如果@Lines的长度的新值比设置的大就插入@Lines目前的内容并继续 
While (isnull(LEN(@Line),0) + @BlankSpaceAdded + 
@CurrentPos-@BasePos + @LFCR) > @DefinedLength 
BEGIN 
SELECT @AddOnLen = @DefinedLength-(isnull(LEN(@Line),0) + 
@BlankSpaceAdded) 
INSERT #CommentText VALUES 
( @LineId, 
isnull(@Line, N'') + isnull(SUBSTRING(@SyscomText, 
@BasePos, @AddOnLen), N'')) 
SELECT @Line = NULL, @LineId = @LineId + 1, 
@BasePos = @BasePos + @AddOnLen, @BlankSpaceAdded = 0 
END 
SELECT @Line = isnull(@Line, N'') + 
isnull(SUBSTRING(@SyscomText, @BasePos, @CurrentPos-@BasePos + @LFCR), N'') 
SELECT @BasePos = @CurrentPos+2 
INSERT #CommentText VALUES( @LineId, @Line ) 
SELECT @LineId = @LineId + 1 
SELECT @Line = NULL 
END 
ELSE 
--如果回车没找到 
BEGIN 
IF @BasePos <= @TextLength 
BEGIN 
--如果@Lines长度的新值大于定义的长度 
While (isnull(LEN(@Line),0) + @BlankSpaceAdded + 
@TextLength-@BasePos+1 ) > @DefinedLength 
BEGIN 
SELECT @AddOnLen = @DefinedLength - 
(isnull(LEN(@Line),0) + @BlankSpaceAdded) 
INSERT #CommentText VALUES 
( @LineId, 
isnull(@Line, N'') + isnull(SUBSTRING(@SyscomText, 
@BasePos, @AddOnLen), N'')) 
SELECT @Line = NULL, @LineId = @LineId + 1, 
@BasePos = @BasePos + @AddOnLen, @BlankSpaceAdded = 
0 
END 
SELECT @Line = isnull(@Line, N'') + 
isnull(SUBSTRING(@SyscomText, @BasePos, @TextLength-@BasePos+1 ), N'') 
if LEN(@Line) < @DefinedLength and charindex(' ', 
@SyscomText, @TextLength+1 ) > 0 
BEGIN 
SELECT @Line = @Line + ' ', @BlankSpaceAdded = 1 
END 
END 
END 
END 
FETCH NEXT FROM ms_crs_syscom into @SyscomText 
END 
IF @Line is NOT NULL 
INSERT #CommentText VALUES( @LineId, @Line ) 
select Text from #CommentText order by LineId 
CLOSE ms_crs_syscom 
DEALLOCATE ms_crs_syscom 
DROP TABLE #CommentText 
-- ------------------------------------- 
--结束从sp_helptext提取 
-- ------------------------------------- 
--删除用短横线创建的存储过程并重建原始的存储过程 
ROLLBACK TRAN 
DROP TABLE #output

 解密存储过程

1) SSMS里执行存储过程实现解密

exec dbo.usp_decrypt 'dbo.usp_inlight'

得到解密后的存储过程文本并拷贝得到完整结果,见如下截图:

2) SQLCMD里执行存储过程实现解密并将结果输出到文件里。

sqlcmd -S localhost,1434 -U sa -P 'YoUrPassWd123' -d ShenLiang2025 -i '/home/shenliang2025/z.sql' -o result.txt

评论 2 您还未登录,请先 登录 后发表或查看评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
©️2022 CSDN 皮肤主题:编程工作室 设计师:CSDN官方博客 返回首页

打赏作者

ShenLiang2025

您的鼓励是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值