Mais um blog inútil.

Assembly

Dezembro 14, 2010

Árvorezinha 2.0

Arquivado em: arvorezinha, assembly, coding, drama, useless — falso @ 01:07

Ora viva amigos!

Há uns tempos no trabalho um colega meu começou a fazer pouco das minhas árvorezinhas, a dizer que só eram meia árvore, e que eu devia era de fazer uma árvore completa. Eu fiquei SENTIDO com tal AFRONTA, e fiquei a MATUTAR sobre isso, até que decidi por mãos à obra, e criar a Árvorezinha 2.0.

Primeiro decidi faze-la em C porque é a linguagem STANDARD!

[sourcecode language="c"]
#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[])
{
        int altura;
        int i,x;
        int lul;

        if (argc < 2)
        {
                return(0);
        }
        altura = atoi(argv[1]);

        /* Ciclo da altura da Arvore */
        for(i = 1; i <= altura; i++)
        {

                /*
                        Numero de Espaços
                        Começa em 0 porque existem linhas com 0 espaços
                        Algoritmo: altura - linha
                */
                for(x = 0 ; x < (altura-i); x++)
                {
                        putchar(' ');
                }

                /*
                        Numero de Asteriscos
                        Começa em 1 porque não existem linhas sem *
                        Algoritmo: (2 * linha) - 1
                */
                for (x = 1; x <= (2*i)-1; x++)
                {
                        putchar('*');
                }

                putchar('\n');
        }

        /* Largura ultima linha */
        lul = (altura * 2) - 1;

        /*
                Ciclo da altura do tronco
                Algoritmo: altura / 2
        */
        for(i = 1; i <= (altura/2); i++)
        {
                /*
                        Por causa do ASCII nao permitir meio char
                        tive de fazer duas implementacoes diferentes,
                        uma para quando o  valor da altura do tronco
                        e' par, e outra para quando e' impar.
                */
                if (altura % 2)
                {
                        /* Impar */

                        /*
                                Numero de Espaços
                                Algoritmo: (lul / 4) - 1
                        */
                        for(x = 0; x <= (lul/4)-1; x++)
                        {
                                putchar(' ');
                        }


                        /*
                                Numero de # (tronco)
                                Algoritmo: lul / 2
                        */
                        for(x = 0; x <= (lul/2); x++)
                        {
                                putchar('#');
                        }

                        putchar('\n');
                }
                else
                {
                        /* Par */

                        /*
                                Numero de Espaços
                                Algoritmo: lul / 4
                        */
                        for(x = 0; x <= (lul/4); x++)
                        {
                                putchar(' ');
                        }


                        /*
                                Numero de # (tronco)
                                Algoritmo: (lul / 2) - 1
                        */
                        for(x = 0; x <= (lul/2)-1; x++)
                        {
                                putchar('#');
                        }

                        putchar('\n');
                }
        }

}

[/sourcecode]

A pedido de muitas famílias, foi me imposta a tarefa de fazer um RFC da nova árvorezinha, mas não tenho muito jeito para escrever algoritmos em pseudo-código. Então tal obra heróica fica para o caro leitor, façam me um baseado no código em C e enviem-me!

Segundo as próprias leis já pré-estabelecidas da Árvorezinha, tem de existir uma implementação em Assembly! Então não podia cá faltar a minha versão em x86 Assembly.

[sourcecode language="plain"]

;
; Arvorezinha 2.0
; x86 Assembly
; Copyright (C) 2010 Pedro de Oliveira
; //blol.org
;
; this assembly can never fail
;
        BITS            32
        GLOBAL          main

; Vou usar duas funcoes da libc para o codigo nao crescer gigantescamente
; com rotinas que nao interessam nada para aqui.
        EXTERN          atoi
        EXTERN          printf

; Definicao das Variaveis
SECTION         .data

        argc    dd      0
        argv    dd      0

        erro    db      "ERRO! Executar: %s <altura da arvore>",10,0

        card    db      '#'
        newl    db      0xa
        aste    db      '*'
        espa    db      ' '

        altura  dd      0
        i       dd      1
        x       dd      0
        lul     dd      0

; He cometh!
SECTION         .text

main:
        pop     eax                     ; Ignorar...

        pop     eax                     ; Saca o argc da Stack
        mov     dword [argc], eax       ; Guarda o valor na variavel argc

        pop     ebx                     ; Saca a posicao de memoria do
                                        ; argv[0] da Stack
        mov     eax, dword [ebx]        ; Mete a posicao em EAX
        mov     [argv], eax             ; Guarda-a em argv

        add     ebx,0x4                 ; Salta 4 bytes para a frente
                                        ; para o argv[1] ficar em EBX

        mov     eax, [argc]             ; Mete o argc em EAX
        cmp     eax, 0x2                ; Verifica se e' diferente de 2
        jne     jafoste                 ; Se for sai com erro

        push    dword [ebx]             ; Mete o valor de argv[1] na Stack
        call    atoi                    ; Corre o atoi com esse valor
        mov     [altura], eax           ; O resultado fica em EAX, guarda
                                        ; na variavel altura

