首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 數據庫知識 >  >> SQL Server 資料庫 >> SQL Server 2005

SQL Server 2005 加密存儲過程解密實戰:DAC 連線 + 系統表 XOR 還原原始碼

     編輯:SQL Server 2005

核心原理

WITH ENCRYPTION 只是將 sys.sysobjvalues.imageval 中的原始碼以簡單 XOR 混淆。解密步驟:

  1. 取得加密後的 imageval (真實加密碼)。
  2. 建立同名、同長度的假物件 (同樣 WITH ENCRYPTION),取得其 imageval (假加密碼)。
  3. 建立同名、同長度的明文假物件 (無加密),取得其原始 imageval (假明文)。
  4. 利用 XOR 可逆性:真明文 = 真加密碼 XOR 假加密碼 XOR 假明文。
  5. 交易回滾,還原原物件,輸出解密碼。

前置條件:必須使用 DAC (專用管理員連接)

  • SSMS:工具列「資料庫引擎查詢」→ 伺服器名輸入 ADMIN:InstanceName (如 ADMIN:ACCT\PAYABLE) → sysadmin 登入。
  • sqlcmd:sqlcmd -A -S InstanceName -o decrypted.sql 輸出到檔案。
  • 遠端 DAC 需啟用:sp_configure 'remote admin connections', 1; RECONFIGURE;

完整解密存儲過程 (sp_undecrypt)

CREATE PROCEDURE [dbo].[sp_undecrypt]
    @procedure SYSNAME = NULL,
    @revfl INT = 1  -- 1=顯示警告, 0=實際執行解密
