Mais um blog inútil.

Coding

Junho 30, 2008

Debugging em Lunix

Arquivado em: assembly, coding — dcoder @ 10:50

O GNU/Lunix, tal como o Goatse, gira todo à volta da abertura. Assim sendo, não existem debuggers decentes para analisar código binário, sem acesso ao código nem symbols disponíveis. É possível configurar o gdb para ser remotamente útil (cf. first post) mas continua a ser incoveniente e pouco funcional, particularmente quando comparado com as ferramentas disponíveis em Windows para o efeito.

É neste contexto que apresento o EDB Debugger. Embora esteja longe de ser uma ferramenta completa para reverse engineering, é um passo em frente quando comparado com as outras ferramentas rudimentares disponíveis.

Este não é um projecto novo, longe disso…a novidade está no facto de desde esta última versão (0.9) este suportar x86-64, o que pelo menos para mim é bastante útil. Faltam, no entanto, algumas funcionalidades essenciais…não existe detecção de x-refs (o plugin incluído ou funciona mal ou não funciona de todo), pelo que temos de constantemente recorrer ao IDA para qualquer coisa séria; o OpcodeSearcher é muito limitado, assim como o StringSearcher (mais uma vez, IDA to the rescue).

Apesar de tudo, bastante melhor que qualquer debugger feito por freetards.

Junho 10, 2008

Idiot alert

Arquivado em: coding, serious-business, useless — dcoder @ 02:42

Pois é, meus amigos.

Há alguns dias deparei-me com isto: http://forum.kaspersky.com/index.php?showtopic=71652

Aparentemente, os bons senhores da Kaspersky acham boa ideia factorizar um módulo de 1024 bits para de alguma forma combater o ransomware gpcode. Boa sorte com os vossos 100 anos de factorização.

E que tal obterem o utilitário que faz a decriptação (paguem ao gajo se for preciso, nós também temos de vos pagar), e extrairem de lá a chave? Sim, já que não percebem de criptografia, ao menos de reverse engineering devem ter umas luzes.

Enfim.

Abril 27, 2008

Amadores

Arquivado em: coding, drama, fail, useless — dcoder @ 01:10

O FiSH é uma valente seca para se compilar - é um facto. Em particular quando se fala em compilá-lo num SO opensores numa arquitectura não x86. A biblioteca MIRACL que aquilo usa é essencialmente o problema aqui. Portanto a escolha lógica é acabar com esta biblioteca e usar uma ligeiramente mais decente.

Agora, a biblioteca em si não é nada má. Para fins criptográficos provê montes de coisas úteis que seriam feitas à mão de outro modo – números aleatórios seguros, curvas elípticas (e construção de boas curvas - poucas bibliotecas são minimamente úteis neste aspecto), além de possuir hashing (SHA-2) e encriptação (AES) incorporados. No entanto, o processo de compilação é absolutamente deixado ao acaso e a documentação é como deixar o Bear Grylls no deserto sem um hotel por perto.

Obviamente eu não fui o primeiro a ter esta ideia. Nos próprios fórums já foi sugerido múltiplas vezes esta mudança, e aparentemente alguém já a fez. Mas vamos lá olhar para este patch com olhos de ver:

int DH1080_gen(char *priv_key, char *pub_key)
{
…..

+ mpz_t mpz_privkey, mpz_prime, mpz_pubkey, mpz_base;
+ gmp_randstate_t randstate;
// #\#\#\#\#\* RNG START #*#*#*#*#*
time((time_t *)&seed);
+ gmp_randinit_default(randstate);
+ gmp_randseed_ui(randstate, seed);
+ mpz_urandomb(mpz_privkey, randstate, 1080);
+ gmp_randclear(randstate);
seed=0;
// #\#\#\#\#\* RNG END #*#*#*#*#*
….

}

Aparentemente o nosso génio, além de utilizar a função errada (deveria ser mpz_urandomm) para gerar números entre 0 e mpz_prime exclusive (mpz_prime sendo o primo que define o grupo onde estamos a trabalhar e por sua vez define a dificuldade do problema no caso de uma implementação em condições), não verifica se a chave pública criada é 0 ou 1 (o que arruinaria ligeiramente a segurança nesse caso estupidamente remoto). Mas aqui a maior falha é utilizar a data do sistema como seed para a chave privada. Sim, todas as chaves possíveis criadas com este patch estão dependentes de um valor de 32 bits (que na prática pode ser reduzido muito mais – é um timestamp). Parece-me que alguém não faz ideia do que está a fazer (aparentemente uma situação generalizada na indústria da segurança, diga-se de passagem).