ciclo_linhas:
        ; INICIO - CICLO DAS LINHAS DA ARVORE
        mov     eax, [i]                ; i em EAX
        mov     ebx, [altura]           ; altura em EBX

        cmp     ebx, eax                ; Compara
        jb      prepara_tronco          ; i > altura ? proximo passo
        mov     dword [x], 0            ; Mete x a 0

ciclo_espacos:
        ; INICIO - CICLO DE ESPAÇOS ANTES DOS ASTERISCOS
        mov     eax, [x]                ; x em EAX

        ; pretende-se (altura - i) em EBX
        mov     ebx, [altura]           ; altura em EBX
        mov     ecx, [i]                ; i em ECX
        sub     ebx, ecx                ; EBX - ECX

        cmp     ebx, eax                ; Compara
        jbe     prepara_asteriscos      ; x >= (altura - i) ? proximo passo

        push    espa                    ; Espaço
        call    print                   ; write()

        call    incrementa_x
        jmp     ciclo_espacos           ; Volta para o inicio do ciclo
        ; FIM - CICLO DE ESPAÇOS ANTES DOS ASTERISCOS

prepara_asteriscos:
        mov     dword [x], 1            ; Mete x a 1

ciclo_asteriscos:
        ; INICIO - CICLO DE ASTERISCOS (ARVORE)
        mov     ebx, [x]                ; x em EBX

        ; pretende-se (2 * i) - 1 em EAX
        mov     eax, 2                  ; 2 em EAX
        mov     ecx, [i]                ; i em ECX
        mul     ecx                     ; Multiplica EAX por ECX
        dec     eax                     ; Subtrai 1 a EAX

        cmp     eax, ebx                ; Compara
        jb      fim_ciclo_linhas        ; x > (2*i)-1 ? proximo passo

        push    aste                    ; Asterisco
        call    print                   ; write()

        call    incrementa_x
        jmp     ciclo_asteriscos        ; Volta para o inicio do ciclo
        ; FIM - CICLO DE ASTERISCOS (ARVORE)

fim_ciclo_linhas:
        push    newl                    ; Newline
        call    print                   ; write()

        call    incrementa_i
        jmp     ciclo_linhas            ; Volta para o inicio
        ; FIM - CICLO DAS LINHAS DA ARVORE

prepara_tronco:
        ; pretende-se (altura * 2) - 1 em EAX
        mov     eax, [altura]           ; altura em EAX
        mov     ecx, 2                  ; 2 em ECX
        mul     ecx                     ; Multiplica EAX por ECX
        dec     eax                     ; Subtrai 1 a EAX
        mov     dword [lul], eax        ; Guarda a largura da ultima linha
                                        ; em lul


        mov     dword [i], 1            ; Mete o i a 1

ciclo_linhas_tronco:
        ; BEGIN - CICLO DAS LINHAS DO TRONCO
        mov     ecx, [i]                ; i em ECX

        ; pretende-se (altura / 2)
        mov     eax, [altura]           ; altura em EAX
        shr     eax, 1                  ; divide por 2

        cmp     ecx, eax                ; Compara ECX com EAX
        jg      sair                    ; i > (altura / 2) ? Adeus!

        mov     eax, [altura]           ; altura em EAX
        test    eax, 1
        je      pc_tronco_par_espacos   ; e' par?

; --------------------------- IMPAR -------------------------------
pc_tronco_impar_espacos:
        mov     dword [x], 0            ; Mete-se x a 0

c_tronco_impar_espacos:
        ; INICIO - CICLO DOS ESPAÇOS ANTES DO TRONCO (IMPAR)
        mov     ecx, [x]                ; x em EAX

        ; pretende-se (lul / 4) - 1 em EAX
        mov     eax, [lul]              ; lul em EAX
        shr     eax, 2                  ; Divide por 4
        dec     eax                     ; Subtrai 1

        cmp     eax, ecx                ; Compara
        jb      pc_tronco_impar_cardinal; x > (lul/4)-1 ? Next!

        push    espa                    ; Espaço
        call    print                   ; write()

        call    incrementa_x
        jmp     c_tronco_impar_espacos  ; Volta para o inicio
        ; FIM - CICLO DOS ESPAÇOS ANTES DO TRONCO (IMPAR)

pc_tronco_impar_cardinal:
        mov     dword [x], 0            ; Mete x a 0

c_tronco_impar_cardinal:
        ; INICIO - CICLO DOS CARDINAIS DO TRONCO (IMPAR)
        mov     ecx, [x]                ; x em ECX

        ; pretende-se (lul / 2) em EAX
        mov     eax, [lul]              ; lul em EAX
        shr     eax, 1                  ; Divide por 2

        cmp     eax, ecx                ; Compara
        jb      fim_ciclo_linhas_tronco ; x > (lul/2) ? Next!

        push    card                    ; Cardinal
        call    print                   ; write()

        call    incrementa_x

        jmp     c_tronco_impar_cardinal ; Volta para o inico
        ; FIM - CICLO DOS CARDINAIS DO TRONCO (IMPAR)

; --------------------- FIM IMPAR --------------------------------


; ----------------------------- PAR ------------------------------
pc_tronco_par_espacos:
        mov     dword [x], 0            ; Mete x a 0

