Ir para conteúdo
Faça parte da equipe! (2024) ×
Conheça nossa Beta Zone! Novas áreas a caminho! ×

  • Quem está por aqui   0 membros estão online

    • Nenhum usuário registrado visualizando esta página.

DLL Injection - C/C++ Pra Qm Sabe


-leandro-
 Compartilhar

Posts Recomendados

Ola, Tipow naum sei muitu bem mais acho q esse troso todo ae

e pa faser um dll intaum pra qm intende dissu ae e bom

se alguem manja meche manda pm vlw

 

 

DLL Injection - C/C++

 

 

 

Hoje irei mostrar um exemplo de DLL Injection em C/C++.

A técnica DLL Injection consiste em executar um código dentro da memória de um outro processo forçando carregar uma DLL definida por nós.

 

A técnica é muito utilizada em trainers - onde geralmente hí uma DLL e um Loader -, alguns anti-vàrus podem injetar DLL's que trabalham no monitoramento de aplicativos, e é claro: programas maliciosos.

 

Existem diversas formas de injetar uma DLL em um processo. As principais são:

utilizando a função CreateRemoteThread() ou utilizando Hooks. Existe ainda uma maneira mais fícil: adicionado,em um valor do registro, o nome da DLL que o programa serí forçado a carregar - mas não iremos abordí-la também

 

Obs:: O valor acima se encontra em:

 

HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion\Windows\AppInit_DLLs

 

 

No artigo, veremos a primeira forma: criando uma thread que serí executada em um outro processo, através da função CreateRemoteThread().

 

É necessírio ter um conhecimento prévio na linguagem C, uma vez em que não irei abordar alguns conceitos bísicos

 

Para injetar a DLL com este método, os seguintes passos devem ser seguidos:

 

1) Deve-se abrir o processo no qual iremos injetar a DLL com a função OpenProcess().

 

2) Alocamos um espaço na memória deste processo, suficiente para armazenar o caminho da DLL que iremos escrever, através da função VirtualAllocEx.

 

3) Após alocarmos este espaço, escrevemos no endereço retornado pela função VirtualAllocEx(), o caminho da DLL a ser injetada.

 

4) Obtemos o endereço da função LoadLibrary() contida dentro do módulo KERNEL32 através da função GetProcAddress().

 

5) Criamos uma thread remota no processo alvo, passando o endereço da função obtida como função da thread e o endereço alocado como parâmetro.

 

Vejamos:

 

 

1) Deve-se abrir o processo no qual iremos injetar a DLL com a função OpenProcess().

 

Bem, para que possamos abrir um processo pela função OpenProcess(), devemos saber o número ID deste processo, também conhecido como Process ID ou PID. Se você executar o programa "tasklist" verí o PID de cada processo em execução.

 

Veja um exemplo:

 

 

Código:

#include <windows.h> // Header onde a função OpenProcess() é definida

int main()

{

HANDLE processo = OpenProcess(PROCESS_ALL_ACCESS,FALSE,12345);

 

if(!processo)

MessageBox(0,"Ocorreu um erro ao abrir o processo!","Erro",0x10);

else

CloseHandle(processo);

 

return 0;

 

}

 

 

 

Acima, tentamos abrir o processo cujo PID é 12345, com totais permissões.

 

Tomei vergonha na cara e baixei o WIN32.HLP - que é um arquivo HLP contendo a descrição e sintaxe das funções e constates da API do Windows. Segundo a Microsoft, a sintaxe da função OpenProcess() é:

 

 

Citação:

HANDLE OpenProcess(

 

DWORD fdwAccess, // access flag

BOOL fInherit, // handle inheritance flag

DWORD IDProcess // process identifier

);

 

fdwAccess:

modo de acesso:

 

PROCESS_ALL_ACCESS = permissões totais;

PROCESS_CREATE_PROCES = criação de processo;

PROCESS_CREATE_THREAD = para criar uma thread;

PROCESS_DUP_HANDLE = duplicação de handle;

PROCESS_QUERY_INFORMATION = obter informações do processo;

PROCESS_SET_INFORMATION = definir informações;

PROCESS_TERMINATE = terminar um processo;

PROCESS_VM_READ = ler a memória de um processo;

PROCESS_VM_WRITE = escrever na memória de um processo

SYNCHRONIZE = sincronização de funções (WIN NT)

 

fInherit:

se TRUE, processos criados a partir do atual, irão herdar seu handle, se FALSE o handle não serí herdido.

 

IDProcess:

ID do processo (PID).

 

A função retorna ZERO caso ocorra um erro ao abrir o processo.

Em caso de êxito, o valor retornado equivale ao handle do processo.

 

 

 

Sempre devemos fechar o handle de um processo aberto com OpenProcess():

 

 

Citação:

CloseHandle(handle_do_processo);

 

 

 

2) Alocamos um espaço na memória deste processo, suficiente para armazenar o caminho da DLL que iremos escrever, através da função VirtualAllocEx.

 

Se abrimos o processo com direitos de acesso totais, poderemos alocar espaço em sua memória, escrever e ler endereços, etc.

 

Veja:

 

 

Código:

#include <windows.h>

int main()

{

HANDLE processo = OpenProcess(PROCESS_ALL_ACCESS,FALSE,12345);

 

if(!processo){

MessageBox(0,"Ocorreu um erro ao abrir o processo!","Erro",0x10);

return 1;}

 

LPVOID addr = VirtualAllocEx(processo,0,1024,MEM_COMMIT,PAGE_EXECUTE_READWRITE);

 

if(addr == NULL)

MessageBox(0,"Erro ao alocar espaço na memória do processo!","Erro",0x10);

else

VirtualFreeEx(processo,addr,1024,MEM_RELEASE);

 

CloseHandle(processo);

return 0;

 

}

 

 

 

No exemplo acima, alocamos 1024 bytes no processo aberto e armazenamos o endereço no qual foram alocados os bytes na variível addr.

 

Vejamos a sintaxe:

 

 

Citação:

LPVOID VirtualAllocEx(

HANDLE hProcess,

LPVOID lpAddress,

SIZE_T dwSize,

DWORD flAllocationType,

DWORD flProtect

);

 

 

hProcess:

handle do processo;

 

lpAddress:

ponteiro que especifica o endereço inicial da írea que se deseja alocar.

 

dwSize:

quantidade de memória a ser alocada.

 

flAllocationType:

tipo de alocação de memória. No artigo, utilizaremos MEM_COMMIT para alocarmos memória no processo inicializando a região com ZERO.

 

flProtect:

modo de acesso à região alocada.

 

Principais:

 

PAGE_READONLY = leitura apenas

PAGE_READWRITE = leitura e escrita

PAGE_EXECUTE = execução

PAGE_EXECUTE_READ = leitura e execução

PAGE_EXECUTE_READWRITE = execução, leitura e escrita.

 

A função retorna um endereço NULO se falhar ou retorna o endereço da região alocada.

 

 

 

 

No exemplo, alocamos 1024 bytes na região de memória do processo. No entanto, iremos alocar apenas um tamanho suficiente

para escrevemos o caminho da DLL. Veja:

 

 

 

Código:

 

#include <windows.h>

int main()

{

char DLL[]="C:\\Exemplo\\dll1.dll"; // A constante '\\' equivale a '\'

 

HANDLE processo = OpenProcess(PROCESS_ALL_ACCESS,FALSE,12345);

 

if(!processo){

MessageBox(0,"Ocorreu um erro ao abrir o processo!","Erro",0x10);

return 1;}

 

// Aloca o tamanho da string incluindo o caractere NULO

LPVOID addr = VirtualAllocEx(processo,0,strlen(DLL)+1,MEM_COMMIT,PAGE_EXECUTE_READWRITE);

 

if(addr == NULL) // Verifica endereço

MessageBox(0,"Erro ao alocar espaço na memória do processo!","Erro",0x10);

else

VirtualFreeEx(processo,addr,strlen(DLL)+1,MEM_RELEASE);

 

CloseHandle(processo);

return 0;

}

 

 

 

 

Para liberamos o espaço alocado no processo, utilizamos a função VirtualFreeEx():

 

VirtualFreeEx(processo,addr,strlen(DLL)+1,MEM_RELEASE)

 

Sintaxe:

 

 

Citação:

BOOL VirtualFreeEx(

HANDLE hProcess,

LPVOID lpAddress,

SIZE_T dwSize,

DWORD dwFreeType

);

 

hProcess:

handle do processo;

 

lpAddress:

ponteiro que especifica o endereço da írea que se deseja desalocar.

 

dwSize:

número de bytes a desalocar;

 

dwFreeType:

tipo de desalocação. Quando alocamos um espaço com a função VirtualAllocEx, o parâmetro passado deve ser MEM_RELEASE.

 

 

 

 

 

3) Após alocarmos este espaço, escrevemos no endereço retornado pela função VirtualAllocEx, o caminho da DLL a ser injetada.

 

 

Para escrevermos um valor qualquer em um determinado endereço de memória, utilizamos a função WriteProcessMemory():

 

 

Código:

#include <windows.h>

int main()

{

char DLL[]="C:\\Exemplo\\dll1.dll";

 

HANDLE processo = OpenProcess(PROCESS_ALL_ACCESS,FALSE,12345);

 

if(!processo){

MessageBox(0,"Ocorreu um erro ao abrir o processo!","Erro",0x10);

return 1;}

 

// Aloca o tamanho da string incluindo o caractere NULO

LPVOID addr = VirtualAllocEx(processo,0,strlen(DLL)+1,MEM_COMMIT,PAGE_EXECUTE_READWRITE);

 

if(addr == NULL){ // Verifica endereço

MessageBox(0,"Erro ao alocar espaço na memória do processo!","Erro",0x10);

CloseHandle(processo);

return 1;}

 

DWORD bytes;

WriteProcessMemory(processo,addr,(LPVOID)DLL,strlen(DLL+1),&bytes); // Escreve o caminho da DLL no endereço retornado

VirtualFreeEx(processo,addr,strlen(DLL)+1,MEM_RELEASE);

 

CloseHandle(processo);

return 0;

 

}

 

 

 

Acima, escrevemos no endereço retornado o caminho da DLL.

 

Sintaxe:

 

 

Citação:

BOOL WriteProcessMemory(

 

HANDLE hProcess, // handle of process whose memory is written to

LPVOID lpBaseAddress, // address to start writing to

LPVOID lpBuffer, // address of buffer to write data to

DWORD cbWrite, // number of bytes to write

LPDWORD lpNumberOfBytesWritten // actual number of bytes written

);

 

hProcess:

handle do processo;

 

lpBaseAddress:

endereço no qual iremos escrever o valor;

 

cbWrite:

número de bytes a escrever;

 

lpNumberOfBytesWritten:

ponteiro para uma variível do tipo DWORD que irí armazenar o número de bytes que foram escritos.

 

 

 

 

4) Obtemos o endereço da função LoadLibrary() contida dentro do módulo KERNEL32 através da função GetProcAddress().

 

Veja:

 

 

Código:

#include <windows.h>

int main()

{

HMODULE kernel = GetModuleHandle ("KERNEL32");

FARPROC pFunc = GetProcAddress(kernel,"LoadLibraryA");

 

return 0;

}

 

 

 

Acima, armazenamos em "kernel" o valor do módulo KERNEL32.

A variível "pFunc", do tipo FARPROC, armazena o endereço para a função LoadLibrary - LoadLibraryA dentro do módulo - contida dentro do módulo KERNEL32.

 

No entanto, é sempre bom verificar a validade dos valores:

 

 

Código:

#include <windows.h>

int main()

{

HMODULE kernel = GetModuleHandle ("KERNEL32");

if(!kernel)

return 1;

 

 

FARPROC pFunc = GetProcAddress(kernel,"LoadLibraryA");

if(!pFunc)

return 1;

 

MessageBox(0,"Carregados com sucesso!","^^",0x40);

return 0;

}

 

 

 

Em ambos os casos, o valor retornado na ocorrência de erros é NULO, ou seja, ZERO.

 

Vejamos como implementar no código:

 

 

Código:

#include <windows.h>

int main()

{

char DLL[]="C:\\Exemplo\\dll1.dll";

 

HANDLE processo = OpenProcess(PROCESS_ALL_ACCESS,FALSE,12345);

 

if(!processo){

MessageBox(0,"Ocorreu um erro ao abrir o processo!","Erro",0x10);

return 1;}

 

// Aloca o tamanho da string incluindo o caractere NULO

LPVOID addr = VirtualAllocEx(processo,0,strlen(DLL)+1,MEM_COMMIT,PAGE_EXECUTE_READWRITE);

 

if(addr == NULL){ // Verifica endereço

MessageBox(0,"Erro ao alocar espaço na memória do processo!","Erro",0x10);

CloseHandle(processo);

return 1;}

 

DWORD bytes;

WriteProcessMemory(processo,addr,(LPVOID)DLL,strlen(DLL)+1,&bytes); // Escreve o caminho da DLL no endereço retornado

 

HMODULE kernel = GetModuleHandle ("KERNEL32"); // Carrega módulo

if(!kernel)

return 1;

 

FARPROC pFunc = GetProcAddress(kernel,"LoadLibraryA"); // Obtém endereço da função

if(!pFunc)

return 1;

 

VirtualFreeEx(processo,addr,strlen(DLL)+1,MEM_RELEASE);

CloseHandle(processo);

return 0;

 

}

 

 

 

