É muito comum softwares trabalharem com arquivos. O mesmo vale para malware. Considero importante, do ponto de vista de engenharia reversa, saber como as funções do Windows que trabalham com arquivos são chamadas.
Vamos começar pela função CreateFile
, que tanto cria quando abre arquivos e outros objetos no Windows. O protótipo da versão Unicode dessa função é o seguinte:
Agora vamos aos parâmetros:
O caminho do arquivo que será aberto para escrita ou leitura. Se somente um nome for especificado, o diretório de onde o programa é chamado será considerado. Este parâmetro é do tipo LPCSTR na versão ASCII da função e do tipo LPCSWSTR na versão UNICODE.
Este é um campo numérico que designa o tipo de acesso desejado ao arquivo. Os valores possíveis são:
Também é possível combinar tais valores. Por exemplo, GENERIC_READ | GENERIC_WRITE
para abrir um arquivo com acesso de leitura e escrita.
O modo de compartilhamento deste arquivo com outros processos. Os valores possíveis são:
No entanto, o valor 0
é bem comum e faz com que nenhum outro processo apossa abrir o arquivo simultâneamente.
Um ponteiro para uma estrutura especial do tipo SECURITY_ATTRIBUTES
. Em geral, usamos NULL
.
Ações para tomar em relação à criação do arquivo, pode ser:
Atributos e flags especiais para os arquivos. O mais comum é passar somente FILE_ATTRIBUTE_NORMAL
, mas a documentação oficial prevê muitos outros possíveis valores.
Um handle válido para um arquivo modelo, para ter os atributos copiados. Normalmente é NULL
.
Colocando tudo junto, podemos criar um arquivo usando a API do Windows assim:
Logo após a chamada à CreateFileA
, é comum encontrar uma comparação para saber se o objeto foi aberto com sucesso. Como esta função retorna um handle para o arquivo ou o valor INVALID_HANDLE_VALUE
(0xffffffff) em caso de falha, podemos fazer na sequência:
Por fim, é importante fechar o handle obtido para o arquivo. Isso é feito com a função CloseHandle
:
O código que construímos só abre o arquivo, criando-o sempre, e depois o fecha. Nada é escrito nele. Vamos agora escrever algum texto antes de fechar, mas para isso precisamos de mais uma função.
Essa função escreve dados num objeto. Seu protótipo é o seguinte:
hFile
é o handle de um arquivo previamente aberto com a CreateFile
. O próximo parâmetro, lpBuffer
, é um ponteiro para os dados que pretendemos escrever no arquivo. A quantidade de bytes a serem escritos é informada pelo parâmetro nNumberOfBytesToWrite
e a quantidade de bytes que a função conseguiu escrever é colocada num parâmetro de saída opcional lpNumberOfBytesWritten
. Por fim, o parâmetro lpOverlapped
é um ponteiro para uma estrutura do tipo OVERLAPPED
utilizada em casos especials, mas normalmente é NULL
.
A WriteFile
retorna TRUE
se a escrita ocorreu, ou FALSE
em caso de falha.
Com tais definições, podemos completar nosso programa para fazê-lo escrever um texto no arquivo antes de fechar o arquivo com a CloseHandle
. O código final fica assim:
Ao compilar e rodar este código que produzimos, o programa deve criar o arquivo log.txt
e escrever o texto "Programando usando a API do Windows" nele.