c_tronco_par_espacos:
        ; INICIO - CICLO DOS ESPAÇOS ANTES DO TRONCO (PAR)
        mov     ecx, [x]                ; x em ECX

        ; pretende-se (lul / 4) em EAX
        mov     eax, [lul]              ; lul em EAX
        shr     eax, 2                  ; divide por 4

        cmp     eax, ecx                ; Compara
        jb      pc_tronco_par_cardinal  ; x > (lul / 4) ? Next!

        push    espa                    ; Espaço
        call    print                   ; write()

        call    incrementa_x
        jmp     c_tronco_par_espacos    ; Volto para o inico do ciclo
        ; FIM - CICLO DOS ESPAÇOS ANTES DO TRONCO (PAR)

pc_tronco_par_cardinal:
        mov     dword [x], 0            ; Mete x a 0

c_tronco_par_cardinal:
        ; INICIO - CICLO DOS CARDINAIS DO TRONCO (PAR)
        mov     ecx, [x]                ; x em ECX

        ; pretende-se (lul / 2) - 1 em EAX
        mov     eax, [lul]              ; lul em EAX
        shr     eax, 1                  ; Divide por 2
        dec     eax                     ; Subtrai 1

        cmp     eax, ecx                ; Compara
        jb      fim_ciclo_linhas_tronco ; x > (lul / 2) - 1 ? uhuhuh

        push    card                    ; Cardinal
        call    print                   ; write()

        call    incrementa_x

        jmp     c_tronco_par_cardinal   ; Volta para o inicio do ciclo
        ; FIM - CICLO DOS CARDINAIS DO TRONCO (PAR)
; ----------------------- FIM PAR ----------------------------------

fim_ciclo_linhas_tronco:
        push    newl
        call    print

        call    incrementa_i
        jmp     ciclo_linhas_tronco     ; Volta para o inico do ciclo
        ; FIM - CICLO DAS LINHAS DO TRONCO

jafoste:
        mov     eax, [argv]             ; Mete o apontador de argv em EAX
        push    dword eax               ; Mete o endereço de argv na Stack
        push    dword erro              ; Mete o endereço da String na Stack
        call    printf                  ; Escreve no ecra!


sair:
        mov     ebx,0x0                 ; valor de saida
        mov     eax,0x1                 ; sys_exit
        int     0x80

print:
        mov     ecx,[esp+4]             ; Mete o argumento em ECX
        mov     edx,1                   ; Length
        mov     ebx,1                   ; stdout
        mov     eax,4                   ; sys_write
        int     0x80
        ret

incrementa_x:
        mov     eax, [x]
        inc     eax
        mov     dword [x], eax
        ret

incrementa_i:
        mov     eax, [i]
        inc     eax
        mov     dword [i], eax
        ret
[/sourcecode]

E aqui vai a prova dos nove:

[sourcecode language="plain"]
falso@lemonparty:~/src/zbr$ make
rm -f arvore2 arvore.o
nasm -f elf arvore.asm -o arvore.o
gcc -g -o arvore2 arvore.o
falso@lemonparty:~/src/zbr$ ./arvore2 4
   *
  ***
 *****
*******
  ###
  ###
falso@lemonparty:~/src/zbr$ ./arvore2 5
    *
   ***
  *****
 *******
*********
  #####
  #####
falso@lemonparty:~/src/zbr$
[/sourcecode]

Espero lançar futuramente um género de Unit Tests, para testar as varias implementações da Arvorezinha 2.0 que possam surgir, para ver se cumprem o standard ou não.

Espero que tenham gostado do post, até à proxima, fiquem bem e joguem muito! Chuuuuuuack!

Maio 27, 2010

Arvorezinha - HP Precision Architecture (aka PA-RISC aka DEMONIO)

Arquivado em: arvorezinha, assembly, coding, useless — paf @ 16:36

E ca fica mais uma arvorezinha, desta vez numa arquitectura demoniaca.

hpux$ cat arvorezinha.S
        .LEVEL 1.1							; cenas gays do hpux
        .SPACE $PRIVATE$						; o HPPA funciona por spaces, ler arch book
        .SUBSPA $DATA$,QUAD=1,ALIGN=8,ACCESS=31				; pra mais informacoes ou esquizofrenia antecipada
        .SUBSPA $BSS$,QUAD=1,ALIGN=8,ACCESS=31,ZERO,SORT=82
        .SPACE $TEXT$
        .SUBSPA $LIT$,QUAD=0,ALIGN=8,ACCESS=44
        .SUBSPA $CODE$,QUAD=0,ALIGN=8,ACCESS=44,CODE_ONLY
        .IMPORT $global$,DATA
        .IMPORT $$dyncall,MILLICODE
        .IMPORT write,CODE						; eh mais simpatico fazer imports
        .IMPORT exit,CODE
        .IMPORT __main,CODE
        .SPACE $TEXT$
        .SUBSPA $LIT$

        .align 4
STAR
        .STRING "\x2a\x00"
LF
        .STRING "\x0a\x00"
        .SPACE $TEXT$
        .SUBSPA $CODE$

        .align 4
        .NSUBSPA $CODE$,QUAD=0,ALIGN=8,ACCESS=44,CODE_ONLY
        .EXPORT main,ENTRY,PRIV_LEV=3,RTNVAL=GR				; a cena dos privilege levels eh funny
main
        .PROC
        .CALLINFO FRAME=64,CALLS,SAVE_RP,SAVE_SP,ENTRY_GR=3
        .ENTRY
        .CALL
        xor     %r4,%r4,%r4						; aka meter %r4 a zero :)

arewedoneyet
        comib,=,n 5,%r4,kk10xbai					; se %r4 for 5, BAI NAO!
        nop
        xor     %r3,%r3,%r3						; inicializar o counter do segundo loope

letsdothis
        comb,<=,n %r3,%r4,estrela					; se o %r3 for menor ou igual a %r4
        xor %r1,%r1,%r26						; sim, isto eh um nop							

        ldi 1,%r26							; escolher o fd (1 eh stdout)
        ldil LR'LF,%r19							; copiar a stringue com
        ldo RR'LF(%r19),%r25						; paneleirices...
        ldi 1,%r24							; length da stringue
        .CALL ARGW0=GR,ARGW1=GR,ARGW2=GR
        bl write,%r2
        xor %r1,%r2,%r3							; sim, isto eh um nop

        addi    1,%r4,%r4						; incrementar o %r4
        b       arewedoneyet
        shladd %r4,2,%r8,%r15						; sim, isto eh um nop

estrela
        ldi 1,%r26							; ver outro write
        ldil LR'STAR,%r19						; eh a mm merda
        ldo RR'STAR(%r19),%r25
        ldi 1,%r24
        .CALL ARGW0=GR,ARGW1=GR,ARGW2=GR
        bl write,%r2
        add %r13,%r14,%r15						; sim, isto eh um nop

        addi    1,%r3,%r3
        b       letsdothis
        nop								; adivinha...

kk10xbai
        ldi 0,%r26
        .CALL ARGW0=GR
        bl exit,%r2
        shrpw %r8,%r7,8,%r9     ; nop nop nop
        subi,OD  42,%r3,%r12    ; nop nop nop nopppppp! :D
        .EXIT
        .PROCEND
hpux$ gcc arvorezinha.S
*
**
***
****
*****
hpux$

jah agora para esclarecer um pouco certas esquisitisses desta arquitectura, para loadar uma word (32 bits), como todas as instruções têm de ter 32bits eh obvio que nao da para meter um endereço com esse tamanho e ainda gastar 6 bits num opcode. entao o que estes genios da computacao fizeram foi primeiro loadar 21 bits e depois os 11 bits restantes.

tipo ali em cima
ldil LR’STAR,%r19
ldo RR’STAR(%r19),%r25
LR’ saca 21 bits da string STAR para o %r19
RR’ saca os 11 bits que faltam…

digam la, HPPA nao eh uma arquitectura magnifica ? (FUCK NO!)

Maio 25, 2010

Arvorezinha - SPARC!

Arquivado em: arvorezinha, assembly, coding, useless — paf @ 15:10

Btw, esta arch é meio intragável….

solaris$ cat arvore.S
.section  ".rodata1"
.align    4
.L0:
        .ascii           "*\0"
.L1:
        .ascii          "\n\0"

.L2:
        .ascii          "bla\n\0"

        .section        ".text"
        .global         main
main:
        save            %sp,-96,%sp
        mov 0,%g2

arewedoneyet:
        cmp %g2,5       ! comparar com RFC_MAX pois claro, n eh preciso registry pra isto
        be weredonefaggot

        mov 0,%g3       ! inicializar counter1

estrelitas:
        cmp %g3,%g2     ! ah e tal, compara-me a pissa, less or equal?
        ble estrela

        set .L1,%o0     ! meter LF no output register, e mandar printar
        call printf

        inc %g2         ! increasar o counter2
        ba arewedoneyet

estrela:
        set     .L0,%o0 ! printar estrelinha
        call    printf

        inc %g3
        ba estrelitas

weredonefaggot:
        nop
        restore

solaris$ gcc arvore.S -o arvorezinha
solaris$ ./arvorezinha
*
**
***
****
*****
solaris$

Arvorezinha - melhor arquitectura do mundo (Alpha)

Arquivado em: arvorezinha, assembly, coding, useless — paf @ 12:53

Como se lê no subject, fica aqui uma arvorezinha na melhor arquitectura à face do planeta. Em breve na terceira melhor arquitectura à face do planeta…(SPARC)

true64> gcc arvore.S -o arvorezinha
true64> ./arvorezinha
*
**
***
****
*****
true64> cat arvore.S
.data
LF:             .ascii          "\n\0"
GAY:            .ascii          "*"

.text
        .align  4
        .set    noreorder
        .arch   ev4
        .globl  main
        .ent    main

main:
        ldgp    $gp,0($27)		# load ao global pointer
        stq     $26,0($sp)			# inicializar o stack pointer (só naquela)

        lda $10,5                       	# RFC_MAX para o loop principal
        lda $9,0				# counter do loop1

loop1:
        cmpeq $9,$10,$7			# se $9 igual $10, branchar para o final
        bne $7,final

        lda $11,0				# counter para o loop2

loop2:
        cmple $11,$9,$7			# se $11 menor ou igual q $9, estrelar!
        bne $7,estrela

        lda $16,LF				# new line pl0x
        jsr $26,printf
        ldgp $gp,0($26)

        lda $9,1($9)			# uma maneira gay de incrementar
        br loop1

estrela:
        lda     $16,GAY			# printar estrelinha...
        jsr     $26,printf			# é sempre preciso fazer reset ao $gp
        ldgp    $gp,0($26)		# depois de usar uma função

        addq $11,1,$11			# outra maneira gay de incrementar :p
        br loop2

final:
        mov     $31,$0                  # return = 0
        ldq     $26,0($sp)              # limpar a stacka, se bem q nao foi usado mas pronto..
        ret     $31,($26),1             # returnarrrrrrrrr
        .end    main

true64>

Maio 21, 2010

Cracking 102

Arquivado em: assembly, cracking, fail, useless — falso @ 20:21

Ora viva amigos!
Há uns dias lembrei-me do mítico Championship Manager Itália 94/95, e das múltiplas tentativas que fazia para o conseguir jogar devido à protecção anti-copia, que basicamente pedia o resultado do jogo X da pagina Y do manual.

Então lá eu ficava montes de tempo a experimentar combinações ate conseguir jogar. Nessa altura sonhava em conseguir crackar aquilo, mas skills de cracking nesse tempo eram quase nulos. Decidi então tentar hoje.

Abri o CM.EXE num dissassembler e procurei por “Please enter the result”, e vi onde essa string era referenciada, fui parar a uma função que me parecia que era onde era feito o check dos resultados, mas parecia um bocado complexa portanto decidi tentar outra aproximação, fui ver onde esta função do check era chamada e…

seg001:0054                         loc_18FE4:                              ; CODE XREF: _main+47j
seg001:0054 9A 25 00 E4 61                          call    sub_61E65       ; Função do check
seg001:0059
seg001:0059                         loc_18FE9:                              ; CODE XREF: _main+99j
seg001:0059 1E                                      push    ds
seg001:005A 68 18 01                                push    offset aChampionshipMa ; "Championship Manager Italia"
seg001:005D 9A F9 48 83 1A                          call    sub_1F129       ; Call Procedure
seg001:0062 1E                                      push    ds
seg001:0063 68 35 01                                push    offset aHelpNewGameCon ; "*Help|New Game|Continue Season|Quick St"...

Vi que o código a seguir ao CALL parecia ser o menu inicial do jogo então alterei os 5 bytes do CALL para 90 (NOP - No OPeration) e não é que foi logo? A parte do check já nem aparece, vai logo directamente para o menu inicial!
Melhor que isto só mesmo o Benfica ser campeão, oh wait…

Maio 16, 2010

Arvorezinha 68K Assembly

Arquivado em: arvorezinha, assembly, coding, useless — falso @ 22:36

Hoje devido aos posts de hoje do falco sobre arvorezinhas ganhei um pouco de moral e fui à procura de arquitecturas que ainda não tivesse feito em assembly e lembrei-me dos Motorola 68K, os que eram usados nos MACs antigos.
Decidi então meter as mãos à obra, e fui procurar um emulador/simulador ou algo do género para este processador e achei o Easy68K que é um três-em-um, Editor, Assembler e Debugger.
Fiquem bem e joguem muito.

* -------------------------------------------can never fail-
* Program    : arvorezinha
* Written by : Pedro de Oliveira
* Date       : 16/05/2010
* Description: Implementação da arvorezinha em 68K assembly 
*-----------------------------------------------------------
        ORG     $1000
START:                          ; first instruction of program

main:
        MOVE.B  #5,d7           ; maximo de linhas/asteriscos
                                ; está a usar o RFC standard 5
        MOVE.B  #0,d5           ; inicializa o counter1 (d5) a 0

ciclo1:
        CMP.B   d5,d7           ; verifica se chegamos o fim
                                ; comparando o counter1 ao maximo
        BEQ     final           ; se for igual salta para o fim
	
        MOVE.B  #0,d6           ; inicializa o counter2 (d6) a 0

ciclo2:
        CMP.B   d5,d6           ; compara o counter1 com o counter2
        BEQ     estrela         ; se for igual
        BLT     estrela         ; ou menor imprime um asterisco
	
        LEA     newline,a1      ; imprime uma newline
        JSR     print
	
        ADD     #1,d5           ; incrementa o counter1
        JMP     ciclo1          ; salta para o ciclo1

estrela:
        LEA     _estrel,a1      ; imprime um asterisco
        JSR     print
	
        ADD     #1,d6           ; incrementa o counter2
        JMP     ciclo2          ; salta para o ciclo2

final:
        MOVE.B  #9,D0
        TRAP    #15             ; halt simulator

print:
        MOVE.B  #14,d0
        TRAP    #15
        RTS

* Variables and Strings

_estrel	DC.B    '*',0
newline DC.B    $0D,$0A,0

        END     START           ; last line of source

Outubro 2, 2009

Sites em C

Arquivado em: assembly, coding, useless — falso @ 02:23

Ora viva!

Já desde há uns tempos que se tinha falado nos mirques sobre fazer sites super optimizados em C à-lá-OpenBSD.

