Hoje de manhã eu recebi uma pergunta de um amigo que queria saber como corromper um banco de dados, para fazer alguns testes. O mecanismo que ele estava utilizando não era efetivo, então eu mencionei que ele poderia usar um editor hexadecimal para fazer o trabalho, mas como não temos muitas referências em português, resolvi gastar alguns minutinhos para machucar um banco de dados. Vamos?
Criando o banco de dados
Execute o script abaixo para criarmos um coitado que será corrompido…
USE master go
-- drop database BDProblema
CREATE DATABASE BDProblema go
USE BDProblema go
ALTER DATABASE BDProblema SET PAGE_VERIFY NONE go
CREATE TABLE Dados ( IdDado INT IDENTITY(1,1) NOT NULL PRIMARY KEY, Nome VARCHAR(200) NOT NULL) go
INSERT INTO Dados VALUES ('Luciano Caixeta Moreira') go
Note que eu configurei o banco de dados para não trabalhar com nenhum modelo de verificação de página, pois quero mostrar para vocês uma edição do arquivo sem recebermos nenhuma mensagem de erro.
Analisando a tabela criada com DBCC PAGE
Agora vamos dar uma olhada na estrutura da página. Primeiro descobrimos onde ela está e depois usando o DBCC PAGE para vermos sua estrutura.
SELECT * FROM sys.sysindexes as s where s.id = OBJECT_ID('Dados') /* First: 0x900000000100 Arquivo = 1 Página = 144 (0x90) */
DBCC TRACEON(3604) DBCC PAGE (BDProblema, 1, 144, 2)
/* Vamos guardar o início da página, pois é o que importa!
Memory Dump @0x5C19C000
5C19C000: 01010400 00c00001 00000000 00000800 †.....À.......... 5C19C010: 00000000 00000100 1b000000 781f8600 †............x.. 5C19C020: 90000000 01000000 14000000 40000000 †............@... 5C19C030: 13000000 00000000 00000000 00000000 †................ 5C19C040: 01000000 00000000 00000000 00000000 †................ 5C19C050: 00000000 00000000 00000000 00000000 †................ 5C19C060: 30000800 01000000 02000001 0026004c †0............&.L 5C19C070: 75636961 6e6f2043 61697865 7461204d †uciano Caixeta M 5C19C080: 6f726569 72610000 21212121 21212121 †oreira..!!!!!!!!
*/
Agora vamos executar uma pequena alteração para identificarmos se o 0x4c em negrito é realmente o “L” do meu nome.
UPDATE Dados SET Nome = 'Muciano Caixeta Moreira'
/*
5C19C000: 01010400 00c00001 00000000 00000800 †.....À.......... 5C19C010: 00000000 00000100 1b000000 781f8600 †............x.. 5C19C020: 90000000 01000000 14000000 5b000000 †............[... 5C19C030: 02000000 00000000 00000000 00000000 †................ 5C19C040: 01000000 00000000 00000000 00000000 †................ 5C19C050: 00000000 00000000 00000000 00000000 †................ 5C19C060: 30000800 01000000 02000001 0026004d †0............&.M 5C19C070: 75636961 6e6f2043 61697865 7461204d †uciano Caixeta M 5C19C080: 6f726569 72610000 21212121 21212121 †oreira..!!!!!!!!
Aqui vemos que o caractere na posição 0x5C19C06F alterou de 0x4c (L) para 0x4d (M). Como estamos na página 144, sabemos que o offset dessa página no arquivo em bytes é: 144 * 8192 = 1179648 (em hexadecimal –> 0x120000). Vamos para o editor hexadecimal?
Editando o arquivo BDProblema.mdf
Pare a instância do SQL Server em questão e utilizando o editor hexadecimal de sua preferência (baixei o Free Hex Editor Neo da HDD Software) abra o arquivo BDProblema.mdf.
Navegue até o offset 120000 e a partir daí vá até a posição 6F e encontre o caractere 4d, alterando-o para 4c.
(Antes)
(Depois)
Agora salve o arquivo, feche o editor, reinicie a instância do SQL Server e execute um SELECT na tabela Dados. Qual será o resultado??? O “Muciano” voltou a ser “Luciano”. Até aqui não vemos nenhum erro, pois o SQL Server não estava com nenhuma verificação específica para o banco de dados, o que está para mudar…
Habilitando o page checksum e corrompendo o banco
Primeiramente, execute o script abaixo:
ALTER DATABASE BDProblema SET PAGE_VERIFY CHECKSUM go
UPDATE Dados SET Nome = 'Muciano Caixeta Moreira' go
DBCC CHECKDB() GO
DBCC results for 'Dados'. There are 1 rows in 1 pages for object "Dados". CHECKDB found 0 allocation errors and 0 consistency errors in database 'BDProblema'.
Como resultado, teremos um banco de dados com CHECKSUM habilitado e a página com seu checksum calculado, pois foi executado um update na tabela. O CHECKDB vai executar com sucesso e nenhum erro será reportado.
Repita do procedimento listado no tópico “Editando o arquivo BDProblema.mdf”, onde você vai alterar o nome “Muciano” para “Luciano” através do editor hexadecimal. Reinicie o serviço do SQL Server e tente executar a consulta abaixo:
SELECT * FROM Dados /* IdDado Nome ----------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Msg 824, Level 24, State 2, Line 1 SQL Server detected a logical consistency-based I/O error: incorrect checksum (expected: 0xd73d977b; actual: 0xd73d97fb). It occurred during a read of page (1:144) in database ID 7 at offset 0x00000000120000 in file 'C:\Program Files\Microsoft SQL Server\MSSQL10.MSSQLSERVER\MSSQL\DATA\BDProblema.mdf'. Additional messages in the SQL Server error log or system event log may provide more detail. This is a severe error condition that threatens database integrity and must be corrected immediately. Complete a full database consistency check (DBCC CHECKDB). This error can be caused by many factors; for more information, see SQL Server Books Online. */
Se tentar executar um CHECKDB, vai ver algo parecido com:
DBCC results for 'Dados'. Msg 8928, Level 16, State 1, Line 1 Object ID 2105058535, index ID 1, partition ID 72057594038779904, alloc unit ID 72057594039697408 (type In-row data): Page (1:144) could not be processed. See other errors for details. Msg 8939, Level 16, State 98, Line 1 Table error: Object ID 2105058535, index ID 1, partition ID 72057594038779904, alloc unit ID 72057594039697408 (type In-row data), page (1:144). Test (IS_OFF (BUF_IOERR, pBUF->bstat)) failed. Values are 12716041 and -4. There are 0 rows in 0 pages for object "Dados". CHECKDB found 0 allocation errors and 2 consistency errors in table 'Dados' (object ID 2105058535). CHECKDB found 0 allocation errors and 2 consistency errors in database 'BDProblema'. repair_allow_data_loss is the minimum repair level for the errors found by DBCC CHECKDB (BDProblema). DBCC execution completed. If DBCC printed error messages, contact your system administrator.
Pronto! Você está com o seu banco de dados corrompido. Como é um problema na página de dados, não podemos fazer um rebuild de um índice (método utilizado quando um índice não-cluster está corrompido) e temos que partir para outros métodos de disaster recovery, como recuperar um backup.
Espero que você tenha gostado e te ajudado a entender como pode simular falhas no seu banco de dados, para testar seu planejamento de disaster recovery, antes que seu ambiente de produção não esteja ok e você não sabia o que fazer. Além disso, claro, veja como é importante manter o checksum habilitado!
Até a próxima!
[]s Luciano Caixeta Moreira luciano.moreira@microsoft.com =============================================== This post is provided "AS IS" and confers no right ===============================================