app逆向练手系列
1.回音 360加固
import hashlib import time import uuid import requests from urllib.parse import quote_plus def get_sign(params): concat_params = "&".join(f"{key}={quote_plus(str(params[key]), safe='')}" for key in sorted(params)) if len(concat_params) > 10: salt = "meXlhxAm9Lh17V76g5gQZ4C3ELVZgjAg" elif len(concat_params) >= 6: salt = "2S1rybDLpQv4F6jM9zCNJ0Fq436ZfnJ5" else: salt = "sdlfkl345sdfewrs" cipher_text = f"{concat_params}|{salt}" first = hashlib.md5(cipher_text.encode("utf-8")).hexdigest() if len(concat_params) > 10: return hashlib.md5((cipher_text + first).encode("utf-8")).hexdigest() return first url = "https://api.xinyuhole.com/api/dynamic/getPlazaHomePage" params = { 'appkey': "3ak70bq5z9v6f50cj197", 'category': "2", 'deviceDate': int(time.time() * 1000), 'deviceID': "ecd31af825cd749619661be2683ba0e3", 'pg': "0", 'requestId': uuid.uuid4().hex, # 不校验随便写 'size': "10", 'userId': "10734230", 'userToken': "", } # params['requestId'] = hashlib.md5( # (str(uuid.uuid4()) + params['deviceDate']).encode('utf-8') # ).hexdigest() params['sign'] = get_sign(params) headers = { 'User-Agent': "{\"appName\":\"HeartVoice\",\"appVersion\":\"2.23.1\",\"channel\":\"oppo\",\"cpuType\":\"redfin-redfin\",\"deviceName\":\"google-Pixel 5\",\"displayHeight\":\"2160\",\"displayWidth\":\"1080\",\"systemVersion\":\"Android12\"}", 'Connection': "Keep-Alive", 'Accept-Encoding': "gzip" } response = requests.get(url,params=params, headers=headers, timeout=30) if response.content: text = response.content.decode("utf-8", errors="replace") print(text)
so层算法 360脱壳

2.酷安
"""Pure-Python Coolapk X-App-Device/X-App-Token generation and request.""" from __future__ import annotations import base64 import hashlib import json import os import secrets import time import bcrypt import requests # libauth.so .rodata 0x408e6: Base64 -> XOR 0x5a gives the rotating table. _TOKEN_TABLE_B64 = ( "Dg4YDxUcCykLah82Fg8XMQ0eHzALCR8pDyMfNxYeFBsPI2seChwDLxMjajMXDxdvEyAYDxAcOS4XIzEyFw8LaxAJax4VCQ8iFyAyCxYMFy0MamopEyMyCRcOCykNDhweCBwfLQtqCAwXCQsxDwlqMBEJFy4QHjIDFgwLMQ8wHyARCQspF2oYDBYOCy0PM2pqFAkXKRdoGAIWDBc2EBlrHhQcNhQWGQtqDQ4fIBYJCyILah8yFh8XNhMwHyARHDktFyBqNhYzFB8MIB8wCgkDLxQeMTEWHBctDDMiDhEcMS4LIDICFhwXKQ0ZbjAWCQMuD2gYDg4OG2oWHB8vFyAyDhYwFzITMBweFxwXKRNqGAwWGQsxDxktIBAJEykTIBgJFx8XYg8ZIh8WCRMuE2gYCxYPCzUPI2owFhwXKRMjDzEXHAstDDFqLggZIgMXDhc2EBluahQJHy0PaggLFhwXMhMzajEUCRctD2gYCxYwFD0PIy0wFRwfKRQZIg4WHxctDRkiDxYJHy4TIwgOFh4UGBMjamoQHAAUFw8XKQ8eGB8QHD0uFBlqMRYeCzENGWseFxwXIggZMTAWDBdqDDMiDhccPSITI2o3FgwXIhAJaiAQHAsiF2gYCxYJC24NDhgeFxwXLxNqDzIOCS0gChw9LggeGAgXHhQfDwlqMBUcAy8QHjE2FwkLag8gGyAUCRctCB4xMRcOFzEMCSIPFxwLLggZIgMXDhQcEyMiHxYcAykTIA8yFjMLagxqaiIUGSIMFhkXagwjbiAQHA8iFBkiDhYcC24MI24wAxwDIhAeDzAWDxctDyAcHgocEykXah82Fh4XKQweG2oVCRcvFBkxNxYfCzEMMyIfFwkQFBYOFzUPMy0gFhw5Lg9qCAsWMwstDA4cHhAJDy0PIzEwFw8XMhMjaiATCQ8pE2ofMBcOFy0PCWsPFBw5IggeHzYWDwsuEAluMRQcEykTIDIADg4YDgMcHy0LIwgDFgkXNhMJbmoWHD0pDB4IABYPCzUNDhgeCxwDLggZIg0WMBQfDB4YHhccMS4UHg82FhwLbgwJaw8QHD0tFyAIDRYeC24PD2otCyNqNxYPC24NCWsOFwkXKQ8jDzMXDxQbDwkiDxYcAy8TaggPFjMXKQ0eHB8WHBciE2gYCxYMF2oNCW4xFRw5LRdqCAIWDBc1DRlqMBEcHyIWGRdqDDMiDhQcGy4IHggNFg8LNhAZaw4QHBstFBkiPQMb" ) def token_table(clock: int, version_code: int) -> bytes: """Recover the native rotating table and select its 128-byte window.""" decoded = base64.b64decode(_TOKEN_TABLE_B64) table = bytes(value ^ 0x5A for value in decoded) offset = ((int(clock) + int(version_code)) % 100) * 4 + 0x80 return table[offset:offset + 0x80] def generate_device_header(aid: str | None = None, mac: str = "", manufacturer: str = "Google", brand: str = "google", model: str = "Pixel 5", build_number: str = "SQ3A.220705.003.A1") -> str: """Generate the real ``X-App-Device`` field layout used by Coolapk. Native/Java constructs nine ``; `` separated fields, Base64 encodes the UTF-8 bytes without padding, then reverses the complete Base64 string. """ if aid is None: aid = secrets.token_urlsafe(27) fields = (aid, "", "", mac, manufacturer, brand, model, build_number, "null") plain = "; ".join(fields).encode("utf-8") return base64.b64encode(plain).decode("ascii").rstrip("=")[::-1] def decode_device_header(value: str) -> str: """Decode an ``X-App-Device`` value for verification/debugging.""" encoded = value[::-1] return base64.b64decode(encoded + "=" * ((-len(encoded)) % 4)).decode("utf-8") def generate_app_token(device: str, timestamp: int | str, *, app_id: str = "com.coolapk.market", app_code: str = "2608212", clock: int | None = None) -> str: """Generate the recovered v3 token pipeline from request/device context.""" if clock is None: clock = int(timestamp) window = token_table(clock, int(app_code)) rotating = base64.b64decode(window + b"=" * ((-len(window)) % 4)) device_md5 = hashlib.md5(device.encode("utf-8")).hexdigest() material = (app_id.encode("utf-8") + b"&" + rotating + b"&" + device_md5.encode("ascii") + b"&" + str(timestamp).encode("ascii") + b"&" + app_code.encode("ascii")) material_b64 = base64.b64encode(material) password = hashlib.md5(material_b64).hexdigest().encode("ascii") material_md5 = hashlib.md5(material).hexdigest() salt_seed = base64.b64encode( f"{int(timestamp):x}/{material_md5}".encode("ascii") ).decode("ascii").rstrip("=") salt_body = salt_seed.translate(str.maketrans({"+": "."}))[:22] bcrypt_alphabet = "./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" last_index = bcrypt_alphabet.index(salt_body[-1]) & 0x30 salt_body = salt_body[:-1] + bcrypt_alphabet[last_index] salt = ("$2y$04$" + salt_body).encode("ascii") hashed = bcrypt.hashpw(password, salt) if hashed.startswith(b"$2b$"): hashed = b"$2y$" + hashed[4:] return "v3" + base64.b64encode(hashed).decode("ascii").rstrip("=") API_URL = "https://api.coolapk.com/v6/main/init" APP_CODE = "2608212" USER_AGENT = ( "Dalvik/2.1.0 (Linux; U; Android 12; Pixel 5 Build/SQ3A.220705.003.A1) " "(#Build; google; Pixel 5; SQ3A.220705.003.A1; 12) " "+CoolMarket/16.6.1-2608212-community" ) def request_init(aid: str | None = None) -> requests.Response: timestamp = str(int(time.time())) device = generate_device_header(aid) token = generate_app_token(device, timestamp) headers = { "User-Agent": USER_AGENT, "X-Requested-With": "XMLHttpRequest", "X-Sdk-Int": "32", "X-Sdk-Locale": "zh-CN", "X-App-Id": "com.coolapk.market", "X-App-Version": "16.6.1", "X-App-Code": APP_CODE, "X-Api-Version": "16", "X-Dark-Mode": "1", "X-App-Channel": "xiaomi", "X-App-Mode": "community", "X-App-Supported": APP_CODE, "X-App-Device": device, "X-App-Token": token, } return requests.get( API_URL, params={"exp": "0", "t": timestamp}, headers=headers, timeout=20, ) def main() -> None: response = request_init(os.getenv("APP_AID")) print(f"HTTP_STATUS={response.status_code}") try: body = response.json() print(f"RESULT={'OK' if isinstance(body.get('data'), list) else 'ERROR'}") print(json.dumps(body, ensure_ascii=False, separators=(',', ':'))) except ValueError: print("RESULT=ERROR") print(response.text) if __name__ == "__main__": main()

葫芦侠


浙公网安备 33010602011771号