Então hoje num momento de aborrecimento decidi fazer um!

Teve de ser alta executável estático para poder ser executado dentro do chroot do Apache.

Basicamente, é uma pagina central mais dois requests que são feitos por ajax com ajuda do jQuery.

Até inclui alta inline assembly cortesia do dongs!

Vejam-no em acção aqui: lolajax (a extensão é .exe só para ser mais hacker, porque o que retorna é html ;-).

Agosto 25, 2009

printf("oi lindinhos!\n");

Arquivado em: assembly, coding, cracking, useless — charlie-lindinho @ 20:06

há mil dias li um post do *xorl* intitulado de “Funny C programming interview questions”, achei uma certa piada ao raio do post e resolvi escrever aqui sobre isso.

no post o xorl apresenta a solução para uma das questões colocadas neste *site*, no qual nos é questionado se é possível fazer com que a variável “i” apresente outro valor, senão “2”, apenas adicionando código à função foo().

#include <stdio.h>
#include <stdlib.h>

void foo(void);

int main (void)
{
	int i=2;
	foo();
	printf ("%d\n",i);
	return EXIT_SUCCESS;
}

void foo(void)
{
	// add code so that printf above prints different value of i (i.e. not 2)
} 

a primeira coisa que me ocorreu (em mil milésimos de segundo) foi modificar directamente o valor de “i” através da função “printf” e então fiz o seguinte :

#include <stdio.h>
#include <stdlib.h>

void foo(void);

int main(void)
{
	int i = 2;
	foo();
	printf("%d\n", i);
	return EXIT_SUCCESS;
}

void foo(void)
{
	unsigned long addr;
	__asm("movl %%ebp, %0" : : "m"(addr));
	printf("%1$n", addr += 24);
}

o que fiz aqui foi calcular o endereço da variável “i” apartir do base pointer (EBP) e fazer com que a funçao printf escrevesse 0 bytes no endereço da mesma através do especificador de formato “%n”.

bash-3.1# gcc -o printf printf.c
bash-3.1# ./printf
0
bash-3.1# 

ainda assim existe outra solução óbvia da qual me lembrei também, que consiste em fechar o file descriptor utilizado pela função printf ( stdout ) depois da função foo().

void foo(void)
{
	fprintf(stderr, "%d\n", 0);
	close(1);
}

queria dedicar este post inútil ao cavalo que morreu hoje atropelado no brasil.

Julho 31, 2009

kgme1

Arquivado em: assembly, cracking, linux, useless — falso @ 01:32

Ora viva!

Já há uns tempos que tinha falado com o Dongs para fazer um KeygenMe para eu tentar keygennar porque nunca o tinha feito. Ele então fez um e eu pus mãos à obra.

[ kgme.tar.bz2 ]

$ ./kgme
Name: falso
Serial: 12345
Bad serial!

Abri então o ficheiro no IDA e andei a procurar por “Bad serial!”, e então que achei. Vai aqui um dump comentado:

0804830C	movzx   ecx, byte ptr [esi] ; ESI contem o "User"
0804830C                                ; e ECX contem o primeiro char do "User"
0804830F	test    ecx, ecx        ; Se (ECX != 0x0) ZF=0 ELSE ZF=1
08048311	jz      short loc_8048333 ; Se ZF=1 Salta pro drama
08048313	lea     edx, [ebp-10Fh] ; EDX fica com "User" sem o primeiro char
08048319	mov     ebx, 0DEADh
0804831E	db      66h
0804831E	nop                     ; No Operation
08048320
08048320 loc_8048320:
08048320	mov     eax, ebx        ; EAX passa a tar 0xDEAD tambem
08048322	shl     eax, 5          ; Shift Logical Left 5 vezes
08048325	add     eax, ecx        ; Adiciona o valor do char do "User" (ECX) a EAX
08048327	movzx   ecx, byte ptr [edx] ; le o proximo char pra ECX
0804832A	add     edx, 1          ; Add
0804832D	add     ebx, eax        ; Add
0804832F	test    ecx, ecx        ; Logical Compare
08048331	jnz     short loc_8048320 ; Jump if Not Zero (ZF=0)
08048333
08048333 loc_8048333:
08048333	xor     edx, edx        ; Logical Exclusive OR
08048335	mov     eax, offset aBadSerial ; "Bad serial!"
0804833A	cmp     [ebp-10h], ebx  ; Compare Two Operands
0804833D	setz    dl              ; Set Byte if Zero (ZF=1)
08048340	xor     eax, offset aGoodSerial ; "Good serial!"
08048345	neg     edx             ; Two's Complement Negation
08048347	and     eax, edx        ; Logical AND
08048349	xor     eax, offset aBadSerial ; "Bad serial!"

Então o funcionamento da coisa é mais ou menos o seguinte:

/\* inicialização(?) */
\* Le o Name para o registo ESI
\* Mete o primeiro char do Name no registo ECX
\* EDX fica com o Name sem o primeiro char
\* EBX fica com o valor 0xDEAD

/\* ciclo central */
\* Copia o valor de EBX para EAX
\* Faz um shift left 5 vezes a EAX
\* Adiciona o valor do char em ECX a EAX
\* Le o proximo char do Name para ECX
\* Adiciona 1 a EDX
\* Adiciona EAX a EBX
\* Se ECX nao for diferente de 0 salta para o inicio do ciclo