AS
BEGIN
    SET NOCOUNT ON;
    IF @revfl = 1
    BEGIN
        PRINT N'警告:此程序會刪除並重建原始加密物件。';
        PRINT N'請確保已備份資料庫,建議在非生產環境執行。';
        PRINT N'若確定執行,請呼叫 EXEC sp_undecrypt @procedure, 0;';
        RETURN 0;
    END

    DECLARE @maxColID SMALLINT, @procNameLen INT, @objType CHAR(2), @parentName NVARCHAR(MAX);
    SELECT @maxColID = MAX(subobjid) FROM sys.sysobjvalues WHERE objid = OBJECT_ID(@procedure);
    SELECT @procNameLen = DATALENGTH(@procedure) + 29;
    SELECT @objType = type, @parentName = OBJECT_NAME(parent_object_id)
    FROM sys.objects WHERE object_id = OBJECT_ID(@procedure);

    -- 1. 取得真實加密碼
    DECLARE @real_enc NVARCHAR(MAX) = (SELECT TOP 1 imageval FROM sys.sysobjvalues
        WHERE objid = OBJECT_ID(@procedure) AND valclass = 1 ORDER BY subobjid);

    -- 2. 建立假明文物件 (無加密)
    DECLARE @fake_plain NVARCHAR(MAX);
    IF @objType = 'P' SET @fake_plain = N'CREATE PROCEDURE ' + @procedure + N' AS SELECT 1 /*' + REPLICATE(N'*', DATALENGTH(@real_enc)/2 - @procNameLen) + N'*/';
    ELSE IF @objType = 'FN' SET @fake_plain = N'CREATE FUNCTION ' + @procedure + N'() RETURNS INT AS BEGIN RETURN 1 /*' + REPLICATE(N'*', DATALENGTH(@real_enc)/2 - @procNameLen) + N'*/ END';
    ELSE IF @objType = 'V'  SET @fake_plain = N'CREATE VIEW ' + @procedure + N' AS SELECT 1 AS col /*' + REPLICATE(N'*', DATALENGTH(@real_enc)/2 - @procNameLen) + N'*/';
    ELSE IF @objType = 'TR' SET @fake_plain = N'CREATE TRIGGER ' + @procedure + N' ON ' + @parentName + N' AFTER INSERT AS RAISERROR(''N'',16,10) /*' + REPLICATE(N'*', DATALENGTH(@real_enc)/2 - @procNameLen) + N'*/';
    EXEC (@fake_plain);

    -- 3. 取得假明文加密後的 imageval
    DECLARE @fake_enc NVARCHAR(MAX) = (SELECT TOP 1 imageval FROM sys.sysobjvalues
        WHERE objid = OBJECT_ID(@procedure) AND valclass = 1 ORDER BY subobjid);

    -- 4. 建立假加密物件 (同樣 WITH ENCRYPTION)
    DECLARE @fake_enc_obj NVARCHAR(MAX);
    IF @objType = 'P' SET @fake_enc_obj = N'CREATE PROCEDURE ' + @procedure + N' WITH ENCRYPTION AS SELECT 1 /*' + REPLICATE(N'*', DATALENGTH(@real_enc)/2 - @procNameLen) + N'*/';
    ELSE IF @objType = 'FN' SET @fake_enc_obj = N'CREATE FUNCTION ' + @procedure + N'() RETURNS INT WITH ENCRYPTION AS BEGIN RETURN 1 /*' + REPLICATE(N'*', DATALENGTH(@real_enc)/2 - @procNameLen) + N'*/ END';
    ELSE IF @objType = 'V'  SET @fake_enc_obj = N'CREATE VIEW ' + @procedure + N' WITH ENCRYPTION AS SELECT 1 AS col /*' + REPLICATE(N'*', DATALENGTH(@real_enc)/2 - @procNameLen) + N'*/';
    ELSE IF @objType = 'TR' SET @fake_enc_obj = N'CREATE TRIGGER ' + @procedure + N' ON ' + @parentName + N' WITH ENCRYPTION AFTER INSERT AS RAISERROR(''N'',16,10) /*' + REPLICATE(N'*', DATALENGTH(@real_enc)/2 - @procNameLen) + N'*/';
    EXEC (@fake_enc_obj);

    -- 5. 取得假加密物件的 imageval
    DECLARE @fake_enc2 NVARCHAR(MAX) = (SELECT TOP 1 imageval FROM sys.sysobjvalues
        WHERE objid = OBJECT_ID(@procedure) AND valclass = 1 ORDER BY subobjid);

    -- 6. XOR 還原真明文 (逐字元)
    DECLARE @real_plain NVARCHAR(MAX) = REPLICATE(N'A', DATALENGTH(@real_enc)/2);
    DECLARE @i INT = 1;
    WHILE @i <= DATALENGTH(@real_enc)/2
    BEGIN
        SET @real_plain = STUFF(@real_plain, @i, 1,
            NCHAR(UNICODE(SUBSTRING(@real_enc, @i, 1)) ^
                  UNICODE(SUBSTRING(@fake_plain, @i, 1)) ^
                  UNICODE(SUBSTRING(@fake_enc2, @i, 1))));
        SET @i += 1;
    END

    -- 7. 輸出格式化 (模擬 sp_helptext 換行邏輯)
    CREATE TABLE #out(line NVARCHAR(MAX));
    INSERT #out SELECT @real_plain;
    -- 這裡簡化直接輸出,完整版需按 255 字元換行
    SELECT @real_plain AS DecryptedCode;

    -- 8. 回滾交易,還原原物件
    ROLLBACK TRAN;
    DROP TABLE #out;
END;
GO

使用方法

-- DAC 連線下執行
EXEC sp_undecrypt 'dbo.YourEncryptedProc', 0;
-- 或 sqlcmd 輸出檔案
sqlcmd -A -S . -Q "EXEC sp_undecrypt 'dbo.YourEncryptedProc', 0" -o decrypted.sql

關鍵限制與風險

  • 僅適用 WITH ENCRYPTION (非 SQL 2017+ 的 ENCRYPTION 選項或 Always Encrypted)。
  • 必須在 DAC 連線下執行 (需 sysadmin)。
  • 會暫時刪除原物件並重建,務必先備份資料庫,建議在還原的測試庫執行。
  • 超長物件 (超過複寫長度限制) 可能解密不全,需分段處理。
  • 解密屬逆向工程,請遵守授權協議與法律法規。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved