forked from ktaranov/sqlserver-kit
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathDecrypt T-SQL module.sql
More file actions
110 lines (89 loc) · 3.66 KB
/
Copy pathDecrypt T-SQL module.sql
File metadata and controls
110 lines (89 loc) · 3.66 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
SET NOCOUNT ON
DECLARE @owner sysname='dbo', @name sysname='sp_someprocedure';
-----------------------------------------------------------
--- Declarations:
DECLARE @offset int=1;
DECLARE @datalength int;
DECLARE @encrypted_object nvarchar(max);
DECLARE @decrypted_object nvarchar(max)=N'';
DECLARE @fake_object nvarchar(max);
DECLARE @fake_encrypted_object nvarchar(max);
DECLARE @lf nvarchar(max)=NCHAR(13)+NCHAR(10);
DECLARE @type varchar(128);
DECLARE @object_id int=OBJECT_ID('['+@owner+'].['+@name+']');
DECLARE @a int, @b int, @c int;
--- Check that the object exists
IF (@object_id IS NULL) BEGIN;
RAISERROR('Object does not exist.', 16, 1);
RETURN;
END;
--- Check that the object really is encrypted.
IF (NOT EXISTS (SELECT TOP 1 * FROM sys.sql_modules
WHERE [object_id]=@object_id AND [definition] IS NULL)) BEGIN;
RAISERROR('Object is not encrypted.', 16, 1);
RETURN;
END;
--- Store the SQL type name of the object in @type
SELECT @type=(CASE [type]
WHEN 'P' THEN 'PROCEDURE'
WHEN 'TR' THEN 'TRIGGER'
WHEN 'V' THEN 'VIEW'
ELSE 'FUNCTION' END)
FROM sys.objects
WHERE [object_id]=@object_id;
--- @encrypted_object is the encrypted, binary, version of the code:
SELECT TOP 1 @encrypted_object=imageval
FROM sys.sysobjvalues
WHERE [objid]=@object_id AND valclass=1 and subobjid=1;
SET @datalength=DATALENGTH(@encrypted_object)/2;
--- We're going to ALTER the existing object to a "known plaintext"
--- with encryption. That way, we can reverse-engineer the encryption
--- key, using the new encrypted object.
--- All of this is done in a transaction that we'll roll back when
--- we're done with it.
SET @fake_object=N'ALTER '+@type+N' ['+@owner+N'].['+@name+N']
WITH ENCRYPTION AS
';
--- Fill the fake object with dashes ("-") until it's as long as
--- the encrypted object.
WHILE (DATALENGTH(@fake_object)/2<@datalength) BEGIN;
IF (DATALENGTH(@fake_object)/2+4000<@datalength)
SET @fake_object=@fake_object+REPLICATE(N'-', 4000);
ELSE
SET @fake_object=@fake_object+REPLICATE(N'-',
@datalength-(DATALENGTH(@fake_object)/2));
END;
BEGIN TRANSACTION;
--- Implement the fake encrypted object:
EXEC(@fake_object);
--- Retrieve the encrypted version of the "known plaintext".
SELECT TOP 1 @fake_encrypted_object=imageval
FROM sys.sysobjvalues
WHERE [objid]=@object_id AND valclass=1 and subobjid=1;
--- Now that we have the encrypted fake object, roll back
--- the transaction, so we don't break the original object.
ROLLBACK TRANSACTION;
--- Change the @fake_object from ALTER to CREATE (because this is
--- how the encrypted objects are stored in the database!)
SET @fake_object='CREATE'+SUBSTRING(@fake_object, 6, LEN(@fake_object));
-----------------------------------------------------------
--- Perform decryption using the three versions: the encrypted
--- code, the plaintext fake code and the encrypted fake code.
WHILE (@offset<=@datalength) BEGIN;
SELECT
@a=UNICODE(SUBSTRING(@encrypted_object, @offset, 1)),
@b=UNICODE(SUBSTRING(@fake_object, @offset, 1)),
@c=UNICODE(SUBSTRING(@fake_encrypted_object, @offset, 1));
SELECT @decrypted_object=@decrypted_object+NCHAR(@a^(@b^@c)),
@offset=@offset+1;
END;
-----------------------------------------------------------
--- Print the results:
WHILE (@decrypted_object IS NOT NULL) BEGIN;
PRINT LEFT(@decrypted_object,
CHARINDEX(@lf, @decrypted_object+@lf)-1);
SET @decrypted_object=NULLIF(
SUBSTRING(@decrypted_object,
CHARINDEX(@lf, @decrypted_object+@lf)+LEN(@lf),
LEN(@decrypted_object)), '');
END;