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.

Injetar Dll em processos (svchost.exe) (pt piratas) 100%


subgg
 Compartilhar

Posts Recomendados

Hi,

 

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 Wink

 

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 Wink

 

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() é:

 

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():

 

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:

 

 

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:

 

 

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:

 

 

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:

 

 

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:

 

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: Selecionar tudo

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 Wink

 

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

Link para o comentário
Compartilhar em outros sites

Tópico muito interessante e muito bem explicado, ótimo para quem deseja realmente saber fazer e como funciona um injector.

Só não intendi porque você postou ele aqui. Só pra ele ser trancado? Lol?

Você postando ele aqui, ninguém vai dar valor, por falta de conhecimento da área xD

Área errada amigo, área correta seria de programação.

Vô pedir pra um moderador mover, já que é um bom tópico.(lá terá gente q valorizará)

Ah, esqueceu de por os créditos/fonte do tuto '-'

Abraço.

 

@off

Acho q já vih esse tuto em algum outro lugar, mas n me recordo rsrs

Interessante que ele faz o injector dele em console :P

Mas ia ser tenso msm fazer um tuto de C com GUI xD

você podia deixar o tópico + organizado colocando os codes em códigos php(butãozinho q tem na formatação de texto) e destacando os comentários importantes :]

Link para o comentário
Compartilhar em outros sites

Tópico em Área Errada, tome mais cuidado antes de criar um tópico, verifique se a área onde você se encontra tem ligação com o assunto do seu tópico.

 

Tópico movido para »PT Tutoriais

 

Membro avisado.

Link para o comentário
Compartilhar em outros sites

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.