Vou tentar dar um exemplo:

User: Jim

/\* inicialização */
\* ESI = Jim
\* ECX = J (0x4a)
\* EDX = im
\* EBX = 0xdead

( valores dos registos )
-- ECX = J | EDX = im | EBX = 0xdead –

/\* ciclo central */
( Primeiro ciclo - J )
\* EAX = EBX
-- ECX = J | EDX = im | EBX = 0xdead | EAX = 0xdead –
\* shift left 5 vezes a EAX
-- ECX = J | EDX = im | EBX = 0xdead | EAX = 0x1bd5a0 –
\* adiciona o valor do char em ECX (J - 0x4a) a EAX
-- ECX = J | EDX = im | EBX = 0xdead | EAX = 0x1bd5ea –
\* Le o proximo char do Name pra ECX
-- ECX = i | EDX = im | EBX = 0xdead | EAX = 0x1bd5ea –
\* Adiciona 1 a EDX
-- ECX = i | EDX = m | EBX = 0xdead | EAX = 0x1bd5ea –
\* Adiciona EAX a EBX
-- ECX = i | EDX = m | EBX = 0x1cb497 | EAX = 0x1bd5ea –
\* Se ECX é diferente de 0 então do inicio de novo!

( Segundo ciclo - i )
\* EAX = EBX
-- ECX = i | EDX = m | EBX = 0x1cb497 | EAX = 0x1cb497 –
\* shift left 5 vezes a EAX
-- ECX = i | EDX = m | EBX = 0x1cb497 | EAX = 0x39692e0 –
\* adiciona o valor do char em ECX (i - 0x69) a EAX
-- ECX = i | EDX = m | EBX = 0x1cb497 | EAX = 0x3969349 –
\* Le o proximo char do Name pra ECX
-- ECX = m | EDX = m | EBX = 0x1cb497 | EAX = 0x3969349 –
\* Adiciona 1 a EDX (fica limpo)
-- ECX = m | EBX = 0x1cb497 | EAX = 0x3969349 –
\* Adiciona EAX a EBX
-- ECX = m | EBX = 0x3b347e0 | EAX = 0x3969349 –
\* Se ECX é diferente de 0 então do inicio de novo!

( Terceiro ciclo - m )
\* EAX = EBX
-- ECX = m | EBX = 0x3b347e0 | EAX = 0x3b347e0 –
\* shift left 5 vezes a EAX
-- ECX = m | EBX = 0x3b347e0 | EAX = 0x7668fc00 –
\* adiciona o valor do char em ECX (m - 0x6d) a EAX
-- ECX = m | EBX = 0x3b347e0 | EAX = 0x7668fc6d –
\* Le o proximo char do Name pra ECX (fica limpo)
-- EBX = 0x3b347e0 | EAX = 0x7668fc6d –
\* Adiciona 1 a EDX (continua limpo)
-- EBX = 0x3b347e0 | EAX = 0x7668fc6d –
\* Adiciona EAX a EBX
-- EBX = 0x7a1c444d | EAX = 0x7668fc6d –
\* ECX é zero, então temos a serial em EBX

$ kgme
Name: Jim
Serial: 7a1c444d
Good serial!

Fiz uma implementação em C++ do keygen, que a única coisa que usa de c++ é o cout mas mesmo assim, aqui vai:

//============================================================================
// Name        : lolkg.cpp
// Author      : falso
// Version     : 0.1-pre1-beta2-rc4
// Copyright   : WTFPL
// Description : Keygen para o kgme do dongs
//============================================================================

#include <iostream>
using namespace std;

int main() {

	char name[50];

	cout << "|         |    |\n";
	cout << "|    ,---.|    |__/ ,---.\n";
	cout << "|    |   ||    |  \\ |   |\n";
	cout << "`---'`---'`---'`   ``---|\n";
	cout << "                    `---'\n";

	cout << "Name: " << flush;
	cin >> name;

	int ebx = 0xdead;
	int eax = ebx;
	int ecx = name[0];

	int i = 1;

	while (ecx != 0x0) {
		eax = ebx;
		eax = eax << 5;
		eax = eax + ecx;
		ecx = name[i];
		i++;
		ebx = ebx + eax;
	}

	printf("Serial: %x\n",ebx);

	return 0;
}

E já agora, uma em MIPS assembly pro PCSpim:

# this asm can never fail
#
# lolkg
.data
us: .asciiz "User: "
u: .space 50

.text
.globl main
main:

# print user..
li $v0,4
la $a0,us
syscall

# get string
li $v0,8
la $a0,u
syscall

# variavel inicial do algoritmo
li $s0,0xdead # s0 - ebx
move $s1,$s0 # s1 - eax

la $s5,u # tmp
#apanha o primeiro char do Username
lb $s2,0($s5) # s2 - ecx

_while:
move $s1,$s0
sll $s1,$s1,5
add $s1,$s1,$s2

addi $s5,$s5,1
lb $s2,0($s5) # s2 - ecx

addu $s0,$s0,$s1
bne $s2,0xa,_while