5) Criamos uma thread remota no processo alvo, passando o endereço da função obtida como função da thread e o endereço alocado como parâmetro.

 

Neste último passo, faremos com que o processo carregue a DLL "C:\Exemplo\dll1.dll".

 

Veja:

 

 

Código:

#include <windows.h>

int main()

{

char DLL[]="C:\\Exemplo\\dll1.dll";

 

HANDLE processo = OpenProcess(PROCESS_ALL_ACCESS,FALSE,12345);

 

if(!processo){

MessageBox(0,"Ocorreu um erro ao abrir o processo!","Erro",0x10);

return 1;}

 

// Aloca o tamanho da string incluindo o caractere NULO

LPVOID addr = VirtualAllocEx(processo,0,strlen(DLL)+1,MEM_COMMIT,PAGE_EXECUTE_READWRITE);

 

if(addr == NULL){ // Verifica endereço

MessageBox(0,"Erro ao alocar espaço na memória do processo!","Erro",0x10);

CloseHandle(processo);

return 1;}

 

DWORD bytes;

WriteProcessMemory(processo,addr,(LPCVOID)DLL,strlen(DLL)+1,&bytes); // Escreve o caminho da DLL no endereço retornado

 

HMODULE kernel = GetModuleHandle ("KERNEL32"); // Carrega módulo

if(!kernel)

return 1;

 

FARPROC pFunc = GetProcAddress(kernel,"LoadLibraryA"); // Obtém endereço da função

if(!pFunc)

return 1;

 

HANDLE thread = CreateRemoteThread(processo,NULL,0,(LPTHREAD_START_ROUTINE)pFunc,addr,0,NULL);

if(!thread)

MessageBox(0,"Ocorreu um erro ao criar a thread!","Erro",0x10);

 

VirtualFreeEx(processo,addr,strlen(DLL)+1,MEM_RELEASE);

CloseHandle(processo);

return 0;

 

}

 

 

 

Veja:

 

 

Código:

HANDLE thread = CreateRemoteThread(proc,NULL,0,(LPTHREAD_START_ROUTINE)pFunc,addr,0,NULL);

if(!thread)

MessageBox(0,"Ocorreu um erro ao criar a thread!","Erro",0x10);

 

 

 

Criamos uma thread remota no processo passando o endereço que o ponteiro para função "pFunc" armazena. Como parâmetro, passamos o endereço alocado e que nesta fase, armazena o caminho da DLL.

 

Vejamos a sintaxe:

 

 

 

Citação:

HANDLE CreateRemoteThread(

 

HANDLE hProcess, // handle to process to create thread in

LPSECURITY_ATTRIBUTES lpThreadAttributes, // address of thread security attributes

DWORD dwStackSize, // initial thread stack size, in bytes

LPTHREAD_START_ROUTINE lpStartAddress, // address of thread function

LPVOID lpParameter, // address of argument for new thread

DWORD dwCreationFlags, // creation flags

LPDWORD lpThreadId // address of returned thread identifier

);

 

hProcess:

handle do processo;

 

lpThreadAttributes:

ponteiro para uma estrutura do tipo SECURITY_ATTRIBUTES. Se passado como NULL, o sistema usa valor padrões.

 

dwStackSize:

tamanho inicial da stack em bytes. Se ZERO, valores padrões são usados.

 

lpStartAddress:

endereço da função da Thread.

 

lpParameter:

um parâmetro opcional que serí passado à função da Thread.

 

dwCreationFlags:

opções de inicialização. Se a flag CREATE_SUSPENDED, a thread não é executada após sua criação - necessita da função ResumeThread. Se ZERO, a thread é executada assim que é criada.

 

lpThreadId:

ponteiro para uma variível do tipo DWORD que irí armazenar um valor ID da thread.

 

 

Se a função tiver êxito, é retornando um valor como handle da thread.