Mas enfim, não se pode apenas criticar. Com o intuito de parecer ligeiramente menos hipócrita, coloco aqui a minha própria modificação que utiliza um método ligeiramente mais seguro para a geração de chaves (no código original, era criado e seedado um novo csprng por cada troca – qual a necessidade?). Utilizo a cifra ISAAC para a geração de números aleatórios (não se pode ser muito mais judeu que isto, eh?), e esta é alimentada com 256 bytes do /dev/urandom (caso queiram portar para Windows podem facilmente utilizar a RtlGenRandom) misturados com a SHA-256 do blow.ini e do irssi.conf. É então gerado um número e certificamo-nos que este se encontra no intervalo [2; prime1080-1].

Para a aritmética uso a GMP. Alterei apenas o plugin para irssi, mas quaisquer alterações são facilmente movidas para as outras versões. Deixo o licenciamento para quem não tem mais nada em que pensar.

Download

Nota: Se estiverem a usar Ubuntu e não conseguirem compilar, a culpa não é minha.

Nota2: Se são verdadeiramente paranóicos, estão a utilizar a ferramenta errada. A troca de chaves como é implementada no FiSH (puro Diffie-Hellman) é vulnerável a ataques man-in-the-middle, uma vez que não existe qualquer autenticação; se querem algo minimamente seguro, talvez o SILC não seja um mau começo.

Abril 17, 2008

Cracking X-Chat -- part ii

Arquivado em: coding, cracking, drama, fail, useless — dcoder @ 23:21

Aparentemente saiu uma nova versão do xcrap, 2.8.7a. Eu reparei nisto e lembrei-me que houve um post do falso ha uns tempos que falava de como crackar opensores. Infelizmente, não tenho muito tempo por isso vou ser sucinto.

O leitor assíduo facilmente vai descompactar o executável (é uma versão antiga do UPX) e encontrar a função de interesse (sub_4018CD).

Aqui encontramos o algoritmo de verificação, que consiste essencialmente em:

Hash = SHA-1(Linha3|Linha4|Linha4)

E = 0x25F86508483EFD

N = 0xB5BA27D856CCBE6B61CFE96A387D8E265A65897510AE91212634A7397432D1B2407604CAFA9DC77EF29A87B86D938748E0C4921D46C3AC4BCE7E00EECDFCF782DBD0D44C46C9057724CCF7DEDF36924E4683721FF55EDC570C4C71927887D67C1B1488A33E0B3F64160701B2390C3B3F278490B22DE9906A65B9DFBDF4E838870EFD5851DC0B2C94E444E0B1D2DAAA5C6060D3976E170BB8692111E26D178871008AE42EE250A856D2354102B57F560420AC9F89D004AF761341764FBEDD194A27AF6F34B9C0E3A48013734C6CBD3C216CFAD9B1F3DFDB76FE8519C78E3E95F3C4B39006111DE983C88D72CD4613D4CB852D36244D7B8D4AB15C740415382735

