A análise de dados retornados por requisições web frequentemente revela que a informação pode estar cifrada. Este artigo detalha o processo de decifração de respostas de uma API específica, utilizando tanto Python quanto a execução direta de código JavaScript.
Ao inspecionar o tráfego de rede para o endpoint https://www.swguancha.com/home/city-detail?code=310100, observa-se que os dados de resposta são strings cifradas. Em cenários onde os dados de retorno são criptografados, é comum que a lógica de decifragem esteja implementada através de interceptadores (interceptors) no lado do cliente.
A investigação do código JavaScript revela a presença de interceptadores de resposta. Após análise, um dos interceptadores exibe palavras-chave como decrypt e AES, indicando que a lógica de decifragem reside ali.
Definindo um ponto de interrupção (breakpoint) e recarregando a página, podemos examinar as variáveis relevantes. t.data contém a resposta cifrada, enquanto key e iv (se aplicável) são utilizados para o processo de decifragem. A chave (key) é obtida a partir de uma constante definida no código (l) e convertida para UTF-8. O modo de operação, identificado como u.mode.ECB, confirma o uso do modo ECB (Electronic Codebook). Neste caso específico, o vetor de inicialização (iv) não é necessário devido ao modo ECB.
Implementação em Python
A decifragem pode ser realizada diretamente em Python utilizando a biblioteca pycryptodome.
import requests
from Crypto.Cipher import AES
from Crypto.Util.Padding import unpad
import base64
# O URL da API pode variar dependendo do endpoint específico
api_url = "https://app.swguancha.com/client/v1/cPublic/consumer/property/type/search?level=2"
# Cabeçalhos necessários para a requisição
request_headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36",
"Referer": "https://www.swguancha.com/"
}
# Realiza a requisição GET
response = requests.get(api_url, headers=request_headers)
# A resposta bruta pode conter espaços que precisam ser removidos
encrypted_data_raw = response.text.replace(" ", "")
# Chave de decifragem obtida da análise do JavaScript
decryption_key_str = "QV1f3nHn2qm7i3xrj3Y9K9imDdGTjTu9"
decryption_key_bytes = decryption_key_str.encode("utf-8")
# Configuração do cifrador AES em modo ECB
cipher_aes = AES.new(key=decryption_key_bytes, mode=AES.MODE_ECB)
# Decifra os dados: primeiro decodifica de Base64, depois aplica AES
decrypted_data_bytes = cipher_aes.decrypt(base64.b64decode(encrypted_data_raw))
# Remove o padding PKCS7
decrypted_data_unpadded = unpad(decrypted_data_bytes, 16)
# Converte os bytes decifrados para string UTF-8
original_data = decrypted_data_unpadded.decode("utf-8")
print(original_data)
Execução de Código JavaScript com Python
Alternativamente, é possível executar o código JavaScript original que realiza a decifragem, utilziando a biblioteca PyExecJS.
Primeiro, crie um arquivo decryptor.js com o seguinte contteúdo:
var CryptoJS = require("crypto-js");
var encryptionKey = "QV1f3nHn2qm7i3xrj3Y9K9imDdGTjTu9";
function decryptResponse(encryptedText) {
var keyParsed = CryptoJS.enc.Utf8.parse(encryptionKey);
var decrypted = CryptoJS.AES.decrypt(encryptedText, keyParsed, {
mode: CryptoJS.mode.ECB,
padding: CryptoJS.pad.Pkcs7
});
var decryptedString = decrypted.toString(CryptoJS.enc.Utf8);
var jsonData = JSON.parse(decryptedString);
return jsonData;
}
Em seguida, utilize o seguinte script Python para chamar a função JavaScript:
from functools import partial
import subprocess
import requests
import base64
import execjs
# Necessário para garantir que subprocess.Popen use encoding UTF-8
subprocess.Popen = partial(subprocess.Popen, encoding="utf-8")
api_url = "https://app.swguancha.com/client/v1/cPublic/consumer/property/type/search?level=2"
request_headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36",
"Referer": "https://www.swguancha.com/"
}
response = requests.get(api_url, headers=request_headers)
encrypted_data_raw = response.text.replace(" ", "")
# Carrega o código JavaScript do arquivo
with open("decryptor.js", "r", encoding="utf-8") as f:
js_code = f.read()
# Compila o código JavaScript
js_runtime = execjs.compile(js_code)
# Chama a função JavaScript com os dados cifrados
decrypted_result = js_runtime.call("decryptResponse", encrypted_data_raw)
print(decrypted_result)
Ambos os métodos permitem obter os dados originais da API, demonstrando a flexibilidade ao lidar com diferentes requisitos de implementação.