Do contrírio, é retornado ZERO.

 

 

 

Observe os parâmetros:

 

 

Citação:

lpStartAddress:

endereço da função da Thread.

 

lpParameter:

um parâmetro opcional que serí passado à função da Thread.

 

 

 

No nosso exemplo, correspondem, respectivamente: ao ponteiro pFunc e ao endereço armazenado em addr.

Como se sabe, "pFunc" armazena o endereço externo da função LoadLibrary().

 

Quando passamos estes valores, implicitamente, fazemos com que o processo alvo execute algo similar a:

 

 

Código:

LoadLibrary(CAMINHO_DA_DLL);

 

 

Utilizamos a função LoadLibrary() para carregar uma DLL.

 

Percebeu? Criamos uma thread que, na verdade, executa a função LoadLibrary() e tem como parâmetro o valor do endereço armazenado na variível "addr", que por sua vez, armazena o caminho da DLL

 

Pelo o que eu escrevi até agora, acho que o artigo não ficou bom, para tentar melhorí-lo, irei postar o código de um programa que ilustra o funcionamento:

 

injetar.c

 

 

Código:

#include <stdio.h> // Stardard I/O

#include <stdlib.h> // malloc(), exit()

#include <string.h> // Manipulação de strings

#include <windows.h> // API do Windows

#include <tlhelp32.h> // Listar processos

 

// Declaração de funções

void injetar(DWORD pid, char*);

void erro(const char*);

 

 

char dll_nome[0x100]; // Caminho da DLL a injetar

char processo_nome[0x30]; // Nome do processo

 

// As variíveis abaixo estão relacionadas à lista de processos

 

PROCESSENTRY32 processo; // Informações do processo

HANDLE SnapShot; // Handle SnapShot -> listar processos

DWORD PID = 0; // Número ID do processo

 

 

// As variíveis abaixo estão relecionadas à injeção da DLL

 

DWORD tam; // Tamanho (em bytes) a alocar remotamente no processo

DWORD bytes = 0; // Retorno -> bytes alocados

HANDLE proc; // HANDLE do processo

HMODULE kernel; // Módulo -> kernel que serí carregado

LPVOID addr; // Endereço no qual foi alocado um espaço

FARPROC pFunc; // Ponteiro para a função LoadLibrary() dentro de Kernel32

HANDLE thread; // Handle para a thread remota

 

 

int main(int argn, char * arg[])

{

system("cls");

if(argn != 3) // Verifica argumentos

{

printf("Uso: %s <caminho da DLL> <nome do processo>",strrchr(arg[0],'\\')+1);

return 1;

}

 

snprintf(dll_nome,0x100,"%s",arg[1]); // Armazena o caminho da DLL

 

HINSTANCE dll = LoadLibrary(dll_nome); // Verifica se a DLL pode ser acessada

if(!dll)

{

printf("Erro ao acessar a DLL \"%s\".",dll_nome);

return 1;

}

FreeLibrary(dll); // Fecha a DLL

 

snprintf(processo_nome,0x30,"%s",arg[2]); // Armazena o nome do processo

 

 

// Tenta iniciar a listagem de processos

if(!(SnapShot=CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0)))

return 1;

 

processo.dwSize=sizeof(PROCESSENTRY32); // Define tamanho da estrutura

 

if(!Process32First(SnapShot,&processo)) // Tenta obter o primeiro processo

return 1;

 

while(Process32Next(SnapShot,&processo)) // Enquanto houverem processos

{

if(!strcmp(strlwr(processo.szExeFile),strlwr(processo_nome))){ // Compara com o argumento

PID = processo.th32ProcessID; // Armazena o PID do processo, se encontrado

break; // Encerra LOOP

}

}

CloseHandle(SnapShot); // Fecha handle

 

if(!PID) // Verifica se o PID foi obtido

printf("O processo \"%s\" nao foi encontrado!",processo_nome);

else

injetar(PID,dll_nome); // Injeta no processo a DLL

 

return 0;

}

 

 

void injetar(DWORD pid, char * DLL)

{

tam = strlen(DLL)+1; // Espaço a ser alocado remotamente

 

kernel = GetModuleHandle ("KERNEL32"); // Carrega módulo KERNEL

if(!kernel)

erro(DLL);

 

proc = OpenProcess(PROCESS_ALL_ACCESS,FALSE,pid); // Tenta abrir o processo

if(!proc)

erro(DLL);

 

// Tenta alocar um espaço no processo e obtém o endereço

addr = VirtualAllocEx(proc,0,tam,MEM_COMMIT,PAGE_EXECUTE_READWRITE);

if(!addr)

erro(DLL);

 

// Escreve o nome da DLL neste endereço

WriteProcessMemory(proc,addr,(LPCVOID)DLL,tam,&bytes);

 

 

// Tenta obter endereço da função LoadLibrary()

pFunc = GetProcAddress(kernel,"LoadLibraryA");

if(!pFunc)

erro(DLL);

 

 

// Tenta criar Thread remota -> fazer com que o processo carregue a DLL

thread = CreateRemoteThread(proc,NULL,0,(LPTHREAD_START_ROUTINE)pFunc,addr,0,NULL);

if(!thread)

erro(DLL);

 

printf("A DLL \"%s\" foi injetada com sucesso no processo \"%s\".",DLL,processo_nome);

 

VirtualFreeEx(proc,addr,tam,MEM_RELEASE); // Libera espaço alocado no processo

CloseHandle(proc); // Fecha handle do processo

 

 

}

 

 

void erro(const char* DLL) // Mostra erro e encerra

{

printf("Ocorreu um erro ao tentar injetar a DLL \"%s\".",DLL);

exit(1); // Encerra o programa

}

 

 

 

Uma dica: quando queremos injetar uma DLL que esteja localizada dentro de C:\WINDOWS\System32, não é necessírio incluir todo o caminho, mas apenas o nome da DLL. Exemplo:

 

C:\WINDOWS\WSOCK32.DLL = WSOCK32.DLL

 

Exemplo de uso do programa acima:

 

injetar WSOCK32.DLL explorer.exe

 

 

O programa iria tentar injetar a DLL WSOCK32 contida em C:\WINDOWS\System32 dentro do processo "explorer.exe".

 

Quando uma DLL é injetada, esta permanece até que o processo seja finalizado ou reiniciado. Durante este intervalo, não é possàvel renomear ou deletar esta DLL.

 

Por esta mesma razão, muitos programas maliciosos injetam DLL's em processo cràticos do sistema, como WinLogon.exe, crss.exe, etc. Uma vez em que, em situação normal, estes processos não são finalizados, mesmo que se detecte a DLL maliciosa, não poderàamos deletí-la enquanto o processo estivesse em execução.

 

Você pode verificar as DLLs injetadas em um processo através de um ListDlls - um programa bem simples que mostra esta e outras informações:

 

É necessário se cadastrar para acessar o conteúdo.
... tDlls.mspx (lolz não achei outro link =X )

 

 

Bem, ainda falando sobre processo cràticos, por padrão, estes não podem ser abertos com a função OpenProcess() devido àlgumas restrições do sistema. Geralmente, para abri-los, alteramos seus privilégios para o modo DEBUG, com auxàlio da função OpenProcessToken(). No entanto, para não tornar o artigo mais cansativo, optarei por não abordar a técnica.

 

Gostaria de esclarecer que o que eu expliquei foi essencialmente o bísico e recomendo a busca de maiores informações para ampliar o conhecimento.

 

Alguns links:

 

É necessário se cadastrar para acessar o conteúdo.
(procurem informações sobre as funções utilizadas no texto)

É necessário se cadastrar para acessar o conteúdo.
... torial.asp

É necessário se cadastrar para acessar o conteúdo.

É necessário se cadastrar para acessar o conteúdo.

htp://www.dreamincode.net/code/snippet407.htm

 

Hí um tempo atrís, escrevi um texto abordando o bísico da criação de DLLs em C/C++, caso tenham interesse:

 

É necessário se cadastrar para acessar o conteúdo.
... ?t=8529949

 

 

Caso, ainda, tenha interesse no método de inserir o valor no registro, também hí um pequeno artigo explicando como manipular o registro em C/C++:

 

É necessário se cadastrar para acessar o conteúdo.
... ?t=8529949

 

Bem é isso...

Bye.

Link para o comentário
Compartilhar em outros sites

  • 2 semanas atrás...
Este tópico está impedido de receber novos posts.
 Compartilhar

×
×
  • Criar Novo...

Informação Importante

Nós fazemos uso de cookies no seu dispositivo para ajudar a tornar este site melhor. Você pode ajustar suas configurações de cookies , caso contrário, vamos supor que você está bem para continuar.