GoodSignature = 00 01 FF FF … (tem de ter 256 bytes (2048 bit) … FF FF 00 30 21 30 09 06 05 2B 0E 03 02 1A 05 00 04 14 | Hash

if (Linha2 ^ E (mod N) == GoodSignature) return GOOD else return BAD

OK, então temos basicamente uma assinatura digital baseada em RSA com 2048 bits. Não existem exploits óbvias (padding, expoente baixo, …) que se possam aproveitar; portanto, para fazer um keygen temos de alterar a chave pública. Escolham uma e substituam no sítio apropriado (public_key_n). Para gerar uma chave válida, temos então:

void generate_key(void)

{

char LInha1[] = “# Designed and implemented exclusively for the lulz”;

char Linha2[1024];

char Linha3[] = “Some Jew”;

char Linha4[] = “Crap”;

char Linha5[] = “More crap”;

HCRYPTPROV hProv;

HCRYPTHASH hHash;

unsigned char appendage[] = {00, 30, 21, 30, 09, 06, 05, 2B, 0E, 03, 02, 1A, 05, 00, 04, 14};

unsigned char good_signature[256];

unsigned char sha[32];

unsigned long tmp = 20;

mpz_t n, d, c;

memset(Linha2, 0, sizeof(Linha2)*sizeof(Linha2[0]));

CryptAcquireContext(&hProv, 0, 0, 1, 0xF0000000);
CryptCreateHash(hProv, 0x00008004, 0, 0, &hHash);
CryptHashData(hHash, Line3, strlen(Line3), 0);
CryptHashData(hHash, Line4, strlen(Line4), 0);
CryptHashData(hHash, Line5, strlen(Line5), 0);
CryptGetHashParam(hHash, 2, sha, &tmp, 0);
CryptDestroyHash(hHash);
CryptReleaseContext(hProv, 0);

memset(good_signature, 0xFF, 256);

memcpy(good_signature+220, appendage, sizeof(appendage));

memcpy(good_signature+236, sha, 20);

good_signature[0] = 0;

good_signature[1] = 1;

mpz_init_set_str(n, “9AFF449090074D691910719D0B384FDA86FAB987938E74CB6E6A91BE6086A8E11BDBD2EF7C1F3761EEBC3AB171F2FB9A79BD8A3CFBAD54A707F39FB8E804A0F4874447BE66550E9D444C496D251FF2402DC8DBAD7352124633F5CAF43A3971362B4466F28AAB1C2A1E81F36B8EE5E6284DD9645E500083B0B9102D559A57A52F0E831F7B39B630DC9B479E3914F34F33363A2075F372E650B94D230528A998D1613C097D78C1C66AE647E0DCF9590E3CA012C3A26614F851AE520163699044F6E8F71B8EDA7091DFDB4745FE27A806EF56E6B7B7175B7859B1725ACF6A03CC941DFED8773AA02DF350C3C0479744411B7F1CD625F5BF4F76E38DD42AC4901A89”, 16);

mpz_init_set_str(d, “36C70BF3DDBD70026346284E9E40E0B1637DD2FF8506F959772CBCEE7F2613A8697D8B822C6849753541DFAECA891A50C0F515E42F1BC8DFF2F48452BA27D29602E572DC9676512F1631AEF655C8F37C03C9E9E5E532CABE4ABD0E0495FA1556AC484D2F5F6E8AF08F934C80CC8D0369215FA2E5F73C0648509867BE61B766C716D84934F76699FAD81EC04E78E88CCC592D59B183361F35B2F3A0F2FEDC17F94F73831111984E5AB2AFCCC019090E4A48AB6CFE249066EFA6D02A4A9EA8369E60EF45A2CC921AE66C52CA1D273EB0355BAC9FD7598258FF94ED311100E732D22224B3744C3ABBB6BA4995781B8427D2BBF605488AC20E19483C10894283506D”, 16);

mpz_init(c);

mpz_powm(c, c, d, n);

printf("%s\n", Linha1);

gmp_printf("%Zd\n", c);

printf("%s\n", Linha3);

printf("%s\n", Linha4);

printf("%s\n", Linha5);

mpz_clear(n);

mpz_clear(d);

mpz_clear(c);

}

Disclaimer: este código foi feito de cabeça e nem sequer o tentei compilar. Se não funcionar, DESCUBRAM porquê!

Note-se que o autor implementou duas verificações para prevenir a alteração do executável (e assim também, da chave).

Primeira:

UPX0:004081EE loc_4081EE: ; CODE XREF: sub_4081BA+45j
UPX0:004081EE movzx edi, ds:public_key_n[ecx]
UPX0:004081F5 add edi, edx
UPX0:004081F7 shl edi, 1
UPX0:004081F9 inc ecx
UPX0:004081FA cmp ecx, 40h
UPX0:004081FD mov edx, edi
UPX0:004081FF jb short loc_4081EE
UPX0:00408201 cmp edx, 0B3A690A6h
UPX0:00408207 pop edi
UPX0:00408208 jz short loc_40822B

Segunda:

UPX0:00425A7A loc_425A7A: ; CODE XREF: sub_425A14+74j
UPX0:00425A7A movzx edx, byte ptr [eax]
UPX0:00425A7D imul ecx, 1Fh
UPX0:00425A80 add ecx, edx
UPX0:00425A82 dec eax
UPX0:00425A83 cmp eax, offset sub_401000
UPX0:00425A88 jnz short loc_425A7A
UPX0:00425A8A cmp ecx, 1D9AB667h
UPX0:00425A90 jz short locret_425A98

Certifiquem-se que corrigem isto quando alterarem o executável.

Já agora, a IDB comentada.

Um bem haja para todos.

Fevereiro 17, 2008

Wonder Shaper GUI

Arquivado em: coding, linux — amg @ 16:20

Isto é um GUI que fiz para oferecerem às vossas namoradas para elas configurarem o wonder shaper sem terem muito trabalho.

Ler o README para mais detalhes.

Wonder Shaper GUI

Fevereiro 5, 2008

Conceito dum sistema de permissoes

Arquivado em: coding, useless — armorfist @ 13:10

Oix caros blogfags.
Hoje vou mostrar aqui um método de gestão de permissões com base de dados. Não vou dar nada em concreto, apenas a teoria.
Imaginemos que temos o saite separado em módulos, e queremos um sistema de permissões que suporte grupos que depois estarão associados a utilizadores.

Carreguem ali naquele botão MOAR para verem o resto.

Temos o módulo " noticias", " blogs", " morte" e " lulz". Grupo chamado " Admin" tem acesso ao modulo de " noticias", " blogs", " morte" e " lulz" enquanto o grupo " Doslulz" apenas tem acesso ao modulo " lulz" e o grupo " Damorte" apenas tem acesso ao modulo " morte". Cada utilizador poderá fazer parte de 1 ou mais grupos, sendo que se fizer parte do grupo " Admin" terá acesso aos módulos " noticias", " blogs", " morte" e " lulz", se fizer parte do grupo " Doslulz" e o grupo " Damorte" terá acesso aos módulos " lulz" e " morte" respectivamente. Uma das maneiras de fazer isto com base de dados é ter 3 tabelas, uma para guardar os módulos, outra para guardar os grupos, e outra para guardar os utilizadores que pertencem aos grupos.

Exemplo:
Tabela Modulos:
id_modulo
nome

Tabela Grupos:
id_grupo
nome
acessos

Tabela Membros_do_grupo:
id_membro
grupos

Existe uma operação muito fofa que se chama “Bitwise AND” representado em sql pelo operador " &" que funciona da seguinte forma:

Em binário: 2 = 1 0, 4 = 100, 6 = 1 1 0
O bit a 1 do 2 também esta a 1 no 6, logo 2 está contido em 6

Outro exemplo:
Em binário: 32 = 1 00000, 8 = 1 000, 32+8 = 40 = 1 0 1 000
O bit a 1 de 32 também está a 1 no 40, e o bit a 1 de 8 também está a 1 em 40, logo estão ambos contidos em 40.

(Obrigado Dcoder pela explicação)

Desta forma, usamos potências de 2 para os ID’ s dos módulos e grupos, e guardamos a soma dos ID’ s na coluna " acessos" e " grupos" da tabela grupos e membros respectivamente.

Exemplo:

Tabela Modulos:
---
id_modulo = 2
nome = “noticias”
---
id_modulo = 4
nome = “blogs”
---
id_modulo = 8
nome = “morte”
---
id_modulo = 16
nome = “lulz”
--- Tabela Grupos:
---
id_grupo = 2
nome = “Admin”
acessos = 30 (2+4+8+16) ---
id_grupo = 4
nome = “Doslulz”
acessos = 16
---
id_grupo = 8
nome = “Damorte”
acessos = 8

Tabela Membros_do_grupo:
id_membro = 1
grupos = 2 (tem acesso ao grupo “Admin”) ---
id_membro = 2
grupos = 12 (4+8 tem acesso ao grupo “Doslulz” e “Damorte”)

De seguida poderemos fazer uma query do estilo:

SELECT Modulos.nome,Grupos.nome
FROM Membros_do_grupo
LEFT JOIN Grupos
ON Grupos.id_grupo & Membros_do_grupo.grupos
LEFT JOIN Modulos
ON Modulos.id_modulo & Grupos.acessos
WHERE Membros_do_grupo.id_membro = 2

Esta query iria dar o resultado que o utilizador id 2 pertencia ao grupo " Doslulz" e " Damorte" e consequentemente tinha acesso ao modulo " lulz" e " morte".

Isto é tudo muito bonito, mas o problema com as potencias é que crescem exponencialmente, como podem observar no gráfico abaixo.

Grafico exponencial

Gráfico da função exponencial base 2

Para terem uma ideia, se tivermos 30 módulos, o modulo numero 30 irá ter o ID 2^30 que é nada mais nada menos que 1073741824. Isto sem contar que teremos de somar o ID de todos os módulos para guardar na coluna acessos da tabela grupos, que se fossem 30, poderia chegar ao número 2147483646 ( ITS OVER NINE THOUSAAAAAAAAND).
È ai que entram os logaritmos. Para quem não tem mais que o 9º ano, um logaritmo de x com base b dá o numero pelo qual teríamos de elevar b de forma a dar x, ou seja: y = logb(x) é equivalente a x=b^y. Ainda não perceberam? Ok. log2(16) = 4 é equivalente a 2^4 = 16. Não é muito difícil.
Se formos ver o gráfico do logaritmo vemos que ele cresce mais lentamente que o da exponencial:

Gráfico logaritmo
Gráfico da função logarítmica, vermelho representa a base e, verde representa a base 10 e roxo representa a base 1.7

Então em vez de guardar o ID do módulo em forma de potencia de 2, guardamos o logaritmo base 2 desse numero:

Tabela Modulos:
---
id_modulo = 1 (log2(2))
nome = “noticias”
---
id_modulo = 2 (log2(4))
nome = “blogs”
---
id_modulo = 3 (log2(8))
nome = “morte”
---
id_modulo = 4 (log2(16))
nome = “lulz”
---

Para fazer os grupos, teremos de fazer a soma dos ID’s dos módulos em formato de potencia de 2, mas desta vez, depois da soma, aplicamos aqui também a função logarítmica base 2, reduzindo drasticamente o numero:

Tabela Grupos:
---
id_grupo = 1 (log2(2))
nome = “Admin”
acessos = 4.907 (arredondado para cima a 3 casas decimais) (2+4+8+16 = 30 -> log2(30) = 4.907 ) ---
id_grupo = 4 (log2(16))
nome = “Doslulz”
acessos = 4 (log2(16)) ---
id_grupo = 3 (log2(8))
nome = “Damorte”
acessos = 3 (log2(8)) Tabela Membros_do_grupo:
id_membro = 1
grupos = 1 (log2(2)) ---
id_membro = 2
grupos = 3.585 (4+8 = 12 tem acesso ao grupo “Doslulz” e “Damorte” -> log2(12) = 3.585 )

E finalmente a query que viram em cima um pouco modificada para este sistema funcionar:

SELECT Modulos.nome,Grupos.nome
FROM Membros_do_grupo
LEFT JOIN Grupos
ON POW(2,Grupos.id_grupo) & CEILING(POW(2,Membros_do_grupo.grupos))
LEFT JOIN Modulos
ON POW(2,Modulos.id_modulo) & CEILING(POW(2,Grupos.acessos))
WHERE Membros_do_grupo.id_membro = 2

Os valores guardados na base de dados ficam drasticamente reduzidos, e a conversão é feita na própria query através da função POW(x,y), que eleva x a y. CEILING é para arredondar o numero para cima para as colunas grupos e acessos darem números inteiros. Apesar de parecer que irá ter perdas de performance em questão de processamento, esta query é tão ou mais rápida a executar que uma query simples de SELECT. Por exemplo com 10 módulos, demora cerca de 0.004 segundos a executar, o que é insignificante.

Fim. Espero que percebam e que isto seja útil. (ao contrario dos posts do Dcoder, que ninguém percebe nada, e tudo é inútil) (amo-te mt Dcoder)

Bjs

Copyright (C) 2008  Armorfist

This information is free: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This information is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this article.  If not, see http://www.gnu.org/licenses/.

Janeiro 29, 2008

Gerador de Galeria de imagens HTML (Python)

Arquivado em: coding, work — amg @ 18:28

É um script que fiz em Python para gerar uma galeria de fotos em html a partir de um directório com fotos, pois precisava de o fazer porque tinha um directório com várias fotos e “colocar” uma foto de cada vez em código html é trabalhoso, por isso aproveitei uma biblioteca de Python e pus mãos à obra.

A minha primeira dificuldade foi certamente criar uma thumbnail da imagem em questão, por isso dei uma visita ao Google (http://www.google.pt) e rapidamente encontrei o que queria: Python Imaging Library (http://www.pythonware.com/products/pil/). É óbvio que não sabia como trabalhar com este, então disse a mim mesmo: RTFM, fi-lo e em questão de minutos já sabia minimamente o que queria.

Primeiro de tudo tive que indicar que imagem abrir, para isto atribuí a uma variável o resultado de

Image.open(imagem)

Em que imagem será uma variável com o caminho da foto/ficheiro.

Também declarei outra variável: THUMBSIZE, em que atribuí a esta a largura e altura da thumbnail (230x153), mais propriamente o valor 230,153. Após isto utilizei a função

Thumbnail

da biblioteca PIL (Python Imaging Library) para a criar, que tem a seguinte sintaxe:

Img (esta foi uma variável criada por mim em que terá como valor o resultado de image.open(imagem) –

img.thumbnail(THUMBSIZE)

OK. Já tenho a thumbnail da imagem, agora tenho que a salvar… mas há um problema: Imaginemos que o utilizador do script já o correu anteriormente, mas agora acrescentou mais imagens, só que as thumbnails das imagens já existentes encontram-se no directório… como fazer para não criar uma thumbnail de uma thumbnail?

É simples, basta utilizar um if para verificar se as primeiras 5 letras da variável imagem são constituídas pela palavra thumb

If imagem[0:5] != “thumb”:

Após esta verificação, caso o resultado seja Verdadeiro e não Falso, o script vai executar o que vem a seguir a esta condição:

Img.save(’thumb.’ + str(imagem), “JPEG”)

Ou seja, o ficheiro ficará: thumb.Foto1.JPG note-se aqui o uso da função str() para converter o valor de imagem para uma string (cadeia de caracteres alfanuméricos). Basicamente a função save do PIL é para salvar num ficheiro as alterações feitas à imagem.

E pronto, temos o problema de criar as thumbnails resolvido.

Aqui abaixo segue-se o código completo do script.

galeria.txt

Tive que o colocar num ficheiro porque não sei mandar o wordpress ignorar tags html.

Nota: As tags html do código não estão terminadas porque fiz isto um pouco à pressa.

Janeiro 20, 2008

Conversor de Binário para Decimal

Arquivado em: coding, useless — amg @ 21:34

O sadik pediu-me para não postar mais, mas vou postar…

Este é um programinha que fiz o ano passado em Programação (Pascal), era para se utilizar operações com strings mas utilizei o método (010 = 0 * 2 ^ 0 + 1 * 2 ^ 1 + 0 * 2 ^ 2 = 2)
O código é estranho, até usei uns ifs que não sei porquê, mas resolveram os problemas que tinha (caso o último número fosse 0 acrescentava um valor: 010 ficava 3, 0100 ficava 5, mas já 011 ficava 3 e 0101 ficava 5):

Program bin_dec;

    function expoente(x,y:longint):longint;
        var
            z,n:longint;
    begin
        n := x;
        for z := 2 to y do
            n := n * x;
        expoente := n;
    end;

    var
        num, aux, multi, digito, valor, soma:longint;
        exp:integer;
    begin
        write('Num (bin): ');
        readln(num);
        multi := 10;
        aux := num;
        exp := 0;
        soma := 0;
        while (aux <> 0) do
        begin
            digito := aux mod 10;
            aux := aux div 10;
            multi := multi * 10;
            if (exp = 0) and (digito = 1) then
            begin
                soma := 1;
                exp := 1;
            end
            else
            begin
                valor := expoente(2,exp);
                exp := exp + 1;
                soma := soma + digito * valor;
            end;
        end;
        writeln(num,'(bin) = ',soma,'(dec)');
        readln;
    end.

Podem testar com o FPC.

EDIT: Coloquei blocos de identação para o código ficar mais bonito.

Janeiro 11, 2008

Arvorezinha em Asus OLED

Arquivado em: coding, linux, useless — mirage @ 14:42

Não queria deixar de participar na saga das arvorezinhas (pena já não ser natal e fazermos pinheirozinhos). Aqui fica uma arvorezinha desenhada no OLED do Asus G1S, um lcd de 128x32 pixels e programável em Linux.

asusoled_arvorezinha.jpg

Arvorezinha em perl

Arquivado em: coding, useless — devnull @ 12:51

Já que tamos numa de fazer arvorezinhas, aqui vai o meu one liner em perl
$i=1;while($i <=5 ) {print ‘*’ x $i++ . “\n”;}