Patch de emergência 2
Caloni, 2010-11-09 computer blogNo artigo anterior fizemos um patch rapidinho na memória se aproveitando de um Sleep nojento que o código nos forneceu.
E se não houvesse Sleep?
As chances de estarmos escrevendo no momento em que a função está sendo executada são tremendas, de forma que não poderíamos sobrescrevê-la sem correr o risco de um crash.
Uma solução alternativa para isso é alocar um novo pedaço de memória para a versão corrigida e trocar o endereço de chamada na função main.
windbg criticalservice3.exe
0:000> uf DoProcess
criticalservice3!DoProcess [s:\docs\artigos\criticalservice3.cpp @ 8]:
8 00401020 55 push ebp
...
12 0040107d 5d pop ebp
12 0040107e c3 ret
0:000> .writemem DoProcess.func 00401020 0040107e
Writing 5f bytes.
windbg -pvr -pn criticalservice2.exe
0:000> .dvalloc 0x5f
Allocated 1000 bytes starting at 00030000
0:000> .readmem DoProcess.func 00030000 L5f
Reading 5f bytes.
0:000> uf 00030000
00030000 55 push ebp
...
0003005d 5d pop ebp
0003005e c3 ret
Antes de trocarmos o endereço dentro do main precisamos "consertar" a função copiada. Ela está usando as funções globais rand e printf, e as chamadas usam offsets relativos. Como agora a função está em outro offset, temos que reconstruir as chamadas:
00401026 e8da000000 call criticalservice3!rand (00401105) 00030006 e8da000000 call 000300e5 0:000> a 00030006 00030006 call 0x00401105 call 0x00401105 0003000b 00401073 e852000000 call criticalservice3!printf (004010ca) 00030053 e852000000 call 000300aa 0:000> a 00030053 00030053 call 0x004010ca call 0x004010ca 00030058
Agora a função está pronta para ser usada.
0:000> uf 00030000 00030000 55 push ebp 00030001 8bec mov ebp,esp 00030003 83ec0c sub esp,0Ch 00030006 e8fa103d00 call criticalservice2!rand (00401105) 0003000b 99 cdq ... 0003004e 6828a04000 push offset criticalservice2!GetSystemInfo 00030053 e872103d00 call criticalservice2!printf (004010ca) 00030058 83c40c add esp,0Ch 0003005b 8be5 mov esp,ebp 0003005d 5d pop ebp 0003005e c3 ret 0:000> uf main criticalservice2!main [s:\docs\artigos\criticalservice2.cpp @ 16]: 16 00401080 55 push ebp ... criticalservice2!main+0x1f [s:\docs\artigos\criticalservice2.cpp @ 21]: 21 0040109f call criticalservice2!ILT+0(?DoProcessYAXXZ) (00401005) 22 004010a4 jmp criticalservice2!main+0x16 (00401096)
É nessa parte que trocaremos o endereço o endereço 00401005 pela memória alocada. Note que essa escrita é muito rápida e o programa lê esse endereço por muito pouco tempo se compararmos com todas as intruções que são executadas. No entanto, essa escrita não é atômica, e mesmo que as chances sejam extremamente remotas, ainda assim pode haver uma colisão no acesso à essa parte.
É salutar rezar por 10 segundos.
0:000> a 0040109f 0040109f call 0x00030000 call 0x00030000 004010a4
E voilà! A partir do momento em que digitei o call seguido de enter, a função nova já começou a operar em cima do processo ainda rodando. Se quisermos voltar a função antiga, sem problemas:
0:000> a 0040109f 0040109f call 0x00401005 call 0x00401005 004010a4
Não façam isso em casa, crianças ;)