Desde pequeno tenho o gosto de desmontar as coisas, eu não tive muitos brinquedos e os poucos que tinha eu desmontava todos. Meu pai devia pensar que eu destroçava os brinquedos, mas eu procurava ver o funcionamento das coisas por dentro e ainda continuo e claro meus brinquedos mudaram.
Quando ganhei meu primeiro computador passei os 3 primeiros meses sem ver a luz do dia literalmente – Era um Positivo com míseros 128mb de RAM mas que rodava o counter-strike – com a falta de instrução, resolvi procurar por mim mesmo com os recursos disponíveis.
Nesses 3 primeiros meses mexi no windows xp de cabo a rabo, como eu não tinha acesso à internet naquela época, lembro que achei o utilitário msconfig olhando arquivo por arquivo na pasta system32. Bons tempos aquele.
Enfim, voltando ao assunto de desmontar, ver como tudo funciona é prazeroso, olhar as coisas se encaixando e funcionando é uma sensação que não consigo explicar. Mas o mal de desmontar as coisas é montar novamente e deixar tudo funcionando como antes – já estraguei muito carrinho assim.
Com o computador não foi diferente, mas é claro que eu não ia violar a garantia abrindo o danado, parti logo para ver como tudo funcionava, abri muitas dlls, muitos exes no bloco de notas e só via coisa estranha, como eu não entendi nada daquilo eu só ficava boiando.
Aprendendo programação, fui entendendo aos poucos como era brilhante e complexo o funcionamento do computador, pelo menos pra mim, me fascinava. Hoje com o conhecimento que tenho vejo que falta muito a aprender.
Mas o que tem a ver desmontar carrinhos e desmontar softwares?
A ideologia é a mesma e o prazer também, mas sem perdas de peças como ocorre no hardware. Com o software quando não dá certo basta reiniciar.
Lembro do primeiro software que violei, era um que mostrava as senhas do antigo MSN, o software era pago e precisava de uma licença pra mostrar a senha por completo. Lembro que fiquei todo bobo com aquilo, e quem não ficaria?
Hoje em dia quebro alguns softwares que utilizo, como o conversor de dvd e um servidor dlna.
É errado? Pode ser que sim. Mas tudo que é errado é mais legal. ;)
Então se você é pai e leu isso, quando ver seu filho desmontando um carrinho, ajude-o e mostre como aquilo funciona, pois seu pequeno garoto pode virar um grande profissional em engenharia reversa. E o mercado paga muito bem para esses profissionais.
Para terem uma idéia existe um filme chamado "O Pagamento (Paycheck)", o ator principal é uma especialista em engenharia reversa onde ele cria uma máquina que prever o futuro.
Att, Gilson Fabiano
segunda-feira, 24 de junho de 2013
segunda-feira, 11 de março de 2013
Sublime Text 2/3 Build 2126-3019 + Patch
Sublime Text 3
Lançado apenas para membros registrados (até o momento), tras novos recursos e melhorias que podem ser conferidas no site oficial. O build atual é 3019 que pode ser baixado aqui (windows x86).Sublime Text 2
O nosso querido Sublime Text 2 se graduou saindo do Beta. Seu Build atual é 2217 (versão 2.0.1).Você pode baixar a nova versão do Sublime Text 2 por aqui.
Patch
O patch agora é multi versão desde o build 2126 até o atual 3019, mas apenas suportando versões do windows para arquitetura x86 (32 bits).Acesse aqui e baixe o patch!
Em caso de dúvidas entre em contato por aqui.
Att, Gilson Fabiano
domingo, 3 de março de 2013
C++, Barra de progresso nos botões da barra de tarefas no Windows 7.
Deixar o character "afk" as vezes fica um tanto complicado, ainda mais quando PK'lowlevel ta sem nada pra fazer. Como o cliente não dá a opção de mostrar na barra de tarefa a vida do personagem, resolvi implementar.
No começo foi trabalhosso devido ao pacote do compilador não ter incluso os headers necessários e por eu não ter usado o CoInitialize() corretamente. Depois de muitas horas, tentativas e pesquisas descobri que não estava iniciando a biblioteca COM(por isso o EAX ficava com o cara de tacho). Mas graças ao todo poderoso oráculo (vulgo google) tudo se encaixou.
Vamos dá uma olhada num exemplo e ver como implementar esse estilo em uma janela do bloco de notas aberta.
Recomendo o link onde o autor faz uma introdução de COM e explica o que é e como usar (texto em inglês).
Att, Gilson Fabiano.
No começo foi trabalhosso devido ao pacote do compilador não ter incluso os headers necessários e por eu não ter usado o CoInitialize() corretamente. Depois de muitas horas, tentativas e pesquisas descobri que não estava iniciando a biblioteca COM
Vamos dá uma olhada num exemplo e ver como implementar esse estilo em uma janela do bloco de notas aberta.
#include <windows.h>
#include <shobjidl.h>
const GUID my_IID_ITaskbarList3 =
{ 0xea1afb91, 0x9e28, 0x4b86, { 0x90, 0xe9, 0x9e, 0x9f, 0x8a, 0x5e, 0xef, 0xaf } };
const GUID my_CLSID_TaskbarList =
{ 0x56fdf344, 0xfd6d, 0x11d0, { 0x95, 0x8a, 0x00, 0x60, 0x97, 0xc9, 0xa0, 0x90 } };
ITaskbarList3* ptbl = NULL;
int main()
{
// inicia a biblioteca
CoInitialize(NULL);
// cria a instancia para a interface ITaskbarList3
CoCreateInstance(my_CLSID_TaskbarList, NULL, CLSCTX_INPROC_SERVER, my_IID_ITaskbarList3, (LPVOID*)&ptbl);
// procura por uma janela do bloco de notas
HWND hWindow = FindWindow("Notepad", NULL);
ptbl->SetProgressState(hWindow, TBPF_ERROR);
ptbl->SetProgressValue(hWindow, 40, 100);
return 0;
}
Recomendo o link onde o autor faz uma introdução de COM e explica o que é e como usar (texto em inglês).
Att, Gilson Fabiano.
quinta-feira, 14 de fevereiro de 2013
C++, Chamando endereços como se fossem funções
Quando se usa uma dll injetável ou algum outro código, saber o endereço da função não é o suficiente - as vezes. Para evitar de códigos em asm massivos em seu código fonte podemos criar um tipo da função ou simplesmente usar uma sintaxe.
type-return ([modifier] *[variable])([type , [type , [type , ...]]])
ou
Att, Gilson Fabiano
Sintaxe
type-return ([modifier] *[variable])([type , [type , [type , ...]]])
Veja
void (*variavel)(int, int, char); // declara a variavel variavel = (void(*)(int, int, char))0x00FF00FF; // atribui o valor do seu endereço a ser chamado variavel(10, 20, 6);
ou
( (void(*)(int, int, char)) 0x00FF00FF ) (10, 20, 6);
Código de exemplo
void function1(int x, int y, char z)
{
printf("Function1 - X: %d, Y: %d, Z: %d\n", x, y, z);
}
int function2(int x, int y, char z)
{
printf("Function2 - X: %d, Y: %d, Z: %d\n", x, y, z);
return (x + y + z);
}
int main()
{
void(*f1)(int, int, char);
int (*f2)(int, int, char);
f1 = &function1;
f2 = &function2;
f1(1,2,3);
int result = f2(4,5,6);
printf("Result: %d", result);
return 0;
}
Att, Gilson Fabiano
segunda-feira, 21 de janeiro de 2013
C++, Trabalhando com flags (bits)
Trabalhar com 32 bits é fácil num compilador x86, mas quando isso
Segue as funções
set_flag seta bit 1, remove_flag seta bit 0 e has_flag verifica se o bit é 1. O indice usado é 0. A função não verifica estouro de memória, portando cuidado!
variavel = 1 << 33;torna-se inpertinente as coisas começam a ficar sérias. Em prol disso fiz algumas funções que sanam essa necessidade (não que o bitset não o faça) de trabalhar com mais de 32 bits (agora o flag é infinito filhote).
Segue as funções
void set_flag(char *flags, int flag)
{
flags[ (int)((float)(flag +1) / 8.0) ] |= (1 << (flag % 8));
}
void remove_flag(char *flags, int flag)
{
flags[ (int)((float)(flag +1) / 8.0) ] ^= (1 << (flag % 8));
}
bool has_flag(char *flags, int flag)
{
return (int)flags[ (int)((float)(flag +1) / 8.0) ] & (1 << (flag % 8));
}
set_flag seta bit 1, remove_flag seta bit 0 e has_flag verifica se o bit é 1. O indice usado é 0. A função não verifica estouro de memória, portando cuidado!
Exemplo
char flags[1] = {0}; // 1 byte = 8 bits
set_flag((char*)flags, 1); // liga o segundo bit
set_flag((char*)flags, 2); // liga o terceiro bit
printf("%d\n", has_flag(flags, 0) )
printf("%d\n", has_flag(flags, 1) )
quarta-feira, 4 de julho de 2012
Variáveis anônimas no C++
Procurando por uma referência de uma app que baixei pro meu novo celular com android ;D~, na dropdown do google aparece "c++ anonymous objects", como nunca tinha visto isso resolvi ver quais seriam os resultados.
O primeiro resultado que aparece é do learncpp, esse: http://www.learncpp.com/cpp-tutorial/814-anonymous-variables-and-objects/, no texto o autor fala:
Então é criado uma variável anônima? Como sou muito curioso resolvi por a prova.
Compilei as seguintes funções usando o compilador GCC 4.6.1 sem nenhum parâmetro de aumento de performace:
Eis seus códigos em máquina:
Agora cadê a variável criada no add(int x, int y)? Se olharmos bem no registrador EAX é posto o valor y, no EDX é posto o valor x e por final é adicionado EDX ao EAX, só isso!
No add2(int x, int y) acontece o mesmo, mas só que no final há uma referência a nossa variável int tmp, após os cálculos a variável tmp vai pra pilha MOV DWORD PTR SS:[EBP-4, EAX e logo em seguida é colocada no registrador de retorno EAX.
Analizando meus dados acima é de fato que não existem variáveis anônimas(não no meu compilador), não as que ele disse. Mas pode ocorrer de existir, não sei, vai saber!
Att, Gilson Fabiano
O primeiro resultado que aparece é do learncpp, esse: http://www.learncpp.com/cpp-tutorial/814-anonymous-variables-and-objects/, no texto o autor fala:
Quando a expressão nX + nY é avaliado, o resultado é colocado em uma variável anónima e sem nome. Uma cópia da variável anónima é retornado para o chamador por valor.
Então é criado uma variável anônima? Como sou muito curioso resolvi por a prova.
Compilei as seguintes funções usando o compilador GCC 4.6.1 sem nenhum parâmetro de aumento de performace:
int add(int x, int y)
{
return x + y;
}
int add2(int x, int y)
{
int tmp = x + y;
return tmp;
}
Eis seus códigos em máquina:
// add(int x, int y) PUSH EBP MOV EBP,ESP MOV EAX,DWORD PTR SS:[EBP+0C] MOV EDX,DWORD PTR SS:[EBP+8] ADD EAX,EDX POP EBP RETN // add2(int x, int y) PUSH EBP MOV EBP,ESP SUB ESP,10 MOV EAX,DWORD PTR SS:[EBP+0C] MOV EDX,DWORD PTR SS:[EBP+8] ADD EAX,EDX MOV DWORD PTR SS:[EBP-4],EAX MOV EAX,DWORD PTR SS:[EBP-4] LEAVE RETN
Agora cadê a variável criada no add(int x, int y)? Se olharmos bem no registrador EAX é posto o valor y, no EDX é posto o valor x e por final é adicionado EDX ao EAX, só isso!
No add2(int x, int y) acontece o mesmo, mas só que no final há uma referência a nossa variável int tmp, após os cálculos a variável tmp vai pra pilha MOV DWORD PTR SS:[EBP-4, EAX e logo em seguida é colocada no registrador de retorno EAX.
Analizando meus dados acima é de fato que não existem variáveis anônimas
Att, Gilson Fabiano
quarta-feira, 25 de abril de 2012
Injetando funções em aplicações
Veremos aqui uma técnica muito comum entre programadores de trainers/bots/macros que é a injeção de códigos em aplicações já compiladas sem alterar o estado fisíco do arquivo da aplicação. Caso queira pesquisar mais sobre o assunto procure por "inject dll", "hook function" e ainda "hooking function" tendo em base o "hook".
A aplicação que iremos modificar têm o seguinte código fonte:
Continuando...
Iremos injetar um código que imprima na tela "You number entered are: <numero digitado>" toda vez que a get_number() for chamado. Para isso precisaremos saber os endereços da printf e a variável T na memória (O depurador usado aqui é o ollydbg).
Na janela "search" procure por printf e siga sua referência.
Iremos nos deparar com nossa função get_number(), apertando a tecla espaço iremos ver o endereço que se refere a printf, que no nosso caso é 0x00401A8C.
Agora falta só o endereço da variável T. Se olharmos direito veremos o endereço após a chamada da printf, onde começa as instruções da scanf, que é a referência da váriavel e o formato que iremos extrair. Então, BINGO! Temos também o endereço da variável T que no nosso caso é 0x00404008.
Analizando as instruções
Encontramos um lugar perfeito para injetar nosso código, olhe bem no endereço 0x00401B4D a instrução MOV EAX, DWORD PTR DS:[program.404008] ela ocupa 5 bytes, a quantidade que precisamos.
Nota: Iremos sobrepor a instrução e adiciona-la em nosso código para não quebrar o fluxo original do programa.
Primeiro nosso código a ser injetado.
Nossas funções de injetar e alocar os dados na memória.
Dando uma atenção em *(PDWORD)&JMP[1] = funaddr - address - 5. Como o JMP é relativo a sua posição atual, é subtraido da posição de destimo a posição atual mais os 5 bytes da instrução. O resto do código é alto explicativo.
Faltando apenas nossa função principal, o main:
Dando a atenção devida em WriteProcessMemory(hProc, funaddr + 0x0F, &straddr, 4, NULL), onde mudaremos o endereço para nosso texto alocado anteriormente. Para entender o porque o do funaddr + 0x0F veja a imagem do nosso código compilado e alocado:
Olhe a quantidade de bytes que temos que pular até chegar no endereço que queremos mudar. 15 bytes sendo 0x0F o mesmo que 15 em hexadecimal. Sendo assim temos a posição da função alocada mais 15 bytes.
Att, Gilson Fabiano
A aplicação que iremos modificar têm o seguinte código fonte:
#include <stdio.h>
#include <stdlib.h>
int T;
void get_number()
{
printf("Enter Number: ");
scanf("%d", &T);
}
int main()
{
system("title my program");
do
{
get_number();
}
while (T);
return 0;
}
Nosso programa pede um número de entrada, caso esse número seja 0 ele sai, do contrário repete, e assim sucessivamente. Certo?Continuando...
Iremos injetar um código que imprima na tela "You number entered are: <numero digitado>" toda vez que a get_number() for chamado. Para isso precisaremos saber os endereços da printf e a variável T na memória (O depurador usado aqui é o ollydbg).
Descobrindo os endereços
Para descobrirmos o endereço da função printf, vá em Search for > All intermodular calls,Na janela "search" procure por printf e siga sua referência.
Iremos nos deparar com nossa função get_number(), apertando a tecla espaço iremos ver o endereço que se refere a printf, que no nosso caso é 0x00401A8C.
Agora falta só o endereço da variável T. Se olharmos direito veremos o endereço após a chamada da printf, onde começa as instruções da scanf, que é a referência da váriavel e o formato que iremos extrair. Então, BINGO! Temos também o endereço da variável T que no nosso caso é 0x00404008.
Procurando um local para injetar
Precisamos saber também onde iremos injetar nosso código para que fique similar a:do
{
get_number();
printf("You number entered are: %d", T);
}
while (T);Analizando as instruções
Encontramos um lugar perfeito para injetar nosso código, olhe bem no endereço 0x00401B4D a instrução MOV EAX, DWORD PTR DS:[program.404008] ela ocupa 5 bytes, a quantidade que precisamos.
Nota: Iremos sobrepor a instrução e adiciona-la em nosso código para não quebrar o fluxo original do programa.
Fazendo os códigos
Agora que temos os endereços e o local onde iremos injetar, só codificar!Primeiro nosso código a ser injetado.
typedef void t_call(...);
#define _printf(...) ((t_call*)0x00401A8C)(__VA_ARGS__) // nossa printf
int get_number_hook()
{
asm(".intel_syntax noprefix\n"); // muda a sintaxe pro intel
// adicionar -masm=intel no build
_printf((char*)0xFFFFFFFF, *((int*)0x00404008)) // nossa chamada, com a variavel T
asm("mov eax, dword ptr ds:[0x404008]"); // instrução sobreposta pelo nosso jmp
asm("mov edx, 0x00401B52");
asm("jmp edx");
}
void get_number_hook_end(){}; // apenas para saber onde o get_number_hook termina
Nossas funções de injetar e alocar os dados na memória.
void hook(HANDLE hProc, DWORD address, DWORD funaddr) // injeta nosso código
{
char JMP[5] = {0};
JMP[0] = 0xE9;
*(PDWORD)&JMP[1] = funaddr - address - 5;
DWORD OldProtect;
VirtualProtectEx(hProc, address, 5, PAGE_EXECUTE_WRITECOPY, &OldProtect);
WriteProcessMemory(hProc, address, &JMP, 5, NULL);
VirtualProtectEx(hProc, address, 5, OldProtect, NULL);
}
DWORD alloc(HANDLE hProcess, PVOID pointer, DWORD size) // aloca os dados
{
LPVOID addr = VirtualAllocEx(hProcess, 0, size, MEM_COMMIT | MEM_RESERVE ,PAGE_EXECUTE_READWRITE);
WriteProcessMemory(hProcess, addr, pointer, size, NULL);
return addr;
}Dando uma atenção em *(PDWORD)&JMP[1] = funaddr - address - 5. Como o JMP é relativo a sua posição atual, é subtraido da posição de destimo a posição atual mais os 5 bytes da instrução. O resto do código é alto explicativo.
Faltando apenas nossa função principal, o main:
int main()
{
DWORD pID;
HWND hWnd = FindWindow(NULL, "my program");
if (hWnd && GetWindowThreadProcessId(hWnd, &pID))
{
HANDLE hProc = OpenProcess(PROCESS_ALL_ACCESS, 0, pID);
if (hProc)
{
DWORD straddr, funaddr;
printf("HWND: %d\n" , hWnd );
printf("PID: %d\n" , pID );
printf("HANDLE: %d\n", hProc);
printf("Injetando get_number_hook()");
char *my_str = "You number entered are: %d\n";
// aloca nosso texto e retorna o endereço
straddr = alloc(hProc, my_str, strlen(my_str));
// aloca nosso código e retorna o endereço
funaddr = alloc(hProc, &get_number_hook, (DWORD)((DWORD)&get_number_hook_end - (DWORD)&get_number_hook));
// lembra do _printf((char*)0xFFFFFFFF...) ?
// muda ao endereço do 0xFFFFFFFF para nosso texto
WriteProcessMemory(hProc, funaddr + 0x0F, &straddr, 4, NULL);
// injeta nosso código em 0x00401B4D
hook(hProc, 0x00401B4D, funaddr);
CloseHandle(hProc);
}
}
return 0;
}Dando a atenção devida em WriteProcessMemory(hProc, funaddr + 0x0F, &straddr, 4, NULL), onde mudaremos o endereço para nosso texto alocado anteriormente. Para entender o porque o do funaddr + 0x0F veja a imagem do nosso código compilado e alocado:
Olhe a quantidade de bytes que temos que pular até chegar no endereço que queremos mudar. 15 bytes sendo 0x0F o mesmo que 15 em hexadecimal. Sendo assim temos a posição da função alocada mais 15 bytes.
Downloads
Código fonte e executáveis (5kb)Conclusão
Muitas coisas podem ser feita com essa técnica, o que mostrei aqui foi apenas o básico. Boa sorte em suas aplicações. ;)Att, Gilson Fabiano
Assinar:
Postagens (Atom)




