{"id":51091177,"url":"https://github.com/linkmail16/happymod-reverse-engineering","last_synced_at":"2026-06-24T02:02:18.842Z","repository":{"id":360417101,"uuid":"1250020813","full_name":"Linkmail16/HappyMod-Reverse-Engineering","owner":"Linkmail16","description":null,"archived":false,"fork":false,"pushed_at":"2026-05-26T09:33:00.000Z","size":57,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-26T11:16:32.020Z","etag":null,"topics":["happymod","reverse-engineering","reversing"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Linkmail16.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-05-26T08:27:57.000Z","updated_at":"2026-05-26T09:33:12.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/Linkmail16/HappyMod-Reverse-Engineering","commit_stats":null,"previous_names":["linkmail16/happymod-reverse-engineering"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/Linkmail16/HappyMod-Reverse-Engineering","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Linkmail16%2FHappyMod-Reverse-Engineering","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Linkmail16%2FHappyMod-Reverse-Engineering/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Linkmail16%2FHappyMod-Reverse-Engineering/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Linkmail16%2FHappyMod-Reverse-Engineering/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Linkmail16","download_url":"https://codeload.github.com/Linkmail16/HappyMod-Reverse-Engineering/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Linkmail16%2FHappyMod-Reverse-Engineering/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34713791,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-24T02:00:07.484Z","response_time":106,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["happymod","reverse-engineering","reversing"],"created_at":"2026-06-24T02:02:18.058Z","updated_at":"2026-06-24T02:02:18.837Z","avatar_url":"https://github.com/Linkmail16.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# ApkOmega / HappyMod API — Reverse Engineering Documentation\n\nLa documentacion la obtuve realizando ingenieria inversa al apk de HappyMod\n\n---\n\n## Tabla de contenidos\n\n1. [Generacion del UID](#1-generacion-del-uid)\n2. [Generacion del Stamp](#2-generacion-del-stamp)\n3. [Decodificacion de la respuesta](#3-decodificacion-de-la-respuesta)\n4. [Una implementacion mia en Python](#4-implementacion-completa-en-python)\n5. [Endpoints basicos de la app](#5-endpoints-documentados-de-la-aplicacion)\n  \n   - 5.1 [Sincronizacion de tiempo del servidor](#51-sincronizacion-de-tiempo-del-servidor)\n   - 5.2 [Busqueda de aplicaciones](#52-busqueda-de-aplicaciones)\n   - 5.3 [Generacion del Hash de descarga](#53-generacion-del-hash-de-descarga)\n   - 5.4 [Descarga del APK](#54-descarga-de-apk)\n   - 5.5 [Detalle de aplicacion](#55-detalle-de-aplicacion)\n\n---\n\n## 1. Generacion del UID\n\n### Algoritmo\n\n```\nuid = MD5( prefijo + identificador )\n```\n\n#### Prefijo (siempre igual para el mismo dispositivo)\n\n```python\nprefijo = \"35\"\nprefijo += str(len(Build.BOARD)        % 10)\nprefijo += str(len(Build.BRAND)        % 10)\nprefijo += str(len(Build.DEVICE)       % 10)\nprefijo += str(len(Build.DISPLAY)      % 10)\nprefijo += str(len(Build.HOST)         % 10)\nprefijo += str(len(Build.ID)           % 10)\nprefijo += str(len(Build.MANUFACTURER) % 10)\nprefijo += str(len(Build.MODEL)        % 10)\nprefijo += str(len(Build.PRODUCT)      % 10)\nprefijo += str(len(Build.TAGS)         % 10)\nprefijo += str(len(Build.TYPE)         % 10)\nprefijo += str(len(Build.USER)         % 10)\n```\n\n#### Identificador (por orden de prioridad)\n\n```\n1. Google Advertising ID (GAID) -- preferido en dispositivos modernos\n        si GAID es null o contiene \"00000000\" -- siguiente\n2. Build.SERIAL + ANDROID_ID -- Android \u003c 8.0 (SDK \u003c 26)\n        si vacio \u003e siguiente\n3. UUID aleatorio persistido en:\n        Android \u003e= 13  → SharedPreferences\n        Android 6-12   → Downloads/HappyMod/device_id.txt (si hay permisos)\n                         o sharedPreferences si no hay permisos\n        Android \u003e= 10  → MediaStore (device_id.png en Downloads/HappyMod/)\n```\n\n#### Implementacion Python\n\n```python\nimport hashlib\n\ndef generate_uid(board, brand, device, display, host,\n                 build_id, manufacturer, model, product,\n                 tags, type_, user, identifier: str) -\u003e str:\n    prefix = \"35\"\n    for field in [board, brand, device, display, host,\n                  build_id, manufacturer, model, product,\n                  tags, type_, user]:\n        prefix += str(len(field) % 10)\n    return hashlib.md5((prefix + identifier).encode()).hexdigest()\n```\n\n---\n\n## 2. Generacion del Stamp\n\n### El `time_str`\n\n```java\n// C0060b.m256b()\ntime_str = (System.currentTimeMillis() / 1000) - offset_servidor\n```\n\nEl `offset_servidor` es la diferencia entre el reloj local y el timestamp\ndevuelto por `server_time.php`, entonces, `time_str` es el\ntimestamp unix actual en segundos sincronizado con el servidor\n\n### Logica nativa (`libCSTAMP.so`)\n\nFuncion:\n`Java_com_happymod_apk_utils_NativeHelper_getStamp`:\n\n```c\n// argumentos: a3 = time_str,  a4 = uid\nv11 = Jstring2CStr(a1, a4);   // uid\nv10 = Jstring2CStr(a1, a3);   // time_str\n\nptr = malloc(len(v11) + len(v10) + len(KEY) + 1);\nstrcpy(ptr, v11);              // uid\nstrcat(ptr, v10);              // + time_str\nstrcat(ptr, KEY);              // + \"this_is_happymod\"\n\nMD5Init();\nMD5Update(ctx, ptr, len(ptr));\nMD5Final(digest, ctx);\n\n// formatea los 16 bytes como hex lowercase\nfor i in 0..15:\n    sprintf(result, \"%s%02x\", result, digest[i])\n\nreturn result;\n```\n\nkey extraida del segmento `.rodata` de `libCSTAMP.so` en offset `0x989`:\n```\n\"this_is_happymod\"\n```\n\n### Quedaria asi\n\n```\nstamp = MD5( uid + time_str + \"this_is_happymod\" )\n```\n\n#### Aca entonces en Python\n\n```python\nimport hashlib, time, requests\n\ndef get_server_offset(uid: str) -\u003e int:\n    r = requests.post(\n        \"https://app.apkomega.com/202010/api/server_time.php\",\n        data={\"version\": \"3.2.6\", \"uid\": uid, \"country\": \"CO\"}\n    )\n    body = decode_response(r.text)\n    data = json.loads(body)\n    if data.get(\"status\") == 1:\n        return int(time.time()) - data[\"timestamp\"]\n    return 0\n\ndef get_stamp(uid: str, offset: int = 0) -\u003e str:\n    time_str = str(int(time.time()) - offset)\n    key      = \"this_is_happymod\"\n    raw      = uid + time_str + key\n    return hashlib.md5(raw.encode()).hexdigest()\n```\n\n---\n\n## 3. Decodificacion de la respuesta\n\nLa respuesta http no es json directo, pasa por tres capas en orden:\n\n```\nrespuesta http raw\n        |\n        v\n[1] sustitucion posicional (vigenere numerico inverso)\n        |\n        v\n[2] base64 decode  (alphabet estandar A-Za-z0-9+/)\n        |\n        v\n[3] gzip decompress  (si magic bytes == 0x1f 0x8b)\n        |\n        v\njson valido\n```\n\n### 1 — Sustitucion posicional \n\nPara cada caracter en posicion `i`:\n- Si es alfanumerico `[0-9 A-Z a-z]`:\n  - `shifted = ASCII(char) - (i % 10)`\n  - Wrapping entre los tres rangos `[48-57]`, `[65-90]`, `[97-122]`\n\n```python\ndef vigenere_decode(raw: str) -\u003e str:\n    result = []\n    for i, ch in enumerate(raw):\n        code = ord(ch)\n        if (48 \u003c= code \u003c= 57) or (65 \u003c= code \u003c= 90) or (97 \u003c= code \u003c= 122):\n            shifted = code - (i % 10)\n            if shifted \u003c 48:\n                code = 122 - (48 - shifted) + 1\n            elif code \u003c 65 or shifted \u003e= 65:\n                if code \u003c 97 or shifted \u003e= 97:\n                    code = shifted\n                else:\n                    code = (90 - (97 - shifted)) + 1\n            else:\n                code = (57 - (65 - shifted)) + 1\n        result.append(chr(code))\n    return ''.join(result)\n```\n\n### 2 — Base64 decode\n\nAlphabet estandar (`f20716a` / `f20717b`, flags=0):\n```\nA-Z a-z 0-9 + /\n```\n\n```python\nimport base64\ndef b64_decode(s: str) -\u003e bytes:\n    return base64.b64decode(s + '==')  # padding por si falta\n```\n\n### 3 — Gzip decompress (`m22190e`)\n\nEl metodo detecta automaticamente el magic header `0x1f 0x8b`:\n\n```python\nimport gzip\ndef maybe_gunzip(data: bytes) -\u003e bytes:\n    if data[:2] == b'\\x1f\\x8b':\n        return gzip.decompress(data)\n    return data\n```\n\n### Funcion completa\n\n```python\ndef decode_response(raw: str) -\u003e str:\n    step1 = vigenere_decode(raw)\n    step2 = b64_decode(step1)\n    step3 = maybe_gunzip(step2)\n    return step3.decode('utf-8')\n```\n\n---\n\n## 4. Mi implementacion en Python\n\n```python\nimport hashlib, base64, gzip, time, json\nimport requests\n\n# los datos que requiere el endpoint\n\nUID     = \"68920e5674b1d3ec969e4637d31e0345\"  \nVERSION = \"3.2.6\"\nLANG    = \"es\"\nBASE    = \"https://app.apkomega.com\"\n\n# decodificamos\ndef vigenere_decode(raw: str) -\u003e str:\n    result = []\n    for i, ch in enumerate(raw):\n        code = ord(ch)\n        if (48 \u003c= code \u003c= 57) or (65 \u003c= code \u003c= 90) or (97 \u003c= code \u003c= 122):\n            shifted = code - (i % 10)\n            if shifted \u003c 48:\n                code = 122 - (48 - shifted) + 1\n            elif code \u003c 65 or shifted \u003e= 65:\n                code = shifted if (code \u003e= 97 and shifted \u003e= 97) else (90 - (97 - shifted)) + 1\n            else:\n                code = (57 - (65 - shifted)) + 1\n        result.append(chr(code))\n    return ''.join(result)\n\ndef decode_response(raw: str) -\u003e str:\n    step1 = vigenere_decode(raw)\n    step2 = base64.b64decode(step1 + '==')\n    if step2[:2] == b'\\x1f\\x8b':\n        step2 = gzip.decompress(step2)\n    return step2.decode('utf-8')\n\n# stamp\n\ndef get_server_offset(uid: str) -\u003e int:\n    try:\n        r = requests.post(\n            BASE + \"/202010/api/server_time.php\",\n            data={\"version\": VERSION, \"uid\": uid, \"country\": \"CO\"}\n        )\n        data = json.loads(decode_response(r.text))\n        if data.get(\"status\") == 1:\n            return int(time.time()) - data[\"timestamp\"]\n    except Exception as e:\n        print(\"Error obteniendo server time:\", e)\n    return 0\n\ndef get_stamp(uid: str, offset: int = 0) -\u003e str:\n    time_str = str(int(time.time()) - offset)\n    return hashlib.md5((uid + time_str + \"this_is_happymod\").encode()).hexdigest()\n\n# busqueda\n\ndef search(keyword: str, page: int = 1, is_new_user: bool = True) -\u003e dict:\n    offset = get_server_offset(UID)\n    stamp  = get_stamp(UID, offset)\n\n    payload = {\n        \"version\":     VERSION,\n        \"uid\":         UID,\n        \"stamp\":       stamp,\n        \"page\":        str(page),\n        \"keywords\":    keyword,\n        \"lang\":        LANG,\n        \"is_new_user\": \"1\" if is_new_user else \"2\",\n        \"is_input\":    \"2\",\n        \"input_word\":  keyword[:3],\n    }\n\n    r = requests.post(BASE + \"/202010/api/search_list.php\", data=payload)\n    return json.loads(decode_response(r.text))\n\n# ejemplo\n\nif __name__ == \"__main__\":\n    result = search(\"whatsapp\")\n    for app in result.get(\"list\", []):\n        print(app.get(\"title\"), \"-\", app.get(\"url_id\"))\n```\n\n---\n\n## 5. Endpoints documentados de la aplicacion\n\nTodos los endpoints que usan `stamp` requieren que este sea generado en el momento\nde la solicitud, la respuesta de todos los endpoints de `apkomega.com`\nusa el mismo esquema de cifrado descrito en la seccion 4\n\n---\n\n### 5.1 Sincronizacion de tiempo del servidor\n\n**URL:**\n```\nPOST https://app.apkomega.com/202010/api/server_time.php\n```\n\n**Payload:**\n\n| Campo     | Descripcion          | Ejemplo |\n|-----------|----------------------|---------|\n| `version` | Version del APK      | `3.2.6` |\n| `uid`     | UID del dispositivo  | `68920e5674b1d3ec969e4637d31e0345` |\n| `country` | Codigo de pais ISO   | `CO`    |\n\n**Respuesta decodificada**\n\n```json\n{\n  \"status\": 1,\n  \"timestamp\": 1716000000\n}\n```\n\n| Campo       | Descripcion                                      |\n|-------------|--------------------------------------------------|\n| `status`    | `1` = exito, `-20` = error de fecha              |\n| `timestamp` | Timestamp Unix actual del servidor (segundos)    |\n\nEl cliente calcula `offset = tiempo_local - timestamp_servidor` y lo resta\na cada `time_str` para sincronizar el stamp con el servidor\n\nOjo: El resultado se cachea en memoria (`_server_time_offset`) para no repetir\nla llamada en cada stamp\n\n---\n\n### 5.2 Busqueda de aplicaciones\n\n**URL:**\n```\nPOST https://app.apkomega.com/202010/api/search_list.php\n```\n\n**Payload:**\n\n| Campo        | Tipo  | Descripcion                                           | Ejemplo     |\n|--------------|-------|-------------------------------------------------------|-------------|\n| `version`    | str   | Version del APK                                       | `3.2.6`     |\n| `uid`        | str   | UID del dispositivo                                   | `68920e...` |\n| `stamp`      | str   | Token MD5 (ver seccion 3)                             | `aded81...` |\n| `page`       | int   | Numero de pagina (empieza en 1)                       | `1`         |\n| `keywords`   | str   | Termino de busqueda                                   | `whatsapp`  |\n| `lang`       | str   | Idioma ISO 639-1                                      | `es`        |\n| `is_new_user`| int   | `1` si el APK se instalo hoy, `2` si no               | `1`         |\n| `is_input`   | int   | `2` si el usuario escribio el termino, `1` si no      | `2`         |\n| `input_word` | str   | Primeros 3 chars escritos antes de buscar             | `wha`       |\n\n**Respuesta decodificada:**\n\n```json\n{\n  \"status\": 1,\n  \"has_next_page\": 1,\n  \"list\": [\n    {\n      \"mod_info\":          \"Mod descripcion\",\n      \"title\":             \"WhatsApp\",\n      \"icon\":              \"https://...\",\n      \"url_id\":            \"com.whatsapp\",\n      \"star\":              \"4.5\",\n      \"size\":              \"50M\",\n      \"author\":            \"WhatsApp Inc.\",\n      \"update_flag_image\": \"\",\n      \"has_faq\":           \"0\",\n      \"is_ad\":             0,\n      \"data_type\":         0\n    }\n  ]\n}\n```\n\n| Campo            | Descripcion                                              |\n|------------------|----------------------------------------------------------|\n| `status`         | `1` = hay resultados, `-20` = error de sesion            |\n| `has_next_page`  | `1` si hay mas paginas disponibles                       |\n| `url_id`         | Package name del APK — se usa en otras llamadas          |\n| `data_type`      | `1` = tiene lista de mods, `0` = APK simple              |\n| `is_ad`          | `1` = es un resultado patrocinado                        |\n| `update_flag_image` | URL de imagen de badge (ej. \"Updated\"), vacio si no   |\n\n---\n\n### 5.3 Generacion del hash de descarga\n\nEl `hash` es un hash es un token de autorizacion derivado\ndel package name del mod, construido cortando y reordenando 4 fragmentos de 4\ncaracteres del md5\n\n**Codigo java original:**\n\n```java\nString strM23357b = C8854j.m23357b(this.f2163b + \"android_require_apk\");\nString str27 = strM23357b.substring(10, 14)\n             + strM23357b.substring(25, 29)\n             + strM23357b.substring(18, 22)\n             + strM23357b.substring(5,  9);\n```\n\nDonde `this.f2163b` es el `url_id` del mod y `C8854j.m23357b()` es md5\n\n**Entonces:**\n\n```\nfull_md5 = MD5( url_id + \"android_require_apk\" )\nhash     = full_md5[10:14] + full_md5[25:29] + full_md5[18:22] + full_md5[5:9]\n```\n\n**Ya en python:**\n\n```python\nimport hashlib\n\ndef generate_hash(url_id: str) -\u003e str:\n    full_md5 = hashlib.md5((url_id + \"android_require_apk\").encode()).hexdigest()\n    return full_md5[10:14] + full_md5[25:29] + full_md5[18:22] + full_md5[5:9]\n```\n\n**Verificacion:**\n\n```\nurl_id  = \"com.mod.tiktok-videos-shop-livemod-apk-43-9-16\"\nfull_md5 = MD5(\"com.mod.tiktok-videos-shop-livemod-apk-43-9-16android_require_apk\")\n         = \"...2496...81fc...2664...746c...\"   (posiciones 5,10,18,25)\nhash    = \"24962664746c81fc\"  16 chars hex\n```\n\n---\n\n### 5.4 Descarga de APK\n\n**URL:**\n```\nPOST https://d.apkomega.com/202101/api/get_apk_download_v2.php\n```\n\nUsa subdominio `d.` (en lugar de `app.`) y ruta `202101` (en lugar de `202010`).\n\n**Payload:**\n\n| Campo      | Tipo  | Descripcion                                        | Ejemplo / Valor fijo         |\n|------------|-------|----------------------------------------------------|------------------------------|\n| `version`  | str   | Version del APK                                    | `3.2.6`                      |\n| `uid`      | str   | UID del dispositivo                                | `68920e...`                  |\n| `stamp`    | str   | Token MD5 (ver seccion 3)                          | generado en el momento       |\n| `country`  | str   | Codigo de pais ISO                                 | `US`                         |\n| `lang`     | str   | Idioma ISO 639-1                                   | `es`                         |\n| `hash`     | str   | Token de autorizacion de 16 chars (ver seccion 6.3)| `24962664746c81fc`           |\n| `url_id`   | str   | Package name del mod (no de la app base)           | `com.mod.tiktok-...`         |\n| `refer`    | str   | Titulo del mod concatenado con `\\|1`               | `TikTok Mod 43.9.16\\|1`      |\n| `aid`      | str   | ID fijo extraido de `libCSTAMP.so` offset `0x940`  | `98pyooirb6mad326`           |\n| `get_hpt`  | int   | Flag desconocido, siempre `0`                      | `0`                          |\n| `channel`  | str   | Canal de distribucion                              | `happymod`                   |\n| `username` | str   | Usuario logueado, vacio si no hay sesion           | `\"\"`                         |\n\n**Sobre `aid`:** Es el string `STRAID` extraido del segmento `.rodata` de\n`libCSTAMP.so`, generado por `NativeHelper.getAid()`\n\n**Sobre `url_id`:** Debe ser el `url_id` del mod especifico (Ejemplo:\n`com.mod.tiktok-videos-shop-livemod-apk-43-9-16`), no el package name de la app\nbase (`com.zhiliaoapp.musically`), el servidor devuelve `status: -10` si se usa\nel package base\n\n**Respuesta decodificada:**\n\n```json\n{\n  \"status\":      1,\n  \"url_id\":      \"com.mod.tiktok-videos-shop-livemod-apk-43-9-16\",\n  \"apk_path\":    \"http://s4-hot-2-c.happymodio.com/downloadfile/mod/\u003cstamp\u003e/\u003cpath_encoded\u003e=\",\n  \"static_path\": \"http://s4-hot-2-c.happymodio.com/download_file/mod/\u003cmd5\u003e.swf\",\n  \"stamp\":       \"bbddd820f5af2ebbd76c9d822e9a02cf\",\n  \"path\":        \"\u003cbase64_encoded_path\u003e=\",\n  \"cache_time\":  59,\n  \"full_size\":   \"481246481\",\n  \"what_level\":  \"lv5\",\n  \"verify\":      \"f1b5c559cc1acfe67f6a37dac0ffba7a\",\n  \"no_cdn\":      0,\n  \"is_boundle\":  0,\n  \"is_force\":    0,\n  \"is_vip\":      0,\n  \"vip_award_time\": 0\n}\n```\n\n| Campo         | Descripcion                                                        |\n|---------------|--------------------------------------------------------------------|\n| `status`      | `1` = exito, `-10` = hash invalido o url_id incorrecto             |\n| `apk_path`    | URL de descarga con path codificado internamente — no usar directamente |\n| `static_path` | **URL directa de descarga del APK** — esta es la que se usa        |\n| `stamp`       | MD5 del servidor para validar la descarga                          |\n| `full_size`   | Tamano del APK en bytes                                            |\n| `what_level`  | Nivel de CDN asignado (`lv5` = CDN caliente)                       |\n| `verify`      | MD5 del archivo APK para verificar integridad post-descarga        |\n| `is_vip`      | `1` si el mod requiere cuenta VIP                                  |\n\n---\n\n### 5.5 Detalle de aplicacion\n\n**URL:**\n```\nGET https://app.happymodapp.com/clist/{version},{lang},{country},{page},{url_id},{sort},{page},{template}\n```\n\nUsa un dominio diferente (`happymodapp.com`) y no requiere `uid` ni `stamp`.\nLa respuesta tampoco usa el esquema de cifrado de las otras apis\n\n**Parametros de ruta:**\n\n| Parametro  | Descripcion                              | Ejemplo / Default              |\n|------------|------------------------------------------|--------------------------------|\n| `version`  | Version del APK                          | `3.2.6`                        |\n| `lang`     | Idioma ISO 639-1                         | `es`                           |\n| `country`  | Codigo de pais ISO                       | `US`                           |\n| `page`     | Numero de pagina (aparece dos veces)     | `1`                            |\n| `url_id`   | Package name de la app                   | `com.whatsapp`                 |\n| `sort`     | Criterio de ordenamiento de mods         | `rating`                       |\n| `template` | Template HTML del servidor               | `pdt_mod_list_v3.html`         |\n\n**Ejemplo de url construida:**\n```\nGET https://app.happymodapp.com/clist/3.2.6,es,US,1,com.whatsapp,rating,1,pdt_mod_list_v3.html\n```\n\n**Respuesta:** html o json crudo, no cifrado, me dio pereza documentarlo y ya\n\n---\n\n## 6. Analice:\n\n| Clase Java (nombres de jadx)       | Nombre original          | Funcion                                        |\n|-------------------------|--------------------------|---------------------------------------------|\n| `p410y5.C9106c`         | `SearchManager.java`     | Construye y ejecuta la peticion de busqueda |\n| `p007a5.C0060b`         | `TimestampManager.java`  | Genera `time_str` sincronizado al servidor  |\n| `p376v6.C8861q`         | `Util.java`              | Utilidades: uid, version, stamp, pais       |\n| `p212h7.C7774c`         | `DeviceIdUtil.java`      | Genera el uid del dispositivo               |\n| `p320q7.C8474a`         | `HappyKobe24.java`       | Decodificacion capa 1 (Vigenere)            |\n| `p320q7.C8475b`         | `MyKobe.java`            | Decodificacion capa 2/3 (Base64 + GZIP)    |\n| `p309p7.C8416q`         | `IcOld.java`             | Constantes de endpoints de la API           |\n| `libCSTAMP.so`          | Nativa (C/C++)           | Genera el stamp con MD5                     |\n\n### Strings clave extraidas de `libCSTAMP.so`\n\n| Offset  | Valor                | Uso                          |\n|---------|----------------------|------------------------------|\n| `0x989` | `this_is_happymod`   | Salt del stamp (KEY)         |\n| `0x940` | `98pyooirb6mad326`   | STRAID — usado en `getAid()` |\n\n---\n\n\u003e La documentacion la hice apoyandome de JADX e IDA pro, la app no esta tan ofuscada asi que fue facil reversear todo\n\u003e Lo hice con fines educativos y de investigacion\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flinkmail16%2Fhappymod-reverse-engineering","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flinkmail16%2Fhappymod-reverse-engineering","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flinkmail16%2Fhappymod-reverse-engineering/lists"}