A study in software modification and automation by integrating Paterva’s CaseFile and Maltego

Maltego is an excellent intelligence and data visualization tool, but the need of being online(and the requirement of an registered account) make it pretty much useless for more sophisticated usages(like crime investigation or any other private and offline usage). For this, CaseFile was created, which is, basically, Maltego offline without the transforms. But transforms(offline and over closed-source data) would make the life of analysts easier in checking/validating information. To have the best of two worlds, I’ve extracted the transform engine from Maltego and inserted on CaseFile, also, removing the need of login and information leakage that the tool usually allow, making trustable and usable even by the government.

First, Maltego is a great tool and everyone who likes it should support Paterva and buy licenses. This is a study in software modification, automation and should not be used to cause harm to Paterva’s copyrights/busines model by any means. That’s why I’m using old versions of Maltego and Casefile.

The versions used was:

  • Maltego 3.1: maltego-3.1.1_CE-2012-04-11.zip md5 400b427652ca3e8ed60a6d6b7a457e81
  • CaseFile 1.0: maltego-CF.1.0.1_community-2012-03-14.zip md5 8d009eae5c899d74458712fe0e1458e1

They were originally downloaded from:

The base tools used was:

  • Jasmin ( http://jasmin.sourceforge.net/ ), an assembler for the Java Virtual Machine. It takes ASCII descriptions of Java classes, written in a simple assembler-like syntax using the Java Virtual Machine instruction set. It converts them into binary Java class files, suitable for loading by a Java runtime system.
  • ClassFileAnalyzer ( http://classfileanalyzer.javaseiten.de/ ), an analyzer and disassembler (Jasmin syntax 2) for Java class files.

First, I removed the annoying background image at maltego/modules/locale/com-paterva-maltego-ui-graph_maltego.jar.

Then, I’ve copied some files related to transform from Maltego to CaseFile:

  from maltego-ui/
    com-paterva-maltego-transforms-standard
    com-paterva-maltego-transform-protocol-v2
    com-paterva-maltego-transform-manager
    com-paterva-maltego-transform-finder     # needed by com-paterva-maltego-transform-manager
    com-paterva-maltego-transform-discovery  # needed by com-paterva-maltego-transform-protocol-v2
    com-paterva-maltego-transform-runner     # needed by com-paterva-maltego-transform-protocol-v2
  from maltego-core-platform/
    com-paterva-maltego-typing               # for com.paterva.maltego.typing.TypeNameValidator

The next step was define a series of modifications and fine tunning on CaseFile:

  • remove savetoserver and fake transform
  • remove startpage website
  • remove server discovery from manage transforms toolbar
  • always use trivialurldisplay
  • make showURL a stub in trivialurldisplay
  • remove google-me and wikipedia-me actions
  • remove all discover transforms actions
  • remove lots of webbrowser actions
  • enable transform limit toolbar

For that, I’ve put all modifications in .diff, .jdiff or .java where .diff is applied by standard POSIX patch utility, .jdiff is recompiled with jasmine and .java is compiled with jdk’s javac and integrated into target application.

Instructions:

  • Run cfpatch:
    ./cfpatch maltego-3.1.1_CE-2012-04-11.zip maltego-CF.1.0.1_community-2012-03-14.zip CF-custom.zip
  • Extact CF-custom.zip to the place where you want to install the custom CaseFile.

Extra
Create an .java file with the header:

//target-contains: com/paterva/maltego/graph/MaltegoGraph.class
//filename: org/hopto/im/Test.java

to integrate a new piece of software on Casefile. Example:

//target-contains: com/paterva/maltego/graph/MaltegoGraph.class
//filename: org/hopto/im/Test.java

// the above lines are to indicate that this class will be added
// in the same JAR module that file com/paterva/maltego/graph/MaltegoGraph.class
// and that the original name of this file is org/hopto/im/Test.java

package org.hopto.im;
public class Test {
    public static void main(String[] args) {
        System.out.println("Hello");
    }
}

All the working scripts and tools can be found at: https://github.com/paoloo/casefile-extender

Advertisements

Serviço de checagem de CPF em bash script+python

Analisando um app de iPhone(depois mostro o passo a passo e as ferramentas), me vi precisando escrever um teste rápido no bash com o curl, que é uma ferramente absolutamente excepcional, mas me ví com problemas deevido a geração do HMAC e fazer parsing do resultado(sed+awk+cut é meio doloroso ne).
Acabei fazendo algo meio hibrido assim:

#!/bin/bash
cpfHASH=`echo "$1 $2" | python -c "from hashlib import sha1; from hmac import new as hmac; import sys; v=sys.stdin.read().strip().split(' '); print hmac('Sup3RbP4ssCr1t0grPhABr4sil','%s%s' % (v[0],v[1]),sha1).digest().encode('hex')"`

saidA=`curl https://movel01.receita.fazenda.gov.br/servicos-rfb/v2/IRPF/cpf -s -k -H "token: $cpfHASH" -H "plataforma: iPhone OS" -H "dispositivo: iPhone" -H "aplicativo: Pessoa Física" -H "versao: 8.3" -H "versao_app: 4.1" -d "cpf=$1&dataNascimento=$2" 2>&1`

python -c "null=None; a=$saidA; print ''.join(['%s = %s\n' % (c,a[c]) for c in a])"

Ficou meio porco usar o python para gerar o hash e para fazer o parsing, mas resolveu o meu problema. A execução é simples, o chato é que requer, além do CPF, a data de nascimento. Mas futuramente integrarei uma ferramenta para conseguir esta informação ;D

$ ./cpf.sh 13326724691 14121947
horaConsulta = 20:49:31
exception = None
codigoRetorno = 00
mensagemRetorno = OK
dataIsncricao = anterior a 10/11/1990
digitoVerificador = 00
nome = DILMA VANA ROUSSEFF
dataEmissao = 20/11/2015
horaEmissao = 08:49:32
mensagemObito = None
anoObito = 0000
codigoControle = CCA9.63A0.C92D.1C0D
codSituacaoCadastral = 0
dataConsulta = 20/11/2015
descSituacaoCadastral = REGULAR
dataNascimento = 14/12/1947

O código se encontra em https://github.com/paoloo/servicos/blob/master/cpf.sh

o/

Lua + C + Python – Mais que uma combinação macabra, uma gambiarra sinistra

Antes de mais nada: Por que?
Eu precisava fazer deploy de uma shared library em um ARM com linux(um raspberry Pi) extremamente capado, e não podia instalar todas as tools de dev, pois estava no limite de espaço do cartão, devido a aplicação dele. Mas precisava desta shared lib para carregar no python, via ctypes, pois o mesmo usaria as informações extraidas do hardware pelo .c, interpretaria e daria ordens ao resto da eletrônica. Acontece que os parametros do C variavam muito, precisavam ser tunados constantemente. Foi daí que rolou a ideia do LUA.
A ideia foi boa? Bom, funcionou. E até que faz um pouco de sentido, de alguma forma haha

vamos la, o loader, em python, é simplezão:

$ cat > loader.py << _EOF_
import ctypes
biblioteca=ctypes.CDLL('./zoalib.so')
biblioteca.zoeira.restype = ctypes.c_int
biblioteca.zoeira.argtypes = [ctypes.c_int]
biblioteca.zoeira(5)
_EOF_

O loader em C:

$ cat >zoalib.c << _EOF_
#include "lua.h"
#include "lauxlib.h"

int zoeira(int a)
{
    double z;
    lua_State *L = lua_open();
    luaL_openlibs(L);
    luaL_loadfile(L, "zoeira.lua");	/* arquivo lua */
    lua_pcall(L, 0, 0, 0);		/* limpa a pilha */
    lua_getglobal(L, "modelamotor");	/* nome da função do lua */
    lua_pushnumber(L, 3);		/* envia primeiro argumento */
    lua_pushnumber(L, 4);		/* envia segundo argumento */
    lua_pcall(L, 2, 1, 0);
    z = lua_tonumber(L, -1);		/* pega resultados */
    printf("Resultado: %f\n",z);
    lua_pop(L, 1);
    lua_close(L);
    return (a+1);
}
_EOF_

E o script em lua:

$ cat > zoeira.lua << _EOF_
function modelamotor (param1, param2)
    return math.sqrt(param1^2 + param^2)
end
_EOF_

Agora, vamos compilar com estes poucos parametros e rodar haha:

$ gcc -I/usr/include/lua5.1 zoalib.c -llua5.1 -lm -fPIC -shared -Wl,-soname,zoalib -o zoalib.so
$ python l.py
Resultado: 5.000000
6

Hell yeah!
Embora isso seja absurdamente mais util nos raspberryPi/beaglebone, talvez haja algum uso no desktop, vai saber haha.

Lua + C – uma combinação perfeita

Lua é uma linguagem de script imperativa, procedural, pequena(sério, muito pequena), reflexiva e leve, projetada para expandir aplicações em geral, com o objetivo de agilizar a prototipagem e fr ser embarcada em softwares complexos.

Embarcar lua em C/C++ por ter sido o pensamento original da linguagem, é algo muito fácil e incrivelmente util.

antes vamos instalar a biblioteca de desenvolvimento do lua no ubuntu:

# apt-get install liblua5.1-0-dev

Agara vamos fazer algo simples: uma função em C que executa instruções em lua

$ cat > 1.c << _EOF_
#include "lua.h"
#include "lauxlib.h"
int main(int argc, char **argv)
{
    lua_State *L = luaL_newstate();
    luaL_openlibs(L);
    luaL_dostring(L, "print('Hey hey hey, '.._VERSION)");
    return 0;
}
_EOF_

compilar, lembrando de linkar a biblioteca do lua e adicionar ao include:

$ gcc -I/usr/include/lua5.1 -o 1 1.c -llua5.1 -lm
$ ./1
Hey hey hey, Lua 5.1

Ok, funcionou. Fazer o C carregar um arquivo contendo o script em lua é igualmente trivial, muda apenas a instrução luaL_dostring() por luaL_dofile(), visto a seguir:

$ cat > 2.c << _EOF_
#include "lua.h"
#include "lauxlib.h"
int main(int argc, char **argv)
{
    lua_State *L = luaL_newstate();
    luaL_openlibs(L);
    luaL_dofile(L, "dois.lua");
    return 0;
}
_EOF_

E criar o script “dois.lua” que será carregado. Neste caso, não estou gerenciando erros, mas é um código em C, todos os erros devem ser checados ou vai crashar tudo.

$ cat > dois.lua << _EOF_
print "go go go"
for i=1,5 do
   print(i) 
end
print "hell yeah!"
_EOF_

compilar igualmente e rodar:

$ gcc -I/usr/include/lua5.1 -o 2 2.c -llua5.1 -lm
$ ./2
go go go
1
2
3
4
5
hell yeah!

Lembrando que o script pode ser mudado depois da compilação, esta é a ideia, na verdade haha.

Até aqui, tudo bem. Agora vamos fazer o lua acessar uma função do C:

$ car > 3.c << _EOF_
#include "lua.h"
#include "lauxlib.h"
static int huehue(lua_State *L){ /* método que será chamado dentro do script */
  int n = lua_gettop(L); /* numero de argumentos */
  double sum = 0;
  int i;
  for (i = 1; i <= n; i++){
    sum += lua_tonumber(L, i);
  }
  lua_pushnumber(L, sum / n); /* envia primeira resposta */
  lua_pushnumber(L, sum);     /* envia segunda resposta */
  lua_pushnumber(L, 666);     /* envia terceira resposta */
  return 3;                   /* quantidade de respostas */
}
int main(int argc, char **argv)
{
    lua_State *L = luaL_newstate();
    luaL_openlibs(L);
    lua_register(L, "huehue", huehue);
    luaL_dofile(L, "tres.lua");
    return 0;
}
_EOF_

e o arquivo lua:

$ cat > tres.lua << __EOF__
print("arquivo lua\n")
_r, _s, _t = huehue(1,2,3,5,8,9)
print(_r.." - ".._s.." - ".._t)
__EOF__

A compilação continua a mesma:

$ gcc -I/usr/include/lua5.1 -o 3 3.c -llua5.1 -lm
$ ./3
arquivo lua

4.6666666666667 - 28 - 666

Beleza, so lebrar de registrar a função que se quer exportar para o script lua e tudo funciona muito bem.
Agora a ultima fronteira, fazer o C carregar uma função do lua. Para que isso? bom, vamos dizer que está extraindo dados do hardware de alguma forma em C, mas lidar com isso é complexo ou exige várias mudanças. Re-escrever e re-compilar não é exatamente a saída mais agradavel. Lua pode ser a resposta.
O exemplo que estou colocando, é, entretanto, mais simples. O C para dois parametros para uma função continha, que na prática executa o teorema de pitagoras, mas pode ser mudado para qualquer coisa sem requerer recompilação

$ cat > 4.c << _EOF_
#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"
int main()
{
    double z;
    lua_State *L = lua_open();
    luaL_openlibs(L);
    luaL_loadfile(L, "quatro.lua");	/* arquivo lua */
    lua_pcall(L, 0, 0, 0);		/* limpa a pilha */
    lua_getglobal(L, "continha");	/* nome da função do lua */
    lua_pushnumber(L, 3);		/* envia primeiro argumento */
    lua_pushnumber(L, 4);		/* envia segundo argumento */
    lua_pcall(L, 2, 1, 0);
    z = lua_tonumber(L, -1);		/* pega resultados */
    printf("Resultado: %f\n",z);
    lua_pop(L, 1);
    lua_close(L);
    return 0;
}
_EOF_

e o arquivo lua:

$ cat > quatro.lua << _EOF_
function continha (x, y)
    return math.sqrt(x^2 + y^2)
end
_EOF_

Como sempre, a compilação é a mesma:

$ gcc -I/usr/include/lua5.1 -o 4 4.c -llua5.1 -lm
$ ./4
Resultado: 5.000000

Lindo!
Como podemos ver, embarcar lua em c não só faz sentido, como pode facilitar muito a extensão de um software mais complexos. E é por isto que é tão udada em jogos e em aplicações mobile(compiladas com c++).
Usem lua, é uma coisa linda!
haha

Acessando PCI Express com python

Usando lspci para retornar o valor do dispositivo:
01:00.0 Non-VGA unclassified device: Altera Corporation Device 0de4 (rev 01)
Encontra-o em /sys/devices/
/sys/devices/pci0000:00/0000:00:01.0/0000:01:00.0
Habilita-o com:

 echo -n 1 > /sys/devices/pci0000:00/0000:00:01.0/0000:01:00.0/enable 

Depois, só rodar o script(salvar como placapci.py):

import mmap, sys
with open('/sys/devices/pci0000:00/0000:00:01.0/0000:01:00.0/resource0', 'r+b') as f:
    mm = mmap.mmap(f.fileno(), 32)
    mm[:1] = chr(int(sys.argv[1], 16))

no caso, ativar os leds de uma altera lindona:
python placapci.py 0xAA
01
python placapci.py 0x55
02

É isso aí.

Minha primeira tentativa de decodificar um apk android e usar seu serviço

UPDATE 15/maio/2014 no final do arquivo!
UPDATE 20/novembro/2015 no final do arquivo!

Escolhi como meu primeiro alvo a aplicaçao:
https://play.google.com/store/apps/details?id=br.gov.sinesp.cidadao.android
que checa os dados das placas dos carros e diz qual carro é. Algo bem inocente ;D
Depois de baixar o br.gov.sinesp.cidadao.android.apk e checar sua estrutura interna, pude ver que apenas classes.dex, resources.arsc e AndroidManifest.xml eram interessantes.
Primeiro procurei uma ferramente para transformar o dex em jar. Pela ordem das pesquisas no google, tentei inicialmente o apktool( http://android-apktool.googlecode.com/files/apktool1.5.2.tar.bz2 ), mas nao funcionou, deu trocentos erros. Passei para o dex2jar( http://dex2jar.googlecode.com/files/dex2jar-0.0.9.15.zip )… esse funcionou como mágica e gerou o classes_dex2jar.jar, que abri com o jd-gui ( http://jd.benow.ca/jd-gui/downloads/jd-gui-0.3.5.linux.i686.tar.gz ). Comecei a explorar.
Iniciando em br.gov.sinesp.cidadao, vi que android.* nao tinha nada interessante. Mas tanto util.Hash quanto cordova.plugin.InfoAplicacaoPlugin pareciam promissores.
Comecei, lógico, pelo Hash.

public class Hash
{
public static String generateHash(String paramString1, String paramString2)
{
SecretKeySpec localSecretKeySpec = new SecretKeySpec(paramString1.getBytes(), "HmacSHA1");
try
{
Mac localMac = Mac.getInstance("HmacSHA1");
localMac.init(localSecretKeySpec);
byte[] arrayOfByte = localMac.doFinal(paramString2.getBytes());
new Hex();
String str = new String(Hex.encode(arrayOfByte), "UTF-8");
return str;
}
...

Um método bem simples que usa HMAC(Hash-based Message Authentication Code) para gerar o hash encodado em hexa vindo de dois parametros (paramString1 e paramString2). Implementar HMAC em python e hex encodar a saida é trivial:

from hashlib import sha1
from hmac import new as hmac
generateHash = lambda(placa): hmac(paramString1, paramString2, sha1).digest().encode('hex')

Agora é achar o diacho destes paramString1 e paramString2.
Através da documentação do PhoneGap( http://docs.phonegap.com/en/2.0.0/guide_plugin-development_android_index.md.html ), cheguei a classe Plugin, que deve ser chamado no javascript da view da aplicação. O formato do chamado ao plugin é:

exec(<successFunction>, <failFunction>, <service>, <action>, [<args>]);

Ou seja, a função chamada caso o request seja um sucesso, caso ele falhe, o serviço, ação e os parametros. Não encontrei no código original os parametros tais quais estão definidos, porem na classe InfoAplicacaoPlugin que extende CordovaPlugin e que está em /br/gov/sinesp/cidadao/cordova/plugin/, encontrei as definiçoes dos plugins, especialmente:

public final String ACTION_GET_APP_INFO = "getAppInfo";
public final String ACTION_GET_TOKEN = "getToken";
...
private String chave = "sheacsrhet";

E no método execute encontrei:

if ("getToken".equals(paramString))
{
String str1 = paramJSONArray.getString(0);
localJSONObject.put("token", Hash.generateHash(this.chave, str1));
}
paramCallbackContext.success(localJSONObject);

Huhuhu… já tenho a chave, so preciso descobrir o que raios é paramJSONArray.getString(0).
Dando mais uma passeada pelo javascript, encontrei em /assets/www/js/plugin/InfoApp.js o seguinte:
InfoApp.prototype.getToken = function(funcaoRetornoSucesso, funcaoRetornoErro, dados)
Ou seja, uma redefinição do exec original onde apenas 3 parametros eram necessarios! Procurando um pouco mais, achei em /assets/www/js/sinesp-cidadao.js o seguinte:

window.plugins.infoApp.getToken(
function(retorno){
sucessoGetToken(retorno);
var ws = new WebService(URL_SERVICO);
var parametrosHeader = getParametrosHeader();
var parametrosBody = getParametrosBody();
ws.call(METODO_SERVICO, parametrosHeader, parametrosBody, retornoServico, retornoServicoErro);
},
erroGetToken,
[placa]
);

Então, pude saber que paramJSONArray.getString(0) era a própria placa. Ufa.
Agora fica fácil reescrever a função de HASH em python:

from hashlib import sha1
from hmac import new as hmac
generateHash = lambda(placa): hmac("sheacsrhet",placa,sha1).digest().encode('hex')

Sniffei a saida do app e meu código. O hash bateu ;D
Porém, tambem tem como parametro IP e localizacao geografica(lat e long). Não sei se o sistema pode restringir a checagem por local/IP, então, porque nao randomizar tambem? ;D
Latitute e longitude é facil fazer um esquema para randomizar o valor dentro de um raio de cobertura, evitando de por um local inexistente ou, sei lá, no Japão.

rLat = lambda(raio): '%.7f' % (( raio/111000.0 * math.sqrt(random.random()) ) * math.cos(2 * 3.141592654 * random.random()) + (-3.7506985))

rLong = lambda(raio): '%.7f' % (( raio/111000.0 * math.sqrt(random.random()) ) * math.sin(2 * 3.141592654 * random.random()) + (-38.5290245))

Usei a latitude e longitude de Fortaleza/Ceará como referencia.
O próximo passo é montar tudo:

#coding: utf-8
import socket
import random, math
from hashlib import sha1
from hmac import new as hmac

generateHash = lambda(placa): hmac("sheacsrhet",placa,sha1).digest().encode('hex')

rLong = lambda(raio): '%.7f' % (( raio/111000.0 * math.sqrt(random.random()) ) * math.sin(2 * 3.141592654 * random.random()) + (-38.5290245))

rLat = lambda(raio): '%.7f' % (( raio/111000.0 * math.sqrt(random.random()) ) * math.cos(2 * 3.141592654 * random.random()) + (-3.7506985))

pacote = lambda(placa): 'POST /sinesp-cidadao/ConsultaPlaca HTTP/1.1\nHost: sinespcidadao.sinesp.gov.br\nContent-Length: %d\nOrigin: file://\nSOAPAction: \nContent-Type: application/x-www-form-urlencoded; charset=UTF-8\nAccept: text/plain, */*; q=0.01\nx-wap-profile: http://wap.samsungmobile.com/uaprof/GT-S7562.xml\nUser-Agent: Mozilla/5.0 (Linux; U; Android 4.1.4; pt-br; GT-S1162L Build/IMM76I) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30\nAccept-Encoding: gzip,deflate\nAccept-Language: pt-BR, en-US\nAccept-Charset: utf-8, iso-8859-1, utf-16, gb2312, gbk, *;q=0.7\n\n%s' % ( len(payload(placa)), payload(placa) )

payload = lambda(placa): '<?xml version="1.0" encoding="utf-8" standalone="yes" ?><soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" ><soap:Header><dispositivo>GT-S1312L</dispositivo><nomeSO>Android</nomeSO><versaoAplicativo>1.1.1</versaoAplicativo><versaoSO>4.1.4</versaoSO><aplicativo>aplicativo</aplicativo><ip>177.206.169.90</ip><token>%s</token><latitude>%s</latitude><longitude>%s</longitude></soap:Header><soap:Body><webs:getStatus xmlns:webs="http://soap.ws.placa.service.sinesp.serpro.gov.br/"><placa>%s</placa></webs:getStatus></soap:Body></soap:Envelope>\n/sinesp-cidadao/ConsultaPlaca HTTP/1.1\r<br>\r\n' % (generateHash(placa),rLat(20000),rLong(20000), placa)

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(("sinespcidadao.sinesp.gov.br", 80))
s.send(pacote('XXX0000'))
print s.recv(1024)
s.close()

Pronto. Funciona ;D Para efeito de beleza, pode-se usar alguma lib de parsing de XML ou mete um belo e bruto regex da escuridão para parsear tudo com a sutileza de um macaco-ogro do pântano.

 

[UPDATE 15/maio/2014] Conforme foi percebido pelo Lúcio Corrêa( @luciofcorrea ), o sistema mudou e a sinesp tentou obfuscar o resultado. Mas não foi muito difícil gerar novamente o HASH e obter os novos parametros.
Primeiro, em /br/gov/sinesp/cidadao/android/f/k.class foi mantida a chave antiga, para enganar uma busca por strings, porem em /br/gov/sinesp/cidadao/android/f/j.class a localSecretKeySpec mudou, ao invés de usar o valor em k.java, ele seta a senha estáticamente:

SecretKeySpec localSecretKeySpec = new SecretKeySpec("shienshenlhq".getBytes(), "HmacSHA1");

Desta forma, a nova chave é “shienshenlhq”.
Em /br/gov/sinesp/cidadao/android/f/a.class temos

public static final String a = "http://sinespcidadao.sinesp.gov.br/sinesp-cidadao/ConsultaPlacaNovo27032014";

ou seja, muda a string a se fazer o POST.
Já em /br/gov/sinesp/cidadao/android/e/c.class, encontramos o novo campo a ser incluído: versaoAplicativo, com conteudo fixo “1.1.1” e o parametro aplicativo agora tem o valor fixo “aplicativo”.
Com tudo isto incluído, o script voltou a funcionar. e está postado no meu github: https://github.com/paoloo/servicos/blob/master/placa.py

[UPDATE 20/NOVEMBRO/2015] Como da ultima vez, a string de request estava obfuscada, mas foi encontrada pelo grande Junior Kaibro, que a postou no comentario. O novo POST é feito para /sinesp-cidadao/ConsultaPlacaNovo e só, nada mais mudou. Atualizei no github. Depois de tanto tempo é legal ver o pessoal mantendo a ferramenta viva. E se colocarem captcha, relaxem, eu quebro ;D

variaveis e funçoes em caracteres nao-ascii: uma realidade perturbadora

Quanto tempo levará para codigos como o descrito aqui (que funciona, infelizmente) se tornarem comuns? Eu sei, em alguns casos isso é util (EXs: var π = Math.PI ou var λ = function(){};) e que neste caso do meu exemplo, são apenas componentes dos alfabetos japoneses. Porém, alem de vários alfabetos, tambem são permitidos coisas absurdas como ಠ益ಠ ou 个卐Δℕ, e isto é um convite ao caos!!!!!!!!

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<script>
var ヽン = function(ヽロノ){ alert(ヽロノ); }
var ヽo_oノ = function(){ ツ = "ヽo_oノ ", ー=0; while(ー<9){ツ+=ツ; ー++;} return ツ; }
</script>
</head>
<body>
<input type="button" onClick="javascript:ヽン(ヽo_oノ())">
</body>
</html>

É ou não é bizarro?

Ah, uma forma rápida de checar se a variável é permitida(alem de escrever em um texto e abrir no navegador hahahaha), é através do site http://mothereff.in/js-variables.