# imprime o serial, mas em decimal ;-(
# nao sei como imprimir em hex, pois o serial é em HEX
li $v0,1
move $a0,$s0
syscall

#sai
li $v0,10
syscall

Espero que todo este conhecimento inútil sirva para alguém, nem que seja pra despertar um bichozinho pequenino pro cracking! Fiquem bem, e crackem muito!

Junho 6, 2009

Cracking 101

Arquivado em: assembly, cracking, useless — falso @ 00:53

Ora viva!

O software há dias estava a tentar descobrir como se cracka um simples strncmp(3), então eu fiquei com ideias de criar um breve *curso* de cracking para os iniciantes.
Começamos com o seguinte sores:

#include <stdio.h>

int main() {
        char loljews[10];

        printf("--> ");
        scanf("%s",&loljews);
        if(strncmp(loljews,"morte",5)==0) {
                printf(" OK ;-)\n");
        } else {
                printf(" FAiLED!\n");
        }

        return 1;
}

O código julgo que é auto-explicativo. O que se pretende é, depois de ter o programa compilado alterar o executável de forma a que aceite qualquer palavra sem ser “morte” e diga OK.
Então corri o programa no gdb e fiz “disassemble main”

Dump of assembler code for function main:
0x08048464 <main+0>:    push   %ebp
0x08048465 <main+1>:    mov    %esp,%ebp
0x08048467 <main+3>:    and    $0xfffffff0,%esp
0x0804846a <main+6>:    sub    $0x20,%esp
0x0804846d <main+9>:    mov    $0x8048590,%eax
0x08048472 <main+14>:   mov    %eax,(%esp)
0x08048475 <main+17>:   call   0x8048368 <printf@plt> # print "-->"
0x0804847a <main+22>:   mov    $0x8048595,%eax
0x0804847f <main+27>:   lea    0x16(%esp),%edx
0x08048483 <main+31>:   mov    %edx,0x4(%esp)
0x08048487 <main+35>:   mov    %eax,(%esp)
0x0804848a <main+38>:   call   0x8048378 <__isoc99_scanf@plt>
0x0804848f <main+43>:   movl   $0x5,0x8(%esp)
0x08048497 <main+51>:   movl   $0x8048598,0x4(%esp)
0x0804849f <main+59>:   lea    0x16(%esp),%eax
0x080484a3 <main+63>:   mov    %eax,(%esp)
0x080484a6 <main+66>:   call   0x8048398 <strncmp@plt> # faz o call ao strncmp
0x080484ab <main+71>:   test   %eax,%eax
0x080484ad <main+73>:   jne    0x80484bd <main+89> # Se não é igual, salta pra bad_boy
0x080484af <main+75>:   movl   $0x804859e,(%esp) # good_boy
0x080484b6 <main+82>:   call   0x8048388 <puts@plt> # print "OK"
0x080484bb <main+87>:   jmp    0x80484c9 <main+101> # salta para o fim
0x080484bd <main+89>:   movl   $0x80485a6,(%esp) # bad_boy
0x080484c4 <main+96>:   call   0x8048388 <puts@plt> # print "failed"
0x080484c9 <main+101>:  mov    $0x1,%eax # fim
0x080484ce <main+106>:  leave
0x080484cf <main+107>:  ret

Primeiro uma lista de instruções normalmente usadas para o cracking e os seus opcodes em hexadecimal.

JNE - Jump if Not Equal - 75
JE - Jump if Equal - 74
JMP - Jump - EB
NOP - No Operation - 90
JA - Jump if Above - 77
JB - Jump if Below - 72
JNA - Jump if Not Above - 76
JLE - Jump if Less or Equal - 7E
JL - Jump if Less - 7C

O que se pretende então é alterar ali aquele JNE em <main+73>. Mas para o quê? A primeira ideia seria inverter o sentido do jump, em vez de ser JNE passava a ser JE. Mas assim ficávamos com um problema, ao metermos “morte” iamos parar ao “failed”.
Então o que podemos fazer perguntam vocês?

Para explicar primeiro precisei de instalar um hex editor para Linux. O biew pareceu-me bem. Abri o executável nele e andei à procura do naco de código acima (do gdb).

000004A6:E8EDFEFFFF                     calln     file:00000398
000004AB:85C0                           test      eax,eax                      
000004AD:750E                           jne       file:000004BD
000004AF:C704249E850408                 mov       [esp],0804859E
000004B6:E8CDFEFFFF                     calln     file:00000388
000004BB:EB0C                           jmps      file:000004C9
000004BD:C70424A6850408                 mov       [esp],080485A6
000004C4:E8BFFEFFFF                     calln     file:00000388
000004C9:B801000000                     mov       eax,00000001                 
000004CE:C9                             leave

O que eu fiz foi alterar os os bytes do JNE e da posição para onde salta “75 0E”, para dois NOPs (No Operation - Não faz nada) “90 90”. Assim ele nunca faz o teste, e segue sempre em frente para o good_guy e depois sai.

Espero que isto tenha alguma utilidade para alguém! Para a próxima talvez haja um com algo mais complexo tipo Username com Serial derivada do Username ou algo do género.

Até la, fiquem bem e crackem muito ;-)