Quando o navegador não quer largar um arquivo

Caloni, 2008-08-13 computer blog

De 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.

De volta ao WinDbg

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.

[os_processosfantasma] [antidebugging_during_the_process_attach]