zoukankan      html  css  js  c++  java
  • SQL存储过程解密研究

    从网上搜索SQL存储过程解密,可以看到一大堆的资料,其内容都基本上都一致,这是先放上一篇:
    解密存储过程
    本文将以此为基础进行研究,虽能解密成功,但其中解密那一段究其原理是到底是什么,一直也弄不明白,望了解内情的朋友告知。
    先谈问题:
    网上得来的存储过和经试验存在几个问题:
    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行的存储程,本文不再提供),验证得出结论,短小的存储过程很快即解密成功,并输出,但长度较大的却解密失败。
    接下来看看其如何解密的:
    先看这句
    select @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<=(datalength(@real_01)/2)
    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将内容输出到文本。
    先建立一个物理表,用于存储解密后的数据:
    CREATE TABLE [dbo].[SQL_DECODE](
    [ID] [
    int] IDENTITY(1,1) NOT NULL,
    [SQLTEXT] [nvarchar](max) NOT NULL,
    CONSTRAINT [ID] PRIMARY KEY CLUSTERED
    (
    [ID] ASC
    )
    ) ON [PRIMARY]

    GO

    然后建立一个存储过程,遍历所有加密过的存储过程,调用解密存储过程进行解密,解密后输出:
    CREATE PROCEDURE [dbo].[DECODE_DATABASE]
    AS
    SET NOCOUNT ON
    BEGIN

    DECLARE @PROC_NAME VARCHAR(
    256)
    SET @PROC_NAME
    = ''
    DECLARE @ROWS INT
    DECLARE @TEMP TABLE(
    NAME VARCHAR(
    256)
    )
    INSERT INTO @TEMP SELECT NAME FROM sysobjects WHERE TYPE
    = 'P'
    AND NAME NOT IN (
    'DECODE_DATABASE', 'DECODE_PROC'
    )
    SET @ROWS
    = @@ROWCOUNT
    WHILE @ROWS
    > 0
    BEGIN
    SELECT @PROC_NAME
    = NAME FROM (
    SELECT ROW_NUMBER() OVER (ORDER by NAME) AS ROW, NAME FROM @TEMP
    ) T
    WHERE ROW
    = @ROWS
    EXEC [DECODE_PROC] @PROC_NAME
    PRINT @PROC_NAME
    SET @ROWS
    = @ROWS - 1
    END

    RETURN

    EXEC master..xp_cmdshell
    'bcp "SELECT [SQLTEXT] FROM TEST.dbo.[SQL_DECODE]" queryout C:\decode.txt -c -T -S PC2011043012JUJ'
    END


    GO

    最后是改造后的存储过程:
    CREATE PROCEDURE [dbo].[DECODE_PROC](
    @PROC_NAME SYSNAME
    = NULL
    )
    AS
    SET NOCOUNT ON

    DECLARE @PROC_NAME_LEN INT
    --存储过程名长度
    DECLARE @MAX_COL_ID SMALLINT
    --最大列ID
    SELECT @MAX_COL_ID
    = MAX(subobjid) FROM sys.sysobjvalues WHERE objid = OBJECT_ID(@PROC_NAME) GROUP BY imageval

    SELECT @PROC_NAME_LEN
    = DATALENGTH(@PROC_NAME) + 29
    DECLARE @REAL_01 NVARCHAR(MAX)
    --真实加密存储过程数据
    DECLARE @FACK_01 NVARCHAR(MAX)
    --修改为假的存储过程,长度(40003 - 存在过程名长度),原理不明?
    DECLARE @FACK_ENCRYPT_01 NVARCHAR(MAX)
    --伪加密存储过街程数据
    DECLARE @REAL_DECRYPT_01 NVARCHAR(MAX)
    --最终解密后的数据,初始化为原始加密长度的一半的“A”,原理不明?

    SET @REAL_01
    = (
    SELECT imageval FROM sys.sysobjvalues WHERE objid
    = object_id(@PROC_NAME) AND valclass = 1 AND subobjid = 1
    )

    DECLARE @REAL_DATA_LEN BIGINT
    SET @REAL_DATA_LEN
    = DATALENGTH(@REAL_01)
    --PRINT @REAL_DATA_LEN

    DECLARE @FACK_LEN BIGINT
    SET @FACK_LEN
    = @REAL_DATA_LEN * 10 --改造:假的长度在原真实数据长度上放大10倍

    --此处需将NVARCHAR显示转换成NVARCHAR(MAX),不然将只能产生4K长度
    SET @FACK_01
    = 'ALTER PROCEDURE ' + @PROC_NAME + ' WITH ENCRYPTION AS ' + REPLICATE(CONVERT(NVARCHAR(MAX), '-'), @FACK_LEN - @PROC_NAME_LEN)
    --PRINT '@FACK_01 = ' + STR(LEN(@FACK_01))
    EXECUTE (@FACK_01)
    SET @FACK_ENCRYPT_01
    = (
    SELECT imageval FROM sys.sysobjvalues WHERE objid
    = object_id(@PROC_NAME) AND valclass = 1 AND subobjid = 1
    )

    SET @FACK_01
    = 'CREATE PROCEDURE ' + @PROC_NAME + ' WITH ENCRYPTION AS ' + REPLICATE(CONVERT(VARCHAR(MAX), '-'), @FACK_LEN - @PROC_NAME_LEN)
    SET @REAL_DECRYPT_01
    = REPLICATE(CONVERT(NVARCHAR(MAX), N'A'), (DATALENGTH(@REAL_01) /2))
    --PRINT 'LEN(@REAL_DECRYPT_01) = ' + STR(LEN(@REAL_DECRYPT_01))


    --按位对 @REAL_01、 @FACK_01、 @REAL_DECRYPT_01 进行异或操作。
    DECLARE @INT_PROC_SPACE BIGINT
    SET @INT_PROC_SPACE
    = 1
    WHILE @INT_PROC_SPACE
    <= (DATALENGTH(@REAL_01) /2 )
    BEGIN
    SET @REAL_DECRYPT_01
    = STUFF(
    @REAL_DECRYPT_01,
    @INT_PROC_SPACE,
    1,
    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))))
    )
    SET @INT_PROC_SPACE
    = @INT_PROC_SPACE + 1
    END

    --移除WITH ENCRYPTION
    SET @REAL_DECRYPT_01 = REPLACE(@REAL_DECRYPT_01, 'WITH ENCRYPTION', '')
    INSERT INTO [SQL_DECODE] VALUES (@REAL_DECRYPT_01)

    --PRINT '@REAL_DECRYPT_01 = ' + @REAL_DECRYPT_01
    --PRINT 'LEN(@REAL_DECRYPT_01) = ' + STR(LEN(@REAL_DECRYPT_01))

    --删除原存储过程
    SET @FACK_01
    = 'DROP PROCEDURE ' + @PROC_NAME
    EXEC(@FACK_01)

    GO

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


    或者命令行模式下敲如下命令:
    >sp_configure 'show advanced options',1
    >reconfigure
    >go
    >sp_configure 'xp_cmdshell',1
    >reconfigure
    >go
  • 相关阅读:
    PAT B1045 快速排序 (25 分)
    PAT B1042 字符统计 (20 分)
    PAT B1040 有几个PAT (25 分)
    PAT B1035 插入与归并 (25 分)
    PAT B1034 有理数四则运算 (20 分)
    PAT B1033 旧键盘打字 (20 分)
    HDU 1231 最大连续子序列
    HDU 1166 敌兵布阵
    HDU 1715 大菲波数
    HDU 1016 Prime Ring Problem
  • 原文地址:https://www.cnblogs.com/FlySoul/p/FM.html
Copyright © 2011-2022 走看看