Quando o navegador não quer largar um arquivo
Caloni, 2008-08-13 computer blogDe vez em quando gosto muito de um vídeo que estou assistindo. Gosto tanto que faço questão de guardar para assistir mais vezes depois. O problema é que o meu Firefox ou, para ser mais técnico, o plugin de vídeo que roda em cima do meu navegador, não permite isso. Ele simplesmente cria um arquivo temporário para exibir o vídeo e logo depois o apaga, utilizando uma técnica muito útil da função CreateFile, que bloqueia o acesso do arquivo temporário e apaga-o logo após o uso:
dwShareMode 0 disables subsequent open operations on a file or device to request any type of access to that file or device.
dwFlagsAndAttributes 0x00000000 FILE_FLAG_DELETE_ON_CLOSE the file is to be deleted immediately after all of its handles are closed, which includes the specified handle and any other open or duplicated handles.
Muito bem. Isso quer dizer que é possível abrir um arquivo que mais ninguém pode abrir (nem para copiar para outro arquivo), e ao mesmo tempo garante que quando ele for fechado será apagado. Isso parece uma ótima proteção de cópia não-autorizada para a maioria das pessoas.
Infelizmente, tudo isso roda sob limites muito restritos: um navegador, rodando em user mode, usando APIs bem definidas e facilmente depuráveis.
Antes de iniciar a reprodução do vídeo, e conseqüentemente a criação do arquivo temporário, podemos atachar uma instância do nosso depurador do coração e colocar um breakpoint onde interessa:
windbg -pn firefox.exe ntdll!DbgBreakPoint: 7c901230 cc int 3 0:017> bp kernel32!CreateFileA 0:017> bp kernel32!CreateFileW 0:017> g Breakpoint 2 hit eax=00000001 ebx=00000000 ecx=05432c10 edx=0000003e esi=0532ea00 edi=00000000 eip=7c831f31 esp=0317fdc4 ebp=0317fde8 iopl=0 nv up ei pl nz na po nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202 kernel32!CreateFileW: 7c810760 8bff mov edi,edi
Nesse momento podemos dar uma boa olhada nos parâmetros 4 e 6 da função para ver se trata-se realmente da proteção prevista (na verdade, prevista, nada; esse é um artigo baseado em uma experiência passada; vamos imaginar, contudo, que estamos descobrindo essas coisas como na primeira vez).
0:000> dd esp 0012f30c 300afc06 03f91920 c0000000 00000000 0012f31c 00000000 00000002 14000000 00000000
Como podemos ver, o modo de compartilhamento do arquivo é nenhum. Entre os flags definidos no sexto parâmetro, está o de apagar o arquivo ao fechar o handle, como pude constatar no header do SDK.
Nesse caso, a solução mais óbvia e simples foi deixar esse bit desabilitado, não importando se o modo de compartilhamento está desativado. Tudo que temos que fazer é assistir o vídeo mais uma vez e fechar a aba do navegador. O arquivo será fechado, o compartilhamento aberto, e o arquivo, não apagado.
0:012> bp kernel32!CreateFileW "ed @esp+4*6 poi(@esp+4*6) & 0xfbffffff" breakpoint 1 redefined 0:012> bp kernel32!CreateFileA "ed @esp+4*6 poi(@esp+4*6) & 0xfbffffff" breakpoint 0 redefined 0:012> g
E agora posso voltar a armazenar meus vídeos favoritos.