Há 3 anos atrás pude proferir "It's alive, it's alive" com minha própria linguagem para parsing de buffers.
Não regulo muito e resolvi criar algo orientado à instruções, imagine um ASSEMBLY só que para buffers... Mas esse pseudo-ASSEMBLY é realmente alienígena!
É a BPL (Buffer Parsing Language), confesso que já fui mais criativo em acrônimos, e realmente é uma sigla bem genérica, hehe.
As instruções BPL (bem atômicas até certo ponto) são:
| INSTRUÇÃO | AÇÃO |
| aux | Cria um registrador auxiliar |
| set | Seta todo conteúdo de um buffer |
| wlk | Incrementa/decrementa ponteiro de deslocamento do buffer |
| ldb | Põe um byte no offset atual de um buffer |
| bob | Checa por início de buffer |
| eob | Checa pelo final do buffer |
| jmp | Salto condicional |
| lbl | Adiciona marcação de label no código, usado nos jumps |
| add | Incrementa valor contido na posição de memória atual do buffer |
| sub | Similar a add mas em termos de decremento |
| mul | Similar a sub mas em termos de multiplicação |
| div | Similar a mul mas em termos de divisão |
| alu | Resolve uma expressão lógica |
| var | Cria uma variável, ok, me chame de Herege ASSEMBLY people |
Cada instrução informada tem suas particularidades quanto à passagem de parâmetros, caso queira saber mais, encontre os detalhes na documentação informada no final desse post.
Que tal exemplos:
# Rot13 em C-Stringsvar byte %byte 0x0lbl ___DO_ROT13ldb %byte BUFjmp eq BUF 0x00 ___WALK_ON ___CONTINUElbl ___CONTINUEsub %byte 13ldb BUF %bytelbl ___WALK_ONwlk > BUFeob %byte BUFjmp ne %byte 1 ___DO_ROT13 ___END_ROT13lbl ___END_ROT13
Um maior, que atesta minha loucura :P
## ``urldecoding.bpl'' ( Thu 08 May 2008 10:10:42 AM UTC )## URL decoding sem suporte para Utf-8#var byte %result_flag 0aux %nibble_l 1aux %nibble_h 1aux %buf 8192lbl ___NEXT_HEX_BYTEeob %result_flag BUFjmp eq %result_flag 1 ___DECODING_END ___DO_NEXT_HEX_BYTElbl ___DO_NEXT_HEX_BYTEjmp eq BUF "%" ___HEX_2_CHAR_BYTE ___NEXT_HEX_BYTE_CONTINUElbl ___NEXT_HEX_BYTE_CONTINUEjmp eq BUF "+" ___PLUS_2_SPACE ___SIMPLE_ASSIGMENTlbl ___PLUS_2_SPACEldb %buf " "jmp eq %buf " " ___POINTER_AHEAD ___POINTER_AHEAD # goto ;)lbl ___SIMPLE_ASSIGMENTldb %buf BUFlbl ___POINTER_AHEADwlk > %bufwlk > BUFjmp eq 1 1 ___NEXT_HEX_BYTE ___NEXT_HEX_BYTElbl ___HEX_2_CHAR_BYTEwlk > BUF #[%]XX -> %[X]Xldb %nibble_h BUFjmp ge %nibble_h "0" ___IS_NUMBER_H ___NOT_NUMBER_Hlbl ___IS_NUMBER_Hjmp le %nibble_h "9" ___NUMBER_2_DEC_H ___NOT_NUMBER_Hlbl ___NOT_NUMBER_Hjmp ge %nibble_h "a" ___IS_LWR_ALPHA_H ___NOT_LWR_ALPHA_Hlbl ___IS_LWR_ALPHA_Hjmp le %nibble_h "f" ___LWR_ALPHA_2_DEC_H ___NOT_LWR_ALPHA_Hlbl ___NOT_LWR_ALPHA_Hjmp ge %nibble_h "A" ___IS_UPR_ALPHA_H ___NOT_UPR_ALPHA_Hlbl ___IS_UPR_ALPHA_Hjmp le %nibble_h "F" ___UPR_ALPHA_2_DEC_H ___NOT_UPR_ALPHA_Hlbl ___NOT_UPR_ALPHA_Hldb %buf BUFwlk > BUFwlk > %bufjmp eq 1 1 ___NEXT_HEX_BYTE ___NEXT_HEX_BYTElbl ___NUMBER_2_DEC_Hsub %nibble_h 48jmp eq 1 1 ___NEXT_NIBBLE ___NEXT_NIBBLElbl ___LWR_ALPHA_2_DEC_Hsub %nibble_h 87jmp eq 1 1 ___NEXT_NIBBLE ___NEXT_NIBBLElbl ___UPR_ALPHA_2_DEC_Hsub %nibble_h 55lbl ___NEXT_NIBBLEmul %nibble_h 16wlk > BUF #%[X]X -> %X[X]ldb %nibble_l BUFjmp ge %nibble_l "0" ___IS_NUMBER_L ___NOT_NUMBER_Llbl ___IS_NUMBER_Ljmp le %nibble_l "9" ___NUMBER_2_DEC_L ___NOT_NUMBER_Llbl ___NOT_NUMBER_Ljmp ge %nibble_l "a" ___IS_LWR_ALPHA_L ___NOT_LWR_ALPHA_Llbl ___IS_LWR_ALPHA_Ljmp le %nibble_l "f" ___LWR_ALPHA_2_DEC_L ___NOT_LWR_ALPHA_Llbl ___NOT_LWR_ALPHA_Ljmp ge %nibble_l "A" ___IS_UPR_ALPHA_L ___NOT_UPR_ALPHA_Llbl ___IS_UPR_ALPHA_Ljmp le %nibble_l "F" ___UPR_ALPHA_2_DEC_L ___NOT_UPR_ALPHA_Llbl ___NOT_UPR_ALPHA_Lldb %buf BUFwlk > BUFwlk > %bufjmp eq 1 1 ___NEXT_HEX_BYTE ___NEXT_HEX_BYTElbl ___NUMBER_2_DEC_Lsub %nibble_l 48jmp eq 1 1 ___ADJUST_L ___ADJUST_Llbl ___LWR_ALPHA_2_DEC_Lsub %nibble_l 87jmp eq 1 1 ___ADJUST_L ___ADJUST_Llbl ___UPR_ALPHA_2_DEC_Lsub %nibble_l 55jmp eq 1 1 ___ADJUST_L ___ADJUST_Llbl ___ADJUST_Ladd %nibble_h %nibble_lldb %buf %nibble_hwlk > %bufwlk > BUFjmp eq 1 1 ___NEXT_HEX_BYTE ___NEXT_HEX_BYTElbl ___DECODING_ENDset BUF "\0x00"lbl ___GET_BUF_REG_BEGINwlk < %bufbob %result_flag %bufjmp ne %result_flag 1 ___GET_BUF_REG_BEGIN ___OVERWRITE_INPUTlbl ___OVERWRITE_INPUTldb BUF %bufwlk > %bufwlk > BUFeob %result_flag %bufjmp eq %result_flag 1 ___DONE ___OVERWRITE_INPUTlbl ___DONE
É, criei um monstro.
"Inquirrível funquiciona. Está vivo, está vivo! MuAhhauahuahauh."
-- Dr. Bufferstein.
Pensei em criar a BPL enquanto desenvolvia um sniffer e esbarrei no problema de filtrar de forma geral dados vindos de protocolos layer7.
Meu sniffer no caso trabalha com uma linguagem bem específica que permite acesso aos campos dos protocolos de camada de rede e transporte, mas é impossível criar todos os campos para protocolos layer7 visto que à cada hora surge um novo (eita exagero)...
Nisso a BPL resolvia meu problema, entregando ao usuário a responsabilidade de criar seus próprios filtros para extração da informação layer7 desejada.
Fora que os usuários do sniffer podem criar seus próprios parsers e distribuir isso como funções de biblioteca.
Documentação e compilador/interpretador em: BPL_pack.
Igor para Dr. Bufferstein:
"- Qual é o próximo plano mestre??"
"- Parsearemos o Mundo..."
"- Bom!"